def clean(self): try: user_dict = client.sso_search_user_by_email(self.cleaned_data["email"]) except HTTPError as e: error_text = e.response.text if e.response.status_code == 404: msg = _("User with email %s not found") raise ValidationError({"email": msg % self.cleaned_data["email"]}) logger.error("Error when searching user on the SSO: %s", error_text) raise ValidationError(error_text[:MAX_ERROR_MESSAGE_LENGTH]) user = client.construct_user(user_dict) logger.info("Added SSO user %s locally", user)
def get(self, request, *args, **kwargs): # verify the authentication token and # retrieve the User instance from the SSO server message = request.GET.get('message', None) if not message: return HttpResponseBadRequest('No message') if settings.SSO_USE_V2_LOGIN: try: payload = jwt.decode(message, settings.SSO_SECRET, audience=settings.SSO_KEY) except jwt.exceptions.DecodeError: return HttpResponseBadRequest( "Failed to decode JWT signature.") except jwt.exceptions.ExpiredSignatureError: return HttpResponseBadRequest( "JWT recieved from the SSO has expired.") user_data = json.loads(payload['user']) if settings.SSO_ALLOW_ONLY_KNOWN_USERS: # First check if the user is known. if not User.objects.filter(username=user_data['username'], is_active=True).exists(): logger.info( "Username %s isn't known/active locally", user_data['username']) return HttpResponseRedirect( reverse('lizard_auth_client.disallowed_user')) user = client.construct_user(user_data) else: user = verify_auth_token(message) if not user: return HttpResponseBadRequest('Verification failed') # link the user instance to the default database backend # and call django-auth's login function user.backend = "%s.%s" % (BACKEND.__module__, BACKEND.__class__.__name__) django_login(request, user) # redirect the user to the stored "next" url, which is probably a # protected page if 'sso_after_login_next' in request.session: sso_after_login_next = request.session['sso_after_login_next'] del request.session['sso_after_login_next'] else: sso_after_login_next = getattr( settings, 'LOGIN_REDIRECT_URL', '/') return HttpResponseRedirect(sso_after_login_next)
def verify_auth_token(untrusted_message): """ Verifies a Auth Token. Returns a django.contrib.auth.models.User instance if successful or False. """ # decrypt the message untrusted = URLSafeTimedSerializer(settings.SSO_SECRET).loads( untrusted_message, max_age=300) # do some extra validation if 'auth_token' not in untrusted: return False if 'request_token' not in untrusted: return False # call the SSO server to verify the token params = { 'auth_token': untrusted['auth_token'], 'key': settings.SSO_KEY } message = URLSafeTimedSerializer(settings.SSO_SECRET).dumps(params) url = urljoin(settings.SSO_SERVER_PRIVATE_URL, 'sso/api/verify') + '/' response = requests.get( url, params={ 'key': settings.SSO_KEY, 'message': message }, timeout=10 ) # ensure the response is sane if response.status_code != 200: return False # build a User object from the message data = URLSafeTimedSerializer(settings.SSO_SECRET).loads( response.content, max_age=300) user_data = json.loads(data['user']) user = client.construct_user(user_data) if 'roles' in data: role_data = json.loads(data['roles']) client.synchronize_roles(user, role_data) return user
def clean(self): try: user_dict = client.sso_create_user( self.cleaned_data["first_name"], self.cleaned_data["last_name"], self.cleaned_data["email"], self.cleaned_data["username"], ) except HTTPError as e: error_text = e.response.text if "duplicate username" in error_text: raise ValidationError({"username": (_("Username %s already used") % self.cleaned_data["username"])}) logger.error("Error when creating user on the SSO: %s", error_text) raise ValidationError(error_text[:MAX_ERROR_MESSAGE_LENGTH]) user = client.construct_user(user_dict) logger.info("Created user %s on the SSO and added it locally", user)
def handle(self, *args, **options): """ """ sso_user = options.get('sso_user') if not sso_user: msg = '[E] Please provide the username for the user ' \ 'you are trying to sync.' raise Exception(msg) if V: print("[*] About to SSO-sync data for a User " "with username '%s'..." % sso_user) try: user_data = sso_get_user_django(sso_user) if V: print("[+] Received serialized User object: %s" % str(user_data)) user = construct_user(user_data) if V: print("[+] OK, build User instance: %s" % str(user)) user.save() if V: print("[+] OK, succesfully saved this User instance!") except Exception as err: print("[E] err = '%s'" % str(err))
def authenticate(self, username=None, password=None): try: if username and password: user_data = None cache_key = 'SSOBackend.authenticate.{0}'.format(username) # Try getting the user_data from cache first. cached_credentials = cache.get(cache_key) if cached_credentials is not None: logger.debug( 'Found user "%s" in the credential cache.', username) # Found in cache, check the (hashed) password. (cached_user_data, cached_hashed_password) = cached_credentials if check_password(password, cached_hashed_password): logger.debug('Cached hashed password is OK.') user_data = cached_user_data else: logger.debug( 'Failed cached password check for user "%s".', username) else: logger.debug( 'Could not find user "%s" in the credential cache.', username) # Not found in cache, call the SSO server. if settings.SSO_USE_V2_LOGIN: if settings.SSO_ALLOW_ONLY_KNOWN_USERS: # First check if the user is known. if not User.objects.filter( username=username, is_active=True).exists(): logger.debug( "Username %s isn't known/active locally", username) return None user_data = client.sso_authenticate_django_v2( username, password) else: user_data = client.sso_authenticate_django_v1( username, password) # Store user_data in cache. hashed_password = make_password(password) if not is_password_usable(hashed_password): return None else: cache.set( cache_key, (user_data, hashed_password), settings.SSO_CREDENTIAL_CACHE_TIMEOUT_SECONDS) # Use either the cached user profile data, or fresh data from # the SSO server to construct a Django User instance. If # fresh data is used, also synchronize roles. if user_data: user = client.construct_user(user_data) if not cached_credentials: if not settings.SSO_USE_V2_LOGIN: client.sso_sync_user_organisation_roles(user) return user except client.AuthenticationFailed as e: logger.info(e) return None except: logger.exception('Error while authenticating user "%s".', username) return None