예제 #1
0
    def test_faulty_id_token(self):
        _faulty_signed_jwt = self._faulty_id_token()

        with pytest.raises(BadSignature):
            IdToken().from_jwt(_faulty_signed_jwt, key=[SYMKey(key="TestPassword")])

        # What if no verification key is given ?
        # Should also result in an exception
        with pytest.raises(MissingSigningKey):
            IdToken().from_jwt(_faulty_signed_jwt)
예제 #2
0
def test_verify_id_token_missing_c_hash():
    code = "AccessCode1"

    idt = IdToken(
        **{
            "sub": "553df2bcf909104751cfd8b2",
            "aud": ["5542958437706128204e0000", "554295ce3770612820620000"],
            "auth_time": 1441364872,
            "azp": "554295ce3770612820620000",
        })

    kj = KeyJar()
    kj.add_symmetric("", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"])
    kj.add_symmetric(
        "https://sso.qa.7pass.ctf.prosiebensat1.com",
        "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ",
        ["sig"],
    )
    packer = JWT(
        kj,
        sign_alg="HS256",
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        lifetime=3600,
    )
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(code=code, id_token=_jws)
    with pytest.raises(MissingRequiredAttribute):
        verify_id_token(
            msg,
            check_hash=True,
            keyjar=kj,
            iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
            client_id="554295ce3770612820620000",
        )
예제 #3
0
    def test_token_endpoint_with_extra_claims(
            self, context, frontend_config_with_extra_id_token_claims,
            authn_req):
        frontend = self.create_frontend(
            frontend_config_with_extra_id_token_claims)

        user_id = "test_user"
        self.insert_client_in_client_db(frontend, authn_req["redirect_uri"])
        self.insert_user_in_user_db(frontend, user_id)
        authn_req["response_type"] = "code"
        authn_resp = frontend.provider.authorize(authn_req, user_id)

        context.request = AccessTokenRequest(
            redirect_uri=authn_req["redirect_uri"],
            code=authn_resp["code"]).to_dict()
        credentials = "{}:{}".format(CLIENT_ID, CLIENT_SECRET)
        basic_auth = urlsafe_b64encode(
            credentials.encode("utf-8")).decode("utf-8")
        context.request_authorization = "Basic {}".format(basic_auth)

        response = frontend.token_endpoint(context)
        parsed = AccessTokenResponse().deserialize(response.message, "json")
        assert parsed["access_token"]

        id_token = IdToken().from_jwt(parsed["id_token"],
                                      key=[frontend.signing_key])
        assert id_token["email"] == "*****@*****.**"
예제 #4
0
    def test_hybrid_flow(self):
        self.authn_request_args['response_type'] = 'code id_token token'
        auth_req = AuthorizationRequest().from_dict(self.authn_request_args)
        resp = self.provider.authorize(auth_req,
                                       TEST_USER_ID,
                                       extra_id_token_claims={'foo': 'bar'})

        assert resp['state'] == self.authn_request_args['state']
        assert resp['code'] in self.provider.authz_state.authorization_codes

        assert resp['access_token'] in self.provider.authz_state.access_tokens
        assert resp[
            'expires_in'] == self.provider.authz_state.access_token_lifetime
        assert resp['token_type'] == 'Bearer'

        id_token = IdToken().from_jwt(resp['id_token'],
                                      key=[self.provider.signing_key])
        assert_id_token_base_claims(resp['id_token'],
                                    self.provider.signing_key, self.provider,
                                    self.authn_request_args)
        assert id_token["c_hash"] == jws.left_hash(
            resp['code'].encode('utf-8'), 'HS256')
        assert id_token["at_hash"] == jws.left_hash(
            resp['access_token'].encode('utf-8'), 'HS256')
        assert id_token['foo'] == 'bar'
예제 #5
0
def test_make_id_token():
    srv = Server()
    srv.keyjar = KEYJ
    srv.keyjar["http://oic.example/rp"] = KC_RSA

    session = {"sub": "user0", "client_id": "http://oic.example/rp"}
    issuer = "http://oic.example/idp"
    code = "abcdefghijklmnop"
    _idt = srv.make_id_token(session,
                             loa="2",
                             issuer=issuer,
                             code=code,
                             access_token="access_token")

    algo = "RS256"
    ckey = srv.keyjar.get_signing_key(alg2keytype(algo), session["client_id"])
    _signed_jwt = _idt.to_jwt(key=ckey, algorithm="RS256")

    idt = IdToken().from_jwt(_signed_jwt, keyjar=srv.keyjar)
    print idt
    header = unpack(_signed_jwt)

    lha = left_hash(code, func="HS" + header[0]["alg"][-3:])
    assert lha == idt["c_hash"]

    atr = AccessTokenResponse(id_token=_signed_jwt,
                              access_token="access_token",
                              token_type="Bearer")
    atr["code"] = code
    assert atr.verify(keyjar=srv.keyjar)
예제 #6
0
파일: provider.py 프로젝트: valintepes/pyop
    def do_post_logout_redirect(self, end_session_request):
        # type: (oic.oic.message.EndSessionRequest) -> oic.oic.message.EndSessionResponse
        if 'post_logout_redirect_uri' not in end_session_request:
            return None

        client_id = None
        if 'id_token_hint' in end_session_request:
            id_token = IdToken().from_jwt(end_session_request['id_token_hint'],
                                          key=[self.signing_key])
            client_id = id_token['aud'][0]

        if 'post_logout_redirect_uri' in end_session_request:
            if not client_id:
                return None
            if not end_session_request[
                    'post_logout_redirect_uri'] in self.clients[client_id].get(
                        'post_logout_redirect_uris', []):
                return None

        end_session_response = EndSessionResponse()
        if 'state' in end_session_request:
            end_session_response['state'] = end_session_request['state']

        return end_session_response.request(
            end_session_request['post_logout_redirect_uri'])
예제 #7
0
def test_verify_token_encrypted_no_key():
    idt = IdToken(
        sub="553df2bcf909104751cfd8b2",
        aud=["5542958437706128204e0000", "554295ce3770612820620000"],
        auth_time=1441364872,
        azp="554295ce3770612820620000",
    )
    kj = KeyJar()
    kb = KeyBundle()
    kb.do_local_der(
        os.path.join(os.path.dirname(__file__), "data", "keys", "cert.key"),
        "some",
        ["enc", "sig"],
    )
    kj.add_kb("", kb)
    kj.add_kb("https://sso.qa.7pass.ctf.prosiebensat1.com", kb)

    packer = JWT(
        kj,
        lifetime=3600,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        encrypt=True,
    )
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    # Do not pass they keyjar with keys
    with pytest.raises(VerificationError):
        verify_id_token(
            msg,
            keyjar=KeyJar(),
            iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
            client_id="554295ce3770612820620000",
        )
예제 #8
0
def test_verify_id_token_mismatch_aud_azp():
    idt = IdToken(
        **{
            "sub": "553df2bcf909104751cfd8b2",
            "aud": ["5542958437706128204e0000", "554295ce3770612820620000"],
            "auth_time": 1441364872,
            "azp": "aaaaaaaaaaaaaaaaaaaa",
        })

    kj = KeyJar()
    kj.add_symmetric("", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"])
    kj.add_symmetric(
        "https://sso.qa.7pass.ctf.prosiebensat1.com",
        "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ",
        ["sig"],
    )
    packer = JWT(kj,
                 sign_alg="HS256",
                 iss="https://example.com/as",
                 lifetime=3600)
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    with pytest.raises(ValueError):
        verify_id_token(
            msg,
            keyjar=kj,
            iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
            client_id="aaaaaaaaaaaaaaaaaaaa",
        )
예제 #9
0
    def test_handle_authn_response_returns_id_token_for_verified_affiliation(
            self, signing_key_path, context, scope_value, affiliation):
        authn_req = AuthorizationRequest(
            scope='openid ' + scope_value,
            client_id='client1',
            redirect_uri='https://client.example.com',
            response_type='id_token')
        context.state[self.frontend.name] = {
            'oidc_request': authn_req.to_urlencoded()
        }
        internal_response = InternalResponse(
            AuthenticationInformation(None, str(datetime.now()),
                                      'https://idp.example.com'))
        internal_response.attributes['affiliation'] = [affiliation]
        internal_response.user_id = 'user1'

        resp = self.frontend.handle_authn_response(context, internal_response)
        auth_resp = AuthorizationResponse().from_urlencoded(
            urlparse(resp.message).fragment)

        id_token = IdToken().from_jwt(
            auth_resp['id_token'],
            key=[RSAKey(key=rsa_load(signing_key_path))])
        assert id_token['iss'] == self.frontend.base_url
        assert id_token['aud'] == ['client1']
        assert id_token['auth_time'] == internal_response.auth_info.timestamp
예제 #10
0
 def test_configurable_userinfo_endpoint_method_is_used(self, method):
     state = 'state'
     nonce = 'nonce'
     sub = 'foobar'
     authn = OIDCAuthentication(
         self.app,
         provider_configuration_info={
             'issuer': ISSUER,
             'token_endpoint': '/token'
         },
         client_registration_info={'client_id': 'foo'},
         userinfo_endpoint_method=method)
     authn.client.do_access_token_request = MagicMock(
         return_value=AccessTokenResponse(
             **{
                 'id_token': IdToken(**{
                     'sub': sub,
                     'nonce': nonce
                 }),
                 'access_token': 'access_token'
             }))
     userinfo_request_mock = MagicMock(return_value=OpenIDSchema(
         **{'sub': sub}))
     authn.client.do_user_info_request = userinfo_request_mock
     with self.app.test_request_context('/redirect_uri?code=foo&state=' +
                                        state):
         flask.session['state'] = state
         flask.session['nonce'] = nonce
         flask.session['destination'] = '/'
         authn._handle_authentication_response()
     userinfo_request_mock.assert_called_with(method=method, state=state)
예제 #11
0
def test_verify_token_encrypted():
    idt = IdToken(
        sub="553df2bcf909104751cfd8b2",
        aud=["5542958437706128204e0000", "554295ce3770612820620000"],
        auth_time=1441364872,
        azp="554295ce3770612820620000",
    )
    kj = KeyJar()
    kb = KeyBundle()
    kb.do_local_der(
        os.path.join(os.path.dirname(__file__), "data", "keys", "cert.key"),
        "some",
        ["enc", "sig"],
    )
    kj.add_kb("", kb)
    kj.add_kb("https://sso.qa.7pass.ctf.prosiebensat1.com", kb)

    packer = JWT(
        kj,
        lifetime=3600,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        encrypt=True,
    )
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    vidt = verify_id_token(
        msg,
        keyjar=kj,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        client_id="554295ce3770612820620000",
    )
    assert vidt
    assert vidt.jwe_header == {"enc": "A128CBC-HS256", "alg": "RSA1_5", "cty": "JWT"}
예제 #12
0
    def test_does_not_need_refresh(self):
        authn = OIDCAuthentication(
            self.app,
            provider_configuration_info={'issuer': ISSUER},
            client_registration_info={
                'client_id': 'foo',
                'session_refresh_interval_seconds': 1
            },
        )
        client_mock = MagicMock()
        callback_mock = MagicMock()
        now = time.time()
        callback_mock.__name__ = 'test_callback'  # required for Python 2
        authn.client = client_mock
        id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce', 'exp': 0})
        with self.app.test_request_context('/'):
            flask.session['destination'] = '/'
            flask.session['access_token'] = 'test token'
            flask.session['id_token'] = id_token.to_dict()
            flask.session['id_token_jwt'] = id_token.to_jwt()
            flask.session['last_authenticated'] = now + 100
            authn.oidc_auth(callback_mock)()
            session = Session(
                flask_session=flask.session,
                client_registration_info=authn.client_registration_info)

            assert session.needs_refresh() is False
예제 #13
0
    def test_faulty_idtoken(self):
        _now = time_util.utc_time_sans_frac()
        idval = {
            'nonce': 'KUEYfRM2VzKDaaKD',
            'sub': 'EndUserSubject',
            'iss': 'https://alpha.cloud.nds.rub.de',
            'exp': _now + 3600,
            'iat': _now,
            'aud': 'TestClient'
        }
        idts = IdToken(**idval)
        key = SYMKey(key="TestPassword")
        _signed_jwt = idts.to_jwt(key=[key], algorithm="HS256")

        # Mess with the signed id_token
        p = _signed_jwt.split(".")
        p[2] = "aaa"
        _faulty_signed_jwt = ".".join(p)

        _info = {
            "access_token": "accessTok",
            "id_token": _faulty_signed_jwt,
            "token_type": "Bearer",
            "expires_in": 3600
        }

        at = AccessTokenResponse(**_info)
        with pytest.raises(BadSignature):
            at.verify(key=[key])
예제 #14
0
def test_wrong_alg():
    idval = {
        'nonce': 'KUEYfRM2VzKDaaKD',
        'sub': 'EndUserSubject',
        'iss': 'https://alpha.cloud.nds.rub.de',
        'exp': 1420823073,
        'iat': 1420822473,
        'aud': 'TestClient'
    }
    idts = IdToken(**idval)
    key = SYMKey(key="TestPassword")
    _signed_jwt = idts.to_jwt(key=[key], algorithm="HS256")

    _info = {
        "access_token": "accessTok",
        "id_token": _signed_jwt,
        "token_type": "Bearer",
        "expires_in": 3600
    }

    at = AccessTokenResponse(**_info)
    try:
        at.verify(key=[key], algs={"sign": "HS512"})
    except WrongSigningAlgorithm:
        pass
예제 #15
0
def test_faulty_idtoken():
    idval = {
        'nonce': 'KUEYfRM2VzKDaaKD',
        'sub': 'EndUserSubject',
        'iss': 'https://alpha.cloud.nds.rub.de',
        'exp': 1420823073,
        'iat': 1420822473,
        'aud': 'TestClient'
    }
    idts = IdToken(**idval)
    key = SYMKey(key="TestPassword")
    _signed_jwt = idts.to_jwt(key=[key], algorithm="HS256")

    #Mess with the signed id_token
    p = _signed_jwt.split(".")
    p[2] = "aaa"
    _faulty_signed_jwt = ".".join(p)

    _info = {
        "access_token": "accessTok",
        "id_token": _faulty_signed_jwt,
        "token_type": "Bearer",
        "expires_in": 3600
    }

    # Should fail
    at = AccessTokenResponse(**_info)
    try:
        at.verify(key=[key])
    except BadSignature:
        pass
    else:
        raise
예제 #16
0
    def test_get_session_management_id(self):
        now = utc_time_sans_frac()
        smid = "session_management_id"
        idval = {
            "nonce": "KUEYfRM2VzKDaaKD",
            "sub": "EndUserSubject",
            "iss": "https://example.com",
            "exp": now + 3600,
            "iat": now,
            "aud": self.consumer.client_id,
            "sid": smid,
        }
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=KC_RSA.keys(), algorithm="RS256")

        _state = "state"
        self.consumer.sdb[_state] = {
            "redirect_uris": ["https://example.org/cb"]
        }
        resp = AuthorizationResponse(id_token=_signed_jwt, state=_state)
        self.consumer.consumer_config["response_type"] = ["id_token"]
        self.consumer.parse_authz(resp.to_urlencoded())
        assert self.consumer.sso_db["state"]["smid"] == smid
        assert session_get(self.consumer.sso_db, "smid", smid) == [_state]
예제 #17
0
def test_verify_id_token_at_hash():
    token = "AccessTokenWhichCouldBeASignedJWT"
    lhsh = left_hash(token)

    idt = IdToken(
        **{
            "sub": "553df2bcf909104751cfd8b2",
            "aud": ["5542958437706128204e0000", "554295ce3770612820620000"],
            "auth_time": 1441364872,
            "azp": "554295ce3770612820620000",
            "at_hash": lhsh,
        })

    kj = KeyJar()
    kj.add_symmetric("", "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ", ["sig"])
    kj.add_symmetric(
        "https://sso.qa.7pass.ctf.prosiebensat1.com",
        "dYMmrcQksKaPkhdgRNYk3zzh5l7ewdDJ",
        ["sig"],
    )
    packer = JWT(
        kj,
        sign_alg="HS256",
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        lifetime=3600,
    )
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(access_token=token, id_token=_jws)
    verify_id_token(
        msg,
        check_hash=True,
        keyjar=kj,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        client_id="554295ce3770612820620000",
    )
예제 #18
0
    def test_verify_id_token_reject_wrong_aud(self, monkeypatch):
        issuer = "https://provider.example.com"
        monkeypatch.setattr(self.client, "provider_info", {"issuer": issuer})
        id_token = IdToken(**dict(iss=issuer, aud=["nobody"]))

        with pytest.raises(OtherError) as exc:
            self.client._verify_id_token(id_token)
        assert "me" in str(exc.value)
예제 #19
0
def test_faulty_id_token():
    _faulty_signed_jwt = _faulty_id_token()
    try:
        _ = IdToken().from_jwt(_faulty_signed_jwt, key=[SYMKEY])
    except BadSignature:
        pass
    else:
        assert False

    # What if no verification key is given ?
    # Should also result in an exception
    try:
        _ = IdToken().from_jwt(_faulty_signed_jwt)
    except MissingSigningKey:
        pass
    else:
        assert False
예제 #20
0
    def test_authorize_id_token_includes_typ_header(self):
        self.authn_request_args['response_type'] = 'id_token'
        auth_req = AuthorizationRequest().from_dict(self.authn_request_args)
        resp = self.provider.authorize(auth_req, TEST_USER_ID)

        id_token = IdToken().from_jwt(resp['id_token'],
                                      key=[self.provider.signing_key])
        assert id_token.jws_header['typ'] == 'JWT'
예제 #21
0
    def test_complete_auth_token_idtoken_no_alg_config(self):
        _state = "state0"
        self.consumer.consumer_config["response_type"] = ["id_token", "token"]
        self.consumer.provider_info = ProviderConfigurationResponse(
            issuer="https://example.com")  # abs min
        self.consumer.authz_req = {}  # Store AuthzReq with state as key

        args = {
            "client_id": self.consumer.client_id,
            "response_type": self.consumer.consumer_config["response_type"],
            "scope": ["openid"],
            "nonce": "nonce",
        }
        token = IdToken(
            iss="https://example.com",
            aud="client_1",
            sub="some_sub",
            exp=1565348600,
            iat=1565348300,
            nonce="nonce",
        )
        location = (
            "https://example.com/cb?state=state0&access_token=token&token_type=bearer&"
            "scope=openid&id_token={}".format(
                token.to_jwt(key=[SYMKey(key="hemlig")], algorithm="HS256")))
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            result = self.consumer.do_authorization_request(state=_state,
                                                            request_args=args)
            query = parse_qs(urlparse(result.request.url).query)
            assert query["client_id"] == ["client_1"]
            assert query["scope"] == ["openid"]
            assert query["response_type"] == ["id_token token"]
            assert query["state"] == ["state0"]
            assert query["nonce"] == ["nonce"]
            assert query["redirect_uri"] == ["https://example.com/cb"]

        parsed = urlparse(result.headers["location"])

        with freeze_time("2019-08-09 11:00:00"):
            part = self.consumer.parse_authz(query=parsed.query,
                                             algs={"sign": "HS256"})
        assert isinstance(part, tuple)
        auth = part[0]
        atr = part[1]
        idt = part[2]

        assert auth is None
        assert isinstance(atr, AccessTokenResponse)
        assert _eq(
            atr.keys(),
            ["access_token", "id_token", "token_type", "state", "scope"])
        assert isinstance(idt, IdToken)
예제 #22
0
def test_server_authorization_endpoint_id_token():
    provider = provider_init

    bib = {
        "scope": ["openid"],
        "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
        "redirect_uri": "http://localhost:8087/authz",
        "response_type": ["code", "id_token"],
        "client_id": "a1b2c3",
        "nonce": "Nonce",
        "prompt": ["none"]
    }

    req = AuthorizationRequest(**bib)
    areq = AuthorizationRequest(response_type="code",
                                client_id="client_1",
                                redirect_uri="http://example.com/authz",
                                scope=["openid"],
                                state="state000")

    sdb = provider.sdb
    ae = AuthnEvent("userX")
    sid = sdb.create_authz_session(ae, areq)
    sdb.do_sub(sid)
    _info = sdb[sid]
    # All this is jut removed when the id_token is constructed
    # The proper information comes from the session information
    _user_info = IdToken(iss="https://foo.example.om",
                         sub="foo",
                         aud=bib["client_id"],
                         exp=epoch_in_a_while(minutes=10),
                         acr="2",
                         nonce=bib["nonce"])

    print provider.keyjar.issuer_keys
    print _user_info.to_dict()
    idt = provider.id_token_as_signed_jwt(_info,
                                          access_token="access_token",
                                          user_info=_user_info)

    req["id_token"] = idt
    query_string = req.to_urlencoded()

    # client_id not in id_token["aud"] so login required
    resp = provider.authorization_endpoint(request=query_string, cookie="FAIL")

    print resp
    assert "error=login_required" in resp.message

    req["client_id"] = "client_1"
    query_string = req.to_urlencoded()

    # client_id is in id_token["aud"] so no login required
    resp = provider.authorization_endpoint(request=query_string, cookie="FAIL")

    print resp.message
    assert resp.message.startswith("http://localhost:8087/authz")
예제 #23
0
    def test_check_session_endpoint(self):
        session = {"sub": "UserID", "client_id": "number5"}
        idtoken = self.provider.id_token_as_signed_jwt(session)
        csr = CheckSessionRequest(id_token=idtoken)

        info = self.provider.check_session_endpoint(request=csr.to_urlencoded())
        idt = IdToken().deserialize(info.message, "json")
        assert _eq(idt.keys(), ['sub', 'aud', 'iss', 'acr', 'exp', 'iat'])
        assert idt["iss"] == self.provider.name + "/"
예제 #24
0
파일: provider.py 프로젝트: s-hal/pyop
    def logout_user(self, subject_identifier=None, end_session_request=None):
        # type: (Optional[str], Optional[oic.oic.message.EndSessionRequest]) -> None
        if not end_session_request:
            end_session_request = EndSessionRequest()
        if 'id_token_hint' in end_session_request:
            id_token = IdToken().from_jwt(end_session_request['id_token_hint'], key=[self.signing_key])
            subject_identifier = id_token['sub']

        self.authz_state.delete_state_for_subject_identifier(subject_identifier)
예제 #25
0
    def test_logout_redirects_to_provider_if_end_session_endpoint_is_configured(
            self, post_logout_redirect_uri):
        end_session_endpoint = 'https://provider.example.com/end_session'
        client_metadata = {}
        if post_logout_redirect_uri:
            client_metadata['post_logout_redirect_uris'] = [
                post_logout_redirect_uri
            ]

        authn = self.init_app(provider_metadata_extras={
            'end_session_endpoint': end_session_endpoint
        },
                              client_metadata_extras=client_metadata)
        logout_view_mock = self.get_view_mock()
        id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce'})

        # register logout view
        view_func = authn.oidc_logout(logout_view_mock)
        self.app.add_url_rule('/logout', view_func=view_func)

        with self.app.test_request_context('/logout'):
            UserSession(flask.session, self.PROVIDER_NAME).update(
                access_token='test_access_token',
                id_token=id_token.to_dict(),
                id_token_jwt=id_token.to_jwt(),
                userinfo={'sub': 'user1'})
            end_session_redirect = view_func()
            # ensure user session has been cleared
            assert all(k not in flask.session for k in UserSession.KEYS)
            parsed_request = dict(
                parse_qsl(
                    urlparse(end_session_redirect.headers['Location']).query))
            assert parsed_request['state'] == flask.session[
                'end_session_state']

        assert end_session_redirect.status_code == 303
        assert end_session_redirect.location.startswith(end_session_endpoint)
        assert IdToken().from_jwt(parsed_request['id_token_hint']) == id_token

        expected_post_logout_redirect_uri = post_logout_redirect_uri if post_logout_redirect_uri else 'http://{}/logout'.format(
            self.CLIENT_DOMAIN)
        assert parsed_request[
            'post_logout_redirect_uri'] == expected_post_logout_redirect_uri
        assert not logout_view_mock.called
예제 #26
0
파일: provider.py 프로젝트: valintepes/pyop
    def _create_signed_id_token(
        self,
        client_id,  # type: str
        sub,  # type: str
        user_claims=None,  # type: Optional[Mapping[str, Union[str, List[str]]]]
        nonce=None,  # type: Optional[str]
        authorization_code=None,  # type: Optional[str]
        access_token_value=None,  # type: Optional[str]
        extra_id_token_claims=None
    ):  # type: Optional[Mappings[str, Union[str, List[str]]]]
        # type: (...) -> str
        """
        Creates a signed ID Token.
        :param client_id: who the ID Token is intended for
        :param sub: who the ID Token is regarding
        :param user_claims: any claims about the user to be included
        :param nonce: nonce from the authentication request
        :param authorization_code: the authorization code issued together with this ID Token
        :param access_token_value: the access token issued together with this ID Token
        :param extra_id_token_claims: any extra claims that should be included in the ID Token
        :return: a JWS, containing the ID Token as payload
        """

        alg = self.clients[client_id].get(
            'id_token_signed_response_alg', self.configuration_information[
                'id_token_signing_alg_values_supported'][0])
        args = {}

        hash_alg = 'HS{}'.format(alg[-3:])
        if authorization_code:
            args['c_hash'] = jws.left_hash(authorization_code.encode('utf-8'),
                                           hash_alg)
        if access_token_value:
            args['at_hash'] = jws.left_hash(access_token_value.encode('utf-8'),
                                            hash_alg)

        if user_claims:
            args.update(user_claims)

        if extra_id_token_claims:
            args.update(extra_id_token_claims)

        id_token = IdToken(iss=self.configuration_information['issuer'],
                           sub=sub,
                           aud=client_id,
                           iat=int(time.time()),
                           exp=int(time.time()) + self.id_token_lifetime,
                           **args)

        if nonce:
            id_token['nonce'] = nonce

        logger.debug('signed id_token with kid=%s using alg=%s',
                     self.signing_key, alg)
        return id_token.to_jwt([self.signing_key], alg)
예제 #27
0
def assert_id_token_base_claims(jws, verification_key, provider, auth_req):
    id_token = IdToken().from_jwt(jws, key=[verification_key])
    assert id_token['nonce'] == auth_req['nonce']
    assert id_token['iss'] == ISSUER
    assert provider.authz_state.get_user_id_for_subject_identifier(
        id_token['sub']) == TEST_USER_ID
    assert id_token['iat'] == MOCK_TIME.return_value
    assert id_token['exp'] == id_token['iat'] + provider.id_token_lifetime
    assert TEST_CLIENT_ID in id_token['aud']

    return id_token
예제 #28
0
def logout(request, next_page=None):
    if not "op" in request.session.keys():
        return auth_logout_view(request, next_page)

    client = CLIENTS[request.session["op"]]

    # User is by default NOT redirected to the app - it stays on an OP page after logout.
    # Here we determine if a redirection to the app was asked for and is possible.
    if next_page is None and "next" in request.GET.keys():
        next_page = request.GET['next']
    if next_page is None and "next" in request.session.keys():
        next_page = request.session['next']
    extra_args = {}
    if "post_logout_redirect_uris" in client.registration_response.keys() and len(
            client.registration_response["post_logout_redirect_uris"]) > 0:
        if next_page is not None:
            # First attempt a direct redirection from OP to next_page
            next_page_url = resolve_url(next_page)
            urls = [url for url in client.registration_response["post_logout_redirect_uris"] if next_page_url in url]
            if len(urls) > 0:
                extra_args["post_logout_redirect_uri"] = urls[0]
            else:
                # It is not possible to directly redirect from the OP to the page that was asked for.
                # We will try to use the redirection point - if the redirection point URL is registered that is.
                next_page_url = resolve_url('openid_logout_cb')
                urls = [url for url in client.registration_response["post_logout_redirect_uris"] if
                        next_page_url in url]
                if len(urls) > 0:
                    extra_args["post_logout_redirect_uri"] = urls[0]
                else:
                    # Just take the first registered URL as a desperate attempt to come back to the application
                    extra_args["post_logout_redirect_uri"] = client.registration_response["post_logout_redirect_uris"][
                        0]
    else:
        # No post_logout_redirect_uris registered at the OP - no redirection to the application is possible anyway
        pass

    # Redirect client to the OP logout page
    try:
        request_args = None
        if 'id_token' in request.session.keys():
            request_args = {'id_token': IdToken(**request.session['id_token'])}
        res = client.do_end_session_request(state=request.session["state"],
                                            extra_args=extra_args, request_args=request_args)
        resp = HttpResponse(content_type=res.headers["content-type"], status=res.status_code, content=res._content)
        for key, val in res.headers.items():
            resp[key] = val
        return resp
    finally:
        # Always remove Django session stuff - even if not logged out from OP. Don't wait for the callback as it may never come.
        auth_logout(request)
        if next_page:
            request.session['next'] = next_page
예제 #29
0
    def test_session_expiration_set_to_id_token_exp(self):
        token_endpoint = ISSUER + '/token'
        userinfo_endpoint = ISSUER + '/userinfo'
        exp_time = 10
        epoch_int = int(time.mktime(datetime(2017, 1, 1).timetuple()))
        id_token = IdToken(
            **{
                'sub': 'sub1',
                'iat': epoch_int,
                'iss': ISSUER,
                'aud': 'foo',
                'nonce': 'test',
                'exp': epoch_int + exp_time
            })
        token_response = {
            'access_token': 'test',
            'token_type': 'Bearer',
            'id_token': id_token.to_jwt()
        }
        userinfo_response = {'sub': 'sub1'}
        responses.add(responses.POST,
                      token_endpoint,
                      body=json.dumps(token_response),
                      content_type='application/json')
        responses.add(responses.POST,
                      userinfo_endpoint,
                      body=json.dumps(userinfo_response),
                      content_type='application/json')
        authn = OIDCAuthentication(
            self.app,
            provider_configuration_info={
                'issuer': ISSUER,
                'token_endpoint': token_endpoint,
                'userinfo_endpoint': userinfo_endpoint
            },
            client_registration_info={
                'client_id': 'foo',
                'client_secret': 'foo'
            },
        )

        self.app.config.update({'SESSION_PERMANENT': True})
        with self.app.test_request_context(
                '/redirect_uri?state=test&code=test'):
            flask.session['destination'] = '/'
            flask.session['state'] = 'test'
            flask.session['nonce'] = 'test'
            flask.session['id_token'] = id_token.to_dict()
            flask.session['id_token_jwt'] = id_token.to_jwt()
            authn._handle_authentication_response()
            assert flask.session.permanent is True
            assert int(flask.session.permanent_session_lifetime) == exp_time
예제 #30
0
    def test_complete_auth_token_idtoken_none_cipher_token(self):
        _state = "state0"
        self.consumer.consumer_config["response_type"] = ["token"]
        self.consumer.registration_response = RegistrationResponse(
            id_token_signed_response_alg="none")
        self.consumer.provider_info = ProviderConfigurationResponse(
            issuer="https://example.com")  # abs min
        self.consumer.authz_req = {}  # Store AuthzReq with state as key
        self.consumer.sdb[_state] = {"redirect_uris": []}

        args = {
            "client_id": self.consumer.client_id,
            "response_type": self.consumer.consumer_config["response_type"],
            "scope": ["openid"],
            "nonce": "nonce",
        }
        token = IdToken(
            iss="https://example.com",
            aud="client_1",
            sub="some_sub",
            exp=1565348600,
            iat=1565348300,
            nonce="nonce",
        )
        # Downgrade the algorithm to `none`
        location = (
            "https://example.com/cb?state=state0&access_token=token&token_type=bearer&"
            "scope=openid&id_token={}".format(
                token.to_jwt(key=KC_RSA.keys(), algorithm="none")))
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            result = self.consumer.do_authorization_request(state=_state,
                                                            request_args=args)
            query = parse_qs(urlparse(result.request.url).query)
            assert query["client_id"] == ["client_1"]
            assert query["scope"] == ["openid"]
            assert query["response_type"] == ["token"]
            assert query["state"] == ["state0"]
            assert query["nonce"] == ["nonce"]
            assert query["redirect_uri"] == ["https://example.com/cb"]

        parsed = urlparse(result.headers["location"])

        with freeze_time("2019-08-09 11:00:00"):
            with pytest.raises(WrongSigningAlgorithm):
                self.consumer.parse_authz(query=parsed.query)