diff --git a/src/idp_test/check.py b/src/idp_test/check.py index 5dc76e8..9de07ff 100644 --- a/src/idp_test/check.py +++ b/src/idp_test/check.py @@ -431,10 +431,10 @@ class VerifyNameIDPolicyUsage(Check): class VerifyNameIDMapping(Check): """ - Verify the nameID in the response is according to the provided - NameIDPolicy + Verify that a new NameID is issued and that it follows the + given policy. """ - id = "verify-name-id-policy-usage" + id = "verify-name-id-mapping" def _func(self, environ): response = environ["response"][-1].response @@ -455,6 +455,24 @@ class VerifyNameIDMapping(Check): return {} +class VerifySPProvidedID(Check): + """ + Verify that a the IdP allows the SP so set a SP provided ID + """ + id = "verify-sp-provided-id" + + def _func(self, environ): + response = environ["response"][-1].response + nip = environ["oper.args"]["new_id"] + nid = response.name_id + try: + assert nid.sp_provided_id == nip.new_id + except AssertionError: + self._message = "SP provided id not properly set" + self._status = WARNING + + return {} + def factory(id): for name, obj in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(obj): diff --git a/src/idp_test/saml2int.py b/src/idp_test/saml2int.py index dc2e50f..f8b0e6e 100644 --- a/src/idp_test/saml2int.py +++ b/src/idp_test/saml2int.py @@ -1,4 +1,7 @@ -from saml2 import BINDING_HTTP_REDIRECT, BINDING_URI, samlp, BINDING_PAOS +from saml2 import BINDING_HTTP_REDIRECT +from saml2 import BINDING_URI +from saml2 import samlp +from saml2 import BINDING_PAOS from saml2 import BINDING_SOAP from saml2 import BINDING_HTTP_POST from saml2.saml import NAMEID_FORMAT_PERSISTENT @@ -11,6 +14,7 @@ from idp_test.check import VerifyLogout from idp_test.check import VerifyContent from idp_test.check import VerifySuccessStatus from idp_test.check import VerifyNameIDMapping +from idp_test.check import VerifySPProvidedID from saml2.samlp import NameIDPolicy @@ -148,12 +152,26 @@ class ECP_AuthnRequest(AuthnRequest): # relay_state = rdict["header"][0].text # return {"SAMLRequest": message, "RelayState": relay_state} +class ManageNameIDRequest(Request): + request = "manage_name_id_request" + _args = {"binding": BINDING_SOAP, + "new_id": samlp.NewID("New identifier")} + + def __init__(self): + Request.__init__(self) + self.tests["post"].append(VerifySuccessStatus) + + def setup(self, environ): + resp = environ["response"][-1].response + assertion = resp.assertion[0] + self.args["name_id"] = assertion.subject.name_id + # ----------------------------------------------------------------------------- OPERATIONS = { 'basic-authn': { "name": 'Absolute basic SAML2 AuthnRequest', - "descr": ('AuthnRequest using HTTP-redirect'), + "descr": 'AuthnRequest using HTTP-redirect', "sequence": [AuthnRequest], "tests": {"pre": [CheckSaml2IntMetaData], "post": [CheckSaml2IntAttributes]} @@ -202,5 +220,9 @@ OPERATIONS = { 'nameid-mapping':{ "name": "Simple NameIDMapping request", "sequence":[AuthnRequest, NameIDMappingRequest] + }, + 'manage_nameid':{ + "name": "Setting the SP provided ID by using ManageNameID", + "sequence":[AuthnRequest, ManageNameIDRequest] } } \ No newline at end of file diff --git a/tests/idp/idp.py b/tests/idp/idp.py index ac30482..487d639 100755 --- a/tests/idp/idp.py +++ b/tests/idp/idp.py @@ -10,7 +10,10 @@ from hashlib import sha1 from urlparse import parse_qs from Cookie import SimpleCookie -from saml2 import server, BINDING_HTTP_ARTIFACT, BINDING_URI, BINDING_PAOS +from saml2 import server +from saml2 import BINDING_HTTP_ARTIFACT +from saml2 import BINDING_URI +from saml2 import BINDING_PAOS from saml2 import BINDING_SOAP from saml2 import BINDING_HTTP_REDIRECT from saml2 import BINDING_HTTP_POST @@ -25,8 +28,6 @@ from saml2.ident import Unknown from saml2.s_utils import rndstr from saml2.s_utils import PolicyError from saml2.saml import AUTHN_PASSWORD -from saml2.saml import NAMEID_FORMAT_PERSISTENT -from saml2.saml import NameID logger = logging.getLogger("saml2.idp") @@ -475,21 +476,24 @@ def kaka2user(kaka): def _mni(environ, start_response, user, query, binding, relay_state=""): logger.info("--- Manage Name ID Service ---") - req = IDP.parse_manage_name_id_response(query, binding) + req = IDP.parse_manage_name_id_request(query, binding) + request = req.message # Do the necessary stuff - in_response_to = req.message.id - name_id = NameID(format=NAMEID_FORMAT_PERSISTENT, text="foobar") + name_id = IDP.ident.handle_manage_name_id_request(request.name_id, + request.new_id, + request.new_encrypted_id, + request.terminate) - info = IDP.response_args(req) - _resp = IDP.create_manage_name_id_response(name_id, **info) + logger.debug("New NameID: %s" % name_id) + + _resp = IDP.create_manage_name_id_response(request) # It's using SOAP binding hinfo = IDP.apply_binding(binding, "%s" % _resp, "", relay_state, response=True) - resp = Response(hinfo["data"], - headers=dict2list_of_tuples(hinfo["headers"])) + resp = Response(hinfo["data"], headers=hinfo["headers"]) return resp(environ, start_response) def mni(environ, start_response, user):