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 create_account(external_id, email, username=None, dn=''): """Create a user capable of logging in with ProxyIDP.""" click.secho("Creating account for {}".format(external_id), fg="yellow") account_info = dict(user=dict(email=email, profile=dict( username=username or external_id.split('@')[0], displayname=dn, full_name=dn, )), external_id=external_id, external_method='ProxyIDP') user = oauth_get_user( client_id=None, account_info=account_info, access_token=None, ) if user: click.secho("Account with this e-mail already exists", fg="red") return user: User = register_account(account_info) if user: db.session.commit() click.secho("Successfully created user {} (ID: {})".format( user.email, user.id), fg="green") else: click.secho("Failed to create user", fg="red")
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 _register_user(name, email, orcid, token): """Add a token to the user, creating the user if doesn't exist. There are multiple possible scenarios: - user exists, has ORCID and token already linked - user exists and has their ORCID linked, but no token is associated - user exists, but doesn't have the ORCID identifier linked - user doesn't exist at all In all the above scenarios this will create the missing parts. Args: name (string): user's name email (string): user's email address orcid (string): user's ORCID identifier token (string): OAUTH authorization token """ # Try to find an existing user entry user_by_orcid = oauth_get_user(orcid) user_by_email = oauth_get_user(None, { 'user': { 'email': email } }) # Make the user if didn't find existing one if not user_by_email and not user_by_orcid: user = User() user.email = email with db.session.begin_nested(): db.session.add(user) else: user = user_by_orcid or user_by_email _link_user_and_token(user, name, orcid, token)
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 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(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 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'])