Closed jakubgs closed 2 years ago
Some links:
Serhan stated in #1 that:
I don't want to use a traditional username/password + 2FA for the login/register process. I want to use WebAuthN with Yubikey for login/register + TOTP 2FA with Mobile App.
Which means that he wants passwordless WebAuthN, as described here: https://github.com/keycloak/keycloak-documentation/blob/master/server_admin/topics/authentication/webauthn.adoc#passwordless-webauthn-together-with-two-factor
There is configuration available in the Authentication
section, which is mostly empty:
Most of the fields are well described in the docs: https://w3c.github.io/webauthn/#dictionary-makecredentialoptions As well as Keycloak docs: https://github.com/keycloak/keycloak-documentation/blob/master/server_admin/topics/authentication/webauthn.adoc#managing-policy
After configuring the WebAuthn Policy
section I added the requirement to my Google user:
And then when I logged in I got prompted for registration of my WebAuthn device:
The default flow does not involve WebAuthn yet:
You cannot modify the default flows like the Browser
one so it has to be copied and adjusted:
Nice, looks like I broke login:
I can see my copied flow in the DB:
keycloak=# SELECT id,alias,provider_id,top_level FROM authentication_flow WHERE alias LIKE '%WebAuthn%';
id | alias | provider_id | top_level
--------------------------------------+------------------------+-------------+-----------
ef2e5995-674b-438d-8450-f49a379ddc1e | WebAuthn Browser | basic-flow | t
cde5514a-9bfd-416e-b8ea-25ca1c1c2f53 | WebAuthn Browser forms | basic-flow | f
(2 rows)
The question is, which table holds the default authentication bindings configuration.
The list of tables is quite long, but I can't seem to find the one with the bindings: https://gist.github.com/jakubgs/4fc46647545888bebce6dadabb7fa0b2
Okay, I found it in the realm
table, which is quite long:
keycloak=# SELECT id,name,otp_policy_type,browser_flow FROM realm;
id | name | otp_policy_type | browser_flow
--------+--------+-----------------+--------------------------------------
master | master | totp | ef2e5995-674b-438d-8450-f49a379ddc1e
(1 row)
Updating it back to browser
flow and restarting Keycloak fixed it:
keycloak=# UPDATE realm SET browser_flow = '2da3ece8-e2c0-4227-ac76-11a86f2f9a86' WHERE id = 'master';
UPDATE 1
You must be careful with these changes to flows or you can lock yourself out.
This documentation describes flow configuration in detail: https://www.keycloak.org/docs/12.0/server_admin/#built-in-flows
Also, looks like flow names can't include special characters like +
, >
, or /
:
Okay. I got a flow working that does User+Pass then optionally WebAuthn or OTP:
Editing these flows is a bit tricky. This UI needs serious work.
The Conditional OTP
part is a custom Flow added with Add flow
from the WebAuthn Browser Forms
line.
I verified that a user created via Google OAuth can login using user/password + WebAuthn/OTP if they set those.
This means that we can re-use existing users if they were created via Google.
If you set up OTP or YubiKey with you account it shows up in the Credentials
section of user profile:
So an admin can remove or reset them.
Interestingly, if I log in with an already existing account it prompts me what to do:
For some reason, despite WebAuthn being first in order it is not proposed as first option during login:
Instead OTP is proposed as first option:
Only after clicking the Try Another Way
link to I see the WebAuthn option:
Upgraded Keycloak from 14.0.0
to 15.0.2
: https://github.com/status-im/infra-office/commit/601f2abd
I also found this issue: https://issues.redhat.com/browse/KEYCLOAK-13199
In a Passwordless WebAuthn deployment, it's typically the preferred option, with password + OTP as a fallback in case the user's browser doesn't support it.
However in Keycloak, manual administrator intervention is required to get the WebAuthn prompt to come first. The priority ordering in the Authentication flow configuration is apparently overridden by the user's own credential ordering, and the standard way of enrolling new users (setting a temporary password) always puts Password first.
This means that the ordering of executions in the flow does not affect the order the user sees.
There is also this: https://issues.redhat.com/browse/KEYCLOAK-13320
This explains why as admin I see the OTP first:
After moving WebAuthn up in the list it appeared first during login. But this is only doable by admin.
Which means, in theory, if I make the WebAuthn configuration required BEFORE OTP, that should fix it:
I've made our current required actions look like this:
I tested registration flow with Serhan and ti turns out if the Update Password
required action is not set to be a Default Action
the user is not prompted for it, and password is not set up:
So I adjusted it to be default:
Now the user is first prompted for the password:
And then for WebAuthn and alter for OTP, which results in the correct order:
Now, according to Serhan the setup we want should not include the user password.
Assuming WebAuthn is 2 factors(hardware + pin) If we count factors the different kinds of setup look like this:
user + pass
- 1 factor(user + pass) + (webauthn / otp)
- 3 or 2 factors(user + pass) + webauthn
- 3 factors(user + pass) + otp
- 2 factorsuser + webauthn + otp
- 3 factorsThe possible advantage of the last option is that when either of the two hardware devices is lost by a user they cannot log into the account anymore and recovery would require an Administrator intervention.
After discussing this with Security team in a call I think we should still retain the password, but treat it as a kind of backup/recovery code rather than a primary way of authentication. Instead we would still use the passwordless flow as default, but use the password for fallbacks where user is missing one of the devices.
So the flow we'd want would look like this:
This way we can cover a case in which someone has lost one of their devices and can't replace them.
There was a request for recovery/backup codes in Keycloak, but it was ignored: https://issues.redhat.com/browse/KEYCLOAK-6270
There exists a backup code extension but it's not part of the Keycloak distribution: https://github.com/thomasdarimont/keycloak-extension-playground/tree/master/auth-backup-codes https://groups.google.com/g/keycloak-dev/c/SC1JvewgLwM
So treating the password as a recovery code makes sense.
I tried this flow, but it only results in user being prompted for WebAuthn without any alternatives in UI:
I also tried this layout, but the result is the same:
Based on this documentation I think I will need to revamp the current Keycloak setup to not use master
realm:
https://www.keycloak.org/docs/latest/getting_started/#realms-and-users
It will make more sense to create a status-im
realm and use that to manage our applications separately.
This will also allow for more strict auth flow for the master
realm.
I was looking into using custom domain for the status-im
realm, so I could keep keycloak.status.im
for administration, but use auth.status.im
or login.status.im
for the status-im
realm. Here are some links:
Although this might be tricky to achieve.
I've added the auth.status.im
domain as alternative frontend for status-im
realm: https://github.com/status-im/infra-office/commit/5f8d94f8
So it's now available at: https://auth.status.im/auth/realms/status-im/account/
I can already see one issue with the realm domain:
When I try to create a Google Identity provider the redirect URL uses keycloak.status.im
:
I also configured SMTP via MailGun for both Keycloak Emails and it works. Will be necessary in the future for email verification.
I've also re-created the Camunda OAuth application, which was easy because it can be exported as a JSON:
Which then can be imported then creating a new one in a separate realm. But the secret gets regenerated. Unfortunately roles and groups had to be created by hand.
Unfortunately there is no built-in way to move users between realms, but it can be done with an SQL query: https://keycloak.discourse.group/t/moving-users-from-one-realm-to-another-realm/6257
But it doesn't look safe, and might break things.
I verfied that login into Camunda works with new status-im
realm and my test user:
When adding a realm one can use a JSON export from another realm:
But the JSON has to be edited by hand to change the ID and name of realm and all UUIDs:
Which means it's easy possible to make a test realm to try out new flows without messing up the orignal.
It actually complains about things like UUIDs of roles being imported:
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "constraint_a"
Detail: Key (id)=(770bbf51-f40b-4f94-b332-aa2a7d448969) already exists.
Although it is possible to not export them at all:
Here's a doc about exporting/importing using the CLI tool: https://github.com/keycloak/keycloak-documentation/blob/master/server_admin/topics/export-import.adoc
This doc shows an example of a flow that could help use design our own:
This flow ALMOST works, but it allows user to log in by using password twice...
Pretty dumb that it doesn't detect password has already been used.
I don't know if the flow we want is even possible with Keycloak without writing some custom conditional plugins.
I've created a thread on Keycloak Discourse asking about a "2 out of N" authentication flow:
https://keycloak.discourse.group/t/how-do-to-2-out-of-n-authentication-flow/10964
This video shows use of custom authenticator plugin: https://www.youtube.com/watch?v=u36QK9oyrtM
This is a nice intro into Keycloak that shows some event logging settings well: https://www.youtube.com/watch?v=XJYy6Aq-PJ8
Since configuring a password as fallback in "2 our of N" setup seems not doable in Keycloak I started looking at what happens if a user loses one of their credentials (otp or yubikey devices) and administrator has to remove them.
With this auth flow:
When I remove the OTP I get prompted to set it up again after logging in with just WebAuthn:
And if I remove the WebAuthn credential I get prompted to register a new device after logging in with OTP:
But the problem is, if I remove both, it prompts user to register both WITHOUT ANY IDENTITY VERIFICATION.
Ok, there is an alternative way to reset credentials, which is by sending an email with a reset link:
And it is possible to reset multiple credentials at the same time:
So in practice it should not be necessary to delete existing credentials as I did.
Though it still worries me that it allows login without any credentials if neither WebAuthn and OTP are configured.
We want to use WebAuthN standard for Authentication with KeyCloak.
This task is required to complete integrations with other services: