def test_07_generate_password(self):
        # test given default characters
        pass_numeric = generate_password(size=12, characters=string.digits)
        self.assertTrue(pass_numeric.isdigit())
        self.assertEqual(len(pass_numeric), 12)

        # test requirements, we loop to get some statistics
        default_chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
        for i in range(10):
            password_req = generate_password(size=3, characters=default_chars, requirements=["AB", "12"])
            # a character from each requirement must be found
            self.assertTrue(
                any(char in "AB" for char in password_req) and any(char in "12" for char in password_req))
            self.assertEqual(len(password_req),3)

        # use letters for base and numbers for requirements
        # this cannot be achieved with a pin policy
        password = generate_password(size=10, characters=string.ascii_letters,
                                     requirements=[string.digits, string.digits, string.digits])
        self.assertEqual(10, len(password))
        self.assertEqual(3, sum(c.isdigit() for c in password))
        self.assertEqual(7, sum(c.isalpha() for c in password))

        # requirements define the minimum length of a password
        password = generate_password(size=0, characters='ABC',
                                     requirements=['1', '2', '3'])
        self.assertEqual(3, len(password))

        # empty characters variable raises an IndexError
        self.assertRaises(IndexError, generate_password, characters='')

        # negative size without requirements results in an empty password
        password = generate_password(size=-1)
        self.assertEqual(password, '')
 def update(self, param):
     """
     This method is called during the initialization process.
     :param param: parameters from the token init
     :type param: dict
     :return: None
     """
     if "genkey" in param:
         # We do not need the genkey! We generate anyway.
         # Otherwise genkey and otpkey will raise an exception in
         # PasswordTokenClass
         del param["genkey"]
     param["otpkey"] = generate_password(size=self.otp_len)
     PasswordTokenClass.update(self, param)
Exemple #3
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
     """
     if "genkey" in param:
         # We do not need the genkey! We generate anyway.
         # Otherwise genkey and otpkey will raise an exception in
         # PasswordTokenClass
         del param["genkey"]
     param["otpkey"] = generate_password(size=self.otp_len)
     PasswordTokenClass.update(self, param)
Exemple #4
0
def create_recoverycode(user,
                        email=None,
                        expiration_seconds=3600,
                        recoverycode=None,
                        base_url=""):
    """
    Create and send a password recovery code

    :param user: User for whom the password reset code should be sent
    :type user: User Object
    :param email: The optional email of the user
    :param recoverycode: Only used for testing purpose
    :return: bool
    """
    base_url = base_url.strip("recover")
    base_url += "#"
    recoverycode = recoverycode or generate_password(size=24)
    hash_code = hash_with_pepper(recoverycode)
    # send this recoverycode
    #
    pwreset = PasswordReset(hash_code,
                            username=user.login,
                            realm=user.realm,
                            expiration_seconds=expiration_seconds)
    pwreset.save()

    res = False
    if not user:
        raise UserError("User required for recovery token.")
    user_email = user.info.get("email")
    if email and email.lower() != user_email.lower():
        raise UserError("The email does not match the users email.")

    identifier = get_from_config("recovery.identifier")
    if identifier:
        # send email
        r = send_email_identifier(
            identifier, user_email, "Your password reset",
            BODY.format(base_url, user.login, user.realm, recoverycode))
        if not r:
            raise privacyIDEAError("Failed to send email. {0!s}".format(r))
    else:
        raise ConfigAdminError("Missing configuration " "recovery.identifier.")
    res = True
    return res
def create_recoverycode(user, email=None, expiration_seconds=3600,
                        recoverycode=None, base_url=""):
    """
    Create and send a password recovery code

    :param user: User for whom the password reset code should be sent
    :type user: User Object
    :param email: The optional email of the user
    :param recoverycode: Only used for testing purpose
    :return: bool
    """
    base_url = base_url.strip("recover")
    base_url += "#"
    recoverycode = recoverycode or generate_password(size=24)
    hash_code = hash_with_pepper(recoverycode)
    # send this recoverycode
    #
    pwreset = PasswordReset(hash_code, username=user.login,
                            realm=user.realm,
                            expiration_seconds=expiration_seconds)
    pwreset.save()

    res = False
    if not user:
        raise UserError("User required for recovery token.")
    user_email = user.info.get("email")
    if email and email.lower() != user_email.lower():
        raise UserError("The email does not match the users email.")

    identifier = get_from_config("recovery.identifier")
    if identifier:
        # send email
        r = send_email_identifier(identifier, user_email,
                                  "Your password reset",
                                  BODY.format(base_url,
                                              user.login, user.realm,
                                              recoverycode))
        if not r:
            raise privacyIDEAError("Failed to send email. {0!s}".format(r))
    else:
        raise ConfigAdminError("Missing configuration "
                               "recovery.identifier.")
    res = True
    return res
Exemple #6
0
def create_token(serial, username):
    app = create_app(config_name="production",
                     config_file="/etc/privacyidea/pi.cfg",
                     silent=True)

    with app.app_context():
        # Set global values
        params = {"type": TOKENTYPE}
        if username:
            user = User(username, REALM)
        else:
            user = User()
        if serial:
            params["serial"] = serial
        password = generate_password(size=PW_LEN, characters=BASE58)
        params["otplen"] = PW_LEN
        params["otpkey"] = password
        tok = init_token(params, user)
        return tok.token.serial, password
Exemple #7
0
    def do(self, action, options=None):
        """
        This method executes the defined action in the given event.

        :param action:
        :param options: Contains the flask parameters g, request, response
            and the handler_def configuration
        :type options: dict
        :return:
        """
        ret = True
        g = options.get("g")
        request = options.get("request")
        response = options.get("response")
        content = self._get_response_content(response)
        handler_def = options.get("handler_def")
        handler_options = handler_def.get("options", {})

        serial = request.all_data.get("serial") or \
                 content.get("detail", {}).get("serial") or \
                 g.audit_object.audit_data.get("serial")

        if action.lower() in [ACTION_TYPE.SET_TOKENREALM,
                              ACTION_TYPE.SET_DESCRIPTION,
                              ACTION_TYPE.DELETE, ACTION_TYPE.DISABLE,
                              ACTION_TYPE.ENABLE, ACTION_TYPE.UNASSIGN,
                              ACTION_TYPE.SET_VALIDITY,
                              ACTION_TYPE.SET_COUNTWINDOW,
                              ACTION_TYPE.SET_TOKENINFO,
                              ACTION_TYPE.SET_FAILCOUNTER,
                              ACTION_TYPE.CHANGE_FAILCOUNTER,
                              ACTION_TYPE.SET_RANDOM_PIN,
                              ACTION_TYPE.DELETE_TOKENINFO]:
            if serial:
                log.info("{0!s} for token {1!s}".format(action, serial))
                if action.lower() == ACTION_TYPE.SET_TOKENREALM:
                    realm = handler_options.get("realm")
                    only_realm = is_true(handler_options.get("only_realm"))
                    # Set the realm..
                    log.info("Setting realm of token {0!s} to {1!s}".format(
                        serial, realm))
                    # Add the token realm
                    set_realms(serial, [realm], add=not only_realm)
                elif action.lower() == ACTION_TYPE.SET_RANDOM_PIN:
                    # If for any reason we have no value, we default to 6
                    length = int(handler_options.get("length") or 6)
                    pin = generate_password(size=length)
                    if set_pin(serial, pin):
                        content.setdefault("detail", {})["pin"] = pin
                        options.get("response").data = json.dumps(content)
                elif action.lower() == ACTION_TYPE.DELETE:
                    remove_token(serial=serial)
                elif action.lower() == ACTION_TYPE.DISABLE:
                    enable_token(serial, enable=False)
                elif action.lower() == ACTION_TYPE.ENABLE:
                    enable_token(serial, enable=True)
                elif action.lower() == ACTION_TYPE.UNASSIGN:
                    unassign_token(serial)
                elif action.lower() == ACTION_TYPE.SET_DESCRIPTION:
                    description = handler_options.get("description") or ""
                    description, td = parse_time_offset_from_now(description)
                    s_now = (datetime.datetime.now(tzlocal()) + td).strftime(
                        AUTH_DATE_FORMAT)
                    set_description(serial,
                                    description.format(
                                        current_time=s_now,
                                        now=s_now,
                                        client_ip=g.client_ip,
                                        ua_browser=request.user_agent.browser,
                                        ua_string=request.user_agent.string))
                elif action.lower() == ACTION_TYPE.SET_COUNTWINDOW:
                    set_count_window(serial,
                                     int(handler_options.get("count window",
                                                             50)))
                elif action.lower() == ACTION_TYPE.SET_TOKENINFO:
                    tokeninfo = handler_options.get("value") or ""
                    tokeninfo, td = parse_time_offset_from_now(tokeninfo)
                    s_now = (datetime.datetime.now(tzlocal()) + td).strftime(
                        AUTH_DATE_FORMAT)
                    try:
                        username = request.User.loginname
                        realm = request.User.realm
                    except Exception:
                        username = "******"
                        realm = "N/A"
                    add_tokeninfo(serial, handler_options.get("key"),
                                  tokeninfo.format(
                                      current_time=s_now,
                                      now=s_now,
                                      client_ip=g.client_ip,
                                      username=username,
                                      realm=realm,
                                      ua_browser=request.user_agent.browser,
                                      ua_string=request.user_agent.string))
                elif action.lower() == ACTION_TYPE.DELETE_TOKENINFO:
                    delete_tokeninfo(serial, handler_options.get("key"))
                elif action.lower() == ACTION_TYPE.SET_VALIDITY:
                    start_date = handler_options.get(VALIDITY.START)
                    end_date = handler_options.get(VALIDITY.END)
                    if start_date:
                         d = parse_date(start_date)
                         set_validity_period_start(serial, None,
                                                   d.strftime(DATE_FORMAT))
                    if end_date:
                        d = parse_date(end_date)
                        set_validity_period_end(serial, None,
                                                d.strftime(DATE_FORMAT))
                elif action.lower() == ACTION_TYPE.SET_FAILCOUNTER:
                    try:
                        set_failcounter(serial,
                                        int(handler_options.get("fail counter")))
                    except Exception as exx:
                        log.warning("Misconfiguration: Failed to set fail "
                                    "counter!")
                elif action.lower() == ACTION_TYPE.CHANGE_FAILCOUNTER:
                    try:
                        token_obj = get_one_token(serial=serial)
                        token_obj.set_failcount(
                            token_obj.token.failcount + int(handler_options.get("change fail counter")))
                    except Exception as exx:
                        log.warning("Misconfiguration: Failed to increase or decrease fail "
                                    "counter!")
            else:
                log.info("Action {0!s} requires serial number. But no serial "
                         "number could be found in request.")

        if action.lower() == ACTION_TYPE.INIT:
            log.info("Initializing new token")
            init_param = {"type": handler_options.get("tokentype"),
                          "genkey": 1,
                          "realm": handler_options.get("realm", "")}
            user = None
            if is_true(handler_options.get("user")):
                user = self._get_tokenowner(request)
                tokentype = handler_options.get("tokentype")
                # Some tokentypes need additional parameters
                if handler_options.get("additional_params"):
                    add_params = yaml.safe_load(handler_options.get("additional_params"))
                    if type(add_params) == dict:
                        init_param.update(add_params)

                if tokentype == "sms":
                    if handler_options.get("dynamic_phone"):
                        init_param["dynamic_phone"] = 1
                    else:
                        init_param['phone'] = user.get_user_phone(
                            phone_type='mobile', index=0)
                        if not init_param['phone']:
                            log.warning("Enrolling SMS token. But the user "
                                        "{0!r} has no mobile number!".format(user))
                    if handler_options.get("sms_identifier"):
                        init_param["sms.identifier"] = handler_options.get("sms_identifier")
                elif tokentype == "email":
                    if handler_options.get("dynamic_email"):
                        init_param["dynamic_email"] = 1
                    else:
                        init_param['email'] = user.info.get("email", "")
                        if not init_param['email']:
                            log.warning("Enrolling EMail token. But the user {0!s}"
                                        "has no email address!".format(user))
                    if handler_options.get("smtp_identifier"):
                        init_param["email.identifier"] = handler_options.get("smtp_identifier")
                elif tokentype == "motp":
                    init_param['motppin'] = handler_options.get("motppin")

            t = init_token(param=init_param, user=user)
            log.info("New token {0!s} enrolled.".format(t.token.serial))

        return ret
    def test_20_pin_policy(self):
        # Unspecified character specifier
        self.assertRaises(PolicyError, check_pin_contents, "1234", "+o")

        r, c = check_pin_contents("1234", "n")
        self.assertTrue(r)

        r, c = check_pin_contents(r"[[[", "n")
        self.assertFalse(r)

        r, c = check_pin_contents(r"[[[", "c")
        self.assertFalse(r)

        r, c = check_pin_contents(r"[[[", "s")
        self.assertTrue(r)

        # check the validation of a generated password with square brackets
        password = generate_password(size=3, requirements=['[', '[', '['])
        r, c = check_pin_contents(password, "s")
        self.assertTrue(r)

        r, c = check_pin_contents("abc", "nc")
        self.assertFalse(r)
        self.assertEqual(
            "Missing character in PIN: {}".format(CHARLIST_CONTENTPOLICY['n']),
            c)

        r, c = check_pin_contents("123", "nc")
        self.assertFalse(r)
        self.assertEqual(
            r"Missing character in PIN: {}".format(
                CHARLIST_CONTENTPOLICY['c']), c)

        r, c = check_pin_contents("123", "ncs")
        self.assertFalse(r)
        self.assertTrue(
            r"Missing character in PIN: {}".format(
                CHARLIST_CONTENTPOLICY['c'] in c), c)
        self.assertTrue(
            r"Missing character in PIN: {}".format(
                CHARLIST_CONTENTPOLICY['s'] in c), c)

        r, c = check_pin_contents("1234", "")
        self.assertFalse(r)
        self.assertEqual(c, "No policy given.")

        # check for either number or character
        r, c = check_pin_contents("1234", "+cn")
        self.assertTrue(r)

        r, c = check_pin_contents("1234xxxx", "+cn")
        self.assertTrue(r)

        r, c = check_pin_contents("xxxx", "+cn")
        self.assertTrue(r)
        self.assertTrue(check_pin_contents("test1234", "+cn")[0])
        self.assertTrue(check_pin_contents("test12$$", "+cn")[0])
        self.assertTrue(check_pin_contents("test12", "+cn")[0])
        self.assertTrue(check_pin_contents("1234", "+cn")[0])

        r, c = check_pin_contents("@@@@", "+cn")
        self.assertFalse(r)
        self.assertEqual(
            c, "Missing character in PIN: {}{}".format(
                CHARLIST_CONTENTPOLICY['c'], CHARLIST_CONTENTPOLICY['n']))

        # check for exclusion
        # No special character
        r, c = check_pin_contents("1234", "-s")
        self.assertTrue(r)
        r, c = check_pin_contents("1234aaaa", "-s")
        self.assertTrue(r)
        r, c = check_pin_contents("1234aaaa//", "-s")
        self.assertFalse(r)

        # A pin that falsely contains a number
        r, c = check_pin_contents("1234aaa", "-sn")
        self.assertFalse(r)
        self.assertEqual(c, "Not allowed character in PIN!")
        r, c = check_pin_contents("///aaa", "-sn")
        self.assertFalse(r)
        # A pin without a number and without a special
        r, c = check_pin_contents("xxxx", "-sn")
        self.assertTrue(r)

        r, c = check_pin_contents("1234@@@@", "-c")
        self.assertTrue(r)

        # A pin with only digits allowed
        r, c = check_pin_contents("1234", "-cs")
        self.assertTrue(r)
        r, c = check_pin_contents("a1234", "-cs")
        self.assertFalse(r)

        # A pin with only a specified list of chars
        r, c = check_pin_contents("1234111", "[1234]")
        self.assertTrue(r)
        r, c = check_pin_contents("12345", "[1234]")
        self.assertFalse(r)