Implementing keycloak User Storage SPI in Scala using Akka
by Céline Leduc
Hello there,
I’m currently implementing a User Storage SPI in Scala using Akka which is the main protocol used within our back services.
I first encountered some troubles regarding sbt assembly and the configuration files, leading to the creation of this ticket here on lightbend forum https://discuss.lightbend.com/t/configuration-error-when-deploying-akka-a... <https://discuss.lightbend.com/t/configuration-error-when-deploying-akka-a...>
I finally managed to retrieve correctly my configuration file adding it manually and reading it via ConfigFactory.parseFile(filename)
However, now I’m facing a new exception : I get an ClassNotFoundException for the class akka.event.DefaultLoggingFilter at startup.
A message with the same issue has already been published two years ago on the mailing list but doesn’t have any precise answer.
Does anyone know what may be causing this error and how to solve it? Or maybe have a sample of working integration of a Scala User Storage SPI using Akka?
Here is the complete stack trace I’m getting :
09:19:32,530 WARN [org.keycloak.services] (default task-466) KC-SERVICES0013: Failed authentication: java.lang.ClassNotFoundException: akka.event.DefaultLoggingFilter from [Module "deployment.keycloak-server.war" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:255)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at akka.actor.ReflectiveDynamicAccess.$anonfun$getClassFor$1(ReflectiveDynamicAccess.scala:22)
at scala.util.Try$.apply(Try.scala:213)
at akka.actor.ReflectiveDynamicAccess.getClassFor(ReflectiveDynamicAccess.scala:21)
at akka.actor.ReflectiveDynamicAccess.createInstanceFor(ReflectiveDynamicAccess.scala:39)
at akka.actor.ActorSystemImpl.<init>(ActorSystem.scala:780)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:246)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:289)
at akka.actor.ActorSystem$.apply(ActorSystem.scala:264)
at med.lib.service.client.MicroServiceClient.$init$(MicroServiceClient.scala:27)
at med.lib.service.client.KeycloakDataServicesClient.<init>(KeycloakDataServicesClient.scala:18)
at med.lib.service.keycloak.DSInterface.<init>(DSInterface.scala:22)
at med.lib.service.keycloak.DSUserStorageProvider.<init>(DSUserStorageProvider.scala:19)
at med.lib.service.keycloak.DSUserStorageProviderFactory.create(DSUserStorageProviderFactory.scala:43)
at med.lib.service.keycloak.DSUserStorageProviderFactory.create(DSUserStorageProviderFactory.scala:19)
at org.keycloak.storage.UserStorageManager.getStorageProviderInstance(UserStorageManager.java:92)
at org.keycloak.storage.UserStorageManager.getEnabledStorageProviders(UserStorageManager.java:130)
at org.keycloak.storage.UserStorageManager.getUserByEmail(UserStorageManager.java:407)
at org.keycloak.models.cache.infinispan.UserCacheSession.getUserByEmail(UserCacheSession.java:380)
at org.keycloak.models.utils.KeycloakModelUtils.findUserByNameOrEmail(KeycloakModelUtils.java:207)
at org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator.validateUserAndPassword(AbstractUsernameFormAuthenticator.java:148)
at org.keycloak.authentication.authenticators.browser.UsernamePasswordForm.validateForm(UsernamePasswordForm.java:55)
at org.keycloak.authentication.authenticators.browser.UsernamePasswordForm.action(UsernamePasswordForm.java:48)
at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:113)
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.processAuthentication(LoginActionsService.java:263)
at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:259)
at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:320)
at sun.reflect.GeneratedMethodAccessor701.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: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)
Thanks for your help!
Céline Leduc
Céline Leduc
Software engineer
www.libmed.fr
Soutenue par :
- Le Ministère de l’Enseignement supérieur, de la Recherche et de l’Innovation
- BPI France
5 years, 6 months
Session persistence in MySQL
by Mihai Gogu
Hello,
We have a keycloak 6.0.1 setup in kubernetes and we want to configure the infinispan persistence for sessions through MySQL since we can expect the containers to be restarted at any time and setting up more infinispan owners does not offer enough guarantees for our needs.
The config that we have now is like this:
<subsystem xmlns="urn:jboss:domain:infinispan:8.0">
<cache-container name="keycloak”>
…
<distributed-cache name="sessions" statistics-enabled="true" owners="1">
<jdbc-store data-source="KeycloakDS" dialect="MYSQL" fetch-state="true" passivation="false" preload="true" purge="false" shared="true" singleton="false">
<property name="dropTableOnExit">false</property>
<property name="createTableOnStart">true</property>
</jdbc-store>
</distributed-cache>
…
</cache-container>
</subsystem>
When we try to start Keycloak with this config we get the following error:
]) - failure description: {"WFLYCTL0080: Failed services" => {"org.wildfly.clustering.infinispan.cache.keycloak.sessions" => "org.infinispan.commons.CacheException: Unable to invoke method public void org.infinispan.persistence.manager.PreloadManager.start() on object of type PreloadManager Caused by: org.infinispan.commons.CacheException: Unable to invoke method public void org.infinispan.persistence.manager.PreloadManager.start() on object of type PreloadManager Caused by: java.lang.RuntimeException: org.h2.jdbc.JdbcSQLException: Invalid value \"-2147483648\" for parameter \"rows\" [90008-193] Caused by: org.h2.jdbc.JdbcSQLException: Invalid value \"-2147483648\" for parameter \"rows\" [90008-193]”}}
Can you please point us to an example config for this use case or help us with some advices on how we can achieve session persistence with MySQL? We are also using MySQL as the database for Keycloak (users, clients, configs etc…)
Thank you!
5 years, 6 months
Re: [keycloak-user] Upgrade to 6.0.1 - Oracle driver failing to load
by Weber, Wolfgang
Hi!
Regarding the question: Has something changed between these versions requiring driver install changes?
Check https://issues.jboss.org/browse/WFLY-10640, resolved with WildFly 14. Configured datasource are checked now whether the specified datasource-class or xa-datasource-class is a valid implementation of javax.sql.DataSource or javax.sql.XADataSource when adding new jdbc driver or adding new (xa-)datasource.
Regards,
Wolfgang
On Wed, 2019-06-05 at 13:35 +0000, David Paul wrote:
> Hi all,
>
> I was able to determine that it is 4.5.0 to 4.6.0 that breaks the oracle driver load. Was something changed between those versions that breaks the upgrade process I used (shown in email content below)? I used that same process from:
> 3.2.1 to 3.4
> 3.4 to 4.0
> 4.0 to 4.1
> 4.1 to 4.2.1
> 4.2.1 to 4.5
>
> 4.5 to 4.6 causes the error I listed in the below email content.
> My (oracle) linux 7 OS is up to date and I have tried java 7, 8 and openJava 10. Also I used ojdbc7.jar and ojdbc8.jar drivers
>
> Has something changed between these versions requiring driver install changes?
>
> Dave
>
>
>
> changes?
________________________________
BearingPoint Technology GmbH
Sitz: Premstätten bei Graz
Firmenbuchgericht: Landesgericht für ZRS Graz
Firmenbuchnummer: FN 44354b
The information in this email is confidential and may be legally privileged. If you are not the intended recipient of this message, any review, disclosure, copying, distribution, retention, or any action taken or omitted to be taken in reliance on it is prohibited and may be unlawful. If you are not the intended recipient, please reply to or forward a copy of this message to the sender and delete the message, any attachments, and any copies thereof from your system.
5 years, 6 months
Missing custom attributes from migrated users
by luis.villaca@petrobras.com.br
Greetings,
I do not see the custom attributes from users created in Realm A, migrated
to Realm B.
I have configured in Realm A, using it for SSO, a user federation that
validates the credentials and fetches user data from a service (via a
custom UserStorageProvider), and populates a Keycloak user with name,
e-mail, and some corporate attributes like division (setting
singleAttributes from UserModel).
Then in realm B I have an Identity Provider that points to a Broker in
Realm A. In "first login flow" I have a custom Authentication flow, with
two execution steps:
- Create User If Unique
- Automatically Link Brokered Account
This allows me to automatically migrate this user to my realm.
So login from realm B ends in authentication in realm A, which pulls a user
according to our service. Then the process migrates user data to realm B -
but as I inspect this user I see e-mail, name (first & last) but I cannot
see my custom attributes.
Any hints?
Thanks,
Luis
"O emitente desta mensagem � respons�vel por seu conte�do e endere�amento. Cabe ao destinat�rio cuidar quanto ao tratamento adequado. Sem a devida autoriza��o, a divulga��o, a reprodu��o, a distribui��o ou qualquer outra a��o em desconformidade com as normas internas do Sistema Petrobras s�o proibidas e pass�veis de san��o disciplinar, c�vel e criminal."
"The sender of this message is responsible for its content and addressing. The receiver shall take proper care of it. Without due authorization, the publication, reproduction, distribution or the performance of any other action not conforming to Petrobras System internal policies and procedures is forbidden and liable to disciplinary, civil or criminal sanctions."
"El emisor de este mensaje es responsable por su contenido y direccionamiento. Cabe al destinatario darle el tratamiento adecuado. Sin la debida autorizaci�n, su divulgaci�n, reproducci�n, distribuci�n o cualquier otra acci�n no conforme a las normas internas del Sistema Petrobras est�n prohibidas y ser�n pasibles de sanci�n disciplinaria, civil y penal."
5 years, 6 months
The "Lost data because of abrupt leavers" message in the server logs
by Hossein Doutaghy
Hi,
We are seeing the following FATAL logs message in server.log whenever a
node leaves the HA cluster.
15:39:21,605 FATAL [org.infinispan.CLUSTER] (transport-thread--p14-t6)
[Context=clientSessions] ISPN000313: Lost data because of abrupt
leavers [ckey-ckey-1]
I do not see any session lost when a node is leaving a cluster. Could you
please confirm why this message is generate and is there actually any data
lose at the time a node leaves the cluster?
Can we prevent this FATAL message from showing in the logs? if so, how it
is possible?
--
Moe Doutaghy
5 years, 6 months
OIDC Client Secret Encryption
by Reese Garth
Hi,
I have APIs that I’d like to give programmatic access to partners and I have some questions on how best to use Keycloak to facilitate this. From the research I’ve done, it seems that the best method is to use the client credentials grant where each partner can create a new client in Keycloak and have their app authenticate as that client to access the APIs. My largest hesitation with using this method is that the client secret is stored in plaintext and is visible in the admin UI.
1. Is there a particular reason the generated client secret is stored in plaintext? I’m assuming there is, but I can’t figure out what it would be.
2. Is there any possibility to add encrypted client secrets as a feature in the future?
3. Are there any alternatives/best practices for programmatic access that makes use of Keycloak?
Thanks for your time,
Reese
CONFIDENTIALITY NOTICE AND DISCLAIMER : This telecommunication, including any and all attachments, contains confidential information intended only for the person(s) to whom it is addressed. Any dissemination, distribution, copying or disclosure is strictly prohibited and is not a waiver of confidentiality. If you have received this telecommunication in error, please notify the sender immediately by return electronic mail and delete the message from your inbox and deleted items folders. This telecommunication does not constitute an express or implied agreement to conduct transactions by electronic means, nor does it constitute a contract offer, a contract amendment or an acceptance of a contract offer. Contract terms contained in this telecommunication are subject to legal review and the completion of formal documentation and are not binding until same is confirmed in writing and has been signed by an authorized signatory.
5 years, 6 months
Keycloak Gatekeeper access token encryption
by Jody H
Hi,
I am trying to use the Keycloak Gatekeeper proxy and have found a problem I
can't seem to solve.
I have a service which is hosting a webservice and an api.
Keycloak gatekeeper is protecting this application.
I have another webservice which is making requests to this api.
I have encrypted tokens/cookies enabled in my gatekeeper config.
I have looked into the source code of gatekeeper to figure out how the
token is being decrypted, when it is coming inside of the Authorization
header instead of a cookie. It is like this:
1) The token is read from the "Authorization: Bearer" header:
https://github.com/keycloak/keycloak-gatekeeper/blob/master/session.go#L75
2) If encryption is enabled, the access token needs be decrypted:
https://github.com/keycloak/keycloak-gatekeeper/blob/master/session.go#L3...
3) Before decryption, the access token from the Authorization header will
be base64-decoded:
https://github.com/keycloak/keycloak-gatekeeper/blob/master/utils.go#L197
4) After decoding, it will be decrypted by AES-GCM:
https://github.com/keycloak/keycloak-gatekeeper/blob/master/utils.go#L167...
I can't seem to figure out how to make requests to the gatekeeper proxy so
that the access token I pass in the Authorization header can be read by the
gatekeeper. I have checked multiple times that the key I use to encrypt my
access token is identical to the one I use in the gatekeeper config.
I am using this javascript code to encrypt my data:
https://gist.github.com/chrisveness/43bcda93af9f646d083fad678071b90a - then
after encryption, I base64 encode it and add it to the "Autorization:
Bearer [base64-encoded encrypted-access-token]" header. The error
gatekeeper gives me is this:
https://github.com/keycloak/keycloak-gatekeeper/blob/master/utils.go#L204
The relevant javascript code looks like this:
const key = "MY_KEY_HERE_WITH_32_CHARACTERS"; //key is equal to the on in
the gatekeeper config
const ciphertext = await aesGcmEncrypt(keycloak.token, key);
console.log(ciphertext);
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Authorization', 'Bearer ' + btoa(ciphertext));
req.onreadystatechange = function () {
if (req.readyState == 4) {
if (req.status == 200) {
document.getElementById("userid").innerHTML = req.responseText + " (" + new
Date() + ")";
} else if (req.status == 403) {
console.log('Forbidden');
} else if (req.status == 401) {
console.log('Unauthorized');
}
}
}
req.send();
Can someone help me out? Sorry for the wall of text and thanks in advance!
Best regards,
5 years, 6 months
Is Keycloak 2.5.4 EOL or unsupported?
by Nanze Panze
I’m not finding an easy way to tell if Keycloak 2.5.4 is EOL or
unsupported. Looking at the Github releases this version was released in
Feb 2017. That in itself doesn’t tell me if the version is unsupported or
contains security vulnerabilities.
Can someone from Redhat please provide some information regarding the
status of this version.
Thanks in advance.
5 years, 6 months