Beispiel #1
0
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,
                    }
                )
            )
Beispiel #3
0
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,
                                   }))
Beispiel #5
0
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,
                    },
                ))
Beispiel #6
0
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,
            }
        ))
Beispiel #7
0
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'])
Beispiel #8
0
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
Beispiel #9
0
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")
        )
Beispiel #10
0
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"))
Beispiel #11
0
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")
        )
Beispiel #12
0
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")
        )
Beispiel #13
0
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()
Beispiel #14
0
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"})
Beispiel #15
0
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)
Beispiel #17
0
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'))
Beispiel #19
0
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()
Beispiel #21
0
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'))
Beispiel #22
0
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
Beispiel #23
0
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'))
Beispiel #24
0
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))
Beispiel #25
0
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"))
Beispiel #26
0
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'))
Beispiel #27
0
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()
Beispiel #29
0
    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})
Beispiel #30
0
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()
Beispiel #32
0
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()
Beispiel #33
0
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'
        })
Beispiel #34
0
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'])
Beispiel #35
0
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
Beispiel #36
0
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