def auth_user_passthru(wrapped_function, user_object, passw, options=None):
    """
    This decorator checks the policy settings of ACTION.PASSTHRU.
    If the authentication against the userstore is not successful,
    the wrapped function is called.

    The wrapped function is usually token.check_user_pass, which takes the
    arguments (user, passw, options={})

    :param wrapped_function:
    :param user_object:
    :param passw:
    :param options: Dict containing values for "g" and "clientip"
    :return: Tuple of True/False and reply-dictionary
    """

    from privacyidea.lib.token import get_tokens
    options = options or {}
    g = options.get("g")
    if g:
        clientip = options.get("clientip")
        policy_object = g.policy_object
        pass_thru = policy_object.get_policies(action=ACTION.PASSTHRU,
                                               scope=SCOPE.AUTH,
                                               realm=user_object.realm,
                                               resolver=user_object.resolver,
                                               user=user_object.login,
                                               client=clientip,
                                               active=True)
        if len(pass_thru) > 1:
            raise PolicyError("Contradicting passthru policies.")
        if pass_thru and get_tokens(user=user_object, count=True) == 0:
            # If the user has NO Token, authenticate against the user store
            # Now we need to check the userstore password
            pass_thru_action = pass_thru[0].get("action").get("passthru")
            policy_name = pass_thru[0].get("name")
            if pass_thru_action in ["userstore", True]:
                if user_object.check_password(passw):
                    return True, {
                        "message":
                        "The user authenticated against "
                        "his userstore according to "
                        "policy '%s'." % policy_name
                    }
            else:
                # We are doing RADIUS passthru
                log.info("Forwarding the authentication request to the radius "
                         "server %s" % pass_thru_action)
                radius = get_radius(pass_thru_action)
                r = radius.request(radius.config, user_object.login, passw)
                if r:
                    return True, {
                        'message':
                        "The user authenticated against "
                        "the RADIUS server %s according "
                        "to policy '%s'." % (pass_thru_action, policy_name)
                    }

    # If nothing else returned, we return the wrapped function
    return wrapped_function(user_object, passw, options)
Exemple #2
0
 def test_07_non_ascii(self):
     radiusmock.setdata(response=radiusmock.AccessAccept)
     r = add_radius(identifier="myserver", server="1.2.3.4",
                    secret="testing123", dictionary=DICT_FILE)
     self.assertTrue(r > 0)
     radius = get_radius("myserver")
     r = RADIUSServer.request(radius.config, u"nönäscii", u"passwörd")
     self.assertEqual(r, True)
 def test_05_RADIUS_request(self):
     radiusmock.setdata(success=True, timeout=True)
     r = add_radius(identifier="myserver", server="1.2.3.4",
                    secret="testing123", dictionary=DICT_FILE)
     self.assertTrue(r > 0)
     radius = get_radius("myserver")
     # A timeout will return false
     r = RADIUSServer.request(radius.config, "user", "password")
     self.assertEqual(r, False)
Exemple #4
0
 def test_05_RADIUS_request(self):
     radiusmock.setdata(response=radiusmock.AccessAccept, timeout=True)
     r = add_radius(identifier="myserver", server="1.2.3.4",
                    secret="testing123", dictionary=DICT_FILE)
     self.assertTrue(r > 0)
     radius = get_radius("myserver")
     # A timeout will return false
     r = RADIUSServer.request(radius.config, "user", "password")
     self.assertEqual(r, False)
def auth_user_passthru(wrapped_function, user_object, passw, options=None):
    """
    This decorator checks the policy settings of ACTION.PASSTHRU.
    If the authentication against the userstore is not successful,
    the wrapped function is called.

    The wrapped function is usually token.check_user_pass, which takes the
    arguments (user, passw, options={})

    :param wrapped_function:
    :param user_object:
    :param passw:
    :param options: Dict containing values for "g" and "clientip"
    :return: Tuple of True/False and reply-dictionary
    """
    from privacyidea.lib.token import get_tokens
    options = options or {}
    g = options.get("g")
    if g:
        policy_object = g.policy_object
        clientip = options.get("clientip")
        pass_thru = policy_object.get_policies(action=ACTION.PASSTHRU,
                                               scope=SCOPE.AUTH,
                                               realm=user_object.realm,
                                               resolver=user_object.resolver,
                                               user=user_object.login,
                                               client=clientip,
                                               active=True,
                                               sort_by_priority=True)
        # We only go to passthru, if the user has no tokens!
        if pass_thru and get_tokens(user=user_object, count=True) == 0:
            # Ensure that there are no conflicting action values within the same priority
            policy_object.check_for_conflicts(pass_thru, "passthru")
            pass_thru_action = pass_thru[0].get("action").get("passthru")
            policy_name = pass_thru[0].get("name")
            if pass_thru_action in ["userstore", True]:
                # Now we need to check the userstore password
                if user_object.check_password(passw):
                    g.audit_object.add_policy([p.get("name") for p in pass_thru])
                    return True, {"message": u"against userstore due to '{!s}'".format(
                                      policy_name)}
            else:
                # We are doing RADIUS passthru
                log.info("Forwarding the authentication request to the radius "
                         "server %s" % pass_thru_action)
                radius = get_radius(pass_thru_action)
                r = radius.request(radius.config, user_object.login, passw)
                if r:
                    g.audit_object.add_policy([p.get("name") for p in pass_thru])
                    return True, {'message': u"against RADIUS server {!s} due to '{!s}'".format(
                                      pass_thru_action, policy_name)}

    # If nothing else returned, we return the wrapped function
    return wrapped_function(user_object, passw, options)
def auth_user_passthru(wrapped_function, user_object, passw, options=None):
    """
    This decorator checks the policy settings of ACTION.PASSTHRU.
    If the authentication against the userstore is not successful,
    the wrapped function is called.

    The wrapped function is usually token.check_user_pass, which takes the
    arguments (user, passw, options={})

    :param wrapped_function:
    :param user_object:
    :param passw:
    :param options: Dict containing values for "g" and "clientip"
    :return: Tuple of True/False and reply-dictionary
    """

    from privacyidea.lib.token import get_tokens
    options = options or {}
    g = options.get("g")
    if g:
        clientip = options.get("clientip")
        policy_object = g.policy_object
        pass_thru = policy_object.get_policies(action=ACTION.PASSTHRU,
                                               scope=SCOPE.AUTH,
                                               realm=user_object.realm,
                                               resolver=user_object.resolver,
                                               user=user_object.login,
                                               client=clientip, active=True)
        if len(pass_thru) > 1:
            raise PolicyError("Contradicting passthru policies.")
        if pass_thru and get_tokens(user=user_object, count=True) == 0:
            # If the user has NO Token, authenticate against the user store
            # Now we need to check the userstore password
            pass_thru_action = pass_thru[0].get("action").get("passthru")
            policy_name = pass_thru[0].get("name")
            if pass_thru_action in ["userstore", True]:
                if user_object.check_password(passw):
                    return True, {"message": "The user authenticated against "
                                             "his userstore according to "
                                             "policy '%s'." % policy_name}
            else:
                # We are doing RADIUS passthru
                log.info("Forwarding the authentication request to the radius "
                         "server %s" % pass_thru_action)
                radius = get_radius(pass_thru_action)
                r = radius.request(radius.config, user_object.login, passw)
                if r:
                    return True, {'message': "The user authenticated against "
                                             "the RADIUS server %s according "
                                             "to policy '%s'." %
                                             (pass_thru_action, policy_name)}

    # If nothing else returned, we return the wrapped function
    return wrapped_function(user_object, passw, options)
def auth_user_passthru(wrapped_function, user_object, passw, options=None):
    """
    This decorator checks the policy settings of ACTION.PASSTHRU.
    If the authentication against the userstore is not successful,
    the wrapped function is called.

    The wrapped function is usually token.check_user_pass, which takes the
    arguments (user, passw, options={})

    :param wrapped_function:
    :param user_object:
    :param passw:
    :param options: Dict containing values for "g" and "clientip"
    :return: Tuple of True/False and reply-dictionary
    """
    from privacyidea.lib.token import get_tokens
    options = options or {}
    g = options.get("g")
    if get_tokens(user=user_object, count=True) == 0 and g:
        # We only go to passthru, if the user has no tokens!
        clientip = options.get("clientip")
        policy_object = g.policy_object
        pass_thru = policy_object.get_policies(action=ACTION.PASSTHRU,
                                               scope=SCOPE.AUTH,
                                               realm=user_object.realm,
                                               resolver=user_object.resolver,
                                               user=user_object.login,
                                               client=clientip,
                                               active=True,
                                               sort_by_priority=True)
        # Ensure that there are no conflicting action values within the same priority
        policy_object.check_for_conflicts(pass_thru, "passthru")
        if pass_thru:
            pass_thru_action = pass_thru[0].get("action").get("passthru")
            policy_name = pass_thru[0].get("name")
            if pass_thru_action in ["userstore", True]:
                # Now we need to check the userstore password
                if user_object.check_password(passw):
                    g.audit_object.add_policy([p.get("name") for p in pass_thru])
                    return True, {"message": u"against userstore due to '{!s}'".format(
                                      policy_name)}
            else:
                # We are doing RADIUS passthru
                log.info("Forwarding the authentication request to the radius "
                         "server %s" % pass_thru_action)
                radius = get_radius(pass_thru_action)
                r = radius.request(radius.config, user_object.login, passw)
                if r:
                    g.audit_object.add_policy([p.get("name") for p in pass_thru])
                    return True, {'message': u"against RADIUS server {!s} due to '{!s}'".format(
                                      pass_thru_action, policy_name)}

    # If nothing else returned, we return the wrapped function
    return wrapped_function(user_object, passw, options)
    def test_04_RADIUS_request(self):
        radiusmock.setdata(success=True)
        r = add_radius(identifier="myserver", server="1.2.3.4",
                       secret="testing123", dictionary=DICT_FILE)
        self.assertTrue(r > 0)
        radius = get_radius("myserver")
        r = RADIUSServer.request(radius.config, "user", "password")
        self.assertEqual(r, True)

        radiusmock.setdata(success=False)
        r = RADIUSServer.request(radius.config, "user", "password")
        self.assertEqual(r, False)
    def check_otp(self, otpval, counter=None, window=None, options=None):
        """
        run the RADIUS request against the RADIUS server

        :param otpval: the OTP value
        :param counter: The counter for counter based otp values
        :type counter: int
        :param window: a counter window
        :type counter: int
        :param options: additional token specific options
        :type options: dict
        :return: counter of the matching OTP value.
        :rtype: int
        """
        otp_count = -1
        options = options or {}

        radius_dictionary = None
        radius_identifier = self.get_tokeninfo("radius.identifier")
        radius_user = self.get_tokeninfo("radius.user")
        system_radius_settings = self.get_tokeninfo("radius.system_settings")
        if radius_identifier:
            # New configuration
            radius_server_object = get_radius(radius_identifier)
            radius_server = radius_server_object.config.server
            radius_port = radius_server_object.config.port
            radius_server = "%s:%s" % (radius_server, radius_port)
            radius_secret = radius_server_object.get_secret()
            radius_dictionary = radius_server_object.config.dictionary

        elif system_radius_settings:
            # system configuration
            radius_server = get_from_config("radius.server")
            radius_secret = get_from_config("radius.secret")
            # Is returned as unicode, so we convert it to utf-8
            radius_secret = radius_secret.encode("utf-8")
        else:
            # individual token settings
            radius_server = self.get_tokeninfo("radius.server")
            # Read the secret
            secret = self.token.get_otpkey()
            radius_secret = binascii.unhexlify(secret.getKey())

        # here we also need to check for radius.user
        log.debug("checking OTP len:%s on radius server: %s, user: %s" 
                  % (len(otpval), radius_server, radius_user))

        try:
            # pyrad does not allow to set timeout and retries.
            # it defaults to retries=3, timeout=5

            # TODO: At the moment we support only one radius server.
            # No round robin.
            server = radius_server.split(':')
            r_server = server[0]
            r_authport = 1812
            if len(server) >= 2:
                r_authport = int(server[1])
            nas_identifier = get_from_config("radius.nas_identifier",
                                             "privacyIDEA")
            if not radius_dictionary:
                radius_dictionary = get_from_config("radius.dictfile",
                                                    "/etc/privacyidea/"
                                                    "dictionary")
            log.debug("NAS Identifier: %r, "
                      "Dictionary: %r" % (nas_identifier, radius_dictionary))
            log.debug("constructing client object "
                      "with server: %r, port: %r, secret: %r" %
                      (r_server, r_authport, radius_secret))

            srv = Client(server=r_server,
                         authport=r_authport,
                         secret=radius_secret,
                         dict=Dictionary(radius_dictionary))

            req = srv.CreateAuthPacket(code=pyrad.packet.AccessRequest,
                                       User_Name=radius_user.encode('ascii'),
                                       NAS_Identifier=nas_identifier.encode('ascii'))

            req["User-Password"] = req.PwCrypt(otpval)
            if "transactionid" in options:
                req["State"] = str(options.get("transactionid"))

            response = srv.SendPacket(req)
            c = response.code
            # TODO: handle the RADIUS challenge
            """
            if response.code == pyrad.packet.AccessChallenge:
                opt = {}
                for attr in response.keys():
                    opt[attr] = response[attr]
                res = False
                log.debug("challenge returned %r " % opt)
                # now we map this to a privacyidea challenge
                if "State" in opt:
                    reply["transactionid"] = opt["State"][0]
                if "Reply-Message" in opt:
                    reply["message"] = opt["Reply-Message"][0]
            """
            if response.code == pyrad.packet.AccessAccept:
                log.info("Radiusserver %s granted "
                         "access to user %s." % (r_server, radius_user))
                otp_count = 0
            else:
                log.warning("Radiusserver %s"
                            "rejected access to user %s." %
                            (r_server, radius_user))

        except Exception as ex:  # pragma: no cover
            log.error("Error contacting radius Server: %r" % (ex))
            log.debug("%s" % traceback.format_exc())

        return otp_count
Exemple #10
0
def auth_user_passthru(wrapped_function, user_object, passw, options=None):
    """
    This decorator checks the policy settings of ACTION.PASSTHRU.
    If the authentication against the userstore is not successful,
    the wrapped function is called.

    The wrapped function is usually token.check_user_pass, which takes the
    arguments (user, passw, options={})

    :param wrapped_function:
    :param user_object:
    :param passw:
    :param options: Dict containing values for "g" and "clientip"
    :return: Tuple of True/False and reply-dictionary
    """
    from privacyidea.lib.token import get_tokens
    from privacyidea.lib.token import assign_token
    options = options or {}
    g = options.get("g")
    if g:
        policy_object = g.policy_object
        pass_thru = Match.user(
            g,
            scope=SCOPE.AUTH,
            action=ACTION.PASSTHRU,
            user_object=user_object).policies(write_to_audit_log=False)
        # We only go to passthru, if the user has no tokens!
        if pass_thru and get_tokens(user=user_object, count=True) == 0:
            # Ensure that there are no conflicting action values within the same priority
            policy_object.check_for_conflicts(pass_thru, "passthru")
            pass_thru_action = pass_thru[0].get("action").get("passthru")
            policy_name = pass_thru[0].get("name")
            if pass_thru_action in ["userstore", True]:
                # Now we need to check the userstore password
                if user_object.check_password(passw):
                    g.audit_object.add_policy(
                        [p.get("name") for p in pass_thru])
                    return True, {
                        "message":
                        u"against userstore due to '{!s}'".format(policy_name)
                    }
            else:
                # We are doing RADIUS passthru
                log.info("Forwarding the authentication request to the radius "
                         "server %s" % pass_thru_action)
                radius = get_radius(pass_thru_action)
                r = radius.request(radius.config, user_object.login, passw)
                if r:
                    g.audit_object.add_policy(
                        [p.get("name") for p in pass_thru])
                    # TODO: here we can check, if the token should be assigned.
                    passthru_assign = Match.user(
                        g,
                        scope=SCOPE.AUTH,
                        action=ACTION.PASSTHRU_ASSIGN,
                        user_object=user_object).action_values(unique=True)
                    messages = []
                    if passthru_assign:
                        components = list(passthru_assign)[0].split(":")
                        if len(components) >= 2:
                            prepend_pin = components[0] == "pin"
                            otp_length = int(components[int(prepend_pin)])
                            pin, otp = split_pin_pass(passw, otp_length,
                                                      prepend_pin)
                            realm_tokens = get_tokens(realm=user_object.realm,
                                                      assigned=False)
                            window = 100
                            if len(components) == 3:
                                window = int(components[2])
                            for token_obj in realm_tokens:
                                otp_check = token_obj.check_otp(otp,
                                                                window=window)
                                if otp_check >= 0:
                                    # We do not check any max tokens per realm or user,
                                    # since this very user currently has no token
                                    # and the unassigned token already was contained in the user's realm
                                    assign_token(serial=token_obj.token.serial,
                                                 user=user_object,
                                                 pin=pin)
                                    messages.append(
                                        u"autoassigned {0!s}".format(
                                            token_obj.token.serial))
                                    break

                        else:
                            log.warning(
                                "Wrong value in passthru_assign policy: {0!s}".
                                format(passthru_assign))
                    messages.append(
                        u"against RADIUS server {!s} due to '{!s}'".format(
                            pass_thru_action, policy_name))
                    return True, {'message': ",".join(messages)}

    # If nothing else returned, we return the wrapped function
    return wrapped_function(user_object, passw, options)
    def _check_radius(self, otpval, options=None, radius_state=None):
        """
        run the RADIUS request against the RADIUS server

        :param otpval: the OTP value
        :param options: additional token specific options
        :type options: dict
        :return: counter of the matching OTP value.
        :rtype: AccessAccept, AccessReject, AccessChallenge
        """
        result = AccessReject
        radius_message = None
        if options is None:
            options = {}

        radius_dictionary = None
        radius_identifier = self.get_tokeninfo("radius.identifier")
        radius_user = self.get_tokeninfo("radius.user")
        system_radius_settings = self.get_tokeninfo("radius.system_settings")
        radius_timeout = 5
        radius_retries = 3
        if radius_identifier:
            # New configuration
            radius_server_object = get_radius(radius_identifier)
            radius_server = radius_server_object.config.server
            radius_port = radius_server_object.config.port
            radius_server = u"{0!s}:{1!s}".format(radius_server, radius_port)
            radius_secret = radius_server_object.get_secret()
            radius_dictionary = radius_server_object.config.dictionary
            radius_timeout = int(radius_server_object.config.timeout or 10)
            radius_retries = int(radius_server_object.config.retries or 1)
        elif system_radius_settings:
            # system configuration
            radius_server = get_from_config("radius.server")
            radius_secret = get_from_config("radius.secret")
        else:
            # individual token settings
            radius_server = self.get_tokeninfo("radius.server")
            # Read the secret
            secret = self.token.get_otpkey()
            radius_secret = binascii.unhexlify(secret.getKey())

        # here we also need to check for radius.user
        log.debug(u"checking OTP len:{0!s} on radius server: "
                  u"{1!s}, user: {2!r}".format(len(otpval), radius_server,
                                               radius_user))

        try:
            # pyrad does not allow to set timeout and retries.
            # it defaults to retries=3, timeout=5

            # TODO: At the moment we support only one radius server.
            # No round robin.
            server = radius_server.split(':')
            r_server = server[0]
            r_authport = 1812
            if len(server) >= 2:
                r_authport = int(server[1])
            nas_identifier = get_from_config("radius.nas_identifier",
                                             "privacyIDEA")
            if not radius_dictionary:
                radius_dictionary = get_from_config(
                    "radius.dictfile", "/etc/privacyidea/dictionary")
            log.debug(u"NAS Identifier: %r, "
                      u"Dictionary: %r" % (nas_identifier, radius_dictionary))
            log.debug(u"constructing client object "
                      u"with server: %r, port: %r, secret: %r" %
                      (r_server, r_authport, to_unicode(radius_secret)))

            srv = Client(server=r_server,
                         authport=r_authport,
                         secret=to_bytes(radius_secret),
                         dict=Dictionary(radius_dictionary))

            # Set retries and timeout of the client
            srv.timeout = radius_timeout
            srv.retries = radius_retries

            req = srv.CreateAuthPacket(
                code=pyrad.packet.AccessRequest,
                User_Name=radius_user.encode('utf-8'),
                NAS_Identifier=nas_identifier.encode('ascii'))

            req["User-Password"] = req.PwCrypt(otpval)

            if radius_state:
                req["State"] = radius_state
                log.info(
                    u"Sending saved challenge to radius server: {0!r} ".format(
                        radius_state))

            try:
                response = srv.SendPacket(req)
            except Timeout:
                log.warning(
                    u"The remote RADIUS server {0!s} timeout out for user {1!s}."
                    .format(r_server, radius_user))
                return AccessReject

            # handle the RADIUS challenge
            if response.code == pyrad.packet.AccessChallenge:
                # now we map this to a privacyidea challenge
                if "State" in response:
                    radius_state = response["State"][0]
                if "Reply-Message" in response:
                    radius_message = response["Reply-Message"][0]

                result = AccessChallenge
            elif response.code == pyrad.packet.AccessAccept:
                radius_state = '<SUCCESS>'
                radius_message = 'RADIUS authentication succeeded'
                log.info(u"RADIUS server {0!s} granted "
                         u"access to user {1!s}.".format(
                             r_server, radius_user))
                result = AccessAccept
            else:
                radius_state = '<REJECTED>'
                radius_message = 'RADIUS authentication failed'
                log.debug(u'radius response code {0!s}'.format(response.code))
                log.info(u"Radiusserver {0!s} "
                         u"rejected access to user {1!s}.".format(
                             r_server, radius_user))
                result = AccessReject

        except Exception as ex:  # pragma: no cover
            log.error("Error contacting radius Server: {0!r}".format((ex)))
            log.info("{0!s}".format(traceback.format_exc()))

        options.update({'radius_result': result})
        options.update({'radius_state': radius_state})
        options.update({'radius_message': radius_message})
        return result
Exemple #12
0
    def check_otp(self, otpval, counter=None, window=None, options=None):
        """
        run the RADIUS request against the RADIUS server

        :param otpval: the OTP value
        :param counter: The counter for counter based otp values
        :type counter: int
        :param window: a counter window
        :type counter: int
        :param options: additional token specific options
        :type options: dict
        :return: counter of the matching OTP value.
        :rtype: int
        """
        otp_count = -1
        options = options or {}

        radius_dictionary = None
        radius_identifier = self.get_tokeninfo("radius.identifier")
        radius_user = self.get_tokeninfo("radius.user")
        system_radius_settings = self.get_tokeninfo("radius.system_settings")
        if radius_identifier:
            # New configuration
            radius_server_object = get_radius(radius_identifier)
            radius_server = radius_server_object.config.server
            radius_port = radius_server_object.config.port
            radius_server = "{0!s}:{1!s}".format(radius_server, radius_port)
            radius_secret = radius_server_object.get_secret()
            radius_dictionary = radius_server_object.config.dictionary

        elif system_radius_settings:
            # system configuration
            radius_server = get_from_config("radius.server")
            radius_secret = get_from_config("radius.secret")
            # Is returned as unicode, so we convert it to utf-8
            radius_secret = radius_secret.encode("utf-8")
        else:
            # individual token settings
            radius_server = self.get_tokeninfo("radius.server")
            # Read the secret
            secret = self.token.get_otpkey()
            radius_secret = binascii.unhexlify(secret.getKey())

        # here we also need to check for radius.user
        log.debug(
            "checking OTP len:{0!s} on radius server: {1!s}, user: {2!r}".
            format(len(otpval), radius_server, radius_user))

        try:
            # pyrad does not allow to set timeout and retries.
            # it defaults to retries=3, timeout=5

            # TODO: At the moment we support only one radius server.
            # No round robin.
            server = radius_server.split(':')
            r_server = server[0]
            r_authport = 1812
            if len(server) >= 2:
                r_authport = int(server[1])
            nas_identifier = get_from_config("radius.nas_identifier",
                                             "privacyIDEA")
            if not radius_dictionary:
                radius_dictionary = get_from_config(
                    "radius.dictfile", "/etc/privacyidea/"
                    "dictionary")
            log.debug("NAS Identifier: %r, "
                      "Dictionary: %r" % (nas_identifier, radius_dictionary))
            log.debug("constructing client object "
                      "with server: %r, port: %r, secret: %r" %
                      (r_server, r_authport, radius_secret))

            srv = Client(server=r_server,
                         authport=r_authport,
                         secret=radius_secret,
                         dict=Dictionary(radius_dictionary))

            req = srv.CreateAuthPacket(
                code=pyrad.packet.AccessRequest,
                User_Name=radius_user.encode('ascii'),
                NAS_Identifier=nas_identifier.encode('ascii'))

            req["User-Password"] = req.PwCrypt(otpval)
            if "transactionid" in options:
                req["State"] = str(options.get("transactionid"))

            response = srv.SendPacket(req)
            c = response.code
            # TODO: handle the RADIUS challenge
            """
            if response.code == pyrad.packet.AccessChallenge:
                opt = {}
                for attr in response.keys():
                    opt[attr] = response[attr]
                res = False
                log.debug("challenge returned %r " % opt)
                # now we map this to a privacyidea challenge
                if "State" in opt:
                    reply["transactionid"] = opt["State"][0]
                if "Reply-Message" in opt:
                    reply["message"] = opt["Reply-Message"][0]
            """
            if response.code == pyrad.packet.AccessAccept:
                log.info("Radiusserver %s granted "
                         "access to user %s." % (r_server, radius_user))
                otp_count = 0
            else:
                log.warning("Radiusserver %s"
                            "rejected access to user %s." %
                            (r_server, radius_user))

        except Exception as ex:  # pragma: no cover
            log.error("Error contacting radius Server: {0!r}".format((ex)))
            log.debug("{0!s}".format(traceback.format_exc()))

        return otp_count
def auth_user_passthru(wrapped_function, user_object, passw, options=None):
    """
    This decorator checks the policy settings of ACTION.PASSTHRU.
    If the authentication against the userstore is not successful,
    the wrapped function is called.

    The wrapped function is usually token.check_user_pass, which takes the
    arguments (user, passw, options={})

    :param wrapped_function:
    :param user_object:
    :param passw:
    :param options: Dict containing values for "g" and "clientip"
    :return: Tuple of True/False and reply-dictionary
    """
    from privacyidea.lib.token import get_tokens
    from privacyidea.lib.token import assign_token
    options = options or {}
    g = options.get("g")
    if g:
        policy_object = g.policy_object
        clientip = options.get("clientip")
        pass_thru = policy_object.get_policies(action=ACTION.PASSTHRU,
                                               scope=SCOPE.AUTH,
                                               realm=user_object.realm,
                                               resolver=user_object.resolver,
                                               user=user_object.login,
                                               client=clientip,
                                               active=True,
                                               sort_by_priority=True)
        # We only go to passthru, if the user has no tokens!
        if pass_thru and get_tokens(user=user_object, count=True) == 0:
            # Ensure that there are no conflicting action values within the same priority
            policy_object.check_for_conflicts(pass_thru, "passthru")
            pass_thru_action = pass_thru[0].get("action").get("passthru")
            policy_name = pass_thru[0].get("name")
            if pass_thru_action in ["userstore", True]:
                # Now we need to check the userstore password
                if user_object.check_password(passw):
                    g.audit_object.add_policy([p.get("name") for p in pass_thru])
                    return True, {"message": u"against userstore due to '{!s}'".format(
                                      policy_name)}
            else:
                # We are doing RADIUS passthru
                log.info("Forwarding the authentication request to the radius "
                         "server %s" % pass_thru_action)
                radius = get_radius(pass_thru_action)
                r = radius.request(radius.config, user_object.login, passw)
                if r:
                    g.audit_object.add_policy([p.get("name") for p in pass_thru])
                    # TODO: here we can check, if the token should be assigned.
                    passthru_assign = policy_object.get_action_values(action=ACTION.PASSTHRU_ASSIGN,
                                                                      scope=SCOPE.AUTH,
                                                                      realm=user_object.realm,
                                                                      resolver=user_object.resolver,
                                                                      user=user_object.login,
                                                                      client=clientip,
                                                                      unique=True,
                                                                      audit_data=g.audit_object.audit_data)
                    messages = []
                    if passthru_assign:
                        components = list(passthru_assign)[0].split(":")
                        if len(components) >= 2:
                            prepend_pin = components[0] == "pin"
                            otp_length = int(components[int(prepend_pin)])
                            pin, otp = split_pin_pass(passw, otp_length, prepend_pin)
                            realm_tokens = get_tokens(realm=user_object.realm,
                                                      assigned=False)
                            window = 100
                            if len(components) == 3:
                                window = int(components[2])
                            for token_obj in realm_tokens:
                                otp_check = token_obj.check_otp(otp, window=window)
                                if otp_check >= 0:
                                    # We do not check any max tokens per realm or user,
                                    # since this very user currently has no token
                                    # and the unassigned token already was contained in the user's realm
                                    assign_token(serial=token_obj.token.serial,
                                                 user=user_object, pin=pin)
                                    messages.append(u"autoassigned {0!s}".format(token_obj.token.serial))
                                    break

                        else:
                            log.warning("Wrong value in passthru_assign policy: {0!s}".format(passthru_assign))
                    messages.append(u"against RADIUS server {!s} due to '{!s}'".format(pass_thru_action, policy_name))
                    return True, {'message': ",".join(messages)}

    # If nothing else returned, we return the wrapped function
    return wrapped_function(user_object, passw, options)