def testAccessors(self): """Test for LogoutRequest accessors""" self.lr.id = "request id" self.lr.version = saml2.VERSION self.lr.issue_instant = "2007-09-14T01:05:02Z" self.lr.destination = "http://www.example.com/Destination" self.lr.consent = saml.CONSENT_UNSPECIFIED self.lr.issuer = saml.Issuer() self.lr.signature = ds.Signature() self.lr.extensions = samlp.Extensions() self.lr.not_on_or_after = "2007-10-14T01:05:02Z" self.lr.reason = "http://www.example.com/Reason" self.lr.base_id = saml.BaseID() self.lr.name_id = saml.NameID() self.lr.encrypted_id = saml.EncryptedID() self.lr.session_index = samlp.SessionIndex() new_lr = samlp.logout_request_from_string(self.lr.to_string()) assert new_lr.id == "request id" assert new_lr.version == saml2.VERSION assert new_lr.issue_instant == "2007-09-14T01:05:02Z" assert new_lr.destination == "http://www.example.com/Destination" assert new_lr.consent == saml.CONSENT_UNSPECIFIED assert isinstance(new_lr.issuer, saml.Issuer) assert isinstance(new_lr.signature, ds.Signature) assert isinstance(new_lr.extensions, samlp.Extensions) assert new_lr.not_on_or_after == "2007-10-14T01:05:02Z" assert new_lr.reason == "http://www.example.com/Reason" assert isinstance(new_lr.base_id, saml.BaseID) assert isinstance(new_lr.name_id, saml.NameID) assert isinstance(new_lr.encrypted_id, saml.EncryptedID) assert isinstance(new_lr.session_index[0], samlp.SessionIndex)
def testAccessors(self): """Test for LogoutRequest accessors""" self.lr.id = "request id" self.lr.version = saml2.VERSION self.lr.issue_instant = "2007-09-14T01:05:02Z" self.lr.destination = "http://www.example.com/Destination" self.lr.consent = saml.CONSENT_UNSPECIFIED self.lr.issuer = saml.Issuer() self.lr.signature = ds.Signature() self.lr.extensions = samlp.Extensions() self.lr.not_on_or_after = "2007-10-14T01:05:02Z" self.lr.reason = "http://www.example.com/Reason" self.lr.base_id = saml.BaseID() self.lr.name_id = saml.NameID() self.lr.encrypted_id = saml.EncryptedID() self.lr.session_index = samlp.SessionIndex() new_lr = samlp.logout_request_from_string(self.lr.to_string()) assert new_lr.id == "request id" assert new_lr.version == saml2.VERSION assert new_lr.issue_instant == "2007-09-14T01:05:02Z" assert new_lr.destination == "http://www.example.com/Destination" assert new_lr.consent == saml.CONSENT_UNSPECIFIED assert isinstance(new_lr.issuer, saml.Issuer) assert isinstance(new_lr.signature, ds.Signature) assert isinstance(new_lr.extensions, samlp.Extensions) assert new_lr.not_on_or_after == "2007-10-14T01:05:02Z" assert new_lr.reason == "http://www.example.com/Reason" assert isinstance(new_lr.base_id, saml.BaseID) assert isinstance(new_lr.name_id, saml.NameID) assert isinstance(new_lr.encrypted_id, saml.EncryptedID) assert isinstance(new_lr.session_index[0], samlp.SessionIndex)
def correctly_signed_logout_request(self, decoded_xml, must=False, origdoc=None): """ Check if a request is correctly signed, if we have metadata for the SP that sent the info use that, if not use the key that are in the message if any. :param decoded_xml: The SAML message as a XML string :param must: Whether there must be a signature :param origdoc: The original XML message :return: None if the signature can not be verified otherwise request as a samlp.Request instance """ request = samlp.logout_request_from_string(decoded_xml) if not request: raise TypeError("Not a LogoutRequest") if not request.signature: if must: raise SignatureError("Missing must signature") else: return request return self._check_signature(decoded_xml, request, class_name(request), origdoc)
def test_logout_1(self): """ one IdP/AA logout from""" # information about the user from an IdP session_info = { "name_id": "123456", "issuer": "urn:mace:example.com:saml:roland:idp", "not_on_or_after": in_a_while(minutes=15), "ava": { "givenName": "Anders", "surName": "Andersson", "mail": "*****@*****.**" } } self.client.users.add_information_about_person(session_info) entity_ids = self.client.users.issuers_of_info("123456") assert entity_ids == ["urn:mace:example.com:saml:roland:idp"] resp = self.client.global_logout("123456", "Tired", in_a_while(minutes=5)) print resp assert resp assert len(resp) == 1 assert resp.keys() == entity_ids http_args = resp[entity_ids[0]] assert isinstance(http_args, dict) assert http_args["headers"] == [('Content-type', 'text/html')] info = unpack_form(http_args["data"][3]) xml_str = base64.b64decode(info["SAMLRequest"]) req = logout_request_from_string(xml_str) print req assert req.reason == "Tired"
def http_redirect_logout_request(self, get, subject_id, log=None): """ Deal with a LogoutRequest received through HTTP redirect :param get: The request as a dictionary :param subject_id: the id of the current logged user :return: a tuple with a list of header tuples (presently only location) and a status which will be True in case of success or False otherwise. """ headers = [] success = False if log is None: log = self.logger try: saml_request = get['SAMLRequest'] except KeyError: return None if saml_request: xml = decode_base64_and_inflate(saml_request) request = samlp.logout_request_from_string(xml) if log: log.debug(request) if request.name_id.text == subject_id: status = samlp.STATUS_SUCCESS success = self.local_logout(subject_id) else: status = samlp.STATUS_REQUEST_DENIED response, destination = self .make_logout_response( request.issuer.text, request.id, status) if log: log.info("RESPONSE: {0:>s}".format(response)) if 'RelayState' in get: rstate = get['RelayState'] else: rstate = "" (headers, _body) = http_redirect_message(str(response), destination, rstate, 'SAMLResponse') return headers, success
def testUsingTestData(self): """Test for logout_request_from_string() using test data""" new_lr = samlp.logout_request_from_string(samlp_data.TEST_LOGOUT_REQUEST) assert new_lr.id == "request id" assert new_lr.version == saml2.VERSION assert new_lr.issue_instant == "2007-09-14T01:05:02Z" assert new_lr.destination == "http://www.example.com/Destination" assert new_lr.consent == saml.CONSENT_UNSPECIFIED assert isinstance(new_lr.issuer, saml.Issuer) assert isinstance(new_lr.signature, ds.Signature) assert isinstance(new_lr.extensions, samlp.Extensions) assert new_lr.not_on_or_after == "2007-10-14T01:05:02Z" assert new_lr.reason == "http://www.example.com/Reason" assert isinstance(new_lr.base_id, saml.BaseID) assert isinstance(new_lr.name_id, saml.NameID) assert isinstance(new_lr.encrypted_id, saml.EncryptedID) assert isinstance(new_lr.session_index[0], samlp.SessionIndex) assert new_lr.session_index[0].text.strip() == "session index"
def testUsingTestData(self): """Test for logout_request_from_string() using test data""" new_lr = samlp.logout_request_from_string(samlp_data.TEST_LOGOUT_REQUEST) assert new_lr.id == "request id" assert new_lr.version == saml2.VERSION assert new_lr.issue_instant == "2007-09-14T01:05:02Z" assert new_lr.destination == "http://www.example.com/Destination" assert new_lr.consent == saml.CONSENT_UNSPECIFIED assert isinstance(new_lr.issuer, saml.Issuer) assert isinstance(new_lr.signature, ds.Signature) assert isinstance(new_lr.extensions, samlp.Extensions) assert new_lr.not_on_or_after == "2007-10-14T01:05:02Z" assert new_lr.reason == "http://www.example.com/Reason" assert isinstance(new_lr.base_id, saml.BaseID) assert isinstance(new_lr.name_id, saml.NameID) assert isinstance(new_lr.encrypted_id, saml.EncryptedID) assert isinstance(new_lr.session_index[0], samlp.SessionIndex) assert new_lr.session_index[0].text.strip() == "session index"
def http_redirect_logout_request(self, get, subject_id): """ Deal with a LogoutRequest received through HTTP redirect :param get: The request as a dictionary :param subject_id: the id of the current logged user :return: a tuple with a list of header tuples (presently only location) and a status which will be True in case of success or False otherwise. """ headers = [] success = False try: saml_request = get['SAMLRequest'] except KeyError: return None if saml_request: xml = decode_base64_and_inflate(saml_request) request = samlp.logout_request_from_string(xml) logger.debug(request) if request.name_id.text == subject_id: status = samlp.STATUS_SUCCESS success = self.local_logout(subject_id) else: status = samlp.STATUS_REQUEST_DENIED response, destination = self.make_logout_response( request.issuer.text, request.id, status) logger.info("RESPONSE: {0:>s}".format(response)) if 'RelayState' in get: rstate = get['RelayState'] else: rstate = "" (headers, _body) = http_redirect_message(str(response), destination, rstate, 'SAMLResponse') return headers, success
def http_redirect_logout_request_check_session_index(self, get, session_index, log=None): """ Deal with a LogoutRequest received through HTTP redirect :param get: The request as a dictionary :param subject_id: the id of the current logged user :return: a tuple with a list of header tuples (presently only location) """ msg = {} try: saml_request = get['SAMLRequest'] except KeyError: return None if saml_request: xml = decode_base64_and_inflate(saml_request) logger.info('logout request: %s' % xml) request = samlp.logout_request_from_string(xml) logger.debug(request) if request.session_index[0].text == session_index: status = samlp.STATUS_SUCCESS else: status = samlp.STATUS_REQUEST_DENIED response, destination = self .make_logout_response( request.issuer.text, request.id, status) logger.info("RESPONSE: {0:>s}".format(response)) if 'RelayState' in get: rstate = get['RelayState'] else: rstate = "" msg = http_redirect_message(str(response), destination, rstate, 'SAMLResponse') return msg
def http_redirect_logout_request_check_session_index( self, get, session_index, log=None): """ Deal with a LogoutRequest received through HTTP redirect :param get: The request as a dictionary :param subject_id: the id of the current logged user :return: a tuple with a list of header tuples (presently only location) """ msg = {} try: saml_request = get['SAMLRequest'] except KeyError: return None if saml_request: xml = decode_base64_and_inflate(saml_request) logger.info('logout request: %s' % xml) request = samlp.logout_request_from_string(xml) logger.debug(request) if request.session_index[0].text == session_index: status = samlp.STATUS_SUCCESS else: status = samlp.STATUS_REQUEST_DENIED response, destination = self.make_logout_response( request.issuer.text, request.id, status) logger.info("RESPONSE: {0:>s}".format(response)) if 'RelayState' in get: rstate = get['RelayState'] else: rstate = "" msg = http_redirect_message(str(response), destination, rstate, 'SAMLResponse') return msg
def logout_endpoint(self, xml_str, binding): if binding == BINDING_SOAP: _str = parse_soap_enveloped_saml_logout_request(xml_str) else: _str = xml_str req = logout_request_from_string(_str) _resp = self.create_logout_response(req, [binding]) if binding == BINDING_SOAP: # SOAP packing #headers = {"content-type": "application/soap+xml"} soap_message = make_soap_enveloped_saml_thingy(_resp) # if self.sign and self.sec: # _signed = self.sec.sign_statement_using_xmlsec(soap_message, # class_name(attr_resp), # nodeid=attr_resp.id) # soap_message = _signed response = "%s" % soap_message else: # Just POST response = "%s" % _resp return DummyResponse(200, response)
def correctly_signed_logout_request(self, decoded_xml, must=False, origdoc=None): """ Check if a request is correctly signed, if we have metadata for the SP that sent the info use that, if not use the key that are in the message if any. :param decoded_xml: The SAML message as a XML string :param must: Whether there must be a signature :param origdoc: The original XML message :return: None if the signature can not be verified otherwise request as a samlp.Request instance """ request = samlp.logout_request_from_string(decoded_xml) if not request: raise TypeError("Not a LogoutRequest") if not request.signature: if must: raise SignatureError("Missing must signature") else: return request return self._check_signature(decoded_xml, request, class_name(request), origdoc)
def test_logout_1(self): """ one IdP/AA logout from""" # information about the user from an IdP session_info = { "name_id": "123456", "issuer": "urn:mace:example.com:saml:roland:idp", "not_on_or_after": in_a_while(minutes=15), "ava": { "givenName": "Anders", "surName": "Andersson", "mail": "*****@*****.**" } } self.client.users.add_information_about_person(session_info) entity_ids = self.client.users.issuers_of_info("123456") assert entity_ids == ["urn:mace:example.com:saml:roland:idp"] resp = self.client.global_logout("123456", "Tired", in_a_while(minutes=5)) print resp assert resp assert len(resp) == 1 assert resp.keys() == entity_ids item = resp[entity_ids[0]] assert isinstance(item, tuple) assert item[0] == [('Content-type', 'text/html')] lead = "name=\"SAMLRequest\" value=\"" body = item[1][3] i = body.find(lead) i += len(lead) j = i + body[i:].find('"') info = body[i:j] xml_str = base64.b64decode(info) #xml_str = decode_base64_and_inflate(info) req = logout_request_from_string(xml_str) print req assert req.reason == "Tired" # def test_logout_2(self): # """ one IdP/AA with BINDING_SOAP, can't actually send something""" # # conf = config.SPConfig() # conf.load_file("server2_conf") # client = Saml2Client(conf) # # # information about the user from an IdP # session_info = { # "name_id": "123456", # "issuer": "urn:mace:example.com:saml:roland:idp", # "not_on_or_after": in_a_while(minutes=15), # "ava": { # "givenName": "Anders", # "surName": "Andersson", # "mail": "*****@*****.**" # } # } # client.users.add_information_about_person(session_info) # entity_ids = self.client.users.issuers_of_info("123456") # assert entity_ids == ["urn:mace:example.com:saml:roland:idp"] # destinations = client.config.single_logout_services(entity_ids[0], # BINDING_SOAP) # print destinations # assert destinations == ['http://*****:*****@example.com" # } # } # client.users.add_information_about_person(session_info_authn) # session_info_aa = { # "name_id": "123456", # "issuer": "urn:mace:example.com:saml:roland:aa", # "not_on_or_after": in_a_while(minutes=15), # "ava": { # "eduPersonEntitlement": "Foobar", # } # } # client.users.add_information_about_person(session_info_aa) # entity_ids = client.users.issuers_of_info("123456") # assert _leq(entity_ids, ["urn:mace:example.com:saml:roland:idp", # "urn:mace:example.com:saml:roland:aa"]) # resp = client.global_logout("123456", "Tired", in_a_while(minutes=5)) # print resp # assert resp # assert resp[0] # a session_id # assert resp[1] == '200 OK' # # HTTP POST # assert resp[2] == [('Content-type', 'text/html')] # assert resp[3][0] == '<head>' # assert resp[3][1] == '<title>SAML 2.0 POST</title>' # # state_info = client.state[resp[0]] # print state_info # assert state_info["entity_id"] == entity_ids[0] # assert state_info["subject_id"] == "123456" # assert state_info["reason"] == "Tired" # assert state_info["operation"] == "SLO" # assert state_info["entity_ids"] == entity_ids # assert state_info["sign"] == True # # def test_authz_decision_query(self): # conf = config.SPConfig() # conf.load_file("server3_conf") # client = Saml2Client(conf) # # AVA = {'mail': u'*****@*****.**', # 'eduPersonTargetedID': '95e9ae91dbe62d35198fbbd5e1fb0976', # 'displayName': u'Roland Hedberg', # 'uid': 'http://roland.hedberg.myopenid.com/'} # # sp_entity_id = "sp_entity_id" # in_response_to = "1234" # consumer_url = "http://example.com/consumer" # name_id = saml.NameID(saml.NAMEID_FORMAT_TRANSIENT, text="name_id") # policy = Policy() # ava = Assertion(AVA) # assertion = ava.construct(sp_entity_id, in_response_to, # consumer_url, name_id, # conf.attribute_converters, # policy, issuer=client._issuer()) # # adq = client.create_authz_decision_query_using_assertion("entity_id", # assertion, # "read", # "http://example.com/text") # # assert adq # print adq # assert adq.keyswv() != [] # assert adq.destination == "entity_id" # assert adq.resource == "http://example.com/text" # assert adq.action[0].text == "read" # # def test_request_to_discovery_service(self): # disc_url = "http://example.com/saml2/idp/disc" # url = discovery_service_request_url("urn:mace:example.com:saml:roland:sp", # disc_url) # print url # assert url == "http://example.com/saml2/idp/disc?entityID=urn%3Amace%3Aexample.com%3Asaml%3Aroland%3Asp" # # url = discovery_service_request_url( # self.client.config.entityid, # disc_url, # return_url= "http://example.org/saml2/sp/ds") # # print url # assert url == "http://example.com/saml2/idp/disc?entityID=urn%3Amace%3Aexample.com%3Asaml%3Aroland%3Asp&return=http%3A%2F%2Fexample.org%2Fsaml2%2Fsp%2Fds" # # def test_get_idp_from_discovery_service(self): # pdir = {"entityID": "http://example.org/saml2/idp/sso"} # params = urllib.urlencode(pdir) # redirect_url = "http://example.com/saml2/sp/disc?%s" % params # # entity_id = discovery_service_response(url=redirect_url) # assert entity_id == "http://example.org/saml2/idp/sso" # # pdir = {"idpID": "http://example.org/saml2/idp/sso"} # params = urllib.urlencode(pdir) # redirect_url = "http://example.com/saml2/sp/disc?%s" % params # # entity_id = discovery_service_response(url=redirect_url, # returnIDParam="idpID") # # assert entity_id == "http://example.org/saml2/idp/sso" # self.server.close_shelve_db() # # def test_unsolicited_response(self): # """ # # """ # self.server = Server("idp_conf") # # conf = config.SPConfig() # conf.load_file("server_conf") # self.client = Saml2Client(conf) # # for subject in self.client.users.subjects(): # self.client.users.remove_person(subject) # # IDP = "urn:mace:example.com:saml:roland:idp" # # ava = { "givenName": ["Derek"], "surName": ["Jeter"], # "mail": ["*****@*****.**"], "title": ["The man"]} # # resp_str = "%s" % self.server.create_authn_response( # identity=ava, # in_response_to="id1", # destination="http://lingon.catalogix.se:8087/", # sp_entity_id="urn:mace:example.com:saml:roland:sp", # name_id_policy=samlp.NameIDPolicy( # format=saml.NAMEID_FORMAT_PERSISTENT), # userid="*****@*****.**") # # resp_str = base64.encodestring(resp_str) # # self.client.allow_unsolicited = True # authn_response = self.client.authn_request_response( # {"SAMLResponse":resp_str}, ()) # # assert authn_response is not None # assert authn_response.issuer() == IDP # assert authn_response.response.assertion[0].issuer.text == IDP # session_info = authn_response.session_info() # # print session_info # assert session_info["ava"] == {'mail': ['*****@*****.**'], # 'givenName': ['Derek'], # 'surName': ['Jeter']} # assert session_info["issuer"] == IDP # assert session_info["came_from"] == "" # response = samlp.response_from_string(authn_response.xmlstr) # assert response.destination == "http://lingon.catalogix.se:8087/" # # # One person in the cache # assert len(self.client.users.subjects()) == 1 # self.server.close_shelve_db()
def _parse_logout_request(self, enc_request): xmlstr = decode_base64_and_inflate(urllib.unquote(enc_request)) return logout_request_from_string(xmlstr)
def test_Saml_logout(self): not_on_or_after = time.time() + 3600 identity = { 'id-1': { 'https://sso.example.com/idp/metadata': (not_on_or_after, { 'authn_info': [], 'name_id': 'id-1', 'not_on_or_after': not_on_or_after, 'came_from': '/next', 'ava': { 'uid': ['123456'] } }) } } # modifying config in this test, make copy so as not to effect # following tests. tmp_sp_config = copy.deepcopy(sp_config) with self.app.test_request_context('/', method='GET'): sp = auth.Saml(tmp_sp_config) # first need to be logged in, let's pretend session['_saml_identity'] = identity session['_saml_subject_id'] = 'id-1' resp = sp.logout(next_url='/next') self.assertEqual(resp.status_code, 302) self.assert_("SAMLRequest" in resp.headers['Location']) url = urlparse.urlparse(resp.headers['Location']) self.assertEqual(url.hostname, 'sso.example.com') self.assertEqual(url.path, '/idp/slo') params = urlparse.parse_qs(url.query) self.assert_('SAMLRequest' in params) logout = samlp.logout_request_from_string( decode_base64_and_inflate(params['SAMLRequest'][0])) self.assertEqual(logout.destination, 'https://sso.example.com/idp/slo') self.assertEqual(logout.name_id.text, 'id-1') self.assertIsNotNone(logout.signature) # check the caches still contain data self.assertEqual(session['_saml_identity'], identity) self.assertEqual(session['_saml_subject_id'], 'id-1') # verify state cache self.assert_(logout.id in session['_saml_state']) self.assertEqual(session['_saml_state'][logout.id]['entity_id'], 'https://sso.example.com/idp/metadata') self.assertEqual(session['_saml_state'][logout.id]['operation'], 'SLO') self.assertEqual(session['_saml_state'][logout.id]['subject_id'], 'id-1') self.assertEqual(session['_saml_state'][logout.id]['return_to'], '/next') self.assertTrue(session['_saml_state'][logout.id]['sign']) # test unsigned logout request with self.app.test_request_context('/', method='GET'): tmp_sp_config['key_file'] = None tmp_sp_config['service']['sp']['logout_requests_signed'] = 'false' sp = auth.Saml(tmp_sp_config) # first need to be logged in, let's pretend session['_saml_identity'] = identity session['_saml_subject_id'] = 'id-1' resp = sp.logout(next_url='/next') self.assertEqual(resp.status_code, 302) self.assert_("SAMLRequest" in resp.headers['Location']) url = urlparse.urlparse(resp.headers['Location']) params = urlparse.parse_qs(url.query) self.assert_('SAMLRequest' in params) logout = samlp.logout_request_from_string( decode_base64_and_inflate(params['SAMLRequest'][0])) self.assertIsNone(logout.signature) # verify state cache shows signing off self.assertFalse(session['_saml_state'][logout.id]['sign'])
def test_Saml_logout(self): not_on_or_after = time.time()+3600 identity = {'id-1': { 'https://sso.example.com/idp/metadata': ( not_on_or_after, { 'authn_info': [], 'name_id': 'id-1', 'not_on_or_after': not_on_or_after, 'came_from': '/next', 'ava': {'uid': ['123456']} } ) }} # modifying config in this test, make copy so as not to effect # following tests. tmp_sp_config = copy.deepcopy(sp_config) with self.app.test_request_context('/', method='GET'): sp = auth.Saml(tmp_sp_config) # first need to be logged in, let's pretend session['_saml_identity'] = identity session['_saml_subject_id'] = 'id-1' resp = sp.logout(next_url='/next') self.assertEqual(resp.status_code, 302) self.assert_("SAMLRequest" in resp.headers['Location']) url = urlparse.urlparse(resp.headers['Location']) self.assertEqual(url.hostname, 'sso.example.com') self.assertEqual(url.path, '/idp/slo') params = urlparse.parse_qs(url.query) self.assert_('SAMLRequest' in params) logout = samlp.logout_request_from_string( decode_base64_and_inflate(params['SAMLRequest'][0])) self.assertEqual(logout.destination, 'https://sso.example.com/idp/slo') self.assertEqual(logout.name_id.text, 'id-1') self.assertIsNotNone(logout.signature) # check the caches still contain data self.assertEqual(session['_saml_identity'], identity) self.assertEqual(session['_saml_subject_id'], 'id-1') # verify state cache self.assert_(logout.id in session['_saml_state']) self.assertEqual(session['_saml_state'][logout.id]['entity_id'], 'https://sso.example.com/idp/metadata') self.assertEqual(session['_saml_state'][logout.id]['operation'], 'SLO') self.assertEqual(session['_saml_state'][logout.id]['subject_id'], 'id-1') self.assertEqual(session['_saml_state'][logout.id]['return_to'], '/next') self.assertTrue(session['_saml_state'][logout.id]['sign']) # test unsigned logout request with self.app.test_request_context('/', method='GET'): tmp_sp_config['key_file'] = None tmp_sp_config['service']['sp']['logout_requests_signed'] = 'false' sp = auth.Saml(tmp_sp_config) # first need to be logged in, let's pretend session['_saml_identity'] = identity session['_saml_subject_id'] = 'id-1' resp = sp.logout(next_url='/next') self.assertEqual(resp.status_code, 302) self.assert_("SAMLRequest" in resp.headers['Location']) url = urlparse.urlparse(resp.headers['Location']) params = urlparse.parse_qs(url.query) self.assert_('SAMLRequest' in params) logout = samlp.logout_request_from_string( decode_base64_and_inflate(params['SAMLRequest'][0])) self.assertIsNone(logout.signature) # verify state cache shows signing off self.assertFalse(session['_saml_state'][logout.id]['sign'])
def test_logout_1(self): """ one IdP/AA logout from""" # information about the user from an IdP session_info = { "name_id": "123456", "issuer": "urn:mace:example.com:saml:roland:idp", "not_on_or_after": in_a_while(minutes=15), "ava": { "givenName": "Anders", "surName": "Andersson", "mail": "*****@*****.**" } } self.client.users.add_information_about_person(session_info) entity_ids = self.client.users.issuers_of_info("123456") assert entity_ids == ["urn:mace:example.com:saml:roland:idp"] resp = self.client.global_logout("123456", "Tired", in_a_while(minutes=5)) print resp assert resp assert len(resp) == 1 assert resp.keys() == entity_ids item = resp[entity_ids[0]] assert isinstance(item, tuple) assert item[0] == [('Content-type', 'text/html')] lead = "name=\"SAMLRequest\" value=\"" body = item[1][3] i = body.find(lead) i += len(lead) j = i + body[i:].find('"') info = body[i:j] xml_str = base64.b64decode(info) #xml_str = decode_base64_and_inflate(info) req = logout_request_from_string(xml_str) print req assert req.reason == "Tired" # def test_logout_2(self): # """ one IdP/AA with BINDING_SOAP, can't actually send something""" # # conf = config.SPConfig() # conf.load_file("server2_conf") # client = Saml2Client(conf) # # # information about the user from an IdP # session_info = { # "name_id": "123456", # "issuer": "urn:mace:example.com:saml:roland:idp", # "not_on_or_after": in_a_while(minutes=15), # "ava": { # "givenName": "Anders", # "surName": "Andersson", # "mail": "*****@*****.**" # } # } # client.users.add_information_about_person(session_info) # entity_ids = self.client.users.issuers_of_info("123456") # assert entity_ids == ["urn:mace:example.com:saml:roland:idp"] # destinations = client.config.single_logout_services(entity_ids[0], # BINDING_SOAP) # print destinations # assert destinations == ['http://*****:*****@example.com" # } # } # client.users.add_information_about_person(session_info_authn) # session_info_aa = { # "name_id": "123456", # "issuer": "urn:mace:example.com:saml:roland:aa", # "not_on_or_after": in_a_while(minutes=15), # "ava": { # "eduPersonEntitlement": "Foobar", # } # } # client.users.add_information_about_person(session_info_aa) # entity_ids = client.users.issuers_of_info("123456") # assert _leq(entity_ids, ["urn:mace:example.com:saml:roland:idp", # "urn:mace:example.com:saml:roland:aa"]) # resp = client.global_logout("123456", "Tired", in_a_while(minutes=5)) # print resp # assert resp # assert resp[0] # a session_id # assert resp[1] == '200 OK' # # HTTP POST # assert resp[2] == [('Content-type', 'text/html')] # assert resp[3][0] == '<head>' # assert resp[3][1] == '<title>SAML 2.0 POST</title>' # # state_info = client.state[resp[0]] # print state_info # assert state_info["entity_id"] == entity_ids[0] # assert state_info["subject_id"] == "123456" # assert state_info["reason"] == "Tired" # assert state_info["operation"] == "SLO" # assert state_info["entity_ids"] == entity_ids # assert state_info["sign"] == True # # def test_authz_decision_query(self): # conf = config.SPConfig() # conf.load_file("server3_conf") # client = Saml2Client(conf) # # AVA = {'mail': u'*****@*****.**', # 'eduPersonTargetedID': '95e9ae91dbe62d35198fbbd5e1fb0976', # 'displayName': u'Roland Hedberg', # 'uid': 'http://roland.hedberg.myopenid.com/'} # # sp_entity_id = "sp_entity_id" # in_response_to = "1234" # consumer_url = "http://example.com/consumer" # name_id = saml.NameID(saml.NAMEID_FORMAT_TRANSIENT, text="name_id") # policy = Policy() # ava = Assertion(AVA) # assertion = ava.construct(sp_entity_id, in_response_to, # consumer_url, name_id, # conf.attribute_converters, # policy, issuer=client._issuer()) # # adq = client.create_authz_decision_query_using_assertion("entity_id", # assertion, # "read", # "http://example.com/text") # # assert adq # print adq # assert adq.keyswv() != [] # assert adq.destination == "entity_id" # assert adq.resource == "http://example.com/text" # assert adq.action[0].text == "read" # # def test_request_to_discovery_service(self): # disc_url = "http://example.com/saml2/idp/disc" # url = discovery_service_request_url("urn:mace:example.com:saml:roland:sp", # disc_url) # print url # assert url == "http://example.com/saml2/idp/disc?entityID=urn%3Amace%3Aexample.com%3Asaml%3Aroland%3Asp" # # url = discovery_service_request_url( # self.client.config.entityid, # disc_url, # return_url= "http://example.org/saml2/sp/ds") # # print url # assert url == "http://example.com/saml2/idp/disc?entityID=urn%3Amace%3Aexample.com%3Asaml%3Aroland%3Asp&return=http%3A%2F%2Fexample.org%2Fsaml2%2Fsp%2Fds" # # def test_get_idp_from_discovery_service(self): # pdir = {"entityID": "http://example.org/saml2/idp/sso"} # params = urllib.urlencode(pdir) # redirect_url = "http://example.com/saml2/sp/disc?%s" % params # # entity_id = discovery_service_response(url=redirect_url) # assert entity_id == "http://example.org/saml2/idp/sso" # # pdir = {"idpID": "http://example.org/saml2/idp/sso"} # params = urllib.urlencode(pdir) # redirect_url = "http://example.com/saml2/sp/disc?%s" % params # # entity_id = discovery_service_response(url=redirect_url, # returnIDParam="idpID") # # assert entity_id == "http://example.org/saml2/idp/sso" # self.server.close_shelve_db() # # def test_unsolicited_response(self): # """ # # """ # self.server = Server("idp_conf") # # conf = config.SPConfig() # conf.load_file("server_conf") # self.client = Saml2Client(conf) # # for subject in self.client.users.subjects(): # self.client.users.remove_person(subject) # # IDP = "urn:mace:example.com:saml:roland:idp" # # ava = { "givenName": ["Derek"], "surName": ["Jeter"], # "mail": ["*****@*****.**"], "title": ["The man"]} # # resp_str = "%s" % self.server.create_authn_response( # identity=ava, # in_response_to="id1", # destination="http://lingon.catalogix.se:8087/", # sp_entity_id="urn:mace:example.com:saml:roland:sp", # name_id_policy=samlp.NameIDPolicy( # format=saml.NAMEID_FORMAT_PERSISTENT), # userid="*****@*****.**") # # resp_str = base64.encodestring(resp_str) # # self.client.allow_unsolicited = True # authn_response = self.client.authn_request_response( # {"SAMLResponse":resp_str}, ()) # # assert authn_response is not None # assert authn_response.issuer() == IDP # assert authn_response.response.assertion[0].issuer.text == IDP # session_info = authn_response.session_info() # # print session_info # assert session_info["ava"] == {'mail': ['*****@*****.**'], # 'givenName': ['Derek'], # 'surName': ['Jeter']} # assert session_info["issuer"] == IDP # assert session_info["came_from"] == "" # response = samlp.response_from_string(authn_response.xmlstr) # assert response.destination == "http://lingon.catalogix.se:8087/" # # # One person in the cache # assert len(self.client.users.subjects()) == 1 # self.server.close_shelve_db()