def deleteItem(self, item: Authenticator): # For every user, remove assigned services (mark them for removal) for user in item.users.all(): for userService in user.userServices.all(): userService.user = None userService.removeOrCancel() item.delete()
def __registerUser(authenticator: Authenticator, authInstance: AuthenticatorInstance, username: str) -> typing.Optional[User]: """ Check if this user already exists on database with this authenticator, if don't, create it with defaults This will work correctly with both internal or externals cause we first authenticate the user, if internal and user do not exists in database authenticate will return false, if external and return true, will create a reference in database """ from uds.core.util.request import getRequest username = authInstance.transformUsername(username) logger.debug('Transformed username: %s', username) request = getRequest() usr = authenticator.getOrCreateUser(username, username) usr.real_name = authInstance.getRealName(username) usr.save() if usr is not None and State.isActive(usr.state): # Now we update database groups for this user usr.getManager().recreateGroups(usr) # And add an login event events.addEvent(authenticator, events.ET_LOGIN, username=username, srcip=request.ip) # pylint: disable=maybe-no-member events.addEvent(authenticator, events.ET_PLATFORM, platform=request.os.OS, browser=request.os.Browser, version=request.os.Version) # pylint: disable=maybe-no-member return usr return None
def authenticateViaCallback(authenticator: Authenticator, params: typing.Any) -> typing.Optional[User]: """ Given an username, this method will get invoked whenever the url for a callback for an authenticator is requested. The idea behind this is that, with authenticators that are based on url redirections (SSO auths), we provide a mechanism to allow the authenticator to login the user. This will: * Check that the authenticator supports a callback, raise an error if it doesn't support it. * Invoke authenticator callback, and expects, on exit, a valid username. If it gets None or '', it will raise an error. * Register user inside uds if necesary, will invoke in the process **getRealUsername** to get it, so keep it wher you can recover it. * Update user group membership using Authenticator getGroups, so, in your callbacks, remember to store (using provided environment storage, for example) the groups of this user so your getGroups will work correctly. """ gm = auths.GroupsManager(authenticator) authInstance = authenticator.getInstance() # If there is no callback for this authenticator... if authInstance.authCallback == auths.Authenticator.authCallback: raise auths.exceptions.InvalidAuthenticatorException() username = authInstance.authCallback(params, gm) if username is None or username == '' or gm.hasValidGroups() is False: raise auths.exceptions.InvalidUserException( 'User doesn\'t has access to UDS') return __registerUser(authenticator, authInstance, username)
def search(self, item: Authenticator) -> typing.List[typing.Dict]: self.ensureAccess(item, permissions.PERMISSION_READ) try: type_ = self._params['type'] if type_ not in ('user', 'group'): raise self.invalidRequestException() term = self._params['term'] limit = int(self._params.get('limit', '50')) auth = item.getInstance() canDoSearch = type_ == 'user' and ( auth.searchUsers != auths.Authenticator.searchUsers) or ( auth.searchGroups != auths.Authenticator.searchGroups) if canDoSearch is False: raise self.notSupported() if type_ == 'user': return list(auth.searchUsers(term))[:limit] else: return list(auth.searchGroups(term))[:limit] except Exception as e: logger.exception('Too many results: %s', e) return [{ 'id': _('Too many results...'), 'name': _('Refine your query') }]
def authenticate(username: str, password: str, authenticator: Authenticator, useInternalAuthenticate: bool = False) -> typing.Optional[User]: """ Given an username, password and authenticator, try to authenticate user @param username: username to authenticate @param password: password to authenticate this user @param authenticator: Authenticator (database object) used to authenticate with provided credentials @param useInternalAuthenticate: If True, tries to authenticate user using "internalAuthenticate". If false, it uses "authenticate". This is so because in some situations we may want to use a "trusted" method (internalAuthenticate is never invoked directly from web) @return: None if authentication fails, User object (database object) if authentication is o.k. """ logger.debug('Authenticating user %s with authenticator %s', username, authenticator) # If global root auth is enabled && user/password is correct, if not useInternalAuthenticate and GlobalConfig.SUPER_USER_ALLOW_WEBACCESS.getBool(True) and username == GlobalConfig.SUPER_USER_LOGIN.get(True) and password == GlobalConfig.SUPER_USER_PASS.get(True): return getRootUser() gm = auths.GroupsManager(authenticator) authInstance = authenticator.getInstance() if useInternalAuthenticate is False: res = authInstance.authenticate(username, password, gm) else: res = authInstance.internalAuthenticate(username, password, gm) if res is False: return None logger.debug('Groups manager: %s', gm) # If do not have any valid group if gm.hasValidGroups() is False: logger.info('User {} has been authenticated, but he does not belongs to any UDS know group') return None return __registerUser(authenticator, authInstance, username)
def __init__(self, *args, **kwargs): # If an specified login is passed in, retrieve it & remove it from kwargs dict tag = kwargs.get('tag', None) if 'tag' in kwargs: del kwargs['tag'] logger.debug('tag is "{0}"'.format(tag)) super(LoginForm, self).__init__(*args, **kwargs) choices = [] nonStandard = [] standard = [] auths = Authenticator.getByTag(tag) for a in auths: if a.getType() is None: continue if a.getType().isCustom() and tag == 'disabled': continue choices.append((a.uuid, a.name)) if a.getType().isCustom(): nonStandard.append(a.uuid) else: standard.append(a.uuid) self.fields['authenticator'].choices = choices self.fields['nonStandard'].initial = ','.join(nonStandard) self.fields['standard'].initial = ','.join(standard)
def getAuthInfo(auth: Authenticator): theType = auth.getType() return { 'id': auth.uuid, 'name': auth.name, 'label': auth.small_name, 'priority': auth.priority, 'is_custom': theType.isCustom() }
def getRootUser(): # pylint: disable=unexpected-keyword-arg, no-value-for-parameter from uds.models import Authenticator u = User(id=ROOT_ID, name=GlobalConfig.SUPER_USER_LOGIN.get(True), real_name=_('System Administrator'), state=State.ACTIVE, staff_member=True, is_admin=True) u.manager = Authenticator() u.getGroups = lambda: [] u.updateLastAccess = lambda: None u.logout = lambda: None return u
def getRootUser() -> User: # pylint: disable=unexpected-keyword-arg, no-value-for-parameter user = User(id=ROOT_ID, name=GlobalConfig.SUPER_USER_LOGIN.get(True), real_name=_('System Administrator'), state=State.ACTIVE, staff_member=True, is_admin=True) user.manager = Authenticator() # Fake overwrite some methods, a bit cheating? maybe? :) user.getGroups = lambda: [] # type: ignore user.updateLastAccess = lambda: None # type: ignore user.logout = lambda: None # type: ignore return user
def item_as_dict(self, item: Authenticator) -> typing.Dict[str, typing.Any]: type_ = item.getType() return { 'numeric_id': item.id, 'id': item.uuid, 'name': item.name, 'tags': [tag.tag for tag in item.tags.all()], 'comments': item.comments, 'priority': item.priority, 'small_name': item.small_name, 'users_count': item.users.count(), 'type': type_.type(), 'type_name': type_.name(), 'type_info': self.typeInfo(type_), 'permission': permissions.getEffectivePermission(self._user, item) }
def __init__(self, *args, **kwargs): # If an specified login is passed in, retrieve it & remove it from kwargs dict tag = kwargs.get('tag', None) if 'tag' in kwargs: del kwargs['tag'] # Parent init super(LoginForm, self).__init__(*args, **kwargs) choices = [] for a in Authenticator.getByTag(tag): if not a.getType(): # Not existing manager for the auth? continue if a.getType().isCustom() and tag == 'disabled': continue choices.append((a.uuid, a.name)) self.fields['authenticator'].choices = choices
def getRootUser() -> User: """ Returns an user not in DB that is ROOT for the platform Returns: User: [description] """ user = User( id=ROOT_ID, name=GlobalConfig.SUPER_USER_LOGIN.get(True), real_name=_('System Administrator'), state=State.ACTIVE, staff_member=True, is_admin=True, ) user.manager = Authenticator() # type: ignore # Fake overwrite some methods, a bit cheating? maybe? :) user.getGroups = lambda: [] # type: ignore user.updateLastAccess = lambda: None # type: ignore user.logout = lambda: None # type: ignore return user
def login(request, tag=None): """ View responsible of logging in an user :param request: http request :param tag: tag of login auth """ # request.session.set_expiry(GlobalConfig.USER_SESSION_LENGTH.getInt()) response = None # Default empty form form = LoginForm(tag=tag) if request.method == 'POST': form = LoginForm(request.POST, tag=tag) user, data = checkLogin(request, form, tag) if user: response = HttpResponseRedirect(reverse('uds.web.views.index')) webLogin(request, response, user, data) # data is user password here else: # error, data = error if isinstance(data, int): return errors.errorView(request, data) # Error to notify form.add_error(None, data) if response is None: response = render(request, theme.template('login.html'), { 'form': form, 'authenticators': Authenticator.getByTag(tag), 'customHtml': GlobalConfig.CUSTOM_HTML_LOGIN.get(True), 'version': VERSION } ) getUDSCookie(request, response) return response
def login(request, tag=None): ''' View responsible of logging in an user :param request: http request :param tag: tag of login auth ''' # request.session.set_expiry(GlobalConfig.USER_SESSION_LENGTH.getInt()) host = request.META.get('HTTP_HOST') or request.META.get('SERVER_NAME') or 'auth_host' # Last one is a placeholder in case we can't locate host name # Get Authenticators limitation logger.debug('Host: {0}'.format(host)) if GlobalConfig.DISALLOW_GLOBAL_LOGIN.getBool(True) is True: if tag is None: try: Authenticator.objects.get(small_name=host) tag = host except Exception: try: tag = Authenticator.objects.order_by('priority')[0].small_name except Exception: # There is no authenticators yet, simply allow global login to nowhere.. :-) tag = None logger.debug('Tag: {0}'.format(tag)) logger.debug(request.method) if request.method == 'POST': if 'uds' not in request.COOKIES: logger.debug('Request does not have uds cookie') return errors.errorView(request, errors.COOKIES_NEEDED) # We need cookies to keep session data request.session.cycle_key() form = LoginForm(request.POST, tag=tag) if form.is_valid(): os = OsDetector.getOsFromUA(request.META.get('HTTP_USER_AGENT')) try: authenticator = Authenticator.objects.get(pk=form.cleaned_data['authenticator']) except Exception: authenticator = Authenticator() userName = form.cleaned_data['user'] cache = Cache('auth') cacheKey = str(authenticator.id) + userName tries = cache.get(cacheKey) if tries is None: tries = 0 if authenticator.getInstance().blockUserOnLoginFailures is True and tries >= GlobalConfig.MAX_LOGIN_TRIES.getInt(): form.add_form_error('Too many authentication errors. User temporarily blocked.') authLogLogin(request, authenticator, userName, 'Temporarily blocked') else: user = authenticate(userName, form.cleaned_data['password'], authenticator) logger.debug('User: {}'.format(user)) if user is None: logger.debug("Invalid credentials for user {0}".format(userName)) tries += 1 cache.put(cacheKey, tries, GlobalConfig.LOGIN_BLOCK.getInt()) form.add_form_error('Invalid credentials') authLogLogin(request, authenticator, userName, 'Invalid credentials') else: logger.debug('User {} has logged in'.format(userName)) cache.remove(cacheKey) # Valid login, remove cached tries response = HttpResponseRedirect(reverse('uds.web.views.index')) webLogin(request, response, user, form.cleaned_data['password']) # Add the "java supported" flag to session request.session['OS'] = os authLogLogin(request, authenticator, user.name) return response else: form = LoginForm(tag=tag) response = render_to_response(theme.template('login.html'), {'form': form, 'customHtml': GlobalConfig.CUSTOM_HTML_LOGIN.get(True)}, context_instance=RequestContext(request)) getUDSCookie(request, response) return response
def checkLogin( # pylint: disable=too-many-branches, too-many-statements request: 'HttpRequest', form: 'LoginForm', tag: typing.Optional[str] = None ) -> typing.Tuple[typing.Optional['User'], typing.Any]: host = request.META.get('HTTP_HOST') or request.META.get( 'SERVER_NAME' ) or 'auth_host' # Last one is a placeholder in case we can't locate host name # Get Authenticators limitation logger.debug('Host: %s', host) if GlobalConfig.DISALLOW_GLOBAL_LOGIN.getBool(False) is True: if tag is None: try: Authenticator.objects.get(small_name=host) tag = host except Exception: try: tag = Authenticator.objects.order_by( 'priority')[0].small_name except Exception: # There is no authenticators yet, simply allow global login to nowhere.. :-) tag = None logger.debug('Tag: %s', tag) if 'uds' not in request.COOKIES: logger.debug('Request does not have uds cookie') return (None, errors.COOKIES_NEEDED) if form.is_valid(): os = request.os try: authenticator = Authenticator.objects.get( uuid=processUuid(form.cleaned_data['authenticator'])) except Exception: authenticator = Authenticator() userName = form.cleaned_data['user'] if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True: userName = userName.lower() cache = Cache('auth') cacheKey = str(authenticator.id) + userName tries = cache.get(cacheKey) or 0 triesByIp = cache.get(request.ip) or 0 maxTries = GlobalConfig.MAX_LOGIN_TRIES.getInt() if (authenticator.getInstance().blockUserOnLoginFailures is True and (tries >= maxTries) or triesByIp >= maxTries): authLogLogin(request, authenticator, userName, 'Temporarily blocked') return ( None, _('Too many authentication errrors. User temporarily blocked')) password = form.cleaned_data['password'] user = None if password == '': password = '******' # Random string, in fact, just a placeholder that will not be used :) user = authenticate(userName, password, authenticator) logger.debug('User: %s', user) if user is None: logger.debug("Invalid user %s (access denied)", userName) cache.put(cacheKey, tries + 1, GlobalConfig.LOGIN_BLOCK.getInt()) cache.put(request.ip, triesByIp + 1, GlobalConfig.LOGIN_BLOCK.getInt()) authLogLogin(request, authenticator, userName, 'Access denied (user not allowed by UDS)') return (None, _('Access denied')) request.session.cycle_key() logger.debug('User %s has logged in', userName) cache.remove(cacheKey) # Valid login, remove cached tries # Add the "java supported" flag to session request.session['OS'] = os if form.cleaned_data['logouturl'] != '': logger.debug('The logoout url will be %s', form.cleaned_data['logouturl']) request.session['logouturl'] = form.cleaned_data['logouturl'] authLogLogin(request, authenticator, user.name) return (user, form.cleaned_data['password']) logger.info('Invalid form received') return (None, _('Invalid data'))
def checkLogin(request, form, tag=None): host = request.META.get('HTTP_HOST') or request.META.get('SERVER_NAME') or 'auth_host' # Last one is a placeholder in case we can't locate host name # Get Authenticators limitation logger.debug('Host: {0}'.format(host)) if GlobalConfig.DISALLOW_GLOBAL_LOGIN.getBool(False) is True: if tag is None: try: Authenticator.objects.get(small_name=host) tag = host except Exception: try: tag = Authenticator.objects.order_by('priority')[0].small_name except Exception: # There is no authenticators yet, simply allow global login to nowhere.. :-) tag = None logger.debug('Tag: {0}'.format(tag)) if 'uds' not in request.COOKIES: logger.debug('Request does not have uds cookie') return (None, errors.COOKIES_NEEDED) if form.is_valid(): os = request.os try: authenticator = Authenticator.objects.get(uuid=processUuid(form.cleaned_data['authenticator'])) except Exception: authenticator = Authenticator() userName = form.cleaned_data['user'] if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True: userName = userName.lower() cache = Cache('auth') cacheKey = str(authenticator.id) + userName tries = cache.get(cacheKey) if tries is None: tries = 0 if authenticator.getInstance().blockUserOnLoginFailures is True and tries >= GlobalConfig.MAX_LOGIN_TRIES.getInt(): authLogLogin(request, authenticator, userName, 'Temporarily blocked') return (None, _('Too many authentication errrors. User temporarily blocked')) else: password = form.cleaned_data['password'] user = None if password == '': password = '******' # Random string, in fact, just a placeholder that will not be used :) user = authenticate(userName, password, authenticator) logger.debug('User: {}'.format(user)) if user is None: logger.debug("Invalid user {0} (access denied)".format(userName)) tries += 1 cache.put(cacheKey, tries, GlobalConfig.LOGIN_BLOCK.getInt()) authLogLogin(request, authenticator, userName, 'Access denied (user not allowed by UDS)') return (None, _('Access denied')) else: request.session.cycle_key() logger.debug('User {} has logged in'.format(userName)) cache.remove(cacheKey) # Valid login, remove cached tries # Add the "java supported" flag to session request.session['OS'] = os if form.cleaned_data['logouturl'] != '': logger.debug('The logoout url will be {}'.format(form.cleaned_data['logouturl'])) request.session['logouturl'] = form.cleaned_data['logouturl'] authLogLogin(request, authenticator, user.name) return (user, form.cleaned_data['password']) logger.info('Invalid form received') return (None, _('Invalid data'))
def login(request, tag=None): ''' View responsible of logging in an user :param request: http request :param tag: tag of login auth ''' # request.session.set_expiry(GlobalConfig.USER_SESSION_LENGTH.getInt()) host = request.META.get('HTTP_HOST') or request.META.get('SERVER_NAME') or 'auth_host' # Last one is a placeholder in case we can't locate host name # Get Authenticators limitation logger.debug('Host: {0}'.format(host)) if GlobalConfig.DISALLOW_GLOBAL_LOGIN.getBool(False) is True: if tag is None: try: Authenticator.objects.get(small_name=host) tag = host except Exception: try: tag = Authenticator.objects.order_by('priority')[0].small_name except Exception: # There is no authenticators yet, simply allow global login to nowhere.. :-) tag = None logger.debug('Tag: {0}'.format(tag)) logger.debug(request.method) if request.method == 'POST': if 'uds' not in request.COOKIES: logger.debug('Request does not have uds cookie') return errors.errorView(request, errors.COOKIES_NEEDED) # We need cookies to keep session data request.session.cycle_key() form = LoginForm(request.POST, tag=tag) if form.is_valid(): os = request.os try: authenticator = Authenticator.objects.get(pk=form.cleaned_data['authenticator']) except Exception: authenticator = Authenticator() userName = form.cleaned_data['user'] if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True: userName = userName.lower() cache = Cache('auth') cacheKey = str(authenticator.id) + userName tries = cache.get(cacheKey) if tries is None: tries = 0 if authenticator.getInstance().blockUserOnLoginFailures is True and tries >= GlobalConfig.MAX_LOGIN_TRIES.getInt(): form.add_error(None, 'Too many authentication errors. User temporarily blocked.') authLogLogin(request, authenticator, userName, 'Temporarily blocked') else: password = form.cleaned_data['password'] user = None if password == '': password = '******' user = authenticate(userName, password, authenticator) logger.debug('User: {}'.format(user)) if user is None: logger.debug("Invalid credentials for user {0}".format(userName)) tries += 1 cache.put(cacheKey, tries, GlobalConfig.LOGIN_BLOCK.getInt()) form.add_error(None, ugettext('Invalid credentials')) authLogLogin(request, authenticator, userName, 'Invalid credentials') else: logger.debug('User {} has logged in'.format(userName)) cache.remove(cacheKey) # Valid login, remove cached tries response = HttpResponseRedirect(reverse('uds.web.views.index')) webLogin(request, response, user, form.cleaned_data['password']) # Add the "java supported" flag to session request.session['OS'] = os if form.cleaned_data['logouturl'] != '': logger.debug('The logoout url will be {}'.format(form.cleaned_data['logouturl'])) request.session['logouturl'] = form.cleaned_data['logouturl'] authLogLogin(request, authenticator, user.name) return response else: logger.info('Invalid form received') else: form = LoginForm(tag=tag) response = render_to_response( theme.template('login.html'), { 'form': form, 'customHtml': GlobalConfig.CUSTOM_HTML_LOGIN.get(True), 'version': VERSION }, context_instance=RequestContext(request) ) getUDSCookie(request, response) return response