Example #1
0
    def page(self) -> CBORPageResult:
        assert user.id is not None
        user.need_permission("general.manage_2fa")

        raw_data = request.get_data()
        logger.debug("Raw request: %r", raw_data)
        data: dict[str, object] = cbor.decode(raw_data)
        client_data = ClientData(data["clientDataJSON"])
        att_obj = AttestationObject(data["attestationObject"])
        logger.debug("Client data: %r", client_data)
        logger.debug("Attestation object: %r", att_obj)

        auth_data = make_fido2_server().register_complete(
            session.session_info.webauthn_action_state, client_data, att_obj
        )

        ident = auth_data.credential_data.credential_id.hex()
        credentials = load_two_factor_credentials(user.id, lock=True)

        if ident in credentials["webauthn_credentials"]:
            raise MKGeneralException(_("Your WebAuthn credetial is already in use"))

        credentials["webauthn_credentials"][ident] = WebAuthnCredential(
            {
                "credential_id": ident,
                "registered_at": int(time.time()),
                "alias": "",
                "credential_data": bytes(auth_data.credential_data),
            }
        )
        save_two_factor_credentials(user.id, credentials)

        flash(_("Registration successful"))
        return {"status": "OK"}
Example #2
0
    def _action(self) -> None:
        assert user.id is not None
        credentials = load_two_factor_credentials(user.id, lock=True)

        credential_id = request.get_ascii_input_mandatory("_edit")
        credential = credentials["webauthn_credentials"].get(credential_id)
        if credential is None:
            raise MKUserError("_edit", _("The credential does not exist"))

        vs = self._valuespec(credential)
        settings = vs.from_html_vars("profile")
        vs.validate_value(settings, "profile")

        credential["alias"] = settings["alias"]

        save_two_factor_credentials(user.id, credentials)

        flash(_("Successfully changed the credential."))

        # In distributed setups with remote sites where the user can login, start the
        # user profile replication now which will redirect the user to the destination
        # page after completion. Otherwise directly open up the destination page.
        origtarget = "user_two_factor_overview.py"
        if user.authorized_login_sites():
            raise redirect(
                makeuri_contextless(request, [("back", origtarget)],
                                    filename="user_profile_replicate.py"))
        raise redirect(origtarget)
Example #3
0
    def _action(self) -> None:
        assert user.id is not None
        credentials = load_two_factor_credentials(user.id)

        if credential_id := request.get_ascii_input("_delete"):
            if credential_id not in credentials["webauthn_credentials"]:
                return
            del credentials["webauthn_credentials"][credential_id]
            save_two_factor_credentials(user.id, credentials)
            flash(_("Credential has been deleted"))
Example #4
0
def test_is_two_factor_backup_code_valid_matches(user_id) -> None:
    display_codes, store_codes = userdb.make_two_factor_backup_codes()
    credentials = userdb.load_two_factor_credentials(user_id)
    credentials["backup_codes"] = store_codes
    assert len(credentials["backup_codes"]) == 10
    userdb.save_two_factor_credentials(user_id, credentials)

    assert userdb.is_two_factor_backup_code_valid(user_id,
                                                  display_codes[3]) is True

    credentials = userdb.load_two_factor_credentials(user_id)
    assert len(credentials["backup_codes"]) == 9
Example #5
0
def test_is_two_factor_backup_code_valid_matches(user_id: UserId) -> None:
    codes = userdb.make_two_factor_backup_codes(rounds=5)
    credentials = userdb.load_two_factor_credentials(user_id)
    credentials["backup_codes"] = [pwhashed for _password, pwhashed in codes]
    userdb.save_two_factor_credentials(user_id, credentials)
    assert len(credentials["backup_codes"]) == 10

    valid = userdb.is_two_factor_backup_code_valid(user_id, codes[3][0])
    assert valid

    credentials = userdb.load_two_factor_credentials(user_id)
    assert len(credentials["backup_codes"]) == 9
Example #6
0
class UserTwoFactorOverview(ABCUserProfilePage):
    def _page_title(self) -> str:
        return _("Two-factor authentication")

    def __init__(self) -> None:
        super().__init__("general.manage_2fa")

    def _action(self) -> None:
        assert user.id is not None
        credentials = load_two_factor_credentials(user.id)

        if credential_id := request.get_ascii_input("_delete"):
            if credential_id not in credentials["webauthn_credentials"]:
                return
            del credentials["webauthn_credentials"][credential_id]
            save_two_factor_credentials(user.id, credentials)
            flash(_("Credential has been deleted"))

        if request.has_var("_backup_codes"):
            display_codes, credentials[
                "backup_codes"] = make_two_factor_backup_codes()
            save_two_factor_credentials(user.id, credentials)
            flash(
                _("The following backup codes have been generated: <ul>%s</ul> These codes are "
                  "displayed only now. Save them securely.") %
                "".join(f"<li><tt>{c}</tt></li>" for c in display_codes))
Example #7
0
    def page(self) -> CBORPageResult:
        assert user.id is not None
        user.need_permission("general.manage_2fa")

        raw_data = request.get_data()
        logger.debug("Raw request: %r", raw_data)
        data: dict[str, object] = cbor.decode(raw_data)
        client_data = ClientData(data["clientDataJSON"])
        att_obj = AttestationObject(data["attestationObject"])
        logger.debug("Client data: %r", client_data)
        logger.debug("Attestation object: %r", att_obj)

        try:
            auth_data = make_fido2_server().register_complete(
                session.session_info.webauthn_action_state, client_data,
                att_obj)
        except ValueError as e:
            if "Invalid origin in ClientData" in str(e):
                raise MKGeneralException(
                    "The origin %r is not valid. You need to access the UI via HTTPS "
                    "and you need to use a valid host or domain name. See werk #13325 for "
                    "further information" % client_data.get("origin")) from e
            raise

        ident = auth_data.credential_data.credential_id.hex()
        credentials = load_two_factor_credentials(user.id, lock=True)

        if ident in credentials["webauthn_credentials"]:
            raise MKGeneralException(
                _("Your WebAuthn credential is already in use"))

        credentials["webauthn_credentials"][ident] = WebAuthnCredential({
            "credential_id":
            ident,
            "registered_at":
            int(time.time()),
            "alias":
            "",
            "credential_data":
            bytes(auth_data.credential_data),
        })
        save_two_factor_credentials(user.id, credentials)

        flash(_("Registration successful"))
        return {"status": "OK"}
Example #8
0
def test_disable_two_factor_authentication(user_id: UserId) -> None:
    credentials = userdb.TwoFactorCredentials({
        "webauthn_credentials": {
            "id":
            userdb.WebAuthnCredential({
                "credential_id": "id",
                "registered_at": 1337,
                "alias": "Steckding",
                "credential_data": b"whatever",
            }),
        },
        "backup_codes": [],
    })
    userdb.save_two_factor_credentials(user_id, credentials)

    assert userdb.is_two_factor_login_enabled(user_id) is True
    userdb.disable_two_factor_authentication(user_id)
    assert userdb.is_two_factor_login_enabled(user_id) is False
Example #9
0
def test_save_two_factor_credentials(user_id: UserId) -> None:
    credentials = userdb.TwoFactorCredentials({
        "webauthn_credentials": {
            "id":
            userdb.WebAuthnCredential({
                "credential_id": "id",
                "registered_at": 1337,
                "alias": "Steckding",
                "credential_data": b"whatever",
            }),
        },
        "backup_codes": [
            "asdr2ar2a2ra2rara2",
            "dddddddddddddddddd",
        ],
    })
    userdb.save_two_factor_credentials(user_id, credentials)
    assert userdb.load_two_factor_credentials(user_id) == credentials