Projet

Général

Profil

0001-tests-PEP8-codestyle-12867.patch

Benjamin Dauvergne, 15 avril 2019 17:13

Télécharger (21,9 ko)

Voir les différences:

Subject: [PATCH 1/2] tests: PEP8 / codestyle (#12867)

 tests/test_rootdirectory.py |  34 ++++++--
 tests/test_saml_auth.py     | 170 ++++++++++++++++++++++++------------
 2 files changed, 141 insertions(+), 63 deletions(-)
tests/test_rootdirectory.py
1
import os
2
import sys
1
# w.c.s. - web application for online forms
2
# Copyright (C) 2005-2010  Entr'ouvert
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16

  
3 17
import shutil
4 18

  
5 19
import pytest
6 20

  
7 21
from quixote import cleanup
8 22
from wcs.qommon import sessions
9
from wcs import formdef
10 23
from wcs.qommon.http_request import HTTPRequest
11 24
from wcs.formdef import FormDef
12 25
from wcs.categories import Category
......
52 65

  
53 66
    formdef2 = FormDef()
54 67
    formdef2.category_id = category.id
55
    formdef2.name  = formdef2.url_name = 'test-formdef-2'
68
    formdef2.name = formdef2.url_name = 'test-formdef-2'
56 69
    formdef2.store()
57 70

  
58 71

  
......
77 90
    assert 'href="category1/test-formdef-1/"' in output
78 91
    assert 'href="category1/test-formdef-2/"' in output
79 92

  
93

  
80 94
def test_private_site_anonymous_access():
81 95
    FormDef.wipe()
82 96
    create_formdef()
......
84 98
    formdef1.store()
85 99
    formdef2.store()
86 100
    with pytest.raises(wcs.forms.root.errors.AccessUnauthorizedError):
87
        output = indexhtml()
101
        indexhtml()
102

  
88 103

  
89 104
def test_semi_private_site_anonymous_access():
90 105
    FormDef.wipe()
......
95 110
    assert 'href="category1/test-formdef-1/"' not in output
96 111
    assert 'href="category1/test-formdef-2/"' in output
97 112

  
113

  
98 114
def test_private_site_authorized_access():
99 115
    FormDef.wipe()
100 116
    create_formdef()
......
105 121
    assert 'href="category1/test-formdef-1/"' in output
106 122
    assert 'href="category1/test-formdef-2/"' in output
107 123

  
124

  
108 125
def test_private_site_unauthorized_access():
109 126
    FormDef.wipe()
110 127
    create_formdef()
......
112 129
    formdef1.store()
113 130
    formdef2.store()
114 131
    with pytest.raises(wcs.forms.root.errors.AccessUnauthorizedError):
115
        output = indexhtml(user2)
132
        indexhtml(user2)
133

  
116 134

  
117 135
def test_private_site_semi_authorized_access():
118 136
    FormDef.wipe()
......
125 143
    assert 'href="category1/test-formdef-1/"' in output
126 144
    assert 'href="category1/test-formdef-2/"' not in output
127 145

  
146

  
128 147
def test_advertized_site_anonymous_access():
129 148
    FormDef.wipe()
130 149
    create_formdef()
......
137 156
    assert 'href="category1/test-formdef-2/"' not in output
138 157
    assert 'authentication required' in output  # locales ?
139 158

  
159

  
140 160
def test_advertized_site_user_access():
141 161
    FormDef.wipe()
142 162
    create_formdef()
......
149 169
    assert 'href="category1/test-formdef-2/"' not in output
150 170
    assert 'authentication required' in output  # locales ?
151 171

  
172

  
152 173
def test_static_directories():
153 174
    assert get_app(pub).get('/static/css/wcs.css')
154 175
    assert get_app(pub).get('/static/images/feed-icon-10x10.png')
......
160 181
    assert 'Directory listing denied' in get_app(pub).get('/static/css/').body
161 182
    assert get_app(pub).get('/static/xxx', status=404)
162 183

  
184

  
163 185
def test_jquery_debug_mode():
164 186
    FormDef.wipe()
165 187
    create_formdef()
tests/test_saml_auth.py
1
# w.c.s. - web application for online forms
2
# Copyright (C) 2005-2010  Entr'ouvert
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16

  
1 17
import datetime
2 18
import os
3
import sys
4 19
import shutil
5 20
import urlparse
6 21

  
......
11 26

  
12 27
import pytest
13 28

  
14
from quixote import cleanup
15
from quixote import get_session, get_session_manager
29
from quixote import get_session_manager
16 30
from wcs.qommon.http_request import HTTPRequest
17 31
from wcs.qommon.misc import get_lasso_server
18 32
from wcs.qommon.saml2 import Saml2Directory
19
from wcs.qommon.ident.idp import MethodAdminDirectory, AdminIDPDir
20
from wcs.qommon import sessions, x509utils
33
from wcs.qommon.ident.idp import MethodAdminDirectory
34
from wcs.qommon import x509utils
21 35
from wcs.roles import Role
22 36

  
23 37
from utilities import get_app, create_temporary_pub, clean_temporary_pub
......
27 41
pytestmark = pytest.mark.skipif('lasso is None')
28 42

  
29 43
IDP_METADATA = """<?xml version="1.0"?>
30
<ns0:EntityDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ns1="http://www.w3.org/2000/09/xmldsig#" entityID="http://sso.example.net/saml2/metadata">
31
  <ns0:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
32
    <ns0:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://sso.example.net/saml2/artifact" index="0"/>
33
    <ns0:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://sso.example.net/saml2/slo" ResponseLocation="http://sso.example.net/saml2/slo_return"/>
34
    <ns0:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sso.example.net/saml2/slo" ResponseLocation="http://sso.example.net/saml2/slo_return"/>
35
    <ns0:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://sso.example.net/saml2/slo/soap"/>
36
    <ns0:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://sso.example.net/saml2/sso"/>
37
    <ns0:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sso.example.net/saml2/sso"/>
44
<ns0:EntityDescriptor
45
   xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"
46
   xmlns:ns1="http://www.w3.org/2000/09/xmldsig#"
47
   entityID="http://sso.example.net/saml2/metadata">
48
  <ns0:IDPSSODescriptor
49
    protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
50
    <ns0:ArtifactResolutionService
51
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
52
      Location="http://sso.example.net/saml2/artifact" index="0"/>
53
    <ns0:SingleLogoutService
54
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
55
      Location="http://sso.example.net/saml2/slo"
56
      ResponseLocation="http://sso.example.net/saml2/slo_return"/>
57
    <ns0:SingleLogoutService
58
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
59
      Location="http://sso.example.net/saml2/slo"
60
      ResponseLocation="http://sso.example.net/saml2/slo_return"/>
61
    <ns0:SingleLogoutService
62
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
63
      Location="http://sso.example.net/saml2/slo/soap"/>
64
    <ns0:SingleSignOnService
65
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
66
      Location="http://sso.example.net/saml2/sso"/>
67
    <ns0:SingleSignOnService
68
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
69
      Location="http://sso.example.net/saml2/sso"/>
38 70
  </ns0:IDPSSODescriptor>
39 71
</ns0:EntityDescriptor>"""
40 72

  
......
43 75
    if 'pub' in metafunc.fixturenames:
44 76
        metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
45 77

  
78

  
46 79
@pytest.fixture
47 80
def pub(request):
48 81
    pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
......
53 86
        'saml2_metadata': 'saml2-metadata.xml',
54 87
        'saml2_base_url': 'http://example.net/saml',
55 88
        'saml2_providerid': 'http://example.net/saml/metadata'
56
        }
89
    }
90
    pub.cfg['identification'] = {'methods': ['idp']}
57 91
    MethodAdminDirectory().generate_rsa_keypair()
58 92
    setup_idps(pub)
59 93
    pub.user_class.wipe()
......
71 105
            base_id = 'http-sso.example.net-saml2-metadata'
72 106
        else:
73 107
            base_id = 'http-sso%s.example.net-saml2-metadata' % i
74
            metadata = IDP_METADATA.replace('sso.example.net',
75
                    'sso%d.example.net' % i)
108
            metadata = IDP_METADATA.replace(
109
                'sso.example.net', 'sso%d.example.net' % i)
76 110
        pub.cfg['idp'][base_id] = {
77 111
            'metadata': 'idp-%s-metadata.xml' % base_id,
78 112
            'publickey': 'idp-%s-publickey.pem' % base_id,
79 113
            'role': lasso.PROVIDER_ROLE_IDP,
80 114
        }
81 115
        filename = pub.cfg['idp'][base_id]['metadata']
82
        fd = file(os.path.join(pub.app_dir, filename), 'w')
116
        fd = open(os.path.join(pub.app_dir, filename), 'w')
83 117
        fd.write(metadata)
84 118
        fd.close()
85 119

  
86 120
        filename = pub.cfg['idp'][base_id]['publickey']
87
        fd = file(os.path.join(pub.app_dir, filename), 'w')
121
        fd = open(os.path.join(pub.app_dir, filename), 'w')
88 122
        fd.write(idp_publickey)
89 123
        fd.close()
90 124

  
91 125
        filename = pub.cfg['idp'][base_id]['publickey'].replace('public', 'private')
92
        fd = file(os.path.join(pub.app_dir, filename), 'w')
126
        fd = open(os.path.join(pub.app_dir, filename), 'w')
93 127
        fd.write(idp_privatekey)
94 128
        fd.close()
95 129

  
......
99 133
def teardown_module(module):
100 134
    clean_temporary_pub()
101 135

  
136

  
102 137
def test_login(pub):
103 138
    req = HTTPRequest(None, {
104 139
        'SERVER_NAME': 'example.net',
105 140
        'SCRIPT_NAME': '',
106
        })
141
    })
107 142
    pub._set_request(req)
108 143
    saml2 = Saml2Directory()
109 144
    saml2.perform_login()
110 145
    assert req.response.status_code == 302
111 146
    assert req.response.headers['location'].startswith('http://sso.example.net/saml2/sso?SAMLRequest')
112 147

  
148

  
113 149
def get_authn_response_msg(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT):
114
    idp_metadata_filepath = os.path.join(pub.app_dir,
115
            'idp-http-sso.example.net-saml2-metadata-metadata.xml')
116
    idp_key_filepath = os.path.join(pub.app_dir,
117
            'idp-http-sso.example.net-saml2-metadata-privatekey.pem')
150
    idp_metadata_filepath = os.path.join(
151
        pub.app_dir, 'idp-http-sso.example.net-saml2-metadata-metadata.xml')
152
    idp_key_filepath = os.path.join(
153
        pub.app_dir, 'idp-http-sso.example.net-saml2-metadata-privatekey.pem')
118 154
    idp = lasso.Server(idp_metadata_filepath, idp_key_filepath, None, None)
119 155
    idp.addProvider(lasso.PROVIDER_ROLE_SP,
120
            os.path.join(pub.app_dir, 'saml2-metadata.xml'),
121
            os.path.join(pub.app_dir, 'public-key.pem'))
156
                    os.path.join(pub.app_dir, 'saml2-metadata.xml'),
157
                    os.path.join(pub.app_dir, 'public-key.pem'))
122 158
    login = lasso.Login(idp)
123 159
    login.initIdpInitiatedAuthnRequest(pub.cfg['sp']['saml2_providerid'])
124 160
    login.request.nameIDPolicy.format = ni_format
......
126 162
    login.request.protocolBinding = lasso.SAML2_METADATA_BINDING_POST
127 163
    login.processAuthnRequestMsg(None)
128 164
    login.validateRequestMsg(True, True)
129
    login.buildAssertion(lasso.SAML2_AUTHN_CONTEXT_PASSWORD,
130
            datetime.datetime.now().isoformat(),
131
            'unused',
132
            (datetime.datetime.now() - datetime.timedelta(3600)).isoformat(),
133
            (datetime.datetime.now() + datetime.timedelta(3600)).isoformat())
165
    login.buildAssertion(
166
        lasso.SAML2_AUTHN_CONTEXT_PASSWORD,
167
        datetime.datetime.now().isoformat(),
168
        'unused',
169
        (datetime.datetime.now() - datetime.timedelta(3600)).isoformat(),
170
        (datetime.datetime.now() + datetime.timedelta(3600)).isoformat())
134 171
    if ni_format == lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED:
135 172
        login.assertion.subject.nameID.content = '1234'
136 173
    value = lasso.MiscTextNode.newWithString('John')
......
173 210
    login.buildAuthnResponseMsg()
174 211
    return login.msgBody
175 212

  
213

  
176 214
def get_assertion_consumer_request(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT):
177 215
    req = HTTPRequest(None, {
178 216
        'SERVER_NAME': 'example.net',
179 217
        'SCRIPT_NAME': '',
180 218
        'PATH_INFO': '/saml/assertionConsumerPost',
181
        })
219
    })
182 220
    pub._set_request(req)
183 221
    pub.session_class.wipe()
184 222
    req.session = pub.session_class(id=1)
......
186 224
    req.form['SAMLResponse'] = get_authn_response_msg(pub, ni_format=ni_format)
187 225
    return req
188 226

  
227

  
189 228
def test_saml_metadata(pub):
190 229
    req = HTTPRequest(None, {'SERVER_NAME': 'example.net', 'SCRIPT_NAME': '', })
191 230
    pub._set_request(req)
......
195 234
    assert '<EntityDescriptor' in body
196 235
    assert req.response.content_type == 'text/xml'
197 236

  
237

  
198 238
def test_saml_public_key(pub):
199 239
    req = HTTPRequest(None, {'SERVER_NAME': 'example.net', 'SCRIPT_NAME': '', })
200 240
    pub._set_request(req)
......
204 244
    assert body.startswith('-----BEGIN PUBLIC KEY-----')
205 245
    assert req.response.content_type == 'application/octet-stream'
206 246

  
247

  
207 248
def test_assertion_consumer(pub):
208 249
    req = get_assertion_consumer_request(pub)
209 250
    saml2 = Saml2Directory()
210
    body = saml2.assertionConsumerPost()
251
    saml2.assertionConsumerPost()
211 252

  
212 253
    assert req.response.status_code == 303
213 254
    assert req.response.headers['location'] == 'http://example.net'
214 255
    assert req.session.user is not None
215 256

  
257

  
216 258
def test_assertion_consumer_unspecified(pub):
217 259
    req = get_assertion_consumer_request(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED)
218 260
    saml2 = Saml2Directory()
219
    body = saml2.assertionConsumerPost()
261
    saml2.assertionConsumerPost()
220 262

  
221 263
    assert req.response.status_code == 303
222 264
    assert req.response.headers['location'] == 'http://example.net'
223 265
    assert req.session.user is not None
224 266

  
267

  
225 268
def test_assertion_consumer_existing_federation(pub, caplog):
226 269
    # setup an hobo profile
227 270
    from wcs.ctl.check_hobos import CmdCheckHobos
......
257 300
        'SERVER_NAME': 'example.net',
258 301
        'SCRIPT_NAME': '',
259 302
        'PATH_INFO': '/saml/assertionConsumerPost',
260
        })
303
    })
261 304
    pub._set_request(req)
262
    req.session = pub.session_class(id=2) # another session
305
    req.session = pub.session_class(id=2)  # another session
263 306
    req.session.message = ('error', 'blah')
264 307
    req.form['SAMLResponse'] = saml_response_body
265 308
    assert req.session.user is None
......
280 323
    assert req.session.saml_authn_context == lasso.SAML2_AUTHN_CONTEXT_PASSWORD
281 324
    assert req.session.message is None
282 325

  
326

  
283 327
def test_assertion_consumer_redirect_after_url(pub):
284 328
    req = get_assertion_consumer_request(pub)
285 329
    req.form['RelayState'] = '/foobar/?test=ok'
286 330
    saml2 = Saml2Directory()
287
    saml_response_body = req.form['SAMLResponse']
288
    body = saml2.assertionConsumerPost()
331
    saml2.assertionConsumerPost()
289 332
    assert req.response.status_code == 303
290 333
    assert req.response.headers['location'] == 'http://example.net/foobar/?test=ok'
291 334

  
335

  
292 336
def test_assertion_consumer_full_url_redirect_after_url(pub):
293 337
    req = get_assertion_consumer_request(pub)
294 338
    req.form['RelayState'] = 'http://example.org/foobar/?test=ok'
295 339
    saml2 = Saml2Directory()
296
    saml_response_body = req.form['SAMLResponse']
297
    body = saml2.assertionConsumerPost()
340
    saml2.assertionConsumerPost()
298 341
    assert req.response.status_code == 303
299 342
    assert req.response.headers['location'] == 'http://example.org/foobar/?test=ok'
300 343

  
344

  
301 345
def test_saml_login_page(pub):
302 346
    resp = get_app(pub).get('/login/')
303 347
    assert resp.status_int == 302
......
306 350
    request.initFromQuery(urlparse.urlparse(resp.location).query)
307 351
    assert request.forceAuthn is False
308 352

  
353

  
309 354
def test_saml_login_page_force_authn(pub):
310 355
    resp = get_app(pub).get('/login/?forceAuthn=true')
311 356
    assert resp.status_int == 302
......
314 359
    request.initFromQuery(urlparse.urlparse(resp.location).query)
315 360
    assert request.forceAuthn is True
316 361

  
362

  
317 363
def test_saml_login_page_several_idp(pub):
318 364
    setup_idps(pub, idp_number=4)
319 365
    # even if there are multiple IdP, /login/ will initiate SSO with the first
......
324 370
    assert resp.status_int == 302
325 371
    assert resp.location.startswith('http://%s/saml2/sso?SAMLRequest=' % first_idp_domain)
326 372

  
373

  
327 374
def test_saml_backoffice_redirect(pub):
328 375
    resp = get_app(pub).get('/backoffice/')
329 376
    assert resp.status_int == 302
......
337 384
    request.initFromQuery(urlparse.urlparse(resp.location).query)
338 385
    assert ':next_url>http://example.net/backoffice/<' in request.getOriginalXmlnode()
339 386

  
387

  
340 388
def test_saml_register(pub):
341 389
    get_app(pub).get('/register/', status=404)
342 390
    pub.cfg['saml_identities'] = {'identity-creation': 'self'}
......
350 398
    assert resp.location.startswith('http://sso.example.net/saml2/sso?SAMLRequest=')
351 399

  
352 400
    # check redirection to known registration page
353
    pub.cfg['saml_identities'] = {'identity-creation': 'self',
354
            'registration-url': 'http://sso.example.net/registration'}
401
    pub.cfg['saml_identities'] = {
402
        'identity-creation': 'self',
403
        'registration-url': 'http://sso.example.net/registration'
404
    }
355 405
    pub.write_cfg()
356 406
    resp = get_app(pub).get('/register/')
357 407
    assert resp.location == 'http://sso.example.net/registration'
358 408

  
359 409
    # check redirection to known registration page, with a variable
360
    pub.cfg['saml_identities'] = {'identity-creation': 'self',
361
            'registration-url': 'http://sso.example.net/registration?next_url=[next_url]'}
410
    pub.cfg['saml_identities'] = {
411
        'identity-creation': 'self',
412
        'registration-url': 'http://sso.example.net/registration?next_url=[next_url]'
413
    }
362 414
    pub.write_cfg()
363 415
    resp = get_app(pub).get('/register/')
364 416
    assert resp.location == 'http://sso.example.net/registration?next_url=http%3A%2F%2Fexample.net%2Fregister%2F'
365 417

  
418

  
366 419
def test_saml_logout(pub):
367 420
    req = get_assertion_consumer_request(pub)
368 421
    saml2 = Saml2Directory()
369 422
    saml2.assertionConsumerPost()
370 423
    assert req.session.user is not None
371
    body = saml2.slo_sp()
424
    saml2.slo_sp()
372 425
    assert req.response.headers['location'].startswith('http://sso.example.net/saml2/slo?SAMLRequest=')
373 426
    assert req.session.user is None
374 427

  
428

  
375 429
def test_saml_idp_logout(pub):
376 430
    req = get_assertion_consumer_request(pub)
377 431
    saml2 = Saml2Directory()
......
387 441
    name_id = req.session.name_identifier
388 442

  
389 443
    # and recreate an idp session
390
    idp_metadata_filepath = os.path.join(pub.app_dir,
391
            'idp-http-sso.example.net-saml2-metadata-metadata.xml')
392
    idp_key_filepath = os.path.join(pub.app_dir,
393
            'idp-http-sso.example.net-saml2-metadata-privatekey.pem')
444
    idp_metadata_filepath = os.path.join(
445
        pub.app_dir, 'idp-http-sso.example.net-saml2-metadata-metadata.xml')
446
    idp_key_filepath = os.path.join(
447
        pub.app_dir, 'idp-http-sso.example.net-saml2-metadata-privatekey.pem')
394 448
    idp = lasso.Server(idp_metadata_filepath, idp_key_filepath, None, None)
395
    idp.addProvider(lasso.PROVIDER_ROLE_SP,
396
            os.path.join(pub.app_dir, 'saml2-metadata.xml'),
397
            os.path.join(pub.app_dir, 'public-key.pem'))
449
    idp.addProvider(
450
        lasso.PROVIDER_ROLE_SP,
451
        os.path.join(pub.app_dir, 'saml2-metadata.xml'),
452
        os.path.join(pub.app_dir, 'public-key.pem'))
398 453

  
399 454
    login = lasso.Login(idp)
400 455
    login.initIdpInitiatedAuthnRequest(pub.cfg['sp']['saml2_providerid'])
......
403 458
    login.request.protocolBinding = lasso.SAML2_METADATA_BINDING_POST
404 459
    login.processAuthnRequestMsg(None)
405 460
    login.validateRequestMsg(True, True)
406
    login.buildAssertion(lasso.SAML2_AUTHN_CONTEXT_PASSWORD,
407
            datetime.datetime.now().isoformat(),
408
            'unused',
409
            (datetime.datetime.now() - datetime.timedelta(3600)).isoformat(),
410
            (datetime.datetime.now() + datetime.timedelta(3600)).isoformat())
461
    login.buildAssertion(
462
        lasso.SAML2_AUTHN_CONTEXT_PASSWORD,
463
        datetime.datetime.now().isoformat(),
464
        'unused',
465
        (datetime.datetime.now() - datetime.timedelta(3600)).isoformat(),
466
        (datetime.datetime.now() + datetime.timedelta(3600)).isoformat())
411 467
    login.assertion.subject.nameID.content = name_id
412 468
    login.assertion.id = assertion_id
413 469
    login.assertion.authnStatement[0].sessionIndex = assertion_id
414
-