def test_scope_who_am_i(provider):
    registration_params = {
        "application_type": "web",
        "response_types": ["code", "token"],
        "redirect_uris": "http://example.org"
    }
    reg_req = RegistrationRequest(**registration_params)
    resp = provider.registration_endpoint(reg_req.to_urlencoded())
    reg_resp = RegistrationResponse().from_json(resp.message)

    auth_req = AuthorizationRequest(
        **{
            "client_id": reg_resp["client_id"],
            "scope": "openid who_am_i",
            "response_type": "code token",
            "redirect_uri": "http://example.org",
            "state": "state0",
            "nonce": "nonce0"
        })
    resp = provider.authorization_endpoint(auth_req.to_urlencoded())
    auth_resp = AuthorizationResponse().from_urlencoded(resp.message)

    userinfo_req = UserInfoRequest(
        **{"access_token": auth_resp["access_token"]})
    resp = provider.userinfo_endpoint(userinfo_req.to_urlencoded())
    userinfo_resp = AuthorizationResponse().from_json(resp.message)

    assert userinfo_resp["given_name"] == "Bruce"
    assert userinfo_resp["family_name"] == "Lee"
Ejemplo n.º 2
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]
Ejemplo n.º 3
0
    def test_userinfo_request(self):
        aresp = AuthorizationResponse(code="code", state="state000")
        tresp = AccessTokenResponse(
            access_token="access_token",
            token_type="Bearer",
            expires_in=600,
            refresh_token="refresh",
            scope=["openid"],
        )

        self.client.parse_response(
            AuthorizationResponse,
            aresp.to_urlencoded(),
            sformat="urlencoded",
            state="state0",
        )
        self.client.parse_response(AccessTokenResponse,
                                   tresp.to_json(),
                                   state="state0")

        path, body, method, h_args = self.client.user_info_request(
            state="state0")
        assert path == "http://example.com/userinfo"
        assert method == "GET"
        assert body is None
        assert h_args == {"headers": {"Authorization": "Bearer access_token"}}
Ejemplo n.º 4
0
    def test_userinfo_request_post(self):
        aresp = AuthorizationResponse(code="code", state="state000")
        tresp = AccessTokenResponse(
            access_token="access_token",
            token_type="bearer",
            expires_in=600,
            refresh_token="refresh",
            scope=["openid"],
        )

        self.client.parse_response(
            AuthorizationResponse,
            aresp.to_urlencoded(),
            sformat="urlencoded",
            state="state0",
        )
        self.client.parse_response(AccessTokenResponse,
                                   tresp.to_json(),
                                   state="state0")

        path, body, method, h_args = self.client.user_info_request(
            method="POST", state="state0")

        assert path == "http://example.com/userinfo"
        assert method == "POST"
        assert body == "access_token=access_token"
        assert h_args == {
            "headers": {
                "Content-Type": "application/x-www-form-urlencoded"
            }
        }
Ejemplo n.º 5
0
 def parse_authentication_response(self, redirect_uri, fragment_encoded=False):
     parsed_url = urlparse(redirect_uri)
     if fragment_encoded:
         response = parsed_url.fragment
     else:
         response = parsed_url.query
     authn_response = AuthorizationResponse().from_urlencoded(response)
     assert authn_response.verify(key=[self.app.provider.signing_key])
     return authn_response
Ejemplo n.º 6
0
    def id_token(self, released_claims, idp_entity_id, transaction_id, transaction_session):
        """Make a JWT encoded id token and pass it to the redirect URI.

        :param released_claims: dictionary containing the following
            user_id: identifier for the user (as delivered by the IdP, dependent on whether transient or persistent
                        id was requested)
            auth_time: time of the authentication reported from the IdP
            idp_entity_id: entity id of the selected IdP
        :param transaction_id:
        :return: raises cherrypy.HTTPRedirect.
        """

        identifier = released_claims["Identifier"]
        auth_time = released_claims["Authentication time"]

        # have to convert text representation into seconds since epoch
        _time = time.mktime(str_to_time(auth_time))

        # construct the OIDC response
        transaction_session["sub"] = identifier

        extra_claims = {k.lower(): released_claims[k] for k in ["Country", "Domain"] if k in released_claims}
        _jwt = self.OP.id_token_as_signed_jwt(transaction_session, loa="", auth_time=_time, exp={"minutes": 30},
                                              extra_claims=extra_claims)

        _elapsed_transaction_time = get_timestamp() - transaction_session["start_time"]
        log_transaction_complete(logger, cherrypy.request, transaction_id,
                                 transaction_session["client_id"],
                                 idp_entity_id, _time, _elapsed_transaction_time,
                                 extra_claims, _jwt)

        try:
            _state = transaction_session["state"]
        except KeyError:
            _state = None
        authzresp = AuthorizationResponse(state=_state, id_token=_jwt)

        if "redirect_uri" in transaction_session:
            _ruri = transaction_session["redirect_uri"]
        else:
            _error_msg = _("We could not complete your validation because an error occurred while "
                           "handling your request. Please return to the service which initiated the "
                           "validation request and try again.")
            try:
                cinfo = self.OP.cdb[transaction_session["client_id"]]
                _ruri = cinfo["redirect_uris"][0]
            except KeyError as e:
                abort_with_enduser_error(transaction_id, transaction_session["client_id"], cherrypy.request, logger,
                                         _error_msg,
                                         "Unknown RP client id '{}': '{}'.".format(transaction_session["client_id"],
                                                                                   str(e)))

        location = authzresp.request(_ruri, True)
        logger.debug("Redirected to: '{}' ({})".format(location, type(location)))
        raise cherrypy.HTTPRedirect(location)
Ejemplo n.º 7
0
    def authorization_endpoint(self, query):
        req = self.parse_authorization_request(query=query)
        aevent = AuthnEvent("user", "salt", authn_info="acr")
        sid = self.sdb.create_authz_session(aevent, areq=req)
        self.sdb.do_sub(sid, 'client_salt')
        _info = self.sdb[sid]

        if "code" in req["response_type"]:
            if "token" in req["response_type"]:
                grant = _info["code"]
                _dict = self.sdb.upgrade_to_token(grant)
                _dict["oauth_state"] = "authz",

                _dict = by_schema(AuthorizationResponse(), **_dict)
                resp = AuthorizationResponse(**_dict)
            else:
                _state = req["state"]
                resp = AuthorizationResponse(state=_state,
                                             code=_info["code"])

        else:  # "implicit" in req.response_type:
            grant = _info["code"]
            params = AccessTokenResponse.c_param.keys()

            if "token" in req["response_type"]:
                _dict = dict([(k, v) for k, v in
                              self.sdb.upgrade_to_token(grant).items() if k in
                              params])
                try:
                    del _dict["refresh_token"]
                except KeyError:
                    pass
            else:
                _dict = {"state": req["state"]}

            if "id_token" in req["response_type"]:
                _idt = self.make_id_token(_info, issuer=self.name)
                alg = "RS256"
                ckey = self.keyjar.get_signing_key(alg2keytype(alg),
                                                   _info["client_id"])
                _signed_jwt = _idt.to_jwt(key=ckey, algorithm=alg)
                p = _signed_jwt.split(".")
                p[2] = "aaa"
                _dict["id_token"] = ".".join(p)

            resp = AuthorizationResponse(**_dict)

        location = resp.request(req["redirect_uri"])
        response = Response()
        response.headers = {"location": location}
        response.status_code = 302
        response.text = ""
        return response
Ejemplo n.º 8
0
    def handle_authn_response(self, context, internal_resp):
        """
        See super class method satosa.frontends.base.FrontendModule#handle_authn_response
        :type context: satosa.context.Context
        :type internal_response: satosa.internal_data.InternalResponse
        :rtype oic.utils.http_util.Response
        """
        auth_req = self._get_authn_request_from_state(context.state)

        # filter attributes to return in ID Token as claims
        attributes = self.converter.from_internal(
            "openid", internal_resp.get_attributes())
        satosa_logging(
            LOGGER, logging.DEBUG,
            "Attributes delivered by backend to OIDC frontend: {}".format(
                json.dumps(attributes)), context.state)
        flattened_attributes = {k: v[0] for k, v in attributes.items()}
        requested_id_token_claims = auth_req.get("claims", {}).get("id_token")
        user_claims = self._get_user_info(flattened_attributes,
                                          requested_id_token_claims,
                                          auth_req["scope"])
        satosa_logging(
            LOGGER, logging.DEBUG,
            "Attributes filtered by requested claims/scope: {}".format(
                json.dumps(user_claims)), context.state)

        # construct epoch timestamp of reported authentication time
        auth_time = datetime.datetime.strptime(
            internal_resp.auth_info.timestamp, "%Y-%m-%dT%H:%M:%SZ")
        epoch_timestamp = (auth_time -
                           datetime.datetime(1970, 1, 1)).total_seconds()

        base_claims = {
            "client_id": auth_req["client_id"],
            "sub": internal_resp.get_user_id(),
            "nonce": auth_req["nonce"]
        }
        id_token = self.provider.id_token_as_signed_jwt(
            base_claims,
            user_info=user_claims,
            auth_time=epoch_timestamp,
            loa="",
            alg=self.sign_alg)

        oidc_client_state = auth_req.get("state")
        kwargs = {}
        if oidc_client_state:  # inlcude any optional 'state' sent by the client in the authn req
            kwargs["state"] = oidc_client_state

        auth_resp = AuthorizationResponse(id_token=id_token, **kwargs)
        http_response = auth_resp.request(
            auth_req["redirect_uri"], self._should_fragment_encode(auth_req))
        return SeeOther(http_response)
Ejemplo n.º 9
0
    def test_do_user_info_request(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant(10)  # expired grant
        grant.add_code(resp)
        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")
        token = Token(resp)
        grant.tokens.append(token)
        self.client.grant["state0"] = grant

        resp = self.client.do_user_info_request(state="state0")
        assert isinstance(resp, OpenIDSchema)
        assert _eq(resp.keys(),
                   ['name', 'email', 'verified', 'nickname', 'sub'])
        assert resp["name"] == "Melody Gardot"
Ejemplo n.º 10
0
    def setup_userinfo_endpoint(self):
        cons = Consumer(
            {},
            CONSUMER_CONFIG,
            {"client_id": CLIENT_ID},
            server_info=SERVER_INFO,
        )
        cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        cons.keyjar[""] = KC_RSA

        cons.client_secret = "drickyoughurt"
        state, location = cons.begin(
            "openid", "token", path=TestConfiguration.get_instance().rp_base)

        resp = self.provider.authorization_endpoint(
            request=urlparse(location).query)

        # redirect
        atr = AuthorizationResponse().deserialize(
            urlparse(resp.message).fragment, "urlencoded")

        uir = UserInfoRequest(access_token=atr["access_token"],
                              schema="openid")
        resp = self.provider.userinfo_endpoint(request=uir.to_urlencoded())
        responses.add(responses.POST,
                      self.op_base + "userinfo",
                      body=resp.message,
                      status=200,
                      content_type='application/json')
Ejemplo n.º 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"}
Ejemplo n.º 12
0
    def test_userinfo_endpoint(self):
        self.cons.client_secret = "drickyoughurt"
        self.cons.config["response_type"] = ["token"]
        self.cons.config["request_method"] = "parameter"

        state, location = self.cons.begin("openid",
                                          "token",
                                          path="http://localhost:8087")

        resp = self.server.authorization_endpoint(
            request=location.split("?")[1])

        line = resp.message
        path, query = line.split("#")

        # redirect
        atr = AuthorizationResponse().deserialize(query, "urlencoded")

        uir = UserInfoRequest(access_token=atr["access_token"],
                              schema="openid")

        resp3 = self.server.userinfo_endpoint(request=uir.to_urlencoded())
        ident = OpenIDSchema().deserialize(resp3.message, "json")
        print ident.keys()
        assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
Ejemplo n.º 13
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",
        )
Ejemplo n.º 14
0
def test_userinfo_endpoint():
    server = provider_init

    _session_db = {}
    cons = Consumer(_session_db,
                    CONSUMER_CONFIG,
                    CLIENT_CONFIG,
                    server_info=SERVER_INFO)
    cons.debug = True
    cons.client_secret = "drickyoughurt"
    cons.config["response_type"] = ["token"]
    cons.config["request_method"] = "parameter"
    cons.keyjar[""] = KC_RSA

    state, location = cons.begin("openid",
                                 "token",
                                 path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    line = resp.message
    path, query = line.split("#")

    # redirect
    atr = AuthorizationResponse().deserialize(query, "urlencoded")

    uir = UserInfoRequest(access_token=atr["access_token"], schema="openid")

    resp3 = server.userinfo_endpoint(request=uir.to_urlencoded())
    ident = OpenIDSchema().deserialize(resp3.message, "json")
    print ident.keys()
    assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
Ejemplo n.º 15
0
    def test_do_user_info_request(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant(10)  # expired grant
        grant.add_code(resp)
        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access",
                                   token_type="Bearer")
        token = Token(resp)
        grant.tokens.append(token)
        self.client.grant["state0"] = grant

        resp = self.client.do_user_info_request(state="state0")
        assert isinstance(resp, OpenIDSchema)
        assert _eq(resp.keys(),
                   ['name', 'email', 'verified', 'nickname', 'sub'])
        assert resp["name"] == "Melody Gardot"
Ejemplo n.º 16
0
    def test_do_user_info_request(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant(10)  # expired grant
        grant.add_code(resp)
        resp2 = AccessTokenResponse(
            refresh_token="refresh_with_me", access_token="access", token_type="Bearer"
        )
        token = Token(resp2)
        grant.tokens.append(token)
        self.client.grant["state0"] = grant
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.POST,
                "https://example.com/userinfo",
                content_type="application/json",
                json={
                    "name": "Melody Gardot",
                    "email": "*****@*****.**",
                    "verified": False,
                    "nickname": "Melody",
                    "sub": "some sub",
                },
            )

            resp3 = self.client.do_user_info_request(state="state0")
        assert isinstance(resp3, OpenIDSchema)
        assert _eq(resp3.keys(), ["name", "email", "verified", "nickname", "sub"])
        assert resp3["name"] == "Melody Gardot"
Ejemplo n.º 17
0
    def test_client_id(self):
        resp = AuthorizationResponse(code="code",
                                     state="stateX").to_urlencoded()
        self.client.parse_response(AuthorizationResponse,
                                   resp,
                                   sformat="urlencoded")
        args = {
            "code": "code",
            "redirect_uri": self.client.redirect_uris[0],
            "client_id": self.client.client_id,
        }

        url, query, ht_args, cis = self.client.request_info(
            AccessTokenRequest,
            method="POST",
            request_args=args,
            state="stateX",
            authn_method="client_secret_basic",
            grant_type="authorization_code",
        )

        assert "client_id" not in cis

        args = {"code": "code", "redirect_uri": self.client.redirect_uris[0]}

        url, query, ht_args, cis = self.client.request_info(
            AccessTokenRequest,
            method="POST",
            request_args=args,
            state="stateX",
            authn_method="client_secret_basic",
            grant_type="authorization_code",
        )

        assert "client_id" not in cis
Ejemplo n.º 18
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",
        )
Ejemplo n.º 19
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",
        )
Ejemplo n.º 20
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
Ejemplo n.º 21
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",
    )
Ejemplo n.º 22
0
    def test_verify_token_type(self):
        args = {"access_token": "foobar", "token_type": "bearer"}
        ar = AuthorizationResponse(**args)
        ar.verify()

        args = {"access_token": "foobar"}
        ar = AuthorizationResponse(**args)
        with pytest.raises(MissingRequiredValue):
            ar.verify()
Ejemplo n.º 23
0
    def authorize(self, authentication_request,  # type: oic.oic.message.AuthorizationRequest
                  user_id,  # type: str
                  extra_id_token_claims=None
                  # type: Optional[Union[Mapping[str, Union[str, List[str]]], Callable[[str, str], Mapping[str, Union[str, List[str]]]]]
                  ):
        # type: (...) -> oic.oic.message.AuthorizationResponse
        """
        Creates an Authentication Response for the specified authentication request and local identifier of the
        authenticated user.
        """
        custom_sub = self.userinfo[user_id].get('sub')
        if custom_sub:
            self.authz_state.subject_identifiers[user_id] = {'public': custom_sub}
            sub = custom_sub
        else:
            sub = self._create_subject_identifier(user_id, authentication_request['client_id'],
                                                  authentication_request['redirect_uri'])

        self._check_subject_identifier_matches_requested(authentication_request, sub)
        response = AuthorizationResponse()

        authz_code = None
        if 'code' in authentication_request['response_type']:
            authz_code = self.authz_state.create_authorization_code(authentication_request, sub)
            response['code'] = authz_code

        access_token_value = None
        if 'token' in authentication_request['response_type']:
            access_token = self.authz_state.create_access_token(authentication_request, sub)
            access_token_value = access_token.value
            self._add_access_token_to_response(response, access_token)

        if 'id_token' in authentication_request['response_type']:
            if extra_id_token_claims is None:
                extra_id_token_claims = {}
            elif callable(extra_id_token_claims):
                extra_id_token_claims = extra_id_token_claims(user_id, authentication_request['client_id'])

            requested_claims = self._get_requested_claims_in(authentication_request, 'id_token')
            if len(authentication_request['response_type']) == 1:
                # only id token is issued -> no way of doing userinfo request, so include all claims in ID Token,
                # even those requested by the scope parameter
                requested_claims.update(
                    scope2claims(
                        authentication_request['scope'], extra_scope_dict=self.extra_scopes
                    )
                )

            user_claims = self.userinfo.get_claims_for(user_id, requested_claims)
            response['id_token'] = self._create_signed_id_token(authentication_request['client_id'], sub,
                                                                user_claims,
                                                                authentication_request.get('nonce'),
                                                                authz_code, access_token_value, extra_id_token_claims)
            logger.debug('issued id_token=%s from requested_claims=%s userinfo=%s extra_claims=%s',
                         response['id_token'], requested_claims, user_claims, extra_id_token_claims)

        if 'state' in authentication_request:
            response['state'] = authentication_request['state']
        return response
Ejemplo n.º 24
0
    def test_full_flow(self, context, frontend_with_extra_scopes):
        redirect_uri = "https://client.example.com/redirect"
        response_type = "code id_token token"
        mock_callback = Mock()
        frontend_with_extra_scopes.auth_req_callback_func = mock_callback
        # discovery
        http_response = frontend_with_extra_scopes.provider_config(context)
        provider_config = ProviderConfigurationResponse().deserialize(http_response.message, "json")

        # client registration
        registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=[response_type])
        context.request = registration_request.to_dict()
        http_response = frontend_with_extra_scopes.client_registration(context)
        registration_response = RegistrationResponse().deserialize(http_response.message, "json")

        # authentication request
        authn_req = AuthorizationRequest(
            redirect_uri=redirect_uri,
            client_id=registration_response["client_id"],
            response_type=response_type,
            scope="openid email eduperson",
            state="state",
            nonce="nonce",
        )
        context.request = dict(parse_qsl(authn_req.to_urlencoded()))
        frontend_with_extra_scopes.handle_authn_request(context)
        assert mock_callback.call_count == 1

        # fake authentication response from backend
        internal_response = self.setup_for_authn_response(
            context, frontend_with_extra_scopes, authn_req
        )
        http_response = frontend_with_extra_scopes.handle_authn_response(
            context, internal_response
        )
        authn_resp = AuthorizationResponse().deserialize(urlparse(http_response.message).fragment, "urlencoded")
        assert "code" in authn_resp
        assert "access_token" in authn_resp
        assert "id_token" in authn_resp

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

        http_response = frontend_with_extra_scopes.token_endpoint(context)
        parsed = AccessTokenResponse().deserialize(http_response.message, "json")
        assert "access_token" in parsed
        assert "id_token" in parsed

        # userinfo request
        context.request = {}
        context.request_authorization = "Bearer {}".format(parsed["access_token"])
        http_response = frontend_with_extra_scopes.userinfo_endpoint(context)
        parsed = OpenIDSchema().deserialize(http_response.message, "json")
        assert "email" in parsed
        assert "eduperson_principal_name" in parsed
        assert "eduperson_scoped_affiliation" in parsed
Ejemplo n.º 25
0
    def handle_authn_response(self, context, internal_resp):
        """
        See super class method satosa.frontends.base.FrontendModule#handle_authn_response
        :type context: satosa.context.Context
        :type internal_response: satosa.internal_data.InternalResponse
        :rtype oic.utils.http_util.Response
        """
        auth_req = self._get_authn_request_from_state(context.state)

        # filter attributes to return in ID Token as claims
        attributes = self.converter.from_internal("openid", internal_resp.get_attributes())
        satosa_logging(LOGGER, logging.DEBUG,
                       "Attributes delivered by backend to OIDC frontend: {}".format(
                               json.dumps(attributes)), context.state)
        flattened_attributes = {k: v[0] for k, v in attributes.items()}
        requested_id_token_claims = auth_req.get("claims", {}).get("id_token")
        user_claims = self._get_user_info(flattened_attributes,
                                          requested_id_token_claims,
                                          auth_req["scope"])
        satosa_logging(LOGGER, logging.DEBUG,
                       "Attributes filtered by requested claims/scope: {}".format(
                               json.dumps(user_claims)), context.state)

        # construct epoch timestamp of reported authentication time
        auth_time = datetime.datetime.strptime(internal_resp.auth_info.timestamp,
                                               "%Y-%m-%dT%H:%M:%SZ")
        epoch_timestamp = (auth_time - datetime.datetime(1970, 1, 1)).total_seconds()

        base_claims = {"client_id": auth_req["client_id"],
                       "sub": internal_resp.get_user_id(),
                       "nonce": auth_req["nonce"]}
        id_token = self.provider.id_token_as_signed_jwt(base_claims, user_info=user_claims,
                                                        auth_time=epoch_timestamp,
                                                        loa="",
                                                        alg=self.sign_alg)

        oidc_client_state = auth_req.get("state")
        kwargs = {}
        if oidc_client_state:  # inlcude any optional 'state' sent by the client in the authn req
            kwargs["state"] = oidc_client_state

        auth_resp = AuthorizationResponse(id_token=id_token, **kwargs)
        http_response = auth_resp.request(auth_req["redirect_uri"],
                                          self._should_fragment_encode(auth_req))
        return SeeOther(http_response)
Ejemplo n.º 26
0
    def authorization_endpoint(self, query):
        req = self.parse_authorization_request(query=query)
        aevent = AuthnEvent("user", "salt", authn_info="acr")
        sid = self.sdb.create_authz_session(aevent, areq=req)
        self.sdb.do_sub(sid, 'client_salt')
        _info = self.sdb[sid]

        if "code" in req["response_type"]:
            if "token" in req["response_type"]:
                grant = _info["code"]
                _dict = self.sdb.upgrade_to_token(grant)
                _dict["oauth_state"] = "authz",

                _dict = by_schema(AuthorizationResponse(), **_dict)
                resp = AuthorizationResponse(**_dict)
                # resp.code = grant
            else:
                _state = req["state"]
                resp = AuthorizationResponse(state=_state, code=_info["code"])

        else:  # "implicit" in req.response_type:
            grant = _info["code"]
            params = AccessTokenResponse.c_param.keys()

            if "token" in req["response_type"]:
                _dict = dict([
                    (k, v)
                    for k, v in self.sdb.upgrade_to_token(grant).items()
                    if k in params
                ])
                try:
                    del _dict["refresh_token"]
                except KeyError:
                    pass
            else:
                _dict = {"state": req["state"]}

            if "id_token" in req["response_type"]:
                _idt = self.make_id_token(_info, issuer=self.name)
                alg = "RS256"
                ckey = self.keyjar.get_signing_key(alg2keytype(alg),
                                                   _info["client_id"])
                _signed_jwt = _idt.to_jwt(key=ckey, algorithm=alg)
                p = _signed_jwt.split(".")
                p[2] = "aaa"
                _dict["id_token"] = ".".join(p)

            resp = AuthorizationResponse(**_dict)

        location = resp.request(req["redirect_uri"])
        response = Response()
        response.headers = {"location": location}
        response.status_code = 302
        response.text = ""
        return response
Ejemplo n.º 27
0
    def test_full_flow(self):
        self.do_auth_flow()

        # incoming accepted consent, verify response is OIDC authn response to client
        resp = self.app.get('/consent/handle_consent/allow')
        assert resp.status_code == 303
        authn_resp = AuthorizationResponse().from_urlencoded(
            urlparse(dict(resp.headers)['Location']).fragment)
        assert 'id_token' in authn_resp
    def test_userinfo_request(self):
        aresp = AuthorizationResponse(code="code", state="state000")
        tresp = AccessTokenResponse(access_token="access_token",
                                    token_type="Bearer",
                                    expires_in=600, refresh_token="refresh",
                                    scope=["openid"])

        self.client.parse_response(AuthorizationResponse, aresp.to_urlencoded(),
                                   sformat="urlencoded", state="state0")
        self.client.parse_response(AccessTokenResponse, tresp.to_json(),
                                   state="state0")

        path, body, method, h_args = self.client.user_info_request(
                state="state0")
        assert path == "http://example.com/userinfo"
        assert method == "GET"
        assert body is None
        assert h_args == {'headers': {'Authorization': 'Bearer access_token'}}
Ejemplo n.º 29
0
    def test_full_flow_with_denied_user_consent(self):
        self.do_auth_flow()

        # incoming denied consent, verify response is OIDC authn error response 'access_denied'
        resp = self.app.get('/consent/handle_consent/deny')
        assert resp.status_code == 303
        authn_resp = AuthorizationResponse().from_urlencoded(
            urlparse(dict(resp.headers)['Location']).fragment)
        assert authn_resp['error'] == 'access_denied'
Ejemplo n.º 30
0
def test_get_access_token_request():
    resp = AuthorizationResponse(code="code", state="state")

    grant = Grant(1)
    grant.add_code(resp)

    client = Client()
    client.grant["openid"] = grant
    time.sleep(2)
    raises(GrantExpired, 'client.construct_AccessTokenRequest(state="openid")')
Ejemplo n.º 31
0
def test_client_get_grant():
    cli = Client()

    resp = AuthorizationResponse(code="code", state="state")
    grant = Grant()
    grant.add_code(resp)

    cli.grant["state"] = grant

    gr1 = cli.grant_from_state("state")

    assert gr1.code == "code"
    def test_userinfo_request_post(self):
        aresp = AuthorizationResponse(code="code", state="state000")
        tresp = AccessTokenResponse(access_token="access_token",
                                    token_type="bearer",
                                    expires_in=600, refresh_token="refresh",
                                    scope=["openid"])

        self.client.parse_response(AuthorizationResponse, aresp.to_urlencoded(),
                                   sformat="urlencoded", state="state0")
        self.client.parse_response(AccessTokenResponse, tresp.to_json(),
                                   state="state0")

        path, body, method, h_args = self.client.user_info_request(
                method="POST",
                state="state0")

        assert path == "http://example.com/userinfo"
        assert method == "POST"
        assert body == "access_token=access_token"
        assert h_args == {'headers': {
            'Content-Type': 'application/x-www-form-urlencoded'}}
    def __call__(self, request):
        query = urlparse(request.url).query

        req = self.provider.parse_authorization_request(query=query)

        resp = AuthorizationResponse()

        if 'code' in req['response_type']:
            authz_code = rndstr(10)
            authz_info = {
                'used': False,
                'exp': time.time() + self.provider.authorization_code_lifetime,
                'sub': 'test-sub',
                'granted_scope': ' '.join(req['scope']),
                'auth_req': req.to_dict()
            }
            self.provider.authz_codes[authz_code] = authz_info

            resp['code'] = authz_code

        if 'state' in req:
            resp['state'] = req['state']

        return (302, {'Location': resp.request(req['redirect_uri'])}, '')
Ejemplo n.º 34
0
    def test_handle_authn_response(self, context, frontend, authn_req):
        self.insert_client_in_client_db(frontend, authn_req["redirect_uri"])
        internal_response = self.setup_for_authn_response(context, frontend, authn_req)
        http_resp = frontend.handle_authn_response(context, internal_response)
        assert http_resp.message.startswith(authn_req["redirect_uri"])

        resp = AuthorizationResponse().deserialize(urlparse(http_resp.message).fragment)
        assert resp["state"] == authn_req["state"]
        id_token = IdToken().from_jwt(resp["id_token"], key=[frontend.signing_key])
        assert id_token["iss"] == BASE_URL
        assert id_token["nonce"] == authn_req["nonce"]
        assert id_token["aud"] == [authn_req["client_id"]]
        assert "sub" in id_token
        assert id_token["email"] == USERS["testuser1"]["email"][0]
        assert frontend.name not in context.state
    def __call__(self, request):
        query = urlparse(request.url).query

        req = self.provider.parse_authorization_request(query=query)

        resp = AuthorizationResponse()

        if 'code' in req['response_type']:
            authz_code = rndstr(10)
            authz_info = {
                'used': False,
                'exp': time.time() + self.provider.authorization_code_lifetime,
                'sub': 'test-sub',
                'granted_scope': ' '.join(req['scope']),
                'auth_req': req.to_dict()
            }
            self.provider.authz_codes[authz_code] = authz_info

            resp['code'] = authz_code

        if 'state' in req:
            resp['state'] = req['state']

        return (302, {'Location': resp.request(req['redirect_uri'])}, '')
Ejemplo n.º 36
0
    def test_verify_token_type(self):
        args = {
            "access_token": "foobar",
            "token_type": "bearer"
            }
        ar = AuthorizationResponse(**args)
        ar.verify()

        args = {
            "access_token": "foobar",
            }
        ar = AuthorizationResponse(**args)
        with pytest.raises(MissingRequiredValue):
            ar.verify()
def test_dynamic_client(provider_info, browser):
    redirect_uri = "http://localhost"
    # Dynamic registration
    reg_req = RegistrationRequest(**{"redirect_uris": [redirect_uri], "response_types": ["id_token"]})
    resp = requests.post(reg_req.request(provider_info["registration_endpoint"]))
    reg_resp = RegistrationResponse().from_json(resp.text)

    # Authentication
    auth_req = AuthorizationRequest(
        **{"client_id": reg_resp["client_id"], "scope": "openid", "response_type": "id_token",
           "redirect_uri": redirect_uri, "state": "state0", "nonce": "nonce0"})
    browser.get(auth_req.request(provider_info["authorization_endpoint"]))
    fill_login_details(browser)

    # Authentication response
    urlencoded_resp = urlparse(browser.current_url).fragment
    auth_resp = AuthorizationResponse().from_urlencoded(urlencoded_resp)
    idt = IdToken().from_jwt(auth_resp["id_token"], verify=False)
    assert browser.current_url.startswith(redirect_uri)
    assert auth_resp["state"] == "state0"
    assert idt["nonce"] == "nonce0"
Ejemplo n.º 38
0
    def test_userinfo_endpoint_authn(self):
        self.cons.client_secret = "drickyoughurt"
        self.cons.config["response_type"] = ["token"]
        self.cons.config["request_method"] = "parameter"
        state, location = self.cons.begin("openid", "token",
                                          path="http://localhost:8087")

        resp = self.provider.authorization_endpoint(
                request=urlparse(location).query)

        # redirect
        atr = AuthorizationResponse().deserialize(
                urlparse(resp.message).fragment, "urlencoded")

        uir = UserInfoRequest(schema="openid")

        resp = self.provider.userinfo_endpoint(request=uir.to_urlencoded(),
                                               authn='Bearer ' + atr[
                                                   'access_token'])
        ident = OpenIDSchema().deserialize(resp.message, "json")
        assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
Ejemplo n.º 39
0
 def test_do_user_info_request_http_errors(self):
     resp = AuthorizationResponse(code="code", state="state")
     grant = Grant(10)  # expired grant
     grant.add_code(resp)
     resp2 = AccessTokenResponse(
         refresh_token="refresh_with_me", access_token="access", token_type="Bearer"
     )
     token = Token(resp2)
     grant.tokens.append(token)
     self.client.grant["state0"] = grant
     with responses.RequestsMock() as rsps:
         rsps.add(
             responses.POST,
             "https://example.com/userinfo",
             status=405,
             headers={"Allow": "GET"},
         )
         with pytest.raises(CommunicationError) as excp:
             self.client.do_user_info_request(state="state0")
         assert excp.value.args[0] == "Server responded with HTTP Error Code 405"
         assert excp.value.args[1] == ["GET"]
Ejemplo n.º 40
0
    def authz_part2(self, user, areq, sid, **kwargs):
        """
        After the authentication this is where you should end up
        """
        _log_debug = logger.debug
        _log_debug("- in authenticated() -")

        # Do the authorization
        try:
            info = OpenIDSchema(**self._collect_user_info(self.sdb[sid]))
            permission = self.authz(user)
            self.sdb.update(sid, "permission", permission)
        except Exception:
            raise

        _log_debug("response type: %s" % areq["response_type"])

        # create the response
        aresp = AuthorizationResponse()
        try:
            aresp["state"] = areq["state"]
        except KeyError:
            pass

        if "response_type" in areq and \
                len(areq["response_type"]) == 1 and \
                "none" in areq["response_type"]:
            pass
        else:
            if self.sdb.is_revoked(sid):
                return self._error(error="access_denied",
                                   descr="Token is revoked")

            _sinfo = self.sdb[sid]

            try:
                aresp["scope"] = areq["scope"]
            except KeyError:
                pass

            _log_debug("_dic: %s" % _sinfo)

            rtype = set(areq["response_type"][:])
            if "code" in areq["response_type"]:
                #if issue_new_code:
                #    scode = self.sdb.duplicate(_sinfo)
                #    _sinfo = self.sdb[scode]

                _code = aresp["code"] = _sinfo["code"]
                rtype.remove("code")
            else:
                self.sdb[sid]["code"] = None
                _code = None

            if "token" in rtype:
                _dic = self.sdb.update_to_token(issue_refresh=False, key=sid)

                _log_debug("_dic: %s" % _dic)
                for key, val in _dic.items():
                    if key in aresp.parameters() and val is not None:
                        aresp[key] = val

                rtype.remove("token")

            try:
                _access_token = aresp["access_token"]
            except KeyError:
                _access_token = None

            if "id_token" in areq["response_type"]:
                user_info = self.userinfo_in_id_token_claims(_sinfo)
                client_info = self.cdb[areq["client_id"]]

                id_token = self.sign_encrypt_id_token(
                    _sinfo, client_info, areq, code=_code,
                    access_token=_access_token, user_info=user_info)

                aresp["id_token"] = id_token
                _sinfo["id_token"] = id_token
                rtype.remove("id_token")

            if len(rtype):
                return BadRequest("Unknown response type")

        try:
            redirect_uri = self.get_redirect_uri(areq)
        except (RedirectURIError, ParameterError), err:
            return BadRequest("%s" % err)
Ejemplo n.º 41
0
                                                    "json")

            _log_debug("areq: %s" % areq)


        # Do the authorization
        try:
            permission = self.function["authorize"](user)
            self.sdb.update(scode, "permission", permission)
        except Exception:
            raise

        _log_debug("response type: %s" % areq["response_type"])

        # create the response
        aresp = AuthorizationResponse()
        try:
            aresp["state"] = areq["state"]
        except KeyError:
            pass

        if "response_type" in areq and \
                len(areq["response_type"]) == 1 and \
                "none" in areq["response_type"]:
            pass
        else:
            if self.sdb.is_revoked(scode):
                return self._error(environ, start_response,
                                   error="access_denied",
                                   descr="Token is revoked")