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")
def test_verify_id_token_at_hash_and_chash(): token = 'AccessTokenWhichCouldBeASignedJWT' at_hash = left_hash(token) code = 'AccessCode1' c_hash = left_hash(code) idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": at_hash, 'c_hash': c_hash }) 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, code=code) verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def test_verify_id_token_at_hash_fail(): token = 'AccessTokenWhichCouldBeASignedJWT' token2 = 'ACompletelyOtherAccessToken' 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=token2, id_token=_jws) with pytest.raises(AtHashError): verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
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 + "/"
def _parse_id_token(self, id_token, redirect_uri): try: return IdToken().from_jwt(id_token, keyjar=self.keyjar) except Exception, err: logger.error("Faulty id_token: %s" % id_token) logger.error("Exception: %s" % (err.__class__.__name__,)) id_token = IdToken().from_jwt(id_token, verify=False) logger.error("IdToken: %s" % id_token.to_dict()) return self._redirect_authz_error("invalid_id_token_object", redirect_uri)
def _faulty_id_token(): idval = {'nonce': 'KUEYfRM2VzKDaaKD', 'sub': 'EndUserSubject', 'iss': 'https://alpha.cloud.nds.rub.de', 'exp': 1420823073, 'iat': 1420822473, 'aud': 'TestClient'} idts = IdToken(**idval) _signed_jwt = idts.to_jwt(key=[SYMKEY], algorithm="HS256") # Mess with the signed id_token p = _signed_jwt.split(".") p[2] = "aaa" return ".".join(p)
def test_check_session_endpoint(): server = provider_init print server.name session = {"sub": "UserID", "client_id": "number5"} idtoken = server.id_token_as_signed_jwt(session) csr = CheckSessionRequest(id_token=idtoken) info = server.check_session_endpoint(request=csr.to_urlencoded()) print info idt = IdToken().deserialize(info.message, "json") print idt.keys() assert _eq(idt.keys(), ['sub', 'aud', 'iss', 'acr', 'exp', 'iat']) assert idt["iss"] == server.name
def _faulty_id_token(self): idval = {'nonce': 'KUEYfRM2VzKDaaKD', 'sub': 'EndUserSubject', 'iss': 'https://alpha.cloud.nds.rub.de', 'exp': 1420823073, 'iat': 1420822473, 'aud': 'TestClient'} idts = IdToken(**idval) _signed_jwt = idts.to_jwt(key=[SYMKey(key="TestPassword")], algorithm="HS256") # Mess with the signed id_token p = _signed_jwt.split(".") p[2] = "aaa" return ".".join(p)
def test_wrong_alg(self): 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) with pytest.raises(WrongSigningAlgorithm): at.verify(key=[key], algs={"sign": "HS512"})
def test_id_token(): idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": "L4Ign7TCAD_EppRbHAuCyw", "iat": 1441367116, "exp": 1441374316, "iss": "https://sso.qa.7pass.ctf.prosiebensat1.com" }) idt.verify()
def test_session_expiration_set_to_configured_lifetime( self, time_mock, utc_time_sans_frac_mock): timestamp = time.mktime(datetime(2017, 1, 1).timetuple()) time_mock.return_value = timestamp utc_time_sans_frac_mock.return_value = int(timestamp) exp_time = 10 state = 'test_state' nonce = 'test_nonce' id_token = IdToken(iss=self.PROVIDER_BASEURL, aud=self.CLIENT_ID, sub='sub1', exp=int(timestamp) + exp_time, iat=int(timestamp), nonce=nonce) token_response = { 'access_token': 'test', 'token_type': 'Bearer', 'id_token': id_token.to_jwt() } token_endpoint = self.PROVIDER_BASEURL + '/token' responses.add(responses.POST, token_endpoint, json=token_response) session_lifetime = 1234 self.app.config['PERMANENT_SESSION_LIFETIME'] = session_lifetime self.init_app( provider_metadata_extras={'token_endpoint': token_endpoint}) with self.app.test_client() as client: with client.session_transaction() as session: UserSession(session, self.PROVIDER_NAME) session['destination'] = '/' session['state'] = state session['nonce'] = nonce resp = client.get('/redirect_uri?state={}&code=test'.format(state)) cookies = SimpleCookie() cookies.load(resp.headers['Set-Cookie']) session_cookie_expiration = cookies[ self.app.config['SESSION_COOKIE_NAME']]['expires'] try: parsed_expiration = datetime.strptime(session_cookie_expiration, '%a, %d-%b-%Y %H:%M:%S GMT') except ValueError: parsed_expiration = datetime.strptime(session_cookie_expiration, '%a, %d %b %Y %H:%M:%S GMT') cookie_lifetime = (parsed_expiration - datetime.utcnow()).total_seconds() assert cookie_lifetime == pytest.approx(session_lifetime, abs=1)
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=time.time(), exp=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)
def test_logout_handles_provider_without_end_session_endpoint(self): authn = self.init_app() id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce'}) logout_view_mock = self.get_view_mock() 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'}) logout_result = authn.oidc_logout(logout_view_mock)() assert all(k not in flask.session for k in UserSession.KEYS) self.assert_view_mock(logout_view_mock, logout_result)
def test_wrong_alg(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") _info = {"access_token": "accessTok", "id_token": _signed_jwt, "token_type": "Bearer", "expires_in": 3600} at = AccessTokenResponse(**_info) with pytest.raises(WrongSigningAlgorithm): at.verify(key=[key], algs={"sign": "HS512"})
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' authn._handle_authentication_response() assert flask.session.permanent assert int(flask.session.permanent_session_lifetime) == exp_time
def test_server_authorization_endpoint_id_token(self): 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 = self.server.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 self.server.keyjar.issuer_keys print _user_info.to_dict() idt = self.server.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 = self.server.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 = self.server.authorization_endpoint(request=query_string, cookie="FAIL") print resp.message assert resp.message.startswith("http://localhost:8087/authz")
def test_complete_auth_token_idtoken_cipher_downgrade(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", ) # 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"] == ["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"): with pytest.raises(WrongSigningAlgorithm): self.consumer.parse_authz(query=parsed.query)
def test_oidc_logout_redirects_to_provider(self): end_session_endpoint = 'https://provider.example.com/end_session' post_logout_uri = 'https://client.example.com/post_logout' authn = OIDCAuthentication(self.app, provider_configuration_info={'issuer': ISSUER, 'end_session_endpoint': end_session_endpoint}, client_registration_info={'client_id': 'foo', 'post_logout_redirect_uris': [post_logout_uri]}) callback_mock = MagicMock() callback_mock.__name__ = 'test_callback' # required for Python 2 id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce'}) with self.app.test_request_context('/logout'): flask.session['id_token_jwt'] = id_token.to_jwt() resp = authn.oidc_logout(callback_mock)() assert resp.status_code == 303 assert not callback_mock.called
def test_logout_handles_provider_without_end_session_endpoint(self): post_logout_uri = 'https://client.example.com/post_logout' authn = OIDCAuthentication(self.app, provider_configuration_info={'issuer': ISSUER}, client_registration_info={'client_id': 'foo', 'post_logout_redirect_uris': [post_logout_uri]}) id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce'}) with self.app.test_request_context('/logout'): flask.session['access_token'] = 'abcde' flask.session['userinfo'] = {'foo': 'bar', 'abc': 'xyz'} flask.session['id_token'] = id_token.to_dict() flask.session['id_token_jwt'] = id_token.to_jwt() end_session_redirect = authn._logout() assert all(k not in flask.session for k in ['access_token', 'userinfo', 'id_token', 'id_token_jwt']) assert end_session_redirect is None
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"] == "*****@*****.**"
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'])
def test_id_token(): idt = IdToken(**{ "sub": "553df2bcf909104751cfd8b2", "aud": [ "5542958437706128204e0000", "554295ce3770612820620000" ], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": "L4Ign7TCAD_EppRbHAuCyw", "iat": 1441367116, "exp": 1441374316, "iss": "https://sso.qa.7pass.ctf.prosiebensat1.com" }) idt.verify()
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'
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
def test_id_token(): _now = time_util.utc_time_sans_frac() idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": "L4Ign7TCAD_EppRbHAuCyw", "iat": _now, "exp": _now + 3600, "iss": "https://sso.qa.7pass.ctf.prosiebensat1.com", }) idt.verify()
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)
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)
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")
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)
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'}
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
def _func(self, environ): res = {} msg = None for msg in environ["item"]: if msg.type() == "AuthorizationResponse": break keys = environ["client"].keystore.get_keys("ver", owner=None) idt = IdToken().deserialize(msg["id_token"], "jwt", key=keys) if idt.to_dict() == environ["item"][-1].to_dict(): pass else: self._status = self.status res["message"] = " ".join([ "My deserialization of the IDToken differs from what the", "checkID response"]) return res
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'
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 = SessionDB() sid = sdb.create_authz_session("userX", AREQ) _info = sdb[sid] _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() resp = provider.authorization_endpoint(request=QUERY_STRING) print resp assert "error=login_required" in resp.message
def test_verify_iat_in_future_expired(self): now = time_util.utc_time_sans_frac() idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": "L4Ign7TCAD_EppRbHAuCyw", "iat": now + 3600, "exp": now, "iss": "https://sso.qa.7pass.ctf.prosiebensat1.com", }) with pytest.raises(EXPError): idt.verify(skew=7200)
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)
def _faulty_id_token(self): idval = { "nonce": "KUEYfRM2VzKDaaKD", "sub": "EndUserSubject", "iss": "https://alpha.cloud.nds.rub.de", "exp": 1420823073, "iat": 1420822473, "aud": "TestClient", } idts = IdToken(**idval) _signed_jwt = idts.to_jwt(key=[SYMKey(key="TestPassword")], algorithm="HS256") # Mess with the signed id_token p = _signed_jwt.split(".") p[2] = "aaa" return ".".join(p)
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 else: raise
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
def test_check_session_endpoint(): server = provider_init print server.name # server.keyjar["number5"] = KeyChain({"hmac":CDB["number5"]["client_secret"]}, # usage=["ver"]) session = {"sub": "UserID", "client_id": "number5"} idtoken = server.id_token_as_signed_jwt(session) csr = CheckSessionRequest(id_token=idtoken) environ = BASE_ENVIRON.copy() environ["QUERY_STRING"] = csr.to_urlencoded() info = server.check_session_endpoint(environ, start_response) print info idt = IdToken().deserialize(info[0], "json") print idt.keys() assert _eq(idt.keys(), ['sub', 'aud', 'iss', 'acr', 'exp', 'iat']) assert idt["iss"] == server.name
def test_faulty_idtoken(self): 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} at = AccessTokenResponse(**_info) with pytest.raises(BadSignature): at.verify(key=[key])
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
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])
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
def test_logout_handles_provider_without_end_session_endpoint(self): post_logout_uri = 'https://client.example.com/post_logout' authn = OIDCAuthentication( self.app, provider_configuration_info={'issuer': ISSUER}, client_registration_info={ 'client_id': 'foo', 'post_logout_redirect_uris': [post_logout_uri] }) id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce'}) with self.app.test_request_context('/logout'): flask.session['access_token'] = 'abcde' flask.session['userinfo'] = {'foo': 'bar', 'abc': 'xyz'} flask.session['id_token'] = id_token.to_dict() flask.session['id_token_jwt'] = id_token.to_jwt() end_session_redirect = authn._logout() assert all( k not in flask.session for k in ['access_token', 'userinfo', 'id_token', 'id_token_jwt']) assert end_session_redirect is None
def test_authorization_endpoint_id_token(self): 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 = self.provider.sdb ae = AuthnEvent("userX", "salt") sid = sdb.create_authz_session(ae, areq) sdb.do_sub(sid, "client_salt") _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"]) idt = self.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 = self.provider.authorization_endpoint(request=query_string, cookie="FAIL") parsed_resp = parse_qs(urlparse(resp.message).fragment) assert parsed_resp["error"][0] == "login_required" req["client_id"] = "client_1" query_string = req.to_urlencoded() # client_id is in id_token["aud"] so no login required resp = self.provider.authorization_endpoint(request=query_string, cookie="FAIL") assert resp.message.startswith("http://localhost:8087/authz")
def _func(self, conv): res = {} instance = None for instance, msg in conv.protocol_response: if instance.type() == "AuthorizationResponse": break kj = conv.client.keyjar keys = {} for issuer in kj.keys(): keys.update(kj.get("ver", issuer=issuer)) idt = IdToken().deserialize(instance["id_token"], "jwt", key=keys) if idt.to_dict() == conv.protocol_response[-1][0].to_dict(): pass else: self._status = self.status res["message"] = " ".join([ "My deserialization of the IDToken differs from what the", "checkID response"]) return res
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 = SessionDB() sid = sdb.create_authz_session("username", AREQ) _info = sdb[sid] _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 environ = BASE_ENVIRON.copy() environ["QUERY_STRING"] = req.to_urlencoded() resp = provider.authorization_endpoint(environ, start_response) print resp line = resp[0] assert "error=login_required" in line
def test_verify_id_token_iss_not_in_keyjar(): 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', lifetime=3600, iss='https://example.com/op') _jws = packer.pack(**idt.to_dict()) msg = AuthorizationResponse(id_token=_jws) with pytest.raises(ValueError): verify_id_token(msg, check_hash=True, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000")
def test_verify_id_token(): 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(id_token=_jws) vidt = verify_id_token(msg, keyjar=kj, iss="https://sso.qa.7pass.ctf.prosiebensat1.com", client_id="554295ce3770612820620000") assert vidt
def test_logout(self): end_session_endpoint = 'https://provider.example.com/end_session' post_logout_uri = 'https://client.example.com/post_logout' authn = OIDCAuthentication(self.app, provider_configuration_info={'issuer': ISSUER, 'end_session_endpoint': end_session_endpoint}, client_registration_info={'client_id': 'foo', 'post_logout_redirect_uris': [post_logout_uri]}) id_token = IdToken(**{'sub': 'sub1', 'nonce': 'nonce'}) with self.app.test_request_context('/logout'): flask.session['access_token'] = 'abcde' flask.session['userinfo'] = {'foo': 'bar', 'abc': 'xyz'} flask.session['id_token'] = id_token.to_dict() flask.session['id_token_jwt'] = id_token.to_jwt() end_session_redirect = authn._logout() assert all(k not in flask.session for k in ['access_token', 'userinfo', 'id_token', 'id_token_jwt']) assert end_session_redirect.status_code == 303 assert end_session_redirect.headers['Location'].startswith(end_session_endpoint) parsed_request = dict(parse_qsl(urlparse(end_session_redirect.headers['Location']).query)) assert parsed_request['state'] == flask.session['end_session_state'] assert parsed_request['id_token_hint'] == id_token.to_jwt() assert parsed_request['post_logout_redirect_uri'] == post_logout_uri
return s1 == s2 CLIENT_SECRET = "abcdefghijklmnop" CLIENT_ID = "client_1" KC_HMAC_VS = KeyBundle({"hmac": "abcdefghijklmnop"}, usage=["ver", "sig"]) KC_RSA = KeyBundle(source="file://../oc3/certs/mycert.key", type="rsa", usage=["ver", "sig"]) KC_HMAC_S = KeyBundle({"hmac": "abcdefghijklmnop"}, usage=["sig"]) KEYJ = KeyJar() KEYJ[""] = [KC_RSA, KC_HMAC_S] KEYJ["client_1"] = [KC_HMAC_VS] IDTOKEN = IdToken(iss="http://oic.example.org/", sub="user_id", aud=CLIENT_ID, exp=utc_time_sans_frac()+86400, nonce="N0nce", iat=time.time()) # ----------------- CLIENT -------------------- class TestOICClient(): def setup_class(self): self.client = Client(CLIENT_ID) self.client.redirect_uris = ["http://example.com/redirect"] self.client.client_secret = CLIENT_SECRET self.client.keyjar[""] = KC_RSA def test_areq_1(self): ar = self.client.construct_AuthorizationRequest( request_args={"response_type":["code"]})
CLIENT_SECRET = "abcdefghijklmnop" CLIENT_ID = "client_1" KC_SYM_S = KeyBundle({"kty": "oct", "key": "abcdefghijklmnop", "use": "sig"}) _key = rsa_load("../oc3/certs/mycert.key") KC_RSA = KeyBundle({"key": _key, "kty": "RSA", "use": "sig"}) KEYJ = KeyJar() KEYJ[""] = [KC_RSA, KC_SYM_S] KEYJ["client_1"] = [KC_SYM_S] IDTOKEN = IdToken(iss="http://oic.example.org/", sub="user_id", aud=CLIENT_ID, exp=utc_time_sans_frac() + 86400, nonce="N0nce", iat=time.time()) # ----------------- CLIENT -------------------- class TestOICClient(): def setup_class(self): self.client = Client(CLIENT_ID) self.client.redirect_uris = ["http://example.com/redirect"] self.client.client_secret = CLIENT_SECRET self.client.keyjar[""] = KC_RSA def test_areq_1(self): ar = self.client.construct_AuthorizationRequest( request_args={"response_type": ["code"]})
from jwkest.jws import alg2keytype from oic.oic.message import IdToken from oic.utils.keyio import KeyBundle, KeyJar __author__ = 'rohe0002' b0 = KeyBundle(source="http://localhost:8090/exports/jwk.json", src_type="jwk", usage=["ver", "dec", "sig"]) b1 = KeyBundle(source="http://localhost:8090/exports/cert.pem", src_type="x509", usage=["ver", "dec", "sig"]) print b0 print b1 kj = KeyJar() kj["foobar"] = [b0, b1] idt = IdToken().from_dict({"user_id": "diana", "aud": "uo5nowsdL3ck", "iss": "https://localhost:8092", "acr": "2", "exp": 1354442188, "iat": 1354359388}) ckey = kj.get_signing_key(alg2keytype("RS256"), "foobar") _signed_jwt = idt.to_jwt(key=ckey, algorithm="RS256")
CLIENT_SECRET = "abcdefghijklmnop" CLIENT_ID = "client_1" rsapub = rsa_load("../oc3/certs/mycert.key") KEYS = [ ["abcdefghijklmnop", "hmac", "ver", "client_1"], ["abcdefghijklmnop", "hmac", "sig", "client_1"], [rsapub, "rsa", "sig", "."], [rsapub, "rsa", "ver", "."], ] SIGN_KEY = {"hmac": ["abcdefghijklmnop"]} IDTOKEN = IdToken( iss="http://oic.example.org/", user_id="user_id", aud=CLIENT_ID, exp=time_sans_frac() + 86400, nonce="N0nce" ) # ----------------- CLIENT -------------------- class TestOICClient: def setup_class(self): self.client = Client(CLIENT_ID) self.client.redirect_uris = ["http://example.com/redirect"] self.client.client_secret = CLIENT_SECRET self.client.keystore.set_sign_key(rsapub, "rsa") self.client.keystore.set_verify_key(rsapub, "rsa") def test_areq_1(self): ar = self.client.construct_AuthorizationRequest(request_args={"response_type": ["code"]})
def make_id_token(self, session, loa="2", issuer="", keytype="rsa", code=None, access_token=None, user_info=None): #defaults inawhile = {"days": 1} # Handle the idtoken_claims extra = {} try: oidreq = OpenIDRequest().deserialize(session["oidreq"], "json") itc = oidreq["id_token"] logger.debug("ID Token claims: %s" % itc.to_dict()) try: inawhile = {"seconds": itc["max_age"]} except KeyError: inawhile = {} if "claims" in itc: for key, val in itc["claims"].items(): if key == "auth_time": extra["auth_time"] = time_util.utc_time_sans_frac() elif key == "acr": #["2","http://id.incommon.org/assurance/bronze"] extra["acr"] = verify_acr_level(val, loa) except KeyError: pass if user_info is None: _args = {} else: _args = user_info.to_dict() # Make sure that there are no name clashes for key in ["iss", "user_id", "aud", "exp", "acr", "nonce", "auth_time"]: try: del _args[key] except KeyError: pass if code: _args["c_hash"] = jwt.left_hash(code, "HS256") if access_token: _args["at_hash"] = jwt.left_hash(access_token, "HS256") idt = IdToken(iss=issuer, user_id=session["user_id"], aud = session["client_id"], exp = time_util.epoch_in_a_while(**inawhile), acr=loa, **_args) for key, val in extra.items(): idt[key] = val if "nonce" in session: idt.nonce = session["nonce"] # sign with clients secret key _keystore = self.keystore if keytype == "hmac": ckey = {"hmac": _keystore.get_sign_key("hmac", owner=session["client_id"])} algo = "HS256" elif keytype == "rsa": # own asymmetric key algo = "RS256" ckey = {"rsa": _keystore.get_sign_key("rsa")} else: algo = "ES256" ckey = {"ec":_keystore.get_sign_key("ec")} logger.debug("Sign idtoken with '%s'" % (ckey,)) return idt.to_jwt(key=ckey, algorithm=algo)
def make_id_token(self, session, loa="2", issuer="", alg="RS256", code=None, access_token=None, user_info=None): """ :param session: Session information :param loa: Level of Assurance/Authentication context :param issuer: My identifier :param alg: Which signing algorithm to use for the IdToken :param code: Access grant :param access_token: Access Token :param user_info: If user info are to be part of the IdToken :return: IDToken instance """ #defaults inawhile = {"days": 1} # Handle the idtoken_claims extra = {} itc = self.id_token_claims(session) if itc: try: inawhile = {"seconds": itc["max_age"]} except KeyError: inawhile = {} if "claims" in itc: for key, val in itc["claims"].items(): if key == "auth_time": extra["auth_time"] = time_util.utc_time_sans_frac() elif key == "acr": #["2","http://id.incommon.org/assurance/bronze"] extra["acr"] = verify_acr_level(val, loa) if user_info is None: _args = {} else: _args = user_info.to_dict() # Make sure that there are no name clashes for key in ["iss", "sub", "aud", "exp", "acr", "nonce", "auth_time"]: try: del _args[key] except KeyError: pass halg = "HS%s" % alg[-3:] if code: _args["c_hash"] = jws.left_hash(code, halg) if access_token: _args["at_hash"] = jws.left_hash(access_token, halg) idt = IdToken(iss=issuer, sub=session["sub"], aud = session["client_id"], exp = time_util.epoch_in_a_while(**inawhile), acr=loa, iat = time_util.utc_now(), **_args) for key, val in extra.items(): idt[key] = val if "nonce" in session: idt.nonce = session["nonce"] return idt
def __call__(self, request): data = request.body req = self.provider.parse_token_request(body=data) if 'grant_type' not in req: return (400, {}, 'Missing grant_type') if req['grant_type'] == 'authorization_code': authz_code = req['code'] authz_info = self.provider.authz_codes[authz_code] auth_req = authz_info['auth_req'] client_id = auth_req['client_id'] if authz_info['used']: raise Exception('code already used') return (400, {}, 'Invalid authorization code') if authz_info['exp'] < time.time(): raise Exception('code expired') return (400, {}, 'Invalid authorization code') authz_info['used'] = True access_token = { 'value': rndstr(), 'expires_in': self.provider.access_token_lifetime, 'type': 'Bearer' } at_value = access_token['value'] self.provider.access_tokens[at_value] = { 'iat': time.time(), 'exp': time.time() + self.provider.access_token_lifetime, 'sub': 'test-sub', 'client_id': client_id, 'aud': [client_id], 'scope': authz_info['granted_scope'], 'granted_scope': authz_info['granted_scope'], 'token_type': access_token['type'], 'auth_req': auth_req } resp = AccessTokenResponse() resp['access_token'] = at_value resp['token_type'] = access_token['type'] resp['expires_in'] = access_token['expires_in'] resp['refresh_token'] = None args = { 'c_hash': jws.left_hash(authz_code.encode('utf-8'), 'HS256'), 'at_hash': jws.left_hash(at_value.encode('utf-8'), 'HS256'), } id_token = IdToken( iss=self.config['issuer'], sub='test-sub', aud=client_id, iat=time.time(), exp=time.time() + self.provider.id_token_lifetime, **args) if 'nonce' in auth_req: id_token['nonce'] = auth_req['nonce'] resp['id_token'] = id_token.to_jwt( [self.provider.signing_key], 'RS256') json_data = resp.to_json() return ( 200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', 'Pragma': 'no-cache', }, json_data ) return (400, {}, 'Unsupported grant_type')