Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Generic] Add support for manage_groups #708

Merged
merged 5 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions oauthenticator/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def _login_service_default(self):
that accepts the returned json (as a dict) and returns the groups list.

This configures how group membership in the upstream provider is determined
for use by `allowed_groups`, `admin_groups`, etc.
It has no effect on its own, and is not related to users' _JupyterHub_ group membership.
for use by `allowed_groups`, `admin_groups`, etc. If `manage_groups` is True,
this will also determine users' _JupyterHub_ group membership.
""",
)

Expand Down Expand Up @@ -154,15 +154,22 @@ async def update_auth_model(self, auth_model):
the user isn't part of `admin_users` or `admin_groups`. Note that
leaving it at None makes users able to retain an admin status while
setting it to False makes it be revoked.

Also populates groups if `manage_groups` is set.
"""
if self.manage_groups or self.admin_groups:
user_info = auth_model["auth_state"][self.user_auth_state_key]
user_groups = self.get_user_groups(user_info)

if self.manage_groups:
auth_model["groups"] = sorted(user_groups)

if auth_model["admin"]:
# auth_model["admin"] being True means the user was in admin_users
return auth_model

if self.admin_groups:
# admin status should in this case be True or False, not None
user_info = auth_model["auth_state"][self.user_auth_state_key]
user_groups = self.get_user_groups(user_info)
auth_model["admin"] = bool(user_groups & self.admin_groups)

return auth_model
Expand Down
20 changes: 19 additions & 1 deletion oauthenticator/tests/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ def get_authenticator(generic_client):
False,
False,
),
(
"20",
{
"manage_groups": True,
"allow_all": True,
},
True,
None,
),
],
)
async def test_generic(
Expand All @@ -166,14 +175,20 @@ async def test_generic(
c.GenericOAuthenticator = Config(class_config)
c.GenericOAuthenticator.username_claim = "username"
authenticator = get_authenticator(config=c)
manage_groups = False
if "manage_groups" in class_config:
manage_groups = authenticator.manage_groups

handled_user_model = user_model("user1")
handler = generic_client.handler_for_user(handled_user_model)
auth_model = await authenticator.get_authenticated_user(handler, None)

if expect_allowed:
assert auth_model
assert set(auth_model) == {"name", "admin", "auth_state"}
expected_keys = {"name", "admin", "auth_state"}
if manage_groups:
expected_keys.add("groups")
assert set(auth_model) == expected_keys
assert auth_model["admin"] == expect_admin
auth_state = auth_model["auth_state"]
assert json.dumps(auth_state)
Expand All @@ -183,6 +198,9 @@ async def test_generic(
assert "scope" in auth_state
user_info = auth_state[authenticator.user_auth_state_key]
assert auth_model["name"] == user_info[authenticator.username_claim]
if manage_groups:
assert auth_model["groups"] == user_info[authenticator.claim_groups_key]

else:
assert auth_model == None

Expand Down