def test_unauthorized_signup(remote, app_rest, models_fixture): """Test unauthorized redirect on signup callback handler.""" datastore = app_rest.extensions['invenio-accounts'].datastore existing_email = '*****@*****.**' user = datastore.find_user(email=existing_email) example_response = {'access_token': 'test_access_token'} example_account_info = { 'user': { 'email': existing_email, 'external_id': '1234', 'external_method': 'test_method' } } # Mock remote app's handler current_oauthclient.signup_handlers[remote.name] = { 'info': lambda resp: example_account_info, } _security.confirmable = True _security.login_without_confirmation = False user.confirmed_at = None expected_url_args = {"message": "Unauthorized.", "code": 401} resp = authorized_signup_handler(example_response, remote) check_response_redirect_url_args(resp, expected_url_args)
def _init(): ioc = app_rest.extensions['oauthlib.client'] # setup the user account via cern_openid with app_rest.test_client() as c: # Ensure remote apps have been loaded (due to before first request) resp = c.get( url_for('invenio_oauthclient.rest_login', remote_app='cern_openid')) assert resp.status_code == 302 example_response, example_token, example_account_info = \ example_cern_openid_rest mock_response(app_rest.extensions['oauthlib.client'], 'cern_openid', example_token) mock_remote_get(ioc, 'cern_openid', example_response) resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='cern_openid', code='test', state=get_state('cern_openid'))) assert resp.status_code == 302 expected_url_args = { "message": "Successfully authorized.", "code": 200, } check_response_redirect_url_args(resp, expected_url_args) assert len(g.identity.provides) == 3
def test_signup_handler(remote, app_rest, models_fixture): """Test signup handler.""" datastore = app_rest.extensions['invenio-accounts'].datastore existing_email = '*****@*****.**' user = datastore.find_user(email=existing_email) # Already authenticated login_user(user) assert current_user.is_authenticated resp1 = signup_handler(remote) expected_url_args = {"message": "Successfully signed up.", "code": 200} check_response_redirect_url_args(resp1, expected_url_args) logout_user() assert not current_user.is_authenticated # No OAuth token resp2 = signup_handler(remote) expected_url_args = {"message": "Token not found.", "code": 400} check_response_redirect_url_args(resp2, expected_url_args) # Not coming from authorized request token = RemoteToken.create(user.id, 'testkey', 'mytoken', 'mysecret') token_setter(remote, token, 'mysecret') with pytest.raises(BuildError): signup_handler(remote)
def test_authorized_rest_handler(app_rest): """Test authorized callback handler.""" oauth = current_oauthclient.oauth remote = oauth.remote_apps['github'] # General error example_response = {'error': 'error'} resp = authorized_rest(example_response, remote) expected_url_args = { "message": "Authorization with remote service failed.", "code": 400, } check_response_redirect_url_args(resp, expected_url_args) # Bad verification error example_response = {'error': 'bad_verification_code'} resp = authorized_rest(example_response, remote) check_redirect_location(resp, '/oauth/login/github/') # Incorrect client credentials example_response = {'error': 'incorrect_client_credentials'} with pytest.raises(OAuthResponseError): authorized_rest(example_response, remote) # Redirect uri mismatch example_response = {'error': 'redirect_uri_mismatch'} with pytest.raises(OAuthResponseError): authorized_rest(example_response, remote)
def test_authorized_signup_handler(remote, app_rest, models_fixture): """Test authorized signup handler.""" datastore = app_rest.extensions['invenio-accounts'].datastore user = datastore.find_user(email='*****@*****.**') example_response = {'access_token': 'test_access_token'} # Mock remote app's handler current_oauthclient.signup_handlers[remote.name] = { 'setup': lambda token, resp: None } # Authenticate user oauth_authenticate('dev', user) # Mock next url next_url = '/test/redirect' session[token_session_key(remote.name) + '_next_url'] = next_url # Check user is redirected to next_url expected_url_args = { "message": "Successfully authorized.", "code": 200, "next_url": next_url } resp = authorized_signup_handler(example_response, remote) check_response_redirect_url_args(resp, expected_url_args)
def test_account_info_not_allowed_account(app_rest, example_cern_openid_rest): """Test account info extraction.""" client = app_rest.test_client() app_rest.config['OAUTHCLIENT_CERN_OPENID_ALLOWED_ROLES'] = [ 'another cern role' ] ioc = app_rest.extensions['oauthlib.client'] # Ensure remote apps have been loaded (due to before first request) client.get( url_for('invenio_oauthclient.rest_login', remote_app='cern_openid')) example_response, _, example_account_info = example_cern_openid_rest mock_remote_get(ioc, 'cern_openid', example_response) resp = account_info_rest(ioc.remote_apps['cern_openid'], None) assert g.oauth_logged_in_with_remote == ioc.remote_apps['cern_openid'] assert resp.status_code == 302 expected_url_args = { "message": "CERN account not allowed.", "code": 400, } check_response_redirect_url_args(resp, expected_url_args)
def test_account_setup(app_rest, example_cern_openid_rest, models_fixture): """Test account setup after login.""" with app_rest.test_client() as c: ioc = app_rest.extensions['oauthlib.client'] # Ensure remote apps have been loaded (due to before first request) resp = c.get( url_for('invenio_oauthclient.rest_login', remote_app='cern_openid')) assert resp.status_code == 302 example_response, example_token, example_account_info = \ example_cern_openid_rest mock_response(app_rest.extensions['oauthlib.client'], 'cern_openid', example_token) mock_remote_get(ioc, 'cern_openid', example_response) resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='cern_openid', code='test', state=get_state('cern_openid'))) assert resp.status_code == 302 expected_url_args = { "message": "Successfully authorized.", "code": 200, } check_response_redirect_url_args(resp, expected_url_args) assert len(g.identity.provides) == 3 datastore = app_rest.extensions['invenio-accounts'].datastore user = datastore.find_user(email='*****@*****.**') user.password = hash_password("1234") assert user with app_rest.test_request_context(): resp = disconnect_rest_handler(ioc.remote_apps['cern_openid']) assert resp.status_code >= 300 # simulate login (account_info fetch) g.oauth_logged_in_with_remote = ioc.remote_apps['cern_openid'] login_user(user) assert len(g.identity.provides) == 3 logout_user() assert len(g.identity.provides) == 1 assert "cern_resource" not in session assert OAUTHCLIENT_CERN_OPENID_SESSION_KEY not in session # Login again to test the disconnect handler g.oauth_logged_in_with_remote = ioc.remote_apps['cern_openid'] login_user(user) assert len(g.identity.provides) == 3 disconnect_rest_handler(ioc.remote_apps['cern_openid'])
def test_unauthorized_disconnect(remote, app_rest): """Test disconnect handler when user is not authenticated.""" def mock_unauthorized(): return "Unauthorized" app_rest.login_manager.unauthorized = mock_unauthorized resp = disconnect_handler(remote) expected_url_args = {"message": "Unauthorized.", "code": 401} check_response_redirect_url_args(resp, expected_url_args)
def test_already_linked_exception(remote, app_rest): """Test error when service is already linked to another account.""" @oauth_resp_remote_error_handler def mock_handler(resp, remote): raise AlreadyLinkedError(None, None) resp = mock_handler(None, remote) expected_url_args = { "message": "External service is already linked to another account.", "code": 400 } check_response_redirect_url_args(resp, expected_url_args)
def test_authorized_reject(app_rest): """Test a rejected request.""" with app_rest.test_client() as c: c.get(url_for('invenio_oauthclient.rest_login', remote_app='cern')) resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='cern', error='access_denied', error_description='User denied access', state=get_state('cern'))) assert resp.status_code in (301, 302) expected_url_args = { "message": "You rejected the authentication request.", "code": 400, } check_response_redirect_url_args(resp, expected_url_args)
def test_account_setup(app_rest, example_cern_openid_rest, models_fixture): """Test account setup after login.""" with app_rest.test_client() as c: ioc = app_rest.extensions['oauthlib.client'] # Ensure remote apps have been loaded (due to before first request) resp = c.get( url_for('invenio_oauthclient.rest_login', remote_app='cern_openid')) assert resp.status_code == 302 example_response, example_token, example_account_info = \ example_cern_openid_rest mock_response(app_rest.extensions['oauthlib.client'], 'cern_openid', example_token) mock_remote_get(ioc, 'cern_openid', example_response) resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='cern_openid', code='test', state=get_state('cern_openid'))) assert resp.status_code == 302 expected_url_args = { "message": "Successfully authorized.", "code": 200, } check_response_redirect_url_args(resp, expected_url_args) assert len(g.identity.provides) == 3 datastore = app_rest.extensions['invenio-accounts'].datastore user = datastore.find_user(email='*****@*****.**') assert user with app_rest.test_request_context(): resp = disconnect_rest_handler(ioc.remote_apps['cern_openid']) assert resp.status_code >= 300 login_user(user) assert len(g.identity.provides) == 3 disconnect_rest_handler(ioc.remote_apps['cern_openid'])
def test_token_getter_setter(app_rest, monkeypatch): """Test token getter setter.""" # Mock session id monkeypatch.setattr('invenio_oauthclient._compat._create_identifier', lambda: '1234') monkeypatch.setattr( 'invenio_oauthclient.views.client._create_identifier', lambda: '1234') oauth = app_rest.extensions['oauthlib.client'] # Mock user user = MagicMock() user.id = 1 user.get_id = MagicMock(return_value=1) user.is_anonymous = False with app_rest.test_client() as c: login_user_via_session(c, user) # First call login to be redirected res = c.get(url_for('invenio_oauthclient.rest_login', remote_app='full')) assert res.status_code == 302 assert res.location.startswith( oauth.remote_apps['full'].authorize_url ) state = parse_qs(urlparse(res.location).query)['state'][0] # Mock resposen class mock_response(app_rest.extensions['oauthlib.client'], 'full') # Imitate that the user authorized our request in the remote # application. c.get(url_for( 'invenio_oauthclient.rest_authorized', remote_app='full', code='test', state=state, )) # Assert if everything is as it should be. from flask import session as flask_session assert flask_session['oauth_token_full'] == \ ('test_access_token', '') t = RemoteToken.get(1, 'fullid') assert t.remote_account.client_id == 'fullid' assert t.access_token == 'test_access_token' assert RemoteToken.query.count() == 1 # Mock a new authorized request mock_response(app_rest.extensions['oauthlib.client'], 'full', data={ 'access_token': 'new_access_token', 'scope': "", 'token_type': 'bearer' }) c.get(url_for( 'invenio_oauthclient.rest_authorized', remote_app='full', code='test', state=state )) t = RemoteToken.get(1, 'fullid') assert t.access_token == 'new_access_token' assert RemoteToken.query.count() == 1 val = token_getter( app_rest.extensions['oauthlib.client'].remote_apps['full']) assert val == ('new_access_token', '') # Disconnect account res = c.get(url_for( 'invenio_oauthclient.rest_disconnect', remote_app='full', )) assert res.status_code == 302 expected_url_args = { "message": "Successfully disconnected.", "code": 200 } check_response_redirect_url_args(res, expected_url_args) # Assert that remote account have been removed. t = RemoteToken.get(1, 'fullid') assert t is None # TODO: Figure out what is leaving session open & blocked db.session.close()
def test_account_setup(app_rest, example_cern, models_fixture): """Test account setup after login.""" with app_rest.test_client() as c: ioc = app_rest.extensions['oauthlib.client'] # Ensure remote apps have been loaded (due to before first request) resp = c.get( url_for('invenio_oauthclient.rest_login', remote_app='cern')) assert resp.status_code == 302 example_response, example_token, example_account_info = example_cern mock_response(app_rest.extensions['oauthlib.client'], 'cern', example_token) mock_remote_get(ioc, 'cern', example_response) resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='cern', code='test', state=get_state('cern'))) assert resp.status_code == 302 expected_url_args = { "message": "Successfully authorized.", "code": 200, } check_response_redirect_url_args(resp, expected_url_args) assert len(g.identity.provides) == 7 datastore = app_rest.extensions['invenio-accounts'].datastore user = datastore.find_user(email='*****@*****.**') user.password = hash_password("1234") assert user with app_rest.test_request_context(): resp = disconnect_rest_handler(ioc.remote_apps['cern']) assert resp.status_code >= 300 # simulate login (account_info fetch) g.oauth_logged_in_with_remote = ioc.remote_apps['cern'] login_user(user) assert isinstance(g.identity, Identity) assert g.identity.provides == set([ UserNeed(4), UserNeed('*****@*****.**'), RoleNeed('*****@*****.**'), RoleNeed('*****@*****.**'), RoleNeed('*****@*****.**'), RoleNeed('*****@*****.**'), RoleNeed('*****@*****.**'), ]) logout_user() assert isinstance(g.identity, AnonymousIdentity) # NOTE: Wrong role, g.identity.provides = {Need(['id', 4])} read more # https://github.com/inveniosoftware/invenio-access/blob/e28e76d5361a29202b94d498f1968454c24c5c80/tests/test_loaders.py#L47 assert len(g.identity.provides) == 1 assert "cern_resource" not in session assert OAUTHCLIENT_CERN_SESSION_KEY not in session # Login again to test the disconnect handler g.oauth_logged_in_with_remote = ioc.remote_apps['cern'] login_user(user) assert isinstance(g.identity, Identity) assert len(g.identity.provides) == 7 disconnect_rest_handler(ioc.remote_apps['cern'])
def test_authorized_signup_valid_user(app_rest, example_github): """Test authorized callback with sign-up.""" example_email = '*****@*****.**' with app_rest.test_client() as c: # User login with email 'info' with mock.patch('github3.login') as MockLogin: MockLogin.return_value = MockGh(email='*****@*****.**') # Ensure remote apps have been loaded (due to before first # request) resp = c.get( url_for('invenio_oauthclient.rest_login', remote_app='github')) assert resp.status_code == 302 mock_response(app_rest.extensions['oauthlib.client'], 'github', example_github) # User authorized the requests and is redirect back resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='github', code='test', state=_get_state())) assert resp.status_code == 302 expected_url_args = { "message": "Successfully authorized.", "code": 200, } check_response_redirect_url_args(resp, expected_url_args) # Assert database state (Sign-up complete) user = User.query.filter_by(email=example_email).one() remote = RemoteAccount.query.filter_by(user_id=user.id).one() RemoteToken.query.filter_by(id_remote_account=remote.id).one() assert user.active # Disconnect link resp = c.get( url_for('invenio_oauthclient.rest_disconnect', remote_app='github')) assert resp.status_code == 302 # User exists user = User.query.filter_by(email=example_email).one() assert 0 == UserIdentity.query.filter_by(method='orcid', id_user=user.id, id='githubuser').count() assert RemoteAccount.query.filter_by(user_id=user.id).count() == 0 assert RemoteToken.query.count() == 0 # User login with another email ('info2') with mock.patch('github3.login') as MockLogin: MockLogin.return_value = MockGh(email='*****@*****.**') # User authorized the requests and is redirect back resp = c.get( url_for('invenio_oauthclient.rest_authorized', remote_app='github', code='test', state=_get_state())) assert resp.status_code == 302 check_response_redirect_url_args(resp, expected_url_args) # check that exist only one account user = User.query.filter_by(email=example_email).one() assert user.email == example_email