def test_response_mode_query(self):
        self.prepare_data()
        rv = self.client.post('/oauth/authorize', data={
            'client_id': 'hybrid-client',
            'response_type': 'code id_token token',
            'response_mode': 'query',
            '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).query))
        self.assertEqual(params['state'], 'bar')
Exemplo n.º 2
0
def code_from_authorize_response(response):
    """
    Get the code out from a response from ``/oauth2/authorize``.

    Args:
        response (pytest_flask.plugin.JSONResponse): response to get code from

    Return:
        str: the code
    """
    location = response.headers['Location']
    try:
        return dict(url_decode(urlparse.urlparse(location).query))['code']
    except KeyError:
        raise ValueError(
            'response did not contain a code; got headers:\n{}'
            .format(response.headers)
        )
    def test_public_authorize_token(self):
        self.app.config.update({'OAUTH2_REFRESH_TOKEN_GENERATOR': True})
        self.prepare_data(False, token_endpoint_auth_method='none')

        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.assertIn('access_token', resp)
        self.assertNotIn('refresh_token', resp)
Exemplo n.º 4
0
    async def _refresh_token(self, url, refresh_token=None, body='',
                             headers=None, auth=USE_CLIENT_DEFAULT, **kwargs):
        resp = await self.post(
            url, data=dict(url_decode(body)), headers=headers,
            auth=auth, **kwargs)

        for hook in self.compliance_hook['refresh_token_response']:
            resp = hook(resp)

        resp.raise_for_status()
        token = self.parse_response_token(resp.json())
        if 'refresh_token' not in token:
            self.token['refresh_token'] = refresh_token

        if self.update_token:
            await self.update_token(self.token, refresh_token=refresh_token)

        return self.token
    def test_plain_code_challenge_failed(self):
        self.prepare_data()
        url = self.authorize_url + '&code_challenge=foo'
        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))
        code = params['code']
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'code': code,
                                  'code_verifier': generate_token(48),
                                  'client_id': 'code-client',
                              })
        resp = rv.json()
        self.assertIn('failed', resp['error_description'])
Exemplo n.º 6
0
    def test_plain_code_challenge_success(self):
        self.prepare_data()
        code_verifier = generate_token(48)
        url = self.authorize_url + '&code_challenge=' + code_verifier
        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']
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'code': code,
                                  'code_verifier': code_verifier,
                                  'client_id': 'code-client',
                              })
        resp = json.loads(rv.data)
        self.assertIn('access_token', resp)
    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.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.assertIn('Missing', resp['error_description'])
Exemplo n.º 8
0
    async def _fetch_token(self, url, body='', headers=None, auth=USE_CLIENT_DEFAULT,
                           method='POST', **kwargs):
        if method.upper() == 'POST':
            resp = await self.post(
                url, data=dict(url_decode(body)), headers=headers,
                auth=auth, **kwargs)
        else:
            if '?' in url:
                url = '&'.join([url, body])
            else:
                url = '?'.join([url, body])
            resp = await self.get(url, headers=headers, auth=auth, **kwargs)

        for hook in self.compliance_hook['access_token_response']:
            resp = hook(resp)

        resp.raise_for_status()
        return self.parse_response_token(resp.json())
Exemplo n.º 9
0
    def test_trusted_client_without_code_challenge(self):
        self.prepare_data('client_secret_basic')
        rv = self.client.get(self.authorize_url)
        self.assertEqual(rv.data, b'ok')

        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']
        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('access_token', resp)
Exemplo n.º 10
0
    def parse_response_token(self, status_code, text):
        if status_code >= 400:
            message = "Token request failed with code {}, response was '{}'."
            self.handle_error('fetch_token_denied', message)

        try:
            text = text.strip()
            if text.startswith('{'):
                token = json.loads(text)
            else:
                token = dict(url_decode(text))
        except (TypeError, ValueError) as e:
            error = ("Unable to decode token from token response. "
                     "This is commonly caused by an unsuccessful request where"
                     " a non urlencoded error message is returned. "
                     "The decoding error was %s"
                     "" % e)
            raise ValueError(error)
        return token
Exemplo n.º 11
0
    def test_not_implemented_code_challenge_method(self):
        self.prepare_data()
        url = self.authorize_url + '&code_challenge=foo'
        url += '&code_challenge_method=S128'

        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']
        self.assertRaises(RuntimeError,
                          self.client.post,
                          '/oauth/token',
                          data={
                              'grant_type': 'authorization_code',
                              'code': code,
                              'code_verifier': 'foo',
                              'client_id': 'code-client',
                          })
 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.headers["location"])
     self.assertIn("state=bar", rv.headers["location"])
     params = dict(
         url_decode(urlparse.urlparse(rv.headers["location"]).fragment))
     self.validate_claims(params["id_token"], params)
    def test_token_generator(self):
        m = 'tests.flask.test_oauth2.oauth2_server:token_generator'
        self.app.config.update({'OAUTH2_ACCESS_TOKEN_GENERATOR': m})
        self.prepare_data(False, token_endpoint_auth_method='none')

        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.assertIn('access_token', resp)
        self.assertIn('c-authorization_code.1.', resp['access_token'])
Exemplo n.º 14
0
    def test_s256_code_challenge_success_client_secret_post(self, client, oauth):
        code_verifier = generate_token(48)
        code_challenge = create_s256_code_challenge(code_verifier)

        client.login()

        response = client.post(url_for(
            'oauth.authorize',
            response_type='code',
            client_id=oauth.client_id,
            code_challenge=code_challenge,
            code_challenge_method='S256'
        ), {
            'scope': 'default',
            'accept': '',
        })
        assert 'code=' in response.location

        params = dict(url_decode(urlparse.urlparse(response.location).query))
        code = params['code']

        response = client.post(url_for('oauth.token'), {
            'grant_type': 'authorization_code',
            'code': code,
            'code_verifier': code_verifier,
            'client_id': oauth.client_id,
            'client_secret': oauth.secret
        })

        assert200(response)
        assert response.content_type == 'application/json'
        assert 'access_token' in response.json

        token = response.json['access_token']

        response = client.post(url_for('api.fake'), headers={
            'Authorization': ' '.join(['Bearer', token])
        })

        assert200(response)
        assert response.content_type == 'application/json'
        assert response.json == {'success': True}
Exemplo n.º 15
0
    def get_token_response(self):
        server = self.create_server()
        data = {'response_type': 'code', 'client_id': 'client'}
        request = self.factory.post('/authorize', data=data)
        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']).query))
        code = params['code']

        request = self.factory.post(
            '/oauth/token',
            data={'grant_type': 'authorization_code', 'code': code},
            HTTP_AUTHORIZATION=self.create_basic_auth('client', 'secret'),
        )
        resp = server.create_token_response(request)
        self.assertEqual(resp.status_code, 200)
        data = json.loads(resp.content)
        return data
Exemplo n.º 16
0
    async def _refresh_token(self,
                             url,
                             refresh_token=None,
                             body='',
                             headers=None,
                             auth=None,
                             **kwargs):
        async with self.session.post(url,
                                     data=dict(url_decode(body)),
                                     headers=headers,
                                     auth=auth,
                                     **kwargs) as resp:
            token = await self._parse_token(resp, 'refresh_token_response')
            if 'refresh_token' not in token:
                self.token['refresh_token'] = refresh_token

            if callable(self.token_updater):
                await self.token_updater(self.token)

            return self.token
    def test_authorize_token_no_refresh_token(self):
        self.app.config.update({"OAUTH2_REFRESH_TOKEN_GENERATOR": True})
        self.prepare_data(False, token_endpoint_auth_method="none")

        rv = self.client.post(self.authorize_url, data={"user_id": "1"})
        self.assertIn("code=", rv.headers["location"])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers["location"]).query))
        code = params["code"]
        rv = self.client.post(
            "/oauth/token",
            data={
                "grant_type": "authorization_code",
                "code": code,
                "client_id": "code-client",
            },
        )
        resp = rv.json()
        self.assertIn("access_token", resp)
        self.assertNotIn("refresh_token", resp)
Exemplo n.º 18
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.grant_user = None
        self.credential = None
        self.client = None
    def test_client_secret_post(self):
        self.app.config.update({'OAUTH2_REFRESH_TOKEN_GENERATOR': True})
        self.prepare_data(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.location)

        params = dict(url_decode(urlparse.urlparse(rv.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 = json.loads(rv.data)
        self.assertIn('access_token', resp)
        self.assertIn('refresh_token', resp)
    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'})
        self.assertIn('error=invalid_request', rv.location)

        uri = self.authorize_url + '&redirect_uri=https%3A%2F%2Fa.b'
        rv = self.client.post(uri, 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.assertEqual(resp['error'], 'invalid_request')
Exemplo n.º 21
0
    def test_code_id_token(self):
        self.prepare_data()
        rv = self.client.post(
            "/oauth/authorize",
            data={
                "client_id": "hybrid-client",
                "response_type": "code id_token",
                "state": "bar",
                "nonce": "abc",
                "scope": "openid profile",
                "redirect_uri": "https://a.b",
                "user_id": "1",
            },
        )
        self.assertIn("code=", rv.headers["location"])
        self.assertIn("id_token=", rv.headers["location"])
        self.assertNotIn("access_token=", rv.headers["location"])

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

        params["nonce"] = "abc"
        params["client_id"] = "hybrid-client"
        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 = rv.json()
        self.assertIn("access_token", resp)
        self.assertIn("id_token", resp)
Exemplo n.º 22
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.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.assertIn('id_token', resp)

        jwt = JsonWebToken()
        claims = jwt.decode(resp['id_token'],
                            self.get_validate_key(),
                            claims_cls=CodeIDToken,
                            claims_options={'iss': {
                                'value': 'Authlib'
                            }})
        claims.validate()
    def test_authorize_token(self):
        # generate refresh token
        self.app.config.update({'OAUTH2_REFRESH_TOKEN_GENERATOR': True})
        self.prepare_data()
        url = self.authorize_url + '&state=bar'
        rv = self.client.post(url, data={'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',
                                  'code': code,
                              },
                              headers=headers)
        resp = json.loads(rv.data)
        self.assertIn('access_token', resp)
        self.assertIn('refresh_token', resp)
    def test_token_generator(self):
        m = "tests.fastapi.test_oauth2.oauth2_server:token_generator"
        self.app.config.update({"OAUTH2_ACCESS_TOKEN_GENERATOR": m})
        self.prepare_data(False, token_endpoint_auth_method="none")

        rv = self.client.post(self.authorize_url, data={"user_id": "1"})
        self.assertIn("code=", rv.headers["location"])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers["location"]).query))
        code = params["code"]
        rv = self.client.post(
            "/oauth/token",
            data={
                "grant_type": "authorization_code",
                "code": code,
                "client_id": "code-client",
            },
        )
        resp = rv.json()
        self.assertIn("access_token", resp)
        self.assertIn("c-authorization_code.1.", resp["access_token"])
Exemplo n.º 25
0
    def test_login(self):
        """Test the login redirect"""
        self.registry.oidc.fedora.client_id = "test-client-id"
        with mock.patch('requests.sessions.Session.send',
                        side_effect=fake_send()):
            resp = self.app.get('/oidc/login', status=302)
        location = urlparse(resp.location)
        assert location.scheme == "https"
        assert location.netloc == "id.stg.fedoraproject.org"
        assert location.path == "/openidc/Authorization"

        query_data = dict(url_decode(location.query))
        assert query_data["response_type"] == "code"
        assert query_data["client_id"] == "test-client-id"
        assert query_data["redirect_uri"] == "http://localhost/oidc/authorize"
        assert set(query_data["scope"].split(" ")) == set([
            'openid',
            'email',
            'profile',
            'https://id.fedoraproject.org/scope/groups',
            'https://id.fedoraproject.org/scope/agreements',
        ])
Exemplo n.º 26
0
    def test_response_mode_query(self):
        self.prepare_data()
        rv = self.client.post(
            "/oauth/authorize",
            data={
                "client_id": "hybrid-client",
                "response_type": "code id_token token",
                "response_mode": "query",
                "state": "bar",
                "nonce": "abc",
                "scope": "openid profile",
                "redirect_uri": "https://a.b",
                "user_id": "1",
            },
        )
        self.assertIn("code=", rv.headers["location"])
        self.assertIn("id_token=", rv.headers["location"])
        self.assertIn("access_token=", rv.headers["location"])

        params = dict(
            url_decode(urlparse.urlparse(rv.headers["location"]).query))
        self.assertEqual(params["state"], "bar")
    def test_s256_code_challenge_success(self):
        self.prepare_data()
        code_verifier = generate_token(48)
        code_challenge = create_s256_code_challenge(code_verifier)
        url = self.authorize_url + '&code_challenge=' + code_challenge
        url += '&code_challenge_method=S256'

        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))
        code = params['code']
        rv = self.client.post('/oauth/token',
                              data={
                                  'grant_type': 'authorization_code',
                                  'code': code,
                                  'code_verifier': code_verifier,
                                  'client_id': 'code-client',
                              })
        resp = rv.json()
        self.assertIn('access_token', resp)
Exemplo n.º 28
0
    def test_oauth2_authorize_code_challenge(self):
        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        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'},
        )

        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('code_challenge=', url)
            self.assertIn('code_challenge_method=S256', url)

            state = dict(url_decode(urlparse.urlparse(url).query))['state']
            self.assertIsNotNone(state)
            data = session[f'_state_dev_{state}']

            verifier = data['data']['code_verifier']
            self.assertIsNotNone(verifier)

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

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

            with mock.patch('requests.sessions.Session.send', fake_send):
                token = client.authorize_access_token()
                self.assertEqual(token['access_token'], 'a')
    def test_public_authorize_token(self):
        self.app.config.update({'OAUTH2_REFRESH_TOKEN_GENERATOR': True})
        self.prepare_data(False)
        client = Client.query.filter_by(client_id='code-client').first()
        client.client_secret = ''
        db.session.add(client)
        db.session.commit()

        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.assertIn('access_token', resp)
        self.assertNotIn('refresh_token', resp)
Exemplo n.º 30
0
    def _fetch_token(self, url, **kwargs):
        resp = self.post(url, **kwargs)

        if resp.status_code >= 400:
            error = "Token request failed with code {}, response was '{}'."
            message = error.format(resp.status_code, resp.text)
            raise FetchTokenDeniedError(description=message)

        try:
            text = resp.text.strip()
            if text.startswith('{'):
                token = json.loads(text)
            else:
                token = dict(url_decode(text))
        except (TypeError, ValueError) as e:
            error = ("Unable to decode token from token response. "
                     "This is commonly caused by an unsuccessful request where"
                     " a non urlencoded error message is returned. "
                     "The decoding error was %s"
                     "" % e)
            raise ValueError(error)

        self.token = token
        return token