Ejemplo n.º 1
0
    def __init__(self,
                 client_id=None,
                 client_secret=None,
                 token_endpoint_auth_method=None,
                 revocation_endpoint_auth_method=None,
                 scope=None,
                 redirect_uri=None,
                 token=None,
                 token_placement='header',
                 update_token=None,
                 **kwargs):

        # extract httpx.Client kwargs
        client_kwargs = self._extract_session_request_params(kwargs)
        Client.__init__(self, **client_kwargs)

        _OAuth2Client.__init__(
            self,
            session=self,
            client_id=client_id,
            client_secret=client_secret,
            token_endpoint_auth_method=token_endpoint_auth_method,
            revocation_endpoint_auth_method=revocation_endpoint_auth_method,
            scope=scope,
            redirect_uri=redirect_uri,
            token=token,
            token_placement=token_placement,
            update_token=update_token,
            **kwargs)
Ejemplo n.º 2
0
    def __init__(self, client_id=None, client_secret=None,
                 token_endpoint_auth_method=None,
                 revocation_endpoint_auth_method=None,
                 scope=None, redirect_uri=None,
                 token=None, token_placement='header',
                 update_token=None, **kwargs):

        # extract httpx.Client kwargs
        client_kwargs = self._extract_session_request_params(kwargs)
        AsyncClient.__init__(self, **client_kwargs)

        # We use a "reverse" Event to synchronize coroutines to prevent
        # multiple concurrent attempts to refresh the same token
        self._token_refresh_event = asyncio.Event()
        self._token_refresh_event.set()

        _OAuth2Client.__init__(
            self, session=None,
            client_id=client_id, client_secret=client_secret,
            token_endpoint_auth_method=token_endpoint_auth_method,
            revocation_endpoint_auth_method=revocation_endpoint_auth_method,
            scope=scope, redirect_uri=redirect_uri,
            token=token, token_placement=token_placement,
            update_token=update_token, **kwargs
        )
Ejemplo n.º 3
0
 def __init__(self,
              client_id=None,
              client_secret=None,
              token_endpoint_auth_method=None,
              refresh_token_url=None,
              refresh_token_params=None,
              scope=None,
              redirect_uri=None,
              token=None,
              token_placement='header',
              state=None,
              token_updater=None,
              **kwargs):
     Session.__init__(self)
     OAuth2Client.__init__(self,
                           session=self,
                           client_id=client_id,
                           client_secret=client_secret,
                           client_auth_method=token_endpoint_auth_method,
                           refresh_token_url=refresh_token_url,
                           refresh_token_params=refresh_token_params,
                           scope=scope,
                           redirect_uri=redirect_uri,
                           token=token,
                           token_placement=token_placement,
                           state=state,
                           token_updater=token_updater,
                           **kwargs)
     self.token_endpoint_auth_method = token_endpoint_auth_method
Ejemplo n.º 4
0
    def __init__(self,
                 client_id=None,
                 client_secret=None,
                 token_endpoint_auth_method=None,
                 revocation_endpoint_auth_method=None,
                 scope=None,
                 redirect_uri=None,
                 token=None,
                 token_placement='header',
                 update_token=None,
                 **kwargs):

        Session.__init__(self)
        OAuth2Client.__init__(
            self,
            session=self,
            client_id=client_id,
            client_secret=client_secret,
            token_endpoint_auth_method=token_endpoint_auth_method,
            revocation_endpoint_auth_method=revocation_endpoint_auth_method,
            scope=scope,
            redirect_uri=redirect_uri,
            token=token,
            token_placement=token_placement,
            update_token=update_token,
            **kwargs)
Ejemplo n.º 5
0
def test_pkce_disabled(dummy_application, test_client, dummy_user, pkce_enabled):
    dummy_application.allow_pkce_flow = pkce_enabled
    oauth_client = OAuth2Client(MockSession(test_client),
                                dummy_application.client_id, None,
                                code_challenge_method='S256',
                                token_endpoint=url_for('oauth.oauth_token', _external=True),
                                redirect_uri=dummy_application.default_redirect_uri)

    with test_client.session_transaction() as sess:
        sess.set_session_user(dummy_user)

    code_verifier = generate_token(64)
    auth_endpoint = url_for('oauth.oauth_authorize', _external=True)
    auth_url = oauth_client.create_authorization_url(auth_endpoint, scope='read:legacy_api',
                                                     code_verifier=code_verifier)[0]

    authorized_resp = test_client.post(auth_url, data={'confirm': '1'})
    assert authorized_resp.status_code == 302
    target_url = authorized_resp.headers['Location']

    if pkce_enabled:
        token = oauth_client.fetch_token(authorization_response=target_url, code_verifier=code_verifier)
        assert token.keys() == {'access_token', 'token_type', 'scope'}
    else:
        with pytest.raises(ValueError) as exc_info:
            oauth_client.fetch_token(authorization_response=target_url, code_verifier=code_verifier)
        assert 'invalid_client' in str(exc_info.value)
def test_oauth_flows(create_application, test_client, dummy_user, app, trusted,
                     token_endpoint_auth_method, pkce):
    oauth_app = create_application(name='test', is_trusted=trusted)
    oauth_client = OAuth2Client(
        MockSession(test_client),
        oauth_app.client_id,
        oauth_app.client_secret if not pkce else None,
        code_challenge_method=('S256' if pkce else None),
        scope='read:user',
        response_type='code',
        token_endpoint=url_for('oauth.oauth_token', _external=True),
        token_endpoint_auth_method=token_endpoint_auth_method,
        redirect_uri=oauth_app.default_redirect_uri)

    code_verifier = generate_token(64) if pkce else None
    auth_url, state = oauth_client.create_authorization_url(
        url_for('oauth.oauth_authorize', _external=True),
        code_verifier=code_verifier)

    with test_client.session_transaction() as sess:
        sess.set_session_user(dummy_user)

    # get consent page
    resp = test_client.get(auth_url)
    if trusted:
        authorized_resp = resp
    else:
        assert resp.status_code == 200
        assert b'is requesting the following permissions' in resp.data
        assert b'User information (read only)' in resp.data

        # give consent
        authorized_resp = test_client.post(auth_url, data={'confirm': '1'})

    assert authorized_resp.status_code == 302
    target_url = authorized_resp.headers['Location']
    target_url_parts = url_parse(target_url)

    assert f'state={state}' in target_url_parts.query
    assert target_url == f'{oauth_app.default_redirect_uri}?{target_url_parts.query}'

    # get a token and make sure it looks fine
    token = oauth_client.fetch_token(authorization_response=target_url,
                                     code_verifier=code_verifier)
    assert token == {
        'access_token': token['access_token'],
        'token_type': 'Bearer',
        'scope': 'read:user'
    }

    with app.test_client() as test_client_no_session:
        # make sure we can use our token
        uri, headers, data = oauth_client.token_auth.prepare(
            '/api/user/', {}, '')
        resp = test_client_no_session.get(uri, data=data, headers=headers)
        assert resp.status_code == 200
        assert resp.json['id'] == dummy_user.id

    # authorizing again won't require new consent, regardless of the app being trusted
    assert test_client.get(auth_url).status_code == 302
Ejemplo n.º 7
0
    def __init__(self,
                 client_id=None,
                 client_secret=None,
                 authorization_endpoint=None,
                 token_endpoint=None,
                 token_endpoint_auth_method=None,
                 revocation_endpoint=None,
                 revocation_endpoint_auth_method=None,
                 scope=None,
                 redirect_uri=None,
                 token=None,
                 token_placement='header',
                 token_updater=None,
                 **kwargs):

        refresh_token_url = kwargs.pop('refresh_token_url', None)
        if refresh_token_url is not None and token_endpoint is None:
            token_endpoint = refresh_token_url

        Session.__init__(self)
        OAuth2Client.__init__(
            self,
            session=self,
            client_id=client_id,
            client_secret=client_secret,
            authorization_endpoint=authorization_endpoint,
            token_endpoint=token_endpoint,
            token_endpoint_auth_method=token_endpoint_auth_method,
            revocation_endpoint=revocation_endpoint,
            revocation_endpoint_auth_method=revocation_endpoint_auth_method,
            scope=scope,
            redirect_uri=redirect_uri,
            token=token,
            token_placement=token_placement,
            token_updater=token_updater,
            **kwargs)
Ejemplo n.º 8
0
 def __init__(self,
              client_id=None,
              client_secret=None,
              token_endpoint=None,
              token_endpoint_auth_method=None,
              scope=None,
              redirect_uri=None,
              token=None,
              token_placement='header',
              token_updater=None,
              **kwargs):
     session = ClientSession(request_class=OAuth2Request)
     _OAuth2Client.__init__(self,
                            session=session,
                            client_id=client_id,
                            client_secret=client_secret,
                            client_auth_method=token_endpoint_auth_method,
                            refresh_token_url=token_endpoint,
                            scope=scope,
                            redirect_uri=redirect_uri,
                            token=token,
                            token_placement=token_placement,
                            token_updater=token_updater,
                            **kwargs)
Ejemplo n.º 9
0
def test_no_implicit_flow(dummy_application, test_client, dummy_user):
    oauth_client = OAuth2Client(None,
                                dummy_application.client_id,
                                None,
                                scope='read:user',
                                response_type='token',
                                token_endpoint=url_for('oauth.oauth_token', _external=True),
                                redirect_uri=dummy_application.default_redirect_uri)

    auth_url = oauth_client.create_authorization_url(url_for('oauth.oauth_authorize', _external=True))[0]

    with test_client.session_transaction() as sess:
        sess.set_session_user(dummy_user)

    resp = test_client.get(auth_url)
    assert b'unsupported_response_type' in resp.data
def test_checkin_app_implicit_flow(test_client, dummy_user):
    checkin_app = OAuthApplication.query.filter_by(
        system_app_type=SystemAppType.checkin).one()
    oauth_client = OAuth2Client(None,
                                checkin_app.client_id,
                                None,
                                scope='read:user',
                                response_type='token',
                                token_endpoint=url_for('oauth.oauth_token',
                                                       _external=True),
                                redirect_uri=checkin_app.default_redirect_uri)

    auth_url = oauth_client.create_authorization_url(
        url_for('oauth.oauth_authorize', _external=True))[0]

    with test_client.session_transaction() as sess:
        sess.set_session_user(dummy_user)

    resp = test_client.get(auth_url)
    assert resp.status_code == 302
    assert '#' in resp.headers['Location']
    assert 'access_token=' in resp.headers['Location']
Ejemplo n.º 11
0
def test_oauth_scopes(create_application, test_client, dummy_user, app):
    oauth_app = create_application(name='test', is_trusted=False, allowed_scopes=['read:user', 'read:legacy_api'])
    oauth_client = OAuth2Client(MockSession(test_client),
                                oauth_app.client_id, oauth_app.client_secret,
                                token_endpoint=url_for('oauth.oauth_token', _external=True),
                                redirect_uri=oauth_app.default_redirect_uri)

    with test_client.session_transaction() as sess:
        sess.set_session_user(dummy_user)

    auth_endpoint = url_for('oauth.oauth_authorize', _external=True)
    auth_url = oauth_client.create_authorization_url(auth_endpoint, scope='read:legacy_api')[0]
    assert not oauth_app.user_links.count()

    # get consent page
    resp = test_client.get(auth_url)
    assert resp.status_code == 200
    assert b'is requesting the following permissions' in resp.data
    assert b'Classic API (read only)' in resp.data
    assert b'User information (read only)' not in resp.data

    # give consent
    authorized_resp = test_client.post(auth_url, data={'confirm': '1'})
    assert authorized_resp.status_code == 302
    target_url = authorized_resp.headers['Location']
    assert not oauth_app.user_links.count()  # giving consent does not create the user/app link yet

    # get a token and make sure it looks fine
    token1 = oauth_client.fetch_token(authorization_response=target_url)
    assert token1 == {'access_token': token1['access_token'], 'token_type': 'Bearer', 'scope': 'read:legacy_api'}
    assert len(token1['access_token']) == 47  # longer would be fine but we don't expect this to change
    assert token1['access_token'].startswith(TOKEN_PREFIX_OAUTH)

    app_link = oauth_app.user_links.one()
    assert app_link.user == dummy_user
    assert app_link.scopes == ['read:legacy_api']

    # we cannot use a token with an invalid scope
    with app.test_client() as test_client_no_session:
        uri, headers, data = oauth_client.token_auth.prepare('/api/user/', {}, '')
        resp = test_client_no_session.get(uri, data=data, headers=headers)
        assert resp.status_code == 403

    # request a different scope
    auth_url = oauth_client.create_authorization_url(auth_endpoint, scope='read:user')[0]
    authorized_resp = test_client.post(auth_url, data={'confirm': '1'})
    target_url = authorized_resp.headers['Location']
    token2 = oauth_client.fetch_token(authorization_response=target_url)
    assert token2 == {'access_token': token2['access_token'], 'token_type': 'Bearer', 'scope': 'read:user'}
    assert token2['access_token'] != token1['access_token']
    assert app_link.scopes == ['read:legacy_api', 'read:user']

    # this token is already able to access the endpoint
    with app.test_client() as test_client_no_session:
        uri, headers, data = oauth_client.token_auth.prepare('/api/user/', {}, '')
        resp = test_client_no_session.get(uri, data=data, headers=headers)
        assert resp.status_code == 200
        assert resp.json['id'] == dummy_user.id

    # no scope specified, so we should get a token with all authorized scopes
    auth_url = oauth_client.create_authorization_url(auth_endpoint)[0]
    authorized_resp = test_client.post(auth_url, data={'confirm': '1'})
    target_url = authorized_resp.headers['Location']
    token3 = oauth_client.fetch_token(authorization_response=target_url)
    assert set(token3.pop('scope').split()) == {'read:legacy_api', 'read:user'}
    assert token3 == {'access_token': token3['access_token'], 'token_type': 'Bearer'}
    assert token3['access_token'] != token2['access_token']
    assert app_link.scopes == ['read:legacy_api', 'read:user']

    # and of course that token also has access to the endpoint
    with app.test_client() as test_client_no_session:
        uri, headers, data = oauth_client.token_auth.prepare('/api/user/', {}, '')
        resp = test_client_no_session.get(uri, data=data, headers=headers)
        assert resp.status_code == 200
        assert resp.json['id'] == dummy_user.id

    # reuse an existing scope
    auth_url = oauth_client.create_authorization_url(auth_endpoint, scope='read:user')[0]
    authorized_resp = test_client.post(auth_url, data={'confirm': '1'})
    target_url = authorized_resp.headers['Location']
    token4 = oauth_client.fetch_token(authorization_response=target_url)
    assert token4 != token2  # can't reuse the old token since it's only stored as a hash