Hi. I was able to successfully maintain the template and edit the error
code using your instructions (thanks again!) but unfortunately bumped into
another snag.
Imagine the scenario where you want to log into Keycloak using your Google
credentials. If you have multiple Google accounts, Google will ask you
which one you want to use. If you accidentally choose the wrong one, my
custom authenticator script will notice that there is no corresponding
email address in Keycloak, deny login and give you the custom message. So
far so good.
The problem arises when the user clicks the Google option again from the
resulting custom error page but on the next attempt selects the correct
Google account. The user should log in normally, but instead I'm getting an
error message: "Unexpected error when authenticating with identity
provider". It's like the session has somehow been poisoned, even though I
added context.clearUser(); context.resetFlow(); to the script.
Here is the full script, in case anybody has any ideas on how to reset the
flow successfully.
function myError(context) {
return context.form().setError("You must have an existing account to log in
via Google.", []).createLogin();
}
AuthenticationFlowError =
Java.type("org.keycloak.authentication.AuthenticationFlowError");
SerializedBrokeredIdentityContext =
Java.type("org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext");
AbstractIdpAuthenticator =
Java.type("org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator");
Response = Java.type("javax.ws.rs.core.Response");
MediaType = Java.type("javax.ws.rs.core.MediaType");
users = session.users().getUsers(realm, false);
//LOG.info("users = " + users);
function authenticate(context) {
var serializedCtx =
SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession,
AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
var biCtx = serializedCtx.deserialize(session, authenticationSession);
var idpUsername = biCtx.username;
LOG.info("username = " + idpUsername);
LOG.info("alias = " + biCtx.idpConfig.alias);
for(var u in users) {
//LOG.info("u = " + users[u].getEmail());
if(idpUsername===users[u].getEmail()) {
context.success();
return;
}
}
var response2 = myError(context);
context.clearUser();
context.resetFlow();
context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, response2);
return;
}
On Mon, 17 Dec 2018 at 04:45, Dmitry Telegin <dt(a)acutus.pro> wrote:
Hi Geoffrey, you're welcome :)
As for embedding custom error messages into existing templates, I suggest
that you check out the following thread:
http://lists.jboss.org/pipermail/keycloak-user/2018-December/016669.html
Please let me know if it works for you.
Cheers,
Dmitry
On Fri, 2018-12-14 at 11:49 +0100, Geoffrey Cleaves wrote:
> Thanks Dmitry, I never in a 1000 years would have figured this out.
>
> My goal with all of this is to only allow a user to log in with Google
(or other provider) if there is already an account created with the same
email address. My code below works, but instead of returning an entire
custom page on failure, it would be nice to use the existing template with
simply a different text. I hate to abuse of your free time, but if you have
any tips for that I would be most appreciative.
>
> AuthenticationFlowError =
Java.type("org.keycloak.authentication.AuthenticationFlowError");
>
> // take a look at org.keycloak.broker.provider.BrokeredIdentityContext
to figure out what else you can obtain from that object.
>
> SerializedBrokeredIdentityContext =
Java.type("org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext");
> AbstractIdpAuthenticator =
Java.type("org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator");
> Response = Java.type("javax.ws.rs.core.Response");
> MediaType = Java.type("javax.ws.rs.core.MediaType");
> response = Response.status(401).entity("<h1>You must have an existing
account to log in.</h1>").type(MediaType.TEXT_HTML_TYPE).build();
> users = session.users().getUsers(realm, false);
>
> function authenticate(context) {
> var serializedCtx =
SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession,
AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
> var biCtx = serializedCtx.deserialize(session,
authenticationSession);
> var idpUsername = biCtx.username;
> LOG.info("username = " + idpUsername);
> LOG.info("alias = " + biCtx.idpConfig.alias);
>
> for(var u in users) {
> //LOG.info("u = " + users[u].getEmail());
> if(idpUsername===users[u].getEmail()) {
> context.success();
> return;
> }
> }
>
> context.failure(AuthenticationFlowError.USER_DISABLED, response);
> return;
> }
>
>
> > On Fri, 14 Dec 2018 at 01:34, Dmitry Telegin <dt(a)acutus.pro> wrote:
> > Hello Geoffrey,
> >
> > I was right about to click Send when I finally noticed that statement
in parentheses :-D you were 100% right, what else can I say :)
> >
> > Here we go, try this snippet:
> >
> > SerializedBrokeredIdentityContext =
Java.type("org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext");
> > AbstractIdpAuthenticator =
Java.type("org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator");
> >
> > function authenticate(context) {
> >
> > var serializedCtx =
SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession,
AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
> >
> > var biCtx = serializedCtx.deserialize(session,
authenticationSession);
> >
> > LOG.info(biCtx.username);
> > LOG.info(biCtx.idpConfig.alias);
> >
> > context.success();
> >
> > }
> >
> > Also take a look at
org.keycloak.broker.provider.BrokeredIdentityContext to figure out what
else you can obtain from that object.
> >
> > Good luck :)
> > Dmitry Telegin
> > CTO, Acutus s.r.o.
> > Keycloak Consulting and Training
> >
> > Pod lipami street 339/52, 130 00 Prague 3, Czech Republic
> > +42 (022) 888-30-71
> > E-mail: info(a)acutus.pro
> >
> > On Thu, 2018-12-13 at 14:31 +0100, Geoffrey Cleaves wrote:
> > > Hello. I have a simple JS execution which denies access as the first
step
> > > of the first broker login flow. I would like to access some of the
> > > attributes that Keycloak writes out to the log when executing this
flow
> > > (see below)
> > >
> > > What objects or variables must my JS execution load in order to get
the
> > > identity_provider_identity attribute listed below?
> > >
> > > 20:29:56,588 WARN [org.keycloak.events] (default task-527)
> > > type=IDENTITY_PROVIDER_FIRST_LOGIN_ERROR, realmId=re, clientId=tblic,
> > > userId=null, ipAddress=90., error=user_not_found,
identity_provider=google,
> > > auth_method=openid-connect, redirect_uri=
http://localhost:8222?clientid=tic,
> > > > > identity_provider_identity=user(a)gmail.com, code_id=b07317fdb
> > >
> > > Thanks in advance!
> > >
> > > Geoff
> > > _______________________________________________
> > > keycloak-user mailing list
> > > keycloak-user(a)lists.jboss.org
> > >
https://lists.jboss.org/mailman/listinfo/keycloak-user
> >
>
>
> --
>
> Regards,
> Geoffrey Cleaves
>
>
>
>
>