コード例 #1
0
    def authenticate_totp(self, environ, auth_user):
        totp_challenger = SecurityTOTP.get_for_user(auth_user)

        # if there is no totp configured, don't allow auth
        # shouldn't happen, login flow should create a totp_challenger
        if totp_challenger is None:
            log.info("Login attempted without MFA configured for: {}".format(
                auth_user))
            return None

        request = Request(environ, charset='utf-8')
        if not ('mfa' in request.POST):
            log.info("Could not get MFA credentials from the request")
            return None

        try:
            result = totp_challenger.check_code(request.POST['mfa'])
        except ReplayAttackException as e:
            log.warning(
                "Detected a possible replay attack for user: {}, context: {}".
                format(auth_user, e))
            return None

        if result:
            return auth_user
コード例 #2
0
    def _setup_totp_template_variables(self, context, data_dict):
        """Populates context with
        is_sysadmin
        totp_challenger_uri
        totp_secret
        mfa_test_valid
        """
        c.is_sysadmin = authz.is_sysadmin(c.user)
        c.totp_user_id = data_dict['id']

        user_dict = self._fetch_user_or_fail(context, data_dict)

        c.user_dict = user_dict
        c.is_myself = user_dict['name'] == c.user

        totp_challenger = SecurityTOTP.get_for_user(user_dict['name'])
        if totp_challenger is not None:
            c.totp_secret = totp_challenger.secret
            c.totp_challenger_uri = totp_challenger.provisioning_uri

            mfa_test_code = request.params.get('mfa')
            if request.method == 'POST' and mfa_test_code is not None:
                c.mfa_test_valid = totp_challenger.check_code(mfa_test_code,
                                                              verify_only=True)
                c.mfa_test_invalid = not c.mfa_test_valid
コード例 #3
0
    def new(self, id=None):
        """Set up a users new security TOTP credentials"""
        context = {
            'model': model, 'session': model.Session,
            'user': c.user, 'auth_user_obj': c.userobj
        }
        # pylons includes the rest of the url in the param, so we need to strip the /new suffix
        user_id = id.replace('/new', '')

        data_dict = {'id': user_id, 'user_obj': c.userobj}
        user_dict = self._fetch_user_or_fail(context, data_dict)
        SecurityTOTP.create_for_user(user_dict['name'])
        self._setup_totp_template_variables(context, data_dict)
        log.info("Rotated the 2fa secret for user {}".format(user_id))
        helpers.flash_success(_('Successfully updated two factor authentication secret. Make sure you add the new secret to your authenticator app.'))
        helpers.redirect_to('mfa_configure', id=user_id)
コード例 #4
0
 def reset_totp(self, username):
     print('Resetting totp secret for user', username)
     from ckanext.security.model import SecurityTOTP
     SecurityTOTP.create_for_user(username)
     print('Success!')
コード例 #5
0
    def login(self):
        """
        Ajax call to test username/password/mfa code
        """
        tk.response.headers.update({'Content-Type': 'application/json'})

        try:
            res = {}
            if request.method != 'POST':
                tk.response.status_int = 405
                return json.dumps(res)

            identity = request.params
            if not ('login' in identity and 'password' in identity):
                tk.response.status_int = 422
                return json.dumps(res)

            user_name = identity['login']
            user = model.User.by_name(user_name)

            login_throttle_key = get_login_throttle_key(request, user_name)
            if login_throttle_key is None:
                tk.response.status_int = 403
                return json.dumps(res)

            throttle = LoginThrottle(user, login_throttle_key)
            locked_out = throttle.is_locked()
            if locked_out:
                log.info(
                    'User {} attempted login while brute force lockout in place'
                    .format(user_name))

            invalid_login = user is None or not user.is_active(
            ) or not user.validate_password(identity['password'])
            if invalid_login:
                # Increment the throttle counter if the login failed.
                throttle.increment()

            if locked_out or invalid_login:
                log.info('login failed')
                tk.response.status_int = 403
                return json.dumps(res)

            # find or create 2 factor auth record
            totp_challenger = SecurityTOTP.get_for_user(user.name)
            if totp_challenger is None:
                totp_challenger = SecurityTOTP.create_for_user(user.name)

            mfaConfigured = totp_challenger.last_successful_challenge is not None
            if not mfaConfigured:
                res['totpSecret'] = totp_challenger.secret
                res['totpChallengerURI'] = totp_challenger.provisioning_uri

            res['mfaConfigured'] = mfaConfigured

            if identity['mfa']:
                res['mfaCodeValid'] = totp_challenger.check_code(
                    identity['mfa'], verify_only=True)

            return json.dumps(res)

        except Exception as err:
            log.error('Unhandled error during login: {}'.format(err))
            tk.response.status_int = 500
            return json.dumps({})
コード例 #6
0
    def login(self):
        """
        Ajax call to test username/password/mfa code
        """

        def set_response(status):
            tk.response.status_int = status
            tk.response.headers.update({'Content-Type': 'application/json'})

        try:
            res = {}
            if request.method != 'POST':
                set_response(405)
                return json.dumps(res)

            identity = request.params
            if not ('login' in identity and 'password' in identity):
                set_response(422)
                return json.dumps(res)

            on_mfa_form = identity.get('mfa-form-active') == 'true'

            user_name = identity['login']
            user = model.User.by_name(user_name)

            login_throttle_key = get_login_throttle_key(request, user_name)
            if login_throttle_key is None:
                set_response(403)
                return json.dumps(res)

            throttle = LoginThrottle(user, login_throttle_key)
            locked_out = throttle.is_locked()
            if locked_out:
                log.info('User %s attempted login while brute force lockout in place', user_name)

            invalid_login = user is None or not user.is_active() or not user.validate_password(identity['password'])
            if invalid_login:
                # Increment the throttle counter if the login failed.
                throttle.increment()

            if invalid_login or (locked_out and not on_mfa_form):
                log.info('login failed for %s', user_name)
                set_response(403)
                return json.dumps(res)

            # find or create 2 factor auth record
            totp_challenger = SecurityTOTP.get_for_user(user.name)
            if totp_challenger is None:
                totp_challenger = SecurityTOTP.create_for_user(user.name)

            mfaConfigured = totp_challenger.last_successful_challenge is not None
            if not mfaConfigured:
                res['totpSecret'] = totp_challenger.secret
                res['totpChallengerURI'] = totp_challenger.provisioning_uri

            res['mfaConfigured'] = mfaConfigured
            set_response(200)

            if identity['mfa']:
                code_valid = totp_challenger.check_code(identity['mfa'], verify_only=True)
                res['mfaCodeValid'] = code_valid and not locked_out
                if code_valid:
                    log.info('Login succeeded for %s', user_name)
                else:
                    log.info('User %s supplied invalid 2fa code', user_name)
                    set_response(403)
                    throttle.increment()

            return json.dumps(res)

        except Exception as err:
            log.error('Unhandled error during login: %s', err)
            set_response(500)
            return json.dumps({})