Set which user can authenticate at which client
by Remko Lodder
Hi,
I am new to Keycloak and first of all I would like to thank you and all contributors for all your hard work.
I have little experience with Keycloak and it’s usage so please put me on the correct track in case I am off :-)
So: For a customer and my own environment I am implementing Keycloak. I am consolidating our users in one
Realm and have added a multitude of clients (both saml as oidc). I would like to be able to place selectors on users
when importing them or setting it manually, that someone has access to for example gitlab. I found that Okta has
probably want I am looking for described here:
https://help.okta.com/en/prod/Content/Topics/Directory/group-assign-app.htm <https://help.okta.com/en/prod/Content/Topics/Directory/group-assign-app.htm>
Now, is there something like that also in Keycloak? I would like users to be part of a group, or role, or whatever
and that way control who has access where, without needing to fiddle with the application on the back (I can do
that for targetting specific roles, like admin, manager, read-write, read-only, etc).
I was not able to find something similar .. so probably I overlooked it or didn’t understand the documentation :-)
Any pointers/suggestions/this is not an option right now?
Thanks & Again, thank you all,
Remko
6 years, 10 months
RPT tokens can still be used after approval revokation
by Rivat Olivier
Hi,
I have the following use case
1) alice is creating some resouces (a5 for example)
2) jdoe is asking to access a5
3) alice approves request for Jdoe to access a5
4) Jdoe is getting an rpt token and now can access to a5 (so far so good)
5) Alice is revoking Jdoe access right for a5
6) RPT token of Jdoe is still valid (it has no yet expired)
---> Joe can access to alice a5 resource without any problem
For me it sounds like a bug. I was expecting Jdoe no longer being able
to access alice A5 resource (after revokation from alice).
Regards,
Olivier
6 years, 10 months
(UMA) How is it possible to approve pending request via REST API calls
by Rivat Olivier
Hi,
I am playing with auth_uma_photoz example.
1. I have created some album resources for alice (album a5).
2. Jdoe has made a request to access to alice album
3. Through Rest API calls, I can see that there is a pending request on
a5 resource owned by alice
access_token_alice=$(curl -d "client_id=photoz-restful-api" -d
"client_secret=secret" -d "username=alice" -d "password=alice" -d
"grant_type=password"
http://localhost:8180/auth/realms/photoz/protocol/openid-connect/token |
jq -r .access_token)
curl
http://localhost:8180/auth/realms/photoz/authz/protection/permission/tick...
-H 'Authorization: Bearer '$access_token_alice | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 258 100 258 0 0 86000 0 --:--:-- --:--:-- --:--:--
86000
[
{
"id": "29505d42-da8d-46f5-afe2-f90e35845192",
"owner": "11f3314e-f1c6-40a9-912b-d6f9d0c5a177",
"resource": "dee953ef-1df8-4787-9d32-ce4e407da010",
"scope": "0dc735d5-1ecc-466d-ba9e-e59f8ad563e4",
"granted": false,
"requester": "dceb398e-9f68-4077-8073-ca53137cccb3"
}
]
So my question:
What should be the command syntax to approve this request from Jdoe (I.e
set "granted":true) using teh REST API.
I have made several trials, quite unsuccessful, and haven't found any
hint in the keycloak doc.
Regards,
Olivier
6 years, 10 months
Support for totp in REST client (org.keycloak.admin.client.Keycloak)
by Lukasz Lech
Hello,
I was under impression, that activating TOTP will makes the account unable to use with REST api, but then I've found that people describe how to do that and that is actually supported through 'totp' parameter to the API call.
The parameter would have to be added to org.keycloak.admin.client.token.TokenManager:grantToken() method. Rather through some interface for TOTP generator than the one-time code.
Were there already any plans to extend the library (keycloak-admin-client) to support TOTP?
To my understanding the code like that should work:
if (PASSWORD.equals(accessTokenGrantType)) {
form.param("username", config.getUsername())
.param("password", config.getPassword());
if (config.getTotpGenerator() != null) {
form.param("totp", config.getTotpGenerator().getToken());
}
}
The caller would have to provide the implementation of TotpGenerator compliant with Keycloak settings and set the secret from otp configuration QR code...
Best regards,
Lukasz Lech
6 years, 10 months
Disable logging in via REST API
by Lukasz Lech
Hello,
How to disable logging into Keycloak via REST API, without affecting logging in via browser?
Which URLs I need to block?
I have problem finding out that information...
Best regards,
Lukasz Lech
6 years, 10 months
Permission Handling After Keycloak 4.5.0
by Jahn, Lasse
Hey everyone,
I'm running Keycloak Server Version 4.5.0.Final according to the dockerfile from jboss shown in the dockerhub [1] with only changed keycloak version. (Took the tools from [2])
During developing I noticed that there is an Endpoint missing that I wanted to use (request a group list which have specific client role, for users this enpoint exists
GET /{realm}/clients/{id}/roles/{role-name}/users
In Keycloak 6.0 this also exists for groups.
GET /{realm}/clients/{id}/roles/{role-name}/groups
So I thought why not migrating to 6.0. After successful upgrade I realized that there is no permission tab?!
I wanted to handle the permissions of a user to be a client admin as explained in the documentation [3] but this was not possible.
I thougth that maybe that the docker image does not include everything, so I downloaded all at the keycloak.org available server distributions and run them via standalone.sh (4.8, 5.0, 6.0) all with the same result, there is no permission Tab ?!
Is the documentation not updated and there is a way to enable the permission tab or how can I fullfill the mentioned scenario (client admin which is allowed to map roles) ?
Regards
Lasse
[1] https://hub.docker.com/r/jboss/keycloak/dockerfile
[2] https://github.com/jboss-dockerfiles/keycloak/tree/4.5.0.Final/server
[3] https://www.keycloak.org/docs/latest/server_admin/index.html#managing-one...
Viele Grüße
Lasse Jahn
6 years, 10 months
Identity First authentication flow and trick for extension specific theme resources
by Thomas Darimont
Hello Keycloak-Users,
I made some progress with a Google-like Identity First authentication flow
and found some interesting tricks that I wanted to share.
In my keycloak-extension-playground repository, I added an example
extension which supports a multi-step Identity first authentication
mechanism as Google and others provide.
See:
https://github.com/thomasdarimont/keycloak-extension-playground/tree/mast...
The authentication flow works as follows:
Instead of asking for username AND password on the login screen I only ask
for the username. A password is then asked in a consecutive step.
This enables additional user-specific authentication steps.
You can find a short demo-gif in this tweet:
https://twitter.com/thomasdarimont/status/1146552622943559682
- The example features two authenticators 'SelectUserAuthenticatorForm' and
'PasswordAuthenticatorForm'.
SelectUserAuthenticatorForm: Shows a form to enter the username (or
email) and provides a mechanism for resolving a user based on the given
username.
PasswordAuthenticatorForm: Based on the selected user, a password form is
shown
- The forms are sent asynchronously via AJAX without reloading the login
page
- The authentication process can be aborted/restarted via by clicking
'cancel' on the password form
Now comes a nice trick, I learned while I was looking for a way to ship
custom extension specific js/css/img resources with an authenticator
without(!) having to customize a realm login theme.
As you might now, one can have authenticator/extension specific templates
that are shipped in the extension jar within the 'theme-resources/template'
folder.
This works fine if you can do everything in an .ftl template, but falls
short, when you need extension specific css/js/img.
However, if you also ship a CUSTOM extension specific theme within the
extension, then one can access resources provided by this theme!
In my case:
I created a theme folder with a login theme, named like the extension:
extension: auth-identity-first-extension
theme-name: auth-identity-first-extension-theme
The resulting folder structure looks like this:
auth-identity-first-extension/src/main/resources/theme/auth-identity-first-extension-theme/login/resources
The 'resources' folder contains sub-folders for 'js' and 'css' resources
combined with a META-INF/keycloak-themes.json descriptor.
See:
https://github.com/thomasdarimont/keycloak-extension-playground/tree/mast...
auth-identity-first-extension/src/main/resources/META-INF/keycloak-themes.json:
{ "themes": [
{
"name": "auth-identity-first-extension-theme",
"types": [ "login"]
}
]}
This allows to refer to the extension specific theme resources from within
a template, e.g. in the 'select-user-form.ftl' template this looks like:
<link rel="stylesheet"
href="${url.resourcesPath}/../auth-identity-first-extension-theme/css/identity-first.css">
<script
src="${url.resourcesPath}/../auth-identity-first-extension-theme/js/identity-first.js"
defer></script>
We effectively define a custom theme within the extension jar just for the
sake of exposing extension specific resources.
I know that this feels a bit like a hack (because it is), but seems to work
quite well ;-)
Note that the extension specific theme also shows up within the realm theme
selection, but you can ignore this.
I hope that's useful for you too :)
Cheers,
Thomas
6 years, 10 months
add my email to the list
by Mohammad Haj Hussein (Student)
Dear Keycloak,
Please add my email to the list.
Regards,
Mohammad Haj Hussein
6 years, 10 months
User Storage SPI/LDAP Provider and groups
by Błażej Adamczyk
Hi all,
I want to extend user AND GROUP scheme with my own custom attributes
and data model to fit it to the use case.
I see several options here:
1) Extend the existing Keycloak entities with custom attributes (very
simple, but the attribute bag pattern seems to generic here?)
2) Use the User Storage API to map my own user/group entities to
Keycloak (similarily like the quickstart "user-storage-jpa")
2.1) Use import strategy - this probably would work well but it
seems it is overcomplicating the architecutre (two schemas,
synchronization etc.)
2.2) Use non-import strategy - this seems more relevant for my need
but I have a need to override not only users but also groups.
And finally the question: 2.2 seems fine but after looking through the
interfaces and looking through the ldap code I'm not sure how groups
are working in federated example when import is off.
The code seems to relate everywhere to existing keycloak groups, the
only place which I could find the groups are created is in
GroupLDAPStorageMapper (updateKeycloakGroupTree.., and syncDataFrom..
methods). These are called by specific REST sync URL or by the import
strategy (which in 2.2 is off).
Are the groups somehow automatically created when a group mapper is on
and import off? If so, how is the groups view in console working - is
it showing all LDAP groups? Or just those which were automatically
imported when user groups were accessed?
Also, can you please generally suggest which of the above options (1,
2.1 or 2.2) is better in my scenario and why?
--
Best regards,
Blazej Adamczyk
6 years, 10 months
Setup of role model with two layers in keycloak
by Sven Voigt
Hello there!
I'm part of a frontend project and I need some help to bring our
authorization model into keycloak. We're building on node.js and the
whole project uses stateless micro services - both in our frontend
middleware and for the whole backend services we use. The frontend uses
the standard JS adapter for session and token management.
So far we have identified four roles: travel agent, back office,
configurator and data security officer. That's easy so far. My problem
is how to model the next authorization layer we need.
For example: For the travel agents we want to be able to grant per
person whether he can see specific customer data or is able to cancel
orders. There are about 6-8 options for the travel agents. Thus, for the
back office there shall be options for stock operations or different
views on orders and so on.
Like the backend we don't persist any data! That's why I have store all
the things in keycloak and find a way to easily bring these information
back to our middleware.
Here's what I tried / thought of so far:
* Use groups for the first layer and roles for the second one. -->
doesn't work because the groups don't get exposed in the token.
* Use realm roles for the upper and attributes for the lower hierarchy.
--> attributes are not included in the access token.
* Use realm roles for the upper and client roles on the lower hierarchy.
--> works, but we have to make sure that roles on the second layer are
definitely associated with only one role on the first layer. I don't
know how yet.
* Use roles for the first layer and resources on the second one. -->
That seems to get very close to what we need. But at the moment I can't
figure out the correct approach with all these policies and
permissions...
Thanks for any help and please let me know, if I shall provide some
further information.
Sven
6 years, 10 months
Alternative first broker login for linking only
by Rob Resendez
We have a use case that is sort of a hybrid of the typical IDP login (First Broker Login) and "linking only" via the UMA app. That is to say, we'd like the login form to enumerate IDP buttons, but instead of falling into "Create User If Unique" execution, we would need to fall into some flow similar to the "Handle Existing Account" merge/link process.
Can anyone advise whether there are existing executions I can compose or ought to consult in some way?
Thanks in advance
Rob Resendez
[cid:CPSINew_8e504092-fab6-4ce3-ab1f-37d711ec8192.PNG]<https://www.cpsi.com/>
Electronic Mail Confidentiality Notice:
This electronic mail message and all attachments may contain confidential information belonging to the sender or the intended recipient. This information is intended ONLY for the use of the individual or entity named above. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution (electronic or otherwise), forwarding or taking any action in reliance on the contents of this information is strictly prohibited. If you have received this electronic transmission in error, please immediately notify the sender by telephone, facsimile, or email to arrange for the return of the electronic mail, attachments, or documents.
6 years, 10 months
obtaining RTP by resource name
by Stefanidis, Kyriakos
Hello all,
...more specifically people that use keycloak authorization services.
While dealing with RTPs (without permission tickets) for both user and centrally managed resources we encountered an inconsistent behavior and would like to know if it is considered a bug or works as intended (and why)
The story:
When a resource is owned by the resource provider (a client), you can get a RTP by providing either the resource id (uuid) or the resource name in the "permissions" parameter.
Ex.
"res1" is owned by "client.id" and given "update" scope permission to user "usr" via policy/permission combo
$TOKEN is the access token for user "usr"
curl -X POST \
https://something/auth/realms/something/protocol/openid-connect/token \
-H "Authorization: Bearer $TOKEN" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "audience=client.id" \
--data "permission=res1.id#scope" //correct RTP with "update" for "res1"
OR
--data "permission=res1.name#scope" //correct RTP with "update" for "res1"
When a resource is owned by a user, you can only get a RTP by providing the resource id (uuid) in the "permission" parameter. Requesting by name returns an "Resource with id [res2.name] does not exist."
Ex.
"res2" is owned by "usr" and has an "update" scope
$TOKEN is the access token for user "usr"
curl -X POST \
https://something/auth/realms/something/protocol/openid-connect/token \
-H "Authorization: Bearer $TOKEN" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "audience=client.id" \
--data "permission=res2.id#scope" //correct RTP with "update" for "res1"
OR
--data "permission=res2.name#scope" //"Resource with id [res2.name] does not exist."
The interesting thing is that If you request a RTP without specific "permission" property, keycloak returns the correct RTP with "update" for both res1 and res2 as it should.
Our tests also shown that this behavior does not rely on the "user managed" property but only the "owner" property
Is this supposed to happen?
If yes, why?
If no, which one of the two is the buggy behavior? The behavior for the user owned or the client owned resource?
The main reason for this email is that the fact that you can obtain RTP based on resource name is immensely helpful for us since the other clients (other than the resource provider) cannot get the resource id from keycloak but they do know what they are looking for (the resource name). Not being able to get RTP based on resource name for user owned resources, forces us to use a generic RTP for all resources every time which could become a burden if a user can access a very large number of resources.
Best regards,
Kyriakos Stefanidis
6 years, 10 months
[keycloak-users] [jackson-databind] is default typing enabled in keycloak
by Shiva Prasad Thagadur Prakash
Hi guys,
I was looking into CVE-2019-12814 and CVE-2019-12086. These are related to
default typing in jackson-databind. *Is default typing enabled in keylock?*
When I searched in code base I didn't see it enabled but I wanted to be
sure and hence mailed you guys!
Thanks,
Shiva
6 years, 10 months
Getting this exception Caused by: javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity#org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity$Key@e3a03493]
by Aditya mamidala
We are trying to authenticate an existing user via Keycloak so implemented
a custom SPI and added the custom SPI as User Federation
"Getting a different object with the same identifier value was already
associated with the session exception" when trying to add a user with role
from a custom SPI to Keycloak database
Please find the exception message
*Caused by: javax.persistence.EntityExistsException: A different object
with the same identifier value was already associated with the session :
[org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity#org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity$Key@e3a03493]*
We are trying to use Keycloak *6.0.1* for authentication and using the
custom provider to authenticate the users the user details are are in
custom provider using Storage provider SPI
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
UserModel userModel = new UserAdapter(session, realm, model,
repository.findUserByUsernameOrEmail(username));
RoleModel roleModel = realm.getRole("user");
* // Adding the 'user' RoleModel to the UserModel object*
userModel.grantRole(roleModel);
return userModel;
}
The exception is happening when adding the "user" role and the realm this
user is trying to add has role 'user' when i don't add the user role web
application is redirected to keycloak web page for adding the user ....
Realm containing the user role also there are no existing users fin the
realm
[image: Screen Shot 2019-07-01 at 4.46.39 PM.png]
Newbie to Keycloak. Appreciate the community guidance in resolving the
issue please.
Thanks,
Aditya
6 years, 10 months
Keycloak 6.0.1 caching authentication information for login form?
by Michael Dailous
We're seeing an issue where the login form is being pre-populated with the last user's login information, including password. Apparently, this is happening on a browser that hasn't previously logged in to the Keycloak server.
Has there been any updates to the latest version that might cause this issue?
Thank you,
Michael
6 years, 10 months
Using Active Directory as LDAP/Kerberos provider but all managemet from Keycloak
by Chris Smith
I have a client implementing SSO. The plan is to setup a standalone Active Directory forest as the LDAP/Kerberos federation provider. Active directory was chosen because of limited Linux expertise.
User self service and registration is strongly desired.
I followed the setup and for existing users, authentication works and I can get a Kerberos ticket as a claim.
A new user registration always fails. Has anyone done this?
LDAP provider is Active Directory
Edit Mode is WRITEABLE.
Sync Registrations is ON
Bind DN is an Active Directory domain administrator
Kerberos integration is ON
The Kerberos Principle and keytab are for the same user as the Bind DN.
11:33:49,799 WARN [org.keycloak.services] (default task-1) KC-SERVICES0013: Failed authentication: org.keycloak.models.ModelException: Error creating subcontext [cn=\ ,CN=Users,DC=xxx-sso,DC=com]
at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.createSubContext(LDAPOperationManager.java:625)
at org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore.add(LDAPIdentityStore.java:102)
at org.keycloak.storage.ldap.LDAPUtils.addUserToLDAP(LDAPUtils.java:72)
at org.keycloak.storage.ldap.LDAPStorageProvider.addUser(LDAPStorageProvider.java:269)
at org.keycloak.storage.UserStorageManager.addUser(UserStorageManager.java:147)
at org.keycloak.models.cache.infinispan.UserCacheSession.addUser(UserCacheSession.java:768)
at org.keycloak.authentication.forms.RegistrationUserCreation.success(RegistrationUserCreation.java:133)
at org.keycloak.authentication.FormAuthenticationFlow.processAction(FormAuthenticationFlow.java:251)
at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:97)
at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:873)
at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:292)
at org.keycloak.services.resources.LoginActionsService.processRegistration(LoginActionsService.java:627)
at org.keycloak.services.resources.LoginActionsService.registerRequest(LoginActionsService.java:681)
at org.keycloak.services.resources.LoginActionsService.processRegister(LoginActionsService.java:661)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:139)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:510)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:400)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:364)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:355)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:366)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:338)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:137)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:100)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:439)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:355)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at org.keycloak.services.filters.KeycloakSessionServletFilter.doFilter(KeycloakSessionServletFilter.java:90)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:364)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.naming.NameAlreadyBoundException: [LDAP: error code 68 - 00002071: UpdErr: DSID-030503CF, problem 6005 (ENTRY_EXISTS), data 0
]; remaining name 'cn=\ ,CN=Users,DC=xxx-sso,DC=com'
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3149)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3100)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2891)
at com.sun.jndi.ldap.LdapCtx.c_createSubcontext(LdapCtx.java:812)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_createSubcontext(ComponentDirContext.java:341)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.createSubcontext(PartialCompositeDirContext.java:268)
at javax.naming.directory.InitialDirContext.createSubcontext(InitialDirContext.java:202)
at javax.naming.directory.InitialDirContext.createSubcontext(InitialDirContext.java:202)
at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$8.execute(LDAPOperationManager.java:607)
at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager$8.execute(LDAPOperationManager.java:604)
at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:759)
at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.execute(LDAPOperationManager.java:737)
at org.keycloak.storage.ldap.idm.store.ldap.LDAPOperationManager.createSubContext(LDAPOperationManager.java:604)
... 82 more
11:33:49,946 WARN [org.keycloak.events] (default task-1) type=REGISTER_ERROR, realmId=XXX-SSO, clientId=xxx-sso, userId=null, ipAddress=127.0.0.1, error=invalid_user_credentials, auth_method=openid-connect, auth_type=code, register_method=form, redirect_uri=http://localhost:9080/xxx-sso/kc, code_id=223fbcfb-4946-43c2-b483-5bd104e4f239, email=newUser(a)something.com, username=a.new.user
6 years, 10 months
How to achieve "service continuity" with KeyCloak in Standalone Cluster mode ?
by AMIEL Patrice
Hi all,
I'm trying to deploy KeyCloak (v 4.8.3-final) in Standalone Cluster mode in order to answer a very specific requirement: get continuity of service 1/ in case of crash of a KeyCloak instance, 2/ during the upgrade of my solution.
However, I unfortunately don't get such results :(, despite the fact the cluster looks to be properly configured.
First, as I'm deploying KeyCloak in Kubernetes, I configured KeyCloak in Standalone Cluster by using the DNS_PING and a TCP transport for JGroups. Instances of the cluster can discover/see each other and the cluster is working fine as soon as it is used a couple of seconds/minutes after starting the instances.
I've created a simple script that just get in a loop the JWT tokens using the Token endpoint of a Realm, and I always have a 200 Ok status code whatever the KeyCloak instance that is hit through the Kubernetes Service.
However, coming back to the 2 uses cases I'm interested in, it looks the KeyCloak instances are getting crazy as soon as the cluster is not "stable". By "cluster is not stable", I mean:
- When scaling down the number of Keycloak instances (whatever it is by killing a Container or by a smart scale down of the Kubernetes Deployment)
- When performing a rolling update of the Pods
In both cases, during a particular time, most of the calls to get a JWT return a HTTP 499 status code and KeyCloak logs show the following:
08:14:56,785 ERROR [org.infinispan.interceptors.impl.InvocationContextInterceptor] (timeout-thread--p13-t1) ISPN000136: Error executing command GetKeyValueCommand, writing keys ISPN000476: Timed out waiting for responses for request 1883 from id-provider-5c55bbd99d-kqr8v
at org.infinispan.remoting.transport.impl.MultiTargetRequest.onTimeout(MultiTargetRequest.java:167)
at org.infinispan.remoting.transport.jgroups.StaggeredRequest.onTimeout(StaggeredRequest.java:64)
at org.infinispan.remoting.transport.AbstractRequest.call(AbstractRequest.java:87)
at org.infinispan.remoting.transport.AbstractRequest.call(AbstractRequest.java:22)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
08:14:56,790 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-992) Uncaught server error: org.infinispan.util.concurrent.TimeoutException: ISPN000476: Time-provider-5c55bbd99d-kqr8v
at org.infinispan.interceptors.impl.AsyncInterceptorChainImpl.invoke(AsyncInterceptorChainImpl.java:259)
at org.infinispan.cache.impl.CacheImpl.get(CacheImpl.java:479)
at org.infinispan.cache.impl.CacheImpl.get(CacheImpl.java:472)
at org.infinispan.cache.impl.AbstractDelegatingCache.get(AbstractDelegatingCache.java:348)
at org.infinispan.cache.impl.EncoderCache.get(EncoderCache.java:659)
at org.infinispan.cache.impl.AbstractDelegatingCache.get(AbstractDelegatingCache.java:348)
at org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction.get(InfinispanChangelogBasedTransaction.java:120)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider.getLoginFailureEntity(InfinispanUserSessionProvider.java:678)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider.getUserLoginFailure(InfinispanUserSessionProvider.java:672)
at org.keycloak.services.managers.DefaultBruteForceProtector.isTemporarilyDisabled(DefaultBruteForceProtector.java:306)
at org.keycloak.authentication.authenticators.directgrant.ValidateUsername.authenticate(ValidateUsername.java:85)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:221)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:148)
at org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:910)
at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.resourceOwnerPasswordCredentialsGrant(TokenEndpoint.java:554)
at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:187)
at sun.reflect.GeneratedMethodAccessor449.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:509)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:399)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:363)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:365)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:337)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:137)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:106)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:132)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:100)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:443)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:233)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:139)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:142)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:219)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at org.keycloak.services.filters.KeycloakSessionServletFilter.doFilter(KeycloakSessionServletFilter.java:90)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.infinispan.util.concurrent.TimeoutException: ISPN000476: Timed out waiting for responses for request 1883 from id-provider-5c55bbd99d-kqr8v
at org.infinispan.remoting.transport.impl.MultiTargetRequest.onTimeout(MultiTargetRequest.java:167)
at org.infinispan.remoting.transport.jgroups.StaggeredRequest.onTimeout(StaggeredRequest.java:64)
at org.infinispan.remoting.transport.AbstractRequest.call(AbstractRequest.java:87)
at org.infinispan.remoting.transport.AbstractRequest.call(AbstractRequest.java:22)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
... 1 more
Suppressed: org.infinispan.util.logging.TraceException
at org.infinispan.interceptors.impl.SimpleAsyncInvocationStage.get(SimpleAsyncInvocationStage.java:41)
at org.infinispan.interceptors.impl.AsyncInterceptorChainImpl.invoke(AsyncInterceptorChainImpl.java:250)
at org.infinispan.cache.impl.CacheImpl.get(CacheImpl.java:479)
at org.infinispan.cache.impl.CacheImpl.get(CacheImpl.java:472)
at org.infinispan.cache.impl.AbstractDelegatingCache.get(AbstractDelegatingCache.java:348)
at org.infinispan.cache.impl.EncoderCache.get(EncoderCache.java:659)
at org.infinispan.cache.impl.AbstractDelegatingCache.get(AbstractDelegatingCache.java:348)
at org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction.get(InfinispanChangelogBasedTransaction.java:120)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider.getLoginFailureEntity(InfinispanUserSessionProvider.java:678)
at org.keycloak.models.sessions.infinispan.InfinispanUserSessionProvider.getUserLoginFailure(InfinispanUserSessionProvider.java:672)
at org.keycloak.services.managers.DefaultBruteForceProtector.isTemporarilyDisabled(DefaultBruteForceProtector.java:306)
at org.keycloak.authentication.authenticators.directgrant.ValidateUsername.authenticate(ValidateUsername.java:85)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:221)
at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:148)
at org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:910)
at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.resourceOwnerPasswordCredentialsGrant(TokenEndpoint.java:554)
at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:187)
at sun.reflect.GeneratedMethodAccessor449.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:509)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:399)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:363)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:365)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:337)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:137)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:106)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:132)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:100)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:443)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:233)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:139)
at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:142)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:219)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
at org.keycloak.services.filters.KeycloakSessionServletFilter.doFilter(KeycloakSessionServletFilter.java:90)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
... 1 more
It looks that the KeyCloak instances that is still alive and receiving the call for generation of the JWT is trying to contact the other instances in order to get some data from the distributed cache... In particular, it tries to contact the instance that is no longer here (because killed, shutdown, rolled...), received a Timeout error, and then terminates the incoming request in error.
As I'm making the same request within a loop, I see the error happening during a couple of seconds (around 10 to 15 secs), i.e. during the time the cluster composition is not stabilized yet. When the re-discovery of the cluster has been performed, the new composition of the cluster is updated, and everything goes back to normal!
I can understand, from KeyCloak documentation on server caches (https://www.keycloak.org/docs/4.8/server_installation/index.html#_replica...) that "By default, Keycloak only specifies one owner for data. So if that one node goes down that data is lost. This usually means that users will be logged out and will have to login again. You can change the number of nodes that replicate a piece of data by change the owners attribute in the distributed-cache declaration.", but unfortunately, setting the "owner" field to 2 (or more !) for all distributed caches does not remove the issue.
I even tried to change the type of cache from "distributed-cache" to "replicated-cache", but then KeyCloak is not starting:
<replicated-cache name="sessions"/>
<replicated-cache name="authenticationSessions"/>
<replicated-cache name="offlineSessions"/>
<replicated-cache name="clientSessions"/>
<replicated-cache name="offlineClientSessions"/>
<replicated-cache name="loginFailures"/>
<replicated-cache name="actionTokens">
<object-memory size="-1"/>
<expiration interval="300000" max-idle="-1"/>
</replicated-cache>
Error during startup:
15:07:13,942 ERROR [org.infinispan.topology.LocalTopologyManagerImpl] (transport-thread--p14-t10) ISPN000230: Failed to start rebalance for cache authenticationSessions: java.lang.ClassCastException: org.infinispan.distribution.ch.impl.DefaultConsistentHash cannot be cast to org.infinispan.distribution.ch.impl.ReplicatedConsistentHash
at org.infinispan.distribution.ch.impl.SyncReplicatedConsistentHashFactory.union(SyncReplicatedConsistentHashFactory.java:26)
at org.infinispan.topology.LocalTopologyManagerImpl.doHandleRebalance(LocalTopologyManagerImpl.java:512)
at org.infinispan.topology.LocalTopologyManagerImpl.lambda$handleRebalance$3(LocalTopologyManagerImpl.java:475)
at org.infinispan.executors.LimitedExecutor.runTasks(LimitedExecutor.java:175)
at org.infinispan.executors.LimitedExecutor.access$100(LimitedExecutor.java:37)
at org.infinispan.executors.LimitedExecutor$Runner.run(LimitedExecutor.java:227)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.wildfly.clustering.service.concurrent.ClassLoaderThreadFactory.lambda$newThread$0(ClassLoaderThreadFactory.java:47)
at java.lang.Thread.run(Thread.java:748)
Did I forgot one thing? How to get a real continuity of service with KeyCloak? Is Standalone Cluster mode the good way, and how?
Thanks a lot for your help.
Patrice
________________________________
This message and any attachments are intended solely for the addressees and may contain confidential information. Any unauthorized use or disclosure, either whole or partial, is prohibited.
E-mails are susceptible to alteration. Our company shall not be liable for the message if altered, changed or falsified. If you are not the intended recipient of this message, please delete it and notify the sender.
Although all reasonable efforts have been made to keep this transmission free from viruses, the sender will not be liable for damages caused by a transmitted virus.
6 years, 10 months