Skip to content

Commit

Permalink
drop deprecated OIDC code and any remaining python 2 references
Browse files Browse the repository at this point in the history
  • Loading branch information
guruofgentoo committed Dec 6, 2022
1 parent 26bc0d2 commit 10b1144
Show file tree
Hide file tree
Showing 16 changed files with 21 additions and 302 deletions.
4 changes: 2 additions & 2 deletions docs/source/getting-started.rst
Expand Up @@ -13,7 +13,7 @@ Installation
- With mail (i.e. with a mail manager configured, see below): `pip install keg-auth[mail]`
- JWT (for using JWT tokens as authenticators): `pip install keg-auth[jwt]`
- LDAP (for using LDAP target for authentication): `pip install keg-auth[ldap]`
- OIDC (for OAuth, e.g. Okta or Auth0): `pip install keg-auth[oidc]`
- OAuth (e.g. Google Auth): `pip install keg-auth[oauth]`
- Internationalization extensions: `pip install keg-auth[i18n]`


Expand Down Expand Up @@ -510,7 +510,7 @@ logged-in user during testing:
class TestViews(object):
def setup(self):
def setup_method(self):
ents.User.delete_cascaded()
def test_authenticated_client(self):
Expand Down
7 changes: 0 additions & 7 deletions keg_auth/core.py
Expand Up @@ -127,13 +127,6 @@ def init_config(self, app):
# OAuth profiles
app.config.setdefault('KEGAUTH_OAUTH_PROFILES', [])

# Set defaults for OIDC URI locations
app.config.setdefault('OIDC_AUTH_URI', '/oauth2/v1/authorize')
app.config.setdefault('OIDC_TOKEN_URI', '/oauth2/v1/token')
app.config.setdefault('OIDC_ISSUER', '/oauth2')
app.config.setdefault('OIDC_USERINFO_URI', '/oauth2/userinfo')
app.config.setdefault('KEGAUTH_OIDC_LOGOUT_REDIRECT', None)

# Attempt lockout parameters.
# - Enabled: default True, turns on attempt limits and requires the attempt entity.
# - Limit: maximum number of attempts within the timespan.
Expand Down
144 changes: 0 additions & 144 deletions keg_auth/libs/authenticators.py
Expand Up @@ -977,150 +977,6 @@ def ldap_bind(server_url):
return False


class OidcLoginViewResponder(LoginResponderMixin, ViewResponder):
""" OIDC logins, using an oauth token"""

flash_success = None
page_title = 'Log In'
template_name = 'keg_auth/flash-messages-only.html'

def __init__(self, parent):
warnings.warn(OidcAuthenticator.usage_warning, DeprecationWarning, 2)
super().__init__(parent)

def get(self, *args, **kwargs):
oidc = flask.current_app.auth_manager.oidc
oidc_check = oidc.require_login(lambda: True)()
if oidc_check is not True:
return oidc_check

login_id = oidc.user_getfield("preferred_username")

try:
user = self.parent.verify_user(login_id=login_id)

# User is active and password is verified
return self.on_success(user)
except UserNotFound:
self.on_invalid_user(login_id)
except UserInactive as exc:
self.on_inactive_user(exc.user)

def head(self, *args, **kwargs):
return flask.abort(405, valid_methods=['GET'])

def post(self, *args, **kwargs):
return flask.abort(405, valid_methods=['GET'])


class OidcLogoutViewResponder(LogoutViewResponder):
""" OIDC logout requires some extra leg-work, because token gets refreshed server-side"""

def __init__(self, parent):
warnings.warn(OidcAuthenticator.usage_warning, DeprecationWarning, 2)
super().__init__(parent)

def get(self):
oidc = flask.current_app.auth_manager.oidc
url_login = flask.url_for(flask.current_app.auth_manager.endpoint('login'))
url_after_login = flask.url_for(flask.current_app.auth_manager.endpoint('after-login'))
bad_token_redirect_resp = flask.current_app.login_manager.unauthorized()

url_only_redirect = flask.current_app.config.get('KEGAUTH_OIDC_LOGOUT_REDIRECT')
if url_only_redirect:
flask_login.logout_user()
return flask.abort(flask.redirect(url_only_redirect))

""" Logout won't work if user isn't authenticated to begin with, i.e. there won't be a
token to use. Just redirect to a sane place to force a login to continue."""
try:
user_sub = oidc.user_getfield('sub')
except Exception as exc:
if 'User was not authenticated' not in str(exc):
raise
return flask.abort(flask.redirect(url_login))

""" In some cases e.g. app restart, credentials store may not have valid information in the
flask server-side info. In that case, clear the client token and refresh info from
the oauth source. We have to have a valid id token to make logout work."""
try:
from oauth2client.client import OAuth2Credentials
id_token = OAuth2Credentials.from_json(
oidc.credentials_store[user_sub]
).token_response['id_token']
except KeyError:
oidc.logout()
return flask.abort(bad_token_redirect_resp)

""" Build the oauth request URI, which has to include the ID token. But, logout all client
session info before redirecting there."""
logout_request = '{}{}?id_token_hint={}&post_logout_redirect_uri={}'.format(
flask.current_app.config.get('OIDC_PROVIDER_URL'),
flask.current_app.config.get('OIDC_LOGOUT'),
str(id_token),
flask.current_app.config.get('OIDC_REDIRECT_BASE') + url_after_login,
)
oidc.logout()
flask_login.logout_user()
return flask.redirect(logout_request)


class OidcAuthenticator(LoginAuthenticator):
""" Uses OIDC authentication with an oauth provider, validates against keg-auth db.
Warning: Deprecated.
"""
responder_cls = {
'login': OidcLoginViewResponder,
'logout': OidcLogoutViewResponder,
}
usage_warning = (
'All OIDC objects are now deprecated and will be removed in a future version. Use the '
'OAuth authenticator alongside either a password authenticator or a redirect. '
'flask-oidc formed the core of this authenticator but has not received much maintenance '
'in the last few years. At this time, the library is depending on deprecated/removed '
'items in other libraries (such as itsdangerous) and will need to be updated to be '
'reliably operational again.'
)

def __init__(self, app):
warnings.warn(self.usage_warning, DeprecationWarning, 2)

from flask_oidc import OpenIDConnect

oidc_settings = {
'web': {
'client_id': app.config.get('OIDC_CLIENT_ID'),
'client_secret': app.config.get('OIDC_CLIENT_SECRET'),
'auth_uri': app.config.get('OIDC_PROVIDER_URL') + app.config.get('OIDC_AUTH_URI'),
'token_uri': app.config.get('OIDC_PROVIDER_URL') + app.config.get('OIDC_TOKEN_URI'),
'issuer': app.config.get('OIDC_PROVIDER_URL') + app.config.get('OIDC_ISSUER'),
'userinfo_uri': app.config.get('OIDC_PROVIDER_URL')
+ app.config.get('OIDC_USERINFO_URI'),
'redirect_uris': [
app.config.get('OIDC_REDIRECT_BASE') + app.config.get('OIDC_CALLBACK_ROUTE')
]
}
}

class KAOpenIDConnect(OpenIDConnect):
def load_secrets(self, app):
return oidc_settings
app.auth_manager.oidc = KAOpenIDConnect(app)

super().__init__(app)

def verify_user(self, login_id=None):
user = self.user_ent.query.filter_by(username=login_id).one_or_none()

if not user:
raise UserNotFound
if not user.is_active:
raise UserInactive(user)

return user


class JwtRequestLoader(TokenLoaderMixin, RequestLoader):
""" Loader for JWT tokens contained in the Authorization header.
Expand Down
9 changes: 3 additions & 6 deletions keg_auth/testing.py
@@ -1,6 +1,3 @@
# Using unicode_literals instead of adding 'u' prefix to all stings that go to SA.
from __future__ import unicode_literals

from datetime import timedelta
from unittest import mock
from urllib.parse import quote
Expand Down Expand Up @@ -52,7 +49,7 @@ class AuthAttemptTests(object):
('success', 'Password changed. Please use the new password to login below.')
]

def setup(self):
def setup_method(self):
if has_attempt_model:
self.attempt_ent.delete_cascaded()

Expand Down Expand Up @@ -623,8 +620,8 @@ class AuthTests(AuthAttemptTests):
protected_url = '/secret1'
protected_url_permissions = None

def setup(self):
super().setup()
def setup_method(self):
super().setup_method()
self.user_ent.delete_cascaded()

def test_login_get(self):
Expand Down
2 changes: 1 addition & 1 deletion keg_auth/tests/test_auth_manager.py
Expand Up @@ -11,7 +11,7 @@


class TestAuthManager(object):
def setup(self):
def setup_method(self):
ents.Permission.delete_cascaded()
ents.User.delete_cascaded()
self.am = flask.current_app.auth_manager
Expand Down
2 changes: 1 addition & 1 deletion keg_auth/tests/test_authenticators.py
Expand Up @@ -159,7 +159,7 @@ def test_bad_profile(self):


class TestLdapAuthenticator:
def setup(self):
def setup_method(self):
flask.current_app.config['KEGAUTH_LDAP_SERVER_URL'] = 'abc123'
flask.current_app.config['KEGAUTH_LDAP_DN_FORMAT'] = '{}'

Expand Down
2 changes: 1 addition & 1 deletion keg_auth/tests/test_cli.py
Expand Up @@ -9,7 +9,7 @@

class TestCLI(CLIBase):

def setup(self):
def setup_method(self):
ents.UserNoEmail.delete_cascaded()
ents.User.delete_cascaded()
ents.Attempt.delete_cascaded()
Expand Down
5 changes: 1 addition & 4 deletions keg_auth/tests/test_forms.py
@@ -1,6 +1,3 @@
# Using unicode_literals instead of adding 'u' prefix to all stings that go to SA.
from __future__ import unicode_literals

from blazeutils.strings import randchars
import pytest
from flask import current_app
Expand Down Expand Up @@ -179,7 +176,7 @@ def setup_class(cls):
cls.groups = [ents.Group.testing_create() for _ in range(3)]
cls.bundles = [ents.Bundle.testing_create() for _ in range(3)]

def setup(self):
def setup_method(self):
ents.User.delete_cascaded()

def ok_data(self, **kwargs):
Expand Down
5 changes: 1 addition & 4 deletions keg_auth/tests/test_mail.py
@@ -1,6 +1,3 @@
# Using unicode_literals instead of adding 'u' prefix to all stings that go to SA.
from __future__ import unicode_literals

import flask
from keg_auth import mail
import mock
Expand Down Expand Up @@ -28,7 +25,7 @@ class TestAuthMailManager(object):
def setup_class(cls):
cls.mb = mail.AuthMailManager(mail_ext)

def setup(self):
def setup_method(self):
ents.User.delete_cascaded()

def test_reset_password_message(self):
Expand Down
16 changes: 7 additions & 9 deletions keg_auth/tests/test_model.py
@@ -1,5 +1,3 @@
# Using unicode_literals instead of adding 'u' prefix to all stings that go to SA.
from __future__ import unicode_literals
import base64
import hashlib
import string
Expand All @@ -20,7 +18,7 @@


class TestUserTokenMixin(object):
def setup(self):
def setup_method(self):
ents.UserWithToken.delete_cascaded()

@with_crypto_context(ents.UserWithToken.token)
Expand Down Expand Up @@ -99,7 +97,7 @@ def test_get_user_for_api_token_bad_token(self, token):


class TestUser(object):
def setup(self):
def setup_method(self):
ents.User.delete_cascaded()
ents.Permission.delete_cascaded()

Expand Down Expand Up @@ -402,7 +400,7 @@ def test_disabling_user_does_not_clear_disabled_utc(self):


class TestUserNoEmail(object):
def setup(self):
def setup_method(self):
ents.UserNoEmail.delete_cascaded()

@pytest.mark.parametrize('is_enabled, disabled_utc, is_active', [
Expand Down Expand Up @@ -435,7 +433,7 @@ def test_is_active_sql_expression(self, is_enabled, disabled_utc, is_active):


class TestPermission(object):
def setup(self):
def setup_method(self):
ents.Permission.delete_cascaded()

def test_token_unique(self):
Expand All @@ -449,7 +447,7 @@ def test_token_unique(self):


class TestBundle(object):
def setup(self):
def setup_method(self):
ents.Bundle.delete_cascaded()

def test_name_unique(self):
Expand Down Expand Up @@ -552,7 +550,7 @@ def test_non_permission_update_does_not_reset_user_session_keys(self):


class TestGroup(object):
def setup(self):
def setup_method(self):
ents.Group.delete_cascaded()

def test_name_unique(self):
Expand Down Expand Up @@ -742,7 +740,7 @@ class TestingPermission(object):


class TestPermissionsConditions:
def setup(self):
def setup_method(self):
ents.Permission.delete_cascaded()
ents.User.delete_cascaded()

Expand Down
5 changes: 1 addition & 4 deletions keg_auth/tests/test_navigation.py
@@ -1,6 +1,3 @@
# Using unicode_literals instead of adding 'u' prefix to all stings that go to SA.
from __future__ import unicode_literals

import sys
from unittest import mock

Expand Down Expand Up @@ -66,7 +63,7 @@ class TestNavItem(object):
Tests of node permissions are user-oriented, so we have to run these in a request context
"""

def setup(self):
def setup_method(self):
self.Permission = flask.current_app.auth_manager.entity_registry.permission_cls
self.Permission.delete_cascaded()

Expand Down

0 comments on commit 10b1144

Please sign in to comment.