def test_assertion_with_authn_instant(): ava = {} ast = Assertion(ava) policy = Policy( { "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI, } } ) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) msg = ast.construct( "sp_entity_id", "in_response_to", "consumer_url", name_id, [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, authn_decl=ACD, authn_auth="authn_authn", authn_instant=1234567890, ) print msg assert msg.authn_statement[0].authn_instant == "2009-02-13T23:31:30Z"
def test_assertion_with_noop_attribute_conv(): ava = {"urn:oid:2.5.4.4": "Roland", "urn:oid:2.5.4.42": "Hedberg" } ast = Assertion(ava) policy = Policy({ "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) msg = ast.construct("sp_entity_id", "in_response_to", "consumer_url", name_id, [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, authn_decl=ACD , authn_auth="authn_authn") print(msg) for attr in msg.attribute_statement[0].attribute: assert attr.name_format == NAME_FORMAT_URI assert len(attr.attribute_value) == 1 if attr.name == "urn:oid:2.5.4.42": assert attr.attribute_value[0].text == "Hedberg" elif attr.name == "urn:oid:2.5.4.4": assert attr.attribute_value[0].text == "Roland"
def test_assertion_2(): AVA = {'mail': u'*****@*****.**', 'eduPersonTargetedID': 'http://lingon.ladok.umu.se:8090/idp!http://lingon.ladok.umu.se:8088/sp!95e9ae91dbe62d35198fbbd5e1fb0976', 'displayName': u'Roland Hedberg', 'uid': 'http://roland.hedberg.myopenid.com/'} ava = Assertion(AVA) policy = Policy( { "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) ava = ava.apply_policy( "", policy ) acs = ac_factory("attributemaps") attribute=from_local(acs, ava, policy.get_name_form("")) assert len(attribute) == 4 names = [attr.name for attr in attribute] assert _eq(names, ['urn:oid:0.9.2342.19200300.100.1.3', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'urn:oid:2.16.840.1.113730.3.1.241', 'urn:oid:0.9.2342.19200300.100.1.1'])
def post_auth(authData): for t in authData: if t[0] == 'Stripped-User-Name': userName = t[1][1:-1] elif t[0] == 'User-Password': userPassword = t[1][1:-1] identity = ldap_attributes(userName, userPassword) if identity == None: return radiusd.RLM_MODULE_FAIL indentityFiltered = {k: identity[k] for k in set(ATTRS) & set(identity.keys())} print {k: identity[k] for k in set(ATTRS) & set(identity.keys())} policy = Policy({ 'default': { 'lifetime': {'minutes': 60}, 'attribute_restrictions': None, 'name_form': NAME_FORMAT_URI } }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text='urn:mace:' + LDAP_SERVER) issuer = Issuer(text='moonshot.' + LDAP_SERVER, format=NAMEID_FORMAT_ENTITY) ast = Assertion(indentityFiltered) assertion = ast.construct('', '', '', name_id, [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer) assertion = str(assertion).replace('\n', '') attr = 'SAML-AAA-Assertion' result = (tuple([(attr, x) for x in eq_len_parts('%s' % assertion)])) return radiusd.RLM_MODULE_UPDATED, result, None
def test_assertion_with_authn_instant(): ava = {} ast = Assertion(ava) policy = Policy({ "default": { "lifetime": { "minutes": 240 }, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) farg = add_path( {}, ['subject', 'subject_confirmation', 'method', saml.SCM_BEARER]) add_path(farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'in_response_to', 'in_response_to']) add_path(farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'recipient', 'consumer_url']) msg = ast.construct("sp_entity_id", [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, authn_decl=ACD, authn_auth="authn_authn", authn_instant=1234567890, name_id=name_id, farg=farg) print(msg) assert msg.authn_statement[0].authn_instant == "2009-02-13T23:31:30Z"
def test_assertion_with_authn_instant(): ava = {} ast = Assertion(ava) policy = Policy({ "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) farg = add_path( {}, ['subject', 'subject_confirmation', 'method', saml.SCM_BEARER]) add_path( farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'in_response_to', 'in_response_to']) add_path( farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'recipient', 'consumer_url']) msg = ast.construct( "sp_entity_id", [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, authn_decl=ACD, authn_auth="authn_authn", authn_instant=1234567890, name_id=name_id, farg=farg) print(msg) assert msg.authn_statement[0].authn_instant == "2009-02-13T23:31:30Z"
def test_assertion_with_noop_attribute_conv(): ava = {"urn:oid:2.5.4.4": "Roland", "urn:oid:2.5.4.42": "Hedberg" } ast = Assertion(ava) policy = Policy({ "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) msg = ast.construct("sp_entity_id", "in_response_to", "consumer_url", name_id, [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, authn_decl=ACD , authn_auth="authn_authn") print msg for attr in msg.attribute_statement[0].attribute: assert attr.name_format == NAME_FORMAT_URI assert len(attr.attribute_value) == 1 if attr.name == "urn:oid:2.5.4.42": assert attr.attribute_value[0].text == "Hedberg" elif attr.name == "urn:oid:2.5.4.4": assert attr.attribute_value[0].text == "Roland"
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.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_assertion_with_zero_attributes(): ava = {} ast = Assertion(ava) policy = Policy({ "default": { "lifetime": { "minutes": 240 }, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) msg = ast.construct("sp_entity_id", "in_response_to", "consumer_url", name_id, [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, authn_decl=ACD, authn_auth="authn_authn") print(msg) assert msg.attribute_statement == []
def test_assertion_2(): AVA = {'mail': '*****@*****.**', 'eduPersonTargetedID': 'http://lingon.ladok.umu.se:8090/idp!http://lingon.ladok.umu.se:8088/sp!95e9ae91dbe62d35198fbbd5e1fb0976', 'displayName': 'Roland Hedberg', 'uid': 'http://roland.hedberg.myopenid.com/'} ava = Assertion(AVA) policy = Policy({ "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) ava = ava.apply_policy("", policy) acs = ac_factory(full_path("attributemaps")) attribute = from_local(acs, ava, policy.get_name_form("")) assert len(attribute) == 4 names = [attr.name for attr in attribute] assert _eq(names, ['urn:oid:0.9.2342.19200300.100.1.3', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'urn:oid:2.16.840.1.113730.3.1.241', 'urn:oid:0.9.2342.19200300.100.1.1'])
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.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 create_attribute_response(self, identity, in_response_to, destination, sp_entity_id, userid="", name_id=None, status=None, issuer=None, sign_assertion=False, sign_response=False, attributes=None): """ Create an attribute assertion response. :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param in_response_to: The session identifier of the request :param destination: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param userid: A identifier of the user :param name_id: The identifier of the subject :param status: The status of the response :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the whole response should be signed :param attributes: :return: A response instance """ if not name_id and userid: try: name_id = self.ident.construct_nameid(userid, self.config.policy, sp_entity_id) logger.warning("Unspecified NameID format") except Exception: pass to_sign = [] args = {} if identity: _issuer = self._issuer(issuer) ast = Assertion(identity) policy = self.config.getattr("policy", "aa") if policy: ast.apply_policy(sp_entity_id, policy) else: policy = Policy() if attributes: restr = restriction_from_attribute_spec(attributes) ast = filter_attribute_value_assertions(ast) assertion = ast.construct(sp_entity_id, in_response_to, destination, name_id, self.config.attribute_converters, policy, issuer=_issuer) if sign_assertion: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] args["assertion"] = assertion return self._response(in_response_to, destination, status, issuer, sign_response, to_sign, **args)
def create_aa_response(self, in_response_to, consumer_url, sp_entity_id, identity=None, userid="", name_id=None, status=None, issuer=None, sign_assertion=False, sign_response=False, attributes=None): """ Create an attribute assertion response. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param userid: A identifier of the user :param name_id: The identifier of the subject :param status: The status of the response :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the whole response should be signed :return: A response instance """ if not name_id and userid: try: name_id = self.ident.construct_nameid(self.conf.policy, userid, sp_entity_id, identity) logger.warning("Unspecified NameID format") except Exception: pass to_sign = [] args = {} if identity: _issuer = self.issuer(issuer) ast = Assertion(identity) policy = self.conf.getattr("policy", "aa") if policy: ast.apply_policy(sp_entity_id, policy) else: policy = Policy() if attributes: restr = restriction_from_attribute_spec(attributes) ast = filter_attribute_value_assertions(ast) assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer) if sign_assertion: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] args["assertion"] = assertion return self._response(in_response_to, consumer_url, status, issuer, sign_response, to_sign, **args)
def test_assertion_1(AVA): ava = Assertion(AVA[0]) print ava print ava.__dict__ policy = Policy({ "default": { "attribute_restrictions": { "givenName": ["^R.*"], } } }) ava = ava.apply_policy( "", policy ) print ava assert _eq(ava.keys(), []) ava = Assertion(AVA[1].copy()) ava = ava.apply_policy( "", policy ) assert _eq(ava.keys(), ["givenName"]) assert ava["givenName"] == ["Ryan"] ava = Assertion(AVA[3].copy()) ava = ava.apply_policy( "", policy ) assert _eq(ava.keys(), ["givenName"]) assert ava["givenName"] == ["Roland"]
def test_sign_then_encrypt_assertion2(self): # Begin with the IdPs side _sec = self.server.sec nameid_policy = samlp.NameIDPolicy( allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) asser = Assertion({"givenName": "Derek", "surName": "Jeter"}) assertion = asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") assertion.signature = sigver.pre_signature_part( assertion.id, _sec.my_cert, 1) sigass = _sec.sign_statement(assertion, class_name(assertion), key_file=self.client.sec.key_file, node_id=assertion.id) sigass = rm_xmltag(sigass) response = sigver.response_factory( in_response_to="_012345", destination="http://lingon.catalogix.se:8087/", status=s_utils.success_status_factory(), issuer=self.server._issuer(), encrypted_assertion=EncryptedAssertion()) xmldoc = "%s" % response # strangely enough I get different tags if I run this test separately # or as part of a bunch of tests. xmldoc = add_subelement(xmldoc, "EncryptedAssertion", sigass) enctext = _sec.crypto.encrypt_assertion(xmldoc, _sec.cert_file, pre_encryption_part()) #seresp = samlp.response_from_string(enctext) resp_str = base64.encodestring(enctext) # Now over to the client side resp = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"_012345": "http://foo.example.com/service"}) #assert resp.encrypted_assertion == [] assert resp.assertion assert resp.ava == {'givenName': ['Derek'], 'sn': ['Jeter']}
def test_sign_then_encrypt_assertion2(self): # Begin with the IdPs side _sec = self.server.sec nameid_policy = samlp.NameIDPolicy(allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) asser = Assertion({"givenName": "Derek", "surName": "Jeter"}) assertion = asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") assertion.signature = sigver.pre_signature_part( assertion.id, _sec.my_cert, 1) sigass = _sec.sign_statement(assertion, class_name(assertion), key_file=self.client.sec.key_file, node_id=assertion.id) sigass = rm_xmltag(sigass) response = sigver.response_factory( in_response_to="_012345", destination="https://www.example.com", status=s_utils.success_status_factory(), issuer=self.server._issuer(), encrypted_assertion=EncryptedAssertion() ) xmldoc = "%s" % response # strangely enough I get different tags if I run this test separately # or as part of a bunch of tests. xmldoc = add_subelement(xmldoc, "EncryptedAssertion", sigass) enctext = _sec.crypto.encrypt_assertion(xmldoc, _sec.cert_file, pre_encryption_part()) #seresp = samlp.response_from_string(enctext) resp_str = base64.encodestring(enctext) # Now over to the client side resp = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"_012345": "http://foo.example.com/service"}) #assert resp.encrypted_assertion == [] assert resp.assertion assert resp.ava == {'givenName': ['Derek'], 'sn': ['Jeter']}
def setup_assertion(self, authn, sp_entity_id, in_response_to, consumer_url, name_id, policy, _issuer, authn_statement, identity, best_effort, sign_response, add_subject=True): ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue, exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response)
def test_sign_then_encrypt_assertion2(self): # Begin with the IdPs side _sec = self.server.sec nameid_policy = samlp.NameIDPolicy( allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) asser = Assertion({"givenName": "Derek", "surName": "Jeter"}) assertion = asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") assertion.signature = sigver.pre_signature_part( assertion.id, _sec.my_cert, 1) sigass = _sec.sign_statement( assertion, class_name(assertion), #key_file="pki/mykey.pem", key_file="test.key", node_id=assertion.id) # Create an Assertion instance from the signed assertion _ass = saml.assertion_from_string(sigass) response = sigver.response_factory( in_response_to="_012345", destination="https://www.example.com", status=s_utils.success_status_factory(), issuer=self.server._issuer(), assertion=_ass) enctext = _sec.crypto.encrypt_assertion(response, _sec.cert_file, pre_encryption_part()) #seresp = samlp.response_from_string(enctext) resp_str = base64.encodestring(enctext) # Now over to the client side resp = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"_012345": "http://foo.example.com/service"}) #assert resp.encrypted_assertion == [] assert resp.assertion assert resp.ava == {'givenName': ['Derek'], 'sn': ['Jeter']}
def setup_assertion(self, authn, sp_entity_id, in_response_to, consumer_url, name_id, policy, _issuer, authn_statement, identity, best_effort, sign_response, add_subject=True): ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue as exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) if authn: # expected to be a dictionary # Would like to use dict comprehension but ... authn_args = dict([(AUTHN_DICT_MAP[k], v) for k, v in authn.items() if k in AUTHN_DICT_MAP]) assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, add_subject=add_subject, **authn_args) elif authn_statement: # Got a complete AuthnStatement assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, authn_statem=authn_statement, add_subject=add_subject) else: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, add_subject=add_subject) return assertion
def _authn_response(self, in_response_to, consumer_url, sp_entity_id, identity=None, name_id=None, status=None, authn=None, issuer=None, policy=None, sign_assertion=False, sign_response=False, best_effort=False, encrypt_assertion=False, encrypt_cert=None): """ Create a response. A layer of indirection. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param name_id: The identifier of the subject :param status: The status of the response :param authn: A dictionary containing information about the authn context. :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the response should be signed or not :param best_effort: Even if not the SPs demands can be met send a response. :return: A response instance """ to_sign = [] args = {} #if identity: _issuer = self._issuer(issuer) ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue, exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response)
def post_auth(authData): for t in authData: if t[0] == 'Stripped-User-Name': userName = t[1][1:-1] elif t[0] == 'User-Password': userPassword = t[1][1:-1] identity = ldap_attributes(userName, userPassword) if identity == None: return radiusd.RLM_MODULE_FAIL indentityFiltered = { k: identity[k] for k in set(ATTRS) & set(identity.keys()) } print {k: identity[k] for k in set(ATTRS) & set(identity.keys())} policy = Policy({ 'default': { 'lifetime': { 'minutes': 60 }, 'attribute_restrictions': None, 'name_form': NAME_FORMAT_URI } }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text='urn:mace:' + LDAP_SERVER) issuer = Issuer(text='moonshot.' + LDAP_SERVER, format=NAMEID_FORMAT_ENTITY) ast = Assertion(indentityFiltered) assertion = ast.construct('', '', '', name_id, [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer) assertion = str(assertion).replace('\n', '') attr = 'SAML-AAA-Assertion' result = (tuple([(attr, x) for x in eq_len_parts('%s' % assertion)])) return radiusd.RLM_MODULE_UPDATED, result, None
def setup_assertion(self, authn, sp_entity_id, in_response_to, consumer_url, name_id, policy, _issuer, authn_statement, identity, best_effort, sign_response, farg=None, **kwargs): """ Construct and return the Assertion :param authn: Authentication information :param sp_entity_id: :param in_response_to: The ID of the request this is an answer to :param consumer_url: The recipient of the assertion :param name_id: The NameID of the subject :param policy: Assertion policies :param _issuer: Issuer of the statement :param authn_statement: An AuthnStatement instance :param identity: Identity information about the Subject :param best_effort: Even if not the SPs demands can be met send a response. :param sign_response: Sign the response, only applicable if ErrorResponse :param kwargs: Extra keyword arguments :return: An Assertion instance """ ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue as exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) farg = self.update_farg(in_response_to, consumer_url, farg) if authn: # expected to be a dictionary # Would like to use dict comprehension but ... authn_args = dict( [(AUTHN_DICT_MAP[k], v) for k, v in authn.items() if k in AUTHN_DICT_MAP]) authn_args.update(kwargs) assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, farg=farg['assertion'], name_id=name_id, **authn_args) elif authn_statement: # Got a complete AuthnStatement assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, authn_statem=authn_statement, farg=farg['assertion'], name_id=name_id, **kwargs) else: assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, farg=farg['assertion'], name_id=name_id, **kwargs) return assertion
def _authn_response(self, in_response_to, consumer_url, sp_entity_id, identity=None, name_id=None, status=None, authn=None, issuer=None, policy=None, sign_assertion=False, sign_response=False, best_effort=False, encrypt_assertion=False, encrypt_cert=None, authn_statement=None): """ Create a response. A layer of indirection. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param name_id: The identifier of the subject :param status: The status of the response :param authn: A dictionary containing information about the authn context. :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the response should be signed or not :param best_effort: Even if not the SPs demands can be met send a response. :return: A response instance """ to_sign = [] args = {} #if identity: _issuer = self._issuer(issuer) ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue, exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response)
def test_assertion_with_noop_attribute_conv(): ava = {"urn:oid:2.5.4.4": "Roland", "urn:oid:2.5.4.42": "Hedberg"} ast = Assertion(ava) policy = Policy({ "default": { "lifetime": { "minutes": 240 }, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) farg = add_path( {}, ['subject', 'subject_confirmation', 'method', saml.SCM_BEARER]) add_path(farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'in_response_to', 'in_response_to']) add_path(farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'recipient', 'consumer_url']) msg = ast.construct("sp_entity_id", [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, farg=farg, authn_decl=ACD, name_id=name_id, authn_auth="authn_authn") print(msg) for attr in msg.attribute_statement[0].attribute: assert attr.name_format == NAME_FORMAT_URI assert len(attr.attribute_value) == 1 if attr.name == "urn:oid:2.5.4.42": assert attr.attribute_value[0].text == "Hedberg" elif attr.name == "urn:oid:2.5.4.4": assert attr.attribute_value[0].text == "Roland"
def test_assertion_2(): AVA = { "mail": u"*****@*****.**", "eduPersonTargetedID": "http://lingon.ladok.umu" ".se:8090/idp!http://lingon.ladok.umu" ".se:8088/sp!95e9ae91dbe62d35198fbbd5e1fb0976", "displayName": u"Roland Hedberg", "uid": "http://roland.hedberg.myopenid.com/", } ava = Assertion(AVA) policy = Policy( { "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI, } } ) ava = ava.apply_policy("", policy) acs = ac_factory(full_path("attributemaps")) attribute = from_local(acs, ava, policy.get_name_form("")) assert len(attribute) == 4 names = [attr.name for attr in attribute] assert _eq( names, [ "urn:oid:0.9.2342.19200300.100.1.3", "urn:oid:1.3.6.1.4.1.5923.1.1.1.10", "urn:oid:2.16.840.1.113730.3.1.241", "urn:oid:0.9.2342.19200300.100.1.1", ], )
def test_assertion_with_noop_attribute_conv(): ava = {"urn:oid:2.5.4.4": "Roland", "urn:oid:2.5.4.42": "Hedberg"} ast = Assertion(ava) policy = Policy({ "default": { "lifetime": {"minutes": 240}, "attribute_restrictions": None, # means all I have "name_form": NAME_FORMAT_URI }, }) name_id = NameID(format=NAMEID_FORMAT_TRANSIENT, text="foobar") issuer = Issuer(text="entityid", format=NAMEID_FORMAT_ENTITY) farg = add_path( {}, ['subject', 'subject_confirmation', 'method', saml.SCM_BEARER]) add_path( farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'in_response_to', 'in_response_to']) add_path( farg['subject']['subject_confirmation'], ['subject_confirmation_data', 'recipient', 'consumer_url']) msg = ast.construct( "sp_entity_id", [AttributeConverterNOOP(NAME_FORMAT_URI)], policy, issuer=issuer, farg=farg, authn_decl=ACD, name_id=name_id, authn_auth="authn_authn") print(msg) for attr in msg.attribute_statement[0].attribute: assert attr.name_format == NAME_FORMAT_URI assert len(attr.attribute_value) == 1 if attr.name == "urn:oid:2.5.4.42": assert attr.attribute_value[0].text == "Hedberg" elif attr.name == "urn:oid:2.5.4.4": assert attr.attribute_value[0].text == "Roland"
def setup_assertion(self, authn, sp_entity_id, in_response_to, consumer_url, name_id, policy, _issuer, authn_statement, identity, best_effort, sign_response, add_subject=True): ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue as exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) if authn: # expected to be a dictionary # Would like to use dict comprehension but ... authn_args = dict([ (AUTHN_DICT_MAP[k], v) for k, v in authn.items() if k in AUTHN_DICT_MAP]) assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, add_subject=add_subject, **authn_args) elif authn_statement: # Got a complete AuthnStatement assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, authn_statem=authn_statement, add_subject=add_subject) else: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, add_subject=add_subject) return assertion
def login(self): """ Login endpoint (verify user credentials) """ key = session['request_key'] if 'request_key' in session else None relay_state = session['relay_state'] if 'relay_state' in session else '' self.app.logger.debug('Request key: {}'.format(key)) if key and key in self.ticket: authn_request = self.ticket[key] sp_id = authn_request.message.issuer.text destination = None if authn_request.message.attribute_consuming_service_index is not None: acss = self.server.metadata.assertion_consumer_service( sp_id, authn_request.message.protocol_binding) for acs in acss: if acs.get( 'index' ) == authn_request.message.attribute_consuming_service_index: destination = acs.get('location') break self.app.logger.debug( 'AssertionConsumingServiceIndex Location: {}'.format( destination)) if destination is None: destination = authn_request.message.assertion_consumer_service_url self.app.logger.debug( 'AssertionConsumerServiceUrl: {}'.format(destination)) if destination is None: self._raise_error( 'Impossibile ricavare l\'url di risposta', 'Verificare la presenza e la correttezza dell\'AssertionConsumerServiceIndex, o in alternativa della coppia di attributi AssertionConsumerServiceURL e ProtocolBinding' ) spid_level = authn_request.message.requested_authn_context.authn_context_class_ref[ 0].text authn_info = self.authn_broker.pick( authn_request.message.requested_authn_context) callback, reference = authn_info[0] if request.method == 'GET': # inject extra data in form login based on spid level extra_challenge = callback(**{'key': key}) rendered_form = render_template( 'login.html', **{ 'action': url_for('login'), 'request_key': key, 'relay_state': relay_state, 'extra_challenge': extra_challenge }) return rendered_form, 200 # verify optional challenge based on spid level verified = callback(verify=True, **{ 'key': key, 'data': request.form }) if verified: # verify user credentials user_id, user = self.user_manager.get(request.form['username'], request.form['password'], sp_id) if user_id is not None: # setup response attribute_statement_on_response = self._config.get( 'attribute_statement_on_response') identity = user['attrs'] AUTHN = {"class_ref": spid_level, "authn_auth": spid_level} _data = dict(identity=identity, userid=user_id, in_response_to=authn_request.message.id, destination=destination, sp_entity_id=sp_id, authn=AUTHN, issuer=self.server.config.entityid, sign_alg=SIGN_ALG, digest_alg=DIGEST_ALG, sign_assertion=True) response = self.server.create_authn_response(**_data) http_args = self.server.apply_binding( BINDING_HTTP_POST, response, destination, response=True, sign=True, relay_state=relay_state) # Setup confirmation page data ast = Assertion(identity) policy = self.server.config.getattr("policy", "idp") ast.acs = self.server.config.getattr( "attribute_converters", "idp") res = ast.apply_policy(sp_id, policy, self.server.metadata) attrs = res.keys() attrs_list = '' for _attr in attrs: attrs_list = '{}<tr><td>{}</td></tr>'.format( attrs_list, _attr) self.responses[key] = http_args['data'] rendered_response = render_template( 'confirm.html', **{ 'destination_service': sp_id, 'lines': escape(prettify_xml(response)).splitlines(), 'attrs': attrs, 'action': '/continue-response', 'request_key': key }) return rendered_response, 200 return render_template('403.html'), 403
def test_sign_then_encrypt_assertion_advice(self): # Begin with the IdPs side _sec = self.server.sec nameid_policy = samlp.NameIDPolicy(allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) asser = Assertion({"givenName": "Derek", "surName": "Jeter"}) assertion = asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") a_asser = Assertion({"uid": "test01", "email": "*****@*****.**"}) a_assertion = a_asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") a_assertion.signature = sigver.pre_signature_part( a_assertion.id, _sec.my_cert, 1) assertion.advice = Advice() assertion.advice.encrypted_assertion = [] assertion.advice.encrypted_assertion.append(EncryptedAssertion()) assertion.advice.encrypted_assertion[0].add_extension_element(a_assertion) response = sigver.response_factory( in_response_to="_012345", destination="http://lingon.catalogix.se:8087/", status=s_utils.success_status_factory(), issuer=self.server._issuer() ) response.assertion.append(assertion) response = _sec.sign_statement("%s" % response, class_name(a_assertion), key_file=self.client.sec.key_file, node_id=a_assertion.id) #xmldoc = "%s" % response # strangely enough I get different tags if I run this test separately # or as part of a bunch of tests. #xmldoc = add_subelement(xmldoc, "EncryptedAssertion", sigass) node_xpath = ''.join(["/*[local-name()=\"%s\"]" % v for v in ["Response", "Assertion", "Advice", "EncryptedAssertion", "Assertion"]]) enctext = _sec.crypto.encrypt_assertion(response, _sec.cert_file, pre_encryption_part(), node_xpath=node_xpath) #seresp = samlp.response_from_string(enctext) resp_str = base64.encodestring(enctext) # Now over to the client side resp = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"_012345": "http://foo.example.com/service"}) #assert resp.encrypted_assertion == [] assert resp.assertion assert resp.assertion.advice assert resp.assertion.advice.assertion assert resp.ava == \ {'sn': ['Jeter'], 'givenName': ['Derek'], 'uid': ['test01'], 'email': ['*****@*****.**']}
def _authn_response(self, in_response_to, consumer_url, sp_entity_id, identity=None, name_id=None, status=None, authn=None, issuer=None, policy=None, sign_assertion=False, sign_response=False, best_effort=False, encrypt_assertion=False, encrypt_cert=None): """ Create a response. A layer of indirection. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param name_id: The identifier of the subject :param status: The status of the response :param authn: A dictionary containing information about the authn context. :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the response should be signed or not :param best_effort: Even if not the SPs demands can be met send a response. :return: A response instance """ to_sign = [] args = {} #if identity: _issuer = self._issuer(issuer) ast = Assertion(identity) if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue as exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) if authn: # expected to be a dictionary # Would like to use dict comprehension but ... authn_args = dict([ (AUTHN_DICT_MAP[k], v) for k, v in list(authn.items()) if k in AUTHN_DICT_MAP]) assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, **authn_args) else: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer) if sign_assertion: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] # Store which assertion that has been sent to which SP about which # subject. # self.cache.set(assertion.subject.name_id.text, # sp_entity_id, {"ava": identity, "authn": authn}, # assertion.conditions.not_on_or_after) args["assertion"] = assertion if self.support_AssertionIDRequest() or self.support_AuthnQuery(): self.session_db.store_assertion(assertion, to_sign) return self._response(in_response_to, consumer_url, status, issuer, sign_response, to_sign, encrypt_assertion=encrypt_assertion, encrypt_cert=encrypt_cert, **args)
def test_sign_then_encrypt_assertion_advice(self): # Begin with the IdPs side _sec = self.server.sec nameid_policy = samlp.NameIDPolicy( allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) asser = Assertion({"givenName": "Derek", "surName": "Jeter"}) assertion = asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") a_asser = Assertion({ "uid": "test01", "email": "*****@*****.**" }) a_assertion = a_asser.construct( self.client.config.entityid, "_012345", "http://lingon.catalogix.se:8087/", factory(saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT), policy=self.server.config.getattr("policy", "idp"), issuer=self.server._issuer(), attrconvs=self.server.config.attribute_converters, authn_class=INTERNETPROTOCOLPASSWORD, authn_auth="http://www.example.com/login") a_assertion.signature = sigver.pre_signature_part( a_assertion.id, _sec.my_cert, 1) assertion.advice = Advice() assertion.advice.encrypted_assertion = [] assertion.advice.encrypted_assertion.append(EncryptedAssertion()) assertion.advice.encrypted_assertion[0].add_extension_element( a_assertion) response = sigver.response_factory( in_response_to="_012345", destination="http://lingon.catalogix.se:8087/", status=s_utils.success_status_factory(), issuer=self.server._issuer()) response.assertion.append(assertion) response = _sec.sign_statement("%s" % response, class_name(a_assertion), key_file=self.client.sec.key_file, node_id=a_assertion.id) #xmldoc = "%s" % response # strangely enough I get different tags if I run this test separately # or as part of a bunch of tests. #xmldoc = add_subelement(xmldoc, "EncryptedAssertion", sigass) node_xpath = ''.join([ "/*[local-name()=\"%s\"]" % v for v in [ "Response", "Assertion", "Advice", "EncryptedAssertion", "Assertion" ] ]) enctext = _sec.crypto.encrypt_assertion(response, _sec.cert_file, pre_encryption_part(), node_xpath=node_xpath) #seresp = samlp.response_from_string(enctext) resp_str = base64.encodestring(enctext) # Now over to the client side resp = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"_012345": "http://foo.example.com/service"}) #assert resp.encrypted_assertion == [] assert resp.assertion assert resp.assertion.advice assert resp.assertion.advice.assertion assert resp.ava == \ {'sn': ['Jeter'], 'givenName': ['Derek'], 'uid': ['test01'], 'email': ['*****@*****.**']}
def _response( self, in_response_to, consumer_url=None, sp_entity_id=None, identity=None, name_id=None, status=None, sign=False, policy=Policy(), authn=None, authn_decl=None, issuer=None, ): """ Create a Response that adhers to the ??? profile. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param name_id: The identifier of the subject :param status: The status of the response :param sign: Whether the assertion should be signed or not :param policy: The attribute release policy for this instance :param authn: A 2-tuple denoting the authn class and the authn authority :param authn_decl: :param issuer: The issuer of the response :return: A Response instance """ to_sign = [] if not status: status = success_status_factory() _issuer = self.issuer(issuer) response = response_factory(issuer=_issuer, in_response_to=in_response_to, status=status) if consumer_url: response.destination = consumer_url if identity: ast = Assertion(identity) try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue, exc: return self.error_response(in_response_to, consumer_url, sp_entity_id, exc, name_id) if authn: # expected to be a 2-tuple class+authority (authn_class, authn_authn) = authn assertion = ast.construct( sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer, authn_class=authn_class, authn_auth=authn_authn, ) elif authn_decl: assertion = ast.construct( sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer, authn_decl=authn_decl, ) else: assertion = ast.construct( sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer, ) if sign: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] # Store which assertion that has been sent to which SP about which # subject. # self.cache.set(assertion.subject.name_id.text, # sp_entity_id, {"ava": identity, "authn": authn}, # assertion.conditions.not_on_or_after) response.assertion = assertion
def _authn_response(self, in_response_to, consumer_url, sp_entity_id, identity=None, name_id=None, status=None, authn=None, authn_decl=None, issuer=None, policy=None, sign_assertion=False, sign_response=False): """ Create a response. A layer of indirection. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param name_id: The identifier of the subject :param status: The status of the response :param authn: A 2-tuple denoting the authn class and the authn authority. :param authn_decl: :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the response should be signed or not :return: A response instance """ to_sign = [] args = {} if identity: _issuer = self.issuer(issuer) ast = Assertion(identity) if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue, exc: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) if authn: # expected to be a 2-tuple class+authority (authn_class, authn_authn) = authn assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer, authn_class=authn_class, authn_auth=authn_authn) elif authn_decl: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer, authn_decl=authn_decl) else: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.conf.attribute_converters, policy, issuer=_issuer) if sign_assertion: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] # Store which assertion that has been sent to which SP about which # subject. # self.cache.set(assertion.subject.name_id.text, # sp_entity_id, {"ava": identity, "authn": authn}, # assertion.conditions.not_on_or_after) args["assertion"] = assertion
def test_assertion_1(AVA): ava = Assertion(AVA[0]) print(ava) print(ava.__dict__) policy = Policy( {"default": { "attribute_restrictions": { "givenName": ["^R.*"], } }}) ava = ava.apply_policy("", policy) print(ava) assert _eq(list(ava.keys()), []) ava = Assertion(AVA[1].copy()) ava = ava.apply_policy("", policy) assert _eq(list(ava.keys()), ["givenName"]) assert ava["givenName"] == ["Ryan"] ava = Assertion(AVA[3].copy()) ava = ava.apply_policy("", policy) assert _eq(list(ava.keys()), ["givenName"]) assert ava["givenName"] == ["Roland"]
def create_attribute_response(self, identity, in_response_to, destination, sp_entity_id, userid="", name_id=None, status=None, issuer=None, sign_assertion=False, sign_response=False, attributes=None, sign_alg=None, digest_alg=None, farg=None, **kwargs): """ Create an attribute assertion response. :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param in_response_to: The session identifier of the request :param destination: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param userid: A identifier of the user :param name_id: The identifier of the subject :param status: The status of the response :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the whole response should be signed :param attributes: :param kwargs: To catch extra keyword arguments :return: A response instance """ policy = self.config.getattr("policy", "aa") if not name_id and userid: try: name_id = self.ident.construct_nameid(userid, policy, sp_entity_id) logger.warning("Unspecified NameID format") except Exception: pass to_sign = [] if identity: farg = self.update_farg(in_response_to, sp_entity_id, farg=farg) _issuer = self._issuer(issuer) ast = Assertion(identity) if policy: ast.apply_policy(sp_entity_id, policy, self.metadata) else: policy = Policy() if attributes: restr = restriction_from_attribute_spec(attributes) ast = filter_attribute_value_assertions(ast) assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, name_id=name_id, farg=farg['assertion']) if sign_assertion: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1, sign_alg=sign_alg, digest_alg=digest_alg) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] kwargs['sign_assertion'] = True kwargs["assertion"] = assertion if sp_entity_id: kwargs['sp_entity_id'] = sp_entity_id return self._response(in_response_to, destination, status, issuer, sign_response, to_sign, sign_alg=sign_alg, digest_alg=digest_alg, **kwargs)
def setup_assertion(self, authn, sp_entity_id, in_response_to, consumer_url, name_id, policy, _issuer, authn_statement, identity, best_effort, sign_response, farg=None, session_not_on_or_after=None, **kwargs): """ Construct and return the Assertion :param authn: Authentication information :param sp_entity_id: :param in_response_to: The ID of the request this is an answer to :param consumer_url: The recipient of the assertion :param name_id: The NameID of the subject :param policy: Assertion policies :param _issuer: Issuer of the statement :param authn_statement: An AuthnStatement instance :param identity: Identity information about the Subject :param best_effort: Even if not the SPs demands can be met send a response. :param sign_response: Sign the response, only applicable if ErrorResponse :param kwargs: Extra keyword arguments :return: An Assertion instance """ ast = Assertion(identity) ast.acs = self.config.getattr("attribute_converters", "idp") if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue as exc: if not best_effort: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) farg = self.update_farg(in_response_to, consumer_url, farg) if authn: # expected to be a dictionary # Would like to use dict comprehension but ... authn_args = dict( [(AUTHN_DICT_MAP[k], v) for k, v in authn.items() if k in AUTHN_DICT_MAP]) authn_args.update(kwargs) assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, farg=farg['assertion'], name_id=name_id, session_not_on_or_after=session_not_on_or_after, **authn_args) elif authn_statement: # Got a complete AuthnStatement assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, authn_statem=authn_statement, farg=farg['assertion'], name_id=name_id, **kwargs) else: assertion = ast.construct( sp_entity_id, self.config.attribute_converters, policy, issuer=_issuer, farg=farg['assertion'], name_id=name_id, session_not_on_or_after=session_not_on_or_after, **kwargs) return assertion
def login(self): """ Login endpoint (verify user credentials) """ key = session['request_key'] if 'request_key' in session else None relay_state = session['relay_state'] if 'relay_state' in session else '' self.app.logger.debug('Request key: {}'.format(key)) if key and key in self.ticket: authn_request = self.ticket[key] sp_id = authn_request.message.issuer.text destination = authn_request.message.assertion_consumer_service_url spid_level = authn_request.message.requested_authn_context.authn_context_class_ref[ 0].text authn_info = self.authn_broker.pick( authn_request.message.requested_authn_context) callback, reference = authn_info[0] if request.method == 'GET': # inject extra data in form login based on spid level extra_challenge = callback(**{'key': key}) return FORM_LOGIN.format(url_for('login'), key, relay_state, extra_challenge), 200 # verify optional challenge based on spid level verified = callback(verify=True, **{ 'key': key, 'data': request.form }) if verified: # verify user credentials user_id, user = self.user_manager.get(request.form['username'], request.form['password'], sp_id) if user_id is not None: # setup response attribute_statement_on_response = self._config.get( 'attribute_statement_on_response') identity = user['attrs'] AUTHN = {"class_ref": spid_level, "authn_auth": spid_level} _data = dict(identity=identity, userid=user_id, in_response_to=authn_request.message.id, destination=destination, sp_entity_id=sp_id, authn=AUTHN, issuer=self.server.config.entityid, sign_alg=SIGN_ALG, digest_alg=DIGEST_ALG, sign_assertion=True) response = self.server.create_authn_response(**_data) http_args = self.server.apply_binding( BINDING_HTTP_POST, response, destination, response=True, sign=True, relay_state=relay_state) # Setup confirmation page data ast = Assertion(identity) policy = self.server.config.getattr("policy", "idp") ast.acs = self.server.config.getattr( "attribute_converters", "idp") res = ast.apply_policy(sp_id, policy, self.server.metadata) attrs = res.keys() attrs_list = '' for _attr in attrs: attrs_list = '{}<tr><td>{}</td></tr>'.format( attrs_list, _attr) self.responses[key] = http_args['data'] return CONFIRM_PAGE.format(attrs_list, '/continue-response', key), 200 abort(403)
def _authn_response(self, in_response_to, consumer_url, sp_entity_id, identity=None, name_id=None, status=None, authn=None, issuer=None, policy=None, sign_assertion=False, sign_response=False): """ Create a response. A layer of indirection. :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param sp_entity_id: The entity identifier of the SP :param identity: A dictionary with attributes and values that are expected to be the bases for the assertion in the response. :param name_id: The identifier of the subject :param status: The status of the response :param authn: A dictionary containing information about the authn context. :param issuer: The issuer of the response :param sign_assertion: Whether the assertion should be signed or not :param sign_response: Whether the response should be signed or not :return: A response instance """ to_sign = [] args = {} if identity: _issuer = self._issuer(issuer) ast = Assertion(identity) if policy is None: policy = Policy() try: ast.apply_policy(sp_entity_id, policy, self.metadata) except MissingValue, exc: return self.create_error_response(in_response_to, consumer_url, exc, sign_response) if authn: # expected to be a dictionary if "decl" in authn: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, authn_decl=authn["decl"], authn_auth=authn["authn_auth"]) else: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer, authn_class=authn["class_ref"], authn_auth=authn["authn_auth"]) else: assertion = ast.construct(sp_entity_id, in_response_to, consumer_url, name_id, self.config.attribute_converters, policy, issuer=_issuer) if sign_assertion: assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1) # Just the assertion or the response and the assertion ? to_sign = [(class_name(assertion), assertion.id)] # Store which assertion that has been sent to which SP about which # subject. # self.cache.set(assertion.subject.name_id.text, # sp_entity_id, {"ava": identity, "authn": authn}, # assertion.conditions.not_on_or_after) args["assertion"] = assertion if self.support_AssertionIDRequest() or self.support_AuthnQuery(): self.session_db.store_assertion(assertion, to_sign)