Пример #1
0
class TestClient(object):
    @pytest.fixture(autouse=True)
    def create_client(self):
        self.redirect_uri = "https://example.com/redirect"
        self.authorization_endpoint = "https://example.com/authz"
        self.token_endpoint = "https://example.com/token"

        self.client = Client("1", config={"issuer": "https://example.com/as"})
        self.client.redirect_uris = [self.redirect_uri]
        self.client.authorization_endpoint = self.authorization_endpoint
        self.client.token_endpoint = self.token_endpoint

    def test_construct_authz_req_no_optional_params(self):
        areq = self.client.construct_AuthorizationRequest(
            request_args={"response_type": ["code"]})

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert "state" not in areq
        assert "scope" not in areq

    def test_construct_authz_req_no_input(self):
        atr = self.client.construct_AuthorizationRequest()

        assert atr["redirect_uri"] == self.redirect_uri
        assert atr["response_type"] == ["code"]
        assert atr["client_id"] == "1"

    def test_construct_authz_req_optional_params(self):
        req_args = {
            "response_type": ["code"],
            "scope": ["foo", "bar"],
            "state": "abc"
        }
        areq = self.client.construct_AuthorizationRequest(
            request_args=req_args)

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert areq["state"] == "abc"
        assert areq["scope"] == ["foo", "bar"]

    def test_construct_authz_req_replace_default_state(self):
        req_args = {
            "response_type": ["code"],
            "scope": ["foo", "bar"],
            "state": "efg"
        }
        areq = self.client.construct_AuthorizationRequest(
            request_args=req_args)

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert areq["state"] == "efg"
        assert areq["scope"] == ["foo", "bar"]

    def test_parse_authz_resp_url(self):
        code = "SplxlOBeZQQYbYS6WxSbIA"
        state = "ghi"
        url = "{}?code={}&state={}".format(self.redirect_uri, code, state)
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=url,
                                           sformat="urlencoded")

        assert aresp["code"] == code
        assert aresp["state"] == state

        assert self.client.grant[state].code == aresp["code"]
        assert self.client.grant[state].grant_expiration_time

    def test_parse_authz_resp_query(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=hij"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "hij"

        assert self.client.grant["hij"]
        assert self.client.grant["hij"].code == aresp["code"]
        assert self.client.grant["hij"].grant_expiration_time

    def test_parse_authz_resp_query_multi_scope(self):
        code = "SplxlOBeZQQYbYS6WxSbIA"
        states = ["ghi", "hij", "klm"]

        for state in states:
            self.client.parse_response(
                AuthorizationResponse,
                info="code={}&state={}".format(code, state),
                sformat="urlencoded",
            )

        for state in states:
            assert self.client.grant[state].code == code

        assert _eq(self.client.grant.keys(), states)

    def test_parse_authz_resp_query_unknown_parameter(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=xyz&foo=bar"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "xyz"

        # assert "foo" not in aresp # TODO unknown parameter not discarded

        assert self.client.grant["xyz"]
        assert self.client.grant["xyz"].code == aresp["code"]
        assert self.client.grant["xyz"].grant_expiration_time

    def test_construct_access_token_req(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"stat": grant}

        # scope is default=""
        atr = self.client.construct_AccessTokenRequest(state="stat")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri

    def test_construct_access_token_req_client_credentials(self):
        # scope is default=""
        request_args = {"grant_type": "client_credentials"}
        atr = self.client.construct_AccessTokenRequest(
            state="stat",
            request=CCAccessTokenRequest,
            request_args=request_args)

        assert atr["grant_type"] == "client_credentials"
        assert atr["state"] == "stat"

    def test_construct_access_token_req_extension_grant(self):
        request_args = {
            "grant_type": "urn:ietf:params:oauth:grant-type:saml2-bearer",
            "assertion": "saml assertion",
        }
        atr = self.client.construct_AccessTokenRequest(
            request=ExtensionTokenRequest, request_args=request_args)
        assert atr[
            "grant_type"] == "urn:ietf:params:oauth:grant-type:saml2-bearer"
        assert atr["assertion"] == "saml assertion"

    def test_construct_access_token_request_fail(self):
        with pytest.raises(GrantError):
            self.client.construct_AccessTokenRequest(state="unknown")

    def test_construct_access_token_req_override(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri

    def test_parse_access_token_resp(self):
        atr = AccessTokenResponse(
            access_token="2YotnFZFEjr1zCsicMWpAA",
            token_type="example",
            expires_in=3600,
            refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
            example_parameter="example_value",
        )

        self.client.parse_response(AccessTokenResponse,
                                   info=json.dumps(atr.to_dict()))

        _grant = self.client.grant[""]
        assert len(_grant.tokens) == 1
        token = _grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
        assert token.token_type == "example"
        assert token.token_expiration_time > time_util.time_sans_frac()
        assert token.refresh_token == "tGzv3JOkF0XG5Qx2TlKWIA"

    def test_get_access_token_refresh_with_refresh_token(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"
        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")
        token = Token(resp)
        self.client.grant["foo"].tokens.append(token)

        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(token=token)

        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_get_access_token_refresh_from_state(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"

        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")

        self.client.grant["foo"].tokens.append(Token(resp))
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(state="foo")

        assert isinstance(atr, RefreshAccessTokenRequest)
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_parse_authz_err_resp(self):
        error = "access_denied"
        state = "xyz"
        ruri = "{}?error={}&state={}".format(self.redirect_uri, error, state)

        resp = self.client.parse_response(AuthorizationResponse,
                                          info=ruri,
                                          sformat="urlencoded")

        assert isinstance(resp, AuthorizationErrorResponse)
        assert resp["error"] == error
        assert resp["state"] == state

    def test_return_non_existant_grant(self):
        assert self.client.grant_from_state("123456abcdef") is None

    def test_get_grant(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant()
        grant.add_code(resp)

        self.client.grant["state"] = grant
        new_grant = self.client.grant_from_state("state")
        assert new_grant is not None
        assert new_grant.code == "code"

    def test_construct_access_token_req_with_extra_args(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=abc"
        self.client.parse_response(AuthorizationResponse,
                                   info=query,
                                   sformat="urlencoded")

        req = self.client.construct_AccessTokenRequest(
            state="abc", extra_args={"foo": "bar"})

        assert _eq(
            req.keys(),
            [
                "code", "grant_type", "client_id", "redirect_uri", "foo",
                "state"
            ],
        )
        assert req["foo"] == "bar"

    def test_request_info_simple(self):
        req_args = {"state": "hmm", "response_type": "code"}
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, request_args=req_args)

        assert uri == self.authorization_endpoint
        body_elts = body.split("&")
        expected_body = (
            "state=hmm&redirect_uri={}&response_type=code&client_id=1".format(
                quote(self.redirect_uri, safe="")))
        expected_body_elts = expected_body.split("&")
        assert set(body_elts) == set(expected_body_elts)
        assert h_args == {
            "headers": {
                "Content-Type": "application/x-www-form-urlencoded"
            }
        }
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_simple_get(self):
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest,
                                                          method="GET")
        assert url_compare(
            uri,
            "{}?redirect_uri={}&response_type=code&client_id=1".format(
                self.authorization_endpoint, quote(self.redirect_uri,
                                                   safe="")),
        )
        assert body is None
        assert h_args == {}

    def test_request_info_simple_get_with_req_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", request_args={"state": "init"})

        assert url_compare(
            uri,
            "{}?state=init&redirect_uri={}&response_type=code&client_id=1".
            format(self.authorization_endpoint,
                   quote(self.redirect_uri, safe="")),
        )
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_simple_get_with_extra_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", extra_args={"rock": "little"})

        assert url_compare(
            uri,
            "{}?redirect_uri={}&response_type=code&client_id=1&rock=little".
            format(self.authorization_endpoint,
                   quote(self.redirect_uri, safe="")),
        )
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_with_req_and_extra_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest,
            method="GET",
            request_args={"state": "init"},
            extra_args={"rock": "little"},
        )

        expected = (
            "{}?state=init&redirect_uri={}&response_type=code&client_id=1&rock=little"
        )
        assert url_compare(
            uri,
            expected.format(self.authorization_endpoint,
                            quote(self.redirect_uri, safe="")),
        )
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_construct_access_token_req_expired_grant(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant(-10)  # expired grant
        grant.add_code(resp)

        client = Client()
        client.grant["openid"] = grant
        with pytest.raises(GrantExpired):
            client.construct_AccessTokenRequest(state="openid")

    def test_parse_access_token_resp_json(self):
        atr = self.client.parse_response(AccessTokenResponse,
                                         info=ACC_TOK_RESP.to_json())
        assert _eq(atr.keys(),
                   ["token_type", "scope", "access_token", "refresh_token"])

    def test_parse_access_token_resp_urlencoded(self):
        uatr = self.client.parse_response(AccessTokenResponse,
                                          info=ACC_TOK_RESP.to_urlencoded(),
                                          sformat="urlencoded")
        assert _eq(uatr.keys(),
                   ["token_type", "scope", "access_token", "refresh_token"])

    def test_parse_access_token_resp_url(self):
        url = "{}?{}".format("https://example.com/token",
                             ACC_TOK_RESP.to_urlencoded())
        uatr = self.client.parse_response(AccessTokenResponse,
                                          info=url,
                                          sformat="urlencoded")
        assert _eq(uatr.keys(),
                   ["token_type", "scope", "access_token", "refresh_token"])

    def test_parse_error_resp(self):
        err = ErrorResponse(
            error="invalid_request",
            error_description="Something was missing",
            error_uri="http://example.com/error_message.html",
        )
        jerr = err.to_json()
        uerr = err.to_urlencoded()

        self.client.parse_response(AccessTokenResponse, info=jerr)
        self.client.parse_response(AccessTokenResponse,
                                   info=uerr,
                                   sformat="urlencoded")

        with pytest.raises(ResponseError):
            self.client.parse_response(AccessTokenResponse,
                                       info=jerr,
                                       sformat="urlencoded")

        with pytest.raises(DecodeError):
            self.client.parse_response(AccessTokenResponse, info=uerr)

        with pytest.raises(FormatError):
            self.client.parse_response(
                AccessTokenResponse,
                info=jerr,
                sformat="focus"  # type: ignore
            )

    def test_parse_access_token_resp_missing_attribute(self):
        atresp = AccessTokenResponse(
            access_token="SlAV32hkKG",
            token_type="Bearer",
            refresh_token="8xLOxBtZp8",
            expire_in=3600,
        )
        atdict = atresp.to_dict()
        del atdict["access_token"]  # remove required access_token
        atj = json.dumps(atdict)

        with pytest.raises(MissingRequiredAttribute):
            self.client.parse_response(AccessTokenResponse, info=atj)

        with pytest.raises(MissingRequiredAttribute):
            self.client.parse_response(AccessTokenResponse,
                                       info=urlencode(atdict),
                                       sformat="urlencoded")

    def test_client_parse_args(self):
        args = {
            "response_type": "",
            "client_id": "client_id",
            "redirect_uri": "http://example.com/authz",
            "scope": "scope",
            "state": "state",
        }

        ar_args = self.client._parse_args(AuthorizationRequest, **args)

        assert _eq(
            ar_args.keys(),
            ["scope", "state", "redirect_uri", "response_type", "client_id"],
        )

    def test_client_parse_extra_args(self):
        args = {
            "response_type": "",
            "client_id": "client_id",
            "redirect_uri": "http://example.com/authz",
            "scope": "scope",
            "state": "state",
            "extra_session": "home",
        }
        ar_args = self.client._parse_args(AuthorizationRequest, **args)

        assert _eq(
            ar_args.keys(),
            [
                "state",
                "redirect_uri",
                "response_type",
                "client_id",
                "scope",
                "extra_session",
            ],
        )

    def test_client_endpoint(self):
        self.client.authorization_endpoint = "https://example.org/oauth2/as"
        self.client.token_endpoint = "https://example.org/oauth2/token"
        self.client.token_revocation_endpoint = "https://example.org/oauth2/token_rev"

        assert (self.client._endpoint("authorization_endpoint") ==
                "https://example.org/oauth2/as")
        assert (self.client._endpoint("token_endpoint") ==
                "https://example.org/oauth2/token")
        assert (self.client._endpoint("token_revocation_endpoint") ==
                "https://example.org/oauth2/token_rev")

        auth_endpoint = self.client._endpoint(
            "authorization_endpoint",
            **{"authorization_endpoint": "https://example.com/as"})
        assert auth_endpoint == "https://example.com/as"

        self.client.token_endpoint = ""
        with pytest.raises(MissingEndpoint):
            self.client._endpoint("token_endpoint")
            self.client._endpoint("foo_endpoint")

    def test_do_access_token_request_client_credentials(self):
        class CCMessageFactory(OauthMessageFactory):
            """We are doing client credentials."""

            token_endpoint = MessageTuple(CCAccessTokenRequest,
                                          AccessTokenResponse)

        self.client.message_factory = CCMessageFactory
        with responses.RequestsMock() as rsps:
            rsps.add(
                rsps.POST,
                self.token_endpoint,
                json={
                    "access_token": "Token",
                    "token_type": "bearer"
                },
            )

            resp = self.client.do_access_token_request()
            assert rsps.calls[
                0].request.body == "grant_type=client_credentials"

        assert isinstance(resp, AccessTokenResponse)
        assert resp["access_token"] == "Token"

    def test_do_access_token_request_extension_grant(self):
        class ExtensionMessageFactory(OauthMessageFactory):
            """We are doing Extension grant."""

            token_endpoint = MessageTuple(ExtensionTokenRequest,
                                          AccessTokenResponse)

        self.client.message_factory = ExtensionMessageFactory
        request_args = {
            "assertion": "saml assertion",
            "grant_type": "urn:ietf:params:oauth:grant-type:saml2-bearer",
        }
        with responses.RequestsMock() as rsps:
            rsps.add(
                rsps.POST,
                self.token_endpoint,
                json={
                    "access_token": "Token",
                    "token_type": "bearer"
                },
            )

            resp = self.client.do_access_token_request(
                request_args=request_args)
            request = parse_qs(rsps.calls[0].request.body)
            assert request["assertion"][0] == "saml assertion"
            assert (request["grant_type"][0] ==
                    "urn:ietf:params:oauth:grant-type:saml2-bearer")

        assert isinstance(resp, AccessTokenResponse)
        assert resp["access_token"] == "Token"
Пример #2
0
class TestClient(object):
    @pytest.fixture(autouse=True)
    def create_client(self):
        self.redirect_uri = "https://example.com/redirect"
        self.authorization_endpoint = "https://example.com/authz"

        self.client = Client("1")  # pylint: disable=attribute-defined-outside-init
        self.client.redirect_uris = [self.redirect_uri]
        self.client.response_type = "code"
        self.client.authorization_endpoint = self.authorization_endpoint

    def test_construct_authz_req_no_optional_params(self):
        areq = self.client.construct_AuthorizationRequest(request_args={"response_type": ["code"]})

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert "state" not in areq
        assert "scope" not in areq

    def test_construct_authz_req_no_input(self):
        self.client.response_type = ["code"]
        atr = self.client.construct_AuthorizationRequest()

        assert atr["redirect_uri"] == self.redirect_uri
        assert atr["response_type"] == ["code"]
        assert atr["client_id"] == "1"

    def test_construct_authz_req_optional_params(self):
        req_args = {"response_type": ["code"], "scope": ["foo", "bar"], "state": "abc"}
        areq = self.client.construct_AuthorizationRequest(request_args=req_args)

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert areq["state"] == "abc"
        assert areq["scope"] == ["foo", "bar"]

    def test_construct_authz_req_replace_default_state(self):
        req_args = {"response_type": ["code"], "scope": ["foo", "bar"], "state": "efg"}
        areq = self.client.construct_AuthorizationRequest(request_args=req_args)

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert areq["state"] == "efg"
        assert areq["scope"] == ["foo", "bar"]

    def test_parse_authz_resp_url(self):
        code = "SplxlOBeZQQYbYS6WxSbIA"
        state = "ghi"
        url = "{}?code={}&state={}".format(self.redirect_uri, code, state)
        aresp = self.client.parse_response(AuthorizationResponse, info=url, sformat="urlencoded")

        assert aresp["code"] == code
        assert aresp["state"] == state

        assert self.client.grant[state].code == aresp["code"]
        assert self.client.grant[state].grant_expiration_time

    def test_parse_authz_resp_query(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=hij"
        aresp = self.client.parse_response(AuthorizationResponse, info=query, sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "hij"

        assert self.client.grant["hij"]
        assert self.client.grant["hij"].code == aresp["code"]
        assert self.client.grant["hij"].grant_expiration_time

    def test_parse_authz_resp_query_multi_scope(self):
        code = "SplxlOBeZQQYbYS6WxSbIA"
        states = ["ghi", "hij", "klm"]

        for state in states:
            self.client.parse_response(
                AuthorizationResponse, info="code={}&state={}".format(code, state), sformat="urlencoded"
            )

        for state in states:
            assert self.client.grant[state].code == code

        assert _eq(self.client.grant.keys(), states)

    def test_parse_authz_resp_query_unknown_parameter(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=xyz&foo=bar"
        aresp = self.client.parse_response(AuthorizationResponse, info=query, sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "xyz"

        # assert "foo" not in aresp # TODO unknown parameter not discarded

        assert self.client.grant["xyz"]
        assert self.client.grant["xyz"].code == aresp["code"]
        assert self.client.grant["xyz"].grant_expiration_time

    def test_construct_access_token_req(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"stat": grant}

        # scope is default=""
        atr = self.client.construct_AccessTokenRequest(state="stat")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri

    def test_construct_access_token_request_fail(self):
        with pytest.raises(GrantError):
            self.client.construct_AccessTokenRequest(state="unknown")

    def test_construct_access_token_req_override(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri

    def test_parse_access_token_resp(self):
        atr = AccessTokenResponse(
            access_token="2YotnFZFEjr1zCsicMWpAA",
            token_type="example",
            expires_in=3600,
            refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
            example_parameter="example_value",
        )

        self.client.parse_response(AccessTokenResponse, info=json.dumps(atr.to_dict()))

        _grant = self.client.grant[""]
        assert len(_grant.tokens) == 1
        token = _grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
        assert token.token_type == "example"
        assert token.expires_in == 3600
        assert token.refresh_token == "tGzv3JOkF0XG5Qx2TlKWIA"

        # I'm dropping parameters I don't recognize
        # with pytest.raises(AttributeError): # TODO not satisfied
        #     nothing = token.example_parameter

    def test_get_access_token_refresh_with_refresh_token(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"
        resp = AccessTokenResponse(refresh_token="refresh_with_me", access_token="access")
        token = Token(resp)
        self.client.grant["foo"].tokens.append(token)

        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(token=token)

        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_get_access_token_refresh_from_state(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"

        resp = AccessTokenResponse(refresh_token="refresh_with_me", access_token="access")

        self.client.grant["foo"].tokens.append(Token(resp))
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(state="foo")

        assert isinstance(atr, RefreshAccessTokenRequest)
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_parse_authz_err_resp(self):
        error = "access_denied"
        state = "xyz"
        ruri = "{}?error={}&state={}".format(self.redirect_uri, error, state)

        resp = self.client.parse_response(AuthorizationResponse, info=ruri, sformat="urlencoded")

        assert isinstance(resp, AuthorizationErrorResponse)
        assert resp["error"] == error
        assert resp["state"] == state

    def test_return_non_existant_grant(self):
        assert self.client.grant_from_state("123456abcdef") is None

    def test_get_grant(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant()
        grant.add_code(resp)

        self.client.grant["state"] = grant
        assert self.client.grant_from_state("state").code == "code"

    def test_construct_access_token_req_with_extra_args(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=abc"
        self.client.parse_response(AuthorizationResponse, info=query, sformat="urlencoded")

        req = self.client.construct_AccessTokenRequest(state="abc", extra_args={"foo": "bar"})

        assert _eq(req.keys(), ["code", "grant_type", "client_id", "redirect_uri", "foo"])
        assert req["foo"] == "bar"

    def test_construct_TokenRevocationRequest(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"
        resp = AccessTokenResponse(refresh_token="refresh_with_me", access_token="access")
        token = Token(resp)
        self.client.grant["foo"].tokens.append(token)

        state = "foo"
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state={}".format(state)
        self.client.parse_response(AuthorizationResponse, info=query, sformat="urlencoded")

        req = self.client.construct_TokenRevocationRequest(state=state)
        assert _eq(req.keys(), ["token"])
        assert req["token"] == "access"

    def test_request_info_simple(self):
        req_args = {"state": "hmm", "response_type": "code"}
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest, request_args=req_args)

        # default == "POST"
        assert uri == self.authorization_endpoint
        body_elts = body.split("&")
        expected_body = "state=hmm&redirect_uri={}&response_type=code&client_id=1".format(
            quote(self.redirect_uri, safe="")
        )
        expected_body_elts = expected_body.split("&")
        assert set(body_elts) == set(expected_body_elts)
        assert h_args == {"headers": {"Content-type": "application/x-www-form-urlencoded"}}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_simple_get(self):
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest, method="GET")
        assert url_compare(
            uri,
            "{}?redirect_uri={}&response_type=code&client_id=1".format(
                self.authorization_endpoint, quote(self.redirect_uri, safe="")
            ),
        )
        assert body is None
        assert h_args == {}

    def test_request_info_simple_get_with_req_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", request_args={"state": "init"}
        )

        assert url_compare(
            uri,
            "{}?state=init&redirect_uri={}&response_type=code&client_id=1".format(
                self.authorization_endpoint, quote(self.redirect_uri, safe="")
            ),
        )
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_simple_get_with_extra_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", extra_args={"rock": "little"}
        )

        assert url_compare(
            uri,
            "{}?redirect_uri={}&response_type=code&client_id=1&rock=little".format(
                self.authorization_endpoint, quote(self.redirect_uri, safe="")
            ),
        )
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_with_req_and_extra_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", request_args={"state": "init"}, extra_args={"rock": "little"}
        )

        expected = "{}?state=init&redirect_uri={}&response_type=code&client_id=1&rock=little"
        assert url_compare(uri, expected.format(self.authorization_endpoint, quote(self.redirect_uri, safe="")))
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_construct_access_token_req_expired_grant(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant(-10)  # expired grant
        grant.add_code(resp)

        client = Client()
        client.grant["openid"] = grant
        with pytest.raises(GrantExpired):
            client.construct_AccessTokenRequest(state="openid")

    def test_parse_access_token_resp_json(self):
        atr = self.client.parse_response(AccessTokenResponse, info=ACC_TOK_RESP.to_json())
        assert _eq(atr.keys(), ["token_type", "scope", "access_token", "refresh_token"])

    def test_parse_access_token_resp_urlencoded(self):
        uatr = self.client.parse_response(AccessTokenResponse, info=ACC_TOK_RESP.to_urlencoded(), sformat="urlencoded")
        assert _eq(uatr.keys(), ["token_type", "scope", "access_token", "refresh_token"])

    def test_parse_access_token_resp_url(self):
        url = "{}?{}".format("https://example.com/token", ACC_TOK_RESP.to_urlencoded())
        uatr = self.client.parse_response(AccessTokenResponse, info=url, sformat="urlencoded")
        assert _eq(uatr.keys(), ["token_type", "scope", "access_token", "refresh_token"])

    def test_parse_error_resp(self):
        err = ErrorResponse(
            error="invalid_request",
            error_description="Something was missing",
            error_uri="http://example.com/error_message.html",
        )
        jerr = err.to_json()
        uerr = err.to_urlencoded()

        _ = self.client.parse_response(AccessTokenResponse, info=jerr)
        _ = self.client.parse_response(AccessTokenResponse, info=uerr, sformat="urlencoded")

        with pytest.raises(ResponseError):
            self.client.parse_response(AccessTokenResponse, info=jerr, sformat="urlencoded")

        with pytest.raises(ValueError):
            self.client.parse_response(AccessTokenResponse, info=uerr)

        with pytest.raises(FormatError):
            self.client.parse_response(AccessTokenResponse, info=jerr, sformat="focus")

    def test_parse_access_token_resp_missing_attribute(self):
        atresp = AccessTokenResponse(
            access_token="SlAV32hkKG", token_type="Bearer", refresh_token="8xLOxBtZp8", expire_in=3600
        )
        atdict = atresp.to_dict()
        del atdict["access_token"]  # remove required access_token
        atj = json.dumps(atdict)

        with pytest.raises(MissingRequiredAttribute):
            self.client.parse_response(AccessTokenResponse, info=atj)

        with pytest.raises(MissingRequiredAttribute):
            self.client.parse_response(AccessTokenResponse, info=urlencode(atdict), sformat="urlencoded")

    def test_client_parse_args(self):
        args = {
            "response_type": "",
            "client_id": "client_id",
            "redirect_uri": "http://example.com/authz",
            "scope": "scope",
            "state": "state",
        }

        ar_args = self.client._parse_args(AuthorizationRequest, **args)

        assert _eq(ar_args.keys(), ["scope", "state", "redirect_uri", "response_type", "client_id"])

    def test_client_parse_extra_args(self):
        args = {
            "response_type": "",
            "client_id": "client_id",
            "redirect_uri": "http://example.com/authz",
            "scope": "scope",
            "state": "state",
            "extra_session": "home",
        }
        ar_args = self.client._parse_args(AuthorizationRequest, **args)

        assert _eq(ar_args.keys(), ["state", "redirect_uri", "response_type", "client_id", "scope", "extra_session"])

    def test_client_endpoint(self):
        self.client.authorization_endpoint = "https://example.org/oauth2/as"
        self.client.token_endpoint = "https://example.org/oauth2/token"
        self.client.token_revocation_endpoint = "https://example.org/oauth2/token_rev"

        assert self.client._endpoint("authorization_endpoint") == "https://example.org/oauth2/as"
        assert self.client._endpoint("token_endpoint") == "https://example.org/oauth2/token"
        assert self.client._endpoint("token_revocation_endpoint") == "https://example.org/oauth2/token_rev"

        auth_endpoint = self.client._endpoint(
            "authorization_endpoint", **{"authorization_endpoint": "https://example.com/as"}
        )
        assert auth_endpoint == "https://example.com/as"

        self.client.token_endpoint = ""
        with pytest.raises(MissingEndpoint):
            self.client._endpoint("token_endpoint")
            self.client._endpoint("foo_endpoint")
Пример #3
0
class TestClient(object):
    @pytest.fixture(autouse=True)
    def create_client(self):
        self.redirect_uri = "https://example.com/redirect"
        self.authorization_endpoint = "https://example.com/authz"

        self.client = Client("1", config={'issuer': 'https://example.com/as'})
        self.client.redirect_uris = [self.redirect_uri]
        self.client.response_type = "code"
        self.client.authorization_endpoint = self.authorization_endpoint

    def test_construct_authz_req_no_optional_params(self):
        areq = self.client.construct_AuthorizationRequest(
            request_args={"response_type": ["code"]})

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert "state" not in areq
        assert "scope" not in areq

    def test_construct_authz_req_no_input(self):
        self.client.response_type = ["code"]
        atr = self.client.construct_AuthorizationRequest()

        assert atr["redirect_uri"] == self.redirect_uri
        assert atr["response_type"] == ["code"]
        assert atr["client_id"] == "1"

    def test_construct_authz_req_optional_params(self):
        req_args = {
            "response_type": ["code"],
            "scope": ["foo", "bar"],
            "state": "abc"
        }
        areq = self.client.construct_AuthorizationRequest(
            request_args=req_args)

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert areq["state"] == "abc"
        assert areq["scope"] == ["foo", "bar"]

    def test_construct_authz_req_replace_default_state(self):
        req_args = {
            "response_type": ["code"],
            "scope": ["foo", "bar"],
            "state": "efg"
        }
        areq = self.client.construct_AuthorizationRequest(
            request_args=req_args)

        assert areq["redirect_uri"] == self.redirect_uri
        assert areq["response_type"] == ["code"]
        assert areq["client_id"] == "1"
        assert areq["state"] == "efg"
        assert areq["scope"] == ["foo", "bar"]

    def test_parse_authz_resp_url(self):
        code = "SplxlOBeZQQYbYS6WxSbIA"
        state = "ghi"
        url = "{}?code={}&state={}".format(self.redirect_uri, code, state)
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=url,
                                           sformat="urlencoded")

        assert aresp["code"] == code
        assert aresp["state"] == state

        assert self.client.grant[state].code == aresp["code"]
        assert self.client.grant[state].grant_expiration_time

    def test_parse_authz_resp_query(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=hij"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "hij"

        assert self.client.grant["hij"]
        assert self.client.grant["hij"].code == aresp["code"]
        assert self.client.grant["hij"].grant_expiration_time

    def test_parse_authz_resp_query_multi_scope(self):
        code = "SplxlOBeZQQYbYS6WxSbIA"
        states = ["ghi", "hij", "klm"]

        for state in states:
            self.client.parse_response(AuthorizationResponse,
                                       info="code={}&state={}".format(
                                           code, state),
                                       sformat="urlencoded")

        for state in states:
            assert self.client.grant[state].code == code

        assert _eq(self.client.grant.keys(), states)

    def test_parse_authz_resp_query_unknown_parameter(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=xyz&foo=bar"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "xyz"

        # assert "foo" not in aresp # TODO unknown parameter not discarded

        assert self.client.grant["xyz"]
        assert self.client.grant["xyz"].code == aresp["code"]
        assert self.client.grant["xyz"].grant_expiration_time

    def test_construct_access_token_req(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"stat": grant}

        # scope is default=""
        atr = self.client.construct_AccessTokenRequest(state="stat")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri

    def test_construct_access_token_request_fail(self):
        with pytest.raises(GrantError):
            self.client.construct_AccessTokenRequest(state="unknown")

    def test_construct_access_token_req_override(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri

    def test_parse_access_token_resp(self):
        atr = AccessTokenResponse(access_token="2YotnFZFEjr1zCsicMWpAA",
                                  token_type="example",
                                  expires_in=3600,
                                  refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
                                  example_parameter="example_value")

        self.client.parse_response(AccessTokenResponse,
                                   info=json.dumps(atr.to_dict()))

        _grant = self.client.grant[""]
        assert len(_grant.tokens) == 1
        token = _grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
        assert token.token_type == "example"
        assert token.expires_in == 3600
        assert token.refresh_token == "tGzv3JOkF0XG5Qx2TlKWIA"

        # I'm dropping parameters I don't recognize
        # with pytest.raises(AttributeError): # TODO not satisfied
        #     nothing = token.example_parameter

    def test_get_access_token_refresh_with_refresh_token(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"
        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")
        token = Token(resp)
        self.client.grant["foo"].tokens.append(token)

        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(token=token)

        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_get_access_token_refresh_from_state(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"

        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")

        self.client.grant["foo"].tokens.append(Token(resp))
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(state="foo")

        assert isinstance(atr, RefreshAccessTokenRequest)
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_parse_authz_err_resp(self):
        error = "access_denied"
        state = "xyz"
        ruri = "{}?error={}&state={}".format(self.redirect_uri, error, state)

        resp = self.client.parse_response(AuthorizationResponse,
                                          info=ruri,
                                          sformat="urlencoded")

        assert isinstance(resp, AuthorizationErrorResponse)
        assert resp["error"] == error
        assert resp["state"] == state

    def test_return_non_existant_grant(self):
        assert self.client.grant_from_state("123456abcdef") is None

    def test_get_grant(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant()
        grant.add_code(resp)

        self.client.grant["state"] = grant
        assert self.client.grant_from_state("state").code == "code"

    def test_construct_access_token_req_with_extra_args(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=abc"
        self.client.parse_response(AuthorizationResponse,
                                   info=query,
                                   sformat="urlencoded")

        req = self.client.construct_AccessTokenRequest(
            state="abc", extra_args={"foo": "bar"})

        assert _eq(req.keys(), [
            "code", "grant_type", "client_id", "redirect_uri", "foo", 'state'
        ])
        assert req["foo"] == "bar"

    # def test_construct_TokenRevocationRequest(self):
    #     self.client.grant["foo"] = Grant()
    #     _get = time_util.utc_time_sans_frac() + 60
    #     self.client.grant["foo"].grant_expiration_time = _get
    #     self.client.grant["foo"].code = "access_code"
    #     resp = AccessTokenResponse(refresh_token="refresh_with_me",
    #                                access_token="access")
    #     token = Token(resp)
    #     self.client.grant["foo"].tokens.append(token)
    #
    #     state = "foo"
    #     query = "code=SplxlOBeZQQYbYS6WxSbIA&state={}".format(state)
    #     self.client.parse_response(AuthorizationResponse,
    #                                info=query, sformat="urlencoded")
    #
    #     req = self.client.construct_TokenRevocationRequest(state=state)
    #     assert _eq(req.keys(), ['token'])
    #     assert req["token"] == "access"

    def test_request_info_simple(self):
        req_args = {"state": "hmm", "response_type": "code"}
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, request_args=req_args)

        # default == "POST"
        assert uri == self.authorization_endpoint
        body_elts = body.split('&')
        expected_body = "state=hmm&redirect_uri={}&response_type=code&client_id=1".format(
            quote(self.redirect_uri, safe=""))
        expected_body_elts = expected_body.split('&')
        assert set(body_elts) == set(expected_body_elts)
        assert h_args == {
            'headers': {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_simple_get(self):
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest,
                                                          method="GET")
        assert url_compare(
            uri, '{}?redirect_uri={}&response_type=code&client_id=1'.format(
                self.authorization_endpoint, quote(self.redirect_uri,
                                                   safe="")))
        assert body is None
        assert h_args == {}

    def test_request_info_simple_get_with_req_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", request_args={"state": "init"})

        assert url_compare(
            uri,
            '{}?state=init&redirect_uri={}&response_type=code&client_id=1'.
            format(self.authorization_endpoint,
                   quote(self.redirect_uri, safe="")))
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_simple_get_with_extra_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", extra_args={"rock": "little"})

        assert url_compare(
            uri,
            '{}?redirect_uri={}&response_type=code&client_id=1&rock=little'.
            format(self.authorization_endpoint,
                   quote(self.redirect_uri, safe="")))
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_request_info_with_req_and_extra_args(self):
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest,
            method="GET",
            request_args={"state": "init"},
            extra_args={"rock": "little"})

        expected = '{}?state=init&redirect_uri={}&response_type=code&client_id=1&rock=little'
        assert url_compare(
            uri,
            expected.format(self.authorization_endpoint,
                            quote(self.redirect_uri, safe="")))
        assert body is None
        assert h_args == {}
        assert isinstance(cis, AuthorizationRequest)

    def test_construct_access_token_req_expired_grant(self):
        resp = AuthorizationResponse(code="code", state="state")
        grant = Grant(-10)  # expired grant
        grant.add_code(resp)

        client = Client()
        client.grant["openid"] = grant
        with pytest.raises(GrantExpired):
            client.construct_AccessTokenRequest(state="openid")

    def test_parse_access_token_resp_json(self):
        atr = self.client.parse_response(AccessTokenResponse,
                                         info=ACC_TOK_RESP.to_json())
        assert _eq(atr.keys(),
                   ['token_type', 'scope', 'access_token', 'refresh_token'])

    def test_parse_access_token_resp_urlencoded(self):
        uatr = self.client.parse_response(AccessTokenResponse,
                                          info=ACC_TOK_RESP.to_urlencoded(),
                                          sformat="urlencoded")
        assert _eq(uatr.keys(),
                   ['token_type', 'scope', 'access_token', 'refresh_token'])

    def test_parse_access_token_resp_url(self):
        url = "{}?{}".format("https://example.com/token",
                             ACC_TOK_RESP.to_urlencoded())
        uatr = self.client.parse_response(AccessTokenResponse,
                                          info=url,
                                          sformat="urlencoded")
        assert _eq(uatr.keys(),
                   ['token_type', 'scope', 'access_token', 'refresh_token'])

    def test_parse_error_resp(self):
        err = ErrorResponse(error="invalid_request",
                            error_description="Something was missing",
                            error_uri="http://example.com/error_message.html")
        jerr = err.to_json()
        uerr = err.to_urlencoded()

        self.client.parse_response(AccessTokenResponse, info=jerr)
        self.client.parse_response(AccessTokenResponse,
                                   info=uerr,
                                   sformat="urlencoded")

        with pytest.raises(ResponseError):
            self.client.parse_response(AccessTokenResponse,
                                       info=jerr,
                                       sformat="urlencoded")

        with pytest.raises(ValueError):
            self.client.parse_response(AccessTokenResponse, info=uerr)

        with pytest.raises(FormatError):
            self.client.parse_response(AccessTokenResponse,
                                       info=jerr,
                                       sformat="focus")

    def test_parse_access_token_resp_missing_attribute(self):
        atresp = AccessTokenResponse(access_token="SlAV32hkKG",
                                     token_type="Bearer",
                                     refresh_token="8xLOxBtZp8",
                                     expire_in=3600)
        atdict = atresp.to_dict()
        del atdict["access_token"]  # remove required access_token
        atj = json.dumps(atdict)

        with pytest.raises(MissingRequiredAttribute):
            self.client.parse_response(AccessTokenResponse, info=atj)

        with pytest.raises(MissingRequiredAttribute):
            self.client.parse_response(AccessTokenResponse,
                                       info=urlencode(atdict),
                                       sformat='urlencoded')

    def test_client_parse_args(self):
        args = {
            "response_type": "",
            "client_id": "client_id",
            "redirect_uri": "http://example.com/authz",
            "scope": "scope",
            "state": "state",
        }

        ar_args = self.client._parse_args(AuthorizationRequest, **args)

        assert _eq(
            ar_args.keys(),
            ['scope', 'state', 'redirect_uri', 'response_type', 'client_id'])

    def test_client_parse_extra_args(self):
        args = {
            "response_type": "",
            "client_id": "client_id",
            "redirect_uri": "http://example.com/authz",
            "scope": "scope",
            "state": "state",
            "extra_session": "home"
        }
        ar_args = self.client._parse_args(AuthorizationRequest, **args)

        assert _eq(ar_args.keys(), [
            'state', 'redirect_uri', 'response_type', 'client_id', 'scope',
            'extra_session'
        ])

    def test_client_endpoint(self):
        self.client.authorization_endpoint = "https://example.org/oauth2/as"
        self.client.token_endpoint = "https://example.org/oauth2/token"
        self.client.token_revocation_endpoint = "https://example.org/oauth2/token_rev"

        assert self.client._endpoint(
            "authorization_endpoint") == "https://example.org/oauth2/as"
        assert self.client._endpoint(
            "token_endpoint") == "https://example.org/oauth2/token"
        assert self.client._endpoint(
            "token_revocation_endpoint"
        ) == "https://example.org/oauth2/token_rev"

        auth_endpoint = self.client._endpoint(
            "authorization_endpoint",
            **{"authorization_endpoint": "https://example.com/as"})
        assert auth_endpoint == "https://example.com/as"

        self.client.token_endpoint = ""
        with pytest.raises(MissingEndpoint):
            self.client._endpoint("token_endpoint")
            self.client._endpoint("foo_endpoint")
Пример #4
0
class TestOAuthClient():
    def setup_class(self):
        self.client = Client("1")
        self.client.redirect_uris = ["http://example.com/redirect"]

    def test_areq_1(self):
        ar = self.client.construct_AuthorizationRequest(
            request_args={"response_type": ["code"]})

        assert ar["redirect_uri"] == "http://example.com/redirect"
        assert ar["response_type"] == ["code"]
        assert ar["client_id"] == "1"
        assert "state" not in ar
        assert "scope" not in ar

    def test_areq_2(self):
        self.client.state = "abc"
        req_args = {"response_type": ["code"], "scope": ["foo", "bar"]}
        ar = self.client.construct_AuthorizationRequest(request_args=req_args)

        assert ar["redirect_uri"] == "http://example.com/redirect"
        assert ar["response_type"] == ["code"]
        assert ar["client_id"] == "1"
        assert ar["state"] == "abc"
        assert ar["scope"] == ["foo", "bar"]

    def test_areq_replace_default_state(self):
        self.client.state = "efg"
        req_args = {"response_type": ["code"], "scope": ["foo", "bar"]}
        ar = self.client.construct_AuthorizationRequest(request_args=req_args)

        assert ar["redirect_uri"] == "http://example.com/redirect"
        assert ar["response_type"] == ["code"]
        assert ar["client_id"] == "1"
        assert ar["state"] == "efg"
        assert ar["scope"] == ["foo", "bar"]

    def test_parse_authz_resp_url(self):
        url = "https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=ghi"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=url, sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "ghi"

        assert self.client.grant["ghi"]
        assert self.client.grant["ghi"].code == aresp["code"]
        assert self.client.grant["ghi"].grant_expiration_time

    def test_parse_authz_resp_query(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=hij"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query, sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "hij"

        print self.client.grant.keys()
        assert self.client.grant["hij"]
        assert self.client.grant["hij"].code == aresp["code"]
        assert self.client.grant["hij"].grant_expiration_time

    def test_parse_authz_resp_query_multi_scope(self):
        query = "code=SplxlOBeZQQYbYS6WxAAAA&state=klm"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query, sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxAAAA"
        assert aresp["state"] == "klm"

        assert self.client.grant["klm"]
        assert self.client.grant["klm"].code == aresp["code"]
        assert self.client.grant["klm"].grant_expiration_time

        assert _eq(self.client.grant.keys(), ['ghi', 'hij', 'klm'])

    def test_parse_authz_resp_query_unknown_parameter(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=xyz&foo=bar"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query, sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "xyz"

        print aresp.__dict__.keys()
        assert "foo" not in aresp.__dict__

        assert self.client.grant["xyz"]
        assert self.client.grant["xyz"].code == aresp["code"]
        assert self.client.grant["xyz"].grant_expiration_time

    def test_get_access_token_request_1(self):
        self.client.reset()
        self.client.redirect_uris = ["http://client.example.com/authz"]
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"stat": grant}

        # scope is default=""
        atr = self.client.construct_AccessTokenRequest(state="stat")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == "http://client.example.com/authz"

    def test_construct_access_token_request_fail(self):
        raises(Exception,
               'self.client.construct_AccessTokenRequest(state="unknown")')

    def test_get_access_token_request_override(self):
        self.client.reset()
        self.client.redirect_uris = ["http://client.example.com/authz"]
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == "http://client.example.com/authz"

    def test_construct_request_no_input(self):
        self.client.response_type = ["code"]
        atr = self.client.construct_AuthorizationRequest()

        print atr
        assert atr["redirect_uri"] == "http://client.example.com/authz"
        assert atr["response_type"] == ["code"]
        assert atr["client_id"] == "1"

    def test_parse_access_token_response(self):
        jso = """{
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }"""

        self.client.parse_response(AccessTokenResponse,
                                   info="".join([
                                       x.strip() for x in jso.split("\n")]))

        assert self.client.grant
        _grant = self.client.grant[""]
        assert len(_grant.tokens) == 1
        token = _grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
        assert token.token_type == "example"
        assert token.expires_in == 3600
        assert token.refresh_token == "tGzv3JOkF0XG5Qx2TlKWIA"

        # I'm dropping parameters I don't recognize
        assert "example_parameter" not in self.client.__dict__

        #assert self.client.access_token_is_valid()

    def test_get_access_token_refresh_1(self):
        print self.client.grant

        self.client.grant[""].grant_expiration_time = time.time() + 60
        self.client.grant[""].code = "access_code"
        token = self.client.grant[""].tokens[0]
        print token
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(token=token)

        print atr.to_dict()
        assert atr.type() == "RefreshAccessTokenRequest"
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "tGzv3JOkF0XG5Qx2TlKWIA"

    def test_get_access_token_refresh_2(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"

        print self.client.grant["foo"]
        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")

        self.client.grant["foo"].tokens.append(Token(resp))
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(state="foo")

        assert atr.type() == "RefreshAccessTokenRequest"
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_parse_authz_err_response(self):
        ruri = "https://client.example.com/cb?error=access_denied&state=xyz"

        resp = self.client.parse_response(AuthorizationResponse,
                                          info=ruri, sformat="urlencoded")

        print type(resp), resp
        assert resp.type() == "AuthorizationErrorResponse"

        assert resp["error"] == "access_denied"
        assert resp["state"] == "xyz"

    def test_return_non_existant_grant(self):
        assert self.client.grant_from_state("123456abcdef") is None

    def test_construct_request_with_extra_args(self):
        print self.client.__dict__.items()
        req = self.client.construct_AccessTokenRequest(
            state="foo", extra_args={"foo": "bar"})

        assert req
        print req.keys()
        assert _eq(req.keys(), ['code', 'grant_type', 'client_id',
                                'redirect_uri', 'foo'])
        assert req["foo"] == "bar"

    def test_construct_TokenRevocationRequest(self):
        req = self.client.construct_TokenRevocationRequest(state="foo")

        assert req
        print req.keys()
        assert _eq(req.keys(), ['token'])
        assert req["token"] == "access"

    def test_request_info_simple(self):
        self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest)

        # default == "POST"
        assert uri == 'https://example.com/authz'
        assert body == "redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1"
        assert h_args == {'headers': {'content-type':
                                          'application/x-www-form-urlencoded'}}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_simple_get(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest,
                                                          method="GET")

        assert uri == 'https://example.com/authz?redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_simple_get_with_req_args(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", request_args={"state": "init"})

        print uri
        assert uri == 'https://example.com/authz?state=init&redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_simple_get_with_extra_args(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", extra_args={"rock": "little"})

        print uri
        assert uri == 'https://example.com/authz?redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1&rock=little'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_with_req_and_extra_args(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest,
            method="GET",
            request_args={"state": "init"},
            extra_args={"rock": "little"})

        print uri
        assert uri == 'https://example.com/authz?state=init&redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1&rock=little'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"
Пример #5
0
class TestOAuthClient():
    def setup_class(self):
        self.client = Client("1")
        self.client.redirect_uris = ["http://example.com/redirect"]

    def test_areq_1(self):
        ar = self.client.construct_AuthorizationRequest(
            request_args={"response_type": ["code"]})

        assert ar["redirect_uri"] == "http://example.com/redirect"
        assert ar["response_type"] == ["code"]
        assert ar["client_id"] == "1"
        assert "state" not in ar
        assert "scope" not in ar

    def test_areq_2(self):
        self.client.state = "abc"
        req_args = {"response_type": ["code"], "scope": ["foo", "bar"]}
        ar = self.client.construct_AuthorizationRequest(request_args=req_args)

        assert ar["redirect_uri"] == "http://example.com/redirect"
        assert ar["response_type"] == ["code"]
        assert ar["client_id"] == "1"
        assert ar["state"] == "abc"
        assert ar["scope"] == ["foo", "bar"]

    def test_areq_replace_default_state(self):
        self.client.state = "efg"
        req_args = {"response_type": ["code"], "scope": ["foo", "bar"]}
        ar = self.client.construct_AuthorizationRequest(request_args=req_args)

        assert ar["redirect_uri"] == "http://example.com/redirect"
        assert ar["response_type"] == ["code"]
        assert ar["client_id"] == "1"
        assert ar["state"] == "efg"
        assert ar["scope"] == ["foo", "bar"]

    def test_parse_authz_resp_url(self):
        url = "https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=ghi"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=url,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "ghi"

        assert self.client.grant["ghi"]
        assert self.client.grant["ghi"].code == aresp["code"]
        assert self.client.grant["ghi"].grant_expiration_time

    def test_parse_authz_resp_query(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=hij"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "hij"

        print self.client.grant.keys()
        assert self.client.grant["hij"]
        assert self.client.grant["hij"].code == aresp["code"]
        assert self.client.grant["hij"].grant_expiration_time

    def test_parse_authz_resp_query_multi_scope(self):
        query = "code=SplxlOBeZQQYbYS6WxAAAA&state=klm"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxAAAA"
        assert aresp["state"] == "klm"

        assert self.client.grant["klm"]
        assert self.client.grant["klm"].code == aresp["code"]
        assert self.client.grant["klm"].grant_expiration_time

        assert _eq(self.client.grant.keys(), ['ghi', 'hij', 'klm'])

    def test_parse_authz_resp_query_unknown_parameter(self):
        query = "code=SplxlOBeZQQYbYS6WxSbIA&state=xyz&foo=bar"
        aresp = self.client.parse_response(AuthorizationResponse,
                                           info=query,
                                           sformat="urlencoded")

        assert aresp["code"] == "SplxlOBeZQQYbYS6WxSbIA"
        assert aresp["state"] == "xyz"

        print aresp.__dict__.keys()
        assert "foo" not in aresp.__dict__

        assert self.client.grant["xyz"]
        assert self.client.grant["xyz"].code == aresp["code"]
        assert self.client.grant["xyz"].grant_expiration_time

    def test_get_access_token_request_1(self):
        self.client.reset()
        self.client.redirect_uris = ["http://client.example.com/authz"]
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"stat": grant}

        # scope is default=""
        atr = self.client.construct_AccessTokenRequest(state="stat")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == "http://client.example.com/authz"

    def test_construct_access_token_request_fail(self):
        raises(Exception,
               'self.client.construct_AccessTokenRequest(state="unknown")')

    def test_get_access_token_request_override(self):
        self.client.reset()
        self.client.redirect_uris = ["http://client.example.com/authz"]
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == "http://client.example.com/authz"

    def test_construct_request_no_input(self):
        self.client.response_type = ["code"]
        atr = self.client.construct_AuthorizationRequest()

        print atr
        assert atr["redirect_uri"] == "http://client.example.com/authz"
        assert atr["response_type"] == ["code"]
        assert atr["client_id"] == "1"

    def test_parse_access_token_response(self):
        jso = """{
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }"""

        self.client.parse_response(AccessTokenResponse,
                                   info="".join(
                                       [x.strip() for x in jso.split("\n")]))

        assert self.client.grant
        _grant = self.client.grant[""]
        assert len(_grant.tokens) == 1
        token = _grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
        assert token.token_type == "example"
        assert token.expires_in == 3600
        assert token.refresh_token == "tGzv3JOkF0XG5Qx2TlKWIA"

        # I'm dropping parameters I don't recognize
        assert "example_parameter" not in self.client.__dict__

        #assert self.client.access_token_is_valid()

    def test_get_access_token_refresh_1(self):
        print self.client.grant

        self.client.grant[""].grant_expiration_time = time.time() + 60
        self.client.grant[""].code = "access_code"
        token = self.client.grant[""].tokens[0]
        print token
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(token=token)

        print atr.to_dict()
        assert atr.type() == "RefreshAccessTokenRequest"
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "tGzv3JOkF0XG5Qx2TlKWIA"

    def test_get_access_token_refresh_2(self):
        self.client.grant["foo"] = Grant()
        _get = time_util.utc_time_sans_frac() + 60
        self.client.grant["foo"].grant_expiration_time = _get
        self.client.grant["foo"].code = "access_code"

        print self.client.grant["foo"]
        resp = AccessTokenResponse(refresh_token="refresh_with_me",
                                   access_token="access")

        self.client.grant["foo"].tokens.append(Token(resp))
        # Uses refresh_token from previous response
        atr = self.client.construct_RefreshAccessTokenRequest(state="foo")

        assert atr.type() == "RefreshAccessTokenRequest"
        assert atr["grant_type"] == "refresh_token"
        assert atr["refresh_token"] == "refresh_with_me"

    def test_parse_authz_err_response(self):
        ruri = "https://client.example.com/cb?error=access_denied&state=xyz"

        resp = self.client.parse_response(AuthorizationResponse,
                                          info=ruri,
                                          sformat="urlencoded")

        print type(resp), resp
        assert resp.type() == "AuthorizationErrorResponse"

        assert resp["error"] == "access_denied"
        assert resp["state"] == "xyz"

    def test_return_non_existant_grant(self):
        assert self.client.grant_from_state("123456abcdef") is None

    def test_construct_request_with_extra_args(self):
        print self.client.__dict__.items()
        req = self.client.construct_AccessTokenRequest(
            state="foo", extra_args={"foo": "bar"})

        assert req
        print req.keys()
        assert _eq(req.keys(),
                   ['code', 'grant_type', 'client_id', 'redirect_uri', 'foo'])
        assert req["foo"] == "bar"

    def test_construct_TokenRevocationRequest(self):
        req = self.client.construct_TokenRevocationRequest(state="foo")

        assert req
        print req.keys()
        assert _eq(req.keys(), ['token'])
        assert req["token"] == "access"

    def test_request_info_simple(self):
        self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest)

        # default == "POST"
        assert uri == 'https://example.com/authz'
        assert body == "redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1"
        assert h_args == {
            'headers': {
                'Content-type': 'application/x-www-form-urlencoded'
            }
        }
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_simple_get(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(AuthorizationRequest,
                                                          method="GET")

        assert uri == 'https://example.com/authz?redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_simple_get_with_req_args(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", request_args={"state": "init"})

        print uri
        assert uri == 'https://example.com/authz?state=init&redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_simple_get_with_extra_args(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest, method="GET", extra_args={"rock": "little"})

        print uri
        assert uri == 'https://example.com/authz?redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1&rock=little'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"

    def test_request_info_with_req_and_extra_args(self):
        #self.client.authorization_endpoint = "https://example.com/authz"
        uri, body, h_args, cis = self.client.request_info(
            AuthorizationRequest,
            method="GET",
            request_args={"state": "init"},
            extra_args={"rock": "little"})

        print uri
        assert uri == 'https://example.com/authz?state=init&redirect_uri=http%3A%2F%2Fclient.example.com%2Fauthz&response_type=code&client_id=1&rock=little'
        assert body is None
        assert h_args == {}
        assert cis.type() == "AuthorizationRequest"