def test_roger_patch(tmpdir): root_dir = os.path.join(tmpdir.strpath, "resource/") jrs = JsonResourceServer(root_dir, "info/", "https://example.com") create_alice_resource(jrs) body = json.dumps({"bar": "soap"}) environ = { "REQUEST_METHOD": "PATCH", "REMOTE_USER": "******", 'wsgi.input': StringIO(body), "CONTENT_LENGTH": len(body) } ad = AuthzDescription(resource_set_id=0, scopes=[ "http://dirg.org.umu.se/uma/scopes/read", "http://dirg.org.umu.se/uma/scopes/patch" ], expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse( valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad] ) resp = jrs.do("info/alice/1", environ, permission=ir) assert not isinstance(resp, ErrorResponse) assert resp.message == '{"_id": "1"}'
def test_alice_client_read(tmpdir): root_dir = os.path.join(tmpdir.strpath, "resource/") jrs = JsonResourceServer(root_dir, "info/", "https://example.com") create_alice_resource(jrs) body = json.dumps({"bar": "soap"}) environ = { "REQUEST_METHOD": "GET", "REMOTE_USER": "******", 'wsgi.input': StringIO(body), "CONTENT_LENGTH": len(body) } ad = AuthzDescription(resource_set_id=0, scopes=DEF_SCOPES, expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse(valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad]) resp = jrs.do("info/alice/1", environ, permission=ir) assert not isinstance(resp, ErrorResponse) assert isinstance(resp, Response)
def test_roger_create(): jrs = JsonResourceServer("resource/", "info/", "https://example.com") body = json.dumps({"bar": "soap"}) environ = { "REQUEST_METHOD": "POST", "REMOTE_USER": "******", 'wsgi.input': StringIO(body), "CONTENT_LENGTH": len(body) } ad = AuthzDescription(resource_set_id=0, scopes=["http://dirg.org.umu.se/uma/scopes/read"], expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse( valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad] ) resp = jrs.do("info/alice/1", environ, permission=ir) assert isinstance(resp, ErrorResponse)
def test_alice_client_read(): jrs = JsonResourceServer("resource/", "info/", "https://example.com") body = json.dumps({"bar": "soap"}) environ = { "REQUEST_METHOD": "GET", "REMOTE_USER": "******", 'wsgi.input': StringIO(body), "CONTENT_LENGTH": len(body) } ad = AuthzDescription(resource_set_id=0, scopes=DEF_SCOPES, expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse( valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad] ) resp = jrs.do("info/alice/1", environ, permission=ir) assert not isinstance(resp, ErrorResponse) assert isinstance(resp, Response)
def test_roger_patch(tmpdir): root_dir = os.path.join(tmpdir.strpath, "resource/") jrs = JsonResourceServer(root_dir, "info/", "https://example.com") create_alice_resource(jrs) body = json.dumps({"bar": "soap"}) environ = { "REQUEST_METHOD": "PATCH", "REMOTE_USER": "******", 'wsgi.input': StringIO(body), "CONTENT_LENGTH": len(body) } ad = AuthzDescription(resource_set_id=0, scopes=[ "http://dirg.org.umu.se/uma/scopes/read", "http://dirg.org.umu.se/uma/scopes/patch" ], expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse(valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad]) resp = jrs.do("info/alice/1", environ, permission=ir) assert not isinstance(resp, ErrorResponse) assert resp.message == '{"_id": "1"}'
def upgrade_to_token(self, cont, issue_refresh=False): cont["typ"] = "access" cont["val"] = epoch_in_a_while(self.validity["access"]) if issue_refresh: _c = Content(sub=cont["sub"], aud=cont["aud"], typ="refresh", val=epoch_in_a_while(self.validity["refresh"])) cont["ref"] = _c.to_jwe(self.keys, self.enc, self.alg) return cont
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")
def test_roger_read(): jrs = JsonResourceServer("resource/", "info/", "https://example.com") environ = {"REQUEST_METHOD": "GET", "REMOTE_USER": "******"} ad = AuthzDescription(resource_set_id=0, scopes=["http://dirg.org.umu.se/uma/scopes/read"], expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse( valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad] ) resp = jrs.do("info/alice/1", environ, permission=ir) assert not isinstance(resp, ErrorResponse) assert resp.message == '{"foo": "bar", "_id": 1}'
def create_authz_session(self, sub, areq, **kwargs): """ :param sub: Identifier for the user, this is the real identifier :param areq: The AuthorizationRequest instance :return: The session identifier, which is the database key """ _cont = Content(typ="code", sub=sub, aud=areq["redirect_uri"], val=epoch_in_a_while(self.validity["grant"])) return _cont
def create_authz_session(self, sub, areq, **kwargs): """ :param sub: Identifier for the user, this is the real identifier :param areq: The AuthorizationRequest instance :return: The session identifier, which is the database key """ _cont = Content(typ="code", sub=sub, aud=areq["redirect_uri"], val=epoch_in_a_while(self.validity["grant"])) #return _cont.to_jwe(self.keys, self.enc, self.alg) return _cont
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 test_roger_read(tmpdir): root_dir = os.path.join(tmpdir.strpath, "resource/") jrs = JsonResourceServer(root_dir, "info/", "https://example.com") create_alice_resource(jrs) environ = {"REQUEST_METHOD": "GET", "REMOTE_USER": "******"} ad = AuthzDescription(resource_set_id=0, scopes=["http://dirg.org.umu.se/uma/scopes/read"], expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse(valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad]) resp = jrs.do("info/alice/1", environ, permission=ir) assert not isinstance(resp, ErrorResponse) assert resp.message in [ '{"foo": "bar", "_id": 1}', '{"_id": 1, "foo": "bar"}' ]
def test_roger_create(): jrs = JsonResourceServer("resource/", "info/", "https://example.com") body = json.dumps({"bar": "soap"}) environ = { "REQUEST_METHOD": "POST", "REMOTE_USER": "******", 'wsgi.input': StringIO(body), "CONTENT_LENGTH": len(body) } ad = AuthzDescription(resource_set_id=0, scopes=["http://dirg.org.umu.se/uma/scopes/read"], expires_at=epoch_in_a_while(minutes=45)) ir = IntrospectionResponse(valid=True, expires_at=epoch_in_a_while(minutes=45), issued_at=utc_time_sans_frac, permissions=[ad]) resp = jrs.do("info/alice/1", environ, permission=ir) assert isinstance(resp, ErrorResponse)
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_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 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 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 assertion_jwt(cli, keys, audience, algorithm=OIC_DEF_SIGN_ALG): at = AuthnToken(iss = cli.client_id, prn = cli.client_id, aud = audience, jti = rndstr(8), exp = int(epoch_in_a_while(minutes=10)), iat = utc_now()) return at.to_jwt(key=keys, algorithm=algorithm)
def make_id_token(self, session, loa="2", issuer="", alg="RS256", code=None, access_token=None, user_info=None, auth_time=0): """ :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 = {} for key, val in itc.items(): if key == "auth_time": extra["auth_time"] = auth_time elif key == "acr": #["2","http://id.incommon.org/assurance/bronze"] extra["acr"] = verify_acr_level(val, loa) if user_info is None: _args = {} else: try: _args = user_info.to_dict() except AttributeError: _args = user_info # 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 make_id_token( self, session, loa="2", issuer="", alg="RS256", code=None, access_token=None, user_info=None, auth_time=0, exp=None, extra_claims=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 if exp is None: inawhile = {"days": 1} else: inawhile = exp # Handle the idtoken_claims extra = {} itc = self.id_token_claims(session) if itc: try: inawhile = {"seconds": itc["max_age"]} except KeyError: pass for key, val in itc.items(): if key == "auth_time": extra["auth_time"] = auth_time elif key == "acr": # ["2","http://id.incommon.org/assurance/bronze"] extra["acr"] = verify_acr_level(val, loa) else: if auth_time: extra["auth_time"] = auth_time if loa: extra["acr"] = loa if not user_info: _args = {} else: try: _args = user_info.to_dict() except AttributeError: _args = user_info # 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 extra_claims is not None: _args.update(extra_claims) if code: _args["c_hash"] = jws.left_hash(code.encode("utf-8"), halg) if access_token: _args["at_hash"] = jws.left_hash(access_token.encode("utf-8"), halg) # Should better be done elsewhere if not issuer.endswith("/"): issuer += "/" 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_time_sans_frac(), **_args ) for key, val in extra.items(): idt[key] = val if "nonce" in session: idt["nonce"] = session["nonce"] return idt