adorsys / keycloak-config-cli

Import YAML/JSON-formatted configuration files into Keycloak - Configuration as Code for Keycloak.
Apache License 2.0
780 stars 140 forks source link

AuthenticationFlow with script execution import not work #854

Open michaelottofits opened 1 year ago

michaelottofits commented 1 year ago

Current Behavior

when i import a realm with authenticationflow i get an error.

Error Message: Cannot create execution '' for non-top-level-flow 'myclientflow forms' in realm 'myrealm': HTTP 400 Bad Request

Sample Part of import sample.yaml

---
realm: "myrealm"
 displayName: "wallis" 
 displayNameHtml: "<div class=\"kc-logo-text\"><span>Keycloak</span></div>"
 enabled: true
authenticationFlows:
  - id: xxxx-xxx-xxx-xx-xxx
    alias: myclientflow
    description: browser based authentication
    providerId: basic-flow
    topLevel: true
    builtIn: false
    authenticationExecutions:
      - authenticator: auth-cookie
        authenticatorFlow: false
        requirement: DISABLED
        priority: 0
        autheticatorFlow: false
        userSetupAllowed: false
      - authenticator: auth-spnego
        authenticatorFlow: false
        requirement: DISABLED
        priority: 1
        autheticatorFlow: false
        userSetupAllowed: false
      - authenticator: identity-provider-redirector
        authenticatorFlow: false
        requirement: ALTERNATIVE
        priority: 2
        autheticatorFlow: false
        userSetupAllowed: false
      - authenticatorFlow: true
        requirement: ALTERNATIVE
        priority: 3
        autheticatorFlow: true
        flowAlias: confluencetest jiraprod jiratest Grafana forms
        userSetupAllowed: false
  - id: xxxxxxx-xxxx-xxx-xxxx-xxxxx
    alias: myclientflow forms
    description: Username, password, otp and other auth forms.
    providerId: basic-flow
    topLevel: false
    builtIn: false
    authenticationExecutions:
      - authenticator: auth-username-password-form
        authenticatorFlow: false
        requirement: REQUIRED
        priority: 0
        autheticatorFlow: false
        userSetupAllowed: false
      - authenticatorConfig: myclientflow
        authenticator: script-myclientflow.js
        authenticatorFlow: false
        requirement: REQUIRED
        priority: 1
        autheticatorFlow: false
        userSetupAllowed: false
authenticatorConfig:
  - id: xxxxxx-xxx-xxx-xx-xxxxxxxxxx
    alias: myclientflow
    config:
      scriptName: script-myclientflow.js
      scriptCode: >-
        /*
         * Template for JavaScript based authenticator's.
         * See org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory
         */

        // import enum for error lookup

        AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");

        /**
         * An example authenticate function.
         *
         * The following variables are available for convenience:
         * user - current user {@see org.keycloak.models.UserModel}
         * realm - current realm {@see org.keycloak.models.RealmModel}
         * session - current KeycloakSession {@see org.keycloak.models.KeycloakSession}
         * httpRequest - current HttpRequest {@see org.jboss.resteasy.spi.HttpRequest}
         * script - current script {@see org.keycloak.models.ScriptModel}
         * authenticationSession - current authentication session {@see org.keycloak.sessions.AuthenticationSessionModel}
         * LOG - current logger {@see org.jboss.logging.Logger}
         *
         * You one can extract current http request headers via:
         * httpRequest.getHttpHeaders().getHeaderString("Forwarded")
         *
         * @param context {@see org.keycloak.authentication.AuthenticationFlowContext}
         */
        function authenticate(context) {

            var username = user ? user.username : "anonymous";
            LOG.info(script.name + " trace auth for: " + username);

            var authShouldFail = true;

            for each (var role in user.getRoleMappings()) 
            {

              //if(role.getName().startsWith("Log"))
              if(role.getName().indexOf('myclient') !== -1)
              {
                 authShouldFail = false;  
              }
            }

            if (authShouldFail) {

                context.failure(AuthenticationFlowError.INVALID_USER);

                return;
            }

            context.success();
        }
      scriptDescription: myclient

Expected Behavior

No response

Steps To Reproduce

1. create Keycloak X Image with 19.0.1 and build myclientflow.js into jar and add to provider folder
3. start keycloak in a docker container
2. try to import with java -jar keycloak-config-cli-19.0.1.jar --keycloak.url=http://localhost/auth  --keycloak.user=*** --keycloak.password=***  --import.files.locations=sample.yaml

Environment

Anything else?

No response

sonOfRa commented 1 year ago

As far as I'm aware, this requires the removed "upload_scripts" feature. Scripts can no longer be uploaded directly via a configuration change into keycloak. The only way to use JS authenticators now is the "scripts" feature, which requires the script to be present in your providers.jar.

See https://www.keycloak.org/2022/04/keycloak-1800-released for information on the removal of upload_scripts.

And here's more information on how to deploy script based authenticators, without supplying the .js files as configuration: https://www.keycloak.org/docs/latest/server_development/#_script_providers