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_utilities(models_fixture): """Test utilities.""" app = models_fixture datastore = app.extensions['invenio-accounts'].datastore assert obj_or_import_string('invenio_oauthclient.errors') # User existing_email = '*****@*****.**' user = datastore.find_user(email=existing_email) # Authenticate assert not _get_external_id({}) assert not oauth_authenticate('dev', user, require_existing_link=True) _security.confirmable = True _security.login_without_confirmation = False user.confirmed_at = None assert not oauth_authenticate('dev', user) # Tokens t = RemoteToken.create(user.id, 'dev', 'mytoken', 'mysecret') assert \ RemoteToken.get(user.id, 'dev', access_token='mytoken') == \ RemoteToken.get_by_token('dev', 'mytoken') assert oauth_get_user('dev', access_token=t.access_token) == user assert \ oauth_get_user('dev', account_info={ 'user': { 'email': existing_email } }) == user # Link user to external id external_id = {'id': '123', 'method': 'test_method'} oauth_link_external_id(user, external_id) with pytest.raises(AlreadyLinkedError): oauth_link_external_id(user, external_id) assert oauth_get_user('dev', account_info={ 'external_id': external_id['id'], 'external_method': external_id['method'] }) == user # Cleanup oauth_unlink_external_id(external_id) acc = RemoteAccount.get(user.id, 'dev') acc.delete()
def test_token_getter(remote, models_fixture, app): """Test token getter on response from OAuth server.""" datastore = app.extensions['invenio-accounts'].datastore existing_email = '*****@*****.**' user = datastore.find_user(email=existing_email) # Missing RemoteToken oauth_authenticate('dev', user) assert not token_getter(remote) # Populated RemoteToken RemoteToken.create(user.id, 'testkey', 'mytoken', 'mysecret') oauth_authenticate('dev', user) assert token_getter(remote) == ('mytoken', 'mysecret')
def test_token_getter(remote, models_fixture): """Test token getter on response from OAuth server.""" app = models_fixture datastore = app.extensions['invenio-accounts'].datastore existing_email = '*****@*****.**' user = datastore.find_user(email=existing_email) # Missing RemoteToken oauth_authenticate('dev', user) assert not token_getter(remote) # Populated RemoteToken RemoteToken.create(user.id, 'testkey', 'mytoken', 'mysecret') oauth_authenticate('dev', user) assert token_getter(remote) == ('mytoken', 'mysecret')
def test_utilities(models_fixture): """Test utilities.""" app = models_fixture datastore = app.extensions['invenio-accounts'].datastore assert obj_or_import_string('invenio_oauthclient.errors') # User existing_email = '*****@*****.**' user = datastore.find_user(email=existing_email) # Authenticate assert not _get_external_id({}) assert not oauth_authenticate('dev', user, require_existing_link=True) _security.confirmable = True _security.login_without_confirmation = False user.confirmed_at = None assert not oauth_authenticate('dev', user) # Tokens t = RemoteToken.create(user.id, 'dev', 'mytoken', 'mysecret') assert \ RemoteToken.get(user.id, 'dev', access_token='mytoken') == \ RemoteToken.get_by_token('dev', 'mytoken') assert oauth_get_user('dev', access_token=t.access_token) == user assert \ oauth_get_user('dev', account_info={'user': {'email': existing_email}}) == user # Link user to external id external_id = {'id': '123', 'method': 'test_method'} oauth_link_external_id(user, external_id) with pytest.raises(AlreadyLinkedError): oauth_link_external_id(user, external_id) assert oauth_get_user('dev', account_info={ 'external_id': external_id['id'], 'external_method': external_id['method'] }) == user # Cleanup oauth_unlink_external_id(external_id) acc = RemoteAccount.get(user.id, 'dev') acc.delete()
def authorized_signup_handler(resp, remote, *args, **kwargs): """Handle sign-in/up functionality. This is needed as we don't use Flask Forms (for now), thus the default function would fail. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote.name) + '_autoregister', None) # Store token in session # ---------------------- # Set token in session - token object only returned if # current_user.is_autenticated(). token = response_token_setter(remote, resp) handlers = current_oauthclient.signup_handlers[remote.name] # Sign-in/up user # --------------- if not current_user.is_authenticated: account_info = handlers['info'](resp) account_info_received.send(remote, token=token, response=resp, account_info=account_info) user = oauth_get_user( remote.consumer_key, account_info=account_info, access_token=token_getter(remote)[0], ) if user is None: # Auto sign-up if user not found user = oauth_register(account_info) # Authenticate user if not oauth_authenticate( remote.consumer_key, user, require_existing_link=False, remember=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('remember', False)): return current_app.login_manager.unauthorized() # Link account # ------------ # Need to store token in database instead of only the session when # called first time. token = response_token_setter(remote, resp) # Setup account # ------------- if not token.remote_account.extra_data: account_setup = handlers['setup'](token, resp) account_setup_received.send(remote, token=token, response=resp, account_setup=account_setup) return redirect('/')
def authorized_signup_handler(auth, remote=None, *args, **kwargs): """ Handle sign-in/up functionality. Checks if user is already registered. If not registered, the function registers a new user and authenticates the new user. If there already exists a user object in the database, the user is only authenticated and logged in. :param auth: (onelogin.saml2.auth) Auth object. :param remote: (str) Identity provider key. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote) + '_autoregister', None) # Sign-in/up user # --------------- if current_user.is_authenticated: logout_user() account_info = get_account_info(auth.get_attributes(), remote) user = oauth_get_user(remote, account_info=account_info) if user is None: # Auto sign-up if user not found form = create_csrf_disabled_registrationform() # Fill form with user data form = fill_form(form, account_info['user']) # Try to register user user = oauth_register(form) # if registration fails ... if user is None: return current_app.login_manager.unauthorized() # Authenticate user if not oauth_authenticate(remote, user, require_existing_link=False): return current_app.login_manager.unauthorized() # create external id link try: oauth_link_external_id( user, dict(id=account_info['external_id'], method=remote)) db.session.commit() except AlreadyLinkedError: pass # Redirect to next next_url = get_session_next_url(remote) if next_url: return redirect(next_url) return redirect(current_app.config['SECURITY_POST_LOGIN_VIEW'])
def test_utilities(models_fixture): """Test utilities.""" app = models_fixture datastore = app.extensions["invenio-accounts"].datastore assert obj_or_import_string("invenio_oauthclient.errors") # User existing_email = "*****@*****.**" user = datastore.find_user(email=existing_email) # Authenticate assert not _get_external_id({}) assert not oauth_authenticate("dev", user, require_existing_link=True) _security.confirmable = True _security.login_without_confirmation = False user.confirmed_at = None assert not oauth_authenticate("dev", user) # Tokens t = RemoteToken.create(user.id, "dev", "mytoken", "mysecret") assert RemoteToken.get(user.id, "dev", access_token="mytoken") == RemoteToken.get_by_token("dev", "mytoken") assert oauth_get_user("dev", access_token=t.access_token) == user assert oauth_get_user("dev", account_info={"user": {"email": existing_email}}) == user # Link user to external id external_id = {"id": "123", "method": "test_method"} oauth_link_external_id(user, external_id) with pytest.raises(AlreadyLinkedError): oauth_link_external_id(user, external_id) assert ( oauth_get_user("dev", account_info={"external_id": external_id["id"], "external_method": external_id["method"]}) == user ) # Cleanup oauth_unlink_external_id(external_id) acc = RemoteAccount.get(user.id, "dev") acc.delete()
def authorized_signup_handler(resp, remote, *args, **kwargs): """Handle sign-in/up functionality. This is needed as we don't use Flask Forms (for now), thus the default function would fail. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote.name) + '_autoregister', None) # Store token in session # ---------------------- # Set token in session - token object only returned if # current_user.is_autenticated(). token = response_token_setter(remote, resp) handlers = current_oauthclient.signup_handlers[remote.name] # Sign-in/up user # --------------- if not current_user.is_authenticated: account_info = handlers['info'](resp) account_info_received.send( remote, token=token, response=resp, account_info=account_info ) user = oauth_get_user( remote.consumer_key, account_info=account_info, access_token=token_getter(remote)[0], ) if user is None: # Auto sign-up if user not found user = oauth_register(account_info) # Authenticate user if not oauth_authenticate(remote.consumer_key, user, require_existing_link=False): return current_app.login_manager.unauthorized() # Link account # ------------ # Need to store token in database instead of only the session when # called first time. token = response_token_setter(remote, resp) # Setup account # ------------- if not token.remote_account.extra_data: account_setup = handlers['setup'](token, resp) account_setup_received.send( remote, token=token, response=resp, account_setup=account_setup ) return redirect('/')
def test_authorized_signup_handler(remote, models_fixture): """Test authorized signup handler.""" datastore = models_fixture.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 resp = authorized_signup_handler(example_response, remote) check_redirect_location(resp, next_url)
def authorized_signup_handler(auth, remote=None, *args, **kwargs): """ Handle sign-in/up functionality. Checks if user is already registered. If not registered, the function registers a new user and authenticates the new user. If there already exists a user object in the database, the user is only authenticated and logged in. :param remote: The remote application. :param resp: The response. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote) + '_autoregister', None) # Sign-in/up user # --------------- if not current_user.is_authenticated: account_info = get_account_info(auth.get_attributes(), remote) user = oauth_get_user(remote, account_info=account_info) if user is None: # Auto sign-up if user not found form = create_csrf_disabled_registrationform() form = fill_form(form, account_info['user']) user = oauth_register(form) # if registration fails ... if user is None: return current_app.login_manager.unauthorized() # Authenticate user if not oauth_authenticate(remote, user, require_existing_link=False): return current_app.login_manager.unauthorized() db.session.commit() # Redirect to next next_url = get_session_next_url(remote) if next_url: return redirect(next_url) return redirect(current_app.config['SECURITY_POST_LOGIN_VIEW'])
def signup_handler(remote, *args, **kwargs): """Handle extra signup information. :param remote: The remote application. :returns: Redirect response or the template rendered. """ # User already authenticated so move on if current_user.is_authenticated: return redirect('/') # Retrieve token from session oauth_token = token_getter(remote) if not oauth_token: return redirect('/') session_prefix = token_session_key(remote.name) # Test to see if this is coming from on authorized request if not session.get(session_prefix + '_autoregister', False): return redirect(url_for('.login', remote_app=remote.name)) form = create_registrationform(request.form) if form.validate_on_submit(): account_info = session.get(session_prefix + '_account_info') response = session.get(session_prefix + '_response') # Register user user = oauth_register(form) if user is None: raise OAuthError('Could not create user.', remote) # Remove session key session.pop(session_prefix + '_autoregister', None) # Link account and set session data token = token_setter(remote, oauth_token[0], secret=oauth_token[1], user=user) handlers = current_oauthclient.signup_handlers[remote.name] if token is None: raise OAuthError('Could not create token for user.', remote) if not token.remote_account.extra_data: account_setup = handlers['setup'](token, response) account_setup_received.send(remote, token=token, response=response, account_setup=account_setup) # Registration has been finished db.session.commit() account_setup_committed.send(remote, token=token) else: # Registration has been finished db.session.commit() # Authenticate the user if not oauth_authenticate( remote.consumer_key, user, require_existing_link=False, remember=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('remember', False)): # Redirect the user after registration (which doesn't include the # activation), waiting for user to confirm his email. return redirect('/') # Remove account info from session session.pop(session_prefix + '_account_info', None) session.pop(session_prefix + '_response', None) # Redirect to next next_url = get_session_next_url(remote.name) if next_url: return redirect(next_url) else: return redirect('/') # Pre-fill form account_info = session.get(session_prefix + '_account_info') if not form.is_submitted(): form = fill_form(form, account_info['user']) return render_template( current_app.config['OAUTHCLIENT_SIGNUP_TEMPLATE'], form=form, remote=remote, app_title=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('title', ''), app_description=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('description', ''), app_icon=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('icon', None), )
def authorized_signup_handler(resp, remote, *args, **kwargs): """Handle sign-in/up functionality. :param remote: The remote application. :param resp: The response. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote.name) + '_autoregister', None) # Store token in session # ---------------------- # Set token in session - token object only returned if # current_user.is_autenticated(). token = response_token_setter(remote, resp) handlers = current_oauthclient.signup_handlers[remote.name] # Sign-in/up user # --------------- if not current_user.is_authenticated: account_info = handlers['info'](resp) account_info_received.send(remote, token=token, response=resp, account_info=account_info) user = oauth_get_user( remote.consumer_key, account_info=account_info, access_token=token_getter(remote)[0], ) if user is None: # Auto sign-up if user not found form = create_csrf_disabled_registrationform() form = fill_form(form, account_info['user']) user = oauth_register(form) # if registration fails ... if user is None: # requires extra information session[token_session_key(remote.name) + '_autoregister'] = True session[token_session_key(remote.name) + '_account_info'] = account_info session[token_session_key(remote.name) + '_response'] = resp db.session.commit() return redirect('/') # Authenticate user if not oauth_authenticate( remote.consumer_key, user, require_existing_link=False): return current_app.login_manager.unauthorized() # Link account # ------------ # Need to store token in database instead of only the session when # called first time. token = response_token_setter(remote, resp) # Setup account # ------------- if not token.remote_account.extra_data: account_setup = handlers['setup'](token, resp) account_setup_received.send(remote, token=token, response=resp, account_setup=account_setup) db.session.commit() account_setup_committed.send(remote, token=token) else: db.session.commit() # Redirect to next next_url = get_session_next_url(remote.name) if next_url: return redirect(next_url) return redirect('/')
def authorized_signup_handler(resp, remote, *args, **kwargs): """Handle sign-in/up functionality. :param remote: The remote application. :param resp: The response. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote.name) + '_autoregister', None) # Store token in session # ---------------------- # Set token in session - token object only returned if # current_user.is_autenticated(). token = response_token_setter(remote, resp) handlers = current_oauthclient.signup_handlers[remote.name] # Sign-in/up user # --------------- if not current_user.is_authenticated: account_info = handlers['info'](resp) account_info_received.send(remote, token=token, response=resp, account_info=account_info) user = oauth_get_user( remote.consumer_key, account_info=account_info, access_token=token_getter(remote)[0], ) if user is None: # Auto sign-up if user not found form = create_csrf_disabled_registrationform() form = fill_form(form, account_info['user']) user = oauth_register(form) # if registration fails ... if user is None: # requires extra information session[token_session_key(remote.name) + '_autoregister'] = True session[token_session_key(remote.name) + '_account_info'] = account_info session[token_session_key(remote.name) + '_response'] = resp db.session.commit() return render_template( current_app.config['AUTHENTICATION_POPUP_TEMPLATE'], msg='Registration to the service failed.'), 400 # Authenticate user if not oauth_authenticate( remote.consumer_key, user, require_existing_link=False): return render_template( current_app. config['AUTHENTICATION_POPUP__NO_REDIRECT_TEMPLATE'], msg='Error: Unauthorized user.'), 401 # Link account # ------------ # Need to store token in database instead of only the session when # called first time. token = response_token_setter(remote, resp) # Setup account # ------------- if not token.remote_account.extra_data: account_setup = handlers['setup'](token, resp) account_setup_received.send(remote, token=token, response=resp, account_setup=account_setup) db.session.commit() account_setup_committed.send(remote, token=token) else: db.session.commit() return render_template(current_app.config['AUTHENTICATION_POPUP_TEMPLATE'], msg='Account linked successfully.'), 200
def signup_handler(remote, *args, **kwargs): """Handle extra signup information. :param remote: The remote application. :returns: Redirect response or the template rendered. """ # User already authenticated so move on if current_user.is_authenticated: return redirect('/') # Retrieve token from session oauth_token = token_getter(remote) if not oauth_token: return redirect('/') session_prefix = token_session_key(remote.name) # Test to see if this is coming from on authorized request if not session.get(session_prefix + '_autoregister', False): return redirect(url_for('.login', remote_app=remote.name)) form = create_registrationform(request.form) if form.validate_on_submit(): account_info = session.get(session_prefix + '_account_info') response = session.get(session_prefix + '_response') # Register user user = oauth_register(form) if user is None: raise OAuthError('Could not create user.', remote) # Remove session key session.pop(session_prefix + '_autoregister', None) # Link account and set session data token = token_setter(remote, oauth_token[0], secret=oauth_token[1], user=user) handlers = current_oauthclient.signup_handlers[remote.name] if token is None: raise OAuthError('Could not create token for user.', remote) if not token.remote_account.extra_data: account_setup = handlers['setup'](token, response) account_setup_received.send( remote, token=token, response=response, account_setup=account_setup ) # Registration has been finished db.session.commit() account_setup_committed.send(remote, token=token) else: # Registration has been finished db.session.commit() # Authenticate the user if not oauth_authenticate(remote.consumer_key, user, require_existing_link=False, remember=current_app.config[ 'OAUTHCLIENT_REMOTE_APPS'] [remote.name].get('remember', False)): # Redirect the user after registration (which doesn't include the # activation), waiting for user to confirm his email. return redirect('/') # Remove account info from session session.pop(session_prefix + '_account_info', None) session.pop(session_prefix + '_response', None) # Redirect to next next_url = get_session_next_url(remote.name) if next_url: return redirect(next_url) else: return redirect('/') # Pre-fill form account_info = session.get(session_prefix + '_account_info') if not form.is_submitted(): form = fill_form(form, account_info['user']) return render_template( current_app.config['OAUTHCLIENT_SIGNUP_TEMPLATE'], form=form, remote=remote, app_title=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('title', ''), app_description=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('description', ''), app_icon=current_app.config['OAUTHCLIENT_REMOTE_APPS'][ remote.name].get('icon', None), )
def authorized_signup_handler(resp, remote, *args, **kwargs): """Handle sign-in/up functionality. :param remote: The remote application. :param resp: The response. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote.name) + '_autoregister', None) # Store token in session # ---------------------- # Set token in session - token object only returned if # current_user.is_autenticated(). token = response_token_setter(remote, resp) handlers = current_oauthclient.signup_handlers[remote.name] # Sign-in/up user # --------------- if not current_user.is_authenticated: account_info = handlers['info'](resp) account_info_received.send( remote, token=token, response=resp, account_info=account_info ) user = oauth_get_user( remote.consumer_key, account_info=account_info, access_token=token_getter(remote)[0], ) if user is None: # Auto sign-up if user not found form = create_csrf_disabled_registrationform() form = fill_form( form, account_info['user'] ) user = oauth_register(form) # if registration fails ... if user is None: # requires extra information session[ token_session_key(remote.name) + '_autoregister'] = True session[token_session_key(remote.name) + '_account_info'] = account_info session[token_session_key(remote.name) + '_response'] = resp db.session.commit() return redirect('/') # Authenticate user if not oauth_authenticate(remote.consumer_key, user, require_existing_link=False): return current_app.login_manager.unauthorized() # Link account # ------------ # Need to store token in database instead of only the session when # called first time. token = response_token_setter(remote, resp) # Setup account # ------------- if not token.remote_account.extra_data: account_setup = handlers['setup'](token, resp) account_setup_received.send( remote, token=token, response=resp, account_setup=account_setup ) db.session.commit() account_setup_committed.send(remote, token=token) else: db.session.commit() # Redirect to next next_url = get_session_next_url(remote.name) if next_url: return redirect(next_url) return redirect('/')
def authorized_handler(self, resp, remote, *args, **kwargs): """Handle sign-in functionality. :param remote: The remote application. :param resp: The response. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote.name) + '_autoregister', None) # Store token in session # ---------------------- # Set token in session - token object only returned if # current_user.is_autenticated(). token = response_token_setter(remote, resp) handlers = current_oauthclient.signup_handlers[remote.name] # Sign-in user # --------------- if not current_user.is_authenticated: account_info = handlers['info'](resp) account_info_received.send(remote, token=token, response=resp, account_info=account_info) user = oauth_get_user( remote.consumer_key, account_info=account_info, access_token=token_getter(remote)[0], ) # Make sure that external identity either matches # or is not yet created (gets created on first oidc login) extid = _get_external_id(account_info) user_identity: UserIdentity = UserIdentity.query.filter_by( id=extid['id'], method=extid['method']).first() if user_identity and user_identity.id != extid['id']: abort(401) if user is None: abort(403) # Authenticate user if not oauth_authenticate( remote.consumer_key, user, require_existing_link=False): return current_app.login_manager.unauthorized() # Link account # ------------ # Need to store token in database instead of only the session when # called first time. token = response_token_setter(remote, resp) # Setup account # ------------- if not token.remote_account.extra_data: account_setup = handlers['setup'](token, resp) account_setup_received.send(remote, token=token, response=resp, account_setup=account_setup) db.session.commit() account_setup_committed.send(remote, token=token) else: db.session.commit() # Redirect to next next_url = get_session_next_url(remote.name) if next_url: return redirect(next_url) return redirect(url_for('invenio_oauthclient_settings.index'))
def authorized_signup_handler(auth, remote=None, *args, **kwargs): """ Handle sign-in/up functionality. Checks if user is already registered. If not registered, the function registers a new user and authenticates the new user. If there already exists a user object in the database, the user is only authenticated and logged in. :param auth: (onelogin.saml2.auth) Auth object. :param remote: (str) Identity provider key. :returns: Redirect response. """ # Remove any previously stored auto register session key session.pop(token_session_key(remote) + '_autoregister', None) # Sign-in/up user # --------------- if current_user.is_authenticated: logout_user() account_info = get_account_info(auth.get_attributes(), remote) user = None # Pre-check done to use a case insensitive comparison because this is not # done in invenio --> https://github.com/inveniosoftware/invenio-oauthclient/blob/master/invenio_oauthclient/utils.py#L82 # nopep8 if account_info.get('user', {}).get('email'): user = User.query.filter( func.lower(User.email) == func.lower(account_info['user'] ['email'])).one_or_none() if user is None: user = oauth_get_user(remote, account_info=account_info) if user is None: # Auto sign-up if user not found form = create_csrf_disabled_registrationform() # Fill form with user data form = fill_form(form, account_info['user']) # Try to register user user = oauth_register(form) # if registration fails ... if user is None: return current_app.login_manager.unauthorized() # Authenticate user if not oauth_authenticate(remote, user, require_existing_link=False): return current_app.login_manager.unauthorized() # create external id link try: oauth_link_external_id( user, dict(id=account_info['external_id'], method=remote)) db.session.commit() except AlreadyLinkedError: pass # Redirect to next next_url = get_session_next_url(remote) if next_url: return redirect(next_url) return redirect(current_app.config['SECURITY_POST_LOGIN_VIEW'])