[keycloak-user] How to dynamically trigger a custom required action in a flow ?

GESLIN Fabrice fabrice.geslin-prestataire at laposte.fr
Tue Apr 30 03:43:29 EDT 2019


Hi Sébastien,

We’ve finally found the addRequiredAction() function with the String parameter and it works.

But we felt into a new issue due to the fact that the required actions are sometime handled sorted and sometime not sorted.

For instance, at the end of the authentication flow processing, when the required actions are processed, they are treated in an arbitrary order that doesn’t even correspond to the order in which they were added.  In Keycloak release 4.8.3.FINAL, The call stack leads to line 893 of org.keycloak.services.managers.AuthenticationManager that is:

    public static String nextRequiredAction(final KeycloakSession session, final AuthenticationSessionModel authSession,
                                            final ClientConnection clientConnection,
                                            final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
        final RealmModel realm = authSession.getRealm();
        final UserModel user = authSession.getAuthenticatedUser();
        final ClientModel client = authSession.getClient();

        evaluateRequiredActionTriggers(session, authSession, clientConnection, request, uriInfo, event, realm, user);

        if (!user.getRequiredActions().isEmpty()) {
            return user.getRequiredActions().iterator().next();
        }
        if (!authSession.getRequiredActions().isEmpty()) {
            return authSession.getRequiredActions().iterator().next();
        }

This causes the user to be redirected to the URI of the required action that has been arbitrarily selected. But when the browser GET the corresponding URI, the call stack reaches line 1045 of org.keycloak.services.managers.AuthenticationManager where the required actions are sorted according to their priorities or their names (?!?):


    protected static Response executionActions(KeycloakSession session, AuthenticationSessionModel authSession,

                                               HttpRequest request, EventBuilder event, RealmModel realm, UserModel user,

                                               Set<String> requiredActions) {



        List<RequiredActionProviderModel> sortedRequiredActions = sortRequiredActionsByPriority(realm, requiredActions);



        for (RequiredActionProviderModel model : sortedRequiredActions) {

            RequiredActionFactory factory = (RequiredActionFactory)session.getKeycloakSessionFactory().getProviderFactory(RequiredActionProvider.class, model.getProviderId());

            if (factory == null) {

                throw new RuntimeException("Unable to find factory for Required Action: " + model.getProviderId() + " did you forget to declare it in a META-INF/services file?");

            }

            RequiredActionContextResult context = new RequiredActionContextResult(authSession, realm, event, session, request, user, factory);

            RequiredActionProvider actionProvider = null;

            try {

                actionProvider = createRequiredAction(context);

            } catch (AuthenticationFlowException e) {

                if (e.getResponse() != null) {

                    return e.getResponse();

                }

                throw e;

            }

            actionProvider.requiredActionChallenge(context);

The side effect of this inconsistency is that in our case, where we’ve added a custom required action after the UPDATE_PASSWORD required action to the reset credential flow, the user is first redirected to the URI of our custom action (which is not what we expected) AND the form that is challenged to the user once redirected is the one from the UPDATE_PASSWORD action !

The question is how can we have the required actions that are added to a flow be processed according to the order in which they are added ?

Regards,

Fabrice Geslin

Groupe La Poste

De : Sebastien Blanc [mailto:sblanc at redhat.com]
Envoyé : lundi 29 avril 2019 14:35
À : GESLIN Fabrice <fabrice.geslin-prestataire at laposte.fr>
Cc : keycloak-user at lists.jboss.org
Objet : Re: [keycloak-user] How to dynamically trigger a custom required action in a flow ?

Hi,

When you says it does not accept it, you have an exception at runtime ? Because you have addRequiredAction(String string)

On Mon, Apr 29, 2019 at 12:13 PM GESLIN Fabrice <fabrice.geslin-prestataire at laposte.fr<mailto:fabrice.geslin-prestataire at laposte.fr>> wrote:
Hi,

We're trying to trigger a custom required action  as part of the reset credential.

For this we plan to mimic the implementation of the authenticate method of the org.keycloak.authentication.authenticators.resetcred.ResetPassword.java :

    @Override
    public void authenticate(AuthenticationFlowContext context) {
        if (context.getExecution().isRequired() ||
                (context.getExecution().isOptional() &&
                        configuredFor(context))) {
            context.getAuthenticationSession().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
        }
        context.success();
    }


But the question is what value should we pass to the addRequiredAction() ?

This method seems to only accept the predefined required actions mapped to the values from the  UserModel.RequiredAction enum.

Any help is welcome .

Fabrice Geslin

Groupe La Poste

Post-scriptum La Poste

Ce message est confidentiel. Sous reserve de tout accord conclu par
ecrit entre vous et La Poste, son contenu ne represente en aucun cas un
engagement de la part de La Poste. Toute publication, utilisation ou
diffusion, meme partielle, doit etre autorisee prealablement. Si vous
n'etes pas destinataire de ce message, merci d'en avertir immediatement l'expediteur.
_______________________________________________
keycloak-user mailing list
keycloak-user at lists.jboss.org<mailto:keycloak-user at lists.jboss.org>
https://lists.jboss.org/mailman/listinfo/keycloak-user

Post-scriptum La Poste

Ce message est confidentiel. Sous reserve de tout accord conclu par
ecrit entre vous et La Poste, son contenu ne represente en aucun cas un engagement de la part de La Poste. Toute publication, utilisation ou diffusion, meme partielle, doit etre autorisee prealablement. Si vous n'etes pas destinataire de ce message, merci d'en avertir immediatement
l'expediteur.


More information about the keycloak-user mailing list