-
-
Notifications
You must be signed in to change notification settings - Fork 335
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
Add ability to force MFA on OIDC Logins #971
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this enhancement!
For what it is worth, I am a contributor but not part of Grist Labs, my review is advisory and the merge has to be done by an employee. I proposed some comments with the hope they may be useful.
I will try using deploying OIDC + MFA to test your PR.
cssErrorText(t("Multi-factor-authentication is required for accessing this site, but it is not set up on your \ | ||
account. Please enable it and try again.")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest avoiding the \
at the end of a string, it is not standard JS (or is it required for the translation key collection?).
cssErrorText(t("Multi-factor-authentication is required for accessing this site, but it is not set up on your \ | |
account. Please enable it and try again.")), | |
cssErrorText(t("Multi-factor-authentication is required for accessing this site, but it is not set up on your " + | |
"account. Please enable it and try again.")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The plus should work as well, you're right. I'll test it later this week.
"Multi-factor authentication required{{suffix}}": "Multi-Faktor-Authentifizierung nötig{{suffix}}", | ||
"Multi-factor-authentication is required for accessing this site, but it is not set up on your account. Please enable it and try again.": "Für den Zugriff auf diese Website ist Multi-Faktor-Authentifizierung erforderlich. Diese ist nicht in Ihrem Konto eingerichtet. Bitte richten Sie sie ein und versuchen Sie es erneut.", | ||
"Set up Multi-factor authentication": "Multi-Faktor-Authentifizierung einrichten", | ||
"Try again": "Erneut versuchen" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the localization, but could you do them through Weblate instead, please:
https://github.com/gristlabs/grist-core/blob/main/documentation/translations.md
Co-authored-by: Florent <[email protected]>
cssButtonWrap(bigPrimaryButtonLink( | ||
t("Set up Multi-factor authentication"), | ||
{href: getGristConfig().mfaSettingsUrl, target: '_blank'}, | ||
testId('error-setup-mfa') | ||
)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of showing that property only when getGristConfig().mfaSettingsUrl
is filled with some value? This way, GRIST_OIDC_SP_MFA_SETTINGS_URL
would be optional even when GRIST_OIDC_SP_FORCE_MFA
is set.
cssButtonWrap(bigPrimaryButtonLink( | |
t("Set up Multi-factor authentication"), | |
{href: getGristConfig().mfaSettingsUrl, target: '_blank'}, | |
testId('error-setup-mfa') | |
)), | |
getGristConfig().mfaSettingsUrl ? cssButtonWrap(bigPrimaryButtonLink( | |
t("Set up Multi-factor authentication"), | |
{href: getGristConfig().mfaSettingsUrl, target: '_blank'}, | |
testId('error-setup-mfa') | |
)) : null, |
suffix: getPageTitleSuffix(getGristConfig()) | ||
}); | ||
|
||
const searchParams = new URL(location.href).searchParams; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking: you can otherwise use the URLSearchParams
class:
const searchParams = new URL(location.href).searchParams; | |
const searchParams = new URLSearchParams(location.search); |
} | ||
|
||
res.redirect(`/login/error/mfa-not-enabled?next=${targetUrlRelative}`); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In another PR, I made something that may be of some help :
- the changes in the backend: https://github.com/gristlabs/grist-core/pull/883/files#diff-ee4d5464063d6cfc9dc24b7b63d8858ff7b978dbe767ad2a712c93fe52f7ca1dR229-R248
- the changes in the frontend (you can see how I made the button to allow the user to login again, no need to retrieve particular data from the backend, so you would not need to pass the
next
param): https://github.com/gristlabs/grist-core/pull/883/files#diff-6d05e89e392b7fe826b41130d739c6b32c40abe5bb59f4e31a6404bd1faba0c3R102
I hope my PR will be merged soon and that you could benefit from the changes.
You could still create another error page specifically for MFA.
However, I do not take advantage of the next
param, and I do not see yet how to pass it using _sendAppPage
. Is it something we would like to have absolutely? I tend to think it does not probably bring much discomfort (at least compared to the error itself).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested your work, it works fine, thanks. Still some changes I suggest regarding your PR, with the hope that my suggestions are clear, relevant and may help.
* be determined by OIDC's amr claim: It must include "mfa". Make sure that the IDP returns the amr claim | ||
* correctly, otherwise authentication will fail. | ||
* env GRIST_OIDC_SP_MFA_SETTINGS_URL | ||
* This is needed when GRIST_OIDC_SP_FORCE_MFA is set to true. Enter the URL where the user will be able to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you agree with my suggestion above, don't forget to adapt the comment here :).
@pr0gr8mm3r I have my PR #883 merged, your PR has some conflicts. I would be glad to help, don't hesitate to ask if you need! |
@pr0gr8mm3r Any news on this work? If you need help, please don't hesitate. |
Hey @fflorent, been quite busy recently, and I currently don't have time to look. Please excuse my late reply. If you want to keep the PRs-list clean, feel free to close it. I'll open another one once I've gotten time to work on it again. |
@pr0gr8mm3r No worry, thanks for your reply! Do you want me to resume your work? (Keeping crediting you for the first commits) I am OK with both options: waiting or resuming your work. |
If you have time, that'd be great! Feel free to continue :) |
This PR implements the ability to force users logging in through OIDC to have Multi-factor authentication enabled. It does this by looking at the
amr
claim provided by the IDP. This claim must contain themfa
value. Make sure that the IDP returns the amr claim correctly, otherwise authentication will fail.Two new env vars have been added:
If set to "true", the user will be forced to have multi-factor authentication enabled.
This is needed when GRIST_OIDC_SP_FORCE_MFA is set to true. Enter the URL where the user will be able to configure Multi-factor authentication on their account. This will be shown in the UI if the user does not have MFA enabled.
How to test:
Using Keycloak, it's fairly hard to add the
amr
claim, but Zitadel returns it by default. To test, create a new account on their cloud offering, hook it up to Grist and setGRIST_OIDC_SP_FORCE_MFA
totrue
.Log in without MFA enabled and get an error page.