def test_get_create(self):
        from invenio_oauthclient.models import RemoteAccount, RemoteToken

        t = RemoteToken.create(self.u1, "dev", "mytoken", "mysecret")
        assert t
        assert t.token() == ('mytoken', 'mysecret')

        acc = RemoteAccount.get(self.u1, "dev")
        assert acc
        assert t.remote_account.id == acc.id
        assert t.token_type == ''

        t2 = RemoteToken.create(self.u1,
                                "dev",
                                "mytoken2",
                                "mysecret2",
                                token_type='t2')
        assert t2.remote_account.id == acc.id
        assert t2.token_type == 't2'

        t3 = RemoteToken.get(self.u1, "dev")
        t4 = RemoteToken.get(self.u1, "dev", token_type="t2")
        assert t4.token() != t3.token()

        assert RemoteToken.query.count() == 2
        acc.delete()
        assert RemoteToken.query.count() == 0
    def test_existent_token_for_same_user_but_different_orcid(self):
        # Create existing token: RemoteToken, RemoteAccount, UserIdentity.
        other_orcid = 'otherorcid'
        with db.session.begin_nested():
            # Create RemoteToken and RemoteAccount.
            RemoteToken.create(
                user_id=self.user.id,
                client_id=current_app.config['ORCID_APP_CREDENTIALS']['consumer_key'],
                token=self.token,
                secret=None,
                extra_data={
                    'orcid': other_orcid,
                    'full_name': self.name,
                    'allow_push': True,
                }
            )
            user_identity = UserIdentity(
                id=other_orcid,
                method='orcid',
                id_user=self.user.id
            )
            db.session.add(user_identity)

        with pytest.raises(RemoteTokenOrcidMismatch):
            _link_user_and_token(self.user, self.name, self.orcid, self.token)
def test_get_create_remote_token(app, example):
    """Test create remote token."""
    existing_email = "*****@*****.**"
    datastore = app.extensions["invenio-accounts"].datastore
    user = datastore.find_user(email=existing_email)

    t = RemoteToken.create(user.id, "dev", "mytoken", "mysecret")
    assert t
    assert t.token() == ("mytoken", "mysecret")

    acc = RemoteAccount.get(user.id, "dev")
    assert acc
    assert t.remote_account.id == acc.id
    assert t.token_type == ""

    t2 = RemoteToken.create(user.id, "dev", "mytoken2", "mysecret2", token_type="t2")
    assert t2.remote_account.id == acc.id
    assert t2.token_type == "t2"

    t3 = RemoteToken.get(user.id, "dev")
    t4 = RemoteToken.get(user.id, "dev", token_type="t2")
    assert t4.token() != t3.token()

    assert RemoteToken.query.count() == 2
    acc.delete()
    assert RemoteToken.query.count() == 0
def test_get_create_remote_token(app, models_fixture):
    """Test create remote token."""
    existing_email = '*****@*****.**'
    datastore = app.extensions['invenio-accounts'].datastore
    user = datastore.find_user(email=existing_email)

    t = RemoteToken.create(user.id, 'dev', 'mytoken', 'mysecret')
    assert t
    assert t.token() == ('mytoken', 'mysecret')

    acc = RemoteAccount.get(user.id, 'dev')
    assert acc
    assert t.remote_account.id == acc.id
    assert t.token_type == ''

    t2 = RemoteToken.create(
        user.id, 'dev', 'mytoken2', 'mysecret2',
        token_type='t2'
    )
    assert t2.remote_account.id == acc.id
    assert t2.token_type == 't2'

    t3 = RemoteToken.get(user.id, 'dev')
    t4 = RemoteToken.get(user.id, 'dev', token_type='t2')
    assert t4.token() != t3.token()

    assert RemoteToken.query.count() == 2
    acc.delete()
    assert RemoteToken.query.count() == 0
    def test_existent_token(self):
        # Create existing token: RemoteToken, RemoteAccount, UserIdentity.
        with db.session.begin_nested():
            # Create RemoteToken and RemoteAccount.
            RemoteToken.create(
                user_id=self.user.id,
                client_id=current_app.config['ORCID_APP_CREDENTIALS']['consumer_key'],
                token=self.token,
                secret=None,
                extra_data={
                    'orcid': self.orcid,
                    'full_name': self.name,
                    'allow_push': True,
                }
            )
            user_identity = UserIdentity(
                id=self.orcid,
                method='orcid',
                id_user=self.user.id
            )
            db.session.add(user_identity)

        with mock.patch('inspirehep.modules.orcid.tasks.oauth_link_external_id') as mock_oauth_link_external_id:
            # Mocking `oauth_link_external_id` is necessary because when running
            # with `isolated_app` it raises
            # "FlushError: New instance ... with identity key (...) conflicts with persistent instance ..."
            # rather than the standard and expected `IntegrityError` (which
            # is raised instead when run without `isolated_app`).
            mock_oauth_link_external_id.side_effect = AlreadyLinkedError(self.user, self.orcid)
            _link_user_and_token(self.user, self.name, self.orcid, self.token)

        self._assert_remote_account_and_remote_token_and_user_identity()
def test_get_create_remote_token(models_fixture):
    """Test create remote token."""
    app = models_fixture
    existing_email = "*****@*****.**"
    datastore = app.extensions['invenio-accounts'].datastore
    user = datastore.find_user(email=existing_email)

    t = RemoteToken.create(user.id, "dev", "mytoken", "mysecret")
    assert t
    assert t.token() == ('mytoken', 'mysecret')

    acc = RemoteAccount.get(user.id, "dev")
    assert acc
    assert t.remote_account.id == acc.id
    assert t.token_type == ''

    t2 = RemoteToken.create(
        user.id, "dev", "mytoken2", "mysecret2",
        token_type='t2'
    )
    assert t2.remote_account.id == acc.id
    assert t2.token_type == 't2'

    t3 = RemoteToken.get(user.id, "dev")
    t4 = RemoteToken.get(user.id, "dev", token_type="t2")
    assert t4.token() != t3.token()

    assert RemoteToken.query.count() == 2
    acc.delete()
    assert RemoteToken.query.count() == 0
def test_get_create_remote_token(models_fixture, example):
    """Test create remote token."""
    app = models_fixture
    existing_email = "*****@*****.**"
    datastore = app.extensions['invenio-accounts'].datastore
    user = datastore.find_user(email=existing_email)

    t = RemoteToken.create(user.id, "dev", "mytoken", "mysecret")
    assert t
    assert t.token() == ('mytoken', 'mysecret')

    acc = RemoteAccount.get(user.id, "dev")
    assert acc
    assert t.remote_account.id == acc.id
    assert t.token_type == ''

    t2 = RemoteToken.create(user.id,
                            "dev",
                            "mytoken2",
                            "mysecret2",
                            token_type='t2')
    assert t2.remote_account.id == acc.id
    assert t2.token_type == 't2'

    t3 = RemoteToken.get(user.id, "dev")
    t4 = RemoteToken.get(user.id, "dev", token_type="t2")
    assert t4.token() != t3.token()

    assert RemoteToken.query.count() == 2
    acc.delete()
    assert RemoteToken.query.count() == 0
    def test_get_create(self):
        from invenio_oauthclient.models import RemoteAccount, RemoteToken

        t = RemoteToken.create(self.u1, "dev", "mytoken", "mysecret")
        assert t
        assert t.token() == ('mytoken', 'mysecret')

        acc = RemoteAccount.get(self.u1, "dev")
        assert acc
        assert t.remote_account.id == acc.id
        assert t.token_type == ''

        t2 = RemoteToken.create(
            self.u1, "dev", "mytoken2", "mysecret2",
            token_type='t2'
        )
        assert t2.remote_account.id == acc.id
        assert t2.token_type == 't2'

        t3 = RemoteToken.get(self.u1, "dev")
        t4 = RemoteToken.get(self.u1, "dev", token_type="t2")
        assert t4.token() != t3.token()

        assert RemoteToken.query.count() == 2
        acc.delete()
        assert RemoteToken.query.count() == 0
    def test_get_regression(self):
        from invenio_oauthclient.models import RemoteToken

        t3 = RemoteToken.create(self.u2, "dev", "mytoken", "mysecret")
        t4 = RemoteToken.create(self.u3, "dev", "mytoken", "mysecret")

        assert RemoteToken.get(self.u2, "dev").remote_account.user_id == t3.remote_account.user_id
        assert RemoteToken.get(self.u3, "dev").remote_account.user_id == t4.remote_account.user_id
    def test_get_regression(self):
        from invenio_oauthclient.models import RemoteToken

        t3 = RemoteToken.create(self.u2, "dev", "mytoken", "mysecret")
        t4 = RemoteToken.create(self.u3, "dev", "mytoken", "mysecret")

        assert RemoteToken.get(self.u2, "dev").remote_account.user_id == \
            t3.remote_account.user_id
        assert RemoteToken.get(self.u3, "dev").remote_account.user_id == \
            t4.remote_account.user_id
Beispiel #11
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 #12
0
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_get_regression(app, example):
    """Test regression."""
    datastore = app.extensions["invenio-accounts"].datastore

    email2 = "*****@*****.**"
    email3 = "*****@*****.**"

    user2 = datastore.find_user(email=email2)
    user3 = datastore.find_user(email=email3)

    t3 = RemoteToken.create(user2.id, "dev", "mytoken", "mysecret")
    t4 = RemoteToken.create(user3.id, "dev", "mytoken", "mysecret")

    assert RemoteToken.get(user2.id, "dev").remote_account.user_id == t3.remote_account.user_id
    assert RemoteToken.get(user3.id, "dev").remote_account.user_id == t4.remote_account.user_id
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')
Beispiel #15
0
def test_signup_handler(remote, app_rest, models_fixture):
    """Test signup handler."""
    datastore = app_rest.extensions['invenio-accounts'].datastore
    existing_email = '*****@*****.**'
    user = datastore.find_user(email=existing_email)
    # Already authenticated
    login_user(user)
    assert current_user.is_authenticated
    resp1 = signup_handler(remote)
    expected_url_args = {"message": "Successfully signed up.", "code": 200}
    check_response_redirect_url_args(resp1, expected_url_args)
    logout_user()
    assert not current_user.is_authenticated

    # No OAuth token
    resp2 = signup_handler(remote)
    expected_url_args = {"message": "Token not found.", "code": 400}

    check_response_redirect_url_args(resp2, expected_url_args)

    # Not coming from authorized request
    token = RemoteToken.create(user.id, 'testkey', 'mytoken', 'mysecret')
    token_setter(remote, token, 'mysecret')
    with pytest.raises(BuildError):
        signup_handler(remote)
Beispiel #16
0
def remote_account(app, user_without_role):
    """Create a remote token from user data."""
    remote_account = RemoteAccount.create(1, 'dev', dict())
    remote_token = RemoteToken.create(user_without_role.id, 'dev', 'token',
                                      'secret')

    return remote_account, remote_token
def token_setter(remote, token, secret='', token_type='', extra_data=None,
                 user=None):
    """Set token for user.

    :param remote: The remote application.
    :param token: The token to set.
    :param token_type: The token type. (Default: ``''``)
    :param extra_data: Extra information. (Default: ``None``)
    :param user: The user owner of the remote token. If it's not defined,
        the current user is used automatically. (Default: ``None``)
    :returns: A :class:`invenio_oauthclient.models.RemoteToken` instance or
        ``None``.
    """
    session[token_session_key(remote.name)] = (token, secret)
    user = user or current_user

    # Save token if user is not anonymous (user exists but can be not active at
    # this moment)
    if not user.is_anonymous:
        uid = user.id
        cid = remote.consumer_key

        # Check for already existing token
        t = RemoteToken.get(uid, cid, token_type=token_type)

        if t:
            t.update_token(token, secret)
        else:
            t = RemoteToken.create(
                uid, cid, token, secret,
                token_type=token_type, extra_data=extra_data
            )
        return t
    return None
Beispiel #18
0
def test_rebuilding_access_tokens(app, models_fixture):
    """Test rebuilding access tokens with random new SECRET_KEY."""
    old_secret_key = app.secret_key

    datastore = app.extensions['invenio-accounts'].datastore
    existing_email = '*****@*****.**'
    user = datastore.find_user(email=existing_email)

    # Creating a new remote token and commiting to the db
    test_token = 'mytoken'
    token_type = 'testing'
    with db.session.begin_nested():
        rt = RemoteToken.create(user.id, 'testkey', test_token, app.secret_key,
                                token_type)
        db.session.add(rt)
    db.session.commit()

    # Changing application SECRET_KEY
    app.secret_key = 'NEW_SECRET_KEY'
    db.session.expunge_all()

    # Asserting the decoding error occurs with the stale SECRET_KEY
    if sys.version_info[0] < 3:  # python 2
        remote_token = RemoteToken.query.first()
        assert remote_token.access_token != test_token
    else:  # python 3
        with pytest.raises(ValueError):
            RemoteToken.query.first()

    db.session.expunge_all()
    rebuild_access_tokens(old_secret_key)
    remote_token = RemoteToken.query.filter_by(token_type=token_type).first()

    # Asserting the access_token is not changed after rebuilding
    assert remote_token.access_token == test_token
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 #20
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 #21
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,
                    },
                ))
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 test_get_regression(app, models_fixture):
    """Test regression."""
    datastore = app.extensions['invenio-accounts'].datastore

    email2 = '*****@*****.**'
    email3 = '*****@*****.**'

    user2 = datastore.find_user(email=email2)
    user3 = datastore.find_user(email=email3)

    t3 = RemoteToken.create(user2.id, 'dev', 'mytoken', 'mysecret')
    t4 = RemoteToken.create(user3.id, 'dev', 'mytoken', 'mysecret')

    assert RemoteToken.get(user2.id, 'dev').remote_account.user_id == \
        t3.remote_account.user_id
    assert RemoteToken.get(user3.id, 'dev').remote_account.user_id == \
        t4.remote_account.user_id
Beispiel #24
0
def test_get_regression(app, example):
    """Test regression."""
    datastore = app.extensions['invenio-accounts'].datastore

    email2 = "*****@*****.**"
    email3 = "*****@*****.**"

    user2 = datastore.find_user(email=email2)
    user3 = datastore.find_user(email=email3)

    t3 = RemoteToken.create(user2.id, "dev", "mytoken", "mysecret")
    t4 = RemoteToken.create(user3.id, "dev", "mytoken", "mysecret")

    assert RemoteToken.get(user2.id, "dev").remote_account.user_id == \
        t3.remote_account.user_id
    assert RemoteToken.get(user3.id, "dev").remote_account.user_id == \
        t4.remote_account.user_id
Beispiel #25
0
def remote_account_fixture(app, models_fixture):
    """Create a remote token from user data."""
    datastore = app.extensions['security'].datastore
    user = datastore.find_user(email='*****@*****.**')

    remote_account = RemoteAccount.create(1, 'dev', dict())
    remote_token = RemoteToken.create(user.id, 'dev', 'token', 'secret')

    return remote_account, remote_token
def test_get_regression(models_fixture):
    """Test regression."""
    app = models_fixture
    datastore = app.extensions['invenio-accounts'].datastore

    email2 = '*****@*****.**'
    email3 = '*****@*****.**'

    user2 = datastore.find_user(email=email2)
    user3 = datastore.find_user(email=email3)

    t3 = RemoteToken.create(user2.id, 'dev', 'mytoken', 'mysecret')
    t4 = RemoteToken.create(user3.id, 'dev', 'mytoken', 'mysecret')

    assert RemoteToken.get(user2.id, 'dev').remote_account.user_id == \
        t3.remote_account.user_id
    assert RemoteToken.get(user3.id, 'dev').remote_account.user_id == \
        t4.remote_account.user_id
def test_repr(app, models_fixture):
    """Test representation of RemoteAccount and RemoteToken."""
    datastore = app.extensions['invenio-accounts'].datastore
    user = datastore.find_user(email='*****@*****.**')

    assert 'Remote Token <token_type=type access_token=****oken>' == \
           repr(RemoteToken.create(user.id, 'dev',
                                   'mytoken', 'mysecret',
                                   token_type='type'))

    assert 'Remote Account <id=1, user_id=1>' == \
           repr(RemoteAccount.get(user.id, 'dev'))
def test_repr(models_fixture):
    """Test representation of RemoteAccount adn RemoteToken."""
    datastore = models_fixture.extensions['invenio-accounts'].datastore
    user = datastore.find_user(email='*****@*****.**')

    assert 'Remote Token <token_type=type access_token=mytoken>' == \
           repr(RemoteToken.create(user.id, 'dev',
                                   'mytoken', 'mysecret',
                                   token_type='type'))

    assert 'Remote Account <id=1, user_id=1>' == \
           repr(RemoteAccount.get(user.id, 'dev'))
Beispiel #29
0
def remote_token(app, db, tester_id):
    """Create a remove token for accessing GitHub API."""
    from invenio_oauthclient.models import RemoteToken

    # Create GitHub link
    token = RemoteToken.create(
        tester_id,
        GitHubAPI.remote.consumer_key,
        'test',
        '',
    )
    db.session.commit()
    return token
def remote_token(app, db, tester_id):
    """Create a remove token for accessing GitHub API."""
    from invenio_oauthclient.models import RemoteToken

    # Create GitHub link
    token = RemoteToken.create(
        tester_id,
        GitHubAPI.remote.consumer_key,
        'test',
        '',
    )
    db.session.commit()
    return token
Beispiel #31
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 #32
0
def remote_token(app, db, tester_id):
    """Create a remove token for accessing GitHub API."""
    from invenio_oauthclient.models import RemoteToken
    from invenio_github.helpers import get_client_id

    # Create GitHub link
    token = RemoteToken.create(
        tester_id,
        get_client_id(),
        'test',
        '',
    )
    db.session.commit()
    return token
Beispiel #33
0
    def _create(cls,
                model_class,
                role="superuser",
                orcid=None,
                email=None,
                allow_push=None,
                token=None,
                *args,
                **kwargs):
        ds = current_app.extensions["invenio-accounts"].datastore
        role = ds.find_or_create_role(role)
        user = ds.create_user(
            id=fake.random_number(digits=8, fix_len=True),
            email=fake.email() if not email else email,
            password=hash_password(fake.password()),
            active=True,
            roles=[role],
        )

        if orcid:
            user_orcid_id = UserIdentity(id=orcid,
                                         method="orcid",
                                         id_user=user.get_id())
            db.session.add(user_orcid_id)

            RemoteToken.create(
                user_id=user.get_id(),
                client_id="orcid",
                token=token,
                secret=None,
                extra_data={
                    "orcid": orcid,
                    "allow_push": allow_push
                },
            )

        return user
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_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_account_setup(app, example_cern, models_fixture):
    """Test account setup after login."""
    client = app.test_client()
    ioc = app.extensions['oauthlib.client']

    # Ensure remote apps have been loaded (due to before first request)
    client.get(url_for("invenio_oauthclient.login", remote_app='cern'))

    example_response, example_token, example_account_info = example_cern
    res = get_dict_from_response(example_response)

    mock_remote_get(ioc, 'cern', example_response)

    app = models_fixture
    datastore = app.extensions['invenio-accounts'].datastore
    user = datastore.find_user(email="*****@*****.**")
    token = RemoteToken.create(
        user.id, 'client_id', example_token['access_token'], 'secret',
        token_type=example_token['token_type']
    )
    account_setup(ioc.remote_apps['cern'], token, None)
Beispiel #37
0
def token_setter(remote,
                 token,
                 secret='',
                 token_type='',
                 extra_data=None,
                 user=None):
    """Set token for user.

    :param remote: The remote application.
    :param token: The token to set.
    :param token_type: The token type. (Default: ``''``)
    :param extra_data: Extra information. (Default: ``None``)
    :param user: The user owner of the remote token. If it's not defined,
        the current user is used automatically. (Default: ``None``)
    :returns: A :class:`invenio_oauthclient.models.RemoteToken` instance or
        ``None``.
    """
    session[token_session_key(remote.name)] = (token, secret)
    user = user or current_user

    # Save token if user is not anonymous (user exists but can be not active at
    # this moment)
    if not user.is_anonymous:
        uid = user.id
        cid = remote.consumer_key

        # Check for already existing token
        t = RemoteToken.get(uid, cid, token_type=token_type)

        if t:
            t.update_token(token, secret)
        else:
            t = RemoteToken.create(uid,
                                   cid,
                                   token,
                                   secret,
                                   token_type=token_type,
                                   extra_data=extra_data)
        return t
    return None
def test_signup_handler(remote, app, models_fixture):
    """Test signup handler."""
    datastore = app.extensions['invenio-accounts'].datastore
    existing_email = '*****@*****.**'
    user = datastore.find_user(email=existing_email)

    # Already authenticated
    login_user(user)
    assert current_user.is_authenticated
    resp1 = signup_handler(remote)
    check_redirect_location(resp1, '/')
    logout_user()
    assert not current_user.is_authenticated

    # No OAuth token
    resp2 = signup_handler(remote)
    check_redirect_location(resp2, '/')

    # Not coming from authorized request
    token = RemoteToken.create(user.id, 'testkey', 'mytoken', 'mysecret')
    token_setter(remote, token, 'mysecret')
    with pytest.raises(BuildError):
        signup_handler(remote)
def test_rebuilding_access_tokens(models_fixture):
    """Test rebuilding access tokens with random new SECRET_KEY."""
    app = models_fixture
    old_secret_key = app.secret_key

    datastore = app.extensions['invenio-accounts'].datastore
    existing_email = '*****@*****.**'
    user = datastore.find_user(email=existing_email)

    # Creating a new remote token and commiting to the db
    test_token = 'mytoken'
    token_type = 'testing'
    with db.session.begin_nested():
        rt = RemoteToken.create(user.id, 'testkey', test_token,
                                app.secret_key, token_type)
        db.session.add(rt)
    db.session.commit()

    # Changing application SECRET_KEY
    app.secret_key = 'NEW_SECRET_KEY'
    db.session.expunge_all()

    # Asserting the decoding error occurs with the stale SECRET_KEY
    if sys.version_info[0] < 3:  # python 2
        remote_token = RemoteToken.query.first()
        assert remote_token.access_token != test_token
    else:  # python 3
        with pytest.raises(UnicodeDecodeError):
            RemoteToken.query.first()

    db.session.expunge_all()
    rebuild_access_tokens(old_secret_key)
    remote_token = RemoteToken.query.filter_by(token_type=token_type).first()

    # Asserting the access_token is not changed after rebuilding
    assert remote_token.access_token == test_token
def test_signup_handler(remote, models_fixture):
    """Test signup handler."""
    app = models_fixture
    datastore = app.extensions['invenio-accounts'].datastore
    existing_email = '*****@*****.**'
    user = datastore.find_user(email=existing_email)

    # Already authenticated
    login_user(user)
    assert current_user.is_authenticated
    resp1 = signup_handler(remote)
    check_redirect_location(resp1, '/')
    logout_user()
    assert not current_user.is_authenticated

    # No OAuth token
    resp2 = signup_handler(remote)
    check_redirect_location(resp2, '/')

    # Not coming from authorized request
    token = RemoteToken.create(user.id, 'testkey', 'mytoken', 'mysecret')
    token_setter(remote, token, 'mysecret')
    with pytest.raises(BuildError):
        signup_handler(remote)
Beispiel #41
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 #42
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