diff --git a/portal/views/logon.py b/portal/views/logon.py index 1c1dc88..da7e8e6 100644 --- a/portal/views/logon.py +++ b/portal/views/logon.py @@ -36,7 +36,7 @@ # Django project imports from gui.models.application_settings import Application from gui.models.system_settings import Cluster -from portal.views.responses import response_redirect_with_portal_cookie, set_portal_cookie +from portal.views.responses import response_redirect_with_portal_cookie, set_portal_cookie, response_success, response_failure from portal.system.authentications import Authentication, POSTAuthentication, BASICAuthentication, KERBEROSAuthentication, DOUBLEAuthentication from portal.system.sso_forwards import SSOForwardPOST, SSOForwardBASIC, SSOForwardKERBEROS @@ -63,14 +63,14 @@ logger = logging.getLogger('portal_authentication') - - def log_in(request, token_name=None, token=None, proxy_app_id=None): """ Handle authentication in Vulture Portal :param request: Django request object :returns: Home page if user auth succeed. Logon page if auth failed """ + default_authentication_type = None + cluster = Cluster.objects.get() """ Check if URI arguments are valid """ if token_name and token_name != cluster.getTokenName(): @@ -99,7 +99,7 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): # Redis connection error except RedisConnectionError as e: logger.error("PORTAL::log_in: Unable to connect to Redis server : {}".format(str(e))) - return HttpResponseServerError() + return response_failure(HttpResponseServerError(), "authentication") # Token not found while instantiating RedisSession or RedisAppSession except TokenNotFoundError as e: @@ -112,12 +112,12 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): # If "proxy_app_id" not found : FORBIDDEN except (Application.DoesNotExist, InvalidId, ValidationError) as e: logger.error("PORTAL::log_in: Application with id '{}' not found : {}".format(proxy_app_id, str(e))) - return HttpResponseForbidden() + return response_failure(HttpResponseForbidden(), "authentication") # If redis_session.keys['application_id'] does not exists : FORBIDDEN except (Application.DoesNotExist, ValidationError, InvalidId) as e: logger.error("PORTAL::log_in: Application with id '{}' not found".format(authentication.redis_session.keys['application_id'])) - return HttpResponseForbidden() + return response_failure(HttpResponseForbidden(), "authentication") # If assertionError : Ask credentials by portal except AssertionError as e: @@ -128,6 +128,7 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): """ If user is not authenticated : try to retrieve credentials and authenticate him on backend/fallback-backends """ # If the user is not authenticated and application need authentication if not authentication.is_authenticated(): + default_authentication_type = "authentication" try: backend_id = authentication.authenticate_on_backend() if not backend_id: @@ -146,7 +147,7 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): if authentication_results['data'].get('password_expired', None): logger.info("PORTAL::log_in: User '{}' must change its password, redirect to self-service portal".format(authentication.credentials[0])) app_url = authentication.get_url_portal() - return response_redirect_with_portal_cookie(app_url+str(token_name)+'/self/change', portal_cookie_name, portal_cookie, app_url.startswith('https'), None) + return response_success(response_redirect_with_portal_cookie(app_url+str(token_name)+'/self/change', portal_cookie_name, portal_cookie, app_url.startswith('https'), None), "authentication") # If the user is already authenticated (retrieven with RedisPortalSession ) => SSO else: app_cookie, portal_cookie, oauth2_token = authentication.register_sso(backend_id) @@ -154,23 +155,23 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): except AssertionError as e: logger.error("PORTAL::log_in: Bad captcha taped for username '{}' : {}".format(authentication.credentials[0], e)) - return authentication.ask_credentials_response(request=request, error="Bad captcha") + return response_failure(authentication.ask_credentials_response(request=request, error="Bad captcha"), "authentication") except AccountLocked as e: logger.error("PORTAL::log_in: Error while trying to authenticate user '{}' : {}".format(authentication.credentials[0], e)) - return authentication.ask_credentials_response(request=request, error="Bad credentials") + return response_failure(authentication.ask_credentials_response(request=request, error="Bad credentials"), "authentication") except AuthenticationError as e: logger.error("PORTAL::log_in: AuthenticationError while trying to authenticate user '{}' : {}".format(authentication.credentials[0], e)) - return authentication.ask_credentials_response(request=request, error="Bad credentials") + return response_failure(authentication.ask_credentials_response(request=request, error="Bad credentials"), "authentication") except ACLError as e: logger.error("PORTAL::log_in: ACLError while trying to authenticate user '{}' : {}".format(authentication.credentials[0], e)) - return authentication.ask_credentials_response(request=request, error="Bad credentials") + return response_failure(authentication.ask_credentials_response(request=request, error="Bad credentials"), "authentication") except (DBAPIError, PyMongoError, LDAPError) as e: logger.error("PORTAL::log_in: Repository driver Error while trying to authentication user '{}' : {}".format(authentication.credentials[0], e)) - return authentication.ask_credentials_response(request=request, error="Bad credentials") + return response_failure(authentication.ask_credentials_response(request=request, error="Bad credentials"), "authentication") except (MultiValueDictKeyError, AttributeError, KeyError) as e: #vltprtlsrnm is always empty during the initial redirection. Don't log that @@ -179,16 +180,17 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): except REDISWriteError as e: logger.error("PORTAL::log_in: RedisWriteError while trying to register user '{}' informations : {}".format(authentication.credentials[0], e)) - return HttpResponseServerError() + return response_failure(HttpResponseServerError(), "authentication") except Exception as e: logger.exception(e) - return HttpResponseServerError() + return response_failure(HttpResponseServerError(), "authentication") """ If user is not double-authenticated and double-authentication needed : try to retrieve credentials and authenticate him on otp-backend """ # If the user is authenticated but not double-authenticated and double-authentication required if authentication.double_authentication_required(): + default_authentication_type = "otp" logger.info("PORTAL::log_in: Double authentication required for user '{}'".format(authentication.credentials[0])) try: # Instantiate DOUBLEAuthentication object @@ -204,17 +206,17 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): except AssertionError as e: """ If redis_portal_session does not exists or can't retrieve otp key in redis """ logger.error("PORTAL::log_in: DoubleAuthentication failure for username '{}' : {}".format(authentication.credentials[0], str(e))) - return authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error="Portal cookie expired") + return response_failure(authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error="Portal cookie expired"), "otp") except (Application.DoesNotExist, ValidationError, InvalidId) as e: """ Invalid POST 'vulture_two_factors_authentication' value """ logger.error("PORTAL::log_in: Double-authentication failure for username {} : {}".format(authentication.credentials[0], str(e))) - return HttpResponseForbidden("Intrusion attempt blocked") + return response_failure(HttpResponseForbidden("Intrusion attempt blocked"), "otp") except REDISWriteError as e: """ Cannot register double-authentication in Redis : internal server error """ logger.error("PORTAL::log_in: Failed to write double-authentication results in Redis for username '{}' : {}".format(db_authentication.credentials[0], str(e))) - return HttpResponseServerError() + return response_failure(HttpResponseServerError(), "otp") # If authentication failed : create double-authentication key and ask-it except CredentialsError as e: @@ -222,14 +224,15 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): logger.error("PORTAL::log_in: Double-authentication failure for username {} : {}".format(authentication.credentials[0], str(e))) try: db_authentication.create_authentication() - return db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name) + # If we get here, authentication has succeed + return response_success(db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name), "authentication") except (OTPError, REDISWriteError, RedisConnectionError) as e: """ Error while sending/registering in Redis the OTP informations : display portal""" logger.error("PORTAL::log_in: Failed to create/send double-authentication key : {}".format(str(e))) db_authentication.deauthenticate_user() logger.info("PORTAL::log_in: User '{}' successfully deauthenticated due to db-authentication error".format(authentication.credentials[0])) - return authentication.ask_credentials_response(request=request, error=" Error sending OTP Key
"+str(e)) + return response_failure(authentication.ask_credentials_response(request=request, error=" Error sending OTP Key
"+str(e)), "otp") except AuthenticationError as e: """ Bad OTP key """ @@ -238,29 +241,29 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): db_authentication.create_authentication() db_authentication.authentication_failure() logger.debug("PORTAL:log_in: DoubleAuthentication failure successfully registered in Redis") - return db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error=" Bad OTP key ") + return response_failure(db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error=" Bad OTP key "), "otp") except TwoManyOTPAuthFailure as e: logger.error("PORTAL::log_in: Two many OTP authentication failures for username'{}', redirecting to portal".format(authentication.credentials[0])) db_authentication.deauthenticate_user() logger.info("PORTAL::log_in: User '{}' successfully deauthenticated due to db-authentication error".format(authentication.credentials[0])) - return authentication.ask_credentials_response(request=request, error=e.args[0]) + return response_failure(authentication.ask_credentials_response(request=request, error=e.args[0]), "otp") except (OTPError, REDISWriteError, RedisConnectionError) as e: logger.error("PORTAL::log_in: Error while preparing double-authentication : {}".format(str(e))) - return db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error=" Error sending OTP Key
"+str(e)) + return response_failure(db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error=" Error sending OTP Key
"+str(e)), "otp") except OTPError as e: """ OTP Error while authenticating given token """ logger.error("PORTAL::log_in: Double-authentication failure for username {} : {}".format(authentication.credentials[0], str(e))) - return db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error=" OTP Error {}".format(str(e))) + return response_failure(db_authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error=" OTP Error {}".format(str(e))), "otp") except TwoManyOTPAuthFailure as e: logger.error( "PORTAL::log_in: Two many OTP authentication failures for username'{}', redirecting to portal".format(authentication.credentials[0])) db_authentication.deauthenticate_user() logger.info("PORTAL::log_in: User '{}' successfully deauthenticated due to db-authentication error".format(authentication.credentials[0])) - return authentication.ask_credentials_response(request=request, error=e.args[0]) + return response_failure(authentication.ask_credentials_response(request=request, error=e.args[0]), "otp") # If we arrive here : the user is authenticated # and double-authenticated if double-authentication needed @@ -278,13 +281,14 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): authentication.get_credentials(request) # If we cannot retrieve them, ask credentials if not authentication.credentials[0]:# or not authentication.credentials[1]: - return authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error="Credentials not found") + # If we get here, otp or auth has succeed + return response_success(authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error="Credentials not found"), default_authentication_type) logger.info("PORTAL::log_in: Credentials successfuly retrieven for SSO performing") except Exception as e: logger.error("PORTAL::log_in: Error while retrieving credentials for SSO : ") logger.exception(e) - return authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error="Credentials not found") + return response_success(authentication.ask_credentials_response(request=request, portal_cookie_name=portal_cookie_name, error="Credentials not found"), default_authentication_type) try: # Instantiate SSOForward object with sso_forward type @@ -307,12 +311,12 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): # If the user has not yet a portal cookie : give-it if not request.COOKIES.get(portal_cookie_name, None) or not authentication.redis_base.hgetall(request.COOKIES.get(portal_cookie_name, None)): final_response = set_portal_cookie(final_response, portal_cookie_name, portal_cookie, authentication.get_redirect_url()) - return final_response + return response_success(final_response, default_authentication_type) # If learning credentials cannot be retrieven : ask them except CredentialsMissingError as e: logger.error("PORTAL::log_in: Learning credentials missing : asking-them") - return authentication.ask_learning_credentials(request=request, portal_cookie_name=None if request.POST.get(portal_cookie_name, None) else portal_cookie_name, fields=e.fields_missing) + return response_success(authentication.ask_learning_credentials(request=request, portal_cookie_name=None if request.POST.get(portal_cookie_name, None) else portal_cookie_name, fields=e.fields_missing), default_authentication_type) # If KerberosBackend object cannot be retrieven from mongo with the backend_id that the user is authenticated on except InvalidId: @@ -334,5 +338,5 @@ def log_in(request, token_name=None, token=None, proxy_app_id=None): kerberos_token_resp = authentication_results['data']['token_resp'] except: kerberos_token_resp = None - return response_redirect_with_portal_cookie(redirection_url, portal_cookie_name, portal_cookie, redirection_url.startswith('https'), kerberos_token_resp) + return response_success(response_redirect_with_portal_cookie(redirection_url, portal_cookie_name, portal_cookie, redirection_url.startswith('https'), kerberos_token_resp), default_authentication_type) diff --git a/portal/views/oauth2_portal.py b/portal/views/oauth2_portal.py index 2cdd437..92acdf0 100644 --- a/portal/views/oauth2_portal.py +++ b/portal/views/oauth2_portal.py @@ -34,6 +34,7 @@ from gui.models.system_settings import Cluster from portal.system.authentications import OAUTH2Authentication from portal.system.redis_sessions import REDISBase +from portal.views.responses import response_success, response_failure # Required exceptions imports from bson.errors import InvalidId @@ -80,7 +81,7 @@ def log_in(request): logger.info("OAUTH2::log_in: Authentication succeed for user '{}'".format(authentication.credentials[0])) response = authentication.generate_response(authentication_results) logger.info("OAUTH2::log_in: Response successfully generated for user '{}' : {}".format(authentication.credentials[0], response)) - return response + return response_success(response, "oauth2") # Redis connection error except RedisConnectionError as e: @@ -109,7 +110,7 @@ def log_in(request): logger.error("OAUTH2::log_in: Error while trying to authentication user '{}' : ".format(request.POST.get('username',None))) logger.exception(e) - return HttpResponseForbidden() + return response_failure(HttpResponseForbidden(), "oauth2") @@ -162,6 +163,7 @@ def is_valid_token(request): body = {"active": "false"} logger.debug("OAuth2Portal::is_valid_token: Returning '{}'".format(body)) + response_funcs = {"true"} return JsonResponse(body) else: diff --git a/portal/views/responses.py b/portal/views/responses.py index 988c4cb..f31f39a 100644 --- a/portal/views/responses.py +++ b/portal/views/responses.py @@ -41,6 +41,22 @@ # Global variables BASE_DIR = dirname(dirname(__file__)) +AUTH_TYPE_HEADER = "X-Authentication" +AUTH_RESULT_HEADER = "X-Authentication-Result" + + +def response_success(response, action_type): + if action_type: + response[AUTH_TYPE_HEADER] = action_type + response[AUTH_RESULT_HEADER] = "success" + return response + +def response_failure(response, action_type): + if action_type: + response[AUTH_TYPE_HEADER] = action_type + response[AUTH_RESULT_HEADER] = "failure" + return response + def split_domain(url): """ Split an url and return the 2 last domains diff --git a/portal/views/self.py b/portal/views/self.py index 4316b1a..d8797ab 100644 --- a/portal/views/self.py +++ b/portal/views/self.py @@ -36,6 +36,7 @@ # Django project imports from portal.system.self_actions import SELFService, SELFServiceChange, SELFServiceLogout, SELFServiceLost from vulture_toolkit.auth.exceptions import AuthenticationError, ChangePasswordError +from portal.views.responses import response_failure, response_success # Required exceptions imports from django.utils.datastructures import MultiValueDictKeyError @@ -81,17 +82,17 @@ def self(request, token_name=None, proxy_app_id=None, action=None): except RedisConnectionError as e: # Redis connection error logger.error("PORTAL::log_in: Unable to connect to Redis server : {}".format(str(e))) - return HttpResponseServerError() + return response_failure(HttpResponseServerError(),action) # If assertionError : Forbidden except AssertionError as e: logger.error("PORTAL::log_in: AssertionError while trying to create Authentication : ".format(e)) - return HttpResponseForbidden() + return response_failure(HttpResponseForbidden(), action) except Exception as e: logger.error("Unknown error occured while retrieving user informations :") logger.exception(e) - return HttpResponseForbidden() + return response_failure(HttpResponseForbidden(), action) try: @@ -99,33 +100,33 @@ def self(request, token_name=None, proxy_app_id=None, action=None): if not action: result = Action.perform_action() logger.info("SELF::main: List of apps successfully retrieven") - return Action.main_response(request, result) + return response_success(Action.main_response(request, result), "list_apps") else: - return Action.message_response(Action.perform_action(request, credential)) + return response_success(Action.message_response(Action.perform_action(request, credential)), action) # Redis connection error except RedisConnectionError as e: logger.error("PORTAL::log_in: Unable to connect to Redis server : {}".format(str(e))) - return HttpResponseServerError() + return response_failure(HttpResponseServerError(), action) # If assertionError : Forbidden except AssertionError as e: logger.error("PORTAL::log_in: AssertionError while trying to create Authentication : '{}'".format(e)) - return HttpResponseForbidden(e) + return response_failure(HttpResponseForbidden(e), action) except (DBAPIError, LDAPError, PyMongoError) as e: logger.error("SELF::self: Failed to update password :".format(e)) logger.exception(e) - return Action.ask_credentials_response(request, action, " Database error
" - "Please contact your administrator") + return response_failure(Action.ask_credentials_response(request, action, " Database error
" + "Please contact your administrator"), action) except PasswordMatchError as e: logger.error("SELF::self: Validation form error: '{}'".format(e)) - return Action.ask_credentials_response(request, action, e) + return response_failure(Action.ask_credentials_response(request, action, e), action) except (ChangePasswordError, AuthenticationError) as e: logger.error("SELF::self: Authentication or credentials error : '{}'".format(e)) - return Action.ask_credentials_response(request, action, "Authentication failure.") + return response_failure(Action.ask_credentials_response(request, action, "Authentication failure."), action) except MultiValueDictKeyError as e: if request.method == "GET": @@ -135,13 +136,13 @@ def self(request, token_name=None, proxy_app_id=None, action=None): return Action.ask_credentials_response(request, action, "Field missing : "+str(e)) except SMTPException as e: - return Action.ask_credentials_response(request, action, str(e)) + return response_failure(Action.ask_credentials_response(request, action, str(e)), action) except KeyError as e: logger.exception(e) - return HttpResponseForbidden() + return response_failure(HttpResponseForbidden(), action) except Exception as e: logger.error(type(e)) logger.exception(e) - return Action.message_response("An unknown error occured
Please contact your admninistrator") + return response_failure(Action.message_response("An unknown error occured
Please contact your admninistrator"), action)