Exemplo n.º 1
0
def test_existing_user_is_escalated_to_superuser_group(rf, settings, django_user_model):
    """
    If an existing user is added to a superuser group they should
    be escalated to a superuser.
    """
    settings.OKTA_AUTH = update_okta_settings(
        settings.OKTA_AUTH, "SUPERUSER_GROUP", SUPERUSER_GROUP
    )

    user = django_user_model._default_manager.create_user(
        username="******", email="*****@*****.**"
    )

    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint",
        get_superuser_token_result,
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_refresh_token("refresh")
        assert isinstance(user, django_user_model)
        assert user.is_superuser
Exemplo n.º 2
0
def test_user_is_removed_from_groups(rf, settings, django_user_model):
    """
    When MANAGE_GROUPS is true a user should be removed from a
    group if it's not included in the token response.
    """
    settings.OKTA_AUTH = update_okta_settings(settings.OKTA_AUTH, "MANAGE_GROUPS", True)

    user = django_user_model._default_manager.create_user(
        username="******", email="*****@*****.**"
    )
    group = Group.objects.create(name="test-group")

    user.groups.add(group)

    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint",
        get_normal_user_with_groups_token,
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_refresh_token("refresh")

        groups = user.groups.all()
        assert [("one",), ("two",)] == list(groups.values_list("name"))
Exemplo n.º 3
0
def test_existing_superuser_is_deescalated_from_staff_group(
    rf, settings, django_user_model
):
    """
    If an existing user is removed from a staff group they should
    have the staff flag removed.
    """
    settings.OKTA_AUTH = update_okta_settings(
        settings.OKTA_AUTH, "STAFF_GROUP", STAFF_GROUP
    )

    user = django_user_model._default_manager.create_user(
        username="******",
        email="*****@*****.**",
        is_staff=True,
    )

    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint",
        get_normal_user_with_groups_token,
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_refresh_token("refresh")
        assert isinstance(user, django_user_model)
        assert user.is_staff is False
Exemplo n.º 4
0
def test_validate_token_successfully_validates(rf):
    """ A valid token should return the decoded token. """
    token = build_id_token()
    c = Config()
    with patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        decoded_token = tv.validate_token(token)
        assert decoded_token["jti"] == "randomid"
Exemplo n.º 5
0
def test_conf_raises_error_if_no_settings(settings):
    """
    if there's no OKTA_AUTH in settings then we should
    be raising an ImproperlyConfigured exception.
    """
    del settings.OKTA_AUTH
    with pytest.raises(ImproperlyConfigured):
        Config()
Exemplo n.º 6
0
def test_jwks_returns_if_none_found(rf):
    """ The _jwks method should return None if no key is found. """
    c = Config()

    with patch(
        "okta_oauth2.tokens.TokenValidator.request_jwks", mock_request_jwks
    ), patch("okta_oauth2.tokens.DiscoveryDocument", MagicMock()):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        assert tv._jwks("notakey") is None
def test_no_key_raises_invalid_token(rf):
    """
    If we dont' have a key at all we should be raising an InvalidTokenSignature.
    """
    token = build_id_token()
    c = Config()
    with patch("okta_oauth2.tokens.TokenValidator._jwks",
               Mock(return_value=None)), pytest.raises(InvalidTokenSignature):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 8
0
def test_handle_token_result_handles_missing_tokens(rf):
    """
    If we didn't get any tokens back, don't return a user
    and return the empty token dict so we can check why later.
    """
    c = Config()
    req = rf.get("/")

    tv = TokenValidator(c, "defaultnonce", req)
    result = tv.handle_token_result({})
    assert result == (None, {})
def test_unmatching_nonce_raises_error(rf):
    """
    If our token has the wrong nonce then raise a NonceDoesNotMatch
    """
    token = build_id_token(nonce="wrong-nonce")
    c = Config()

    with patch("okta_oauth2.tokens.TokenValidator._jwks",
               Mock(return_value="secret")), pytest.raises(NonceDoesNotMatch):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 10
0
def test_expired_token_raises_error(rf):
    """
    If our token is expired then we should raise an TokenExpired.
    """
    token = build_id_token(exp=now().timestamp() - 3600)
    c = Config()

    with patch("okta_oauth2.tokens.TokenValidator._jwks",
               Mock(return_value="secret")), pytest.raises(TokenExpired):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 11
0
def test_invalid_audience_in_decoded_token(rf):
    """
    If our audience doesn't match our client id we should raise an InvalidClientID
    """
    token = build_id_token(aud="invalid-aud")
    c = Config()

    with patch("okta_oauth2.tokens.TokenValidator._jwks",
               Mock(return_value="secret")), pytest.raises(InvalidClientID):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 12
0
def test_invalid_issuer_in_decoded_token(rf):
    """
    If our issuers don't match we should raise an IssuerDoesNotMatch.
    """
    token = build_id_token(iss="invalid-issuer")
    c = Config()

    with patch("okta_oauth2.tokens.TokenValidator._jwks",
               Mock(return_value="secret")), pytest.raises(IssuerDoesNotMatch):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 13
0
def test_jwks_returns_cached_key(rf):
    """
    _jwks method should return a cached key if
    there's one in the cache with a matching ID.
    """
    c = Config()
    tv = TokenValidator(c, "defaultnonce", rf.get("/"))
    cache = caches[c.cache_alias]
    cache.set(tv.cache_key, [KEY_1], c.cache_timeout)
    key = tv._jwks(KEY_1["kid"])
    assert key == KEY_1
Exemplo n.º 14
0
def test_wrong_key_raises_invalid_token(rf):
    """
    If we get the wrong key then we should be raising an InvalidTokenSignature.
    """
    token = build_id_token()
    c = Config()
    with patch(
        "okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="wrongkey")
    ), pytest.raises(InvalidTokenSignature):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 15
0
def test_request_jwks(mock_get, rf):
    """ Test jwks method returns json """
    mock_get.return_value = Mock(ok=True)
    mock_get.return_value.json.return_value = mock_request_jwks(None)

    c = Config()

    with patch("okta_oauth2.tokens.TokenValidator._discovery_document", MagicMock()):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        result = tv.request_jwks()
        assert result == mock_request_jwks(None)
Exemplo n.º 16
0
def test_issue_time_is_too_far_in_the_past_raises_error(rf):
    """
    If our token was issued more than about 24 hours ago
    we want to raise a TokenTooFarAway.
    """
    token = build_id_token(iat=now().timestamp() - 200000)
    c = Config()

    with patch("okta_oauth2.tokens.TokenValidator._jwks",
               Mock(return_value="secret")), pytest.raises(TokenTooFarAway):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.validate_token(token)
Exemplo n.º 17
0
def test_invalid_public_named_urls_are_ignored(settings):
    """
    We don't want to crash if our public named urls don't
    exist, instead just skip it.
    """
    settings.OKTA_AUTH = update_okta_settings(settings.OKTA_AUTH,
                                              "PUBLIC_NAMED_URLS",
                                              ("not-a-valid-url", ))
    config = Config()
    assert config.public_urls == [
        re.compile("^/accounts/login/$"),
        re.compile("^/accounts/logout/$"),
        re.compile("^/accounts/oauth2/callback/$"),
    ]
Exemplo n.º 18
0
def test_public_named_urls_are_built(settings):
    """
    We should have reversed url regexes to match against
    in our config objects.
    """
    settings.OKTA_AUTH = update_okta_settings(settings.OKTA_AUTH,
                                              "PUBLIC_NAMED_URLS",
                                              ("named-url", ))
    config = Config()
    assert config.public_urls == [
        re.compile("^/named/$"),
        re.compile("^/accounts/login/$"),
        re.compile("^/accounts/logout/$"),
        re.compile("^/accounts/oauth2/callback/$"),
    ]
Exemplo n.º 19
0
def test_token_validator_gets_token_from_refresh_token(rf, django_user_model):
    """
    We should get our tokens back with a user.
    """
    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint", get_token_result
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_refresh_token("refresh")
        assert "access_token" in tokens
        assert "id_token" in tokens
        assert isinstance(user, django_user_model)
Exemplo n.º 20
0
def test_user_username_setting_returns_user_by_username_and_not_email(
    rf, settings, django_user_model
):
    settings.OKTA_AUTH = update_okta_settings(settings.OKTA_AUTH, "USE_USERNAME", True)

    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint", get_token_result
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_auth_code("authcode")
        assert isinstance(user, django_user_model)
        assert user.username == "fakemail"
        assert user.username != "*****@*****.**"
Exemplo n.º 21
0
def test_jwks_sets_cache_and_returns(rf):
    """
    _jwks method should request keys from okta,
    and if they match the key we're looking for,
    cache and return it.
    """
    c = Config()

    with patch(
        "okta_oauth2.tokens.TokenValidator.request_jwks", mock_request_jwks
    ), patch("okta_oauth2.tokens.DiscoveryDocument", MagicMock()):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        key = tv._jwks(KEY_2["kid"])
        cache = caches[c.cache_alias]
        cached_keys = cache.get(tv.cache_key)
        assert key == KEY_2
        assert KEY_2 in cached_keys
Exemplo n.º 22
0
def test_call_token_endpoint_handles_error(mock_post, rf):
    """
    When we get an error back from the API we should be
    raising an TokenRequestFailed error.
    """
    mock_post.return_value = Mock(ok=True)
    mock_post.return_value.json.return_value = {
        "error": "failure",
        "error_description": "something went wrong",
    }
    endpoint_data = {"grant_type": "authorization_code", "code": "imacode"}

    c = Config()
    MockDiscoveryDocument = MagicMock()

    with patch("okta_oauth2.tokens.DiscoveryDocument",
               MockDiscoveryDocument), pytest.raises(TokenRequestFailed):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tv.call_token_endpoint(endpoint_data)
Exemplo n.º 23
0
def test_groups_are_created_and_user_added(rf, settings, django_user_model):
    """
    If MANAGE_GROUPS is true the groups should be created and the user
    should be added to them.
    """
    settings.OKTA_AUTH = update_okta_settings(settings.OKTA_AUTH, "MANAGE_GROUPS", True)

    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint",
        get_normal_user_with_groups_token,
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_refresh_token("refresh")

        groups = Group.objects.all()
        assert [("one",), ("two",)] == list(groups.values_list("name"))
        assert list(user.groups.all()) == list(Group.objects.all())
Exemplo n.º 24
0
def test_created_user_if_part_of_superuser_group(rf, settings, django_user_model):
    """
    If the user is part of the superuser group defined
    in settings make sure that the created user is a superuser.
    """
    settings.OKTA_AUTH = update_okta_settings(
        settings.OKTA_AUTH, "SUPERUSER_GROUP", SUPERUSER_GROUP
    )

    c = Config()
    req = rf.get("/")
    add_session(req)

    with patch(
        "okta_oauth2.tokens.TokenValidator.call_token_endpoint",
        get_superuser_token_result,
    ), patch("okta_oauth2.tokens.TokenValidator._jwks", Mock(return_value="secret")):
        tv = TokenValidator(c, "defaultnonce", req)
        user, tokens = tv.tokens_from_refresh_token("refresh")
        assert isinstance(user, django_user_model)
        assert user.is_superuser
Exemplo n.º 25
0
def test_call_token_endpoint_returns_tokens(mock_post, rf):
    """
    when we call the token endpoint with valid data we expect
    to receive a bunch of tokens. See assertions to understand which.
    """
    mock_post.return_value = Mock(ok=True)
    mock_post.return_value.json.return_value = {
        "access_token": build_access_token(),
        "id_token": build_id_token(),
        "refresh_token": "refresh",
    }
    endpoint_data = {"grant_type": "authorization_code", "code": "imacode"}

    c = Config()
    MockDiscoveryDocument = MagicMock()

    with patch("okta_oauth2.tokens.DiscoveryDocument", MockDiscoveryDocument):
        tv = TokenValidator(c, "defaultnonce", rf.get("/"))
        tokens = tv.call_token_endpoint(endpoint_data)
        assert "access_token" in tokens
        assert "id_token" in tokens
        assert "refresh_token" in tokens
Exemplo n.º 26
0
def build_access_token(
    aud=None, auth_time=None, exp=None, iat=None, iss=None, sub=None, uid=None
):
    config = Config()

    current_timestamp = now().timestamp()
    iat_offset = 2

    headers = {"alg": "HS256", "kid": "abcdefg"}

    claims = {
        "ver": 1,
        "jti": "randomid",
        "iss": iss if iss else config.issuer,
        "aud": aud if aud else config.client_id,
        "sub": sub if sub else config.client_id,
        "iat": iat if iat else current_timestamp + iat_offset,
        "exp": exp if exp else current_timestamp + iat_offset + 3600,
        "uid": uid if uid else config.client_id,
        "scp": ["openid", "email", "offline_access", "groups"],
    }

    return jwt.encode(claims, "secret", headers=headers, algorithm="HS256")
Exemplo n.º 27
0
def build_id_token(
    aud=None,
    auth_time=None,
    exp=None,
    iat=None,
    iss=None,
    sub=None,
    nonce="defaultnonce",
    groups=[],
):
    config = Config()

    current_timestamp = now().timestamp()
    iat_offset = 2

    claims = {
        "amr": ["pwd"],
        "at_hash": "notarealhash",
        "aud": aud if aud else config.client_id,
        "auth_time": auth_time if auth_time else current_timestamp,
        "email": "*****@*****.**",
        "exp": exp if exp else current_timestamp + iat_offset + 3600,
        "iat": iat if iat else current_timestamp + iat_offset,
        "idp": aud if aud else config.client_id,
        "iss": iss if iss else config.issuer,
        "jti": "randomid",
        "name": "A User",
        "nonce": nonce,
        "preferred_username": "******",
        "sub": sub if sub else config.client_id,
        "ver": 1,
        "groups": groups,
    }

    headers = {"kid": "1A234567890"}

    return jwt.encode(claims, "secret", headers=headers, algorithm="HS256")