Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@graziang
Copy link
Contributor

@graziang graziang commented Jul 4, 2024

If a required action was successful or ignored in RequiredActionProvider.requiredActionChallenge() (like the VERIFY_EMAIL action on an already verified email), the following actions were skipped.

I just have a doubt if the current behavior of ignoring the action in case of a null email in the VERIFY_EMAIL action is correct, or if the user should be stopped with a message indicating that the email is not present and therefore not verified.

Closes #31014

Copy link
Contributor

@rmartinc rmartinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@graziang There are failures in FIPS that (I think) are related as the stacktrace seems to show the modified method. My feeling is that you need to separate the ignore in a different else if. But not tested. 😄

return context.getChallenge();
}
else if (context.getStatus() == RequiredActionContext.Status.SUCCESS) {
else if (context.getStatus() == RequiredActionContext.Status.SUCCESS || context.getStatus() == RequiredActionContext.Status.IGNORE) {
Copy link
Contributor

@rmartinc rmartinc Jul 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be move the ignore in a different if and do the next only in that situation? Something like:

diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 10fd0e7523..847341149f 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -1279,6 +1279,10 @@ public class AuthenticationManager {
             authSession.setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, model.getProviderId());
             return context.getChallenge();
         }
+        else if (context.getStatus() == RequiredActionContext.Status.IGNORE) {
+            authSession.getAuthenticatedUser().removeRequiredAction(factory.getId());
+            authSession.removeRequiredAction(factory.getId());
+            return nextActionAfterAuthentication(session, authSession, session.getContext().getConnection(), request, session.getContext().getUri(), event);
+        }
         else if (context.getStatus() == RequiredActionContext.Status.SUCCESS) {
             event.clone().event(EventType.CUSTOM_REQUIRED_ACTION).detail(Details.CUSTOM_REQUIRED_ACTION, factory.getId()).success();
             // don't have to perform the same action twice, so remove it from both the user and session required actions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case where a user has already verified their email, and for some reason you add the VERIFY_EMAIL and webauthn-register (or any other action with low priority) action to the user, the webauthn-register action would be skipped because of context.success() here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Ok, the failure in fips was that the verify email was re-added all the time. OK. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe then if ignored the event should not be added. I don't think we shoukd report an event if verify_email is ignored. The next line. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, ok about not reporting the event.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking if it would be better to let it fail in any case if the email is null instead of ignoring it, because otherwise if you manually add the required action to the user the behavior between the the two flows would still be different

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks that is general fix for all required which call context.success(); from requiredActionChallenge(final RequiredActionContext context)

context.success(); from requiredActionChallenge(final RequiredActionContext context)

@rmartinc Is it ok for you, are you going to approve this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do the same in both situations. The condition for evaluateTriggers is context.getRealm().isVerifyEmail() && !context.getUser().isEmailVerified() so I would do the same for requiredActionChallenge. The action should not pass if the email is blank but the realm is configured to verify email. I think it's the less disruptive decision. But, as you say, we can also decide to always fail if the action is assigned and the email is blank (but maybe you need to change tests).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@radoslawsyga We need to take a decision about what to do with the verify email action. There is a test that is failing right now. It will be approved and merged when ready.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the PR to always fail if the action is assigned and the email is blank. Tests look OK

Copy link
Contributor

@rmartinc rmartinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @graziang! LGTM! It's a bit of a change but it makes sense in IMHO. Besides actions update profile and verify email can be added to a user to force the email update and the verify.

Copy link
Contributor

@mposolda mposolda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@graziang @rmartinc Thanks for the PR and the review.

I have some doubts as this is quite backwards incompatible change. I've tried to test the scenario like this:

  • New realm test is created
  • Admin switches Verify Email to ON for that realm
  • Admin creates user john with some password and without email (This is possible as email is not required user-profile attribute for administrators by default. It is required just for the regular users)
  • Attempt to login as john . Now I see the error message that email is not set. Moreover user does not have any chance to set his email, so he would be completely stuck at this moment.

I would expect the behaviour for that scenario that after login with username/password user is first required to update his profile (because of Verify profile required action, which was triggered due the email attribute missing) and then email verification required as next step. I've checked that was the behaviour in Keycloak 24.

Do we need to keep the changes in the behaviour in the VerifyEmail class? If we need (which I am not sure), how to make sure that behaviour would be correct (ideally same as in Keycloak 24)?

Maybe one option is that we can make sure that Verify Profile action is before Verify Email action. This will require changing the behaviour for new realms, but also migration as it will need to be updated for existing realms migrated from previous versions (which can be complicated as I am not sure if Verify Profile action is set and enabled by default for the deployments like Keycloak 22 where user-profile was not yet enabled by default). Do we have any better option then tricky migration changes?

@rmartinc
Copy link
Contributor

rmartinc commented Jul 16, 2024

The change in verify email was needed, because if not there was a loop (the evaluate triggers added the action but it was ignored later). My feeling is that the different order in the verify profile and verify email is triggered by the other PR, now the order is exactly specified by the priority in the actions.

I have done some tests with 24.0.5 (I had not done this before):

  • If verify email and profile are set in the realm but the user has no email, the order is the one @mposolda commented (first verify profile and then verify email).
  • If verify email is set in the realm but no verify profile, no action is presented to the user, it logs in directly. So verify email is not executed.

So maybe we should do the following to emulate better the previous behavior (which it's not perfect either):

  • Ignore the verify email if the email is not set. So not modifying the requiredActionChallenge and just ignore if Validation.isBlank(email).
  • Also add this in the evaluateTriggers, do not add the action if the user has no email. This way, the two previous uses are the same. Don't know if some test will fail this way (IIRC there were test errors when login via direct access grants or client credentials, probably because now it's accepted and previously was not accepted).

WDYT? If you don't like that the only way (I have seen) is modifying priorities in the upgrade for the actions.

@mposolda
Copy link
Contributor

mposolda commented Jul 16, 2024

@rmartinc +1 to make sure that behaviour is the same as in Keycloak 24.0.5 for both cases when Verify Email option is enabled and:

  • If Verify Profile required action is enabled, then ask user to fill his email first and then require to verify the email
  • If Verify Profile required action is disabled (or not present), then ignore Verifying Email and let the user to login

Can be also good to make automated tests for those scenarios IMO (if not already present).

From the options you proposed, any of them is OK IMO as long as we have the behaviour as in Keycloak 24. Both are better than changing the order of required actions IMO (due the migration and the possible issues related to that...).

Maybe another option is to not do any changes in the VerifyEmail, but instead do something to make sure that context.ignore() is handled better by the framework and there is no infinite loop? But maybe that is more tricky than the options you proposed, not sure...

@rmartinc
Copy link
Contributor

@graziang I'm working on this, forget about it for noe! 😄

@graziang
Copy link
Contributor Author

@rmartin @mposolda thanks for the review and all the suggestions! IMO the Verify Email action should not be ignored if the email is not set and also not verified when Verify Email is enabled on the realm. Probably the best solution would be that after login with username/password, the user is first required to update their profile (because of the Verify Profile required action, which was triggered due to the missing email attribute) and then verify email required as the next step. This is the behavior with Keycloak 24.0.5.

On the other hand, I agree with Ricardo's proposed solution that it is better than changing the order of required actions because of the migration and the possible issues. @rmartinc feel free to continue the work

@rmartinc
Copy link
Contributor

Superseded by #31358.

@rmartinc rmartinc closed this Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Verify Email" may cause other Required Actions to be ignored

4 participants