def validate_oauth_token(token, request=None): """ Validates the token attached to the request (SessionStorage, GET/POST) On every request, ask OAuth to authorize the token """ # Authorization test user_profile = cas_profile_for_token(token) if not user_profile: return False username = user_profile.get("id") attrs = user_profile.get("attributes") if not username or not attrs: logger.info("Invalid Profile:%s does not have username/attributes" % user_profile) return False # TEST 1 : Must be in the group 'atmo-user' # NOTE: Test 1 will be IGNORED until we can verify it returns 'entitlement' # EVERY TIME! # if not cas_profile_contains(attrs, 'atmo-user'): # raise Unauthorized("User %s is not a member of group 'atmo-user'" # % username) # TODO: TEST 2 : Must have an identity (?) if not AtmosphereUser.objects.filter(username=username): raise Unauthorized("User %s does not exist as an AtmosphereUser" % username) auth_token = obtainOAuthToken(username, token) # logger.info("OAuthToken Obtained for %s:%s" % (username, auth_token)) if not auth_token: return False return True
def ldap_formatAttrs(ldap_attrs): """ Formats attrs into a unified dict to ease in user creation """ logger.info(ldap_attrs) try: return { 'email': ldap_attrs['mail'][0], 'firstName': ldap_attrs['givenName'][0], 'lastName': ldap_attrs['sn'][0], } except KeyError as nokey: logger.exception(nokey) return None
def authenticate(self, request): token_key = None auth = request.META.get('HTTP_AUTHORIZATION', '').split() if len(auth) == 2 and auth[0].lower() == "token": token_key = auth[1] if not token_key and 'token' in request.session: token_key = request.session['token'] if validate_token(token_key): token = self.model.objects.get(key=token_key) logger.info("AuthToken Obtained for %s:%s" % (token.user.username, token_key)) if token.user.is_active: return (token.user, token) return None
def atmo_login(request, *args, **kwargs): if not request: logger.debug("[NOREQUEST] User is being logged out because request" " is empty") logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return HttpResponseRedirect(settings.SERVER_URL + "/logout/") if not request.session: logger.debug("[NOSESSION] User is being logged out because session" " object does not exist in request") logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return HttpResponseRedirect(settings.SERVER_URL + "/logout/") if not request.session.get('username'): logger.debug("[NOUSER] User is being logged out because session" " did not include a username") logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return HttpResponseRedirect(settings.SERVER_URL + "/logout/") # logger.info('atmo_login_required session info: %s' # % request.session.__dict__) logger.info( 'atmo_login_required authentication: %s' % request.session.get('username', '<Username not in session>')) username = request.session.get('username', None) token = request.session.get('token', None) redirect = kwargs.get('redirect', request.get_full_path()) emulator = request.session.get('emulated_by', None) if emulator: # logger.info("%s\n%s\n%s" % (username, redirect, emulator)) logger.info("Test emulator %s instead of %s" % (emulator, username)) logger.debug(request.session.__dict__) # Authenticate the user (Force a CAS test) user = authenticate(username=emulator, password="", auth_token=token, request=request) # AUTHORIZED STAFF ONLY if not user or not user.is_staff: return HttpResponseRedirect(settings.SERVER_URL + "/logout/") logger.info("Emulate success - Logging in %s" % user.username) django_login(request, user) return func(request, *args, **kwargs) user = authenticate(username=username, password="", auth_token=token, request=request) if not user: logger.info("Could not authenticate user %s" % username) # logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return cas_loginRedirect(request, redirect) django_login(request, user) return func(request, *args, **kwargs)
def authenticate(self, username=None, password=None, request=None): """ Return user if validated by CAS Return None otherwise. """ # logger.debug("CASBackend -- U:%s P:%s R:%s" # % (username, password, request)) if not username: logger.debug("CAS Authentication skipped - No Username.") return None (success, cas_response) = cas_validateUser(username) logger.info("Authenticate by CAS: %s - %s %s" % (username, success, cas_response)) if not success: logger.debug("CAS Authentication failed - "+username) return None attributes = cas_response.attributes return get_or_create_user(username, attributes)
def authenticate(self, username=None, password=None, request=None): """ Return user if validated by CAS Return None otherwise. """ # logger.debug("CASBackend -- U:%s P:%s R:%s" # % (username, password, request)) if not username: logger.debug("CAS Authentication skipped - No Username.") return None (success, cas_response) = cas_validateUser(username) logger.info("Authenticate by CAS: %s - %s %s" % (username, success, cas_response)) if not success: logger.debug("CAS Authentication failed - " + username) return None attributes = cas_response.attributes return get_or_create_user(username, attributes)
def atmo_login(request, *args, **kwargs): if not request: logger.debug("[NOREQUEST] User is being logged out because request" " is empty") logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return HttpResponseRedirect(settings.SERVER_URL+"/logout/") if not request.session: logger.debug("[NOSESSION] User is being logged out because session" " object does not exist in request") logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return HttpResponseRedirect(settings.SERVER_URL+"/logout/") if not request.session.get('username'): logger.debug("[NOUSER] User is being logged out because session" " did not include a username") logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return HttpResponseRedirect(settings.SERVER_URL+"/logout/") # logger.info('atmo_login_required session info: %s' # % request.session.__dict__) logger.info('atmo_login_required authentication: %s' % request.session.get('username', '<Username not in session>')) username = request.session.get('username', None) token = request.session.get('token', None) redirect = kwargs.get('redirect', request.get_full_path()) emulator = request.session.get('emulated_by', None) if emulator: # logger.info("%s\n%s\n%s" % (username, redirect, emulator)) logger.info("Test emulator %s instead of %s" % (emulator, username)) logger.debug(request.session.__dict__) # Authenticate the user (Force a CAS test) user = authenticate(username=emulator, password="", auth_token=token, request=request) # AUTHORIZED STAFF ONLY if not user or not user.is_staff: return HttpResponseRedirect(settings.SERVER_URL+"/logout/") logger.info("Emulate success - Logging in %s" % user.username) django_login(request, user) return func(request, *args, **kwargs) user = authenticate(username=username, password="", auth_token=token, request=request) if not user: logger.info("Could not authenticate user %s" % username) # logger.debug("%s\n%s\n%s\n%s" % (request, args, kwargs, func)) return cas_loginRedirect(request, redirect) django_login(request, user) return func(request, *args, **kwargs)
def validate_token(token, request=None): """ Validates the token attached to the request (SessionStorage, GET/POST) If token has expired, CAS will attempt to reauthenticate the user and refresh token. Expired Tokens can be used for GET requests ONLY! """ # Existence test try: auth_token = AuthToken.objects.get(key=token) user = auth_token.user except AuthToken.DoesNotExist: logger.info("AuthToken Retrieved:%s Does not exist." % (token, )) return False if auth_token.is_expired(): if request and request.META['REQUEST_METHOD'] != 'GET': # See if the user (Or the user who is emulating a user) can be # re-authed. user_to_auth = request.session.get('emulated_by', user) if cas_validateUser(user_to_auth): # logger.debug("Reauthenticated user -- Token updated") auth_token.update_expiration() auth_token.save() return True else: logger.info("Token %s expired, User %s " "could not be reauthenticated in CAS" % (token, user)) return False else: logger.debug( "Token %s EXPIRED, but allowing User %s to GET data.." % (token, user)) return True else: return True
def saml_validateTicket(request): """ Method expects 2 GET parameters: 'ticket' & 'sendback' After a CAS Login: Redirects the request based on the GET param 'ticket' Unauthorized Users are redirected to '/' In the event of failure. Authorized Users are redirected to the GET param 'sendback' """ redirect_logout_url = settings.REDIRECT_URL + "/login/" no_user_url = settings.REDIRECT_URL + "/no_user/" logger.debug('GET Variables:%s' % request.GET) ticket = request.GET.get('ticket', None) if not ticket: logger.info("No Ticket received in GET string " "-- Logout user: %s" % redirect_logout_url) return HttpResponseRedirect(redirect_logout_url) logger.debug("ServiceValidate endpoint includes a ticket." " Ticket must now be validated with SAML") # ReturnLocation set, apply on successful authentication saml_client = get_saml_client() saml_response = saml_client.saml_serviceValidate(ticket) if not saml_response.success: logger.debug("CAS Server did NOT validate ticket:%s" " and included this response:%s" % (ticket, saml_response.xml)) return HttpResponseRedirect(redirect_logout_url) try: user = User.objects.get(username=saml_response.user) except User.DoesNotExist: return HttpResponseRedirect(no_user_url) auth_token = create_session_token(None, user, request) if auth_token is None: logger.info("Failed to create AuthToken") HttpResponseRedirect(redirect_logout_url) return_to = request.GET.get('sendback') if not return_to: return HttpResponse(saml_response.response, content_type="text/xml; charset=utf-8") return_to += "?token=%s" % auth_token logger.info("Session token created, return to: %s" % return_to) return HttpResponseRedirect(return_to)
def token_auth(request): """ VERSION 2 AUTH Authentication is based on the POST parameters: * Username (Required) * Password (Not Required if CAS authenticated previously) NOTE: This authentication is SEPARATE from django model authentication Use this to give out tokens to access the API """ logger.info('Request to auth') #logger.info(request) token = request.POST.get('token', None) username = request.POST.get('username', None) # CAS authenticated user already has session data # without passing any parameters if not username: username = request.session.get('username', None) password = request.POST.get('password', None) # LDAP Authenticate if password provided. if username and password: if ldap_validate(username, password): logger.info("LDAP User %s validated. Creating auth token" % username) token = createAuthToken(username) expireTime = token.issuedTime + TOKEN_EXPIRY_TIME auth_json = { 'token': token.key, 'username': token.user.username, 'expires': expireTime.strftime("%b %d, %Y %H:%M:%S") } return HttpResponse( content=json.dumps(auth_json), status=201, content_type='application/json') else: logger.debug("[LDAP] Failed to validate %s" % username) return HttpResponse("LDAP login failed", status=401) # if request.session and request.session.get('token'): # logger.info("User %s already authenticated, renewing token" # % username) # token = validateToken(username, request.session.get('token')) # ASSERT: Token exists here if token: expireTime = token.issuedTime + TOKEN_EXPIRY_TIME auth_json = { 'token': token.key, 'username': token.user.username, 'expires': expireTime.strftime("%b %d, %Y %H:%M:%S") } return HttpResponse( content=json.dumps(auth_json), content_type='application/json') if not username and not password: # The user and password were not found # force user to login via CAS return cas_loginRedirect(request, '/auth/') # CAS Authenticate by Proxy (Password not necessary): if cas_validateUser(username): logger.info("CAS User %s validated. Creating auth token" % username) token = createAuthToken(username) expireTime = token.issuedTime + TOKEN_EXPIRY_TIME auth_json = { 'token': token.key, 'username': token.user.username, 'expires': expireTime.strftime("%b %d, %Y %H:%M:%S") } return HttpResponse( content=json.dumps(auth_json), content_type='application/json') else: logger.debug("[CAS] Failed to validate - %s" % username) return HttpResponse("CAS Login Failure", status=401)
def token_auth(request): """ VERSION 2 AUTH Authentication is based on the POST parameters: * Username (Required) * Password (Not Required if CAS authenticated previously) NOTE: This authentication is SEPARATE from django model authentication Use this to give out tokens to access the API """ logger.info('Request to auth') #logger.info(request) token = request.POST.get('token', None) username = request.POST.get('username', None) # CAS authenticated user already has session data # without passing any parameters if not username: username = request.session.get('username', None) password = request.POST.get('password', None) # LDAP Authenticate if password provided. if username and password: if ldap_validate(username, password): logger.info("LDAP User %s validated. Creating auth token" % username) token = createAuthToken(username) expireTime = token.issuedTime + TOKEN_EXPIRY_TIME auth_json = { 'token': token.key, 'username': token.user.username, 'expires': expireTime.strftime("%b %d, %Y %H:%M:%S") } return HttpResponse(content=json.dumps(auth_json), status=201, content_type='application/json') else: logger.debug("[LDAP] Failed to validate %s" % username) return HttpResponse("LDAP login failed", status=401) # if request.session and request.session.get('token'): # logger.info("User %s already authenticated, renewing token" # % username) # token = validateToken(username, request.session.get('token')) # ASSERT: Token exists here if token: expireTime = token.issuedTime + TOKEN_EXPIRY_TIME auth_json = { 'token': token.key, 'username': token.user.username, 'expires': expireTime.strftime("%b %d, %Y %H:%M:%S") } return HttpResponse(content=json.dumps(auth_json), content_type='application/json') if not username and not password: # The user and password were not found # force user to login via CAS return cas_loginRedirect(request, '/auth/') # CAS Authenticate by Proxy (Password not necessary): if cas_validateUser(username): logger.info("CAS User %s validated. Creating auth token" % username) token = createAuthToken(username) expireTime = token.issuedTime + TOKEN_EXPIRY_TIME auth_json = { 'token': token.key, 'username': token.user.username, 'expires': expireTime.strftime("%b %d, %Y %H:%M:%S") } return HttpResponse(content=json.dumps(auth_json), content_type='application/json') else: logger.debug("[CAS] Failed to validate - %s" % username) return HttpResponse("CAS Login Failure", status=401)
def cas_validateTicket(request): """ Method expects 2 GET parameters: 'ticket' & 'sendback' After a CAS Login: Redirects the request based on the GET param 'ticket' Unauthorized Users are redirected to '/' In the event of failure. Authorized Users are redirected to the GET param 'sendback' """ redirect_logout_url = settings.REDIRECT_URL + "/login/" no_user_url = settings.REDIRECT_URL + "/no_user/" logger.debug('GET Variables:%s' % request.GET) ticket = request.GET.get('ticket', None) sendback = request.GET.get('sendback', None) if not ticket: logger.info("No Ticket received in GET string " "-- Logout user: %s" % redirect_logout_url) return HttpResponseRedirect(redirect_logout_url) logger.debug("ServiceValidate endpoint includes a ticket." " Ticket must now be validated with CAS") # ReturnLocation set, apply on successful authentication caslib = get_cas_client() caslib.service_url = _set_redirect_url(sendback, request) cas_response = caslib.cas_serviceValidate(ticket) if not cas_response.success: logger.debug("CAS Server did NOT validate ticket:%s" " and included this response:%s (Err:%s)" % (ticket, cas_response.object, cas_response.error_str)) return HttpResponseRedirect(redirect_logout_url) if not cas_response.user: logger.debug("User attribute missing from cas response!" "This may require a fix to caslib.py") return HttpResponseRedirect(redirect_logout_url) if not cas_response.proxy_granting_ticket: logger.error("""Proxy Granting Ticket missing! Atmosphere requires CAS proxy as a service to authenticate users. Possible Causes: * ServerName variable is wrong in /etc/apache2/apache2.conf * Proxy URL does not exist * Proxy URL is not a valid RSA-2/VeriSigned SSL certificate * /etc/host and hostname do not match machine.""") return HttpResponseRedirect(redirect_logout_url) updated = updateUserProxy( cas_response.user, cas_response.proxy_granting_ticket) if not updated: return HttpResponseRedirect(redirect_logout_url) logger.info("Updated proxy for <%s> -- Auth success!" % cas_response.user) try: user = User.objects.get(username=cas_response.user) except User.DoesNotExist: return HttpResponseRedirect(no_user_url) auth_token = create_session_token(None, user, request) if auth_token is None: logger.info("Failed to create AuthToken") HttpResponseRedirect(redirect_logout_url) return_to = request.GET['sendback'] logger.info("Session token created, User logged in, return to: %s" % return_to) return HttpResponseRedirect(return_to)