I'm trying to implement a custom keycloack Authenticator SPI for authentication purposes against an external Identity provider. The users already exist on the keycloak store, I only need connection to the custom SPI to authenticate them.
I'm following section 8.3 of the official guide https://www.keycloak.org/docs/latest/server_development/index.html#_auth_spi_walkthrough, which is very similar to what I need.
The problem I'm running into is that after the authentication flow runs into the "action" method of the custom Authenticator, an exception is thrown from the AuthenticationProcessor
Class, which after inspection, comes from following check:
// org.keycloak.authentication.AuthenticationProcessor - line 876
if (authenticationSession.getAuthenticatedUser() == null) {
throw new AuthenticationFlowException(AuthenticationFlowError.UNKNOWN_USER);
}
after seeing this problem, my idea for trying solving it, was getting the user (already verified against the externl Identity Provider) from the keycloak store, and pushing it into the AuthenticationSession, like this:
// Connect against external Service Provider
// and asume "USER_ID" represents an already validated User
// AuthenticationFlowContext = afc is given as parameter
UserFederationManager ufm = afc.getSession().users(); // <-- PROBLEM
UserModel userFound = ufm.getUserById("USER_ID", afc.getRealm());
if (userFound != null) {
// get reference to the authSession
AuthenticationSessionModel asm = afc.getAuthenticationSession();
// set authenticated user on the session
asm.setAuthenticatedUser(userFound );
return true;
}
return false;
The problem with the above code, is that a Java NoSuchMethodExceptionError is thrown regarding the users()
method of the org.keaycloak.models.KeycloackSession
class. Like this:
11:26:32,628 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-14) Uncaught server error: java.lang.NoSuchMethodError: org.keycloak.models.KeycloakSession.users()Lorg/keycloak/models/UserFederationManager;
Any suggestion that you could make to help me solve this would be greatly appreciated!
It seems the problem was that I was using an org.keycloak.models.UserFederationManager instance, instead of an org.keycloak.models.UserProvider instance. The UserFederationManager implements the UserProvider, and it seems the more general type works better than the more specific type under the injection mechanism this keycloak is using
// UserFederationManager ufm = afc.getSession().users(); // <-- PROBLEM
// UserProvider ufm = afc.getSession().users(); // <-- WORKS
Even though it works now, both of your suggestions are valid because my build version is indeed diferent that the one on the runtime, I'll solve that to avoid further Bugs.
Thanks your input Guys!