New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request FIDO2 #1109
Comments
Yes, you made the feature request in the correct place and thanks for offering to implement it. FIDO2 is definitely an improvement over our current 2FA. It's hard to say if we want to add this without a knowing how complex it would be. Can you list the changes required you expect or make a prototype PR if that's easier? Is it possible to use FIDO2 in Elixir/Erlang CLI applications? |
Yes, sure. I will describe the details here until next Sunday. |
Just a heads-up. I'm still working on this. FIDO2 is a bigger spec than I expected, and I wanted to understand it fully before suggesting changes here. |
So, I think I have gathered enough information for this. First, I would like to provide a form of clarification of what FIDO2 is. NounsFIDO2 is a set of specifications by the Fast IDentity Online Alliance hence the name FIDO.
Specifications are here https://fidoalliance.org/specifications/download What do we needFor hex only UAF and U2F are relevant as webauthn is an api implemented by the browser. U2F is the part for implementing 2FA. UAF is for passwordless authentication. For now, I would focus on U2F. For U2F there is already a package on hex which implements this for the browser WAX. This also includes a demo app wax_demo. We need to update the depdencies but overall the project looks good. The client side is a bit trickier. There are currently no elixir libraries implementing this, as we have to read the hardware key, which comes in multiple forms. There is a c library by yubikey https://developers.yubico.com/libfido2/ that we can use in a nif wrapper. This is a widely used project, for example openssh uses this https://github.com/openssh/openssh-portable#dependencies. Another possible solution would be to leverage the browser from the cli. How to integrateWe need to edit the lib/hexpm_web/templates/tfa_auth/show.html.eex template. The view should ask for the hardware device first. The user should have an option to use TOTP instead if he wants to. Only show the question for hardware device if one is registered. The lib/hexpm_web/controllers/tfa_auth_controller.ex has to submit some extra information for the view. This looks like this in the wax_demo. conn
|> put_session(:authentication_challenge, challenge)
|> render("credential.html",
login: login,
with_webauthn: true,
challenge: Base.encode64(challenge.bytes),
rp_id: challenge.rp_id,
user: login,
cred_ids: Enum.map(cred_ids, fn {_login, cred_id, _cose_key} -> cred_id end)
) We edit the render_show and create functions for this. A new controller for the cli would make sense here. For the registration we need to edit the lib/hexpm_web/controllers/dashboard/tfa_setup_controller.ex and lib/hexpm_web/templates/dashboard/tfa_auth_setup/index.html.eex to allow the registration of a hardware device. conn
|> put_session(:challenge, challenge)
|> render("register_key.html",
login: get_session(conn, :login),
challenge: Base.encode64(challenge.bytes),
rp_id: challenge.rp_id,
user: login
) With a new validation def validate(conn, %{
"key" => %{
"attestationObject" => attestation_object_b64,
"clientDataJSON" => client_data_json,
"rawID" => raw_id_b64,
"type" => "public-key"
}
}) do
challenge = get_session(conn, :challenge)
attestation_object = Base.decode64!(attestation_object_b64)
case Wax.register(attestation_object, client_data_json, challenge) do
{:ok, {authenticator_data, result}} ->
Logger.debug(
"Wax: attestation object validated with result #{inspect(result)} " <>
" and authenticator data #{inspect(authenticator_data)}"
)
user = get_session(conn, :login)
WaxDemo.User.register_new_cose_key(
user,
raw_id_b64,
authenticator_data.attested_credential_data.credential_public_key
)
conn
|> put_flash(:info, "Key registered")
|> redirect(to: "/me")
{:error, _} = error ->
Logger.debug("Wax: attestation object validation failed with error #{inspect(error)}")
conn
|> put_flash(:error, "Key registration failed")
|> index(%{})
end
end At the end, we will save a new credential_id and a cose key for the user. Best practice is to allow multiple keys. Because we want to avoid locking someone out if you lose one key. I Probably forgot something to tell here, so please ask if you have questions. |
Next step for me would be to make a POC. Maybe things get clearer after that. |
@ericmj what do you think should i do a POC? |
I saw that hex.pm can do 2FA, but only with OTP. A new and better option would be to also allow 2FA with FIDO2. The advantage is, that fido2 is phishing resistant. Is this the correct place to make such a feature request?
I would be open in trying to implement this.
The text was updated successfully, but these errors were encountered: