def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. This is a modified version of :ref:`invenio_oauthclient.contrib.orcid.account_setup` that stores additional metadata. :param remote: The remote application. :param token: The token value. :param resp: The response. """ with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get('orcid') full_name = resp.get('name') # Set ORCID in extra_data. token.remote_account.extra_data = { 'orcid': orcid, 'full_name': full_name, 'allow_push': current_app.config.get('ORCID_ALLOW_PUSH_DEFAULT', False) } user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, {'id': orcid, 'method': 'orcid'})
def create_user(orcid, email, name, consumer_key, token=None, allow_push=False): user = User() user.email = email with db.session.begin_nested(): db.session.add(user) oauth_link_external_id(user, { 'id': orcid, 'method': 'orcid' }) if token: with db.session.begin_nested(): db.session.add( RemoteToken.create( user_id=user.id, client_id=consumer_key, token=token, secret=None, extra_data={ 'orcid': orcid, 'full_name': name, 'allow_push': allow_push, } ) )
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. This is a modified version of :ref:`invenio_oauthclient.contrib.orcid.account_setup` that stores additional metadata. :param remote: The remote application. :param token: The token value. :param resp: The response. """ with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get("orcid") full_name = resp.get("name") # Set ORCID in extra_data. token.remote_account.extra_data = { "orcid": orcid, "full_name": full_name, "allow_push": current_app.config.get("ORCID_ALLOW_PUSH_DEFAULT", False), } user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, {"id": orcid, "method": "orcid"})
def create_user(orcid, email, name, consumer_key, token=None, allow_push=False): user = User() user.email = email with db.session.begin_nested(): db.session.add(user) oauth_link_external_id(user, {'id': orcid, 'method': 'orcid'}) if token: with db.session.begin_nested(): db.session.add( RemoteToken.create(user_id=user.id, client_id=consumer_key, token=token, secret=None, extra_data={ 'orcid': orcid, 'full_name': name, 'allow_push': allow_push, }))
def create_user(orcid, email, name, consumer_key, token=None, allow_push=False): user = User() user.email = email with db.session.begin_nested(): db.session.add(user) oauth_link_external_id(user, {"id": orcid, "method": "orcid"}) if token: with db.session.begin_nested(): db.session.add( RemoteToken.create( user_id=user.id, client_id=consumer_key, token=token, secret=None, extra_data={ "orcid": orcid, "full_name": name, "allow_push": allow_push, }, ))
def _link_user_and_token(user, name, orcid, token): """Create a link between a user and token, if possible. Args: user (invenio_oauthclient.models.User): an existing user object to connect the token to orcid (string): user's ORCID identifier token (string): OAUTH token for the user """ try: # Link user and ORCID oauth_link_external_id(user, { 'id': orcid, 'method': 'orcid' }) except AlreadyLinkedError: # User already has their ORCID linked pass # Is there already a token associated with this ORCID identifier? if RemoteToken.query.join(RemoteAccount).join(User).join(UserIdentity).filter(UserIdentity.id == orcid).count(): return # If not, create and put the token entry with db.session.begin_nested(): db.session.add(RemoteToken.create( user_id=user.id, client_id=get_value(current_app.config, 'ORCID_APP_CREDENTIALS.consumer_key'), token=token, secret=None, extra_data={ 'orcid': orcid, 'full_name': name, 'allow_push': True, } ))
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 _link_user_and_token(user, name, orcid, token): """Create a link between a user and token, if possible. Args: user (invenio_oauthclient.models.User): an existing user object to connect the token to orcid (string): user's ORCID identifier token (string): OAUTH token for the user Returns: str: the ORCID associated with the new token if we created one, or the ORCID associated with the token whose ``allow_push`` flag changed state. """ result = None try: # Link user and ORCID oauth_link_external_id(user, { 'id': orcid, 'method': 'orcid' }) except AlreadyLinkedError: # User already has their ORCID linked pass # Check whether there are already tokens associated with this # ORCID identifier. tokens = RemoteToken.query.join(RemoteAccount).join(User)\ .join(UserIdentity).filter(UserIdentity.id == orcid).all() if tokens: # Force the allow_push. with db.session.begin_nested(): for token in tokens: if not token.remote_account.extra_data['allow_push']: result = orcid token.remote_account.extra_data['allow_push'] = True else: # If not, create and put the token entry with db.session.begin_nested(): result = orcid RemoteToken.create( user_id=user.id, client_id=get_value(current_app.config, 'ORCID_APP_CREDENTIALS.consumer_key'), token=token, secret=None, extra_data={ 'orcid': orcid, 'full_name': name, 'allow_push': True, } ) return result
def account_setup(remote, token=None, response=None, account_setup=None): """Setup user account.""" gh = GitHubAPI(user_id=token.remote_account.user_id) with db.session.begin_nested(): gh.init_account() # Create user <-> external id link. oauth_link_external_id( token.remote_account.user, dict(id=str(gh.account.extra_data['id']), method="github") )
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get("orcid") # Set ORCID in extra_data. token.remote_account.extra_data = {"orcid": orcid} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=orcid, method="orcid"))
def account_setup(remote, token=None, response=None, account_setup=None): """Setup user account.""" gh = GitHubAPI(user_id=token.remote_account.user_id) with db.session.begin_nested(): gh.init_account() # Create user <-> external id link. oauth_link_external_id( token.remote_account.user, dict(id=str(gh.account.extra_data['id']), method="github") )
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" gh = github3.login(token=resp['access_token']) with db.session.begin_nested(): me = gh.me() token.remote_account.extra_data = {"login": me.login, "id": me.id} # Create user <-> external id link. oauth_link_external_id( token.remote_account.user, dict( id=str(me.id), method="github") )
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 account_setup_handler(remote, token, resp): with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get("orcid") full_name = resp.get("name") # Set ORCID in extra_data. token.remote_account.extra_data = { "orcid": orcid, "full_name": full_name, "allow_push": current_app.config.get("ORCID_ALLOW_PUSH_DEFAULT", False), } user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, {"id": orcid, "method": "orcid"})
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" from invenio_oauthclient.utils import oauth_link_external_id from invenio_db import db with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get("orcid") # Set ORCID in extra_data. token.remote_account.extra_data = {"orcid": orcid} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=orcid, method="orcid"))
def setup_handler(remote, token, resp): """Perform additional setup after the user has been logged in.""" user_info = get_user_info(remote, resp) with db.session.begin_nested(): # fetch the user's Keycloak ID and set it in extra_data keycloak_id = user_info["sub"] token.remote_account.extra_data = { "keycloak_id": keycloak_id, } user = token.remote_account.user external_id = {"id": keycloak_id, "method": remote.name} # link account with external Keycloak ID oauth_link_external_id(user, external_id)
def oauth_register(account_info): """Register new OAuth users. This is needed as we don't use Flask Forms (for now), thus the default function would fail. """ from flask_security.registerable import register_user user_data = account_info.get("user") user_data['password'] = '' user = register_user(**user_data) # Create user <-> external id link. oauth_link_external_id( user, dict(id=str(account_info.get('external_id')), method=account_info.get('external_method'))) return user
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ gh = github3.login(token=resp['access_token']) with db.session.begin_nested(): me = gh.me() token.remote_account.extra_data = {'login': me.login, 'id': me.id} # Create user <-> external id link. oauth_link_external_id(token.remote_account.user, dict(id=str(me.id), method='github'))
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get('orcid') # Set ORCID in extra_data. token.remote_account.extra_data = {'orcid': orcid} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=orcid, method='orcid'))
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 account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ with db.session.begin_nested(): # Retrieve ORCID from response. orcid = resp.get('orcid') # Set ORCID in extra_data. token.remote_account.extra_data = {'orcid': orcid} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=orcid, method='orcid'))
def oauth_register(account_info): """Register new OAuth users. This is needed as we don't use Flask Forms (for now), thus the default function would fail. """ from flask_security.registerable import register_user user_data = account_info.get("user") user_data['password'] = '' user = register_user(**user_data) # Create user <-> external id link. oauth_link_external_id( user, dict( id=str(account_info.get('external_id')), method=account_info.get('external_method') ) ) return user
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" resource = get_resource(remote) external_id = resource['uidNumber'][0] # Set CERN person ID in extra_data. token.remote_account.extra_data = { 'external_id': external_id, } groups = account_groups(token.remote_account, resource) assert not isinstance(g.identity, AnonymousIdentity) extend_identity(g.identity, groups) user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=external_id, method='cern'))
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ info = get_user_info(remote) user_id = get_user_id(remote, info['preferred_username']) with db.session.begin_nested(): token.remote_account.extra_data = { 'login': info['username'], 'id': user_id } # Create user <-> external id link. oauth_link_external_id(token.remote_account.user, dict(id=user_id, method=GLOBUS_EXTERNAL_METHOD))
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" resource = get_resource(remote, resp) with db.session.begin_nested(): person_id = resource.get("cern_person_id") external_id = resource.get("cern_upn") # Set CERN person ID in extra_data. token.remote_account.extra_data = {"external_id": external_id} roles = account_roles_and_extra_data(token.remote_account, resource) assert not isinstance(g.identity, AnonymousIdentity) extend_identity(g.identity, roles) user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=external_id, method="cern_openid"))
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" resource = get_resource(remote) with db.session.begin_nested(): external_id = resource['PersonID'][0] # Set CERN person ID in extra_data. token.remote_account.extra_data = { 'external_id': external_id, } groups = account_groups(token.remote_account, resource) assert not isinstance(g.identity, AnonymousIdentity) extend_identity(g.identity, groups) user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=external_id, method='cern'))
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ gh = github3.login(token=resp['access_token']) with db.session.begin_nested(): me = gh.me() token.remote_account.extra_data = {'login': me.login, 'id': me.id} # Create user <-> external id link. oauth_link_external_id( token.remote_account.user, dict( id=str(me.id), method='github') )
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 account_setup(self, remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ user_info = self.get_userinfo(remote) user_id = self.get_user_id(remote, email=user_info.email) with db.session.begin_nested(): # Put userinfo in extra_data. extra_data = user_info.__dict__ extra_data['external_id'] = user_id extra_data['external_method'] = self.name token.remote_account.extra_data = extra_data user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, {'id': user_id, 'method': self.name})
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: (str) The token value. :param resp: (dict) Response returned from api. """ # Get ORCID record detail record = get_orcid_record(resp.get('orcid'), resp.get('access_token')) with db.session.begin_nested(): # Retrieve ORCID from response. orcid_id = resp.get('orcid') # Set ORCID in extra_data. token.remote_account.extra_data = {'orcid': orcid_id, 'record': record} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, {'id': orcid_id, 'method': 'orcid'})
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" from invenio_oauthclient.utils import oauth_link_external_id from invenio.ext.sqlalchemy import db # Retrieve ORCID from response. orcid = resp.get("orcid") # Set ORCID in extra_data. token.remote_account.extra_data = {"orcid": orcid} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=orcid, method="orcid")) # Fill user full name if not already set if user and not any([user.given_names, user.family_name]): # Query ORCID to get the real name response = remote.get("{0}/orcid-bio".format(orcid), headers={'Accept': 'application/orcid+json'}, content_type="application/json") if response.status == 200: try: name = response.data["orcid-profile"]["orcid-bio"][ "personal-details"] user.given_names = name["given-names"]["value"] user.family_name = name["family-name"]["value"] except KeyError: current_app.logger.exception( "Unexpected return format from ORCID: {0}".format( repr(response.data))) return db.session.add(user) # Refresh user cache current_user.reload()
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in.""" from invenio_oauthclient.utils import oauth_link_external_id from invenio_ext.sqlalchemy import db # Retrieve ORCID from response. orcid = resp.get("orcid") # Set ORCID in extra_data. token.remote_account.extra_data = {"orcid": orcid} user = token.remote_account.user # Create user <-> external id link. oauth_link_external_id(user, dict(id=orcid, method="orcid")) # Fill user full name if not already set if user and not any([user.given_names, user.family_name]): # Query ORCID to get the real name response = remote.get("{0}/orcid-bio".format(orcid), headers={'Accept': 'application/orcid+json'}, content_type="application/json") if response.status == 200: try: name = response.data["orcid-profile"]["orcid-bio"][ "personal-details"] user.given_names = name["given-names"]["value"] user.family_name = name["family-name"]["value"] except KeyError: current_app.logger.exception( "Unexpected return format from ORCID: {0}".format( repr(response.data))) return db.session.add(user) # Refresh user cache current_user.reload()
def account_setup(remote, token, resp): """Perform additional setup after user have been logged in. :param remote: The remote application. :param token: The token value. :param resp: The response. """ user_info = jwt.decode( resp['id_token'], **current_app.config.get('OAUTHCLIENT_OPENAIRE_AAI_JWT_DECODE_PARAMS', OAUTHCLIENT_OPENAIRE_AAI_JWT_DECODE_PARAMS)) openaire_id = user_info['sub'] with db.session.begin_nested(): user = token.remote_account.user # Set extra data so that we mark that the setup is done. token.remote_account.extra_data = {'id': openaire_id} # Create user <-> external id link. oauth_link_external_id(user, { 'id': openaire_id, 'method': 'openaire_aai' })
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'])
def _link_user_and_token(user, name, orcid, access_token): """Create a link between a user and token, if possible. Args: user (invenio_oauthclient.models.User): an existing user object to connect the token to orcid (string): user's ORCID identifier access_token (string): OAUTH token for the user Returns: str: the ORCID associated with the token newly created/enabled. """ try: # Link user and ORCID oauth_link_external_id(user, {"id": orcid, "method": "orcid"}) # Note: AlreadyLinkedError becomes FlushError when testing with isolated_app. except (AlreadyLinkedError, FlushError): # User already has their ORCID linked pass # Search for existing tokens. # Note: there can be only 1 RemoteToken per given RemoteAccount. existing_remote_token = (RemoteToken.query.join(RemoteAccount).filter_by( user=user).one_or_none()) # If not existing_remote_token, create one. if not existing_remote_token: with db.session.begin_nested(): RemoteToken.create( user_id=user.id, client_id=get_value(current_app.config, "ORCID_APP_CREDENTIALS.consumer_key"), token=access_token, secret=None, extra_data={ "orcid": orcid, "full_name": name, "allow_push": True }, ) return orcid # If there is an existing_remote_token: # ensure it is associated to this ORCID and # set allow_push to True. # # Get the ORCID associated with this token. user_identity = UserIdentity.query.filter_by(user=user, method="orcid").one_or_none() # Ensure data consistency. if not user_identity: msg = ('No UserIdentity for user={}, method="orcid", while' " instead there is a RemoteAccount={} and RemoteToken={}") raise Exception( msg.format(user, existing_remote_token.remote_account, existing_remote_token)) if user_identity.id != existing_remote_token.remote_account.extra_data[ "orcid"]: msg = "UserIdentity={} and RemoteToken={} ORCID mismatch: {} != {}" raise Exception( msg.format( user_identity, existing_remote_token, user_identity.id, existing_remote_token.remote_account.extra_data["orcid"], )) if existing_remote_token.remote_account.extra_data["orcid"] != orcid: raise RemoteTokenOrcidMismatch( user, [existing_remote_token.remote_account.extra_data["orcid"], orcid]) # Force the allow_push. with db.session.begin_nested(): if not existing_remote_token.remote_account.extra_data["allow_push"]: existing_remote_token.remote_account.extra_data[ "allow_push"] = True return orcid return None
def _link_user_and_token(user, name, orcid, access_token): """Create a link between a user and token, if possible. Args: user (invenio_oauthclient.models.User): an existing user object to connect the token to orcid (string): user's ORCID identifier access_token (string): OAUTH token for the user Returns: str: the ORCID associated with the token newly created/enabled. """ try: # Link user and ORCID oauth_link_external_id(user, { 'id': orcid, 'method': 'orcid' }) # Note: AlreadyLinkedError becomes FlushError when testing with isolated_app. except (AlreadyLinkedError, FlushError): # User already has their ORCID linked pass # Search for existing tokens. # Note: there can be only 1 RemoteToken per given RemoteAccount. existing_remote_token = RemoteToken.query.join(RemoteAccount).filter_by( user=user).one_or_none() # If not existing_remote_token, create one. if not existing_remote_token: with db.session.begin_nested(): RemoteToken.create( user_id=user.id, client_id=get_value(current_app.config, 'ORCID_APP_CREDENTIALS.consumer_key'), token=access_token, secret=None, extra_data={ 'orcid': orcid, 'full_name': name, 'allow_push': True, } ) return orcid # If there is an existing_remote_token: # ensure it is associated to this ORCID and # set allow_push to True. # # Get the ORCID associated with this token. user_identity = UserIdentity.query.filter_by(user=user, method='orcid').one_or_none() # Ensure data consistency. if not user_identity: msg = 'No UserIdentity for user={}, method="orcid", while' \ ' instead there is a RemoteAccount={} and RemoteToken={}' raise Exception(msg.format( user, existing_remote_token.remote_account, existing_remote_token)) if user_identity.id != existing_remote_token.remote_account.extra_data['orcid']: msg = 'UserIdentity={} and RemoteToken={} ORCID mismatch: {} != {}' raise Exception(msg.format( user_identity, existing_remote_token, user_identity.id, existing_remote_token.remote_account.extra_data['orcid'] )) if existing_remote_token.remote_account.extra_data['orcid'] != orcid: raise RemoteTokenOrcidMismatch(user, [existing_remote_token.remote_account.extra_data['orcid'], orcid]) # Force the allow_push. with db.session.begin_nested(): if not existing_remote_token.remote_account.extra_data['allow_push']: existing_remote_token.remote_account.extra_data['allow_push'] = True return orcid return None