Skip to content

Commit

Permalink
more refactoring (wip) (#1999)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Oct 8, 2024
1 parent 4581a13 commit 98af57a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 44 deletions.
2 changes: 1 addition & 1 deletion irodsbackend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# NOTE: Not exactly REST API view, but URL maintained for backwards comp
path(
route='api/auth',
view=views.BasicAuthView.as_view(),
view=views.BasicAuthAPIView.as_view(),
name='api_auth',
),
]
50 changes: 15 additions & 35 deletions irodsbackend/views.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
"""Views for the irodsbackend app"""

import base64
import logging

from django.conf import settings
from django.contrib.auth import authenticate
from django.http import HttpResponse, JsonResponse
from django.views.generic import View

from django.http import JsonResponse
from rest_framework.response import Response
from rest_framework.views import APIView

from knox.auth import TokenAuthentication
from sodar.users.auth import fallback_to_auth_basic

# Projectroles dependency
from projectroles.models import SODAR_CONSTANTS
Expand Down Expand Up @@ -232,56 +229,39 @@ def get(self, request, *args, **kwargs):
# Basic Auth View --------------------------------------------------------------


class BasicAuthView(View):
# NOTE: Must be based on APIView to avoid CSRF token check
@fallback_to_auth_basic
class BasicAuthAPIView(APIView):
"""
View for verifying login credentials for OIDC and local users in iRODS. Does
not log in the user.
REST API view for verifying login credentials for local users in iRODS.
To be used in environments enabling OIDC access and/or where external
LDAP/AD login is not available.
Should only be used in local development and testing situations or when an
external LDAP/AD login is not available.
"""

http_method_names = ['post']

def post(self, request, *args, **kwargs):
# TODO: Fix so that we actually get here with a token request
if not settings.IRODS_SODAR_AUTH:
logger.error(
'{} failed: {}'.format(
BASIC_AUTH_LOG_PREFIX, BASIC_AUTH_NOT_ENABLED_MSG
)
)
return HttpResponse(BASIC_AUTH_NOT_ENABLED_MSG, status=500)
if 'HTTP_AUTHORIZATION' not in request.META:
return HttpResponse('Auth header not included', status=400)
user_name = None
user = None
auth = request.META['HTTP_AUTHORIZATION'].split()
if len(auth) == 2 and auth[0].lower() == 'basic':
user_name, password = base64.b64decode(auth[1]).decode().split(':')
logger.debug(
'Basic auth requested with user name "{}"'.format(user_name)
return JsonResponse(
{'detail': BASIC_AUTH_NOT_ENABLED_MSG}, status=500
)
# First try with password
user = authenticate(username=user_name, password=password)
# If not successful, try password as Knox token
if not user:
token_auth = TokenAuthentication()
try:
user, _ = token_auth.authenticate_credentials(
password.encode('utf-8')
)
except Exception as ex:
logger.debug('Basic auth with token failed: {}'.format(ex))
if user and user.is_authenticated and user.username == user_name:
if request.user.is_authenticated:
logger.info(
'{} successful: {}'.format(
BASIC_AUTH_LOG_PREFIX, request.user.username
)
)
return HttpResponse('Authenticated', status=200)
return JsonResponse({'detail': 'Authenticated'}, status=200)
logger.error(
'{} failed: User {} not authenticated'.format(
BASIC_AUTH_LOG_PREFIX, request.user.username
)
)
return HttpResponse('Unauthorized', status=401)
return JsonResponse({'detail': 'Unauthorized'}, status=401)
31 changes: 23 additions & 8 deletions sodar/users/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import base64

from functools import wraps

from django.conf import settings
Expand All @@ -12,6 +13,8 @@
from django.utils.decorators import method_decorator, decorator_from_middleware
from django.utils.deprecation import MiddlewareMixin

from knox.auth import TokenAuthentication


class FallbackToAuthBasicMiddleware(MiddlewareMixin):
"""
Expand All @@ -30,17 +33,29 @@ def process_request(self, request):
# Allow disabling of basic auth alltogether in configuration.
if getattr(settings, 'BASICAUTH_DISABLE', False):
return

# When user is not logged in, try to login via HTTP_AUTHORIZATION
# header. If this header is not set, send the response to ask for
# Auth Basic.
if 'HTTP_AUTHORIZATION' in request.META:
auth = request.META['HTTP_AUTHORIZATION'].split()
if len(auth) == 2 and auth[0].lower() == 'basic':
uname, passwd = base64.b64decode(auth[1]).decode().split(':')
user = authenticate(username=uname, password=passwd)
if user:
login(request, user)
if 'HTTP_AUTHORIZATION' not in request.META:
return
auth = request.META['HTTP_AUTHORIZATION'].split()
if len(auth) == 2 and auth[0].lower() == 'basic':
uname, passwd = base64.b64decode(auth[1]).decode().split(':')
user = authenticate(username=uname, password=passwd)
if user:
login(request, user)
# If not authenticated, try token
token_auth = TokenAuthentication()
try:
user, _ = token_auth.authenticate_credentials(
passwd.encode('utf-8')
)
except Exception:
return
if user and user.is_authenticated and user.username == uname:
# TODO: How to log in user with token here?
# TODO: Currently we return response here skipping view method..
return HttpResponse(status=200)

def process_response(self, request, response):
if not request.user.is_authenticated:
Expand Down

0 comments on commit 98af57a

Please sign in to comment.