Skip to content

Commit

Permalink
Refactor web views to be more congruent
Browse files Browse the repository at this point in the history
  • Loading branch information
dkmstr committed Sep 29, 2024
1 parent d4696b1 commit 0306ed5
Show file tree
Hide file tree
Showing 7 changed files with 449 additions and 416 deletions.
80 changes: 46 additions & 34 deletions server/src/uds/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,23 @@

from uds import REST
from uds.core import types
import uds.web.views
import uds.admin.views

from uds.core.util.modfinder import get_urlpatterns_from_modules

from uds.web.views import (
auth,
errors,
main,
mfa,
service,
download,
custom,
images,
)

# Admin
import uds.admin.views


urlpatterns = [
# Root url placeholder
Expand Down Expand Up @@ -71,110 +83,110 @@
# Old urls for federated authentications
re_path(
r'^auth/(?P<authenticator_name>.+)',
uds.web.views.auth_callback,
auth.auth_callback,
name='page.auth.callback.compat',
),
re_path(
r'^authinfo/(?P<authenticator_name>.+)',
uds.web.views.auth_info,
auth.auth_info,
name='page.auth.info.compat',
),
# Ticket authentication
re_path(
r'^tkauth/(?P<ticket_id>[a-zA-Z0-9-]+)$',
uds.web.views.ticket_auth,
auth.ticket_auth,
name='page.auth.ticket.compat',
),
# END COMPAT
# Index
path(
r'uds/page/services',
uds.web.views.main.index,
main.index,
name='page.index',
),
# Login/logouty
# Login/logout
path(
r'uds/page/login',
uds.web.views.main.login,
auth.login,
name=types.auth.AuthenticationInternalUrl.LOGIN.value,
),
re_path(
r'^uds/page/login/(?P<tag>[a-zA-Z0-9-]+)$',
uds.web.views.main.login,
auth.login,
name=types.auth.AuthenticationInternalUrl.LOGIN_LABEL.value,
),
path(
r'uds/page/logout',
uds.web.views.main.logout,
auth.logout,
name=types.auth.AuthenticationInternalUrl.LOGOUT.value,
),
# MFA authentication
path(
r'uds/page/mfa/',
uds.web.views.main.mfa,
mfa.mfa,
name='page.mfa',
),
# Error URL (just a placeholder, calls index with data on url for angular)
re_path(
r'^uds/page/error/(?P<err>[a-zA-Z0-9=-]+)$',
uds.web.views.error,
errors.error,
name='page.error',
),
# Download plugins URL (just a placeholder, calls index with data on url for angular)
path(
r'uds/page/client-download',
uds.web.views.main.index,
main.index,
name='page.client-download',
),
# Federated authentication
re_path(
r'^uds/page/auth/(?P<authenticator_name>[^/]+)$',
uds.web.views.auth_callback,
auth.auth_callback,
name='page.auth.callback',
),
re_path(
r'^uds/page/auth/stage2/(?P<ticket_id>[^/]+)$',
uds.web.views.auth_callback_stage2,
auth.auth_callback_stage2,
name='page.auth.callback_stage2',
),
re_path(
r'^uds/page/auth/info/(?P<authenticator_name>[a-zA-Z0-9.-]+)$',
uds.web.views.auth_info,
auth.auth_info,
name='page.auth.info',
),
# Ticket authentication related
re_path(
r'^uds/page/ticket/auth/(?P<ticket_id>[a-zA-Z0-9.-]+)$',
uds.web.views.ticket_auth,
auth.ticket_auth,
name='page.ticket.auth',
),
path(
r'uds/page/ticket/launcher',
uds.web.views.main.ticket_launcher,
main.ticket_launcher,
name='page.ticket.launcher',
),
# This catch-all must be the last entry in the path uds/page/...
# In fact, client part will process this, but just in case...
re_path(
r'uds/page/.*',
uds.web.views.main.index,
main.index,
name='page.placeholder',
),
# Utility
path(
r'uds/utility/closer',
uds.web.views.service.closer,
service.closer,
name='utility.closer',
),
# Javascript
path(
r'uds/utility/uds.js',
uds.web.views.main.js,
main.js,
name='utility.js',
),
path(
r'uds/adm/utility/uds.js',
uds.web.views.main.js,
main.js,
name='utility-adm.js',
),
# i18n
Expand All @@ -187,71 +199,71 @@
# Downloader
re_path(
r'^uds/utility/download/(?P<download_id>[a-zA-Z0-9-]*)$',
uds.web.views.download,
download.download,
name='utility.downloader',
),
# WEB API path (not REST api, frontend)
re_path(
r'^uds/webapi/img/transport/(?P<transport_id>[a-zA-Z0-9:-]+)$',
uds.web.views.transport_icon,
images.transport_icon,
name='webapi.transport_icon',
),
re_path(
r'^uds/webapi/img/gallery/(?P<image_id>[a-zA-Z0-9-]+)$',
uds.web.views.image,
images.image,
name='webapi.gallery_image',
),
# Enabler and Status action are first processed, and if not match, execute the generic "action" handler
re_path(
r'^uds/webapi/action/(?P<service_id>[a-zA-Z0-9:-]+)/enable/(?P<transport_id>[a-zA-Z0-9:-]+)$',
uds.web.views.user_service_enabler,
service.user_service_enabler,
name='webapi.enabler',
),
re_path(
r'^uds/webapi/action/(?P<service_id>[a-zA-Z0-9:-]+)/status/(?P<transport_id>[a-zA-Z0-9:-]+)$',
uds.web.views.user_service_status,
service.user_service_status,
name='webapi.status',
),
re_path(
r'^uds/webapi/action/(?P<service_id>[a-zA-Z0-9:-]+)/(?P<action_string>[a-zA-Z0-9:-]+)$',
uds.web.views.action,
service.action,
name='webapi.action',
),
# Services list, ...
path(
r'uds/webapi/services',
uds.web.views.main.services_data_json,
service.services_data_json,
name='webapi.services',
),
# Transport own link processor
re_path(
r'^uds/webapi/trans/(?P<service_id>[a-zA-Z0-9:-]+)/(?P<transport_id>[a-zA-Z0-9:-]+)$',
uds.web.views.transport_own_link,
service.transport_own_link,
name='webapi.transport_own_link',
),
# Transport ticket update (for username/password on html5)
re_path(
r'^uds/webapi/trans/ticket/(?P<ticket_id>[a-zA-Z0-9:-]+)/(?P<scrambler>[a-zA-Z0-9:-]+)$',
uds.web.views.main.update_transport_ticket,
service.update_transport_ticket,
name='webapi.transport.update_transport_ticket',
),
# Authenticators custom js
re_path(
r'^uds/webapi/customAuth/(?P<auth_id>[a-zA-Z0-9:-]*)$',
uds.web.views.custom_auth,
auth.custom_auth,
name='uds.web.views.custom_auth',
),
# Error message
re_path(
r'^uds/webapi/error/(?P<err>[0-9]+)$',
uds.web.views.error_message,
errors.error_message,
name='webapi.error',
),
# END WEB API
# Custumization of GUI
re_path(
r'^uds/custom/(?P<component>[a-zA-Z.-]+)$',
uds.web.views.custom.custom,
custom.custom,
name='custom',
),
# REST API
Expand Down
20 changes: 0 additions & 20 deletions server/src/uds/web/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,3 @@
Author: Adolfo Gómez, dkmaster at dkmon dot com
"""
# pyright: reportUnusedImport=false

import logging

# from .login import login, logout
from .service import (
transport_own_link,
transport_icon,
user_service_enabler,
user_service_status,
service_image,
action,
)
from .auth import auth_callback, auth_callback_stage2, auth_info, ticket_auth, custom_auth
from .download import download
from .images import image
from .errors import error, error_message
from . import main
from . import custom

logger = logging.getLogger(__name__)
71 changes: 71 additions & 0 deletions server/src/uds/web/views/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
Author: Adolfo Gómez, dkmaster at dkmon dot com
"""
import logging
import random
import time
import typing

from django.db.models import Q
Expand All @@ -39,6 +41,7 @@
from django.views.decorators.csrf import csrf_exempt

from uds.core import auths, exceptions, types
from uds.core.auths import auth
from uds.core.auths.auth import authenticate_via_callback, log_login, uds_cookie, web_login, web_logout
from uds.core.managers.crypto import CryptoManager
from uds.core.managers.userservice import UserServiceManager
Expand All @@ -48,7 +51,10 @@
from uds.core.util import html
from uds.core.util.model import process_uuid
from uds.models import Authenticator, ServicePool, TicketStore
from uds.web.forms.login_form import LoginForm
from uds.web.util import errors
from uds.web.util.authentication import check_login
from uds.web.views.main import index, logger

if typing.TYPE_CHECKING:
from uds.core.types.requests import ExtendedHttpRequestWithUser
Expand Down Expand Up @@ -288,3 +294,68 @@ def ticket_auth(
except Exception as e:
logger.exception('Exception')
return errors.exception_view(request, e)


@never_cache
def login(request: types.requests.ExtendedHttpRequest, tag: typing.Optional[str] = None) -> HttpResponse:
# Default empty form
tag = tag or request.session.get('tag', None)

logger.debug('Tag: %s', tag)
response: typing.Optional[HttpResponse] = None
if request.method == 'POST':
request.session['restricted'] = False # Access is from login
request.authorized = False # Ensure that on login page, user is unauthorized first

form = LoginForm(request.POST, tag=tag)
login_result = check_login(request, form)
if login_result.user:
response = HttpResponseRedirect(reverse('page.index'))
# Tag is not removed from session, so next login will have it even if not provided
# This means than once an url is used, unless manually goes to "/uds/page/login/xxx"
# The tag will be used again
auth.web_login(
request, response, login_result.user, login_result.password
) # data is user password here

# If MFA is provided, we need to redirect to MFA page
request.authorized = True
if (
login_result.user.manager.get_type().provides_mfa()
and login_result.user.manager.mfa
and login_result.user.groups.filter(skip_mfa=types.states.State.ACTIVE).count() == 0
):
request.authorized = False
response = HttpResponseRedirect(reverse('page.mfa'))

else:
# If redirection on login failure is found, honor it
if login_result.url: # Redirection
return HttpResponseRedirect(login_result.url)

if request.ip not in ('127.0.0.1', '::1'): # If not localhost, wait a bit
time.sleep(
random.SystemRandom().randint(1600, 2400) / 1000
) # On failure, wait a bit if not localhost (random wait)
# If error is numeric, redirect...
if login_result.errid:
return errors.error_view(request, login_result.errid)

# Error, set error on session for process for js
request.session['errors'] = [login_result.errstr]
else:
request.session['tag'] = tag

return response or index(request)


@never_cache
@auth.web_login_required(admin=False)
def logout(request: types.requests.ExtendedHttpRequestWithUser) -> HttpResponse:
auth.log_logout(request)
request.session['restricted'] = False # Remove restricted
request.authorized = False
logoutResponse = request.user.logout(request)
url = logoutResponse.url if logoutResponse.success == types.auth.AuthenticationState.REDIRECT else None

return auth.web_logout(request, url or request.session.get('logouturl', None))
Loading

0 comments on commit 0306ed5

Please sign in to comment.