Skip to content

Commit

Permalink
maint: update tests for recent change
Browse files Browse the repository at this point in the history
  • Loading branch information
consideRatio committed Jun 26, 2023
1 parent 223c89b commit 0e2352e
Show file tree
Hide file tree
Showing 12 changed files with 1,828 additions and 1,208 deletions.
163 changes: 111 additions & 52 deletions oauthenticator/tests/test_auth0.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,97 @@
import logging
from unittest.mock import Mock

from pytest import fixture, mark
from pytest import fixture, mark, raises
from tornado import web
from traitlets.config import Config

from ..auth0 import Auth0OAuthenticator
from ..oauth2 import OAuthLogoutHandler
from .mocks import mock_handler, setup_oauth_mock

auth0_subdomain = "jupyterhub-test"
auth0_domain = "jupyterhub-test.auth0.com"


def user_model(email, nickname=None):
"""Return a user model"""
return {
'email': email,
'nickname': nickname if nickname else email,
'name': 'Hoban Washburn',
}
AUTH0_DOMAIN = "jupyterhub-test.auth0.com"


@fixture
def auth0_client(client):
setup_oauth_mock(
client,
host=auth0_domain,
host=AUTH0_DOMAIN,
access_token_path='/oauth/token',
user_path='/userinfo',
)
return client


@mark.parametrize(
'config', [{"auth0_domain": auth0_domain}, {"auth0_subdomain": auth0_subdomain}]
)
async def test_auth0(config, auth0_client):
cfg = Config()
cfg.Auth0OAuthenticator = Config(config)
authenticator = Auth0OAuthenticator(config=cfg)

handler = auth0_client.handler_for_user(user_model('[email protected]'))
auth_model = await authenticator.get_authenticated_user(handler, None)
assert sorted(auth_model) == ['admin', 'auth_state', 'name']
assert auth_model['name'] == '[email protected]'
auth_state = auth_model['auth_state']
assert 'access_token' in auth_state
assert 'auth0_user' in auth_state
def user_model():
"""Return a user model"""
return {
"email": "[email protected]",
"name": "user1",
}


@mark.parametrize(
'config', [{"auth0_domain": auth0_domain}, {"auth0_subdomain": auth0_subdomain}]
"test_variation_id,class_config,expect_allowed,expect_admin",
[
# no allow config tested
("00", {}, False, None),
# allow config, individually tested
("01", {"allow_all": True}, True, None),
("02", {"allowed_users": {"user1"}}, True, None),
("03", {"allowed_users": {"not-test-user"}}, False, None),
("04", {"admin_users": {"user1"}}, True, True),
("05", {"admin_users": {"not-test-user"}}, False, None),
# allow config, some combinations of two tested
(
"10",
{
"allow_all": False,
"allowed_users": {"not-test-user"},
},
False,
None,
),
(
"11",
{
"admin_users": {"user1"},
"allowed_users": {"not-test-user"},
},
True,
True,
),
],
)
async def test_username_key(config, auth0_client):
cfg = Config()
cfg.Auth0OAuthenticator = Config(config)
authenticator = Auth0OAuthenticator(config=cfg)
authenticator.username_key = 'nickname'
handler = auth0_client.handler_for_user(user_model('[email protected]', 'kayle'))
async def test_auth0(
auth0_client,
test_variation_id,
class_config,
expect_allowed,
expect_admin,
):
print(f"Running test variation id {test_variation_id}")
c = Config()
c.Auth0OAuthenticator = Config(class_config)
c.Auth0OAuthenticator.auth0_domain = AUTH0_DOMAIN
c.Auth0OAuthenticator.username_claim = "name"
authenticator = Auth0OAuthenticator(config=c)

handled_user_model = user_model()
handler = auth0_client.handler_for_user(handled_user_model)
auth_model = await authenticator.get_authenticated_user(handler, None)
assert auth_model['name'] == 'kayle'

if expect_allowed:
assert auth_model
assert set(auth_model) == {"name", "admin", "auth_state"}
assert auth_model["admin"] == expect_admin
auth_state = auth_model["auth_state"]
assert "access_token" in auth_state
user_info = auth_state[authenticator.user_auth_state_key]
assert user_info == handled_user_model
assert auth_model["name"] == user_info[authenticator.username_claim]
else:
assert auth_model == None


async def test_custom_logout(monkeypatch):
Expand All @@ -79,23 +110,51 @@ async def test_custom_logout(monkeypatch):
assert authenticator.logout_url('http://myhost') == 'http://myhost/logout'

# Check redirection to the custom logout url
authenticator.auth0_domain = auth0_domain
authenticator.auth0_domain = AUTH0_DOMAIN
await logout_handler.get()
custom_logout_url = f'https://{auth0_domain}/v2/logout'
custom_logout_url = f'https://{AUTH0_DOMAIN}/v2/logout'
logout_handler.redirect.assert_called_with(custom_logout_url)


async def test_deprecated_config(caplog):
cfg = Config()
cfg.Auth0OAuthenticator.username_key = 'nickname'
log = logging.getLogger("testlog")
authenticator = Auth0OAuthenticator(config=cfg, log=log)

assert (
log.name,
logging.WARNING,
'Auth0OAuthenticator.username_key is deprecated in Auth0OAuthenticator 16.0.0, use '
'Auth0OAuthenticator.username_claim instead',
) in caplog.record_tuples

assert authenticator.username_claim == 'nickname'
@mark.parametrize(
"test_variation_id,class_config,expect_config,expect_loglevel,expect_message",
[
(
"username_key",
{"username_key": "dummy"},
{"username_claim": "dummy"},
logging.WARNING,
"Auth0OAuthenticator.username_key is deprecated in Auth0OAuthenticator 16.0.0, use Auth0OAuthenticator.username_claim instead",
),
],
)
async def test_deprecated_config(
caplog,
test_variation_id,
class_config,
expect_config,
expect_loglevel,
expect_message,
):
"""
Tests that a warning is emitted when using a deprecated config and that
configuring the old config ends up configuring the new config.
"""
print(f"Running test variation id {test_variation_id}")
c = Config()
c.Auth0OAuthenticator = Config(class_config)

test_logger = logging.getLogger('testlog')
if expect_loglevel == logging.ERROR:
with raises(ValueError, match=expect_message):
Auth0OAuthenticator(config=c, log=test_logger)
else:
authenticator = Auth0OAuthenticator(config=c, log=test_logger)
for key, value in expect_config.items():
assert getattr(authenticator, key) == value

captured_log_tuples = caplog.record_tuples
print(captured_log_tuples)

expected_log_tuple = (test_logger.name, expect_loglevel, expect_message)
assert expected_log_tuple in captured_log_tuples
157 changes: 97 additions & 60 deletions oauthenticator/tests/test_azuread.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,27 @@
from unittest import mock

import jwt
import pytest
from pytest import fixture, mark
from traitlets.config import Config

from ..azuread import AzureAdOAuthenticator
from .mocks import setup_oauth_mock


async def test_tenant_id_from_env():
tenant_id = "some_random_id"
with mock.patch.dict(os.environ, {"AAD_TENANT_ID": tenant_id}):
aad = AzureAdOAuthenticator()
assert aad.tenant_id == tenant_id
@fixture
def azure_client(client):
setup_oauth_mock(
client,
host=['login.microsoftonline.com'],
access_token_path=re.compile('^/[^/]+/oauth2/token$'),
token_request_style='jwt',
)
return client


def user_model(tenant_id, client_id, name):
"""Return a user model"""
# model derived from https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#v20
# id_token derived from https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#v20
now = int(time.time())
id_token = jwt.encode(
{
Expand All @@ -49,62 +53,95 @@ def user_model(tenant_id, client_id, name):
}


@pytest.fixture
def azure_client(client):
setup_oauth_mock(
client,
host=['login.microsoftonline.com'],
access_token_path=re.compile('^/[^/]+/oauth2/token$'),
token_request_style='jwt',
)
return client


@pytest.mark.parametrize(
'username_claim',
@mark.parametrize(
"test_variation_id,class_config,expect_allowed,expect_admin",
[
None,
'name',
'oid',
'preferred_username',
# no allow config tested
("00", {}, False, None),
# allow config, individually tested
("01", {"allow_all": True}, True, None),
("02", {"allowed_users": {"user1"}}, True, None),
("03", {"allowed_users": {"not-test-user"}}, False, None),
("04", {"admin_users": {"user1"}}, True, True),
("05", {"admin_users": {"not-test-user"}}, False, None),
# allow config, some combinations of two tested
(
"10",
{
"allow_all": False,
"allowed_users": {"not-test-user"},
},
False,
None,
),
(
"11",
{
"admin_users": {"user1"},
"allowed_users": {"not-test-user"},
},
True,
True,
),
# test username_claim
(
"20",
{"allow_all": True, "username_claim": "name"},
True,
None,
),
(
"21",
{"allow_all": True, "username_claim": "oid"},
True,
None,
),
(
"22",
{"allow_all": True, "username_claim": "preferred_username"},
True,
None,
),
],
)
async def test_azuread(username_claim, azure_client):
cfg = Config()
cfg.AzureAdOAuthenticator = Config(
{
"tenant_id": str(uuid.uuid1()),
"client_id": str(uuid.uuid1()),
"client_secret": str(uuid.uuid1()),
}
)

if username_claim:
cfg.AzureAdOAuthenticator.username_claim = username_claim

authenticator = AzureAdOAuthenticator(config=cfg)

handler = azure_client.handler_for_user(
user_model(
tenant_id=authenticator.tenant_id,
client_id=authenticator.client_id,
name="somebody",
)
async def test_azuread(
azure_client,
test_variation_id,
class_config,
expect_allowed,
expect_admin,
):
print(f"Running test variation id {test_variation_id}")
c = Config()
c.AzureAdOAuthenticator = Config(class_config)
c.AzureAdOAuthenticator.tenant_id = str(uuid.uuid1())
c.AzureAdOAuthenticator.client_id = str(uuid.uuid1())
c.AzureAdOAuthenticator.client_secret = str(uuid.uuid1())
authenticator = AzureAdOAuthenticator(config=c)

handled_user_model = user_model(
tenant_id=authenticator.tenant_id,
client_id=authenticator.client_id,
name="user1",
)
handler = azure_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"}
assert auth_model["admin"] == expect_admin
auth_state = auth_model["auth_state"]
assert "access_token" in auth_state
user_info = auth_state[authenticator.user_auth_state_key]
assert user_info["aud"] == authenticator.client_id
assert auth_model["name"] == user_info[authenticator.username_claim]
else:
assert auth_model == None

auth_model = await authenticator.authenticate(handler)
assert sorted(auth_model) == ['admin', 'auth_state', 'name']

auth_state = auth_model['auth_state']
assert 'access_token' in auth_state
assert 'user' in auth_state

auth_state_user_info = auth_state['user']
assert auth_state_user_info['aud'] == authenticator.client_id

username = auth_model['name']
if username_claim:
assert username == auth_state_user_info[username_claim]
else:
# The default AzureADOAuthenticator `username_claim` is "name"
assert username == auth_state_user_info["name"]
async def test_tenant_id_from_env():
tenant_id = "some_random_id"
with mock.patch.dict(os.environ, {"AAD_TENANT_ID": tenant_id}):
aad = AzureAdOAuthenticator()
assert aad.tenant_id == tenant_id
Loading

0 comments on commit 0e2352e

Please sign in to comment.