Exemple #1
0
    def update(self, param, reset_failcount=True):
        """
        update - process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        if self.hKeyRequired is True:
            genkey = is_true(getParam(param, "genkey", optional))
            if not param.get('keysize'):
                param['keysize'] = 16
            if genkey:
                otpKey = generate_otpkey(param['keysize'])
                del param['genkey']
            else:
                # genkey not set: check otpkey is given
                # this will raise an exception if otpkey is not present
                otpKey = getParam(param, "otpkey", required)

            param['otpkey'] = otpKey
            
        # motp token specific
        mOTPPin = getParam(param, "motppin", required)
        self.token.set_user_pin(mOTPPin)

        TokenClass.update(self, param, reset_failcount)

        return
Exemple #2
0
def before_request():
    """
    This is executed before the request
    """
    ensure_no_config_object()
    request.all_data = get_all_params(request.values, request.data)
    privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \
                         request.host
    g.policy_object = PolicyClass()
    g.audit_object = getAudit(current_app.config)
    g.event_config = EventConfiguration()
    # access_route contains the ip adresses of all clients, hops and proxies.
    g.client_ip = get_client_ip(request,
                                get_from_config(SYSCONF.OVERRIDECLIENT))
    g.audit_object.log({"success": False,
                        "client": g.client_ip,
                        "client_user_agent": request.user_agent.browser,
                        "privacyidea_server": privacyidea_server,
                        "action": "{0!s} {1!s}".format(request.method, request.url_rule),
                        "action_detail": "",
                        "info": ""})

    username = getParam(request.all_data, "username")
    if username:
        # We only fill request.User, if we really have a username.
        # On endpoints like /auth/rights, this is not available
        loginname, realm = split_user(username)
        # overwrite the split realm if we have a realm parameter. Default back to default_realm
        realm = getParam(request.all_data, "realm", default=realm) or realm or get_default_realm()
        # Prefill the request.User. This is used by some pre-event handlers
        request.User = User(loginname, realm)
    def update(self, param, reset_failcount=True):
        """
        update - process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing

        """
        if getParam(param, "dynamic_email", optional=True):
            self.add_tokeninfo("dynamic_email", True)
        else:
            # specific - e-mail
            self._email_address = getParam(param,
                                           self.EMAIL_ADDRESS_KEY,
                                           optional=False)

        # in case of the e-mail token, only the server must know the otpkey
        # thus if none is provided, we let create one (in the TokenClass)
        if 'genkey' not in param and 'otpkey' not in param:
            param['genkey'] = 1

        HotpTokenClass.update(self, param, reset_failcount)
        return
Exemple #4
0
    def update(self, param, reset_failcount=True):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)
        description = "U2F initialization"
        reg_data = getParam(param, "regdata")
        if reg_data:
            self.init_step = 2
            attestation_cert, user_pub_key, key_handle, \
                signature, description = parse_registration_data(reg_data)
            client_data = getParam(param, "clientdata", required)
            client_data_str = url_decode(client_data)
            app_id = self.get_tokeninfo("appId", "")
            # Verify the registration data
            # In case of any crypto error, check_data raises an exception
            check_registration_data(attestation_cert, app_id, client_data_str,
                                    user_pub_key, key_handle, signature)
            self.set_otpkey(key_handle)
            self.add_tokeninfo("pubKey", user_pub_key)

        self.set_description(description)
    def api_endpoint(cls, request, g):
        """
        This provides a function to be plugged into the API endpoint
        /ttype/yubikey which is defined in api/ttype.py

        The endpoint /ttype/yubikey is used for the Yubico validate request
        according to
        https://developers.yubico.com/yubikey-val/Validation_Protocol_V2.0.html

        :param request: The Flask request
        :param g: The Flask global object g
        :return: Flask Response or text

        Required query parameters

        :query id: The id of the client to identify the correct shared secret
        :query otp: The OTP from the yubikey in the yubikey mode
        :query nonce: 16-40 bytes of random data

        Optional parameters h, timestamp, sl, timeout are not supported at the
        moment.
        """
        id = getParam(request.all_data, "id")
        otp = getParam(request.all_data, "otp")
        nonce = getParam(request.all_data, "nonce")
        signature = getParam(request.all_data, "h")
        status = "MISSING_PARAMETER"

        timestamp = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ%f")
        data = {'otp': otp,
                'nonce': nonce,
                'status': status,
                'timestamp': timestamp}

        api_key = cls._get_api_key(id)
        if api_key is None:
            data['status'] = "NO_SUCH_CLIENT"
            data['h'] = ""
        elif otp and id and nonce:
            if signature and not yubico_check_api_signature(request.all_data,
                                                            api_key, signature):
                # yubico server don't send nonce and otp back. Do we want that?
                data['status'] = "BAD_SIGNATURE"
            else:
                res, opt = cls.check_yubikey_pass(otp)
                if res:
                    data['status'] = "OK"
                else:
                    # Do we want REPLAYED_OTP too?
                    data['status'] = "BAD_OTP"

            data["h"] = yubico_api_signature(data, api_key)
        response = """nonce={nonce}
otp={otp}
status={status}
timestamp={timestamp}
h={h}
""".format(**data)

        return "plain", response
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        request = getParam(param, "request", optional)
        spkac = getParam(param, "spkac", optional)
        certificate = None
        if request:
            ca = getParam(param, "ca", required)
            self.add_tokeninfo("CA", ca)
            # During the initialization process, we need to create the
            # certificate
            cacon = get_caconnector_object(ca)
            x509object = cacon.sign_request(request,
                                            options={"spkac": spkac})
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
        else:
            certificate = getParam(param, "certificate", optional)

        if certificate:
            self.add_tokeninfo("certificate", certificate)
    def update(self, param):
        """
        The key holds the public ssh key and this is required
        
        The key probably is of the form "ssh-rsa BASE64 comment"
        """
        # We need to save the token, so that we can later add the tokeninfo
        # Otherwise we might not have created the DB entry, yet and we would
        # be missing the token.id
        self.token.save()

        getParam(param, "sshkey", required)
            
        key_elem = param.get("sshkey").split(" ", 2)
        if len(key_elem) != 3 or key_elem[0] != "ssh-rsa":
            raise Exception("The key must consist of 'ssh-rsa BASE64 comment'")

        key_type = key_elem[0]
        key = key_elem[1]
        key_comment = key_elem[2]
        
        # convert key to hex
        self.add_tokeninfo("ssh_key", key, value_type="password")
        self.add_tokeninfo("ssh_type", key_type)
        self.add_tokeninfo("ssh_comment", key_comment)

        # call the parents function
        TokenClass.update(self, param)
Exemple #8
0
    def update(self, param, reset_failcount=True):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)
        description = "U2F initialization"
        reg_data = getParam(param, "regdata")
        if reg_data:
            self.init_step = 2
            attestation_cert, user_pub_key, key_handle, \
                signature, description = parse_registration_data(reg_data)
            client_data = getParam(param, "clientdata", required)
            client_data_str = url_decode(client_data)
            app_id = self.get_tokeninfo("appId", "")
            # Verify the registration data
            # In case of any crypto error, check_data raises an exception
            check_registration_data(attestation_cert, app_id, client_data_str,
                                    user_pub_key, key_handle, signature)
            self.set_otpkey(key_handle)
            self.add_tokeninfo("pubKey", user_pub_key)

        self.set_description(description)
    def update(self, param):
        """
        second phase of the init process - updates parameters

        :param param: the request parameters
        :return: - nothing -
        """
        # if another OTP length would be specified in /admin/init this would
        # be overwritten by the parent class, which is ok.
        self.set_otplen(6)
        TokenClass.update(self, param)

        remoteServer = getParam(param, "remote.server", required)
        self.add_tokeninfo("remote.server", remoteServer)

        val = getParam(param, "remote.local_checkpin", optional) or 0
        self.add_tokeninfo("remote.local_checkpin", val)

        for key in [
                "remote.serial", "remote.user", "remote.realm",
                "remote.resolver"
        ]:
            val = getParam(param, key, optional)
            if val is not None:
                self.add_tokeninfo(key, val)
Exemple #10
0
    def update(self, param, reset_failcount=True):
        """
        update - process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        if self.hKeyRequired is True:
            genkey = is_true(getParam(param, "genkey", optional))
            if not param.get('keysize'):
                param['keysize'] = 16
            if genkey:
                otpKey = generate_otpkey(param['keysize'])
                del param['genkey']
            else:
                # genkey not set: check otpkey is given
                # this will raise an exception if otpkey is not present
                otpKey = getParam(param, "otpkey", required)

            param['otpkey'] = otpKey
            
        # motp token specific
        mOTPPin = getParam(param, "motppin", required)
        self.token.set_user_pin(mOTPPin)

        TokenClass.update(self, param, reset_failcount)

        return
Exemple #11
0
    def update(self, param, reset_failcount=True):
        """
        update - process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing

        """
        verify = getParam(param, "verify", optional=True)
        if not verify:
            if getParam(param, "dynamic_email", optional=True):
                self.add_tokeninfo("dynamic_email", True)
            else:
                # specific - e-mail
                self._email_address = getParam(param,
                                               self.EMAIL_ADDRESS_KEY,
                                               optional=False)

            # in case of the e-mail token, only the server must know the otpkey
            # thus if none is provided, we let create one (in the TokenClass)
            if 'genkey' not in param and 'otpkey' not in param:
                param['genkey'] = 1

        HotpTokenClass.update(self, param, reset_failcount)
        return
Exemple #12
0
def get_statistics(stats_key=None):
    """
    return a list of all available statistics keys in the database if no *stats_key*
    is specified.

    If a stats_key is specified it returns the data of this key.
    The parameters "start" and "end" can be used to specify a time window,
    from which the statistics data should be fetched.
    """
    if stats_key is None:
        stats_keys = get_stats_keys()
        g.audit_object.log({"success": True})
        return send_result(stats_keys)
    else:
        param = request.all_data
        start = getParam(param, "start")
        if start:
            start = parse_legacy_time(start, return_date=True)
        end = getParam(param, "end")
        if end:
            end = parse_legacy_time(end, return_date=True)
        values = get_values(stats_key=stats_key,
                            start_timestamp=start,
                            end_timestamp=end)
        # convert timestamps to strings
        values_w_string = [(s[0].strftime(AUTH_DATE_FORMAT), s[1])
                           for s in values]
        g.audit_object.log({"success": True})
        return send_result(values_w_string)
    def update(self, param):
        """
        second phase of the init process - updates parameters

        :param param: the request parameters
        :return: - nothing -
        """
        # if another OTP length would be specified in /admin/init this would
        # be overwritten by the parent class, which is ok.
        self.set_otplen(6)
        TokenClass.update(self, param)

        remoteServer = getParam(param, "remote.server", required)
        self.add_tokeninfo("remote.server", remoteServer)

        val = getParam(param, "remote.local_checkpin", optional) or 0
        self.add_tokeninfo("remote.local_checkpin", val)

        for key in ["remote.serial", "remote.user", "remote.path",
                    "remote.realm", "remote.resolver"]:
            val = getParam(param, key, optional)
            if val is not None:
                self.add_tokeninfo(key, val)

        self.add_tokeninfo("tokenkind", TOKENKIND.VIRTUAL)
Exemple #14
0
    def update(self, param):
        """
        The key holds the public ssh key and this is required
        
        The key probably is of the form "ssh-rsa BASE64 comment"
        """
        # We need to save the token, so that we can later add the tokeninfo
        # Otherwise we might not have created the DB entry, yet and we would
        # be missing the token.id
        self.token.save()

        getParam(param, "sshkey", required)

        key_elem = param.get("sshkey").split(" ", 2)
        if len(key_elem) != 3 or key_elem[0] != "ssh-rsa":
            raise Exception("The key must consist of 'ssh-rsa BASE64 comment'")

        key_type = key_elem[0]
        key = key_elem[1]
        key_comment = key_elem[2]

        # convert key to hex
        self.add_tokeninfo("ssh_key", key, value_type="password")
        self.add_tokeninfo("ssh_type", key_type)
        self.add_tokeninfo("ssh_comment", key_comment)

        # call the parents function
        TokenClass.update(self, param)
Exemple #15
0
    def test_01_getParam(self):
        s = getParam({"serial": ""},
                     "serial",
                     optional=False,
                     allow_empty=True)
        self.assertEqual(s, "")

        self.assertRaises(ParameterError,
                          getParam, {"serial": ""},
                          "serial",
                          optional=False,
                          allow_empty=False)

        # check for allowed values
        v = getParam({"sslverify": "0"},
                     "sslverify",
                     allowed_values=["0", "1"],
                     default="1")
        self.assertEqual("0", v)

        v = getParam({"sslverify": "rogue value"},
                     "sslverify",
                     allowed_values=["0", "1"],
                     default="1")
        self.assertEqual("1", v)

        v = getParam({}, "sslverify", allowed_values=["0", "1"], default="1")
        self.assertEqual("1", v)
Exemple #16
0
def get_statistics(stats_key=None):
    """
    return a list of all available statistics keys in the database if no *stats_key*
    is specified.

    If a stats_key is specified it returns the data of this key.
    The parameters "start" and "end" can be used to specify a time window,
    from which the statistics data should be fetched.
    """
    if stats_key is None:
        stats_keys = get_stats_keys()
        g.audit_object.log({"success": True})
        return send_result(stats_keys)
    else:
        param = request.all_data
        start = getParam(param, "start")
        if start:
            start = parse_legacy_time(start, return_date=True)
        end = getParam(param, "end")
        if end:
            end = parse_legacy_time(end, return_date=True)
        values = get_values(stats_key=stats_key, start_timestamp=start, end_timestamp=end)
        # convert timestamps to strings
        values_w_string = [(s[0].strftime(AUTH_DATE_FORMAT), s[1]) for s in values]
        g.audit_object.log({"success": True})
        return send_result(values_w_string)
Exemple #17
0
    def api_endpoint(cls, request, g):
        """
        This provides a function to be plugged into the API endpoint
        /ttype/yubikey which is defined in api/ttype.py

        The endpoint /ttype/yubikey is used for the Yubico validate request
        according to
        https://developers.yubico.com/yubikey-val/Validation_Protocol_V2.0.html

        :param request: The Flask request
        :param g: The Flask global object g
        :return: Flask Response or text

        Required query parameters

        :query id: The id of the client to identify the correct shared secret
        :query otp: The OTP from the yubikey in the yubikey mode
        :query nonce: 16-40 bytes of random data

        Optional parameters h, timestamp, sl, timeout are not supported at the
        moment.
        """
        id = getParam(request.all_data, "id")
        otp = getParam(request.all_data, "otp")
        nonce = getParam(request.all_data, "nonce")
        signature = getParam(request.all_data, "h")
        status = "MISSING_PARAMETER"

        timestamp = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ%f")
        data = {'otp': otp,
                'nonce': nonce,
                'status': status,
                'timestamp': timestamp}

        api_key = cls._get_api_key(id)
        if api_key is None:
            data['status'] = "NO_SUCH_CLIENT"
            data['h'] = ""
        elif otp and id and nonce:
            if signature and not yubico_check_api_signature(request.all_data,
                                                            api_key, signature):
                # yubico server don't send nonce and otp back. Do we want that?
                data['status'] = "BAD_SIGNATURE"
            else:
                res, opt = cls.check_yubikey_pass(otp)
                if res:
                    data['status'] = "OK"
                else:
                    # Do we want REPLAYED_OTP too?
                    data['status'] = "BAD_OTP"

            data["h"] = yubico_api_signature(data, api_key)
        response = """nonce={nonce}
otp={otp}
status={status}
timestamp={timestamp}
h={h}
""".format(**data)

        return "plain", response
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        request = getParam(param, "request", optional)
        spkac = getParam(param, "spkac", optional)
        certificate = None
        if request:
            ca = getParam(param, "ca", required)
            self.add_tokeninfo("CA", ca)
            # During the initialization process, we need to create the
            # certificate
            cacon = get_caconnector_object(ca)
            x509object = cacon.sign_request(request, options={"spkac": spkac})
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
        else:
            certificate = getParam(param, "certificate", optional)

        if certificate:
            self.add_tokeninfo("certificate", certificate)
Exemple #19
0
def twostep_enrollment_parameters(request=None, action=None):
    """
    If the ``2stepinit`` parameter is set to true, this policy function
    reads additional configuration from policies and adds it
    to ``request.all_data``, that is:

     * ``{type}_2step_serversize`` is written to ``2step_serversize``
     * ``{type}_2step_clientsize`` is written to ``2step_clientsize`
     * ``{type}_2step_difficulty`` is written to ``2step_difficulty``

    If no policy matches, the value passed by the user is kept.

    This policy function is used to decorate the ``/token/init`` endpoint.
    """
    policy_object = g.policy_object
    user_object = get_user_from_param(request.all_data)
    serial = getParam(request.all_data, "serial", optional)
    token_type = getParam(request.all_data, "type", optional, "hotp")
    if serial:
        tokensobject_list = get_tokens(serial=serial)
        if len(tokensobject_list) == 1:
            token_type = tokensobject_list[0].token.tokentype
    token_type = token_type.lower()
    role = g.logged_in_user.get("role")
    # Differentiate between an admin enrolling a token for the
    # user and a user self-enrolling a token.
    if role == ROLE.ADMIN:
        adminrealm = g.logged_in_user.get("realm")
    else:
        adminrealm = None
    realm = user_object.realm
    # In any case, the policy's user attribute is matched against the
    # currently logged-in user (which may be the admin or the
    # self-enrolling user).
    user = g.logged_in_user.get("username")
    # Tokentypes have separate twostep actions
    if is_true(getParam(request.all_data, "2stepinit", optional)):
        parameters = ("2step_serversize", "2step_clientsize",
                      "2step_difficulty")
        for parameter in parameters:
            action = u"{}_{}".format(token_type, parameter)
            action_values = policy_object.get_action_values(
                action=action,
                scope=SCOPE.ENROLL,
                unique=True,
                user=user,
                realm=realm,
                client=g.client_ip,
                adminrealm=adminrealm)
            if action_values:
                request.all_data[parameter] = action_values[0]
Exemple #20
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        Do we really always need an otpkey?
        the otpKey is handled in the parent class
        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        # In case am Immutable MultiDict:
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        val = getParam(upd_param, "hashlib", optional)
        if val is not None:
            hashlibStr = val
        else:
            hashlibStr = 'sha1'

        # check if the key_size id provided
        # if not, we could derive it from the hashlib
        key_size = getParam(upd_param, 'key_size', optional)
        if key_size is None:
            upd_param['key_size'] = keylen.get(hashlibStr)
        otpKey = ''
        if self.hKeyRequired is True:
            genkey = int(getParam(upd_param, "genkey", optional) or 0)
            if 1 == genkey:
                # if hashlibStr not in keylen dict, this will
                # raise an Exception
                otpKey = generate_otpkey(upd_param['key_size'])
                del upd_param['genkey']
            else:
                # genkey not set: check otpkey is given
                # this will raise an exception if otpkey is not present
                otpKey = getParam(upd_param, "otpkey", required)
                # finally set the values for the update
            upd_param['otpkey'] = otpKey
        upd_param['hashlib'] = hashlibStr
        self.add_tokeninfo("hashlib", hashlibStr)
        val = getParam(upd_param, "otplen", optional)
        if val is not None:
            self.set_otplen(int(val))
        else:
            self.set_otplen(get_from_config("DefaultOtpLen", 6))

        TokenClass.update(self, upd_param, reset_failcount)
Exemple #21
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        Do we really always need an otpkey?
        the otpKey is handled in the parent class
        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        # In case am Immutable MultiDict:
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        val = getParam(upd_param, "hashlib", optional)
        if val is not None:
            hashlibStr = val
        else:
            hashlibStr = 'sha1'

        # check if the key_size id provided
        # if not, we could derive it from the hashlib
        key_size = getParam(upd_param, 'key_size', optional)
        if key_size is None:
            upd_param['key_size'] = keylen.get(hashlibStr)
        otpKey = ''
        if self.hKeyRequired is True:
            genkey = int(getParam(upd_param, "genkey", optional) or 0)
            if 1 == genkey:
                # if hashlibStr not in keylen dict, this will
                # raise an Exception
                otpKey = generate_otpkey(upd_param['key_size'])
                del upd_param['genkey']
            else:
                # genkey not set: check otpkey is given
                # this will raise an exception if otpkey is not present
                otpKey = getParam(upd_param, "otpkey", required)
                # finally set the values for the update
            upd_param['otpkey'] = otpKey
        upd_param['hashlib'] = hashlibStr
        self.add_tokeninfo("hashlib", hashlibStr)
        val = getParam(upd_param, "otplen", optional)
        if val is not None:
            self.set_otplen(int(val))
        else:
            self.set_otplen(get_from_config("DefaultOtpLen", 6))

        TokenClass.update(self, upd_param, reset_failcount)
Exemple #22
0
    def update(self, param, reset_failcount=True):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)
        reg_data = getParam(param, "regdata")
        verify_cert = is_true(getParam(param, "u2f.verify_cert", default=True))
        if not reg_data:
            self.token.rollout_state = ROLLOUTSTATE.CLIENTWAIT
            # Set the description in the first enrollment step
            if "description" in param:
                self.set_description(getParam(param, "description",
                                              default=""))
        elif reg_data and self.token.rollout_state == ROLLOUTSTATE.CLIENTWAIT:
            attestation_cert, user_pub_key, key_handle, \
                signature, automatic_description = parse_registration_data(reg_data,
                                                                 verify_cert=verify_cert)
            client_data = getParam(param, "clientdata", required)
            client_data_str = url_decode(client_data)
            app_id = self.get_tokeninfo("appId", "")
            # Verify the registration data
            # In case of any crypto error, check_data raises an exception
            check_registration_data(attestation_cert, app_id, client_data_str,
                                    user_pub_key, key_handle, signature)
            self.set_otpkey(key_handle)
            self.add_tokeninfo("pubKey", user_pub_key)
            # add attestation certificate info
            issuer = x509name_to_string(attestation_cert.get_issuer())
            serial = "{!s}".format(attestation_cert.get_serial_number())
            subject = x509name_to_string(attestation_cert.get_subject())

            self.add_tokeninfo("attestation_issuer", issuer)
            self.add_tokeninfo("attestation_serial", serial)
            self.add_tokeninfo("attestation_subject", subject)
            # Reset rollout state
            self.token.rollout_state = ""
            # If no description has already been set, set the automatic description or the
            # description given in the 2nd request
            if not self.token.description:
                self.set_description(
                    getParam(param,
                             "description",
                             default=automatic_description))
        else:
            raise ParameterError(
                "regdata provided but token not in clientwait rollout_state.")
Exemple #23
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        Do we really always need an otpkey?
        the otpKey is handled in the parent class
        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        # In case am Immutable MultiDict:
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        # Special handling of 2-step enrollment
        if is_true(getParam(param, "2stepinit", optional)):
            # Use the 2step_serversize setting for the size of the server secret
            # (if it is set)
            if "2step_serversize" in upd_param:
                upd_param["keysize"] = int(
                    getParam(upd_param, "2step_serversize", required))
            # Add twostep settings to the tokeninfo
            for key, default in [
                ("2step_difficulty", TWOSTEP_DEFAULT_DIFFICULTY),
                ("2step_clientsize", TWOSTEP_DEFAULT_CLIENTSIZE)
            ]:
                self.add_tokeninfo(key, getParam(param, key, optional,
                                                 default))

        val = getParam(upd_param, "hashlib", optional)
        if val is not None:
            hashlibStr = val
        else:
            hashlibStr = self.hashlib

        # check if the key_size is provided
        # if not, we could derive it from the hashlib
        key_size = getParam(upd_param, 'key_size', optional) \
                   or getParam(upd_param, 'keysize', optional)
        if key_size is None:
            upd_param['keysize'] = keylen.get(hashlibStr)

        otpKey = getParam(upd_param, "otpkey", optional)
        genkey = is_true(getParam(upd_param, "genkey", optional))
        if genkey and otpKey:
            # The Base TokenClass does not allow otpkey and genkey at the
            # same time
            del upd_param['otpkey']
        upd_param['hashlib'] = hashlibStr
        # We first need to call the parent class. Since exceptions would be
        # raised here.
        TokenClass.update(self, upd_param, reset_failcount)

        self.add_tokeninfo("hashlib", hashlibStr)

        # check the tokenkind
        if self.token.serial.startswith("UB"):
            self.add_tokeninfo("tokenkind", TOKENKIND.HARDWARE)
Exemple #24
0
def twostep_enrollment_parameters(request=None, action=None):
    """
    If the ``2stepinit`` parameter is set to true, this policy function
    reads additional configuration from policies and adds it
    to ``request.all_data``, that is:

     * ``{type}_2step_serversize`` is written to ``2step_serversize``
     * ``{type}_2step_clientsize`` is written to ``2step_clientsize`
     * ``{type}_2step_difficulty`` is written to ``2step_difficulty``

    If no policy matches, the value passed by the user is kept.

    This policy function is used to decorate the ``/token/init`` endpoint.
    """
    policy_object = g.policy_object
    user_object = get_user_from_param(request.all_data)
    serial = getParam(request.all_data, "serial", optional)
    token_type = getParam(request.all_data, "type", optional, "hotp")
    if serial:
        tokensobject_list = get_tokens(serial=serial)
        if len(tokensobject_list) == 1:
            token_type = tokensobject_list[0].token.tokentype
    token_type = token_type.lower()
    role = g.logged_in_user.get("role")
    # Differentiate between an admin enrolling a token for the
    # user and a user self-enrolling a token.
    if role == ROLE.ADMIN:
        adminrealm = g.logged_in_user.get("realm")
    else:
        adminrealm = None
    realm = user_object.realm
    # In any case, the policy's user attribute is matched against the
    # currently logged-in user (which may be the admin or the
    # self-enrolling user).
    user = g.logged_in_user.get("username")
    # Tokentypes have separate twostep actions
    if is_true(getParam(request.all_data, "2stepinit", optional)):
        parameters = ("2step_serversize", "2step_clientsize", "2step_difficulty")
        for parameter in parameters:
            action = u"{}_{}".format(token_type, parameter)
            action_values = policy_object.get_action_values(action=action,
                                                            scope=SCOPE.ENROLL,
                                                            unique=True,
                                                            user=user,
                                                            realm=realm,
                                                            client=g.client_ip,
                                                            adminrealm=adminrealm)
            if action_values:
                request.all_data[parameter] = action_values[0]
Exemple #25
0
def required_email(request=None, action=None):
    """
    This precondition checks if the "email" parameter matches the regular
    expression in the policy scope=register, action=requiredemail.
    See :ref:`policy_requiredemail`.

    Check ACTION.REQUIREDEMAIL

    This decorator should wrap POST /register

    :param request: The Request Object
    :param action: An optional Action
    :return: Modifies the request paramters or raises an Exception
    """
    email = getParam(request.all_data, "email")
    email_found = False
    email_pols = g.policy_object.\
        get_action_values(ACTION.REQUIREDEMAIL, scope=SCOPE.REGISTER,
                          client=g.client_ip)
    if email and email_pols:
        for email_pol in email_pols:
            # The policy is only "/regularexpr/".
            search = email_pol.strip("/")
            if re.findall(search, email):
                email_found = True
        if not email_found:
            raise RegistrationError("This email address is not allowed to "
                                    "register!")

    return True
Exemple #26
0
    def get_init_detail(self, params=None, user=None):
        """
        This returns the init details during enrollment.

        In the 1st step the QR Code is returned.
        """
        response_detail = TokenClass.get_init_detail(self, params, user)
        if "otpkey" in response_detail:
            del response_detail["otpkey"]
        params = params or {}
        user = user or User()
        tokenlabel = params.get("tokenlabel", "<s>")
        tokenissuer = params.get("tokenissuer", "privacyIDEA")
        sslverify = getParam(params, PUSH_ACTION.SSL_VERIFY, allowed_values=["0", "1"], default="1")
        # Add rollout state the response
        response_detail['rollout_state'] = self.token.rollout_state

        extra_data = {"enrollment_credential": self.get_tokeninfo("enrollment_credential")}
        imageurl = params.get("appimageurl")
        if imageurl:
            extra_data.update({"image": imageurl})
        if self.token.rollout_state == "clientwait":
            # Get the values from the configured PUSH config
            fb_identifier = params.get(PUSH_ACTION.FIREBASE_CONFIG)
            firebase_configs = get_smsgateway(identifier=fb_identifier, gwtype=GWTYPE)
            if len(firebase_configs) != 1:
                raise ParameterError("Unknown Firebase configuration!")
            fb_options = firebase_configs[0].option_dict
            for k in [FIREBASE_CONFIG.PROJECT_NUMBER, FIREBASE_CONFIG.PROJECT_ID,
                      FIREBASE_CONFIG.APP_ID, FIREBASE_CONFIG.API_KEY,
                      FIREBASE_CONFIG.APP_ID_IOS, FIREBASE_CONFIG.API_KEY_IOS]:
                extra_data[k] = fb_options.get(k)
            # this allows to upgrade our crypto
            extra_data["v"] = 1
            extra_data["serial"] = self.get_serial()
            extra_data["sslverify"] = sslverify
            # We display this during the first enrollment step!
            qr_url = create_push_token_url(url=fb_options.get(FIREBASE_CONFIG.REGISTRATION_URL),
                                           user=user.login,
                                           realm=user.realm,
                                           serial=self.get_serial(),
                                           tokenlabel=tokenlabel,
                                           issuer=tokenissuer,
                                           user_obj=user,
                                           extra_data=extra_data,
                                           ttl=fb_options.get(FIREBASE_CONFIG.TTL))
            response_detail["pushurl"] = {"description": _("URL for privacyIDEA Push Token"),
                                          "value": qr_url,
                                          "img": create_img(qr_url, width=250)
                                          }
            self.add_tokeninfo(FIREBASE_CONFIG.PROJECT_ID, fb_options.get(FIREBASE_CONFIG.PROJECT_ID))

            response_detail["enrollment_credential"] = self.get_tokeninfo("enrollment_credential")

        elif self.token.rollout_state == "enrolled":
            # in the second enrollment step we return the public key of the server to the smartphone.
            pubkey = strip_key(self.get_tokeninfo(PUBLIC_KEY_SERVER))
            response_detail["public_key"] = pubkey

        return response_detail
Exemple #27
0
    def update(self, param):

        radiusServer = getParam(param, "radius.server", required)
        self.add_tokeninfo("radius.server", radiusServer)
        # if another OTP length would be specified in /admin/init this would
        # be overwritten by the parent class, which is ok.
        self.set_otplen(6)
        TokenClass.update(self, param)
        val = getParam(param, "radius.local_checkpin", optional)
        self.add_tokeninfo("radius.local_checkpin", val)

        val = getParam(param, "radius.user", required)
        self.add_tokeninfo("radius.user", val)

        val = getParam(param, "radius.secret", required)
        self.token.set_otpkey(binascii.hexlify(val))
Exemple #28
0
def required_email(request=None, action=None):
    """
    This precondition checks if the "email" parameter matches the regular
    expression in the policy scope=register, action=requiredemail.
    See :ref:`policy_requiredemail`.

    Check ACTION.REQUIREDEMAIL

    This decorator should wrap POST /register

    :param request: The Request Object
    :param action: An optional Action
    :return: Modifies the request paramters or raises an Exception
    """
    email = getParam(request.all_data, "email")
    email_found = False
    email_pols = g.policy_object.\
        get_action_values(ACTION.REQUIREDEMAIL, scope=SCOPE.REGISTER,
                          client=request.remote_addr)
    if email and email_pols:
        for email_pol in email_pols:
            # The policy is only "/regularexpr/".
            search = email_pol.strip("/")
            if re.findall(search, email):
                email_found = True
        if not email_found:
            raise RegistrationError("This email address is not allowed to "
                                    "register!")

    return True
    def update(self, param):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        j_questions = getParam(param, "questions", required)
        try:
            # If we have a string, we load the json format
            questions = json.loads(j_questions)
        except TypeError:
            # Obviously we have a dict...
            questions = j_questions
        num_answers = get_from_config("question.num_answers",
                                      DEFAULT_NUM_ANSWERS)
        if len(questions) < int(num_answers):
            raise TokenAdminError(
                _("You need to provide at least %s "
                  "answers.") % num_answers)
        # Save all questions and answers and encrypt them
        for question, answer in questions.iteritems():
            self.add_tokeninfo(question, answer, value_type="password")
        TokenClass.update(self, param)
Exemple #30
0
def enroll_pin(request=None, action=None):
    """
    This policy function is used as decorator for init token.
    It checks, if the user or the admin is allowed to set a token PIN during
    enrollment. If not, it deleted the PIN from the request.
    """
    policy_object = g.policy_object
    role = g.logged_in_user.get("role")
    if role == ROLE.USER:
        scope = SCOPE.USER
        username = g.logged_in_user.get("username")
        realm = g.logged_in_user.get("realm")
        adminrealm = None
    else:
        scope = SCOPE.ADMIN
        username = g.logged_in_user.get("username")
        realm = getParam(request.all_data, "realm")
        adminrealm = g.logged_in_user.get("realm")
    pin_pols = policy_object.get_policies(action=ACTION.ENROLLPIN,
                                          scope=scope,
                                          user=username,
                                          realm=realm,
                                          adminrealm=adminrealm,
                                          client=g.client_ip,
                                          active=True)
    action_at_all = policy_object.get_policies(scope=scope,
                                               active=True,
                                               all_times=True)

    if action_at_all and not pin_pols:
        # Not allowed to set a PIN during enrollment!
        if "pin" in request.all_data:
            del request.all_data["pin"]
    return True
Exemple #31
0
    def update(self, param, reset_failcount=True):
        """
        update - process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        if is_true(getParam(param, 'genkey', optional)):
            raise ParameterError("Generating OTP keys is not supported")

        upd_param = param.copy()

        # If the OTP key is given, it is given as a 496-character hex string which
        # encodes a 248-byte blob. As we want to set a 248-byte OTPKey (= Blob),
        # we unhexlify the OTP key
        if 'otpkey' in param:
            if len(param['otpkey']) != 496:
                raise ParameterError('Expected OTP key as 496-character hex string, but length is {!s}'.format(
                    len(param['otpkey'])
                ))
            try:
                upd_param['otpkey'] = binascii.unhexlify(upd_param['otpkey'])
            except (binascii.Error, TypeError):
                raise ParameterError('Expected OTP key as 496-character hex string, but it is malformed')

        TokenClass.update(self, upd_param, reset_failcount)
Exemple #32
0
    def get_init_detail(self, params=None, user=None):
        """
        This returns the init details during enrollment.

        In the 1st step the QR Code is returned.
        """
        response_detail = TokenClass.get_init_detail(self, params, user)
        if "otpkey" in response_detail:
            del response_detail["otpkey"]
        params = params or {}
        user = user or User()
        tokenlabel = params.get("tokenlabel", "<s>")
        tokenissuer = params.get("tokenissuer", "privacyIDEA")
        sslverify = getParam(params, PUSH_ACTION.SSL_VERIFY, allowed_values=["0", "1"], default="1")
        # Add rollout state the response
        response_detail['rollout_state'] = self.token.rollout_state

        extra_data = {"enrollment_credential": self.get_tokeninfo("enrollment_credential")}
        imageurl = params.get("appimageurl")
        if imageurl:
            extra_data.update({"image": imageurl})
        if self.token.rollout_state == "clientwait":
            # Get the values from the configured PUSH config
            fb_identifier = params.get(PUSH_ACTION.FIREBASE_CONFIG)
            firebase_configs = get_smsgateway(identifier=fb_identifier, gwtype=GWTYPE)
            if len(firebase_configs) != 1:
                raise ParameterError("Unknown Firebase configuration!")
            fb_options = firebase_configs[0].option_dict
            for k in [FIREBASE_CONFIG.PROJECT_NUMBER, FIREBASE_CONFIG.PROJECT_ID,
                      FIREBASE_CONFIG.APP_ID, FIREBASE_CONFIG.API_KEY,
                      FIREBASE_CONFIG.APP_ID_IOS, FIREBASE_CONFIG.API_KEY_IOS]:
                extra_data[k] = fb_options.get(k)
            # this allows to upgrade our crypto
            extra_data["v"] = 1
            extra_data["serial"] = self.get_serial()
            extra_data["sslverify"] = sslverify
            # We display this during the first enrollment step!
            qr_url = create_push_token_url(url=fb_options.get(FIREBASE_CONFIG.REGISTRATION_URL),
                                           user=user.login,
                                           realm=user.realm,
                                           serial=self.get_serial(),
                                           tokenlabel=tokenlabel,
                                           issuer=tokenissuer,
                                           user_obj=user,
                                           extra_data=extra_data,
                                           ttl=fb_options.get(FIREBASE_CONFIG.TTL))
            response_detail["pushurl"] = {"description": _("URL for privacyIDEA Push Token"),
                                          "value": qr_url,
                                          "img": create_img(qr_url, width=250)
                                          }
            self.add_tokeninfo(FIREBASE_CONFIG.PROJECT_ID, fb_options.get(FIREBASE_CONFIG.PROJECT_ID))

            response_detail["enrollment_credential"] = self.get_tokeninfo("enrollment_credential")

        elif self.token.rollout_state == "enrolled":
            # in the second enrollment step we return the public key of the server to the smartphone.
            pubkey = strip_key(self.get_tokeninfo(PUBLIC_KEY_SERVER))
            response_detail["public_key"] = pubkey

        return response_detail
Exemple #33
0
def enroll_pin(request=None, action=None):
    """
    This policy function is used as decorator for init token.
    It checks, if the user or the admin is allowed to set a token PIN during
    enrollment. If not, it deleted the PIN from the request.
    """
    policy_object = g.policy_object
    role = g.logged_in_user.get("role")
    if role == ROLE.USER:
        scope = SCOPE.USER
        username = g.logged_in_user.get("username")
        realm = g.logged_in_user.get("realm")
        adminrealm = None
    else:
        scope = SCOPE.ADMIN
        username = g.logged_in_user.get("username")
        realm = getParam(request.all_data, "realm")
        adminrealm = g.logged_in_user.get("realm")
    pin_pols = policy_object.get_policies(action=ACTION.ENROLLPIN,
                                          scope=scope,
                                          user=username,
                                          realm=realm,
                                          adminrealm=adminrealm,
                                          client=g.client_ip,
                                          active=True)
    action_at_all = policy_object.get_policies(scope=scope,
                                               active=True,
                                               all_times=True)

    if action_at_all and not pin_pols:
        # Not allowed to set a PIN during enrollment!
        if "pin" in request.all_data:
            del request.all_data["pin"]
    return True
Exemple #34
0
    def update(self, param, reset_failcount=True):
        """
        update - process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        if is_true(getParam(param, 'genkey', optional)):
            raise ParameterError("Generating OTP keys is not supported")

        upd_param = param.copy()

        # If the OTP key is given, it is given as a 496-character hex string which
        # encodes a 248-byte blob. As we want to set a 248-byte OTPKey (= Blob),
        # we unhexlify the OTP key
        if 'otpkey' in param:
            if len(param['otpkey']) != 496:
                raise ParameterError(
                    'Expected OTP key as 496-character hex string, but length is {!s}'
                    .format(len(param['otpkey'])))
            try:
                upd_param['otpkey'] = binascii.unhexlify(upd_param['otpkey'])
            except (binascii.Error, TypeError):
                raise ParameterError(
                    'Expected OTP key as 496-character hex string, but it is malformed'
                )

        TokenClass.update(self, upd_param, reset_failcount)
Exemple #35
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        Do we really always need an otpkey?
        the otpKey is handled in the parent class
        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        # In case am Immutable MultiDict:
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        # Special handling of 2-step enrollment
        if is_true(getParam(param, "2stepinit", optional)):
            # Use the 2step_serversize setting for the size of the server secret
            # (if it is set)
            if "2step_serversize" in upd_param:
                upd_param["keysize"] = int(getParam(upd_param, "2step_serversize", required))
            # Add twostep settings to the tokeninfo
            for key, default in [
                ("2step_difficulty", TWOSTEP_DEFAULT_DIFFICULTY),
                ("2step_clientsize", TWOSTEP_DEFAULT_CLIENTSIZE)]:
                self.add_tokeninfo(key, getParam(param, key, optional, default))

        val = getParam(upd_param, "hashlib", optional)
        if val is not None:
            hashlibStr = val
        else:
            hashlibStr = self.hashlib

        # check if the key_size is provided
        # if not, we could derive it from the hashlib
        key_size = getParam(upd_param, 'key_size', optional) \
                   or getParam(upd_param, 'keysize', optional)
        if key_size is None:
            upd_param['keysize'] = keylen.get(hashlibStr)

        otpKey = getParam(upd_param, "otpkey", optional)
        genkey = is_true(getParam(upd_param, "genkey", optional))
        if genkey and otpKey:
            # The Base TokenClass does not allow otpkey and genkey at the
            # same time
            del upd_param['otpkey']
        upd_param['hashlib'] = hashlibStr
        # We first need to call the parent class. Since exceptions would be
        # raised here.
        TokenClass.update(self, upd_param, reset_failcount)

        self.add_tokeninfo("hashlib", hashlibStr)

        # check the tokenkind
        if self.token.serial.startswith("UB"):
            self.add_tokeninfo("tokenkind", TOKENKIND.HARDWARE)
Exemple #36
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        Do we really always need an otpkey?
        the otpKey is handled in the parent class
        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        # In case am Immutable MultiDict:
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        val = getParam(upd_param, "hashlib", optional)
        if val is not None:
            hashlibStr = val
        else:
            hashlibStr = 'sha1'

        # check if the key_size is provided
        # if not, we could derive it from the hashlib
        key_size = getParam(upd_param, 'key_size', optional) \
                   or getParam(upd_param, 'keysize', optional)
        if key_size is None:
            upd_param['keysize'] = keylen.get(hashlibStr)

        if "genkey" in upd_param and "otpkey" in upd_param:
            # The Base TokenClass does not allow otpkey and genkey at the
            # same time
            del upd_param['otpkey']
        upd_param['hashlib'] = hashlibStr
        # We first need to call the parent class. Since exceptions would be
        # raised here.
        TokenClass.update(self, upd_param, reset_failcount)

        # add_tokeninfo and set_otplen save the token object to the database.
        self.add_tokeninfo("hashlib", hashlibStr)
        val = getParam(upd_param, "otplen", optional)
        if val is not None:
            self.set_otplen(int(val))
        else:
            self.set_otplen(get_from_config("DefaultOtpLen", 6))
Exemple #37
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        Do we really always need an otpkey?
        the otpKey is handled in the parent class
        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        # In case am Immutable MultiDict:
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        val = getParam(upd_param, "hashlib", optional)
        if val is not None:
            hashlibStr = val
        else:
            hashlibStr = 'sha1'

        # check if the key_size is provided
        # if not, we could derive it from the hashlib
        key_size = getParam(upd_param, 'key_size', optional) \
                   or getParam(upd_param, 'keysize', optional)
        if key_size is None:
            upd_param['keysize'] = keylen.get(hashlibStr)

        if "genkey" in upd_param and "otpkey" in upd_param:
            # The Base TokenClass does not allow otpkey and genkey at the
            # same time
            del upd_param['otpkey']
        upd_param['hashlib'] = hashlibStr
        # We first need to call the parent class. Since exceptions would be
        # raised here.
        TokenClass.update(self, upd_param, reset_failcount)

        # add_tokeninfo and set_otplen save the token object to the database.
        self.add_tokeninfo("hashlib", hashlibStr)
        val = getParam(upd_param, "otplen", optional)
        if val is not None:
            self.set_otplen(int(val))
        else:
            self.set_otplen(get_from_config("DefaultOtpLen", 6))
Exemple #38
0
    def test_config(cls, params=None):
        mailserver = getParam(params, "email.mailserver", optional=False)
        subject = "Your TEST OTP"
        message = "This is a test."
        mail_from = getParam(params, "email.mailfrom", optional=False)
        recipient = getParam(params, "email.recipient", optional=False)
        password = getParam(params, "email.password")
        username = getParam(params, "email.username")
        port = getParam(params, "email.port", default=25)
        email_tls = getParam(params, "email.tls", default=False)
        r = send_email_data(mailserver,
                            subject,
                            message,
                            mail_from,
                            recipient,
                            username=username,
                            password=password,
                            port=port,
                            email_tls=email_tls)

        description = "Could not send email."
        if r:
            description = TEST_SUCCESSFUL

        return r, description
Exemple #39
0
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        realms = getParam(param, "4eyes", required)
        separator = getParam(param, "separator", optional, default=" ")
        if len(separator) > 1:
            raise ParameterError("The separator must only be one single "
                                 "character")
        realms = self.realms_dict_to_string(realms)
        self.convert_realms(realms)
        self.add_tokeninfo("separator", separator)
        self.add_tokeninfo("4eyes", realms)
Exemple #40
0
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        realms = getParam(param, "4eyes", required)
        separator = getParam(param, "separator", optional, default=" ")
        if len(separator) > 1:
            raise ParameterError("The separator must only be one single "
                                 "character")
        realms = self.realms_dict_to_string(realms)
        self.convert_realms(realms)
        self.add_tokeninfo("separator", separator)
        self.add_tokeninfo("4eyes", realms)
Exemple #41
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        We need to distinguish the first authentication step
        and the second authentication step.

        1. step:
            ``param`` contains:

            - ``type``
            - ``genkey``

        2. step:
            ``param`` contains:

            - ``serial``
            - ``fbtoken``
            - ``pubkey``

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        if "serial" in upd_param and "fbtoken" in upd_param and "pubkey" in upd_param:
            # We are in step 2:
            if self.token.rollout_state != "clientwait":
                raise ParameterError("Invalid state! The token you want to enroll is not in the state 'clientwait'.")
            enrollment_credential = getParam(upd_param, "enrollment_credential", optional=False)
            if enrollment_credential != self.get_tokeninfo("enrollment_credential"):
                raise ParameterError("Invalid enrollment credential. You are not authorized to finalize this token.")
            self.del_tokeninfo("enrollment_credential")
            self.token.rollout_state = "enrolled"
            self.token.active = True
            self.add_tokeninfo(PUBLIC_KEY_SMARTPHONE, upd_param.get("pubkey"))
            self.add_tokeninfo("firebase_token", upd_param.get("fbtoken"))
            # create a keypair for the server side.
            pub_key, priv_key = generate_keypair(4096)
            self.add_tokeninfo(PUBLIC_KEY_SERVER, pub_key)
            self.add_tokeninfo(PRIVATE_KEY_SERVER, priv_key, "password")

        elif "genkey" in upd_param:
            # We are in step 1:
            upd_param["2stepinit"] = 1
            self.add_tokeninfo("enrollment_credential", geturandom(20, hex=True))
            # We also store the firebase config, that was used during the enrollment.
            self.add_tokeninfo(PUSH_ACTION.FIREBASE_CONFIG, param.get(PUSH_ACTION.FIREBASE_CONFIG))
        else:
            raise ParameterError("Invalid Parameters. Either provide (genkey) or (serial, fbtoken, pubkey).")

        TokenClass.update(self, upd_param, reset_failcount)
Exemple #42
0
    def update(self, param):

        radiusServer = getParam(param, "radius.server", required)
        self.add_tokeninfo("radius.server", radiusServer)
        # if another OTP length would be specified in /admin/init this would
        # be overwritten by the parent class, which is ok.
        self.set_otplen(6)
        TokenClass.update(self, param)
        val = getParam(param, "radius.local_checkpin", optional) or 0
        self.add_tokeninfo("radius.local_checkpin", val)

        val = getParam(param, "radius.user", required)
        self.add_tokeninfo("radius.user", val)

        val = getParam(param, "radius.secret", required)
        self.token.set_otpkey(binascii.hexlify(val))

        val = getParam(param, "radius.system_settings", default=False)
        self.add_tokeninfo("radius.system_settings", val)
Exemple #43
0
    def update(self, param, reset_failcount=True):
        """
        process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict
        :return: nothing
        """
        if getParam(param, "dynamic_phone", optional):
            self.add_tokeninfo("dynamic_phone", True)
        else:
            # specific - phone
            phone = getParam(param, "phone", required)
            self.add_tokeninfo("phone", phone)

        # in case of the sms token, only the server must know the otpkey
        # thus if none is provided, we let create one (in the TokenClass)
        if "genkey" not in param and "otpkey" not in param:
            param['genkey'] = 1

        HotpTokenClass.update(self, param, reset_failcount)
Exemple #44
0
    def update(self, param, reset_failcount=True):
        """
        process initialization parameters

        :param param: dict of initialization parameters
        :type param: dict
        :return: nothing
        """
        if getParam(param, "dynamic_phone", optional):
            self.add_tokeninfo("dynamic_phone", True)
        else:
            # specific - phone
            phone = getParam(param, "phone", required)
            self.add_tokeninfo("phone", phone)

        # in case of the sms token, only the server must know the otpkey
        # thus if none is provided, we let create one (in the TokenClass)
        if "genkey" not in param and "otpkey" not in param:
            param['genkey'] = 1

        HotpTokenClass.update(self, param, reset_failcount)
    def update(self, param):
        # New value
        radius_identifier = getParam(param, "radius.identifier")
        self.add_tokeninfo("radius.identifier", radius_identifier)

        # old values
        if not radius_identifier:
            radiusServer = getParam(param, "radius.server", optional=required)
            self.add_tokeninfo("radius.server", radiusServer)
            radius_secret = getParam(param, "radius.secret", optional=required)
            self.token.set_otpkey(hexlify_and_unicode(radius_secret))
            system_settings = getParam(param,
                                       "radius.system_settings",
                                       default=False)
            self.add_tokeninfo("radius.system_settings", system_settings)

            if not (radiusServer or radius_secret) and not system_settings:
                raise ParameterError("Missing parameter: radius.identifier",
                                     id=905)

        # if another OTP length would be specified in /admin/init this would
        # be overwritten by the parent class, which is ok.
        self.set_otplen(6)
        TokenClass.update(self, param)
        val = getParam(param, "radius.local_checkpin", optional) or 0
        self.add_tokeninfo("radius.local_checkpin", val)
        val = getParam(param, "radius.user", required)
        self.add_tokeninfo("radius.user", val)
        self.add_tokeninfo("tokenkind", TOKENKIND.VIRTUAL)
Exemple #46
0
    def update(self, param):
        # New value
        radius_identifier = getParam(param, "radius.identifier")
        self.add_tokeninfo("radius.identifier", radius_identifier)

        # old values
        if not radius_identifier:
            radiusServer = getParam(param, "radius.server", optional=required)
            self.add_tokeninfo("radius.server", radiusServer)
            radius_secret = getParam(param, "radius.secret", optional=required)
            self.token.set_otpkey(binascii.hexlify(radius_secret))
            system_settings = getParam(param, "radius.system_settings",
                                       default=False)
            self.add_tokeninfo("radius.system_settings", system_settings)

        if not radius_identifier and not (radiusServer or radius_secret) and \
                not system_settings:
            raise ParameterError("Missing parameter: radius.identifier", id=905)

        # if another OTP length would be specified in /admin/init this would
        # be overwritten by the parent class, which is ok.
        self.set_otplen(6)
        TokenClass.update(self, param)
        val = getParam(param, "radius.local_checkpin", optional) or 0
        self.add_tokeninfo("radius.local_checkpin", val)

        val = getParam(param, "radius.user", required)
        self.add_tokeninfo("radius.user", val)
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        request = getParam(param, "request", optional)
        spkac = getParam(param, "spkac", optional)
        certificate = getParam(param, "certificate", optional)
        generate = getParam(param, "genkey", optional)
        if request or generate:
            # If we do not upload a user certificate, then we need a CA do
            # sign the uploaded request or generated certificate.
            ca = getParam(param, "ca", required)
            self.add_tokeninfo("CA", ca)
            cacon = get_caconnector_object(ca)
        if request:
            # During the initialization process, we need to create the
            # certificate
            x509object = cacon.sign_request(request,
                                            options={"spkac": spkac})
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
        elif generate:
            # Create the certificate on behalf of another user.
            # Now we need to create the key pair,
            # the request
            # and the certificate
            # We need the user for whom the certificate should be created
            user = get_user_from_param(param, optionalOrRequired=required)

            keysize = getParam(param, "keysize", optional, 2048)
            key = crypto.PKey()
            key.generate_key(crypto.TYPE_RSA, keysize)
            req = crypto.X509Req()
            req.get_subject().CN = user.login
            # Add email to subject
            if user.info.get("email"):
                req.get_subject().emailAddress = user.info.get("email")
            req.get_subject().organizationalUnitName = user.realm
            # TODO: Add Country, Organization, Email
            # req.get_subject().countryName = 'xxx'
            # req.get_subject().stateOrProvinceName = 'xxx'
            # req.get_subject().localityName = 'xxx'
            # req.get_subject().organizationName = 'xxx'
            req.set_pubkey(key)
            req.sign(key, "sha256")
            x509object = cacon.sign_request(crypto.dump_certificate_request(
                crypto.FILETYPE_PEM, req))
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
            # Save the private key to the encrypted key field of the token
            s = crypto.dump_privatekey(crypto.FILETYPE_PEM, key)
            self.add_tokeninfo("privatekey", s, value_type="password")

        if certificate:
            self.add_tokeninfo("certificate", certificate)
Exemple #48
0
    def update(self, param, reset_failcount=True):
        """
        process the initialization parameters

        We need to distinguish the first authentication step
        and the second authentication step.

        1. step:
            parameter type contained.
            parameter genkey contained.

        2. step:
            parameter serial contained
            parameter fbtoken contained
            parameter pubkey contained

        :param param: dict of initialization parameters
        :type param: dict

        :return: nothing
        """
        upd_param = {}
        for k, v in param.items():
            upd_param[k] = v

        if "serial" in upd_param and "fbtoken" in upd_param and "pubkey" in upd_param:
            # We are in step 2:
            if self.token.rollout_state != "clientwait":
                raise ParameterError("Invalid state! The token you want to enroll is not in the state 'clientwait'.")
            enrollment_credential = getParam(upd_param, "enrollment_credential", optional=False)
            if enrollment_credential != self.get_tokeninfo("enrollment_credential"):
                raise ParameterError("Invalid enrollment credential. You are not authorized to finalize this token.")
            self.del_tokeninfo("enrollment_credential")
            self.token.rollout_state = "enrolled"
            self.token.active = True
            self.add_tokeninfo(PUBLIC_KEY_SMARTPHONE, upd_param.get("pubkey"))
            self.add_tokeninfo("firebase_token", upd_param.get("fbtoken"))
            # create a keypair for the server side.
            pub_key, priv_key = generate_keypair(4096)
            self.add_tokeninfo(PUBLIC_KEY_SERVER, pub_key)
            self.add_tokeninfo(PRIVATE_KEY_SERVER, priv_key, "password")

        elif "genkey" in upd_param:
            # We are in step 1:
            upd_param["2stepinit"] = 1
            self.add_tokeninfo("enrollment_credential", geturandom(20, hex=True))
            # We also store the firebase config, that was used during the enrollment.
            self.add_tokeninfo(PUSH_ACTION.FIREBASE_CONFIG, param.get(PUSH_ACTION.FIREBASE_CONFIG))
        else:
            raise ParameterError("Invalid Parameters. Either provide (genkey) or (serial, fbtoken, pubkey).")

        TokenClass.update(self, upd_param, reset_failcount)
Exemple #49
0
def delete_statistics(stats_key):
    """
    Delete the statistics data of a certain stats_key.

    You can specify the start date and the end date when to delete the
    monitoring data.
    You should specify the dates including the timezone. Otherwise your client
    could send its local time and the server would interpret it as its own local
    time which would result in deleting unexpected entries.

    You can specify the dates like 2010-12-31 22:00+0200
    """
    param = request.all_data
    start = getParam(param, "start")
    if start:
        start = parse_legacy_time(start, return_date=True)
    end = getParam(param, "end")
    if end:
        end = parse_legacy_time(end, return_date=True)
    r = delete_stats(stats_key, start, end)
    g.audit_object.log({"success": True})
    return send_result(r)
    def update(self, param):
        """
        This method is called during the initialization process.
        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)

        request = getParam(param, "request", optional)
        spkac = getParam(param, "spkac", optional)
        certificate = getParam(param, "certificate", optional)
        generate = getParam(param, "genkey", optional)
        if request or generate:
            # If we do not upload a user certificate, then we need a CA do
            # sign the uploaded request or generated certificate.
            ca = getParam(param, "ca", required)
            self.add_tokeninfo("CA", ca)
            cacon = get_caconnector_object(ca)
        if request:
            # During the initialization process, we need to create the
            # certificate
            x509object = cacon.sign_request(request, options={"spkac": spkac})
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
        elif generate:
            # Create the certificate on behalf of another user.
            # Now we need to create the key pair,
            # the request
            # and the certificate
            # We need the user for whom the certificate should be created
            user = get_user_from_param(param, optionalOrRequired=required)

            keysize = getParam(param, "keysize", optional, 2048)
            key = crypto.PKey()
            key.generate_key(crypto.TYPE_RSA, keysize)
            req = crypto.X509Req()
            req.get_subject().CN = user.login
            # Add email to subject
            if user.info.get("email"):
                req.get_subject().emailAddress = user.info.get("email")
            req.get_subject().organizationalUnitName = user.realm
            # TODO: Add Country, Organization, Email
            # req.get_subject().countryName = 'xxx'
            # req.get_subject().stateOrProvinceName = 'xxx'
            # req.get_subject().localityName = 'xxx'
            # req.get_subject().organizationName = 'xxx'
            req.set_pubkey(key)
            req.sign(key, "sha256")
            x509object = cacon.sign_request(
                crypto.dump_certificate_request(crypto.FILETYPE_PEM, req))
            certificate = crypto.dump_certificate(crypto.FILETYPE_PEM,
                                                  x509object)
            # Save the private key to the encrypted key field of the token
            s = crypto.dump_privatekey(crypto.FILETYPE_PEM, key)
            self.add_tokeninfo("privatekey", s, value_type="password")

        if certificate:
            self.add_tokeninfo("certificate", certificate)
Exemple #51
0
def delete_statistics(stats_key):
    """
    Delete the statistics data of a certain stats_key.

    You can specify the start date and the end date when to delete the
    monitoring data.
    You should specify the dates including the timezone. Otherwise your client
    could send its local time and the server would interpret it as its own local
    time which would result in deleting unexpected entries.

    You can specify the dates like 2010-12-31 22:00+0200
    """
    param = request.all_data
    start = getParam(param, "start")
    if start:
        start = parse_legacy_time(start, return_date=True)
    end = getParam(param, "end")
    if end:
        end = parse_legacy_time(end, return_date=True)
    r = delete_stats(stats_key, start, end)
    g.audit_object.log({"success": True})
    return send_result(r)
Exemple #52
0
    def update(self, param):
        tokenid = getParam(param, "yubico.tokenid", required)
        if len(tokenid) < YUBICO_LEN_ID:
            log.error("The tokenid needs to be %i characters long!" % YUBICO_LEN_ID)
            raise Exception("The Yubikey token ID needs to be %i characters long!" % YUBICO_LEN_ID)

        if len(tokenid) > YUBICO_LEN_ID:
            tokenid = tokenid[:YUBICO_LEN_ID]
        self.tokenid = tokenid
        # overwrite the maybe wrong lenght given at the command line
        param['otplen'] = 44
        TokenClass.update(self, param)
        self.add_tokeninfo("yubico.tokenid", self.tokenid)
Exemple #53
0
    def update(self, param, reset_failcount=True):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)
        description = "U2F initialization"
        reg_data = getParam(param, "regdata")
        verify_cert = is_true(getParam(param, "u2f.verify_cert", default=True))
        if reg_data:
            self.init_step = 2
            attestation_cert, user_pub_key, key_handle, \
                signature, description = parse_registration_data(reg_data,
                                                                 verify_cert=verify_cert)
            client_data = getParam(param, "clientdata", required)
            client_data_str = url_decode(client_data)
            app_id = self.get_tokeninfo("appId", "")
            # Verify the registration data
            # In case of any crypto error, check_data raises an exception
            check_registration_data(attestation_cert, app_id, client_data_str,
                                    user_pub_key, key_handle, signature)
            self.set_otpkey(key_handle)
            self.add_tokeninfo("pubKey", user_pub_key)
            # add attestation certificat info
            issuer = x509name_to_string(attestation_cert.get_issuer())
            serial = "{!s}".format(attestation_cert.get_serial_number())
            subject = x509name_to_string(attestation_cert.get_subject())

            self.add_tokeninfo("attestation_issuer", issuer)
            self.add_tokeninfo("attestation_serial", serial)
            self.add_tokeninfo("attestation_subject", subject)

        # If a description is given we use the given description
        description = getParam(param, "description", default=description)
        self.set_description(description)
Exemple #54
0
    def update(self, param, reset_failcount=True):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        TokenClass.update(self, param)
        description = "U2F initialization"
        reg_data = getParam(param, "regdata")
        verify_cert = is_true(getParam(param, "u2f.verify_cert", default=True))
        if reg_data:
            self.init_step = 2
            attestation_cert, user_pub_key, key_handle, \
                signature, description = parse_registration_data(reg_data,
                                                                 verify_cert=verify_cert)
            client_data = getParam(param, "clientdata", required)
            client_data_str = url_decode(client_data)
            app_id = self.get_tokeninfo("appId", "")
            # Verify the registration data
            # In case of any crypto error, check_data raises an exception
            check_registration_data(attestation_cert, app_id, client_data_str,
                                    user_pub_key, key_handle, signature)
            self.set_otpkey(key_handle)
            self.add_tokeninfo("pubKey", user_pub_key)
            # add attestation certificat info
            issuer = x509name_to_string(attestation_cert.get_issuer())
            serial = "{!s}".format(attestation_cert.get_serial_number())
            subject = x509name_to_string(attestation_cert.get_subject())

            self.add_tokeninfo("attestation_issuer", issuer)
            self.add_tokeninfo("attestation_serial", serial)
            self.add_tokeninfo("attestation_subject", subject)

        # If a description is given we use the given description
        description = getParam(param, "description", default=description)
        self.set_description(description)
Exemple #55
0
def set_periodic_task_api():
    """
    Create or replace an existing periodic task definition.

    :param id: ID of an existing periodic task definition that should be updated
    :param name: Name of the periodic task
    :param active: true if the periodic task should be active
    :param retry_if_failed: privacyIDEA will retry to execute the task if failed
    :param interval: Interval at which the periodic task should run (in cron syntax)
    :param nodes: Comma-separated list of nodes on which the periodic task should run
    :param taskmodule: Task module name of the task
    :param ordering: Ordering of the task, must be a number >= 0.
    :param options: A dictionary (possibly JSON) of periodic task options, mapping unicodes to unicodes
    :return: ID of the periodic task
    """
    param = request.all_data
    ptask_id = getParam(param, "id", optional=True)
    if ptask_id is not None:
        ptask_id = int(ptask_id)
    name = getParam(param, "name", optional=False)
    active = is_true(getParam(param, "active", default=True))
    retry_if_failed = is_true(getParam(param, "retry_if_failed", default=True))
    interval = getParam(param, "interval", optional=False)
    node_string = getParam(param, "nodes", optional=False)
    if node_string.strip():
        node_list = [node.strip() for node in node_string.split(",")]
    else:
        raise ParameterError(u"nodes: expected at least one node")
    taskmodule = getParam(param, "taskmodule", optional=False)
    if taskmodule not in get_available_taskmodules():
        raise ParameterError("Unknown task module: {!r}".format(taskmodule))
    ordering = int(getParam(param, "ordering", optional=False))
    options = getParam(param, "options", optional=True)
    if options is None:
        options = {}
    elif not isinstance(options, dict):
        options = json.loads(options)
        if not isinstance(options, dict):
            raise ParameterError(u"options: expected dictionary, got {!r}".format(options))
    result = set_periodic_task(name, interval, node_list, taskmodule, ordering, options, active, ptask_id,
                               retry_if_failed)
    g.audit_object.log({"success": True, "info": result})
    return send_result(result)
Exemple #56
0
def set_periodic_task_api():
    """
    Create or replace an existing periodic task definition.

    :param id: ID of an existing periodic task definition that should be updated
    :param name: Name of the periodic task
    :param active: true if the periodic task should be active
    :param interval: Interval at which the periodic task should run (in cron syntax)
    :param nodes: Comma-separated list of nodes on which the periodic task should run
    :param taskmodule: Task module name of the task
    :param ordering: Ordering of the task, must be a number >= 0.
    :param options: A dictionary (possibly JSON) of periodic task options, mapping unicodes to unicodes
    :return: ID of the periodic task
    """
    param = request.all_data
    ptask_id = getParam(param, "id", optional=True)
    if ptask_id is not None:
        ptask_id = int(ptask_id)
    name = getParam(param, "name", optional=False)
    active = is_true(getParam(param, "active", default=True))
    interval = getParam(param, "interval", optional=False)
    node_string = getParam(param, "nodes", optional=False)
    if node_string.strip():
        node_list = [node.strip() for node in node_string.split(",")]
    else:
        raise ParameterError(u"nodes: expected at least one node")
    taskmodule = getParam(param, "taskmodule", optional=False)
    if taskmodule not in get_available_taskmodules():
        raise ParameterError("Unknown task module: {!r}".format(taskmodule))
    ordering = int(getParam(param, "ordering", optional=False))
    options = getParam(param, "options", optional=True)
    if options is None:
        options = {}
    elif not isinstance(options, dict):
        options = json.loads(options)
        if not isinstance(options, dict):
            raise ParameterError(u"options: expected dictionary, got {!r}".format(options))
    result = set_periodic_task(name, interval, node_list, taskmodule, ordering, options, active, ptask_id)
    g.audit_object.log({"success": True, "info": result})
    return send_result(result)
Exemple #57
0
    def update(self, param):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        user_object = get_user_from_param(param, optional)
        if user_object:
            self.set_user(user_object)

        ocrasuite = getParam(param, "ocrasuite", default=OCRA_DEFAULT_SUITE)
        OCRASuite(ocrasuite)
        self.add_tokeninfo("ocrasuite", ocrasuite)
        TokenClass.update(self, param)

        if user_object:
            # We have to set the realms here, since the token DB object does not
            # have an ID before TokenClass.update.
            self.set_realms([user_object.realm])
Exemple #58
0
    def test_config(cls, params=None):
        mailserver = getParam(params, "email.mailserver", optional=False)
        subject = "Your TEST OTP"
        message = "This is a test."
        mail_from = getParam(params, "email.mailfrom", optional=False)
        recipient = getParam(params, "email.recipient", optional=False)
        password = getParam(params, "email.password")
        username = getParam(params, "email.username")
        port = getParam(params, "email.port", default=25)
        email_tls = getParam(params, "email.tls", default=False)
        r = send_email_data(mailserver, subject, message, mail_from,
                            recipient, username=username,
                            password=password, port=port, email_tls=email_tls)

        description = "Could not send email."
        if r:
            description = TEST_SUCCESSFUL

        return r, description
    def update(self, param):
        """
        This method is called during the initialization process.

        :param param: parameters from the token init
        :type param: dict
        :return: None
        """
        j_questions = getParam(param, "questions", required)
        try:
            # If we have a string, we load the json format
            questions = json.loads(j_questions)
        except TypeError:
            # Obviously we have a dict...
            questions = j_questions
        num_answers = get_from_config("question.num_answers",
                                      DEFAULT_NUM_ANSWERS)
        if len(questions) < int(num_answers):
            raise TokenAdminError(_("You need to provide at least %s "
                                    "answers.") % num_answers)
        # Save all questions and answers and encrypt them
        for question, answer in questions.iteritems():
            self.add_tokeninfo(question, answer, value_type="password")
        TokenClass.update(self, param)
    def test_01_getParam(self):
        s = getParam({"serial": ""}, "serial", optional=False, allow_empty=True)
        self.assertEqual(s, "")

        self.assertRaises(ParameterError, getParam, {"serial": ""}, "serial", optional=False, allow_empty=False)