示例#1
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 = session['_dev_authlib_state_']
            self.assertIsNotNone(state)

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

            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)
示例#2
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')
示例#3
0
    def test_parse_id_token_nonce_supported(self):
        key = jwk.dumps('secret', 'oct', kid='f')
        token = get_bearer_token()
        id_token = generate_id_token(
            token, {'sub': '123', 'nonce_supported': False}, key,
            alg='HS256', iss='https://i.b',
            aud='dev', exp=3600,
        )

        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            fetch_token=get_bearer_token,
            jwks={'keys': [key]},
            issuer='https://i.b',
            id_token_signing_alg_values_supported=['HS256', 'RS256'],
        )
        with app.test_request_context():
            session['_dev_authlib_nonce_'] = 'n'
            token['id_token'] = id_token
            user = client.parse_id_token(token)
            self.assertEqual(user.sub, '123')
示例#4
0
    def test_access_token_with_fetch_token(self):
        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth()

        token = get_bearer_token()
        oauth.init_app(app, fetch_token=lambda name: token)
        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')

        def fake_send(sess, req, **kwargs):
            auth = req.headers['Authorization']
            self.assertEqual(auth, 'Bearer {}'.format(token['access_token']))
            resp = mock.MagicMock()
            resp.text = 'hi'
            resp.status_code = 200
            return resp

        with app.test_request_context():
            with mock.patch('requests.sessions.Session.send', fake_send):
                resp = client.get('/api/user')
                self.assertEqual(resp.text, 'hi')

                # trigger ctx.authlib_client_oauth_token
                resp = client.get('/api/user')
                self.assertEqual(resp.text, 'hi')
示例#5
0
async def test_runtime_error_fetch_jwks_uri():
    key = jwk.dumps('secret', 'oct', kid='f')
    token = get_bearer_token()
    id_token = generate_id_token(
        token,
        {'sub': '123'},
        key,
        alg='HS256',
        iss='https://i.b',
        aud='dev',
        exp=3600,
        nonce='n',
    )

    oauth = OAuth()
    client = oauth.register(
        'dev',
        client_id='dev',
        client_secret='dev',
        fetch_token=get_bearer_token,
        issuer='https://i.b',
        id_token_signing_alg_values_supported=['HS256'],
    )
    req_scope = {'type': 'http', 'session': {'_dev_authlib_nonce_': 'n'}}
    req = Request(req_scope)
    token['id_token'] = id_token
    with pytest.raises(RuntimeError):
        await client.parse_id_token(req, token)
示例#6
0
async def test_force_fetch_jwks_uri():
    secret_keys = read_file_path('jwks_private.json')
    token = get_bearer_token()
    id_token = generate_id_token(
        token, {'sub': '123'}, secret_keys,
        alg='RS256', iss='https://i.b',
        aud='dev', exp=3600, nonce='n',
    )

    app = AsyncPathMapDispatch({
        '/jwks': {'body': read_file_path('jwks_public.json')}
    })

    oauth = OAuth()
    client = oauth.register(
        'dev',
        client_id='dev',
        client_secret='dev',
        fetch_token=get_bearer_token,
        jwks_uri='https://i.b/jwks',
        issuer='https://i.b',
        client_kwargs={
            'app': app,
        }
    )

    req_scope = {'type': 'http', 'session': {'_dev_authlib_nonce_': 'n'}}
    req = Request(req_scope)
    token['id_token'] = id_token
    user = await client.parse_id_token(req, token)
    assert user.sub == '123'
示例#7
0
    def test_runtime_error_fetch_jwks_uri(self):
        key = jwk.dumps('secret', 'oct', kid='f')
        token = get_bearer_token()
        id_token = generate_id_token(
            token, {'sub': '123'}, key,
            alg='HS256', iss='https://i.b',
            aud='dev', exp=3600, nonce='n',
        )

        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            fetch_token=get_bearer_token,
            jwks={'keys': [jwk.dumps('secret', 'oct', kid='b')]},
            issuer='https://i.b',
            id_token_signing_alg_values_supported=['HS256'],
        )
        with app.test_request_context():
            session['_dev_authlib_nonce_'] = 'n'
            token['id_token'] = id_token
            self.assertRaises(RuntimeError, client.parse_id_token, token)
示例#8
0
    def test_oauth2_authorize_code_verifier(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'},
        )
        state = 'foo'
        code_verifier = 'bar'
        rv = client.authorize_redirect(request,
                                       'https://a.b/c',
                                       state=state,
                                       code_verifier=code_verifier)
        self.assertEqual(rv.status_code, 302)
        url = rv.get('Location')
        self.assertIn('state=', url)
        self.assertIn('code_challenge=', url)

        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')
async def test_oauth2_authorize():
    oauth = OAuth()
    app = AsyncPathMapDispatch({'/token': {'body': get_bearer_token()}})
    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',
                            client_kwargs={
                                'app': app,
                            })

    req_scope = {'type': 'http', 'session': {}}
    req = Request(req_scope)
    resp = await client.authorize_redirect(req, 'https://b.com/bar')
    assert resp.status_code == 302
    url = resp.headers.get('Location')
    assert 'state=' in url

    state = req.session.get('_dev_authlib_state_')
    assert state is not None

    req_scope.update({
        'path': '/',
        'query_string': f'code=a&state={state}',
        'session': req.session,
    })
    req = Request(req_scope)
    token = await client.authorize_access_token(req)
    assert token['access_token'] == 'a'
示例#10
0
 def test_oauth2_fetch_access_token(self):
     url = 'https://example.com/token'
     token = get_bearer_token()
     with mock.patch('requests.sessions.Session.send') as send:
         send.return_value = mock_send_value(token)
         client = OAuthClient(client_id='foo', access_token_url=url)
         self.assertEqual(client.fetch_access_token(), token)
         self.assertEqual(client.fetch_access_token(url), token)
示例#11
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)
示例#12
0
 def test_oauth2_access_token_with_post(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')
     payload = {'code': 'a', 'state': 'b'}
     with app.test_request_context(data=payload, method='POST'):
         session['_dev_authlib_state_'] = 'b'
         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')
示例#13
0
    def test_openid_authorize(self):
        request = self.factory.get('/login')
        request.session = self.factory.session
        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')
        self.assertEqual(resp.status_code, 302)
        url = resp.get('Location')
        self.assertIn('nonce=', 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']
        with mock.patch('requests.sessions.Session.send') as send:
            send.return_value = mock_send_value(token)

            request2 = self.factory.get(
                '/authorize?state={}&code=foo'.format(state))
            request2.session = request.session

            token = client.authorize_access_token(request2)
            self.assertEqual(token['access_token'], 'a')
            self.assertIn('userinfo', token)
            self.assertEqual(token['userinfo']['sub'], '123')
示例#14
0
async def test_oauth2_authorize_code_challenge():
    dispatch = PathMapDispatch({
        '/token': {'body': get_bearer_token()}
    })
    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',
            'dispatch': dispatch,
        },
    )

    req_scope = {'type': 'http', 'session': {}}
    req = Request(req_scope)

    resp = await client.authorize_redirect(req, redirect_uri='https://b.com/bar')
    assert resp.status_code == 302

    url = resp.headers.get('Location')
    assert 'code_challenge=' in url
    assert 'code_challenge_method=S256' in url

    state = req.session['_dev_authlib_state_']
    assert state is not None

    verifier = req.session['_dev_authlib_code_verifier_']
    assert verifier is not None

    req_scope.update(
        {
            'path': '/',
            'query_string': 'code=a&state={}'.format(state).encode(),
            'session': req.session,
        }
    )
    req = Request(req_scope)

    token = await client.authorize_access_token(req)
    assert token['access_token'] == 'a'
示例#15
0
    def test_oauth2_access_token_with_post(self):
        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',
        )
        payload = {'code': 'a', 'state': 'b'}

        with mock.patch('requests.sessions.Session.send') as send:
            send.return_value = mock_send_value(get_bearer_token())
            request = self.factory.post('/token', data=payload)
            request.session = self.factory.session
            request.session['_state_dev_b'] = {'data': {}}
            token = client.authorize_access_token(request)
            self.assertEqual(token['access_token'], 'a')
示例#16
0
    def test_parse_id_token(self):
        key = jwk.dumps('secret', 'oct', kid='f')
        token = get_bearer_token()
        id_token = generate_id_token(
            token,
            {'sub': '123'},
            key,
            alg='HS256',
            iss='https://i.b',
            aud='dev',
            exp=3600,
            nonce='n',
        )

        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            fetch_token=get_bearer_token,
            jwks={'keys': [key]},
            issuer='https://i.b',
            id_token_signing_alg_values_supported=['HS256', 'RS256'],
        )
        with app.test_request_context():
            self.assertIsNone(client.parse_id_token(token, nonce='n'))

            token['id_token'] = id_token
            user = client.parse_id_token(token, nonce='n')
            self.assertEqual(user.sub, '123')

            claims_options = {'iss': {'value': 'https://i.b'}}
            user = client.parse_id_token(token,
                                         nonce='n',
                                         claims_options=claims_options)
            self.assertEqual(user.sub, '123')

            claims_options = {'iss': {'value': 'https://i.c'}}
            self.assertRaises(InvalidClaimError, client.parse_id_token, token,
                              'n', claims_options)
示例#17
0
async def test_parse_id_token():
    key = jwk.dumps('secret', 'oct', kid='f')
    token = get_bearer_token()
    id_token = generate_id_token(
        token,
        {'sub': '123'},
        key,
        alg='HS256',
        iss='https://i.b',
        aud='dev',
        exp=3600,
        nonce='n',
    )

    oauth = OAuth()
    client = oauth.register(
        'dev',
        client_id='dev',
        client_secret='dev',
        fetch_token=get_bearer_token,
        jwks={'keys': [key]},
        issuer='https://i.b',
        id_token_signing_alg_values_supported=['HS256', 'RS256'],
    )
    req_scope = {'type': 'http', 'session': {'_dev_authlib_nonce_': 'n'}}
    req = Request(req_scope)

    user = await client.parse_id_token(req, token)
    assert user is None

    token['id_token'] = id_token
    user = await client.parse_id_token(req, token)
    assert user.sub == '123'

    claims_options = {'iss': {'value': 'https://i.b'}}
    user = await client.parse_id_token(req, token, claims_options)
    assert user.sub == '123'

    with pytest.raises(InvalidClaimError):
        claims_options = {'iss': {'value': 'https://i.c'}}
        await client.parse_id_token(req, token, claims_options)
示例#18
0
    def test_force_fetch_jwks_uri(self):
        secret_keys = read_file_path('jwks_private.json')
        token = get_bearer_token()
        id_token = generate_id_token(
            token,
            {'sub': '123'},
            secret_keys,
            alg='RS256',
            iss='https://i.b',
            aud='dev',
            exp=3600,
            nonce='n',
        )

        app = Flask(__name__)
        app.secret_key = '!'
        oauth = OAuth(app)
        client = oauth.register(
            'dev',
            client_id='dev',
            client_secret='dev',
            fetch_token=get_bearer_token,
            jwks={'keys': [jwk.dumps('secret', 'oct', kid='f')]},
            jwks_uri='https://i.b/jwks',
            issuer='https://i.b',
        )

        def fake_send(sess, req, **kwargs):
            resp = mock.MagicMock()
            resp.json = lambda: read_file_path('jwks_public.json')
            resp.status_code = 200
            return resp

        with app.test_request_context():
            session['_dev_authlib_nonce_'] = 'n'
            self.assertIsNone(client.parse_id_token(token))

            with mock.patch('requests.sessions.Session.send', fake_send):
                token['id_token'] = id_token
                user = client.parse_id_token(token)
                self.assertEqual(user.sub, '123')
示例#19
0
    def test_request_with_token(self):
        with mock.patch('requests.sessions.Session.send') as send:
            send.return_value = mock_send_value({'name': 'a'})

            client = OAuthClient(client_id='foo')
            token = get_bearer_token()
            resp = client.get('https://i.b/user', token=token)
            self.assertEqual(resp.json()['name'], 'a')

            resp = client.post('https://i.b/user', token=token)
            self.assertEqual(resp.json()['name'], 'a')

            resp = client.put('https://i.b/user', token=token)
            self.assertEqual(resp.json()['name'], 'a')

            resp = client.delete('https://i.b/user', token=token)
            self.assertEqual(resp.json()['name'], 'a')

            client.api_base_url = 'https://i.b'
            resp = client.get('user', token=token)
            self.assertEqual(resp.json()['name'], 'a')
示例#20
0
async def test_oauth2_authorize_access_denied():
    oauth = OAuth()
    app = AsyncPathMapDispatch({'/token': {'body': get_bearer_token()}})
    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',
                            client_kwargs={
                                'app': app,
                            })

    req = Request({
        'type':
        'http',
        'session': {},
        'path':
        '/',
        'query_string':
        'error=access_denied&error_description=Not+Allowed',
    })
    with pytest.raises(OAuthError):
        await client.authorize_access_token(req)
示例#21
0
 def fake_send(sess, req, **kwargs):
     self.assertEqual(sess.token['access_token'], 'dev')
     return mock_send_value(get_bearer_token())
示例#22
0
 async def fetch_token(request):
     return get_bearer_token()
示例#23
0
 def fake_send(sess, req, **kwargs):
     self.assertIn(f'code_verifier={verifier}', req.body)
     return mock_send_value(get_bearer_token())
示例#24
0
 def fake_send(sess, req, **kwargs):
     self.assertIn('code_verifier={}'.format(verifier), req.body)
     return mock_send_value(get_bearer_token())