<div dir="ltr"><div class="gmail_extra"><span id="docs-internal-guid-3d082e9a-cae7-c093-0220-b6eec243ac35"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Thanks :)</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap"><br></span></p><p style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap">Sorry for the rather long mail - steps to demo are first, for some additional thoughts see below.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Is there any chance of having a 1.10.x release line?</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">if you want to try it out you could apply this patch against a new branch from current master:</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"><a href="https://github.com/thomasdarimont/keycloak/commit/3f39479e7fa0c75941cd524ba99de5c85db43b62.patch">https://github.com/thomasdarimont/keycloak/commit/3f39479e7fa0c75941cd524ba99de5c85db43b62.patch</a></span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">then just start the org.keycloak.testsuite.KeycloakServer.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">In the admin-console you need to do the following:</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">1) copy the browser authentication flow to &quot;browser script&quot;</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">2) in the &quot;browser script forms&quot; subflow click on Actions -&gt; Add execution</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">3) select &quot;Script based authentication&quot; from the list</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">4) Mark &quot;Script based authentication&quot; as required</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">5) configure &quot;Script based authentication&quot; via actions -&gt; config</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">6) as config parameters use</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Alias: auth-tracer-script (this is later shown in the auth flow listing)</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Script Engine: Nashorn</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">ScriptName: auth-tracer</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Script:</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">function authenticate(context){</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">  </span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">  LOG.info(scriptName + &quot; --&gt; trace auth for: &quot; + user.username);</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">  context.success();</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">}</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">function action(context){</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">  context.attempted();</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">}</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">7) Save the authenticator</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">8) Goto bindings tab and set the browser flow to &quot;browser script&quot;.</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">9) end.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">I usually create a test user to play with this.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">I&#39;m keen to get this done since we need to be rather flexible regarding auth logic.</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Btw. the Auth0 rules repository is a great example for what can be done with this feature:</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><a href="https://github.com/auth0/rules" style="text-decoration:none"><span style="font-size:14.6667px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">https://github.com/auth0/rules</span></a></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Some things to consider:</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"># Use cases</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">I think scripting should not only be applied for authenticators but also for other components like: event listeners, federation-providers, even custom user action scripts that are performed on login / logout / account / profile updates also configurable validation scripts would be helpful.</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><a href="https://issues.jboss.org/browse/KEYCLOAK-1872?jql=project%20%3D%20KEYCLOAK%20AND%20text%20~%20%22forgerock%22" style="text-decoration:none"><span style="font-size:14.6667px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">https://issues.jboss.org/browse/KEYCLOAK-1872?jql=project%20%3D%20KEYCLOAK%20AND%20text%20~%20%22forgerock%22</span></a></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"># Implementation</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">In my naive implementation I just externalized the authenticate(..) and action(..) method.</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">I think it might be easier for users to have dedicated scriptable authenticators (or rather authentication steps? since they only participate in the authentication but might not decide or authenticate anything...) e.g. ones that just perform some enrichment of the user model, additional tracing etc. others could be more complex by conditionally showing forms, using the providers to send codes (email, sms) etc. </span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">In my POC I exposed a bunch of context variables to the script:</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><a href="https://github.com/thomasdarimont/keycloak/commit/3f39479e7fa0c75941cd524ba99de5c85db43b62#diff-50db206e6dcd6842014f5be864e6c895R89" style="text-decoration:none"><span style="font-size:14.6667px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">https://github.com/thomasdarimont/keycloak/commit/3f39479e7fa0c75941cd524ba99de5c85db43b62#diff-50db206e6dcd6842014f5be864e6c895R89</span></a></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">One should either be very selective here or just hand in securable wrappers that would allow to control access from scripts to context objects.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Allowing users to writing / editing scripts in the admin frontend is great but it would be more helpful if those scripts could be loaded from an external directory that would allow a proper versioning of the scripts outside of keycloak.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Having a ScriptingProvider capable of loading / saving scripts and executing scripts against a provided context would be useful. Within the scriptable components one would then just refer to a script from a “Script Repository”.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">A script should have metadata like a script name, comment, script source, perhaps vcs information.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"># Security</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Offering scripting support of course opens the door to all kind of bad things - I don’t think that my initial assumption “scripts will probably only be specified by administrators and executed on the server…” will hold for long ;-)</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Soner or later one probably needs some sort of sandbox concept here - the Auht0 guys do this:</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">“For security reasons, the Rules code runs in a JavaScript sandbox based on <a href="http://webtask.io">webtask.io</a> where you can use the full power of the ECMAScript 5 language.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">For a list of currently supported sandbox modules, see: Modules Supported by the Sandbox.”</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"># UX for Script Support</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">I think users needs both syntax highlighting and linenumbers for readable scripts both are provided by the currently used ace editor (</span><a href="https://ace.c9.io/#nav=about" style="text-decoration:none"><span style="font-size:14.6667px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">https://ace.c9.io/#nav=about</span></a><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"> )- another popular option would have been codemirror (</span><a href="http://codemirror.net/" style="text-decoration:none"><span style="font-size:14.6667px;font-family:Arial;text-decoration:underline;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">http://codemirror.net/</span></a><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">) but personally I found it easier to integrate ace.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Within the admin console it should be possible to view a script in read-only mode - perhaps this should be the default when opening a component like an authenticator. editing should be enabled via a checkbox or on/off-switch.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">The ace editor support could be used to render a highlighted (read-only) version of JSON (client install) and XML (SAML) configuration.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">We need to find a way to parameterize the ace editor for various other &quot;script&quot; types to get proper highlighting (used in kc-provider-config.html -&gt; mode: xxxx) - perhaps” code” would be a more generic type than &quot;script&quot;. </span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">It would really help to have some server-side validation being performed on save of an authenticator (or any other object), validation errors should be propagated to the frontend and shown near the &quot;culprit&quot;.</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"># Documentation</span></p><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">The user guide should include a section about scripting support in general. </span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Some examples should show the usage of scripting support, e.g. an authenticator, an event listener.</span></p><br><br><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Cheers,</span></p><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt"><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent">Thomas</span></p><div><span style="font-size:14.6667px;font-family:Arial;vertical-align:baseline;white-space:pre-wrap;background-color:transparent"><br></span></div></span></div></div>