Пример #1
0
class TestOICProvider(object):
    def setup_class(self):
        self.server = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB,
                               AUTHN_BROKER, USERINFO,
                               AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
                               keyjar=KEYJAR)

        self.cons = Consumer({}, CONSUMER_CONFIG, CLIENT_CONFIG,
                               server_info=SERVER_INFO, )
        self.cons.behaviour = {"request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]}
        self.cons.debug = True
        self.cons.keyjar[""] = KC_RSA

    def test_server_init(self):
        assert self.server
        assert self.server.authn_broker == AUTHN_BROKER
        print self.server.urlmap
        assert self.server.urlmap["client_1"] == ["https://example.com/authz"]

    def test_server_authorization_endpoint(self):
        bib = {"scope": ["openid"],
               "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
               "redirect_uri": "http://*****:*****@example.com"]
        req["response_types"] = ["code"]

        print req.to_dict()

        resp = self.server.registration_endpoint(request=req.to_json())

        print resp.message
        regresp = RegistrationResponse().deserialize(resp.message, "json")
        print regresp.keys()
        assert _eq(regresp.keys(), ['redirect_uris', 'contacts', 'application_type',
                                    'client_name', 'registration_client_uri',
                                    'client_secret_expires_at',
                                    'registration_access_token',
                                    'client_id', 'client_secret',
                                    'client_id_issued_at', 'response_types'])

    def test_provider_key_setup(self):
        provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None,
                            None, None, None, None, "")
        provider.baseurl = "http://www.example.com/"
        provider.key_setup("static", sig={"format": "jwk", "alg": "RSA"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/static/jwks"

    def _client_id(self, cdb):
        cid = None
        for k, item in cdb.items():
            if item in cdb.keys():
                cid = item
                break

        return cid

    def test_registered_redirect_uri_without_query_component(self):
        provider = Provider("FOO", {}, {}, None, None, None, None, "")
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])

        registration_req = rr.to_json()

        provider.registration_endpoint(request=registration_req)

        correct = [
            "http://example.org/cb",
            "http://example.org/cb/foo",
        ]
        faulty = [
            "http://example.org/foo",
            "http://example.com/cb",
            "http://example.org/cb?got=you",
            "http://example.org/cb/foo?got=you"
        ]

        cid = self._client_id(provider.cdb)

        for ruri in faulty:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code",
                                        scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
                assert False
            except RedirectURIError:
                pass

        for ruri in correct:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code", scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
            except RedirectURIError, err:
                print err
                assert False
Пример #2
0
class TestProvider(object):
    @pytest.fixture(autouse=True)
    def create_provider(self, session_db_factory):
        self.provider = Provider(SERVER_INFO["issuer"],
                                 session_db_factory(SERVER_INFO["issuer"]),
                                 CDB,
                                 AUTHN_BROKER,
                                 USERINFO,
                                 AUTHZ,
                                 verify_client,
                                 SYMKEY,
                                 urlmap=URLMAP,
                                 keyjar=KEYJAR)
        self.provider.baseurl = self.provider.name

        self.cons = Consumer(
            {},
            CONSUMER_CONFIG,
            CLIENT_CONFIG,
            server_info=SERVER_INFO,
        )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.cons.keyjar[""] = KC_RSA

    def test_providerinfo(self):
        self.provider.baseurl = 'http://example.com/path1/path2'
        resp = self.provider.create_providerinfo()
        assert resp.to_dict(
        )['authorization_endpoint'] == 'http://example.com/path1/path2/authorization'

    def test_providerinfo_trailing(self):
        self.provider.baseurl = 'http://example.com/path1/path2/'
        resp = self.provider.create_providerinfo()
        assert resp.to_dict(
        )['authorization_endpoint'] == 'http://example.com/path1/path2/authorization'

    def test_authorization_endpoint(self):
        bib = {
            "scope": ["openid"],
            "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
            "redirect_uri": "http://*****:*****@patch('oic.oic.provider.utc_time_sans_frac', Mock(return_value=123456))
    def test_client_secret_expiration_time(self):
        exp_time = self.provider.client_secret_expiration_time()
        assert exp_time == 209856

    def test_registration_endpoint(self):
        req = RegistrationRequest()

        req["application_type"] = "web"
        req["client_name"] = "My super service"
        req["redirect_uris"] = ["http://example.com/authz"]
        req["contacts"] = ["*****@*****.**"]
        req["response_types"] = ["code"]

        resp = self.provider.registration_endpoint(request=req.to_json())

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(), [
            'redirect_uris', 'contacts', 'application_type', 'client_name',
            'registration_client_uri', 'client_secret_expires_at',
            'registration_access_token', 'client_id', 'client_secret',
            'client_id_issued_at', 'response_types'
        ])

    def test_registration_endpoint_unicode(self):
        data = 'application_type=web&client_name=M%C3%A1+supe%C5%99+service&' \
               'redirect_uris=http%3A%2F%2Fexample.com%2Fauthz&response_types=code'
        resp = self.provider.registration_endpoint(request=data)

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(), [
            'redirect_uris', 'application_type', 'client_name',
            'registration_client_uri', 'client_secret_expires_at',
            'registration_access_token', 'client_id', 'client_secret',
            'client_id_issued_at', 'response_types'
        ])

    def test_registration_endpoint_with_non_https_redirect_uri_implicit_flow(
            self):
        params = {
            "application_type": "web",
            "redirect_uris": ["http://example.com/authz"],
            "response_types": ["id_token", "token"]
        }
        req = RegistrationRequest(**params)
        resp = self.provider.registration_endpoint(request=req.to_json())

        assert resp.status == "400 Bad Request"
        error = json.loads(resp.message)
        assert error["error"] == "invalid_redirect_uri"

    def test_verify_redirect_uris_with_https_code_flow(self):
        params = {
            "application_type": "web",
            "redirect_uris": ["http://example.com/authz"],
            "response_types": ["code"]
        }
        request = RegistrationRequest(**params)
        verified_uris = self.provider.verify_redirect_uris(request)
        assert verified_uris == [("http://example.com/authz", None)]

    def test_verify_redirect_uris_with_non_https_redirect_uri_implicit_flow(
            self):
        params = {
            "application_type": "web",
            "redirect_uris": ["http://example.com/authz"],
            "response_types": ["id_token", "token"]
        }
        request = RegistrationRequest(**params)

        with pytest.raises(InvalidRedirectURIError) as exc_info:
            self.provider.verify_redirect_uris(request)

        assert str(exc_info.value) == "None https redirect_uri not allowed"

    def test_provider_key_setup(self, tmpdir, session_db_factory):
        path = tmpdir.strpath
        provider = Provider("pyoicserv",
                            session_db_factory(SERVER_INFO["issuer"]), None,
                            None, None, None, None, None)
        provider.baseurl = "http://www.example.com"
        provider.key_setup(path, path, sig={"format": "jwk", "alg": "RSA"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/{}/jwks".format(
            path)

    @pytest.mark.parametrize("uri", [
        "http://example.org/foo", "http://example.com/cb",
        "http://example.org/cb?got=you", "http://example.org/cb/foo?got=you"
    ])
    def test_verify_redirect_uri_faulty_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()

        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb",
    ])
    def test_verify_redirect_uri_correct_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        self.provider._verify_redirect_uri(areq)

    def test_verify_sector_identifier_nonreachable(self):
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET, "https://example.com", status=404)
            message = "Couldn't open sector_identifier_uri"
            with pytest.raises(InvalidSectorIdentifier, message=message):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 0

    def test_verify_sector_identifier_error(self):
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        error = ConnectionError('broken connection')
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET, "https://example.com", body=error)
            with pytest.raises(InvalidSectorIdentifier,
                               message="Couldn't open sector_identifier_uri"):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 2
        # First log record is from server...
        assert logcap.records[1].msg == error

    def test_verify_sector_identifier_malformed(self):
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        body = "This is not the JSON you are looking for"
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET, "https://example.com", body=body)
            with pytest.raises(
                    InvalidSectorIdentifier,
                    message="Error deserializing sector_identifier_uri content"
            ):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 1
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == (body, )

    def test_verify_sector_identifier_ru_missing_in_si(self):
        """Redirect_uris is not present in the sector_identifier_uri content."""
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com",
                                 redirect_uris=["http://example.com/missing"])
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET,
                     "https://example.com",
                     body=json.dumps(["http://example.com/present"]))
            with pytest.raises(
                    InvalidSectorIdentifier,
                    message="redirect uri missing from sector_identifiers"):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 2
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == ('["http://example.com/present"]', )
        assert logcap.records[1].msg == "redirect_uris: %s"
        assert logcap.records[1].args == (["http://example.com/missing"], )

    def test_verify_sector_identifier_ru_missing(self):
        """Redirect_uris is not present in the request."""
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        redirects = ["http://example.com/present"]

        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET,
                     "https://example.com",
                     body=json.dumps(redirects))
            si_redirects, si_url = self.provider._verify_sector_identifier(rr)

        assert si_url == "https://example.com"
        assert si_redirects == redirects
        assert len(logcap.records) == 1
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == ('["http://example.com/present"]', )

    def test_verify_sector_identifier_ru_ok(self):
        """Redirect_uris is present in the sector_identifier_uri content."""
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com",
                                 redirect_uris=["http://example.com/present"])
        redirects = ["http://example.com/present"]

        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET,
                     "https://example.com",
                     body=json.dumps(redirects))
            si_redirects, si_url = self.provider._verify_sector_identifier(rr)

        assert si_url == "https://example.com"
        assert si_redirects == redirects
        assert len(logcap.records) == 2
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == ('["http://example.com/present"]', )
        assert logcap.records[1].msg == "redirect_uris: %s"
        assert logcap.records[1].args == (["http://example.com/present"], )

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb", "http://example.org/cb?got=you",
        "http://example.org/cb?foo=you"
        "http://example.org/cb?foo=bar&got=you",
        "http://example.org/cb?foo=you&foo=bar"
    ])
    def test_registered_redirect_uri_faulty_with_query_component(self, uri):
        rr = RegistrationRequest(
            operation="register",
            redirect_uris=["http://example.org/cb?foo=bar"],
            response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    scope="openid",
                                    response_type="code")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    def test_registered_redirect_uri_correct_with_query_component(self):
        rr = RegistrationRequest(
            operation="register",
            redirect_uris=["http://example.org/cb?foo=bar"],
            response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(
            redirect_uri="http://example.org/cb?foo=bar",
            client_id=cid,
            scope="openid",
            response_type="code")

        self.provider._verify_redirect_uri(areq)

    def test_verify_redirect_uri_native_http_localhost(self):
        areq = RegistrationRequest(redirect_uris=["http://localhost/cb"],
                                   application_type='native')

        self.provider.verify_redirect_uris(areq)

    def test_verify_redirect_uri_native_loopback(self):
        areq = RegistrationRequest(redirect_uris=["http://127.0.0.1/cb"],
                                   application_type='native')

        self.provider.verify_redirect_uris(areq)

    def test_verify_redirect_uri_native_http_non_localhost(self):
        areq = RegistrationRequest(redirect_uris=["http://example.org/cb"],
                                   application_type='native')

        try:
            self.provider.verify_redirect_uris(areq)
        except InvalidRedirectURIError:
            assert True

    def test_verify_redirect_uri_native_custom(self):
        areq = RegistrationRequest(
            redirect_uris=["com.example.app:/oauth2redirect"],
            application_type='native')

        self.provider.verify_redirect_uris(areq)

    def test_verify_redirect_uri_native_https(self):
        areq = RegistrationRequest(redirect_uris=["https://example.org/cb"],
                                   application_type='native')

        try:
            self.provider.verify_redirect_uris(areq)
        except InvalidRedirectURIError:
            assert True

    def test_read_registration(self):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/new"],
                                 response_types=["code"])
        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)

        authn = ' '.join(['Bearer', regresp['registration_access_token']])
        query = '='.join(['client_id', regresp['client_id']])
        resp = self.provider.read_registration(authn, query)

        assert json.loads(resp.message) == regresp.to_dict()

    def test_read_registration_wrong_authn(self):
        resp = self.provider.read_registration('wrong string', 'request')
        assert resp.status == '400 Bad Request'
        assert json.loads(resp.message) == {
            'error': 'invalid_request',
            'error_description': None
        }

    def test_key_rollover(self):
        provider2 = Provider("FOOP", {}, {}, None, None, None, None, None)
        provider2.keyjar = KEYJAR
        # Number of KeyBundles
        assert len(provider2.keyjar.issuer_keys[""]) == 1
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 2
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 3
        provider2.remove_inactive_keys(-1)
        assert len(provider2.keyjar.issuer_keys[""]) == 2

    def test_endsession_endpoint(self):
        resp = self.provider.endsession_endpoint("")
        self._assert_cookies_expired(resp.headers)

        # End session not allowed if no cookie is sent (can't determine session)
        resp = self.provider.endsession_endpoint("", cookie="FAIL")
        assert resp.status == "400 Bad Request"

    def test_endsession_endpoint_with_id_token_hint(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        id_token_hint = id_token.to_jwt(algorithm="none")
        resp = self.provider.endsession_endpoint(
            urlencode({"id_token_hint": id_token_hint}))
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_endsession_endpoint_with_post_logout_redirect_uri(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        post_logout_redirect_uri = \
            CDB[CLIENT_CONFIG["client_id"]]["post_logout_redirect_uris"][0][0]
        resp = self.provider.endsession_endpoint(
            urlencode({"post_logout_redirect_uri": post_logout_redirect_uri}))
        assert isinstance(resp, SeeOther)
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_session_state_in_auth_req_for_session_support(
            self, session_db_factory):
        provider = Provider(SERVER_INFO["issuer"],
                            session_db_factory(SERVER_INFO["issuer"]),
                            CDB,
                            AUTHN_BROKER,
                            USERINFO,
                            AUTHZ,
                            verify_client,
                            SYMKEY,
                            urlmap=URLMAP,
                            keyjar=KEYJAR)

        provider.capabilities.update(
            {"check_session_iframe": "https://op.example.com/check_session"})

        req_args = {
            "scope": ["openid"],
            "redirect_uri": "http://localhost:8087/authz",
            "response_type": ["code"],
            "client_id": "number5"
        }
        areq = AuthorizationRequest(**req_args)
        resp = provider.authorization_endpoint(request=areq.to_urlencoded())
        aresp = self.cons.parse_response(AuthorizationResponse,
                                         resp.message,
                                         sformat="urlencoded")
        assert "session_state" in aresp

    def _assert_cookies_expired(self, http_headers):
        cookies_string = ";".join(
            [c[1] for c in http_headers if c[0] == "Set-Cookie"])
        all_cookies = SimpleCookie()

        try:
            cookies_string = cookies_string.decode()
        except (AttributeError, UnicodeDecodeError):
            pass

        all_cookies.load(cookies_string)

        now = datetime.datetime.utcnow()  #
        for c in [
                self.provider.cookie_name, self.provider.session_cookie_name
        ]:
            dt = datetime.datetime.strptime(all_cookies[c]["expires"],
                                            "%a, %d-%b-%Y %H:%M:%S GMT")
            assert dt < now  # make sure the cookies have expired to be cleared

    def _auth_with_id_token(self):
        state, location = self.cons.begin("openid",
                                          "id_token",
                                          path="http://localhost:8087")
        resp = self.provider.authorization_endpoint(
            request=location.split("?")[1])
        aresp = self.cons.parse_response(AuthorizationResponse,
                                         resp.message,
                                         sformat="urlencoded")
        return aresp["id_token"]

    def test_id_token_RS512_sign(self):
        self.provider.capabilities['id_token_signing_alg_values_supported'] = [
            'RS512'
        ]
        self.provider.build_jwx_def()
        id_token = self._auth_with_id_token()
        assert id_token.jws_header['alg'] == "RS512"

    def test_refresh_access_token_request(self):
        authreq = AuthorizationRequest(state="state",
                                       redirect_uri="http://example.com/authz",
                                       client_id=CLIENT_ID,
                                       response_type="code",
                                       scope=["openid", 'offline_access'],
                                       prompt='consent')

        _sdb = self.provider.sdb
        sid = _sdb.access_token.key(user="******", areq=authreq)
        access_grant = _sdb.access_token(sid=sid)
        ae = AuthnEvent("user", "salt")
        _sdb[sid] = {
            "oauth_state": "authz",
            "authn_event": ae.to_json(),
            "authzreq": authreq.to_json(),
            "client_id": CLIENT_ID,
            "code": access_grant,
            "code_used": False,
            "scope": ["openid", 'offline_access'],
            "redirect_uri": "http://example.com/authz",
        }
        _sdb.do_sub(sid, "client_salt")

        # Construct Access token request
        areq = AccessTokenRequest(code=access_grant,
                                  client_id=CLIENT_ID,
                                  redirect_uri="http://example.com/authz",
                                  client_secret=CLIENT_SECRET,
                                  grant_type='authorization_code')

        txt = areq.to_urlencoded()

        resp = self.provider.token_endpoint(request=txt)
        atr = AccessTokenResponse().deserialize(resp.message, "json")

        rareq = RefreshAccessTokenRequest(grant_type="refresh_token",
                                          refresh_token=atr['refresh_token'],
                                          client_id=CLIENT_ID,
                                          client_secret=CLIENT_SECRET,
                                          scope=['openid'])

        resp = self.provider.token_endpoint(request=rareq.to_urlencoded())
        atr2 = AccessTokenResponse().deserialize(resp.message, "json")
        assert atr2['access_token'] != atr['access_token']
        assert atr2['refresh_token'] == atr['refresh_token']
        assert atr2['token_type'] == 'Bearer'
Пример #3
0
class TestProvider(object):
    @pytest.fixture(autouse=True)
    def create_provider(self):
        self.provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]),
                                 CDB,
                                 AUTHN_BROKER, USERINFO,
                                 AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
                                 keyjar=KEYJAR)
        self.provider.baseurl = self.provider.name

        self.cons = Consumer({}, CONSUMER_CONFIG, CLIENT_CONFIG,
                             server_info=SERVER_INFO, )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]}
        self.cons.keyjar[""] = KC_RSA

    def test_authorization_endpoint(self):
        bib = {"scope": ["openid"],
               "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
               "redirect_uri": "http://*****:*****@example.com"]
        req["response_types"] = ["code"]

        resp = self.provider.registration_endpoint(request=req.to_json())

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(),
                   ['redirect_uris', 'contacts', 'application_type',
                    'client_name', 'registration_client_uri',
                    'client_secret_expires_at',
                    'registration_access_token',
                    'client_id', 'client_secret',
                    'client_id_issued_at', 'response_types'])

    def test_registration_endpoint_with_non_https_redirect_uri_implicit_flow(
            self):
        params = {"application_type": "web",
                  "redirect_uris": ["http://example.com/authz"],
                  "response_types": ["id_token", "token"]}
        req = RegistrationRequest(**params)
        resp = self.provider.registration_endpoint(request=req.to_json())

        assert resp.status == "400 Bad Request"
        error = json.loads(resp.message)
        assert error["error"] == "invalid_redirect_uri"

    def test_verify_redirect_uris_with_https_code_flow(self):
        params = {"application_type": "web",
                  "redirect_uris": ["http://example.com/authz"],
                  "response_types": ["code"]}
        request = RegistrationRequest(**params)
        verified_uris = self.provider._verify_redirect_uris(request)
        assert verified_uris == [("http://example.com/authz", None)]

    def test_verify_redirect_uris_with_non_https_redirect_uri_implicit_flow(self):
        params = {"application_type": "web",
                  "redirect_uris": ["http://example.com/authz"],
                  "response_types": ["id_token", "token"]}
        request = RegistrationRequest(**params)

        with pytest.raises(InvalidRedirectURIError) as exc_info:
            self.provider._verify_redirect_uris(request)

        assert str(exc_info.value) == "None https redirect_uri not allowed"

    @pytest.mark.network
    def test_registration_endpoint_openid4us(self):
        req = RegistrationRequest(
            **{'token_endpoint_auth_method': u'client_secret_post',
               'redirect_uris': [
                   u'https://connect.openid4.us:5443/phpRp/index.php/callback',
                   u'https://connect.openid4.us:5443/phpRp/authcheck.php/authcheckcb'],
               'jwks_uri': u'https://connect.openid4.us:5443/phpRp/rp/rp.jwk',
               'userinfo_encrypted_response_alg': u'RSA1_5',
               'contacts': [u'*****@*****.**'],
               'userinfo_encrypted_response_enc': u'A128CBC-HS256',
               'application_type': u'web',
               'client_name': u'ABRP-17',
               'grant_types': [u'authorization_code', u'implicit'],
               'post_logout_redirect_uris': [
                   u'https://connect.openid4.us:5443/phpRp/index.php/logoutcb'],
               'subject_type': u'public',
               'response_types': [u'code', u'token', u'id_token', u'code token',
                                  u'code id_token', u'id_token token',
                                  u'code id_token token'],
               'policy_uri': u'https://connect.openid4.us:5443/phpRp/index.php/policy',
               'logo_uri': u'https://connect.openid4.us:5443/phpRp/media/logo.png'})

        resp = self.provider.registration_endpoint(request=req.to_json())

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(), list(req.keys()) +
                   ['registration_client_uri',
                    'client_secret_expires_at',
                    'registration_access_token',
                    'client_id', 'client_secret',
                    'client_id_issued_at'])

    def test_provider_key_setup(self, tmpdir):
        path = tmpdir.strpath
        provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None,
                            None, None, None, None, "")
        provider.baseurl = "http://www.example.com"
        provider.key_setup(path, path, sig={"format": "jwk", "alg": "RSA"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/{}/jwks".format(
            path)

    @pytest.mark.parametrize("uri", [
        "http://example.org/foo",
        "http://example.com/cb",
        "http://example.org/cb?got=you",
        "http://example.org/cb/foo?got=you"
    ])
    def test_verify_redirect_uri_faulty_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()

        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb",
        "http://example.org/cb/foo"
    ])
    def test_verify_redirect_uri_correct_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        self.provider._verify_redirect_uri(areq)

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb",
        "http://example.org/cb/foo",
        "http://example.org/cb?got=you",
        "http://example.org/cb?foo=you"
        "http://example.org/cb?foo=bar&got=you",
        "http://example.org/cb?foo=you&foo=bar"
    ])
    def test_registered_redirect_uri_faulty_with_query_component(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=[
                                     "http://example.org/cb?foo=bar"],
                                 response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    scope="openid",
                                    response_type="code")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    def test_registered_redirect_uri_correct_with_query_component(self):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=[
                                     "http://example.org/cb?foo=bar"],
                                 response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(
            redirect_uri="http://example.org/cb?foo=bar",
            client_id=cid, scope="openid",
            response_type="code")

        self.provider._verify_redirect_uri(areq)

    def test_key_rollover(self):
        provider2 = Provider("FOOP", {}, {}, None, None, None, None, "")
        provider2.keyjar = KEYJAR
        # Number of KeyBundles
        assert len(provider2.keyjar.issuer_keys[""]) == 1
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 2
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 3
        provider2.remove_inactive_keys(-1)
        assert len(provider2.keyjar.issuer_keys[""]) == 2

    def test_endsession_endpoint(self):
        resp = self.provider.endsession_endpoint("")
        self._assert_cookies_expired(resp.headers)

        # End session not allowed if no cookie is sent (can't determine session)
        resp = self.provider.endsession_endpoint("", cookie="FAIL")
        assert resp.status == "400 Bad Request"

    def test_endsession_endpoint_with_id_token_hint(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        id_token_hint = id_token.to_jwt(algorithm="none")
        resp = self.provider.endsession_endpoint(
            urlencode({"id_token_hint": id_token_hint}))
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_endsession_endpoint_with_post_logout_redirect_uri(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        post_logout_redirect_uri = \
            CDB[CLIENT_CONFIG["client_id"]]["post_logout_redirect_uris"][0][0]
        resp = self.provider.endsession_endpoint(urlencode(
            {"post_logout_redirect_uri": post_logout_redirect_uri}))
        assert isinstance(resp, Redirect)
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_session_state_in_auth_req_for_session_support(self):
        provider = Provider("foo", SessionDB(SERVER_INFO["issuer"]), CDB,
                            AUTHN_BROKER, USERINFO,
                            AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
                            keyjar=KEYJAR, capabilities={
                "check_session_iframe": "https://op.example.com/check_session"})

        req_args = {"scope": ["openid"],
                    "redirect_uri": "http://localhost:8087/authz",
                    "response_type": ["code"],
                    "client_id": "a1b2c3"
                    }
        areq = AuthorizationRequest(**req_args)
        resp = provider.authorization_endpoint(
            request=areq.to_urlencoded())
        aresp = self.cons.parse_response(AuthorizationResponse, resp.message,
                                         sformat="urlencoded")
        assert "session_state" in aresp

    def _assert_cookies_expired(self, http_headers):
        cookies_string = ";".join(
            [c[1] for c in http_headers if c[0] == "Set-Cookie"])
        all_cookies = SimpleCookie()
        all_cookies.load(cookies_string)

        now = datetime.datetime.now()
        for c in [self.provider.cookie_name, self.provider.session_cookie_name]:
            dt = datetime.datetime.strptime(all_cookies[c]["expires"],
                                            "%a, %d-%b-%Y %H:%M:%S GMT")
            assert dt < now  # make sure the cookies have expired to be cleared

    def _auth_with_id_token(self):
        state, location = self.cons.begin("openid", "id_token",
                                          path="http://localhost:8087")
        resp = self.provider.authorization_endpoint(
            request=location.split("?")[1])
        aresp = self.cons.parse_response(AuthorizationResponse, resp.message,
                                         sformat="urlencoded")
        return aresp["id_token"]
Пример #4
0
class TestOICProvider(object):
    def setup_class(self):
        self.server = Provider("pyoicserv",
                               SessionDB(SERVER_INFO["issuer"]),
                               CDB,
                               AUTHN_BROKER,
                               USERINFO,
                               AUTHZ,
                               verify_client,
                               SYMKEY,
                               urlmap=URLMAP,
                               keyjar=KEYJAR)

        self.cons = Consumer(
            {},
            CONSUMER_CONFIG,
            CLIENT_CONFIG,
            server_info=SERVER_INFO,
        )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.cons.debug = True
        self.cons.keyjar[""] = KC_RSA

    def test_server_init(self):
        assert self.server
        assert self.server.authn_broker == AUTHN_BROKER
        print self.server.urlmap
        assert self.server.urlmap["client_1"] == ["https://example.com/authz"]

    def test_server_authorization_endpoint(self):
        bib = {
            "scope": ["openid"],
            "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
            "redirect_uri": "http://*****:*****@example.com"]
        req["response_types"] = ["code"]

        print req.to_dict()

        resp = self.server.registration_endpoint(request=req.to_json())

        print resp.message
        regresp = RegistrationResponse().deserialize(resp.message, "json")
        print regresp.keys()
        assert _eq(regresp.keys(), [
            'redirect_uris', 'contacts', 'application_type', 'client_name',
            'registration_client_uri', 'client_secret_expires_at',
            'registration_access_token', 'client_id', 'client_secret',
            'client_id_issued_at', 'response_types'
        ])

    def test_provider_key_setup(self):
        provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]),
                            None, None, None, None, None, "")
        provider.baseurl = "http://www.example.com/"
        provider.key_setup("static", sig={"format": "jwk", "alg": "RSA"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/static/jwks"

    def _client_id(self, cdb):
        cid = None
        for k, item in cdb.items():
            if item in cdb.keys():
                cid = item
                break

        return cid

    def test_registered_redirect_uri_without_query_component(self):
        provider = Provider("FOO", {}, {}, None, None, None, None, "")
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])

        registration_req = rr.to_json()

        provider.registration_endpoint(request=registration_req)

        correct = [
            "http://example.org/cb",
            "http://example.org/cb/foo",
        ]
        faulty = [
            "http://example.org/foo", "http://example.com/cb",
            "http://example.org/cb?got=you",
            "http://example.org/cb/foo?got=you"
        ]

        cid = self._client_id(provider.cdb)

        for ruri in faulty:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code",
                                        scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
                assert False
            except RedirectURIError:
                pass

        for ruri in correct:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code",
                                        scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
            except RedirectURIError, err:
                print err
                assert False