def test_verify_email(self, clean_mongo, smtp_mock):
        uuidv4 = str(uuid.uuid4())
        tenant, email, password = (
            "test.mender.io-" + uuidv4,
            "some.user+" + uuidv4 + "@example.com",
            "secretsecret",
        )
        create_org(tenant, email, password)

        # login and try to enable two factor authentication
        # it shouldn't be possible since the user email address
        # has not been verified
        r = self.uc.call("POST", useradm.URL_LOGIN, auth=(email, password))
        assert r.status_code == 200
        utoken = r.text
        r = self.uc.with_auth(utoken).call(
            "POST", useradm.URL_SETTINGS, body={"2fa": "enabled"}
        )
        assert r.status_code == 403

        # verify user email address
        r = self.uc.post(useradm.URL_VERIFY_EMAIL_START, body={"email": email})
        assert r.status_code == 202
        # wait for the verification email
        message = None
        for i in range(15):
            messages = smtp_mock.filtered_messages(email)
            if len(messages) > 0:
                message = messages[0]
                break
            time.sleep(1)
        # be sure we received the email
        assert message is not None
        assert message.data != ""
        # extract the secret hash from the link
        match = re.search(
            r"https://hosted.mender.io/ui/#/activate/([a-z0-9\-]+)",
            message.data.decode("utf-8"),
        )
        secret_hash = match.group(1)
        assert secret_hash != ""
        # complete the email address
        r = self.uc.post(
            useradm.URL_VERIFY_EMAIL_COMPLETE, body={"secret_hash": secret_hash},
        )
        assert r.status_code == 204

        # try to enable two factor authentication after email address verification
        # now it should be possible
        r = self.uc.with_auth(utoken).call(
            "POST", useradm.URL_SETTINGS, body={"2fa": "enabled"}
        )
        assert r.status_code == 201
    def test_contact_support(self, clean_mongo, smtp_mock):
        uuidv4 = str(uuid.uuid4())
        tenant, email, password = (
            "test.mender.io-" + uuidv4,
            "some.user-" + uuidv4 + "@example.com",
            "secretsecret",
        )
        org = create_org(tenant, email, password)

        r = api_useradm.call("POST", useradm.URL_LOGIN, auth=(email, password))
        assert r.status_code == 200
        utoken = r.text
        r = api_tadm_v2.with_auth(utoken).call(
            "POST",
            tenantadm_v2.URL_CONTACT_SUPPORT,
            body={
                "subject": "foo",
                "body": "bar"
            },
        )
        assert r.status_code == 202
        # wait for the email
        message = None
        for i in range(15):
            messages = smtp_mock.filtered_messages("*****@*****.**")
            if len(messages) > 0:
                message = messages[0]
                break
            time.sleep(1)

        # be sure we received the email
        assert message is not None
        assert message.data != ""

        # and the email is properly formatted
        data = message.data.decode("utf-8")
        match = re.search(
            r"Subject: ([a-z0-9\-]+)",
            data,
        )
        subject = match.group(1)
        assert re.search(r"Subject: foo", data) is not None
        assert re.search(r"From: [email protected]", data) is not None
        assert re.search(r"To: [email protected]", data) is not None
        assert re.search(r"Organization ID: " + org.id, data) is not None
        assert re.search(r"Organization name: " + tenant, data) is not None
        assert re.search(r"Plan name: os", data) is not None
        assert re.search(r"User ID: " + org.users[0].id, data) is not None
        assert re.search(r"User Email: " + email, data) is not None
        assert re.search(r"bar", data) is not None
    def test_password_reset(self, clean_mongo, smtp_mock):
        uuidv4 = str(uuid.uuid4())
        tenant, email, password = (
            "test.mender.io-" + uuidv4,
            "some.user+" + uuidv4 + "@example.com",
            "secretsecret",
        )
        create_org(tenant, email, password)
        new_password = "******"

        r = self.uc.post(useradm.URL_PASSWORD_RESET_START, body={"email": email})
        assert r.status_code == 202
        # wait for the password reset email
        message = None
        for i in range(15):
            messages = smtp_mock.filtered_messages(email)
            if len(messages) > 0:
                message = messages[0]
                break
            time.sleep(1)
        # be sure we received the email
        assert message is not None
        assert message.data != ""
        # extract the secret hash from the link
        match = re.search(
            r"https://hosted.mender.io/ui/#/password/([a-z0-9\-]+)",
            message.data.decode("utf-8"),
        )
        secret_hash = match.group(1)
        assert secret_hash != ""
        # reset the password
        r = self.uc.post(
            useradm.URL_PASSWORD_RESET_COMPLETE,
            body={"secret_hash": secret_hash, "password": new_password},
        )
        assert r.status_code == 202
        # try to login using the new password
        r = self.uc.call("POST", useradm.URL_LOGIN, auth=(email, new_password))
        assert r.status_code == 200
        assert bool(r.text)
示例#4
0
    def test_enable_disable(self, tenants_users, smtp_mock):
        user_2fa = tenants_users[0].users[0]
        user_no_2fa = tenants_users[0].users[1]

        r = self._login(user_2fa)
        assert r.status_code == 200
        user_2fa_tok = r.text

        # some error scenarios related to invalid 2fa state
        # before email verification - can't touch settings
        for on in [True, False]:
            r = self._toggle_tfa(user_2fa_tok, user_2fa.id, on=True)
            assert r.status_code == 403

        # /2faqr available only in 'unverified' state
        r = uadm.with_auth(user_2fa_tok).call("GET", useradm.URL_2FAQR)

        assert r.status_code == 400

        # /verify available only in 'unverified' state
        r = uadm.with_auth(user_2fa_tok).call("GET", useradm.URL_2FAQR)

        assert r.status_code == 400

        # verify user email address
        r = uadm.post(useradm.URL_VERIFY_EMAIL_START,
                      body={"email": user_2fa.name})
        assert r.status_code == 202
        # wait for the verification email
        message = None
        for i in range(15):
            messages = smtp_mock.filtered_messages(user_2fa.name)
            if len(messages) > 0:
                message = messages[0]
                break
            time.sleep(1)
        # be sure we received the email
        assert message is not None
        assert message.data != ""
        # extract the secret hash from the link
        match = re.search(
            r"https://hosted.mender.io/ui/#/activate/([a-z0-9\-]+)",
            message.data.decode("utf-8"),
        )
        secret_hash = match.group(1)
        assert secret_hash != ""
        # complete the email address
        r = uadm.post(useradm.URL_VERIFY_EMAIL_COMPLETE,
                      body={"secret_hash": secret_hash})
        assert r.status_code == 204

        # enable tfa for 1 user, straight login still works, token is not verified
        r = self._toggle_tfa(user_2fa_tok, user_2fa.id, on=True)
        assert r.status_code == 200

        r = self._login(user_2fa)
        assert r.status_code == 200

        # get the user info and verify 2fa status
        user = self._get_user(user_2fa_tok)
        assert user["tfa_status"] == TFA_UNVERIFIED

        # grab qr code, extract token, calc TOTP
        r = uadm.with_auth(user_2fa_tok).call("GET", useradm.URL_2FAQR)

        assert r.status_code == 200

        secret = self._qr_dec(r.json()["qr"])
        totp = pyotp.TOTP(secret)
        tok = totp.now()

        # verify token
        r = self._verify(user_2fa_tok, tok)
        assert r.status_code == 202

        # get the user info and verify 2fa status
        user = self._get_user(user_2fa_tok)
        assert user["tfa_status"] == TFA_ENABLED

        # login with totp succeeds
        r = self._login(user_2fa, totp=tok)
        assert r.status_code == 200

        # already enabled - can't enable twice
        r = self._toggle_tfa(user_2fa_tok, user_2fa.id, on=True)
        assert r.status_code == 400

        # logi without otp now does not work
        r = self._login(user_2fa)
        assert r.status_code == 401

        # the other user, and other tenant's users, are unaffected
        r = self._login(user_no_2fa)
        assert r.status_code == 200
        user_no_2fa_tok = r.text

        # other users can't change our settings
        r = self._toggle_tfa(user_no_2fa_tok, user_2fa.id, on=False)
        assert r.status_code == 401

        # get the user info and verify 2fa status
        user = self._get_user(user_2fa_tok)
        assert user["tfa_status"] == TFA_ENABLED

        for other_user in tenants_users[1].users:
            r = self._login(other_user)
            assert r.status_code == 200

        # after disabling - straight login works again
        r = self._toggle_tfa(user_2fa_tok, "me", on=False)
        assert r.status_code == 200

        r = self._login(user_2fa)
        assert r.status_code == 200

        # get the user info and verify 2fa status
        user = self._get_user(user_2fa_tok)
        assert user["tfa_status"] == TFA_DISABLED

        # although POST /settings is still functional,
        # it will not save any 2fa settings, and will not break
        # any user's statuses

        # simulate overwriting user statuses - no effect
        signore = self._make_2fa_settings({
            user_2fa.id: TFA_ENABLED,
            user_no_2fa.id: TFA_ENABLED
        })
        r = uadm.with_auth(user_2fa_tok).call("POST", useradm.URL_SETTINGS,
                                              signore)
        assert r.status_code == 201

        # get the user info and verify 2fa status
        user = self._get_user(user_2fa_tok)
        assert user["tfa_status"] == TFA_DISABLED
    def test_enable_disable(self, tenants_users, smtp_mock):
        user_2fa = tenants_users[0].users[0]
        user_no_2fa = tenants_users[0].users[1]

        r = self._login(user_2fa)
        assert r.status_code == 200
        user_2fa_tok = r.text

        # verify user email address
        r = uadm.post(useradm.URL_VERIFY_EMAIL_START,
                      body={"email": user_2fa.name})
        assert r.status_code == 202
        # wait for the verification email
        message = None
        for i in range(15):
            messages = smtp_mock.filtered_messages(user_2fa.name)
            if len(messages) > 0:
                message = messages[0]
                break
            time.sleep(1)
        # be sure we received the email
        assert message is not None
        assert message.data != ""
        # extract the secret hash from the link
        match = re.search(
            r"https://hosted.mender.io/ui/#/activate/([a-z0-9\-]+)",
            message.data.decode("utf-8"),
        )
        secret_hash = match.group(1)
        assert secret_hash != ""
        # complete the email address
        r = uadm.post(useradm.URL_VERIFY_EMAIL_COMPLETE,
                      body={"secret_hash": secret_hash})
        assert r.status_code == 204

        # enable tfa for 1 user, straight login still works, token is not verified
        self._toggle_tfa(user_2fa_tok, user_2fa.id, on=True)
        r = self._login(user_2fa)
        assert r.status_code == 200

        # grab qr code, extract token, calc TOTP
        r = uadm.with_auth(user_2fa_tok).call("GET", useradm.URL_2FAQR)

        assert r.status_code == 200

        secret = self._qr_dec(r.json()["qr"])
        totp = pyotp.TOTP(secret)
        tok = totp.now()

        # verify token
        r = self._verify(user_2fa_tok, tok)
        assert r.status_code == 202

        # login with totp succeeds
        r = self._login(user_2fa, totp=tok)
        assert r.status_code == 200

        # logi without otp now does not work
        r = self._login(user_2fa)
        assert r.status_code == 401

        # the other user, and other tenant's users, are unaffected
        r = self._login(user_no_2fa)
        assert r.status_code == 200

        for other_user in tenants_users[1].users:
            r = self._login(other_user)
            assert r.status_code == 200

        # after disabling - straight login works again
        self._toggle_tfa(user_2fa_tok, user_2fa.id, on=False)
        r = self._login(user_2fa)
        assert r.status_code == 200