def test_07_login_mode(self):
        # a realm: cornelius@r1: PW: test

        def check_webui_user_userstore(user_obj, password,
                                       options=None, superuser_realms=None,
                                       check_otp=False):
            self.assertEqual(check_otp, False)

        def check_webui_user_privacyidea(user_obj, password,
                                         options=None, superuser_realms=None,
                                         check_otp=False):
            self.assertEqual(check_otp, True)

        user_obj = User("cornelius", "r1")

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        # No policy, the function is called with check_otp=False
        login_mode(check_webui_user_userstore, user_obj, "",
                   options=options, superuser_realms="", check_otp=False)

        set_policy(name="pol2",
                   scope=SCOPE.WEBUI,
                   action="%s=%s" % (ACTION.LOGINMODE, LOGINMODE.PRIVACYIDEA))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        # Policy is set, the function is called with check_otp=True
        login_mode(check_webui_user_privacyidea, user_obj, "",
                   options=options, superuser_realms="", check_otp=False)
    def test_01_challenge(self):

        set_policy("chalresp", scope=SCOPE.AUTHZ,
                   action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE))
        token = init_token({"genkey": 1, "serial": "CHAL1", "pin": "pin"})
        from privacyidea.lib.token import check_serial_pass
        r = check_serial_pass(token.token.serial, "pin")
        # The OTP PIN is correct
        self.assertEqual(r[0], False)
        self.assertEqual(r[1].get("message"), "please enter otp: ")
        transaction_id = r[1].get("transaction_id")
        chals = get_challenges()
        self.assertEqual(len(chals), 1)
        self.assertEqual(chals[0].transaction_id, transaction_id)

        # get challenge for this serial
        chals = get_challenges(serial="CHAL1")
        self.assertEqual(len(chals), 1)
        self.assertEqual(chals[0].transaction_id, transaction_id)

        # get challenge for another seial
        chals = get_challenges(serial="CHAL2")
        self.assertEqual(len(chals), 0)

        delete_policy("chalresp")
 def test_03_realm_dropdown(self):
     set_policy("realmdrop", scope=SCOPE.WEBUI,
                action="{0!s}=Hello World".format(ACTION.REALMDROPDOWN))
     with self.app.test_request_context('/', method='GET'):
         res = self.app.full_dispatch_request()
         self.assertTrue(res.status_code == 200, res)
         self.assertIsNotNone(re.search(r'id="REALMS" value=".*World.*"', res.data), res)
    def test_18_auth_timelimit_fail(self):
        user = User("timelimituser", realm=self.realm2)
        pin = "spass"
        # create a token
        token = init_token({"type": "spass", "pin": pin}, user=user)

        # set policy for timelimit
        set_policy(name="pol_time1", scope=SCOPE.AUTHZ, action="%s=2/20s" % ACTION.AUTHMAXFAIL)

        for i in [1, 2]:
            with self.app.test_request_context(
                "/validate/check",
                method="POST",
                data={"user": "******", "realm": self.realm2, "pass": "******"},
            ):
                res = self.app.full_dispatch_request()
                self.assertTrue(res.status_code == 200, res)
                result = json.loads(res.data).get("result")
                self.assertEqual(result.get("value"), False)

        # Now we do the correct authentication, but
        # as already two authentications failed, this will fail, too
        with self.app.test_request_context(
            "/validate/check", method="POST", data={"user": "******", "realm": self.realm2, "pass": pin}
        ):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = json.loads(res.data).get("result")
            self.assertEqual(result.get("value"), False)
            details = json.loads(res.data).get("detail")
            self.assertEqual(details.get("message"), "Only 2 failed authentications per 0:00:20")

        delete_policy("pol_time1")
        remove_token(token.token.serial)
    def test_19_emailtext(self):
        # create a EMAILTEXT policy:
        p = set_policy(name="emailtext",
                       action="%s=%s" % (EMAILACTION.EMAILTEXT, "'Your <otp>'"),
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}
        smtpmock.setdata(response={"*****@*****.**": (200, "OK")})
        transactionid = "123456098713"
        db_token = Token.query.filter_by(serial=self.serial1).first()
        token = EmailTokenClass(db_token)
        c = token.create_challenge(transactionid, options=options)
        self.assertTrue(c[0], c)
        display_message = c[1]
        self.assertTrue(c[3].get("state"), transactionid)
        self.assertEqual(display_message, "Enter the OTP from the Email:")

        # Test AUTOEMAIL
        p = set_policy(name="autoemail",
                       action=EMAILACTION.EMAILAUTO,
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        r = token.check_otp("287922", options=options)
        self.assertTrue(r > 0, r)
    def test_19_validate_passthru(self):
        # user passthru, realm: self.realm2, passwd: pthru
        set_policy(name="pthru", scope=SCOPE.AUTH, action=ACTION.PASSTHRU)

        # Passthru with GET request
        with self.app.test_request_context(
                '/validate/check',
                method='GET',
                query_string=urlencode({"user": "******",
                                        "realm": self.realm2,
                                        "pass": "******"})):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = json.loads(res.data).get("result")
            self.assertEqual(result.get("value"), True)

        # Passthru with POST Request
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={"user": "******",
                                                 "realm": self.realm2,
                                                 "pass": "******"}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = json.loads(res.data).get("result")
            self.assertEqual(result.get("value"), True)

        delete_policy("pthru")
    def test_01a_admin_realms(self):
        admin1 = {"username": "******",
                  "role": "admin",
                  "realm": "realm1"}

        admin2 = {"username": "******",
                  "role": "admin",
                  "realm": "realm2"}

        set_policy(name="pol",
                   scope=SCOPE.ADMIN,
                   action="*", adminrealm="realm1")
        g.policy_object = PolicyClass()
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        req.all_data = {}

        # admin1 is allowed to do everything
        g.logged_in_user = admin1
        r = check_base_action(req, action="delete")
        self.assertTrue(r)

        # admin2 is not allowed.
        g.logged_in_user = admin2
        self.assertRaises(PolicyError, check_base_action, req, action="delete")
        delete_policy("pol")
    def test_03_is_password_reset(self):
        # create resolver and realm
        param = self.parameters
        param["resolver"] = "register"
        param["type"] = "sqlresolver"
        r = save_resolver(param)
        self. assertTrue(r > 0)

        added, failed = set_realm("register", resolvers=["register"])
        self.assertTrue(added > 0)
        self.assertEqual(len(failed), 0)

        # No user policy at all
        r = is_password_reset()
        self.assertEqual(r, True)

        # create policy
        set_policy(name="pwrest", scope=SCOPE.USER, action=ACTION.PASSWORDRESET)
        r = is_password_reset()
        self.assertEqual(r, True)

        # create policy that does not allow password_reset
        set_policy(name="pwrest", scope=SCOPE.USER, action=ACTION.DELETE)
        r = is_password_reset()
        self.assertEqual(r, False)
    def test_03_check_token_upload(self):
        g.logged_in_user = {"username": "******",
                            "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        req.all_data = {"filename": "token.xml"}

        # Set a policy, that does allow the action
        set_policy(name="pol1",
                   scope=SCOPE.ADMIN,
                   action="enrollTOTP, enrollHOTP, %s" % ACTION.IMPORT,
                   client="10.0.0.0/8")
        g.policy_object = PolicyClass()

        # Try to import tokens
        r = check_token_upload(req)
        self.assertTrue(r)

        # The admin can not upload from another IP address
        # An exception is raised
        env["REMOTE_ADDR"] = "192.168.0.1"
        req = Request(env)
        req.all_data = {"filename": "token.xml"}
        self.assertRaises(PolicyError,
                          check_token_upload, req)
        # finally delete policy
        delete_policy("pol1")
    def test_17_auth_timelimit_success(self):
        user = User("timelimituser", realm=self.realm2)
        pin = "spass"
        # create a token
        token = init_token({"type": "spass",
                            "pin": pin}, user=user)

        # set policy for timelimit
        set_policy(name="pol_time1",
                   scope=SCOPE.AUTHZ,
                   action="%s=2/20s" % ACTION.AUTHMAXSUCCESS)

        for i in [1, 2]:
            with self.app.test_request_context('/validate/check',
                                               method='POST',
                                               data={"user": "******",
                                                     "realm": self.realm2,
                                                     "pass": pin}):
                res = self.app.full_dispatch_request()
                self.assertTrue(res.status_code == 200, res)
                result = json.loads(res.data).get("result")
                self.assertEqual(result.get("value"), True)

        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={"user": "******",
                                                 "realm": self.realm2,
                                                 "pass": pin}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = json.loads(res.data).get("result")
            self.assertEqual(result.get("value"), False)

        delete_policy("pol_time1")
        remove_token(token.token.serial)
    def test_06_passthru(self):
        user = User("cornelius", realm="r1")
        passw = "test"
        options = {}
        # A user with no tokens will fail to authenticate
        self.assertEqual(get_tokens(user=user, count=True), 0)
        rv = auth_user_passthru(check_user_pass, user, passw, options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"), "The user has no tokens assigned")

        # Now we set a PASSTHRU policy, so that the user may authenticate
        # against his userstore
        set_policy(name="pol1", scope=SCOPE.AUTH, action=ACTION.PASSTHRU)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        options = {"g": g}
        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(
            rv[1].get("message"), u"The user authenticated against his userstore " u"according to policy 'pol1'."
        )

        # Now assign a token to the user. If the user has a token and the
        # passthru policy is set, the user must not be able to authenticate
        # with his userstore password.
        init_token({"serial": "PTHRU", "type": "spass", "pin": "Hallo"}, user=user)
        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"), "wrong otp pin")

        remove_token("PTHRU")
        delete_policy("pol1")
    def test_14_required_email(self):
        g.logged_in_user = {"username": "******",
                            "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        # Set a mangle policy to change the username
        # and only use the last 4 characters of the username
        set_policy(name="email1",
                   scope=SCOPE.REGISTER,
                   action="%s=/.*@mydomain\..*" % ACTION.REQUIREDEMAIL)
        g.policy_object = PolicyClass()
        # request, that matches the policy
        req.all_data = {"email": "*****@*****.**"}
        # This emails is allowed
        r = required_email(req)
        self.assertTrue(r)

        # This email is not allowed
        req.all_data = {"email": "*****@*****.**"}
        # This emails is allowed
        self.assertRaises(RegistrationError, required_email, req)

        delete_policy("email1")
        g.policy_object = PolicyClass()
        # Without a policy, this email can register
        req.all_data = {"email": "*****@*****.**"}
        # This emails is allowed
        r = required_email(req)
        self.assertTrue(r)
    def test_03_otppin_for_serial(self):
        # now create a policy with userstore PW
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="%s=%s" % (ACTION.OTPPIN, ACTIONVALUE.USERSTORE))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g,
                   "serial": "T001"}

        # create a token and assign to user cornelius
        token = init_token({"serial": "T001", "type": "hotp", "genkey": 1},
                           user=User("cornelius", realm="r1"))
        self.assertTrue(token)

        # Wrong password
        # Not identified by the user but by the token owner
        r = auth_otppin(self.fake_check_otp, token,
                          "WrongPW", options=options,
                          user=None)
        self.assertFalse(r)

        # Correct password from userstore: "test"
        # Not identified by the user but by the token owner
        r = auth_otppin(self.fake_check_otp, token,
                          "test", options=options,
                          user=None)
        self.assertTrue(r)
        delete_policy("pol1")
        remove_token("T001")
    def test_03_no_detail_on_success(self):
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "HOTP123435"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        # The response contains the token type SPASS
        res = {"jsonrpc": "2.0",
               "result": {"status": True,
                          "value": True},
               "version": "privacyIDEA test",
               "id": 1,
               "detail": {"message": "matching 1 tokens",
                          "serial": "HOTP123456",
                          "type": "hotp"}}
        resp = Response(json.dumps(res))

        # Set a policy, that does not allow the detail on success
        set_policy(name="pol2",
                   scope=SCOPE.AUTHZ,
                   action="no_detail_on_success", client="10.0.0.0/8")
        g.policy_object = PolicyClass()

        new_response = no_detail_on_success(req, resp)
        jresult = json.loads(new_response.data)
        self.assertTrue("detail" not in jresult, jresult)
        delete_policy("pol2")
    def test_15_reset_password(self):
        builder = EnvironBuilder(method='POST',
                                 data={'user': "******",
                                       "realm": self.realm1},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        # Set a mangle policy to change the username
        # and only use the last 4 characters of the username
        set_policy(name="recover",
                   scope=SCOPE.USER,
                   action="%s" % ACTION.RESYNC)
        g.policy_object = PolicyClass()
        req.all_data = {"user": "******", "realm": self.realm1}
        # There is a user policy without password reset, so an exception is
        # raised
        self.assertRaises(PolicyError, check_anonymous_user, req,
                          ACTION.PASSWORDRESET)

        # The password reset is allowed
        set_policy(name="recover",
                   scope=SCOPE.USER,
                   action="%s" % ACTION.PASSWORDRESET)
        g.policy_object = PolicyClass()
        r = check_anonymous_user(req, ACTION.PASSWORDRESET)
        self.assertEqual(r, True)
    def test_05_user_has_no_tokens(self):
        user = User("cornelius", realm="r1")
        passw = "test"
        options = {}
        # A user with no tokens will fail to authenticate
        rv = auth_user_has_no_token(check_user_pass, user, passw, options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"),
                         "The user has no tokens assigned")

        # Now we set a policy, that a non existing user will authenticate
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action=ACTION.PASSNOTOKEN)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}
        rv = auth_user_has_no_token(check_user_pass, user, passw,
                                      options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"user has no token, accepted due to "
                         u"'pol1'")
        delete_policy("pol1")
    def test_04a_user_does_not_exist_without_resolver(self):
        user = User("MisterX", realm=self.realm1)
        passw = "somePW"

        # Now we set a policy, that a non existing user will authenticate
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0}, {1}, {2}, {3}=none".format(
                       ACTION.RESETALLTOKENS,
                       ACTION.PASSNOUSER,
                       ACTION.PASSNOTOKEN,
                       ACTION.OTPPIN
                   ),
                   realm=self.realm1)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}
        rv = auth_user_does_not_exist(check_user_pass, user, passw,
                                      options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"user does not exist, accepted due "
                         u"to 'pol1'")
        delete_policy("pol1")
    def test_16_init_token_defaults(self):
        g.logged_in_user = {"username": "******",
                            "role": "user"}
        builder = EnvironBuilder(method='POST',
                                 data={'type': "totp",
                                       "genkey": "1"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        g.client_ip = env["REMOTE_ADDR"]
        req = Request(env)

        # Set a policy that defines the default totp settings
        set_policy(name="pol1",
                   scope=SCOPE.USER,
                   action="totp_otplen=8,totp_hashlib=sha256,totp_timestep=60")
        g.policy_object = PolicyClass()

        # request, that matches the policy
        req.all_data = {
            "type": "totp",
            "genkey": "1"}
        init_token_defaults(req)

        # Check, if the token defaults were added
        self.assertEqual(req.all_data.get("totp.hashlib"), "sha256")
        self.assertEqual(req.all_data.get("otplen"), "8")
        self.assertEqual(req.all_data.get("timeStep"), "60")
        # finally delete policy
        delete_policy("pol1")
    def test_02_userstore_password(self):
        # create a realm, where cornelius has a password test
        rid = save_resolver({"resolver": "myreso",
                             "type": "passwdresolver",
                             "fileName": PWFILE2})
        self.assertTrue(rid > 0, rid)

        (added, failed) = set_realm("r1", ["myreso"])
        self.assertTrue(len(failed) == 0)
        self.assertTrue(len(added) == 1)

        # now create a policy with userstore PW
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="%s=%s" % (ACTION.OTPPIN, ACTIONVALUE.USERSTORE))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        # Wrong password
        r = auth_otppin(self.fake_check_otp, None,
                          "WrongPW", options=options,
                          user=User("cornelius", realm="r1"))
        self.assertFalse(r)

        # Correct password from userstore: "test"
        r = auth_otppin(self.fake_check_otp, None,
                          "test", options=options,
                          user=User("cornelius", realm="r1"))
        self.assertTrue(r)
        delete_policy("pol1")
    def test_13_remote_user(self):
        g.logged_in_user = {"username": "******",
                            "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        env["REMOTE_USER"] = "******"
        req = Request(env)

        # A user, for whom the login via REMOTE_USER is allowed.
        set_policy(name="ruser",
                   scope=SCOPE.WEBUI,
                   action="%s=%s" % (ACTION.REMOTE_USER, REMOTE_USER.ACTIVE))
        g.policy_object = PolicyClass()

        r = is_remote_user_allowed(req)
        self.assertEqual(r, [REMOTE_USER.ACTIVE])

        # Login for the REMOTE_USER is not allowed.
        # Only allowed for user "super", but REMOTE_USER=admin
        set_policy(name="ruser",
                   scope=SCOPE.WEBUI,
                   action="%s=%s" % (ACTION.REMOTE_USER, REMOTE_USER.ACTIVE),
                   user="******")
        g.policy_object = PolicyClass()

        r = is_remote_user_allowed(req)
        self.assertEqual(r, [])

        delete_policy("ruser")
    def test_09_challenge_response_allowed(self):
        user = User("cornelius", realm="r1")
        pin = "test"

        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        options = {"g": g}
        token = init_token({"type": "hotp",
                            "otpkey": "1234",
                            "pin": pin}, user=user)
        # With no policy, it will be no chal resp
        rv = token.is_challenge_request(pin, user=user, options=options)
        self.assertEqual(rv, False)

        # Now we set a policy with several tokentypes
        set_policy(name="pol_chal_resp_1",
                   scope=SCOPE.AUTH,
                   action="%s=hotp tiqr totp" % ACTION.CHALLENGERESPONSE)
        set_policy(name="pol_chal_resp_2",
                   scope=SCOPE.AUTH,
                   action="%s=hotp motp" % ACTION.CHALLENGERESPONSE)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        options = {"g": g}
        rv = token.is_challenge_request(pin, user=user, options=options)
        self.assertEqual(rv, True)
        delete_policy("pol_chal_resp_1")
    def test_08_encrypt_pin(self):
        g.logged_in_user = {"username": "******",
                            "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)

        # Set a policy that defines the PIN to be encrypted
        set_policy(name="pol1",
                   scope=SCOPE.ENROLL,
                   action=ACTION.ENCRYPTPIN)
        g.policy_object = PolicyClass()

        # request, that matches the policy
        req.all_data = {
                        "user": "******",
                        "realm": "home"}
        encrypt_pin(req)

        # Check, if the tokenlabel was added
        self.assertEqual(req.all_data.get("encryptpin"), "True")
        # finally delete policy
        delete_policy("pol1")
    def test_01_otppin(self):
        my_user = User("cornelius", realm="r1")
        set_policy(name="pol1", scope=SCOPE.AUTH, action="%s=%s" % (ACTION.OTPPIN, ACTIONVALUE.NONE))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        # NONE with empty PIN -> success
        r = auth_otppin(self.fake_check_otp, None, "", options=options, user=my_user)
        self.assertTrue(r)
        # NONE with empty PIN -> success, even if the authentication is done
        # for a serial and not a user, since the policy holds for all realms
        token = init_token({"type": "HOTP", "otpkey": "1234"})
        r = auth_otppin(self.fake_check_otp, token, "", options=options, user=None)
        self.assertTrue(r)

        # NONE with some pin -> fail
        r = auth_otppin(self.fake_check_otp, None, "some pin", options=options, user=my_user)
        self.assertFalse(r)

        delete_policy("pol1")
        set_policy(name="pol1", scope=SCOPE.AUTH, action="%s=%s" % (ACTION.OTPPIN, ACTIONVALUE.TOKENPIN))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        r = auth_otppin(self.fake_check_otp, None, "FAKE", options=options, user=my_user)
        self.assertTrue(r)
        r = auth_otppin(self.fake_check_otp, None, "Wrong Pin", options=options, user=my_user)
        self.assertFalse(r)
        delete_policy("pol1")
    def test_07_set_random_pin(self):
        g.logged_in_user = {"username": "******",
                            "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)

        # Set a policy that defines the tokenlabel
        set_policy(name="pol1",
                   scope=SCOPE.ENROLL,
                   action="%s=%s" % (ACTION.OTPPINRANDOM, "12"))
        set_policy(name="pinhandling",
                   scope=SCOPE.ENROLL,
                   action="%s=privacyidea.lib.pinhandling.base.PinHandler" %
                          ACTION.PINHANDLING)
        g.policy_object = PolicyClass()

        # request, that matches the policy
        req.all_data = {
                        "user": "******",
                        "realm": "home"}
        init_random_pin(req)

        # Check, if the tokenlabel was added
        self.assertEqual(len(req.all_data.get("pin")), 12)
        # finally delete policy
        delete_policy("pol1")
        delete_policy("pinhandling")
    def test_08_config_lost_token_policy(self):
        def func1(serial, validity=10, contents="Ccns", pw_len=16, options=None):
            self.assertEqual(validity, 10)
            self.assertEqual(contents, "Ccns")
            self.assertEqual(pw_len, 16)

        def func2(serial, validity=10, contents="Ccns", pw_len=16, options=None):
            self.assertEqual(validity, 5)
            self.assertEqual(contents, "C")
            self.assertEqual(pw_len, 3)

        init_token({"serial": "LOST001", "type": "hotp", "genkey": 1}, user=User("cornelius", realm="r1"))

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        # No policy, the function is called with default values
        config_lost_token(func1, "LOST001", options=options)

        set_policy(
            name="lost_pol2",
            scope=SCOPE.ENROLL,
            action="%s=%s, %s=%s,"
            "%s=%s" % (ACTION.LOSTTOKENPWCONTENTS, "C", ACTION.LOSTTOKENVALID, 5, ACTION.LOSTTOKENPWLEN, 3),
        )
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        # Policy is set, the function is called with check_otp=True
        config_lost_token(func2, "LOST001", options=options)
    def test_06_set_tokenlabel(self):
        g.logged_in_user = {"username": "******",
                            "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)

        # Set a policy that defines the tokenlabel
        set_policy(name="pol1",
                   scope=SCOPE.ENROLL,
                   action="%s=%s" % (ACTION.TOKENLABEL, "<u>@<r>"))
        set_policy(name="pol2",
                   scope=SCOPE.ENROLL,
                   action="%s=%s" % (ACTION.TOKENISSUER, "myPI"))
        g.policy_object = PolicyClass()

        # request, that matches the policy
        req.all_data = {
                        "user": "******",
                        "realm": "home"}
        init_tokenlabel(req)

        # Check, if the tokenlabel was added
        self.assertEqual(req.all_data.get("tokenlabel"), "<u>@<r>")
        # Check, if the tokenissuer was added
        self.assertEqual(req.all_data.get("tokenissuer"), "myPI")
        # finally delete policy
        delete_policy("pol1")
        delete_policy("pol2")
    def test_01_create_simple_policy(self):
        p = set_policy(name="pol1", action="read", scope="system")
        self.assertTrue(p > 0)

        p = set_policy(name="pol2", action="tokentype=HOTP", scope=SCOPE.AUTHZ)
        self.assertTrue(p > 0)

        p = set_policy(name="pol3", action="serial=OATH", scope=SCOPE.AUTHZ)
        self.assertTrue(p > 0)

        p = set_policy(name="pol4", action="enroll, init, disable , enable", scope="admin")
        self.assertTrue(p > 0)

        P = PolicyClass()
        policies = P.get_policies(name="pol3")
        # only one policy found
        self.assertTrue(len(policies) == 1, len(policies))

        policies = P.get_policies(scope=SCOPE.AUTHZ)
        self.assertTrue(len(policies) == 2, len(policies))

        policies = P.get_policies(scope=SCOPE.AUTHZ, action="tokentype")
        self.assertTrue(len(policies) == 1, len(policies))

        policies = P.get_policies(scope="admin", action="disable")
        self.assertTrue(len(policies) == 1, len(policies))
        self.assertTrue(policies[0].get("name") == "pol4")
    def test_22_validate_locked(self):
        # test a user with two tokens
        # One token is locked/revoked.
        #  But the user must be able to login with the 2nd token
        # user lockeduser, realm: self.realm2
        # enroll two tokens
        user = "******"
        set_policy(name="locked",
                   scope=SCOPE.AUTH,
                   action="{0!s}={1!s}".format(ACTION.OTPPIN, "tokenpin"))
        r = init_token({"type": "spass", "serial": "spass1l",
                        "pin": "locked"},
                       user=User(user, self.realm2))
        r = init_token({"type": "spass", "serial": "spass2l",
                        "pin": "locked"},
                       user=User(user, self.realm2))
        # disable first token
        r = revoke_token("spass1l")
        self.assertEqual(r, True)
        # Check that the user still can authenticate with the 2nd token
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={"user": user,
                                                 "realm": self.realm2,
                                                 "pass": "******"}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = json.loads(res.data).get("result")
            self.assertEqual(result.get("value"), True)

        remove_token("spass1l")
        remove_token("spass2l")
        delete_policy("locked")
    def test_19_emailtext(self):
        # create a EMAILTEXT policy:
        p = set_policy(name="emailtext",
                       action="{0!s}={1!s}".format(EMAILACTION.EMAILTEXT, "'Your <otp>'"),
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}
        smtpmock.setdata(response={"*****@*****.**": (200, "OK")})
        transactionid = "123456098713"
        db_token = Token.query.filter_by(serial=self.serial1).first()
        token = EmailTokenClass(db_token)
        c = token.create_challenge(transactionid, options=options)
        self.assertTrue(c[0], c)
        display_message = c[1]
        self.assertTrue(c[3].get("state"), transactionid)
        self.assertEqual(display_message, "Enter the OTP from the Email:")
        _, mimetype = token._get_email_text_or_subject(options, EMAILACTION.EMAILTEXT)
        self.assertEqual(mimetype, "plain")

        # Test AUTOEMAIL
        p = set_policy(name="autoemail",
                       action=EMAILACTION.EMAILAUTO,
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        r = token.check_otp("287922", options=options)
        self.assertTrue(r > 0, r)

        # create a EMAILTEXT policy with template
        p = set_policy(name="emailtext",
                       action="{0!s}=file:{1!s}".format(EMAILACTION.EMAILTEXT, TEMPLATE_FILE),
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}
        smtpmock.setdata(response={"*****@*****.**": (200, "OK")})
        transactionid = "123456098714"
        db_token = Token.query.filter_by(serial=self.serial1).first()
        token = EmailTokenClass(db_token)
        email_text, mimetype = token._get_email_text_or_subject(options, EMAILACTION.EMAILTEXT)
        self.assertTrue("<p>Hello,</p>" in email_text)
        self.assertEqual(mimetype, "html")
        c = token.create_challenge(transactionid, options=options)
        self.assertTrue(c[0], c)
        display_message = c[1]
        self.assertTrue(c[3].get("state"), transactionid)
        self.assertEqual(display_message, "Enter the OTP from the Email:")
 def test_05_custom_login_text(self):
     set_policy("logtext", scope=SCOPE.WEBUI,
                action="{0!s}=Go for it!".format(ACTION.LOGIN_TEXT))
     with self.app.test_request_context('/',
                                        method='GET'):
         res = self.app.full_dispatch_request()
         self.assertTrue(res.status_code == 200, res)
         self.assertTrue(b"Go for it!" in res.data)
Exemple #31
0
    def test_02_get_allowed_audit_realm(self):
        # Check that an administrator is only allowed to see log entries of
        # the defined realms.
        # fill some audit entries
        Audit(action="enroll", success=1, realm="realm1a").save()
        Audit(action="enroll", success=1, realm="realm1a").save()
        Audit(action="enroll", success=1, realm="realm2b").save()
        Audit(action="enroll", success=1, realm="realm2b").save()
        Audit(action="enroll", success=1, realm="realm2b").save()

        # check, that we see all audit entries
        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           data={"realm": "realm1a"},
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = json.loads(res.data.decode('utf8'))
            self.assertTrue(json_response.get("result").get("status"), res)
            self.assertEqual(
                json_response.get("result").get("value").get("count"), 2)

        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = json.loads(res.data.decode('utf8'))
            self.assertTrue(json_response.get("result").get("status"), res)
            self.assertEqual(
                json_response.get("result").get("value").get("count"), 8)
            audit_list = json_response.get("result").get("value").get(
                "auditdata")
            audit_actions = [
                a for a in audit_list if a.get("action") == "GET /audit/"
            ]
            self.assertEqual(len(audit_actions), 2)

        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           data={"realm": "realm2b"},
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = json.loads(res.data.decode('utf8'))
            self.assertTrue(json_response.get("result").get("status"), res)
            self.assertEqual(
                json_response.get("result").get("value").get("count"), 3)

        # set policy for audit realms
        set_policy("audit01",
                   scope=SCOPE.ADMIN,
                   action=ACTION.AUDIT,
                   realm="realm1a")

        # check, that we only see allowed audit realms
        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = json.loads(res.data.decode('utf8'))
            self.assertTrue(json_response.get("result").get("status"), res)
            # We now have 3 entries, as we added one by the search in line #43
            audit_list = json_response.get("result").get("value").get(
                "auditdata")
            audit_realms = [
                a for a in audit_list if a.get("realm") == "realm1a"
            ]
            self.assertEqual(len(audit_realms), 3)
            self.assertEqual(
                json_response.get("result").get("value").get("count"), 3)

        # delete policy
        delete_policy("audit01")
    def test_19_emailtext(self):
        # create a EMAILTEXT policy:
        p = set_policy(name="emailtext",
                       action="{0!s}={1!s}".format(EMAILACTION.EMAILTEXT,
                                                   "'Your <otp>'"),
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}
        smtpmock.setdata(response={"*****@*****.**": (200, "OK")})
        transactionid = "123456098713"
        db_token = Token.query.filter_by(serial=self.serial1).first()
        token = EmailTokenClass(db_token)
        c = token.create_challenge(transactionid, options=options)
        self.assertTrue(c[0], c)
        display_message = c[1]
        self.assertTrue(c[3].get("state"), transactionid)
        self.assertEqual(display_message, _("Enter the OTP from the Email:"))
        _n, mimetype = token._get_email_text_or_subject(
            options, EMAILACTION.EMAILTEXT)
        self.assertEqual(mimetype, "plain")

        # Test AUTOEMAIL
        p = set_policy(name="autoemail",
                       action=EMAILACTION.EMAILAUTO,
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}

        r = token.check_otp("287922", options=options)
        self.assertTrue(r > 0, r)

        # create a EMAILTEXT policy with template
        p = set_policy(name="emailtext",
                       action="{0!s}=file:{1!s}".format(
                           EMAILACTION.EMAILTEXT, TEMPLATE_FILE),
                       scope=SCOPE.AUTH)
        self.assertTrue(p > 0)

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        options = {"g": g}
        smtpmock.setdata(response={"*****@*****.**": (200, "OK")})
        transactionid = "123456098714"
        db_token = Token.query.filter_by(serial=self.serial1).first()
        token = EmailTokenClass(db_token)
        email_text, mimetype = token._get_email_text_or_subject(
            options, EMAILACTION.EMAILTEXT)
        self.assertTrue("<p>Hello,</p>" in email_text)
        self.assertEqual(mimetype, "html")
        c = token.create_challenge(transactionid, options=options)
        self.assertTrue(c[0], c)
        display_message = c[1]
        self.assertTrue(c[3].get("state"), transactionid)
        self.assertEqual(display_message, _("Enter the OTP from the Email:"))
Exemple #33
0
    def test_05_u2f_auth_fails_wrong_issuer(self):
        # test data taken from
        # https://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-u2f-raw-message-formats-ps-20141009.html#examples
        serial = "U2F0010BF6F"
        set_privacyidea_config("u2f.appId", "https://puck.az.intern")
        pin = "test"
        # Registration data
        client_data = "eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCIsImNoYWxsZW5nZSI6ImpIakIxaEM2VjA3dDl4ZnNNaDRfOEQ3U1JuSHRFY1BqUTdsaVl3cWxkX009Iiwib3JpZ2luIjoiaHR0cHM6Ly9wdWNrLmF6LmludGVybiIsImNpZF9wdWJrZXkiOiJ1bnVzZWQifQ"
        reg_data = "BQRHjwxEYFCkLHz3xdrmifKOHl2h17BmRJQ_S1Y9PRAhS2R186T391YE-ryqWis9HSmdp0XpRqUaKk9L8lxJTPpTQF_xFJ_LAsKkPTzKIwUlPIjGZDsLmv0en2Iya17Yz8X8OS89fuxwZOvEok-NQOKUTJP3att_RVe3dEAbq_iOtyAwggJEMIIBLqADAgECAgRVYr6gMAsGCSqGSIb3DQEBCzAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowKjEoMCYGA1UEAwwfWXViaWNvIFUyRiBFRSBTZXJpYWwgMTQzMjUzNDY4ODBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEszH3c9gUS5mVy-RYVRfhdYOqR2I2lcvoWsSCyAGfLJuUZ64EWw5m8TGy6jJDyR_aYC4xjz_F2NKnq65yvRQwmjOzA5MCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS41MBMGCysGAQQBguUcAgEBBAQDAgUgMAsGCSqGSIb3DQEBCwOCAQEArBbZs262s6m3bXWUs09Z9Pc-28n96yk162tFHKv0HSXT5xYU10cmBMpypXjjI-23YARoXwXn0bm-BdtulED6xc_JMqbK-uhSmXcu2wJ4ICA81BQdPutvaizpnjlXgDJjq6uNbsSAp98IStLLp7fW13yUw-vAsWb5YFfK9f46Yx6iakM3YqNvvs9M9EUJYl_VrxBJqnyLx2iaZlnpr13o8NcsKIJRdMUOBqt_ageQg3ttsyq_3LyoNcu7CQ7x8NmeCGm_6eVnZMQjDmwFdymwEN4OxfnM5MkcKCYhjqgIGruWkVHsFnJa8qjZXneVvKoiepuUQyDEJ2GcqvhU2YKY1zBFAiEA4ZkIXXyjEPExcMGtW6kJXqYv7UHgjxJR5h3H9w9FV7gCIFGdhxZDqwCQKplDi-LU4WJ45OyCpNK6lGa72eZqUR_k"
        # Authentication data
        transaction_id = "05871369157706202013"
        challenge = "1616515928c389ba9e028d83eb5f63782cbf351ca6abbc81aeb0dddd4895b609"
        # challenge = "FhZRWSjDibqeAo2D619jeCy_NRymq7yBrrDd3UiVtgk"
        key_handle = "X_EUn8sCwqQ9PMojBSU8iMZkOwua_R6fYjJrXtjPxfw5Lz1-7HBk68SiT41A4pRMk_dq239FV7d0QBur-I63IA"
        client_data_auth = "eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwiY2hhbGxlbmdlIjoiRmhaUldTakRpYnFlQW8yRDYxOWplQ3lfTlJ5bXE3eUJyckRkM1VpVnRnayIsIm9yaWdpbiI6Imh0dHBzOi8vcHVjay5hei5pbnRlcm4iLCJjaWRfcHVia2V5IjoidW51c2VkIn0"
        signature_data = "AQAAAAMwRQIgU8d6waOIRVVydg_AXxediEZGkfFioUjd6FG3OxH2wUMCIQDpxzavJyxRlMwgNmD1Kw-iw_oP2egdshU9hrpxFHTRzQ"

        # step 1
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "u2f",
                                               "user": "******",
                                               "realm": self.realm1,
                                               "serial": serial
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200)
            result = json.loads(res.data.decode('utf8')).get("result")
            detail = json.loads(res.data.decode('utf8')).get("detail")
            self.assertEqual(result.get("status"), True)
            self.assertEqual(result.get("value"), True)

        # Init step 2
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "u2f",
                                               "serial": serial,
                                               "regdata": reg_data,
                                               "clientdata": client_data
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200)
            result = json.loads(res.data.decode('utf8')).get("result")
            detail = json.loads(res.data.decode('utf8')).get("detail")
            self.assertEqual(result.get("status"), True)
            self.assertEqual(result.get("value"), True)

        # create a challenge in the database
        db_challenge = Challenge(serial,
                                 transaction_id=transaction_id,
                                 challenge=challenge,
                                 data=None)
        db_challenge.save()

        set_policy(name="u2f01",
                   scope=SCOPE.AUTHZ,
                   action="{0!s}=issuer/.*Plugup.*/".format(U2FACTION.REQ))

        # Successful C/R authentication
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={
                                               "serial": serial,
                                               "pass": "",
                                               "transaction_id":
                                               transaction_id,
                                               "clientdata": client_data_auth,
                                               "signaturedata": signature_data
                                           }):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 403)
            result = json.loads(res.data.decode('utf8')).get("result")
            self.assertEqual(result.get("status"), False)
            self.assertEqual(result.get("error").get("code"), ERROR.POLICY)
            self.assertEqual(
                result.get("error").get("message"),
                u'The U2F device is not allowed to authenticate due to policy restriction.'
            )

        delete_policy("u2f01")
        remove_token(serial)
    def test_01_setup_eventhandlers(self):
        # This test create an HOTP token with C/R with a pre-event handler
        # and the user uses this HOTP token to directly login to /auth

        # Setup realm
        rid = save_resolver({
            "resolver": self.resolvername1,
            "type": "passwdresolver",
            "fileName": PWFILE
        })
        self.assertTrue(rid > 0, rid)

        (added, failed) = set_realm(self.realm1, [self.resolvername1])
        self.assertTrue(len(failed) == 0)
        self.assertTrue(len(added) == 1)

        set_default_realm(self.realm1)

        # set a policy to authenticate against privacyIDEA
        set_policy("piLogin",
                   scope=SCOPE.WEBUI,
                   action="{0!s}=privacyIDEA".format(ACTION.LOGINMODE))
        # set a policy to for otppin=userstore
        set_policy("otppin",
                   scope=SCOPE.AUTH,
                   action="{0!s}=userstore".format(ACTION.OTPPIN))
        # Set a policy to do C/R with HOTP tokens
        set_policy("crhotp",
                   scope=SCOPE.AUTH,
                   action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE))

        # Create an event handler, that creates HOTP token on /auth with default OTP key
        eid = set_event(
            "createtoken",
            event=["auth"],
            handlermodule="Token",
            action="enroll",
            position="pre",
            conditions={CONDITION.USER_TOKEN_NUMBER: 0},
            options={
                "tokentype": "hotp",
                "user": "******",
                "additional_params": {
                    'otpkey': self.otpkey,
                    # We need to set gekey=0, otherwise the Tokenhandler will
                    # generate a random otpkey
                    'genkey': 0
                }
            })
        # cleanup tokens
        remove_token(user=User("someuser", self.realm1))

        # user tries to log in with his userstore password and gets a transaction_id
        with self.app.test_request_context('/auth',
                                           method='POST',
                                           data={
                                               "username": "******",
                                               "password": "******"
                                           }):
            res = self.app.full_dispatch_request()
            self.assertEqual(401, res.status_code, res)
            result = res.json.get("result")
            self.assertFalse(result.get("status"), result)
            detail = res.json.get("detail")
            self.assertEqual("please enter otp: ", detail.get("message"))
            transaction_id = detail.get("transaction_id")

        # Check if the token was enrolled
        toks = get_tokens(user=User("someuser", self.realm1))
        self.assertEqual(len(toks), 1)
        self.assertEqual(toks[0].token.tokentype, "hotp")
        serial = toks[0].token.serial
        # Check if the correct otpkey was used
        hotptoken = toks[0]
        r = hotptoken.check_otp(self.valid_otp_values[1])
        self.assertTrue(r >= 0)

        # Now the user logs in with the second step of C/R with OTP value of new token
        with self.app.test_request_context('/auth',
                                           method='POST',
                                           data={
                                               "username": "******",
                                               "transaction_id":
                                               transaction_id,
                                               "password":
                                               self.valid_otp_values[2]
                                           }):
            res = self.app.full_dispatch_request()
            self.assertEqual(200, res.status_code, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status"))
            self.assertTrue(result.get("value"))

        # Check that there is still only one token
        toks = get_tokens(user=User("someuser", self.realm1))
        self.assertEqual(len(toks), 1)
        self.assertEqual(toks[0].token.tokentype, "hotp")
        self.assertEqual(serial, toks[0].token.serial)

        # cleanup
        delete_policy("piLogin")
        delete_policy("otppin")
        delete_policy("crhotp")
        delete_event(eid)
        remove_token(hotptoken.token.serial)
    def test_19_ui_get_menus(self):
        delete_all_policies()
        luser = {"username": "******", "role": "admin"}

        # Without policies, the admin gets all
        P = PolicyClass()
        menus = P.ui_get_main_menus(luser)
        self.assertTrue(MAIN_MENU.USERS in menus)
        self.assertTrue(MAIN_MENU.TOKENS in menus)
        self.assertTrue(MAIN_MENU.COMPONENTS in menus)
        self.assertTrue(MAIN_MENU.CONFIG in menus)
        self.assertTrue(MAIN_MENU.MACHINES in menus)

        # Admin has only right to enroll HOTP! :-)
        set_policy("pol1",
                   scope=SCOPE.ADMIN,
                   user="******",
                   action="enrollHOTP")
        P = PolicyClass()
        menus = P.ui_get_main_menus(luser)
        # Thus he can only see the token menu
        self.assertTrue(MAIN_MENU.USERS not in menus)
        self.assertTrue(MAIN_MENU.TOKENS in menus)
        self.assertTrue(MAIN_MENU.COMPONENTS not in menus)
        self.assertTrue(MAIN_MENU.CONFIG not in menus)
        self.assertTrue(MAIN_MENU.MACHINES not in menus)

        set_policy("pol2",
                   scope=SCOPE.ADMIN,
                   user="******",
                   action=ACTION.USERLIST)
        P = PolicyClass()
        menus = P.ui_get_main_menus(luser)
        # Thus he can only see the token menu
        self.assertTrue(MAIN_MENU.USERS in menus)
        self.assertTrue(MAIN_MENU.TOKENS in menus)
        self.assertTrue(MAIN_MENU.COMPONENTS not in menus)
        self.assertTrue(MAIN_MENU.CONFIG not in menus)
        self.assertTrue(MAIN_MENU.MACHINES not in menus)

        set_policy("pol3",
                   scope=SCOPE.ADMIN,
                   user="******",
                   action=ACTION.MACHINELIST)
        P = PolicyClass()
        menus = P.ui_get_main_menus(luser)
        # Thus he can only see the token menu
        self.assertTrue(MAIN_MENU.USERS in menus)
        self.assertTrue(MAIN_MENU.TOKENS in menus)
        self.assertTrue(MAIN_MENU.COMPONENTS not in menus)
        self.assertTrue(MAIN_MENU.CONFIG not in menus)
        self.assertTrue(MAIN_MENU.MACHINES in menus)

        set_policy("pol4",
                   scope=SCOPE.ADMIN,
                   user="******",
                   action=ACTION.SYSTEMDELETE)
        P = PolicyClass()
        menus = P.ui_get_main_menus(luser)
        # Thus he can only see the token menu
        self.assertTrue(MAIN_MENU.USERS in menus)
        self.assertTrue(MAIN_MENU.TOKENS in menus)
        self.assertTrue(MAIN_MENU.COMPONENTS not in menus)
        self.assertTrue(MAIN_MENU.CONFIG in menus)
        self.assertTrue(MAIN_MENU.MACHINES in menus)

        delete_all_policies()
    def test_08_get_webui_settings(self):
        # Test that a machine definition will return offline hashes
        self.setUp_user_realms()
        serial = "offline01"
        tokenobject = init_token({
            "serial": serial,
            "type": "hotp",
            "otpkey": "3132333435363738393031"
            "323334353637383930",
            "pin": "offline",
            "user": "******"
        })

        # Set the Machine and MachineToken
        resolver1 = save_resolver({
            "name": "reso1",
            "type": "hosts",
            "filename": HOSTSFILE
        })

        mt = attach_token(serial, "offline", hostname="gandalf")
        self.assertEqual(mt.token.serial, serial)
        self.assertEqual(mt.token.machine_list[0].machine_id, "192.168.0.1")

        # The request with an OTP value and a PIN of a user, who has not
        # token assigned
        builder = EnvironBuilder(method='POST', data={}, headers={})
        env = builder.get_environ()
        env["REMOTE_ADDR"] = "192.168.0.1"
        g.client_ip = env["REMOTE_ADDR"]
        req = Request(env)
        req.all_data = {"user": "******", "pass": "******"}

        res = {
            "jsonrpc": "2.0",
            "result": {
                "status": True,
                "value": {
                    "role": "user",
                    "username": "******"
                }
            },
            "version": "privacyIDEA test",
            "detail": {
                "serial": serial
            },
            "id": 1
        }
        resp = Response(json.dumps(res))

        new_response = get_webui_settings(req, resp)
        jresult = json.loads(new_response.data)
        self.assertEqual(
            jresult.get("result").get("value").get("token_wizard"), False)

        # Set a policy. User has not token, so "token_wizard" will be True
        set_policy(name="pol_wizard",
                   scope=SCOPE.WEBUI,
                   action=ACTION.TOKENWIZARD)
        g.policy_object = PolicyClass()
        new_response = get_webui_settings(req, resp)
        jresult = json.loads(new_response.data)
        self.assertEqual(
            jresult.get("result").get("value").get("token_wizard"), True)

        delete_policy("pol_wizard")
    def test_10_auth_items_ssh(self):
        # create an SSH token
        token_obj = init_token({"serial": self.serial2, "type": "sshkey",
                                "sshkey": SSHKEY})
        self.assertEqual(token_obj.type, "sshkey")

        # Attach the token to the machine "gandalf" with the application SSH
        r = attach_token(hostname="gandalf", serial=self.serial2,
                         application="ssh", options={"user": "******"})

        self.assertEqual(r.machine_id, "192.168.0.1")

        # fetch the auth_items for application SSH on machine gandalf
        with self.app.test_request_context(
                '/machine/authitem/ssh?hostname=gandalf',
                method='GET',
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result["status"], True)
            sshkey = result["value"].get("ssh")[0].get("sshkey")
            self.assertTrue(sshkey.startswith("ssh-rsa"), sshkey)

        # fetch the auth_items for user testuser
        with self.app.test_request_context(
                '/machine/authitem/ssh?hostname=gandalf&user=testuser',
                method='GET',
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result["status"], True)
            sshkey = result["value"].get("ssh")[0].get("sshkey")
            self.assertTrue(sshkey.startswith("ssh-rsa"), sshkey)

        # fetch auth_items for testuser, but with mangle policy
        # Remove everything that sounds like "SOMETHING\" in front of
        # the username
        set_policy(name="mangle1", scope=SCOPE.AUTH,
                   action="{0!s}=user/.*\\\\(.*)/\\1/".format(ACTION.MANGLE))
        with self.app.test_request_context(
                '/machine/authitem/ssh?hostname=gandalf&user=DOMAIN\\testuser',
                method='GET',
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result["status"], True)
            sshkey = result["value"].get("ssh")[0].get("sshkey")
            self.assertTrue(sshkey.startswith("ssh-rsa"), sshkey)
        delete_policy("mangle1")

        # Now that the policy is deleted, we will not get the auth_items
        # anymore, since the username is not mangled.
        with self.app.test_request_context(
                '/machine/authitem/ssh?hostname=gandalf&user=DOMAIN\\testuser',
                method='GET',
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result["status"], True)
            sshkeys = result["value"].get("ssh")
            # No user DOMAIN\\testuser and no SSH keys
            self.assertFalse(sshkeys)

        # fetch the auth_items on machine gandalf for all applications
        with self.app.test_request_context(
                '/machine/authitem?hostname=gandalf',
                method='GET',
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            sshkey = result["value"].get("ssh")[0].get("sshkey")
            self.assertTrue(sshkey.startswith("ssh-rsa"), sshkey)
    def test_13_passthru_priorities(self):
        user = User("cornelius", realm="r1")
        passw = "test"
        options = {}
        # remove all tokens of cornelius
        remove_token(user=user)

        # A user with no tokens will fail to authenticate
        self.assertEqual(get_tokens(user=user, count=True), 0)
        rv = auth_user_passthru(check_user_pass, user, passw, options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"),
                         "The user has no tokens assigned")

        # Now set a PASSTHRU policy to the userstore
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}=userstore".format(ACTION.PASSTHRU))
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}
        rv = auth_user_passthru(check_user_pass, user, passw,
                                options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against userstore due to 'pol1'")

        # Now add a PASSTHRU policy to a RADIUS config
        radiusmock.setdata(response=radiusmock.AccessAccept)
        set_policy(name="pol2",
                   scope=SCOPE.AUTH,
                   action="{0!s}=radiusconfig1".format(ACTION.PASSTHRU))
        r = add_radius("radiusconfig1", "1.2.3.4", "testing123",
                       dictionary=DICT_FILE)
        self.assertTrue(r > 0)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}

        # They will conflict, because they use the same priority
        with self.assertRaises(PolicyError):
            auth_user_passthru(check_user_pass, user, passw, options=options)

        # Lower pol1 priority
        set_policy(name="pol1", priority=2)

        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against RADIUS server radiusconfig1 due to 'pol2'")

        # Lower pol2 priority
        set_policy(name="pol2", priority=3)

        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against userstore due to 'pol1'")

        # Add old style priority
        set_policy(name="pol3",
                   scope=SCOPE.AUTH,
                   action=ACTION.PASSTHRU)

        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against userstore due to 'pol3'")
        set_policy(name="pol3", priority=2)

        # They will conflict, because they use the same priority
        with self.assertRaises(PolicyError):
            auth_user_passthru(check_user_pass, user, passw, options=options)

        delete_policy("pol3")

        # Now assign a token to the user. If the user has a token and the
        # passthru policy is set, the user must not be able to authenticate
        # with his userstore password.
        init_token({"serial": "PTHRU",
                    "type": "spass", "pin": "Hallo"},
                   user=user)
        rv = auth_user_passthru(check_user_pass, user, passw,
                                options=options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"), "wrong otp pin")

        remove_token("PTHRU")
        delete_policy("pol1")
        delete_policy("pol2")
    def test_12_authcache(self):
        password = "******"
        username = "******"
        realm = "myrealm"
        resolver = "reso001"

        r = save_resolver({"resolver": "reso001",
                           "type": "passwdresolver",
                           "fileName": "tests/testdata/passwords"})
        (added, failed) = set_realm("myrealm", ["reso001"])

        def fake_check_user_pass(user, passw, options=None):
            return True, {"message": "Fake Authentication"}

        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   realm=realm,
                   resolver=resolver,
                   action="{0!s}={1!s}".format(ACTION.AUTH_CACHE, "4h/5m"))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # This successfully authenticates against the authcache
        # We have an authentication, that is within the policy timeout
        AuthCache(username, realm, resolver, _hash_password(password),
                  first_auth=datetime.datetime.utcnow() - timedelta(hours=3),
                  last_auth=datetime.datetime.utcnow() - timedelta(minutes=1)).save()
        r = auth_cache(fake_check_user_pass, User("cornelius", "myrealm"),
                        password, options=options)
        self.assertTrue(r[0])
        self.assertEqual(r[1].get("message"), "Authenticated by AuthCache." )

        # We have an authentication, that is not read from the authcache,
        # since the authcache first_auth is too old.
        delete_from_cache(username, realm, resolver, password)
        AuthCache(username, realm, resolver, _hash_password(password),
                  first_auth=datetime.datetime.utcnow() - timedelta(hours=5),
                  last_auth=datetime.datetime.utcnow() - timedelta(
                      minutes=1)).save()
        r = auth_cache(fake_check_user_pass, User("cornelius", "myrealm"),
                       password, options=options)
        self.assertTrue(r[0])
        self.assertEqual(r[1].get("message"), "Fake Authentication")

        # We have an authentication, that is not read from authcache, since
        # the last_auth is too old = 10 minutes.
        delete_from_cache(username, realm, resolver, password)
        AuthCache(username, realm, resolver, _hash_password(password),
                  first_auth=datetime.datetime.utcnow() - timedelta(hours=1),
                  last_auth=datetime.datetime.utcnow() - timedelta(
                      minutes=10)).save()
        r = auth_cache(fake_check_user_pass, User("cornelius", "myrealm"),
                       password, options=options)
        self.assertTrue(r[0])
        self.assertEqual(r[1].get("message"), "Fake Authentication")

        # We have a policy, with no special last_auth
        delete_policy("pol1")
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   realm=realm,
                   resolver=resolver,
                   action="{0!s}={1!s}".format(ACTION.AUTH_CACHE, "4h"))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        delete_from_cache(username, realm, resolver, password)
        AuthCache(username, realm, resolver, _hash_password(password),
                  first_auth=datetime.datetime.utcnow() - timedelta(hours=2),
                  last_auth=datetime.datetime.utcnow() - timedelta(
                      hours=1)).save()
        r = auth_cache(fake_check_user_pass, User("cornelius", "myrealm"),
                       password, options=options)
        self.assertTrue(r[0])
        self.assertEqual(r[1].get("message"), "Authenticated by AuthCache.")

        # Clean up
        delete_policy("pol1")
        delete_realm("myrealm")
        delete_resolver("reso001")
    def test_16_passthru_assign(self):
        user = User("cornelius", realm="r1")
        passw = "{0!s}test".format(self.valid_otp_values[1])
        options = {}
        # remove all tokens of cornelius
        remove_token(user=user)

        # create unassigned tokens in realm r1
        init_token({
            "type": "hotp",
            "otpkey": "00" * 20,
            "serial": "TOKFAIL"
        },
                   tokenrealms=["r1"])
        init_token(
            {
                "type": "hotp",
                "otpkey": self.otpkey,
                "serial": "TOKMATCH"
            },
            tokenrealms=["r1"])

        # A user with no tokens will fail to authenticate
        self.assertEqual(get_tokens(user=user, count=True), 0)
        rv = auth_user_passthru(check_user_pass, user, passw, options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"),
                         "The user has no tokens assigned")

        # Now add a PASSTHRU policy to a RADIUS config
        radiusmock.setdata(success=True)
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}=radiusconfig1".format(ACTION.PASSTHRU))
        r = add_radius("radiusconfig1",
                       "1.2.3.4",
                       "testing123",
                       dictionary=DICT_FILE)
        self.assertTrue(r > 0)
        set_policy(name="pol2",
                   scope=SCOPE.AUTH,
                   action="{0!s}=6:pin:1234".format(ACTION.PASSTHRU_ASSIGN))

        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}

        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertTrue(u"against RADIUS server radiusconfig1 due to 'pol1'" in
                        rv[1].get("message"))
        self.assertTrue(u"autoassigned TOKMATCH" in rv[1].get("message"))

        # Check if the token is assigned and can authenticate
        r = check_user_pass(User("cornelius", "r1"),
                            "test{0!s}".format(self.valid_otp_values[2]))
        self.assertTrue(r[0])
        self.assertEqual(r[1].get("serial"), "TOKMATCH")

        remove_token("TOKFAIL")
        remove_token("TOKMATCH")
        delete_policy("pol1")
        delete_policy("pol2")
    def test_14_otppin_priority(self):
        my_user = User("cornelius", realm="r1")
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}={1!s}".format(ACTION.OTPPIN,
                                               ACTIONVALUE.NONE),
                   priority=2)
        set_policy(name="pol2",
                   scope=SCOPE.AUTH,
                   action="{0!s}={1!s}".format(ACTION.OTPPIN,
                                               ACTIONVALUE.TOKENPIN),
                   priority=2)
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # error because of conflicting policies
        with self.assertRaises(PolicyError):
            auth_otppin(self.fake_check_otp,
                        None,
                        "",
                        options=options,
                        user=my_user)

        # lower pol2 priority
        set_policy(name="pol2", priority=3)
        g.policy_object.reload_from_db()

        # NONE with empty PIN -> success
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "",
                        options=options,
                        user=my_user)
        self.assertTrue(r)
        # NONE with empty PIN -> success, even if the authentication is done
        # for a serial and not a user, since the policy holds for all realms
        token = init_token({"type": "HOTP", "otpkey": "1234"})
        r = auth_otppin(self.fake_check_otp,
                        token,
                        "",
                        options=options,
                        user=None)
        self.assertTrue(r)

        # NONE with some pin -> fail
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "some pin",
                        options=options,
                        user=my_user)
        self.assertFalse(r)

        # increase pol2 priority
        set_policy(name="pol2", priority=1)
        g.policy_object.reload_from_db()

        r = auth_otppin(self.fake_check_otp,
                        None,
                        "FAKE",
                        options=options,
                        user=my_user)
        self.assertTrue(r)
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "Wrong Pin",
                        options=options,
                        user=my_user)
        self.assertFalse(r)
        delete_policy("pol1")
        delete_policy("pol2")
    def test_01_otppin(self):
        my_user = User("cornelius", realm="r1")
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}={1!s}".format(ACTION.OTPPIN,
                                               ACTIONVALUE.NONE))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # NONE with empty PIN -> success
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "",
                        options=options,
                        user=my_user)
        self.assertTrue(r)
        # NONE with empty PIN -> success, even if the authentication is done
        # for a serial and not a user, since the policy holds for all realms
        token = init_token({"type": "HOTP", "otpkey": "1234"})
        r = auth_otppin(self.fake_check_otp,
                        token,
                        "",
                        options=options,
                        user=None)
        self.assertTrue(r)

        # NONE with some pin -> fail
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "some pin",
                        options=options,
                        user=my_user)
        self.assertFalse(r)

        delete_policy("pol1")
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}={1!s}".format(ACTION.OTPPIN,
                                               ACTIONVALUE.TOKENPIN))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        r = auth_otppin(self.fake_check_otp,
                        None,
                        "FAKE",
                        options=options,
                        user=my_user)
        self.assertTrue(r)
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "Wrong Pin",
                        options=options,
                        user=my_user)
        self.assertFalse(r)
        delete_policy("pol1")
Exemple #43
0
    def test_06_api_auth(self):
        self.setUp_user_realms()

        # get enrolled push token
        toks = get_tokens(tokentype="push")
        self.assertEqual(len(toks), 1)
        tokenobj = toks[0]

        # set PIN
        tokenobj.set_pin("pushpin")
        tokenobj.add_user(User("cornelius", self.realm1))

        # Set a loginmode policy
        set_policy("webui", scope=SCOPE.WEBUI,
                   action="{}={}".format(ACTION.LOGINMODE, LOGINMODE.PRIVACYIDEA))
        # Set a PUSH_WAIT action which will be ignored by privacyIDEA
        set_policy("push1", scope=SCOPE.AUTH, action="{0!s}=20".format(PUSH_ACTION.WAIT))
        with mock.patch('privacyidea.lib.smsprovider.FirebaseProvider.ServiceAccountCredentials') as mySA:
            # alternative: side_effect instead of return_value
            mySA.from_json_keyfile_name.return_value = myCredentials(myAccessTokenInfo("my_bearer_token"))

            # add responses, to simulate the communication to firebase
            responses.add(responses.POST, 'https://fcm.googleapis.com/v1/projects/test-123456/messages:send',
                          body="""{}""",
                          content_type="application/json")

            with self.app.test_request_context('/auth',
                                               method='POST',
                                               data={"username": "******",
                                                     "realm": self.realm1,
                                                     # this will be overwritted by pushtoken_disable_wait
                                                     PUSH_ACTION.WAIT: "10",
                                                     "password": "******"}):
                res = self.app.full_dispatch_request()
                self.assertEqual(res.status_code, 401)
                jsonresp = res.json
                self.assertFalse(jsonresp.get("result").get("value"))
                self.assertFalse(jsonresp.get("result").get("status"))
                self.assertEqual(jsonresp.get("detail").get("serial"), tokenobj.token.serial)
                self.assertIn("transaction_id", jsonresp.get("detail"))
                transaction_id = jsonresp.get("detail").get("transaction_id")
                self.assertEqual(jsonresp.get("detail").get("message"), DEFAULT_CHALLENGE_TEXT)

        # Get the challenge from the database
        challengeobject_list = get_challenges(serial=tokenobj.token.serial,
                                              transaction_id=transaction_id)
        challenge = challengeobject_list[0].challenge
        # This is what the smartphone answers.
        # create the signature:
        sign_data = "{0!s}|{1!s}".format(challenge, tokenobj.token.serial)
        signature = b32encode_and_unicode(
            self.smartphone_private_key.sign(sign_data.encode("utf-8"),
                                             padding.PKCS1v15(),
                                             hashes.SHA256()))

        # We still cannot log in
        with self.app.test_request_context('/auth',
                                           method='POST',
                                           data={"username": "******",
                                                 "realm": self.realm1,
                                                 "pass": "",
                                                 "transaction_id": transaction_id}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 401)
            self.assertFalse(res.json['result']['status'])

        # Answer the challenge
        with self.app.test_request_context('/ttype/push',
                                           method='POST',
                                           data={"serial": tokenobj.token.serial,
                                                 "nonce": challenge,
                                                 "signature": signature}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            self.assertTrue(res.json['result']['status'])
            self.assertTrue(res.json['result']['value'])

        # We can now log in
        with self.app.test_request_context('/auth',
                                           method='POST',
                                           data={"username": "******",
                                                 "realm": self.realm1,
                                                 "pass": "",
                                                 "transaction_id": transaction_id}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200)
            self.assertTrue(res.json['result']['status'])

        delete_policy("push1")
        delete_policy("webui")
    def test_04_get_user_audit_log(self):
        # Test that the user only sees audit log entries with his own data
        self.setUp_user_realms()
        # prepare some log entries for the normal user to try to fetch
        Audit(action="enroll",
              success=1,
              user="******",
              administrator=None,
              resolver="resolver1",
              realm=self.realm1a).save()
        Audit(action="enroll",
              success=1,
              user="******",
              administrator=None,
              resolver="resolver1",
              realm=self.realm1a).save()
        Audit(action="enroll",
              success=1,
              user="******",
              administrator=None,
              resolver="resolver1",
              realm=self.realm2b).save()
        Audit(action="enroll",
              success=1,
              user="******",
              administrator=None,
              resolver="resolver1",
              realm=self.realm2b).save()
        Audit(action="enroll",
              success=1,
              user="******",
              administrator=None,
              resolver="resolver1",
              realm=self.realm2b).save()

        # set policy: normal users in realm1a are allowed to view audit log
        set_policy("audit01",
                   scope=SCOPE.USER,
                   action=ACTION.AUDIT,
                   realm=self.realm1a)

        user_authorization = None
        with self.app.test_request_context('/auth',
                                           method='POST',
                                           data={
                                               'username':
                                               '******'.format(
                                                   self.realm1a),
                                               'password':
                                               '******'
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            value = json_response.get("result").get("value")
            self.assertTrue("auditlog" in value.get("rights"))
            user_authorization = value.get("token")

        # check, that the normal user only sees his own entries
        with self.app.test_request_context(
                '/audit/',
                method='GET',
                data={
                    "action": "**",
                    "action_detail": "**",
                    "administrator": "**",
                    "client": "**",
                    "date": "**",
                    "info": "**",
                    "page": "1",
                    "page_size": "10",
                    "policies": "**",
                    "privacyidea_server": "**",
                    "realm": "**",
                    "resolver": "**",
                    "serial": "**",
                    "sortorder": "desc",
                    "success": "**",
                    "tokentype": "**",
                    "user": "******"
                },
                headers={'Authorization': user_authorization}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            self.assertTrue(json_response.get("result").get("status"), res)
            # We now have 3 entries, as we added one by the search in line #43
            count = json_response.get("result").get("value").get("count")
            auditdata = json_response.get("result").get("value").get(
                "auditdata")
            self.assertGreaterEqual(count, 3)
            # All entries are in realm1A!
            for ad in auditdata:
                self.assertEqual(ad.get("realm"), self.realm1a)

        # try to explicitly query another realm
        with self.app.test_request_context(
                '/audit/',
                method='GET',
                data={
                    "action": "**",
                    "action_detail": "**",
                    "administrator": "**",
                    "client": "**",
                    "date": "**",
                    "info": "**",
                    "page": "1",
                    "page_size": "10",
                    "policies": "**",
                    "privacyidea_server": "**",
                    "realm": self.realm2b,
                    "resolver": "**",
                    "serial": "**",
                    "sortorder": "desc",
                    "success": "**",
                    "tokentype": "**",
                    "user": "******"
                },
                headers={'Authorization': user_authorization}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            self.assertTrue(json_response.get("result").get("status"), res)
            # The normal user can not fetch audit entries, that do not belong to him!
            count = json_response.get("result").get("value").get("count")
            self.assertGreaterEqual(count, 0)

        # delete policy
        delete_policy("audit01")
Exemple #45
0
    def test_01_check_token_action(self):
        g.logged_in_user = {"username": "******", "role": "admin"}
        builder = EnvironBuilder(method='POST',
                                 data={'serial': "OATH123456"},
                                 headers={})
        env = builder.get_environ()
        # Set the remote address so that we can filter for it
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        req.all_data = {"serial": "SomeSerial"}

        # Set a policy, that does allow the action
        set_policy(name="pol1",
                   scope=SCOPE.ADMIN,
                   action="enable",
                   client="10.0.0.0/8")
        g.policy_object = PolicyClass()

        # Action enable is cool
        r = check_base_action(request=req, action="enable")
        self.assertTrue(r)

        # Another action - like "disable" - is not allowed
        # An exception is
        self.assertRaises(PolicyError, check_base_action, req, "disable")

        # Action delete is not allowed
        self.assertRaises(PolicyError, check_base_action, req, "delete")

        # check action with a token realm
        set_policy(name="pol1",
                   scope=SCOPE.ADMIN,
                   action="enable",
                   client="10.0.0.0/8",
                   realm="realm1")
        set_policy(name="pol2",
                   scope=SCOPE.ADMIN,
                   action="*",
                   client="10.0.0.0/8",
                   realm="realm2")
        g.policy_object = PolicyClass()
        # set a polrealm1 and a polrealm2
        # setup realm1
        self.setUp_user_realms()
        # setup realm2
        self.setUp_user_realm2()
        tokenobject = init_token({
            "serial": "POL001",
            "type": "hotp",
            "otpkey": "1234567890123456"
        })
        r = set_realms("POL001", [self.realm1])

        tokenobject = init_token({
            "serial": "POL002",
            "type": "hotp",
            "otpkey": "1234567890123456"
        })
        r = set_realms("POL002", [self.realm2])

        # Token in realm1 can not be deleted
        req.all_data = {"serial": "POL001"}
        self.assertRaises(PolicyError, check_base_action, req, "delete")
        # while token in realm2 can be deleted
        req.all_data = {"serial": "POL002"}
        r = check_base_action(req, action="delete")
        self.assertTrue(r)

        # A normal user can "disable", since no user policies are defined.
        g.logged_in_user = {"username": "******", "role": "user"}
        r = check_base_action(req, "disable")
        self.assertTrue(r)
        delete_policy("pol1")
        delete_policy("pol2")
        remove_token("POL001")
        remove_token("POL002")
Exemple #46
0
    def test_03b_api_authenticate_client(self):
        # Test the /validate/check endpoints without the smartphone endpoint /ttype/push
        self.setUp_user_realms()

        # get enrolled push token
        toks = get_tokens(tokentype="push")
        self.assertEqual(len(toks), 1)
        tokenobj = toks[0]

        # set PIN
        tokenobj.set_pin("pushpin")
        tokenobj.add_user(User("cornelius", self.realm1))

        # We mock the ServiceAccountCredentials, since we can not directly contact the Google API
        with mock.patch('privacyidea.lib.smsprovider.FirebaseProvider.ServiceAccountCredentials') as mySA:
            # alternative: side_effect instead of return_value
            mySA.from_json_keyfile_name.return_value = myCredentials(myAccessTokenInfo("my_bearer_token"))

            # add responses, to simulate the communication to firebase
            responses.add(responses.POST, 'https://fcm.googleapis.com/v1/projects/test-123456/messages:send',
                          body="""{}""",
                          content_type="application/json")

            # Send the first authentication request to trigger the challenge
            with self.app.test_request_context('/validate/check',
                                               method='POST',
                                               data={"user": "******",
                                                     "realm": self.realm1,
                                                     "pass": "******"}):
                res = self.app.full_dispatch_request()
                self.assertTrue(res.status_code == 200, res)
                jsonresp = res.json
                self.assertFalse(jsonresp.get("result").get("value"))
                self.assertTrue(jsonresp.get("result").get("status"))
                self.assertEqual(jsonresp.get("detail").get("serial"), tokenobj.token.serial)
                self.assertTrue("transaction_id" in jsonresp.get("detail"))
                transaction_id = jsonresp.get("detail").get("transaction_id")
                self.assertEqual(jsonresp.get("detail").get("message"), DEFAULT_CHALLENGE_TEXT)

            # Our ServiceAccountCredentials mock has not been called because we use a cached token
            self.assertEqual(len(mySA.from_json_keyfile_name.mock_calls), 0)
            self.assertIn(FIREBASE_FILE, get_app_local_store()["firebase_token"])

        # The mobile device has not communicated with the backend, yet.
        # The user is not authenticated!
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={"user": "******",
                                                 "realm": self.realm1,
                                                 "pass": "",
                                                 "transaction_id": transaction_id}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            jsonresp = res.json
            # Result-Value is false, the user has not answered the challenge, yet
            self.assertFalse(jsonresp.get("result").get("value"))

        # Now the smartphone communicates with the backend and the challenge in the database table
        # is marked as answered successfully.
        challengeobject_list = get_challenges(serial=tokenobj.token.serial,
                                              transaction_id=transaction_id)
        challengeobject_list[0].set_otp_status(True)

        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={"user": "******",
                                                 "realm": self.realm1,
                                                 "pass": "",
                                                 "state": transaction_id}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            jsonresp = res.json
            # Result-Value is True, since the challenge is marked resolved in the DB
        self.assertTrue(jsonresp.get("result").get("value"))

        # We mock the ServiceAccountCredentials, since we can not directly contact the Google API
        # Do single shot auth with waiting
        # Also mock time.time to be 4000 seconds in the future (exceeding the validity of myAccessTokenInfo),
        # so that we fetch a new auth token
        with mock.patch('privacyidea.lib.smsprovider.FirebaseProvider.time') as mock_time:
            mock_time.time.return_value = time.time() + 4000

            with mock.patch('privacyidea.lib.smsprovider.FirebaseProvider.ServiceAccountCredentials') as mySA:
                # alternative: side_effect instead of return_value
                mySA.from_json_keyfile_name.return_value = myCredentials(myAccessTokenInfo("my_new_bearer_token"))

                # add responses, to simulate the communication to firebase
                responses.add(responses.POST, 'https://fcm.googleapis.com/v1/projects/test-123456/messages:send',
                              body="""{}""",
                              content_type="application/json")

                # In two seconds we need to run an update on the challenge table.
                Timer(2, self.mark_challenge_as_accepted).start()

                set_policy("push1", scope=SCOPE.AUTH, action="{0!s}=20".format(PUSH_ACTION.WAIT))
                # Send the first authentication request to trigger the challenge
                with self.app.test_request_context('/validate/check',
                                                   method='POST',
                                                   data={"user": "******",
                                                         "realm": self.realm1,
                                                         "pass": "******"}):
                    res = self.app.full_dispatch_request()
                    self.assertTrue(res.status_code == 200, res)
                    jsonresp = res.json
                    # We successfully authenticated! YEAH!
                    self.assertTrue(jsonresp.get("result").get("value"))
                    self.assertTrue(jsonresp.get("result").get("status"))
                    self.assertEqual(jsonresp.get("detail").get("serial"), tokenobj.token.serial)
                delete_policy("push1")

            # Our ServiceAccountCredentials mock has been called once because we fetched a new token
            self.assertEqual(len(mySA.from_json_keyfile_name.mock_calls), 1)
            self.assertIn(FIREBASE_FILE, get_app_local_store()["firebase_token"])
            self.assertEqual(get_app_local_store()["firebase_token"][FIREBASE_FILE].access_token,
                             "my_new_bearer_token")

        # Authentication fails, if the push notification is not accepted within the configured time
        with mock.patch('privacyidea.lib.smsprovider.FirebaseProvider.ServiceAccountCredentials') as mySA:
            # alternative: side_effect instead of return_value
            mySA.from_json_keyfile_name.return_value = myCredentials(myAccessTokenInfo("my_bearer_token"))

            # add responses, to simulate the communication to firebase
            responses.add(responses.POST, 'https://fcm.googleapis.com/v1/projects/test-123456/messages:send',
                          body="""{}""",
                          content_type="application/json")

            set_policy("push1", scope=SCOPE.AUTH, action="{0!s}=1".format(PUSH_ACTION.WAIT))
            # Send the first authentication request to trigger the challenge
            with self.app.test_request_context('/validate/check',
                                               method='POST',
                                               data={"user": "******",
                                                     "realm": self.realm1,
                                                     "pass": "******"}):
                res = self.app.full_dispatch_request()
                self.assertTrue(res.status_code == 200, res)
                jsonresp = res.json
                # We fail to authenticate! Oh No!
                self.assertFalse(jsonresp.get("result").get("value"))
                self.assertTrue(jsonresp.get("result").get("status"))
                self.assertEqual(jsonresp.get("detail").get("serial"), tokenobj.token.serial)
            delete_policy("push1")
Exemple #47
0
    def test_02_update_policies(self):
        p = set_policy(name="pol1",
                       action="read",
                       scope="system",
                       realm="*",
                       resolver="*",
                       user="******",
                       client="0.0.0.0/0",
                       active="False")
        self.assertTrue(p > 0)

        p = set_policy(name="pol2",
                       action="tokentype=HOTP",
                       scope=SCOPE.AUTHZ,
                       realm="*")
        self.assertTrue(p > 0)

        p = set_policy(name="pol2a",
                       action="tokentype=TOTP",
                       scope=SCOPE.AUTHZ,
                       realm="realm2")
        self.assertTrue(p > 0)

        p = set_policy(name="pol3",
                       action="serial=OATH",
                       scope=SCOPE.AUTHZ,
                       realm="realm1",
                       resolver="resolver1")
        self.assertTrue(p > 0)

        p = set_policy(name="pol4",
                       action="enroll, init, disable , enable",
                       scope="admin",
                       realm="realm2",
                       user="******")
        self.assertTrue(p > 0)

        # enable and disable policies
        policies = PolicyClass().get_policies(active=False)
        num_old = len(policies)
        p = enable_policy("pol4", False)
        policies = PolicyClass().get_policies(active=False)
        self.assertTrue(num_old + 1 == len(policies), (num_old, len(policies)))
        p = enable_policy("pol4", True)
        policies = PolicyClass().get_policies(active=False)
        self.assertTrue(num_old == len(policies), len(policies))

        # find inactive policies
        P = PolicyClass()
        policies = P.get_policies(active=False)
        self.assertTrue(len(policies) == 1, len(policies))
        self.assertTrue(policies[0].get("name") == "pol1")

        # find policies action tokentype
        policies = P.get_policies(action="tokentype")
        self.assertTrue(len(policies) == 2, policies)
        # find policies action serial
        policies = P.get_policies(action="serial")
        self.assertTrue(len(policies) == 1, policies)
        # find policies with scope authorization
        policies = P.get_policies(scope=SCOPE.AUTHZ)
        self.assertTrue(len(policies) == 3, policies)
        # find policies authorization and realm2
        policies = P.get_policies(action="tokentype", scope=SCOPE.AUTHZ)
        self.assertTrue(len(policies) == 2, policies)
        # find policies with user admin
        policies = P.get_policies(scope="admin", user="******")
        self.assertTrue(len(policies) == 1, "%s" % len(policies))
        # find policies with resolver2 and authorization. THe result should
        # be pol2 and pol2a
        policies = P.get_policies(resolver="resolver2", scope=SCOPE.AUTHZ)
        self.assertTrue(len(policies) == 2, policies)

        # find policies with realm1 and authorization. We also include the
        # "*" into the result list. We find pol2 and pol3
        policies = P.get_policies(realm="realm1", scope=SCOPE.AUTHZ)
        self.assertTrue(len(policies) == 2, policies)

        # find policies with resolver1 and authorization.
        # All other authorization policies will also match, since they either
        # user * or
        # have no destinct information about resolvers
        policies = P.get_policies(resolver="resolver1", scope=SCOPE.AUTHZ)
        self.assertTrue(len(policies) == 3, policies)
Exemple #48
0
    def test_02_api_enroll(self):
        self.authenticate()

        # Failed enrollment due to missing policy
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={"type": "push",
                                                 "genkey": 1},
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertNotEqual(res.status_code,  200)
            error = res.json.get("result").get("error")
            self.assertEqual(error.get("message"), "Missing enrollment policy for push token: push_firebase_configuration")
            self.assertEqual(error.get("code"), 303)

        r = set_smsgateway(self.firebase_config_name, u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB",
                           {FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push",
                            FIREBASE_CONFIG.TTL: 10,
                            FIREBASE_CONFIG.API_KEY: "1",
                            FIREBASE_CONFIG.APP_ID: "2",
                            FIREBASE_CONFIG.PROJECT_NUMBER: "3",
                            FIREBASE_CONFIG.PROJECT_ID: "test-123456",
                            FIREBASE_CONFIG.JSON_CONFIG: FIREBASE_FILE})
        self.assertTrue(r > 0)
        set_policy("push1", scope=SCOPE.ENROLL,
                   action="{0!s}={1!s}".format(PUSH_ACTION.FIREBASE_CONFIG,
                                               self.firebase_config_name))

        # 1st step
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={"type": "push",
                                                 "genkey": 1},
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code,  200)
            detail = res.json.get("detail")
            serial = detail.get("serial")
            self.assertEqual(detail.get("rollout_state"), "clientwait")
            self.assertTrue("pushurl" in detail)
            # check that the new URL contains the serial number
            self.assertTrue("&serial=PIPU" in detail.get("pushurl").get("value"))
            self.assertTrue("appid=" in detail.get("pushurl").get("value"))
            self.assertTrue("appidios=" in detail.get("pushurl").get("value"))
            self.assertTrue("apikeyios=" in detail.get("pushurl").get("value"))
            self.assertFalse("otpkey" in detail)
            enrollment_credential = detail.get("enrollment_credential")

        # 2nd step. Failing with wrong serial number
        with self.app.test_request_context('/ttype/push',
                                           method='POST',
                                           data={"serial": "wrongserial",
                                                 "pubkey": self.smartphone_public_key_pem_urlsafe,
                                                 "fbtoken": "firebaseT"}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 404, res)
            status = res.json.get("result").get("status")
            self.assertFalse(status)
            error = res.json.get("result").get("error")
            self.assertEqual(error.get("message"),
                             "No token with this serial number in the rollout state 'clientwait'.")

        # 2nd step. Fails with missing enrollment credential
        with self.app.test_request_context('/ttype/push',
                                           method='POST',
                                           data={"serial": serial,
                                                 "pubkey": self.smartphone_public_key_pem_urlsafe,
                                                 "fbtoken": "firebaseT",
                                                 "enrollment_credential": "WRonG"}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 400, res)
            status = res.json.get("result").get("status")
            self.assertFalse(status)
            error = res.json.get("result").get("error")
            self.assertEqual(error.get("message"),
                             "ERR905: Invalid enrollment credential. You are not authorized to finalize this token.")

        # 2nd step: as performed by the smartphone
        with self.app.test_request_context('/ttype/push',
                                           method='POST',
                                           data={"enrollment_credential": enrollment_credential,
                                                 "serial": serial,
                                                 "pubkey": self.smartphone_public_key_pem_urlsafe,
                                                 "fbtoken": "firebaseT"}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            detail = res.json.get("detail")
            # still the same serial number
            self.assertEqual(serial, detail.get("serial"))
            self.assertEqual(detail.get("rollout_state"), "enrolled")
            # Now the smartphone gets a public key from the server
            augmented_pubkey = "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----\n".format(
                detail.get("public_key"))
            parsed_server_pubkey = serialization.load_pem_public_key(
                to_bytes(augmented_pubkey),
                default_backend())
            self.assertIsInstance(parsed_server_pubkey, RSAPublicKey)
            pubkey = detail.get("public_key")

            # Now check, what is in the token in the database
            toks = get_tokens(serial=serial)
            self.assertEqual(len(toks), 1)
            token_obj = toks[0]
            self.assertEqual(token_obj.token.rollout_state, u"enrolled")
            self.assertTrue(token_obj.token.active)
            tokeninfo = token_obj.get_tokeninfo()
            self.assertEqual(tokeninfo.get("public_key_smartphone"), self.smartphone_public_key_pem_urlsafe)
            self.assertEqual(tokeninfo.get("firebase_token"), u"firebaseT")
            self.assertEqual(tokeninfo.get("public_key_server").strip().strip("-BEGIN END RSA PUBLIC KEY-").strip(), pubkey)
            # The token should also contain the firebase config
            self.assertEqual(tokeninfo.get(PUSH_ACTION.FIREBASE_CONFIG), self.firebase_config_name)
    def test_21_check_all_resolver(self):
        # check_all_resolver allows to find a policy for a secondary user
        # resolver.
        # We create one realm "realm1" with the resolvers
        # reso1 (prio 1)
        # reso2 (prio 2)
        # reso3 (prio 3)
        # A user user@realm1 will be identified as user.reso1@realm1.
        # But we will also match policies for reso2.

        # no realm and resolver
        r = get_realms()
        self.assertEqual(r, {})

        r = get_resolver_list()
        self.assertEqual(r, {})

        # create user realm
        for reso in ["reso1", "resoX", "resoA"]:
            rid = save_resolver({
                "resolver": reso,
                "type": "passwdresolver",
                "fileName": PWFILE
            })
            self.assertTrue(rid > 0, rid)

        # create a realm with reso1 being the resolver with the highest priority
        (added, failed) = set_realm("realm1", ["reso1", "resoX", "resoA"],
                                    priority={
                                        "reso1": 1,
                                        "resoX": 2,
                                        "resoA": 3
                                    })
        self.assertTrue(len(failed) == 0)
        self.assertTrue(len(added) == 3)

        user = User(login="******", realm="realm1")
        # The user, that is created, is cornelius.reso1@realm1
        user_str = "{0!s}".format(user)
        self.assertEqual(user_str, "<cornelius.reso1@realm1>")
        # But the user "cornelius" is also contained in other resolves in
        # this realm
        r = user.get_ordererd_resolvers()
        self.assertEqual(r, ["reso1", "resoX", "resoA"])
        self.assertFalse(user.is_empty())
        self.assertTrue(User().is_empty())

        # define a policy with the wrong resolver
        p = set_policy(name="checkAll",
                       scope=SCOPE.AUTHZ,
                       realm="realm1",
                       resolver="resoX",
                       action="{0}=totp".format(ACTION.TOKENTYPE))
        self.assertTrue(p > 0)
        p = set_policy(name="catchAll",
                       scope=SCOPE.AUTHZ,
                       realm="realm1",
                       action="{0}=totp".format(ACTION.TOKENTYPE))
        self.assertTrue(p > 0)
        P = PolicyClass()
        pols = P.get_policies(scope=SCOPE.AUTHZ,
                              realm=user.realm,
                              resolver=user.resolver,
                              user=user.login)
        self.assertEqual(len(pols), 1)

        # Now we change the policy, so that it uses check_all_resolver, i.e.
        p = set_policy(name="checkAll",
                       scope=SCOPE.AUTHZ,
                       realm="realm1",
                       resolver="resoX",
                       check_all_resolvers=True,
                       action="{0}=totp".format(ACTION.TOKENTYPE))
        self.assertTrue(p > 0)
        P = PolicyClass()
        pols = P.get_policies(scope=SCOPE.AUTHZ,
                              realm=user.realm,
                              resolver=user.resolver,
                              user=user.login)
        self.assertEqual(len(pols), 2)

        # delete policy
        delete_policy("checkAll")
        delete_policy("catchAll")
        # delete resolvers and realm
        delete_realm("realm1")
        for reso in ["reso1", "resoX", "resoA"]:
            rid = delete_resolver(reso)
            self.assertTrue(rid > 0, rid)
Exemple #50
0
    def test_05_autoassign_userstore(self):
        # init a token, that does has no user
        self.setUp_user_realms()
        tokenobject = init_token(
            {
                "serial": "UASSIGN2",
                "type": "hotp",
                "otpkey": "3132333435363738393031"
                "323334353637383930"
            },
            tokenrealms=[self.realm1])
        user_obj = User("autoassignuser", self.realm1)
        # unassign all tokens from the user autoassignuser
        try:
            unassign_token(None, user=user_obj)
        except Exception:
            print("no need to unassign token")

        # The request with an OTP value and a PIN of a user, who has not
        # token assigned
        builder = EnvironBuilder(method='POST', data={}, headers={})
        env = builder.get_environ()
        env["REMOTE_ADDR"] = "10.0.0.1"
        req = Request(env)
        req.all_data = {
            "user": "******",
            "realm": self.realm1,
            "pass": "******"
        }
        # The response with a failed request
        res = {
            "jsonrpc": "2.0",
            "result": {
                "status": True,
                "value": False
            },
            "version": "privacyIDEA test",
            "id": 1
        }
        resp = Response(json.dumps(res))

        # Set the autoassign policy
        # to "userstore"
        set_policy(name="pol2",
                   scope=SCOPE.ENROLL,
                   action="%s=%s" %
                   (ACTION.AUTOASSIGN, AUTOASSIGNVALUE.USERSTORE),
                   client="10.0.0.0/8")
        g.policy_object = PolicyClass()

        new_response = autoassign(req, resp)
        jresult = json.loads(new_response.data)
        self.assertEqual(jresult.get("result").get("value"), True)
        self.assertEqual(jresult.get("detail").get("serial"), "UASSIGN2")

        # authenticate with 287082 a second time will fail
        res, dict = check_user_pass(User("autoassignuser", self.realm1),
                                    "password287082")
        self.assertFalse(res)

        # authenticate with the next OTP 359152 will succeed
        res, dict = check_user_pass(User("autoassignuser", self.realm1),
                                    "password359152")
        self.assertTrue(res)

        delete_policy("pol2")
    def test_15_ui_tokentypes(self):
        P = PolicyClass()
        logged_in_user = {
            "username": "******",
            "role": "admin",
            "realm": "realm1"
        }
        # Without policies, the admin gets all
        tt = P.ui_get_enroll_tokentypes("127.0.0.1", logged_in_user)
        self.assertTrue("hotp" in tt)
        self.assertTrue("totp" in tt)
        self.assertTrue("motp" in tt)
        self.assertTrue("sms" in tt)
        self.assertTrue("spass" in tt)
        self.assertTrue("sshkey" in tt)
        self.assertTrue("email" in tt)
        self.assertTrue("certificate" in tt)
        self.assertTrue("yubico" in tt)
        self.assertTrue("yubikey" in tt)
        self.assertTrue("radius" in tt)

        # An admin may only enroll Yubikeys
        set_policy(name="tokenEnroll",
                   scope=SCOPE.ADMIN,
                   action="enrollYUBIKEY")
        P = PolicyClass()

        tt = P.ui_get_enroll_tokentypes("127.0.0.1", logged_in_user)
        self.assertFalse("hotp" in tt)
        self.assertFalse("totp" in tt)
        self.assertFalse("motp" in tt)
        self.assertFalse("sms" in tt)
        self.assertFalse("spass" in tt)
        self.assertFalse("sshkey" in tt)
        self.assertFalse("email" in tt)
        self.assertFalse("certificate" in tt)
        self.assertFalse("yubico" in tt)
        self.assertTrue("yubikey" in tt)
        self.assertFalse("radius" in tt)

        # A user may enroll nothing
        set_policy(name="someUserAction", scope=SCOPE.USER, action="disable")
        P = PolicyClass()
        tt = P.ui_get_enroll_tokentypes("127.0.0.1", {
            "username": "******",
            "realm": "realm",
            "role": "user"
        })
        self.assertEqual(len(tt), 0)
        delete_policy("tokenEnroll")

        # Two admins:
        # adminA is allowed to enroll tokens in all realms
        # adminB is allowed to enroll tokens only in realmB

        set_policy(name="polAdminA",
                   scope=SCOPE.ADMIN,
                   user="******",
                   action="enrollHOTP, enrollTOTP")
        set_policy(name="polAdminB",
                   scope=SCOPE.ADMIN,
                   user="******",
                   realm="realmB",
                   action="enrollHOTP")
        P = PolicyClass()
        # realm is empty, since in case of an admin, this is the admin realm
        rights = P.ui_get_enroll_tokentypes(None, {
            "role": SCOPE.ADMIN,
            "realm": None,
            "username": "******"
        })
        self.assertTrue("hotp" in rights)
        self.assertTrue("totp" in rights)
        rights = P.ui_get_enroll_tokentypes(None, {
            "role": SCOPE.ADMIN,
            "realm": "",
            "username": "******"
        })
        self.assertTrue("totp" not in rights)
        self.assertTrue("hotp" in rights)
        rights = P.ui_get_enroll_tokentypes(None, {
            "role": SCOPE.ADMIN,
            "realm": "",
            "username": "******"
        })
        self.assertEqual(rights, {})
        delete_policy("polAdminA")
        delete_policy("polAdminB")
Exemple #52
0
    def test_03_custom_parameters(self):
        set_policy(
            name="enrollhotp",
            action=["enrollHOTP=1", "delete", "hotp_2step=allow"],
            scope=SCOPE.ADMIN,
        )
        with self.app.test_request_context(
                '/token/init',
                method='POST',
                data={
                    "type": "hotp",
                    "genkey": "1",
                    "2stepinit": "1",
                    "2step_serversize": "5",
                    "2step_clientsize": "16",
                    "2step_difficulty": "17898",
                    "hashlib": "sha512",  # force 64-byte secret
                    "otplen": "8",
                },
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status") is True, result)
            self.assertTrue(result.get("value") is True, result)
            detail = res.json.get("detail")
            serial = detail.get("serial")
            otpkey_url = detail.get("otpkey", {}).get("value")
            server_component = binascii.unhexlify(otpkey_url.split("/")[2])

        client_component = b"wrongsize0"  # 10 bytes
        hex_client_component = binascii.hexlify(client_component)

        # Supply a client secret of incorrect size
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "hotp",
                                               "serial": serial,
                                               "otpkey": hex_client_component,
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 400, res)
            result = res.json.get("result")
            self.assertFalse(result.get("status"))

        client_component = b"correctsizeABCDE"  # 16 bytes
        hex_client_component = binascii.hexlify(client_component)

        # Now doing the correct 2nd step
        with self.app.test_request_context(
                '/token/init',
                method='POST',
                data={
                    "type": "hotp",
                    "serial": serial,
                    "otpkey": hex_client_component,
                    "2step_serversize": "3",  # will have no effect
                    "2step_clientsize": "4",
                    "2step_difficulty": "33333"
                },
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status") is True, result)
            self.assertTrue(result.get("value") is True, result)
            detail = res.json.get("detail")
            otpkey_url = detail.get("otpkey", {}).get("value")
            otpkey = otpkey_url.split("/")[2]

        # Now try to authenticate
        otpkey_bin = binascii.unhexlify(otpkey)
        otp_value = HmacOtp(digits=8,
                            hashfunc=hashlib.sha512).generate(key=otpkey_bin,
                                                              counter=1)
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={
                                               "serial": serial,
                                               "pass": otp_value
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result.get("status"), True)
            self.assertEqual(result.get("value"), True)

        # Check serversize
        self.assertEqual(len(server_component), 5)
        # Check that the OTP key is what we expected it to be
        expected_secret = pbkdf2(binascii.hexlify(server_component),
                                 client_component, 17898, 64)
        self.assertEqual(otpkey_bin, expected_secret)

        with self.app.test_request_context('/token/' + serial,
                                           method='DELETE',
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)

        delete_policy("enrollhotp")
    def test_04_remote_user_auth(self):
        self.setUp_user_realms()
        # first check that without a remote_user policy the login fails
        with self.app.test_request_context(
                '/auth',
                method='POST',
                data={"username": "******"},
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 401, res)
            result = res.json.get("result")
            self.assertFalse(result.get("status"), result)
            self.assertEqual(result.get("error").get('code'), 4031, result)
            self.assertEqual(
                result.get("error").get('message'),
                'Authentication failure. Wrong credentials', result)
        aentry = self.find_most_recent_audit_entry(action='POST /auth')
        self.assertEqual(aentry['action'], 'POST /auth', aentry)
        self.assertEqual(aentry['success'], 0, aentry)

        # now check that with a disabled remote_user policy the login fails
        set_policy(name="remote",
                   scope=SCOPE.WEBUI,
                   action="{0!s}={1!s}".format(ACTION.REMOTE_USER,
                                               REMOTE_USER.DISABLE))
        with self.app.test_request_context(
                '/auth',
                method='POST',
                data={"username": "******"},
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 401, res)
            result = res.json.get("result")
            self.assertFalse(result.get("status"), result)
            self.assertEqual(result.get("error").get('code'), 4031, result)
            self.assertEqual(
                result.get("error").get('message'),
                'Authentication failure. Wrong credentials', result)
        aentry = self.find_most_recent_audit_entry(action='POST /auth')
        self.assertEqual(aentry['action'], 'POST /auth', aentry)
        self.assertEqual(aentry['success'], 0, aentry)
        self.assertEqual(aentry['policies'], 'remote', aentry)

        # And now check that with an enabled remote_user policy the login succeeds
        set_policy(name="remote",
                   scope=SCOPE.WEBUI,
                   action="{0!s}={1!s}".format(ACTION.REMOTE_USER,
                                               REMOTE_USER.ACTIVE))
        with self.app.test_request_context(
                '/auth',
                method='POST',
                data={"username": "******"},
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status"), result)
            self.assertEqual(result.get("value").get('role'), 'user', result)
        aentry = self.find_most_recent_audit_entry(action='POST /auth')
        self.assertEqual(aentry['action'], 'POST /auth', aentry)
        self.assertEqual(aentry['success'], 1, aentry)
        self.assertEqual(aentry['policies'], 'remote', aentry)

        # check that a remote user with "@" works as well
        set_policy(name="remote",
                   scope=SCOPE.WEBUI,
                   realm=self.realm1,
                   action="{0!s}={1!s}".format(ACTION.REMOTE_USER,
                                               REMOTE_USER.ACTIVE))
        with self.app.test_request_context(
                '/auth',
                method='POST',
                data={"username": "******"},
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status"), result)
            self.assertEqual(result.get("value").get('role'), 'user', result)
        aentry = self.find_most_recent_audit_entry(action='POST /auth')
        self.assertEqual(aentry['action'], 'POST /auth', aentry)
        self.assertEqual(aentry['success'], 1, aentry)
        self.assertEqual(aentry['policies'], 'remote', aentry)

        # check that the policy remote_user=force passes the necessary hidden tag to the
        # login window
        set_policy(name="remote",
                   scope=SCOPE.WEBUI,
                   realm=self.realm1,
                   action="{0!s}={1!s}".format(ACTION.REMOTE_USER,
                                               REMOTE_USER.FORCE))
        with self.app.test_request_context(
                '/',
                method='GET',
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200, res)
            # The login page contains the info about force remote_user, which will hide the
            # "login with credentials" button.
            self.assertIn(
                u'input type=hidden id=FORCE_REMOTE_USER value="True"',
                to_unicode(res.data))

        # bind the remote user policy to an unknown realm
        set_policy(name="remote",
                   scope=SCOPE.WEBUI,
                   realm='unknown',
                   action="{0!s}={1!s}".format(ACTION.REMOTE_USER,
                                               REMOTE_USER.ACTIVE))
        with self.app.test_request_context(
                '/auth',
                method='POST',
                data={"username": "******"},
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 401, res)
            result = res.json.get("result")
            self.assertFalse(result.get("status"), result)
        aentry = self.find_most_recent_audit_entry(action='POST /auth')
        self.assertEqual(aentry['action'], 'POST /auth', aentry)
        self.assertEqual(aentry['success'], 0, aentry)
        self.assertEqual(aentry['policies'], '', aentry)

        # check split@sign is working correctly
        set_policy(name="remote",
                   scope=SCOPE.WEBUI,
                   realm=self.realm1,
                   action="{0!s}={1!s}".format(ACTION.REMOTE_USER,
                                               REMOTE_USER.ACTIVE))
        set_privacyidea_config(SYSCONF.SPLITATSIGN, False)
        with self.app.test_request_context(
                '/auth',
                method='POST',
                data={"username": "******"},
                environ_base={"REMOTE_USER": "******"}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status"), result)
            self.assertEqual(result.get("value").get('role'), 'user', result)
        aentry = self.find_most_recent_audit_entry(action='POST /auth')
        self.assertEqual(aentry['action'], 'POST /auth', aentry)
        self.assertEqual(aentry['success'], 1, aentry)
        self.assertEqual(aentry['policies'], 'remote', aentry)

        delete_policy(name='remote')
        set_privacyidea_config(SYSCONF.SPLITATSIGN, True)
Exemple #54
0
    def test_05_init_totp_token(self):
        set_policy(
            name="allow_2step",
            action=["totp_2step=allow", "enrollTOTP=1", "delete"],
            scope=SCOPE.ADMIN,
        )
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "totp",
                                               "genkey": "1",
                                               "2stepinit": "1"
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status") is True, result)
            self.assertTrue(result.get("value") is True, result)
            detail = res.json.get("detail")
            serial = detail.get("serial")
            otpkey_url = detail.get("otpkey", {}).get("value")
            server_component = binascii.unhexlify(otpkey_url.split("/")[2])
            google_url = detail["googleurl"]["value"]
            self.assertIn('2step_difficulty=10000', google_url)
            self.assertIn('2step_salt=8', google_url)
            self.assertIn('2step_output=20', google_url)
            self.assertEqual(detail['2step_difficulty'], 10000)
            self.assertEqual(detail['2step_salt'], 8)
            self.assertEqual(detail['2step_output'], 20)

        client_component = b"VRYSECRT"
        checksum = hashlib.sha1(client_component).digest()[:4]
        base32check_client_component = base64.b32encode(
            checksum + client_component).strip(b"=")

        # Try to do a 2stepinit on a second step will raise an error
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "totp",
                                               "2stepinit": "1",
                                               "serial": serial,
                                               "otpkey":
                                               base32check_client_component,
                                               "otpkeyformat": "base32check"
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 400)
            result = res.json.get("result")
            self.assertIn(
                '2stepinit is only to be used in the first initialization step',
                result.get("error").get("message"))

        # Invalid base32check will raise an error
        with self.app.test_request_context(
                '/token/init',
                method='POST',
                data={
                    "type": "totp",
                    "2stepinit": "1",
                    "serial": serial,
                    "otpkey": b"A" + base32check_client_component[1:],
                    "otpkeyformat": "base32check"
                },
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertEqual(res.status_code, 400)
            result = res.json.get("result")
            self.assertIn('Malformed base32check data: Incorrect checksum',
                          result.get("error").get("message"))

        # Authentication does not work yet!
        wrong_otp_value = HmacOtp().generate(key=server_component,
                                             counter=int(time.time() // 30))
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={
                                               "serial": serial,
                                               "pass": wrong_otp_value
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json
            self.assertTrue(result.get("result").get("status"))
            self.assertFalse(result.get("result").get("value"))
            self.assertEqual(
                result.get("detail").get("message"),
                u'matching 1 tokens, Token is disabled')

        # Now doing the correct 2nd step
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "totp",
                                               "serial": serial,
                                               "otpkey":
                                               base32check_client_component,
                                               "otpkeyformat": "base32check"
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status") is True, result)
            self.assertTrue(result.get("value") is True, result)
            detail = res.json.get("detail")
            otpkey_url = detail.get("otpkey", {}).get("value")
            otpkey = otpkey_url.split("/")[2]
            self.assertNotIn('2step', detail)

        # Now try to authenticate
        otpkey_bin = binascii.unhexlify(otpkey)
        otp_value = HmacOtp().generate(key=otpkey_bin,
                                       counter=int(time.time() // 30))
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={
                                               "serial": serial,
                                               "pass": otp_value
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result.get("status"), True)
            self.assertEqual(result.get("value"), True)

        # Check that the OTP key is what we expected it to be
        expected_secret = pbkdf2(binascii.hexlify(server_component),
                                 client_component, 10000, 20)
        self.assertEqual(otpkey_bin, expected_secret)

        with self.app.test_request_context('/token/' + serial,
                                           method='DELETE',
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
        delete_policy("allow_2step")
    def test_01_register_user(self):
        smtpmock.setdata(response={"*****@*****.**": (200, "OK")})
        # create resolver and realm
        param = self.parameters
        param["resolver"] = "register"
        param["type"] = "sqlresolver"
        r = save_resolver(param)
        self.assertTrue(r > 0)

        added, failed = set_realm("register", resolvers=["register"])
        self.assertTrue(added > 0)
        self.assertEqual(len(failed), 0)

        # create policy
        r = set_policy(name="pol2",
                       scope=SCOPE.REGISTER,
                       action="{0!s}={1!s}, {2!s}={3!s}".format(
                           ACTION.REALM, "register", ACTION.RESOLVER,
                           "register"))

        # Try to register, but missing parameter
        with self.app.test_request_context('/register',
                                           method='POST',
                                           data={
                                               "username": "******",
                                               "surname": "Kölbel"
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 400, res)

        # Register fails, missing SMTP config
        with self.app.test_request_context('/register',
                                           method='POST',
                                           data={
                                               "username": "******",
                                               "surname": "Kölbel",
                                               "givenname": "Cornelius",
                                               "password": "******",
                                               "email":
                                               "*****@*****.**"
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 400, res)
            data = json.loads(res.data)
            self.assertEqual(
                data.get("result").get("error").get("message"),
                u'ERR10: No SMTP server configuration specified!')

        # Set SMTP config and policy
        add_smtpserver("myserver", "1.2.3.4", sender="pi@localhost")
        set_policy("pol3",
                   scope=SCOPE.REGISTER,
                   action="{0!s}=myserver".format(ACTION.EMAILCONFIG))
        with self.app.test_request_context('/register',
                                           method='POST',
                                           data={
                                               "username": "******",
                                               "surname": "Kölbel",
                                               "givenname": "Cornelius",
                                               "password": "******",
                                               "email":
                                               "*****@*****.**"
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)

        # Registering the user a second time will fail
        with self.app.test_request_context('/register',
                                           method='POST',
                                           data={
                                               "username": "******",
                                               "surname": "Kölbel",
                                               "givenname": "Cornelius",
                                               "password": "******",
                                               "email":
                                               "*****@*****.**"
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 400, res)

        # get the register status
        with self.app.test_request_context('/register', method='GET'):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            data = json.loads(res.data)
            self.assertEqual(data.get("result").get("value"), True)
Exemple #56
0
    def test_06_force_totp_parameters(self):
        set_policy(
            name="force_2step",
            action=["totp_2step=force", "enrollTOTP=1", "delete"],
            scope=SCOPE.ADMIN,
        )
        set_policy(
            name="2step_params",
            action=[
                "totp_2step_difficulty=12345", "totp_2step_serversize=33",
                "totp_2step_clientsize=11"
            ],
            scope=SCOPE.ENROLL,
        )
        with self.app.test_request_context(
                '/token/init',
                method='POST',
                data={
                    "type": "totp",
                    "genkey": "1",
                    "2stepinit": "0",  # will be forced nevertheless
                    "2step_serversize": "3",
                    "2step_clientsize": "4",
                    "2step_difficulty": "33333",
                    "timeStep": "60",
                    "hashlib": "sha512",
                    "otplen": "8",
                },
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status") is True, result)
            self.assertTrue(result.get("value") is True, result)
            detail = res.json.get("detail")
            serial = detail.get("serial")
            otpkey_url = detail.get("otpkey", {}).get("value")
            server_component = binascii.unhexlify(otpkey_url.split("/")[2])
            google_url = detail["googleurl"]["value"]
            self.assertIn('2step_difficulty=12345', google_url)
            self.assertIn('2step_salt=11', google_url)
            self.assertIn('2step_output=64', google_url)
        # Authentication does not work yet!
        wrong_otp_value = HmacOtp(digits=8, hashfunc=hashlib.sha512).generate(
            key=server_component, counter=int(time.time() // 60))
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={
                                               "serial": serial,
                                               "pass": wrong_otp_value
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json
            self.assertTrue(result.get("result").get("status"))
            self.assertFalse(result.get("result").get("value"))
            self.assertEqual(
                result.get("detail").get("message"),
                u'matching 1 tokens, Token is disabled')

        client_component = b"wrongsize"  # 9 bytes
        hex_client_component = binascii.hexlify(client_component)

        # Supply a client secret of incorrect size
        with self.app.test_request_context('/token/init',
                                           method='POST',
                                           data={
                                               "type": "totp",
                                               "serial": serial,
                                               "otpkey": hex_client_component,
                                           },
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 400, res)
            result = res.json.get("result")
            self.assertFalse(result.get("status"))

        client_component = b"correctsize"  # 11 bytes
        hex_client_component = binascii.hexlify(client_component)

        # Now doing the correct 2nd step
        with self.app.test_request_context(
                '/token/init',
                method='POST',
                data={
                    "type": "totp",
                    "serial": serial,
                    "otpkey": hex_client_component,
                    "2step_serversize": "3",  # will have no effect
                    "2step_clientsize": "4",
                    "2step_difficulty": "33333"
                },
                headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertTrue(result.get("status") is True, result)
            self.assertTrue(result.get("value") is True, result)
            detail = res.json.get("detail")
            otpkey_url = detail.get("otpkey", {}).get("value")
            otpkey = otpkey_url.split("/")[2]

        # Now try to authenticate
        otpkey_bin = binascii.unhexlify(otpkey)
        otp_value = HmacOtp(digits=8, hashfunc=hashlib.sha512).generate(
            key=otpkey_bin, counter=int(time.time() // 60))
        with self.app.test_request_context('/validate/check',
                                           method='POST',
                                           data={
                                               "serial": serial,
                                               "pass": otp_value
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            result = res.json.get("result")
            self.assertEqual(result.get("status"), True)
            self.assertEqual(result.get("value"), True)

        # Check serversize
        self.assertEqual(len(server_component), 33)
        # Check that the OTP key is what we expected it to be
        expected_secret = pbkdf2(binascii.hexlify(server_component),
                                 client_component, 12345, 64)
        self.assertEqual(otpkey_bin, expected_secret)

        with self.app.test_request_context('/token/' + serial,
                                           method='DELETE',
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)

        delete_policy("force_2step")
        delete_policy("2step_params")
    def test_03_get_allowed_audit_realm(self):
        # Check than an internal admin is allowed to see all realms
        # A helpdesk user in "adminrealm" is only allowerd to see realm1A
        Audit(action="enroll", success=1, realm=self.realm1a).save()
        Audit(action="enroll", success=1, realm=self.realm1a).save()
        Audit(action="enroll", success=1, realm=self.realm2b).save()
        Audit(action="enroll", success=1, realm=self.realm2b).save()
        Audit(action="enroll", success=1, realm=self.realm2b).save()

        # check, that we see all audit entries
        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           data={"realm": self.realm1a},
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            self.assertTrue(json_response.get("result").get("status"), res)
            self.assertGreaterEqual(
                json_response.get("result").get("value").get("count"), 2)

        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           data={"realm": self.realm2b},
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            self.assertTrue(json_response.get("result").get("status"), res)
            self.assertGreaterEqual(
                json_response.get("result").get("value").get("count"), 3)

        # set policy: helpdesk users in adminrealm are only allowed to
        # view "realm1A".
        set_policy("audit01",
                   scope=SCOPE.ADMIN,
                   action=ACTION.AUDIT,
                   adminrealm="adminrealm",
                   realm=self.realm1a)
        # Test admin is allowed to view unrestricted logs!
        set_policy("audit02",
                   scope=SCOPE.ADMIN,
                   action=ACTION.AUDIT,
                   user="******")

        rid = save_resolver({
            "resolver": self.resolvername1,
            "type": "passwdresolver",
            "fileName": PWFILE
        })
        self.assertTrue(rid > 0, rid)

        (added, failed) = set_realm("adminrealm", [self.resolvername1])
        self.assertTrue(len(failed) == 0)
        self.assertTrue(len(added) == 1)

        helpdesk_authorization = None
        with self.app.test_request_context('/auth',
                                           method='POST',
                                           data={
                                               'username':
                                               '******',
                                               'password': '******'
                                           }):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            value = json_response.get("result").get("value")
            # Helpdesk user is allowed to view the audit log.
            self.assertTrue("auditlog" in value.get("rights"))
            helpdesk_authorization = value.get("token")

        # check, that we only see allowed audit realms
        with self.app.test_request_context(
                '/audit/',
                method='GET',
                data={
                    "action": "**",
                    "action_detail": "**",
                    "administrator": "**",
                    "client": "**",
                    "date": "**",
                    "info": "**",
                    "page": "1",
                    "page_size": "10",
                    "policies": "**",
                    "privacyidea_server": "**",
                    "realm": "**",
                    "resolver": "**",
                    "serial": "**",
                    "sortorder": "desc",
                    "success": "**",
                    "tokentype": "**",
                    "user": "******"
                },
                headers={'Authorization': helpdesk_authorization}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            self.assertTrue(json_response.get("result").get("status"), res)
            # We now have 3 entries, as we added one by the search in line #43
            count = json_response.get("result").get("value").get("count")
            auditdata = json_response.get("result").get("value").get(
                "auditdata")
            self.assertGreaterEqual(count, 3)
            # All entries are in realm1A!
            for ad in auditdata:
                self.assertEqual(ad.get("realm"), self.realm1a)

        # Now check, that the testadmin (self.at) sees all entries!
        with self.app.test_request_context('/audit/',
                                           method='GET',
                                           headers={'Authorization': self.at}):
            res = self.app.full_dispatch_request()
            self.assertTrue(res.status_code == 200, res)
            json_response = res.json
            self.assertTrue(json_response.get("result").get("status"), res)
            # We now have 3 entries, as we added one by the search in line #43
            count = json_response.get("result").get("value").get("count")
            auditdata = json_response.get("result").get("value").get(
                "auditdata")
            self.assertGreaterEqual(count, 10)

        # delete policy
        delete_policy("audit01")
        delete_policy("audit02")
    def test_06_passthru(self):
        user = User("cornelius", realm="r1")
        passw = "test"
        options = {}
        # A user with no tokens will fail to authenticate
        self.assertEqual(get_tokens(user=user, count=True), 0)
        rv = auth_user_passthru(check_user_pass, user, passw, options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"),
                         "The user has no tokens assigned")

        # Now we set a PASSTHRU policy, so that the user may authenticate
        # against his userstore (old style)
        set_policy(name="pol1", scope=SCOPE.AUTH, action=ACTION.PASSTHRU)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}
        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against userstore due to 'pol1'")

        # Now set a PASSTHRU policy to the userstore (new style)
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}=userstore".format(ACTION.PASSTHRU))
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}
        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against userstore due to 'pol1'")

        # Now set a PASSTHRU policy to a RADIUS config (new style)
        radiusmock.setdata(success=True)
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   action="{0!s}=radiusconfig1".format(ACTION.PASSTHRU))
        r = add_radius("radiusconfig1",
                       "1.2.3.4",
                       "testing123",
                       dictionary=DICT_FILE)
        self.assertTrue(r > 0)
        g = FakeFlaskG()
        g.policy_object = PolicyClass()
        g.audit_object = FakeAudit()
        options = {"g": g}
        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertTrue(rv[0])
        self.assertEqual(rv[1].get("message"),
                         u"against RADIUS server radiusconfig1 due to 'pol1'")

        # Now assign a token to the user. If the user has a token and the
        # passthru policy is set, the user must not be able to authenticate
        # with his userstore password.
        init_token({
            "serial": "PTHRU",
            "type": "spass",
            "pin": "Hallo"
        },
                   user=user)
        rv = auth_user_passthru(check_user_pass, user, passw, options=options)
        self.assertFalse(rv[0])
        self.assertEqual(rv[1].get("message"), "wrong otp pin")

        remove_token("PTHRU")
        delete_policy("pol1")
    def test_07_login_mode(self):
        # a realm: cornelius@r1: PW: test

        def check_webui_user_userstore(user_obj,
                                       password,
                                       options=None,
                                       superuser_realms=None,
                                       check_otp=False):
            self.assertEqual(check_otp, False)

        def check_webui_user_privacyidea(user_obj,
                                         password,
                                         options=None,
                                         superuser_realms=None,
                                         check_otp=False):
            self.assertEqual(check_otp, True)

        user_obj = User("cornelius", "r1")

        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # No policy, the function is called with check_otp=False
        login_mode(check_webui_user_userstore,
                   user_obj,
                   "",
                   options=options,
                   superuser_realms="",
                   check_otp=False)

        set_policy(name="pol2",
                   scope=SCOPE.WEBUI,
                   action="{0!s}={1!s}".format(ACTION.LOGINMODE,
                                               LOGINMODE.PRIVACYIDEA))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # Policy is set, the function is called with check_otp=True
        login_mode(check_webui_user_privacyidea,
                   user_obj,
                   "",
                   options=options,
                   superuser_realms="",
                   check_otp=False)

        # Set policy, so that the user is not allowed to login at all
        set_policy(name="pol2",
                   scope=SCOPE.WEBUI,
                   action="{0!s}={1!s}".format(ACTION.LOGINMODE,
                                               LOGINMODE.DISABLE))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # Policy is set. Trying to login raises a policy error
        self.assertRaises(PolicyError,
                          login_mode,
                          check_webui_user_privacyidea,
                          user_obj,
                          "",
                          options=options,
                          superuser_realms="",
                          check_otp=False)
        delete_policy("pol2")
    def test_11_otppin_with_resolvers(self):
        # This tests, if the otppin policy differentiates between users in
        # the same realm but in different resolvers.
        r = save_resolver({
            "resolver": "reso001",
            "type": "passwdresolver",
            "fileName": "tests/testdata/passwords"
        })
        # user "cornelius" is in resolver reso001
        self.assertTrue(r > 0)
        r = save_resolver({
            "resolver": "reso002",
            "type": "passwdresolver",
            "fileName": "tests/testdata/pw-2nd-resolver"
        })
        # user "userresolver2" is in resolver reso002
        self.assertTrue(r > 0)
        (added, failed) = set_realm("myrealm", ["reso001", "reso002"])
        self.assertEqual(len(added), 2)
        self.assertEqual(len(failed), 0)
        my_user_1 = User("cornelius", realm="myrealm")
        my_user_2 = User("userresolver2", realm="myrealm")
        # We set a policy only for resolver reso002
        set_policy(name="pol1",
                   scope=SCOPE.AUTH,
                   realm="myrealm",
                   resolver="reso002",
                   action="{0!s}={1!s}".format(ACTION.OTPPIN,
                                               ACTIONVALUE.NONE))
        g = FakeFlaskG()
        P = PolicyClass()
        g.policy_object = P
        g.audit_object = FakeAudit()
        options = {"g": g}

        # user in reso001 fails with empty PIN, since the policy does not
        # match for him
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "",
                        options=options,
                        user=my_user_1)
        self.assertFalse(r)

        # user in reso002 succeeds with empty PIN, since policy pol1 matches
        # for him
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "",
                        options=options,
                        user=my_user_2)
        self.assertTrue(r)

        # user in reso002 fails with any PIN, since policy pol1 matches
        # for him
        r = auth_otppin(self.fake_check_otp,
                        None,
                        "anyPIN",
                        options=options,
                        user=my_user_2)
        self.assertFalse(r)

        delete_policy("pol1")
        delete_realm("myrealm")
        delete_resolver("reso001")
        delete_resolver("reso002")