Skip to content

Commit

Permalink
Merge pull request #1184 from uc-cdis/feat/only_login_onboarded_users
Browse files Browse the repository at this point in the history
Feat: only allow login of onboarded users
  • Loading branch information
pieterlukasse authored Nov 5, 2024
2 parents 1d33762 + b8388f0 commit 5a3877b
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 8 deletions.
13 changes: 12 additions & 1 deletion fence/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ def set_flask_session_values(user):

user = query_for_user(session=current_app.scoped_session(), username=username)
if user:
if user.active is False:
# Abort login if user.active is False (user.active is None or True are both
# considered active in this case):
raise Unauthorized(
"User is known but not authorized/activated in the system"
)

_update_users_email(user, email)
_update_users_id_from_idp(user, id_from_idp)
_update_users_last_auth(user)
Expand All @@ -111,7 +118,11 @@ def set_flask_session_values(user):
set_flask_session_values(user)
return
else:
# we need a new user
if not config["ALLOW_NEW_USER_ON_LOGIN"]:
# do not create new active users automatically
raise Unauthorized("New user is not yet authorized/activated in the system")

# add the new user
user = User(username=username)

if email:
Expand Down
10 changes: 10 additions & 0 deletions fence/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,16 @@ DEFAULT_BACKOFF_SETTINGS_MAX_TRIES: 3
# here. Something like: [email protected]
SUPPORT_EMAIL_FOR_ERRORS: null

# //////////////////////////////////////////////////////////////////////////////////////
# USER ACTIVATION
# //////////////////////////////////////////////////////////////////////////////////////
# If you want new users (read: users that login for the first time) to automatically be
# allowed through and added to the Fence DB, set this to true. Otherwise, set this to false.
# Setting it to false will ensure the user will only be able to login after the user
# is added to the Fence DB via a separate process. This two-step process allows for
# a separate onboarding and user "approval" process, instead of the default automatic approval.
ALLOW_NEW_USER_ON_LOGIN: true

# //////////////////////////////////////////////////////////////////////////////////////
# SHIBBOLETH
# - Support using `shibboleth` in LOGIN_OPTIONS
Expand Down
8 changes: 1 addition & 7 deletions fence/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@ class FenceConfig(Config):
def post_process(self):
# backwards compatibility if no new YAML cfg provided
# these cfg use to be in settings.py so we need to make sure they gets defaulted
default_config = yaml_load(
open(
os.path.join(
os.path.dirname(os.path.abspath(__file__)), "config-default.yaml"
)
)
)
default_config = yaml_load(open(DEFAULT_CFG_PATH))

defaults = [
"APPLICATION_ROOT",
Expand Down
37 changes: 37 additions & 0 deletions tests/login/test_login_user.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import flask
import pytest
from fence.auth import login_user, logout
from fence.models import User, IdentityProvider
import time
from datetime import datetime
from fence.config import config
from fence.errors import Unauthorized


def test_login_user_already_in_db(db_session):
Expand Down Expand Up @@ -33,6 +36,24 @@ def test_login_user_already_in_db(db_session):
assert flask.g.user == test_user


def test_login_failure_for_user_already_in_db_but_inactive(db_session):
"""
Test that if a user is already in the database, but is set to user.active == False,
and logs in, the login returns an Unauthorized error.
"""
email = "[email protected]"
provider = "Test Provider"
id_from_idp = "Provider_ID_0001"

test_user = User(username=email, is_admin=False, active=False)
db_session.add(test_user)
db_session.commit()
with pytest.raises(
Unauthorized, match="User is known but not authorized/activated in the system"
):
login_user(email, provider, email=email, id_from_idp=id_from_idp)


def test_login_user_with_idp_already_in_db(db_session):
"""
Test that if a user is already in the database, has identity_provider
Expand Down Expand Up @@ -85,6 +106,22 @@ def test_login_new_user(db_session):
assert flask.g.user == test_user


def test_login_new_user_not_allowed(db_session, monkeypatch):
"""
Test that when ALLOW_NEW_USER_ON_LOGIN config is False,
and a user that is not in the database logs in, an
Unauthorized error is returned.
"""
monkeypatch.setitem(config, "ALLOW_NEW_USER_ON_LOGIN", False)
email = "[email protected]"
provider = "Test Provider"
id_from_idp = "Provider_ID_0001"
with pytest.raises(
Unauthorized, match="New user is not yet authorized/activated in the system"
):
login_user(email, provider, email=email, id_from_idp=id_from_idp)


def test_last_auth_update_in_db(db_session):
"""
Test that the _last_auth field in the DB is updated when the user logs in.
Expand Down

0 comments on commit 5a3877b

Please sign in to comment.