예제 #1
0
    def test_pure_code_flow(self):
        self.prepare_data()
        rv = self.client.post('/oauth/authorize',
                              data={
                                  'response_type': 'code',
                                  'client_id': 'code-client',
                                  'state': 'bar',
                                  'scope': 'profile',
                                  'redirect_uri': 'https://a.b',
                                  'user_id': '1'
                              })
        self.assertIn('code=', rv.headers['location'])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers['location']).query))
        self.assertEqual(params['state'], 'bar')

        code = params['code']
        headers = self.create_basic_header('code-client', 'code-secret')
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'redirect_uri': 'https://a.b',
                                  'code': code,
                              },
                              headers=headers)
        resp = rv.json()
        self.assertIn('access_token', resp)
        self.assertNotIn('id_token', resp)
예제 #2
0
    def __init__(self, method, uri, body=None, headers=None):
        InsecureTransportError.check(uri)
        self.method = method
        self.uri = uri
        self.body = body
        self.headers = headers or {}

        # states namespaces
        self.client = None
        self.credential = None
        self.user = None

        self.query = urlparse.urlparse(uri).query
        self.query_params = url_decode(self.query)
        self.body_params = extract_params(body) or []

        self.auth_params, self.realm = _parse_authorization_header(headers)
        self.signature_type, self.oauth_params = _parse_oauth_params(
            self.query_params, self.body_params, self.auth_params)

        params = []
        params.extend(self.query_params)
        params.extend(self.body_params)
        params.extend(self.auth_params)
        self.params = params
예제 #3
0
    def __init__(self, method, uri, body=None, headers=None):
        InsecureTransportError.check(uri)
        #: HTTP method
        self.method = method
        self.uri = uri
        self.body = body
        #: HTTP headers
        self.headers = headers or {}

        self.query = urlparse.urlparse(uri).query
        self.query_params = url_decode(self.query)
        self.body_params = extract_params(body) or []

        params = {}
        if self.query_params:
            params.update(dict(self.query_params))
        if self.body_params:
            params.update(dict(self.body_params))

        #: dict of query and body params
        self.data = params

        #: authenticated user on this request
        self.user = None
        #: authorization_code or token model instance
        self.credential = None
        #: client which sending this request
        self.client = None
    def test_invalid_redirect_uri(self):
        self.prepare_data()
        uri = self.authorize_url + "&redirect_uri=https%3A%2F%2Fa.c"
        rv = self.client.post(uri, data={"user_id": "1"})
        resp = rv.json()
        self.assertEqual(resp["error"], "invalid_request")

        uri = self.authorize_url + "&redirect_uri=https%3A%2F%2Fa.b"
        rv = self.client.post(uri, data={"user_id": "1"})
        self.assertIn("code=", rv.headers["location"])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers["location"]).query))
        code = params["code"]
        headers = self.create_basic_header("code-client", "code-secret")
        rv = self.client.post(
            "/oauth/token",
            data={
                "grant_type": "authorization_code",
                "code": code,
            },
            headers=headers,
        )
        resp = rv.json()
        self.assertEqual(resp["error"], "invalid_request")
예제 #5
0
    def __init__(self, method, uri, body=None, headers=None):
        InsecureTransportError.check(uri)
        #: HTTP method
        self.method = method
        self.uri = uri
        self.body = body
        #: HTTP headers
        self.headers = headers or {}

        self.query = urlparse.urlparse(uri).query

        self.args = dict(url_decode(self.query))
        self.form = self.body or {}

        #: dict of query and body params
        data = {}
        data.update(self.args)
        data.update(self.form)
        self.data = data

        #: authenticate method
        self.auth_method = None
        #: authenticated user on this request
        self.user = None
        #: authorization_code or token model instance
        self.credential = None
        #: client which sending this request
        self.client = None
예제 #6
0
    def __init__(self, method, uri, body=None, headers=None):
        InsecureTransportError.check(uri)
        self.method = method
        self.uri = uri
        self.body = body
        self.headers = headers or {}

        self.query = urlparse.urlparse(uri).query
        self.query_params = url_decode(self.query)
        self.body_params = extract_params(body) or []

        params = {}
        if self.query_params:
            params.update(dict(self.query_params))
        if self.body_params:
            params.update(dict(self.body_params))
        self.data = params

        self.user = None
        self.credential = None
        self.client = None
        self._data_keys = {
            'client_id', 'code', 'redirect_uri', 'scope', 'state',
            'response_type', 'grant_type'
        }
예제 #7
0
    def test_oauth2_authorize_code_challenge(self):
        request = self.factory.get('/login')
        request.session = self.factory.session

        oauth = OAuth()
        client = oauth.register(
            'dev',
            client_id='dev',
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize',
            client_kwargs={'code_challenge_method': 'S256'},
        )
        rv = client.authorize_redirect(request, 'https://a.b/c')
        self.assertEqual(rv.status_code, 302)
        url = rv.get('Location')
        self.assertIn('state=', url)
        self.assertIn('code_challenge=', url)

        state = dict(url_decode(urlparse.urlparse(url).query))['state']
        state_data = request.session[f'_state_dev_{state}']['data']
        verifier = state_data['code_verifier']

        def fake_send(sess, req, **kwargs):
            self.assertIn('code_verifier={}'.format(verifier), req.body)
            return mock_send_value(get_bearer_token())

        with mock.patch('requests.sessions.Session.send', fake_send):
            request2 = self.factory.get('/authorize?state={}'.format(state))
            request2.session = request.session
            token = client.authorize_access_token(request2)
            self.assertEqual(token['access_token'], 'a')
예제 #8
0
    def test_oauth1_authorize(self):
        request = testing.DummyRequest(path="/login")

        oauth = OAuth()
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            request_token_url='https://i.b/request-token',
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize',
        )

        with mock.patch('requests.sessions.Session.send') as send:
            send.return_value = mock_send_value('oauth_token=foo&oauth_verifier=baz')

            resp = client.authorize_redirect(request)
            assert resp.status_code == 302
            url = resp.headers.get('location')
            assert 'oauth_token=foo' in url

        parsed_url = urlparse.urlparse(url)
        request2 = testing.DummyRequest(
            path=parsed_url.path,
            params=dict(urlparse.parse_qsl(parsed_url.query))
        )
        request2.session = request.session
        with mock.patch('requests.sessions.Session.send') as send:
            send.return_value = mock_send_value('oauth_token=a&oauth_token_secret=b')
            token = client.authorize_access_token(request2)
            assert token['oauth_token'] == 'a'
예제 #9
0
    def test_oauth2_authorize(self):
        request = self.factory.get('/login')
        request.session = self.factory.session

        oauth = OAuth()
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize',
        )
        rv = client.authorize_redirect(request, 'https://a.b/c')
        self.assertEqual(rv.status_code, 302)
        url = rv.get('Location')
        self.assertIn('state=', url)
        state = dict(url_decode(urlparse.urlparse(url).query))['state']

        with mock.patch('requests.sessions.Session.send') as send:
            send.return_value = mock_send_value(get_bearer_token())
            request2 = self.factory.get('/authorize?state={}'.format(state))
            request2.session = request.session

            token = client.authorize_access_token(request2)
            self.assertEqual(token['access_token'], 'a')
예제 #10
0
    def test_oauth2_authorize_code_challenge(self):
        request = testing.DummyRequest(path="/login")

        oauth = OAuth()
        client = oauth.register(
            'dev',
            client_id='dev',
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize',
            client_kwargs={'code_challenge_method': 'S256'},
        )
        rv = client.authorize_redirect(request, 'https://a.b/c')
        assert rv.status_code == 302
        url = rv.headers.get('location')
        assert 'state=' in url
        assert 'code_challenge=' in url

        state = dict(url_decode(urlparse.urlparse(url).query))['state']
        verifier = get_session_data(request.session, state, "code_verifier")

        def fake_send(sess, req, **kwargs):
            assert 'code_verifier={}'.format(verifier) in req.body
            return mock_send_value(get_bearer_token())

        with mock.patch('requests.sessions.Session.send', fake_send):
            request2 = testing.DummyRequest(
                path="/authorize",
                params={"state": state}
            )
            request2.session = request.session
            token = client.authorize_access_token(request2)
            assert token['access_token'] == 'a'
예제 #11
0
    def test_code_id_token_access_token(self):
        self.prepare_data()
        rv = self.client.post('/oauth/authorize',
                              data={
                                  'client_id': 'hybrid-client',
                                  'response_type': 'code id_token token',
                                  'state': 'bar',
                                  'nonce': 'abc',
                                  'scope': 'openid profile',
                                  'redirect_uri': 'https://a.b',
                                  'user_id': '1',
                              })
        self.assertIn('code=', rv.location)
        self.assertIn('id_token=', rv.location)
        self.assertIn('access_token=', rv.location)

        params = dict(url_decode(urlparse.urlparse(rv.location).fragment))
        self.assertEqual(params['state'], 'bar')
        self.validate_claims(params['id_token'], params)

        code = params['code']
        headers = self.create_basic_header('hybrid-client', 'hybrid-secret')
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'redirect_uri': 'https://a.b',
                                  'code': code,
                              },
                              headers=headers)
        resp = json.loads(rv.data)
        self.assertIn('access_token', resp)
        self.assertIn('id_token', resp)
예제 #12
0
    def test_authorize_token(self):
        self.prepare_data()
        rv = self.client.post('/oauth/authorize', data={
            'response_type': 'code',
            'client_id': 'code-client',
            'state': 'bar',
            'scope': 'openid profile',
            'redirect_uri': 'https://a.b',
            'user_id': '1'
        })
        self.assertIn('code=', rv.location)

        params = dict(url_decode(urlparse.urlparse(rv.location).query))
        self.assertEqual(params['state'], 'bar')

        code = params['code']
        headers = self.create_basic_header('code-client', 'code-secret')
        rv = self.client.post('/oauth/token', data={
            'grant_type': 'authorization_code',
            'redirect_uri': 'https://a.b',
            'code': code,
        }, headers=headers)
        resp = json.loads(rv.data)
        self.assertIn('access_token', resp)
        self.assertIn('id_token', resp)

        jwt = JWT()
        claims = jwt.decode(
            resp['id_token'], 'secret',
            claims_cls=CodeIDToken,
            claims_options={'iss': {'value': 'Authlib'}}
        )
        claims.validate()
    def test_client_secret_post(self):
        self.app.config.update({"OAUTH2_REFRESH_TOKEN_GENERATOR": True})
        self.prepare_data(
            grant_type="authorization_code\nrefresh_token",
            token_endpoint_auth_method="client_secret_post",
        )
        url = self.authorize_url + "&state=bar"
        rv = self.client.post(url, data={"user_id": "1"})
        self.assertIn("code=", rv.headers["location"])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers["location"]).query))
        self.assertEqual(params["state"], "bar")

        code = params["code"]
        rv = self.client.post(
            "/oauth/token",
            data={
                "grant_type": "authorization_code",
                "client_id": "code-client",
                "client_secret": "code-secret",
                "code": code,
            },
        )
        resp = rv.json()
        self.assertIn("access_token", resp)
        self.assertIn("refresh_token", resp)
    def test_authorize_token_has_refresh_token(self):
        # generate refresh token
        self.app.config.update({"OAUTH2_REFRESH_TOKEN_GENERATOR": True})
        self.prepare_data(grant_type="authorization_code\nrefresh_token")
        url = self.authorize_url + "&state=bar"
        rv = self.client.post(url, data={"user_id": "1"})
        self.assertIn("code=", rv.headers["location"])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers["location"]).query))
        self.assertEqual(params["state"], "bar")

        code = params["code"]
        headers = self.create_basic_header("code-client", "code-secret")
        rv = self.client.post(
            "/oauth/token",
            data={
                "grant_type": "authorization_code",
                "code": code,
            },
            headers=headers,
        )
        resp = rv.json()
        self.assertIn("access_token", resp)
        self.assertIn("refresh_token", resp)
예제 #15
0
    def test_authorize_token(self):
        # generate refresh token
        self.prepare_data()
        rv = self.client.post('/oauth/authorize',
                              data={
                                  'response_type': 'code',
                                  'client_id': 'code-client',
                                  'state': 'bar',
                                  'scope': 'openid profile',
                                  'redirect_uri': 'https://a.b',
                                  'user_id': '1'
                              })
        self.assertIn('code=', rv.location)

        params = dict(url_decode(urlparse.urlparse(rv.location).query))
        self.assertEqual(params['state'], 'bar')

        code = params['code']
        headers = self.create_basic_header('code-client', 'code-secret')
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'redirect_uri': 'https://a.b',
                                  'code': code,
                              },
                              headers=headers)
        resp = json.loads(rv.data)
        self.assertIn('access_token', resp)
        self.assertIn('id_token', resp)
예제 #16
0
    def test_oauth2_authorize(self):
        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        client = oauth.register('dev',
                                client_id='dev',
                                client_secret='dev',
                                api_base_url='https://i.b/api',
                                access_token_url='https://i.b/token',
                                authorize_url='https://i.b/authorize')

        with app.test_request_context():
            resp = client.authorize_redirect('https://b.com/bar')
            self.assertEqual(resp.status_code, 302)
            url = resp.headers.get('Location')
            self.assertIn('state=', url)
            state = dict(url_decode(urlparse.urlparse(url).query))['state']
            self.assertIsNotNone(state)
            data = session[f'_state_dev_{state}']

        with app.test_request_context(path=f'/?code=a&state={state}'):
            # session is cleared in tests
            session[f'_state_dev_{state}'] = data

            with mock.patch('requests.sessions.Session.send') as send:
                send.return_value = mock_send_value(get_bearer_token())
                token = client.authorize_access_token()
                self.assertEqual(token['access_token'], 'a')

        with app.test_request_context():
            self.assertEqual(client.token, None)
예제 #17
0
    def test_create_authorization_response(self):
        server = self.create_server()
        self.prepare_data()
        data = {'response_type': 'token', 'client_id': 'client'}
        request = self.factory.post('/authorize', data=data)
        server.get_consent_grant(request)

        resp = server.create_authorization_response(request)
        self.assertEqual(resp.status_code, 302)
        params = dict(url_decode(urlparse.urlparse(resp['Location']).fragment))
        self.assertEqual(params['error'], 'access_denied')

        grant_user = User.objects.get(username='******')
        resp = server.create_authorization_response(request,
                                                    grant_user=grant_user)
        self.assertEqual(resp.status_code, 302)
        params = dict(url_decode(urlparse.urlparse(resp['Location']).fragment))
        self.assertIn('access_token', params)
예제 #18
0
def parse_implicit_response(uri, state=None):
    """Parse the implicit token response URI into a dict.

    If the resource owner grants the access request, the authorization
    server issues an access token and delivers it to the client by adding
    the following parameters to the fragment component of the redirection
    URI using the ``application/x-www-form-urlencoded`` format:

    **access_token**
            REQUIRED.  The access token issued by the authorization server.

    **token_type**
            REQUIRED.  The type of the token issued as described in
            Section 7.1.  Value is case insensitive.

    **expires_in**
            RECOMMENDED.  The lifetime in seconds of the access token.  For
            example, the value "3600" denotes that the access token will
            expire in one hour from the time the response was generated.
            If omitted, the authorization server SHOULD provide the
            expiration time via other means or document the default value.

    **scope**
            OPTIONAL, if identical to the scope requested by the client,
            otherwise REQUIRED.  The scope of the access token as described
            by Section 3.3.

    **state**
            REQUIRED if the "state" parameter was present in the client
            authorization request.  The exact value received from the
            client.

    Similar to the authorization code response, but with a full token provided
    in the URL fragment:

    .. code-block:: http

        HTTP/1.1 302 Found
        Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
                &state=xyz&token_type=example&expires_in=3600
    """
    fragment = urlparse.urlparse(uri).fragment
    params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True))

    if 'access_token' not in params:
        raise MissingTokenError()

    if 'token_type' not in params:
        raise MissingTokenTypeError()

    if state and params.get('state', None) != state:
        raise MismatchingStateError()

    return params
예제 #19
0
    def parse_authorization_response(self, url):
        """Extract parameters from the post authorization redirect
        response URL.

        :param url: The full URL that resulted from the user being redirected
                    back from the OAuth provider to you, the client.
        :returns: A dict of parameters extracted from the URL.
        """
        token = dict(url_decode(urlparse.urlparse(url).query))
        self.token = token
        return token
예제 #20
0
    def get_authorization_grant(self, uri):
        """Find the authorization grant for current request.

        :param uri: HTTP request URI string.
        :return: grant instance
        """
        InsecureTransportError.check(uri)
        params = dict(url_decode(urlparse.urlparse(uri).query))
        for grant_cls in self._authorization_endpoints:
            if grant_cls.check_authorization_endpoint(params):
                return grant_cls(uri, params, {}, self.client_model,
                                 self.token_generator)
        raise InvalidGrantError()
예제 #21
0
def prepare_request_uri_query(oauth_params, uri):
    """Prepare the Request URI Query.

    Per `section 3.5.3`_ of the spec.

    .. _`section 3.5.3`: http://tools.ietf.org/html/rfc5849#section-3.5.3

    """
    # append OAuth params to the existing set of query components
    sch, net, path, par, query, fra = urlparse.urlparse(uri)
    query = url_encode(
        _append_params(oauth_params, extract_params(query) or []))
    return urlparse.urlunparse((sch, net, path, par, query, fra))
예제 #22
0
    def test_openid_authorize(self):
        request = testing.DummyRequest(path="/login")
        key = jwk.dumps('secret', 'oct', kid='f')

        oauth = OAuth()
        client = oauth.register(
            'dev',
            client_id='dev',
            jwks={'keys': [key]},
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize',
            client_kwargs={'scope': 'openid profile'},
        )

        resp = client.authorize_redirect(request, 'https://b.com/bar')
        assert resp.status_code == 302
        url = resp.headers.get('location')
        assert 'nonce=' in url

        query_data = dict(url_decode(urlparse.urlparse(url).query))
        token = get_bearer_token()
        token['id_token'] = generate_id_token(
            token, {'sub': '123'}, key,
            alg='HS256', iss='https://i.b',
            aud='dev', exp=3600, nonce=query_data['nonce'],
        )
        state = query_data['state']
        metadata = {
            "issuer": "https://i.b",
            "id_token_signing_alg_values_supported": ["HS256", "RS256"],
            'jwks': {'keys': [{'k': 'c2VjcmV0', 'kid': 'f', 'kty': 'oct'}]}
        }

        with (
            mock.patch('requests.sessions.Session.send') as send,
            mock.patch.object(client, "load_server_metadata") as load_server_metadata
        ):
            send.return_value = mock_send_value(token)
            load_server_metadata.return_value = metadata

            request2 = testing.DummyRequest(
                path='/authorize',
                params={"state": state, "code": 'foo'},
            )
            request2.session = request.session

            token = client.authorize_access_token(request2)
            assert token['access_token'] == 'a'
            assert 'userinfo' in token
            assert token['userinfo']['sub'] == '123'
예제 #23
0
def base_string_from_request(method, uri, body, headers):
    """Construct base string from a HTTP request."""
    collected_params = collect_parameters(
        uri_query=urlparse.urlparse(uri).query,
        body=body,
        headers=headers
    )

    normalized_params = normalize_parameters(collected_params)
    normalized_uri = normalize_base_string_uri(
        uri, headers.get('Host', None)
    )

    return construct_base_string(method, normalized_uri, normalized_params)
예제 #24
0
def get_well_known_url(issuer, external=False):
    """Get well-known URI with issuer via Section 4.1.

    :param issuer: URL of the issuer
    :param external: return full external url or not
    :return: URL
    """
    # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
    if external:
        return issuer.rstrip('/') + '/.well-known/openid-configuration'

    parsed = urlparse.urlparse(issuer)
    path = parsed.path
    return path.rstrip('/') + '/.well-known/openid-configuration'
예제 #25
0
    def __init__(self, method, uri, body=None, headers=None):
        InsecureTransportError.check(uri)
        self.method = method
        self.uri = uri
        self.body = body
        self.headers = headers or {}

        # states namespaces
        self.client = None
        self.credential = None
        self.grant_user = None

        self.query = urlparse.urlparse(uri).query
        self.query_params = url_decode(self.query)
        self.body_params = extract_params(body) or []

        auth = headers.get('Authorization')
        self.realm = None
        if auth:
            self.auth_params = _parse_authorization_header(auth)
            self.realm = dict(self.auth_params).get('realm')
        else:
            self.auth_params = []

        oauth_params_set = [
            (SIGNATURE_TYPE_QUERY, list(_filter_oauth(self.query_params))),
            (SIGNATURE_TYPE_BODY, list(_filter_oauth(self.body_params))),
            (SIGNATURE_TYPE_HEADER, list(_filter_oauth(self.auth_params)))
        ]
        oauth_params_set = [params for params in oauth_params_set if params[1]]
        if len(oauth_params_set) > 1:
            found_types = [p[0] for p in oauth_params_set]
            raise DuplicatedOAuthProtocolParameterError(
                '"oauth_" params must come from only 1 signature type '
                'but were found in {}'.format(','.join(found_types))
            )

        if oauth_params_set:
            self.signature_type = oauth_params_set[0][0]
            self.oauth_params = dict(oauth_params_set[0][1])
        else:
            self.signature_type = None
            self.oauth_params = {}

        params = []
        params.extend(self.query_params)
        params.extend(self.body_params)
        params.extend(self.auth_params)
        self.params = params
예제 #26
0
    def test_openid_authorize(self):
        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        key = jwk.dumps('secret', 'oct', kid='f')

        client = oauth.register(
            'dev',
            client_id='dev',
            api_base_url='https://i.b/api',
            access_token_url='https://i.b/token',
            authorize_url='https://i.b/authorize',
            client_kwargs={'scope': 'openid profile'},
            jwks={'keys': [key]},
        )

        with app.test_request_context():
            resp = client.authorize_redirect('https://b.com/bar')
            self.assertEqual(resp.status_code, 302)

            url = resp.headers['Location']
            query_data = dict(url_decode(urlparse.urlparse(url).query))

            state = query_data['state']
            self.assertIsNotNone(state)
            session_data = session[f'_state_dev_{state}']
            nonce = session_data['data']['nonce']
            self.assertIsNotNone(nonce)
            self.assertEqual(nonce, query_data['nonce'])

        token = get_bearer_token()
        token['id_token'] = generate_id_token(
            token,
            {'sub': '123'},
            key,
            alg='HS256',
            iss='https://i.b',
            aud='dev',
            exp=3600,
            nonce=query_data['nonce'],
        )
        path = '/?code=a&state={}'.format(state)
        with app.test_request_context(path=path):
            session[f'_state_dev_{state}'] = session_data
            with mock.patch('requests.sessions.Session.send') as send:
                send.return_value = mock_send_value(token)
                token = client.authorize_access_token()
                self.assertEqual(token['access_token'], 'a')
                self.assertIn('userinfo', token)
예제 #27
0
    def test_trusted_client_missing_code_verifier(self):
        self.prepare_data('client_secret_basic')
        url = self.authorize_url + '&code_challenge=foo'
        rv = self.client.post(url, data={'user_id': '1'})
        self.assertIn('code=', rv.location)

        params = dict(url_decode(urlparse.urlparse(rv.location).query))
        code = params['code']
        headers = self.create_basic_header('code-client', 'code-secret')
        rv = self.client.post('/oauth/token', data={
            'grant_type': 'authorization_code',
            'code': code,
        }, headers=headers)
        resp = json.loads(rv.data)
        self.assertIn('Missing', resp['error_description'])
    def test_public_client(self):
        self.prepare_data(False)
        rv = self.client.post(self.authorize_url, data={'user_id': '1'})
        self.assertIn('code=', rv.location)

        params = dict(url_decode(urlparse.urlparse(rv.location).query))
        code = params['code']
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'code': code,
                                  'client_id': 'code-client',
                              })
        resp = json.loads(rv.data)
        self.assertEqual(resp['error'], 'unauthorized_client')
예제 #29
0
 def test_authorize_id_token(self):
     self.prepare_data()
     rv = self.client.post('/oauth/authorize', data={
         'response_type': 'id_token',
         'client_id': 'implicit-client',
         'scope': 'openid profile',
         'state': 'bar',
         'nonce': 'abc',
         'redirect_uri': 'https://a.b/c',
         'user_id': '1'
     })
     self.assertIn('id_token=', rv.location)
     self.assertIn('state=bar', rv.location)
     params = dict(url_decode(urlparse.urlparse(rv.location).fragment))
     self.validate_claims(params['id_token'], params)
예제 #30
0
def parse_authorization_code_response(uri, state=None):
    """Parse authorization grant response URI into a dict.

    If the resource owner grants the access request, the authorization
    server issues an authorization code and delivers it to the client by
    adding the following parameters to the query component of the
    redirection URI using the ``application/x-www-form-urlencoded`` format:

    **code**
            REQUIRED.  The authorization code generated by the
            authorization server.  The authorization code MUST expire
            shortly after it is issued to mitigate the risk of leaks.  A
            maximum authorization code lifetime of 10 minutes is
            RECOMMENDED.  The client MUST NOT use the authorization code
            more than once.  If an authorization code is used more than
            once, the authorization server MUST deny the request and SHOULD
            revoke (when possible) all tokens previously issued based on
            that authorization code.  The authorization code is bound to
            the client identifier and redirection URI.

    **state**
            REQUIRED if the "state" parameter was present in the client
            authorization request.  The exact value received from the
            client.

    :param uri: The full redirect URL back to the client.
    :param state: The state parameter from the authorization request.

    For example, the authorization server redirects the user-agent by
    sending the following HTTP response:

    .. code-block:: http

        HTTP/1.1 302 Found
        Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
                &state=xyz

    """
    query = urlparse.urlparse(uri).query
    params = dict(urlparse.parse_qsl(query))

    if 'code' not in params:
        raise MissingCodeError()

    if state and params.get('state', None) != state:
        raise MismatchingStateError()

    return params