Ejemplo n.º 1
0
    def authenticate(self, request):
        e = None
        try:
            backend = self.workflow.authentication.repository
            if backend.subtype == "KERBEROS":
                authentication_results = backend.authenticate_token(
                    logger, self.credentials)
                self.backend_id = str(backend.id)
                self.credentials = [authentication_results['data']['dn'], ""]
                logger.info(
                    "AUTH:authenticate: User '{}' successfully authenticated on kerberos repository '{}'"
                    .format(self.credentials[0], backend))
                return authentication_results
            else:
                raise AuthenticationError(
                    "Repository '{}' is not a Kerberos Repository".format(
                        backend))

        except (AuthenticationError, ACLError) as e:
            logger.error(
                "AUTH::authenticate: Authentication failure for kerberos token on primary repository '{}' : "
                "'{}'".format(str(backend), str(e)))

            for fallback_backend in self.workflow.authentication.repositories_fallback.all(
            ):
                try:
                    if backend.subtype == "KERBEROS":
                        authentication_results = fallback_backend.get_backend(
                        ).authenticate_token(logger, self.credentials)
                        self.backend_id = str(backend.id)
                        self.credentials = [
                            authentication_results['data']['dn'], ""
                        ]
                        logger.info(
                            "AUTH:authenticate: User '{}' successfully authenticated on kerberos fallback "
                            "repository '{}'".format(self.credentials[0],
                                                     fallback_backend))

                        return authentication_results
                    else:
                        raise AuthenticationError(
                            "Backend '{}' not a Kerberos Repository".format(
                                fallback_backend))

                except (AuthenticationError, ACLError) as e:
                    logger.error(
                        "AUTH::authenticate: Authentication failure for kerberos token on fallback repository '{}' : "
                        "'{}'".format(str(fallback_backend), str(e)))
                    continue

        raise e or AuthenticationError
Ejemplo n.º 2
0
 def authenticate(self):
     self.oauth2_token = self.redis_portal_session.get_oauth2_token(
         self.authenticated_on_backend())
     if not self.oauth2_token:
         authentication_results = super().authenticate(None)
         logger.debug(
             "OAUTH2_AUTH::authenticate: Oauth2 attributes : {}".format(
                 str(authentication_results['data'])))
         if authentication_results['data'].get('oauth2', None) is not None:
             self.oauth2_token = Uuid4().generate()
             self.register_authentication(
                 authentication_results['data']['oauth2'])
             authentication_results = authentication_results['data'][
                 'oauth2']
         elif self.application.enable_oauth2:
             authentication_results = {
                 'token_return_type': 'both',
                 'token_ttl': self.application.auth_timeout,
                 'scope': '{}'
             }
             self.oauth2_token = Uuid4().generate()
             self.register_authentication(authentication_results)
         else:
             raise AuthenticationError(
                 "OAUTH2_AUTH::authenticate: OAuth2 is not enabled on this app nor on this repository"
             )
     else:
         # REPLACE CREDENTIAL 'user"
         self.redis_oauth2_session = REDISOauth2Session(
             self.redis_base, "oauth2_" + self.oauth2_token)
         authentication_results = self.redis_oauth2_session.keys
     return authentication_results
Ejemplo n.º 3
0
    def authenticate(self, request):
        repository = self.workflow.authentication.otp_repository

        if repository.otp_type == 'email':
            if repository.otp_mail_service == 'vlt_mail_service':
                if self.credentials[0] != self.credentials[
                        1] and self.credentials[0] not in [
                            '', None, 'None', False
                        ]:
                    raise AuthenticationError(
                        "The taped OTP key does not match with Redis value saved"
                    )

        else:
            # The function raise itself AuthenticationError, or return True
            repository.authenticate(self.credentials[0], self.credentials[1])

        logger.info(
            "DB-AUTH::authenticate: User successfully double-authenticated "
            "on OTP backend '{}'".format(repository))
        self.redis_portal_session.register_doubleauthentication(
            str(self.workflow.id, repository.id))
        logger.debug(
            "DB-AUTH::authenticate: Double-authentication results successfully written in Redis portal session"
        )
Ejemplo n.º 4
0
    def set_authentication_params(self, repo, authentication_results):
        if authentication_results:
            result = {}
            self.backend_id = str(repo.id)

            if isinstance(authentication_results, User):
                result = {
                    'data': {
                        'password_expired': False,
                        'account_locked':
                        (not authentication_results.is_active),
                        'user_email': authentication_results.email
                    },
                    'backend': repo
                }
                """ OAuth2 enabled in any case """
                result['data']['oauth2'] = {
                    'scope': '{}',
                    'token_return_type': 'both',
                    'token_ttl': self.workflow.authentication.auth_timeout
                }
            logger.debug(
                "AUTH::set_authentication_params: Authentication results : {}".
                format(authentication_results))
            return result
        else:
            raise AuthenticationError(
                "AUTH::set_authentication_params: Authentication results is empty : '{}' "
                "for username '{}'".format(authentication_results,
                                           self.credentials[0]))
Ejemplo n.º 5
0
    def authenticate(self, username, password, **kwargs):
        """ Authentication method for Kerberos backend

        :param username: String with username
        :param password: String with password
        :return:True if authentication succeed, None otherwise
        """
        backend_id = kwargs['backend_id']
        # Hash "backend_id"+"username" to get the filename of tgt
        ccname = "/tmp/krb5cc_" + sha1("{}{}".format(
            backend_id, username).encode('utf-8')).hexdigest()
        logger.info("Trying to authenticate username {}".format(username))

        tgt = self.create_tgt_from_creds(username, password, ccname)

        if tgt is None:
            logger.error(
                "KerberosClient::authenticate: Kerberos authentication for {} failed"
                .format(username))
            raise AuthenticationError(
                "Credentials not valid or invalid configuration")
        else:
            logger.debug(
                "KerberosClient::authenticate: TGT successfully retrieven/created with credentials"
            )
            logger.info(
                "KerberosClient::authenticate: Successfull authentication for username {}"
                .format(username))
            return {
                'dn': username,
                'user_phone': 'N/A',
                'user_email': username + '@' + self.realm,
                'password_expired': False,
                'account_locked': False
            }
Ejemplo n.º 6
0
 def authenticate(self, username, password, **kwargs):
     subclass = self.get_daughter()
     if isinstance(subclass, InternalRepository):
         return self.internalrepository.authenticate(
             username, password, **kwargs)
     else:
         result = subclass.get_client().authenticate(
             username, password, **kwargs)
         if result['account_locked']:
             raise AuthenticationError(
                 "Account '{}' locked".format(username))
         return result
Ejemplo n.º 7
0
    def authenticate(self, username, password, **kwargs):
        # """Authentication method of LDAP repository, which returns dict of specified attributes:their values
        # :param username: String with username
        # :param password: String with password
        # :param oauth2_attributes: List of attributes to retrieve
        # :return: None and raise if failure, server message otherwise
        # """
        logger.debug("Trying to authenticate username {}".format(username.encode('utf-8')))
        # try:
        # Create client
        srv = Client(server=self.host, secret=self.secret,
                     dict=Dictionary(DICTIONARY_PATH))
        srv.retries = self.max_retry
        srv.timeout = self.max_timeout
        # create request
        req = srv.CreateAuthPacket(code=pyrad.packet.AccessRequest,
                                   User_Name=username, NAS_Identifier=self.nas_id)
        req["Password"] = req.PwCrypt(password)

        # send request
        reply = srv.SendPacket(req)

        logger.debug("Radius authentication username:{}, return code : {}".format(username, reply.code))

        if reply.code == pyrad.packet.AccessAccept:
            ret = ""
            for key, item in reply.iteritems():
                ret += str(key) + ":" + str(item)
        else:
            logger.error("RADIUS_CLI::authenticate: Authentication failure for user '{}'".format(username))
            raise AuthenticationError("Authentication failure on Radius backend for user '{}'".format(username))

        logger.debug("RADIUS_CLI::authenticate: Authentication reply from server : '{}'".format(ret))
        logger.info("RADIUS_CLI::authenticate: Autentication succeed for user '{}'".format(username))
        # except Timeout:
        #     raise Timeout
        # except Exception, e:
        #     logger.error("Unable to authenticate username {} : exception : {}".format(username, str(e)))

        return {
            'dn': username,
            'user_phone': 'N/A',
            'user_email': 'N/A',
            'password_expired': False,
            'account_locked': False
        }
Ejemplo n.º 8
0
    def authenticate(self, user_id, key):
        authy_client = AuthyApiClient(str(self.authy_api_key))
        try:
            if self.type == 'phone':
                verification = authy_client.tokens.verify(
                    str(user_id), str(key))
                if verification.ok():
                    return True
            elif self.type == 'onetouch':
                # It's not the user_id but the 'send_request()' response that is sent here (bad variable name)
                verification = authy_client.one_touch.get_approval_status(
                    str(user_id))
        except Exception as e:
            logger.error(
                "AUTHY_CLIENT::authenticate: Error while trying to verify given key : {}"
                .format(e))
            raise OTPError("Authy error while verificating token : {}".format(
                str(e)))

        if self.type == 'onetouch':
            if verification.ok() and verification.status():
                if verification.content.get('approval_request',
                                            {}).get('status') == 'approved':
                    return True
                elif verification.content.get('approval_request',
                                              {}).get('status') == 'denied':
                    # FIXME
                    #raise TwoManyOTPAuthFailure("The OneTouch request has been denied by the user")
                    raise OTPError(
                        "The OneTouch request has been denied by the user")
                else:
                    raise OTPError("The OneTouch request is not yet approved, "
                                   "status : {}".format(
                                       verification.content.get(
                                           'approval_request',
                                           {}).get('status')))

        # If we arrive here : verification.ok() returned False ; Authentication failure
        raise AuthenticationError(
            "Authy authentication error while verificating token : "
            "{}".format(verification.errors()))
Ejemplo n.º 9
0
    def set_authentication_params(self, repo, authentication_results,
                                  username):
        if authentication_results:
            self.backend_id = str(repo.id)

            if isinstance(authentication_results, User):
                result = {
                    'data': {
                        'password_expired': False,
                        'account_locked':
                        (not authentication_results.is_active),
                        'user_email': authentication_results.email
                    },
                    'backend': repo
                }

            logger.debug(
                "AUTH::set_authentication_params: Authentication results : {}".
                format(authentication_results))
            return result
        else:
            raise AuthenticationError(
                "SELF::authenticate: Authentication result is empty for username '{}'"
                .format(username))
Ejemplo n.º 10
0
 def authenticate(self, user_id, key):
     logger.debug("")
     totp = TOTP(user_id)
     if not totp.verify(key):
         raise AuthenticationError("TOTP taped token is not valid.")
     return True
Ejemplo n.º 11
0
    def authenticate (self, username, password, **kwargs):
        """Authentication method of LDAP repository, which returns dict of specified attributes:their values
        :param username: String with username
        :param password: String with password
        :param oauth2_attributes: List of attributes to retrieve
        :return:
        """
        return_status = kwargs.get('return_status', False)
        logger.debug("Trying to authenticate username {}".format(username))
        # Prevent bind with empty password. As wrote in RFC 4511 LDAP server
        # won't raise an error message at bind
        if len(password) == 0:
            raise AuthenticationError("Empty password is not allowed")
        # Looking for user DN, if found we can try a bind
        found = self.search_user(username)

        if found is not None:
            dn = found[0][0]
            logger.debug("User {} was found in LDAP, its DN is: {}"
                        .format(username.encode('utf-8'), dn))
            self._bind_connection(dn, password)
            # Auth check
            if type(self._ldap_connection.whoami_s()) is None:
                raise AuthenticationError("LDAP bind failed for username {}".format(username))
            else:
                logger.debug("Successful bind for username {}".format(username))
                if return_status is True:
                    return True

                phone, email = 'N/A', 'N/A'
                if self.user_mobile_attr:
                    phone = found[0][1].get(self.user_mobile_attr, 'N/A')
                    if isinstance(phone, list):
                        phone = phone[0]
                if self.user_email_attr:
                    email = found[0][1].get(self.user_email_attr, 'N/A')
                    if isinstance(email, list):
                        email = email[0]

                result = {
                    'dn'              : dn,
                    'user_phone'      : phone,
                    'user_email'      : email,
                    'password_expired': self.is_password_expired(username),
                    'account_locked'  : self.is_user_account_locked(username),
                    'user_groups'     : self.search_user_groups(username)
                }

                if self.enable_oauth2:
                    oauth2_found = self._search_oauth2(username)

                    if str(self.oauth2_type_return) == 'dict':
                        oauth2_scope = dict()
                    elif self.oauth2_type_return == 'list':
                        oauth2_scope = list()
                    else:
                        logger.error("LDAP::authenticate: Oauth2 type return is not dict nor list for user {}".format(dn))
                        return result

                    if self.oauth2_attributes:
                        """ Return attributes needed for OAuth2 scopes """
                        for attr in self.oauth2_attributes:
                            try:
                                if attr.lower() == 'dn':
                                    attr_value = str(oauth2_found[0][0])
                                else:
                                    attr_value = oauth2_found[0][1].get(attr, None)
                                    if attr_value is None:
                                        logger.error("Unable to find oauth2 attribute named {} for user {} ".format(attr, dn))
                                        attr_value = 'N/A'

                                if str(self.oauth2_type_return) == 'dict':
                                    oauth2_scope[attr] = attr_value

                                elif str(self.oauth2_type_return) == 'list':
                                    oauth2_scope.append(str(attr_value))

                            except Exception as e:
                                logger.error("Unable to find oauth2 attribute named {} for user {} : {}".format(attr, dn, e))
                    else:
                        oauth2_scope = '{}'

                    oauth2_result = {
                        'token_ttl': self.oauth2_token_ttl,
                        'token_return_type': self.oauth2_token_return,
                        'scope': oauth2_scope
                    }
                    result['oauth2'] = oauth2_result

                return result
        else:
            logger.error("Unable to found username {} in LDAP repository"
                         "".format(username.encode('utf-8')))
            raise UserNotFound("Unable to found {}".format(username))
Ejemplo n.º 12
0
    def perform_action(self, request, old_password):
        new_passwd = request.POST['password_1']
        new_passwd_cfrm = request.POST['password_2']

        rdm = (request.GET.get("rdm", None) or request.POST.get('rdm', None))

        # If not rdm : Verify password
        if not rdm:
            saved_app_id = self.redis_portal_session.keys['app_id_' +
                                                          str(self.backend.id)]
            saved_app = Application.objects(id=ObjectId(saved_app_id)).only(
                'id', 'name', 'pw_min_len', 'pw_min_upper', 'pw_min_lower',
                'pw_min_number', 'pw_min_symbol').first()
            if not self.redis_portal_session.getAutologonPassword(
                    str(saved_app.id), str(self.backend.id), self.username):
                raise AuthenticationError("Wrong old password")
        else:
            saved_app = self.application

        # Check if password meets required complexity
        upper_case = 0
        lower_case = 0
        number = 0
        symbol = 0

        min_len = int(saved_app.pw_min_len)
        min_upper = int(saved_app.pw_min_upper)
        min_lower = int(saved_app.pw_min_lower)
        min_number = int(saved_app.pw_min_number)
        min_symbol = int(saved_app.pw_min_symbol)

        for i in new_passwd:
            if i.isupper():
                upper_case += 1
            elif i.islower():
                lower_case += 1
            elif i.isdigit():
                number += 1
            else:
                symbol += 1

        if not (len(new_passwd) >= min_len and upper_case >= min_upper
                and lower_case >= min_lower and number >= min_number
                and symbol >= min_symbol):
            logger.info("SELF::change_password: Password is too weak")
            raise AuthenticationError(
                "Password do not meet complexity requirements")

        if self.backend.subtype == "internal":
            user = User.objects.get(username=str(self.username))
            new_password_hash = make_password(new_passwd)
            user.password = new_password_hash
            user.save()
        else:
            self.backend.change_password(
                self.username,
                old_password,
                new_passwd,
                krb5_service=self.application.app_krb_service)
        logger.info(
            "SELF::change_password: Password successfully changed in backend")

        # If not rdm : set new password in Redis portal session
        if not rdm:
            if self.redis_portal_session.setAutologonPassword(
                    str(saved_app.id), str(saved_app.name), str(
                        self.backend.id), self.username, old_password,
                    new_passwd) is None:
                # If setAutologonPasswd return None : the old_password was incorrect
                raise AuthenticationError("Wrong old password")
            logger.info(
                "SELF::change_password: Password successfully changed in Redis"
            )

        return "Password successfully changed"
Ejemplo n.º 13
0
    def retrieve_credentials(self, request):
        """ We may have a password reset token in URI """
        rdm = request.GET.get("rdm", None) or request.POST.get('rdm', None)

        if not rdm:
            super(SELFServiceChange, self).retrieve_credentials(request)

        old_password = None  # None if rdm
        new_passwd = request.POST['password_1']
        new_passwd_cfrm = request.POST['password_2']
        if new_passwd != new_passwd_cfrm:
            raise PasswordMatchError("Password and confirmation mismatches")

        auth_backend = self.application.getAuthBackend()
        auth_backend_fallbacks = self.application.getAuthBackendFallback()

        if rdm:
            assert re_match("^[0-9a-f-]+$",
                            rdm), "PORTAL::self: Injection attempt on 'rdm'"

            email = self.redis_base.hget('password_reset_' + rdm, 'email')
            assert email, "SELF::Change: Invalid Random Key provided: '{}'".format(
                rdm)

            user_infos = self.get_username_by_email(auth_backend,
                                                    auth_backend_fallbacks,
                                                    email)
            self.username = user_infos['user']
            self.backend = user_infos['backend']

        else:
            # Get old_password
            old_password = request.POST[
                'password_old']  # If raise -> ask credentials

            # Get redis_portal_session
            portal_cookie = request.COOKIES.get(self.cluster.getPortalCookie())
            self.redis_portal_session = REDISPortalSession(
                self.redis_base, portal_cookie)
            # If not present -> 403
            assert self.redis_portal_session.exists(
            ), "PORTAL::self: portal session is not valid !"

            # And get username & backend from redis_portal_session
            user_infos = dict()
            auth_backend = self.application.getAuthBackend()
            if self.redis_portal_session.keys.get(
                    'login_' + str(self.application.getAuthBackend().id)):
                try:
                    user_infos = self.authenticate_on_backend(
                        auth_backend, self.username, old_password)
                    self.username = self.redis_portal_session.keys.get(
                        'login_' + str(auth_backend.id))
                    self.backend = auth_backend
                except Exception as e:
                    logger.error(
                        "Seems to have wrong old password on backend : '{}', exception details : "
                        + self.application.getAuthBackend().repo_name)
                    logger.exception(e)
            if not user_infos:
                for backend_fallback in self.application.getAuthBackendFallback(
                ):
                    if self.redis_portal_session.keys.get(
                            'login_' + str(backend_fallback.id)):
                        try:
                            user_infos = self.authenticate_on_backend(
                                backend_fallback, self.username, old_password)
                            self.username = self.redis_portal_session.keys.get(
                                'login_' + str(backend_fallback.id))
                            self.backend = backend_fallback
                            break
                        except:
                            logger.error(
                                "Seems to have wrong old password on backend : "
                                + backend_fallback.repo_name)

            if not self.backend:
                raise AuthenticationError("Wrong old password")
            logger.debug(
                "PORTAL::self: Found username from portal session: {}".format(
                    self.username))

        return old_password