|
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 |
|
-
|