[keycloak-user] High Utilization with Keycloak Spring Boot adapter

Alan Gibson alan.gibson at gmail.com
Tue Nov 8 12:05:16 EST 2016


We'll definitely switch away from Basic auth in the future. But what I
didnt mention is that this REST api has only one client, which is a legacy
application. This app currently sends Basic auth headers with every
request. It will be several months before the resources are available to
update it. Thats why I was trying to find a reasonably performant
configuration on the REST api microservice side as a temporary hack.

>From the sound of it, I think the most expedient thing to do would be to
just set the Basic auth username and password properties in
application.properties until we get around to changing how auth works in
the legacy client.

On Nov 8, 2016 5:31 PM, "Thomas Raehalme" <thomas.raehalme at aitiofinland.com>
wrote:

> Hi!
>
> I meant that the client should store the cookie set by the server after
> the first request and include it in subsequent requests (instead of the
> Basic auth header).
>
> But as Niko wrote in his email you should consider using Bearer tokens for
> much better performance. We are using spring-security-oauth2 [1] in our
> projects as it provides a drop-in replacement for Spring's RestTemplate.
>
> [1] https://github.com/spring-projects/spring-security-
> oauth/tree/master/spring-security-oauth2
>
> Best regards,
> Thomas
>
>
> On Tue, Nov 8, 2016 at 3:59 PM, Alan Gibson <alan.gibson at gmail.com> wrote:
>
>> Thanks for the info Thomas. Can you clarify what you mean by "rely on the
>> HttpSession for the subsequent ones"? I've got Spring Session configured in
>> the Spring Boot service, but that doesn't seem to make any difference.
>>
>>     <dependency>
>>         <groupId>org.springframework.session</groupId>
>>   <artifactId>spring-session</artifactId>
>>     </dependency>
>>
>>     @EnableSpringHttpSession
>>     @Configuration
>>     public class SpringHttpSessionConfig {
>> @Bean
>> public MapSessionRepository sessionRepository() {
>>        return new MapSessionRepository();
>> }
>>     }
>>
>> AFAIK, the Basic auth header is supposed to be sent with every HTTP
>> request. So if every request with Basic auth headers results in a new SSO
>> session within Keycloak, then it would seem that there is no (standards
>> compliant) way to use Basic auth without hammering Keycloak and opening
>> loads of sessions.
>>
>> I assume I'm missing something really obvious here, but I can't think of
>> what. Does keycloak-spring-boot-adapter just not work as a transparent
>> 'proxy' for Basic auth this way?
>>
>> Br, Alan
>>
>> On Tue, Nov 8, 2016 at 6:02 AM, Thomas Raehalme <
>> thomas.raehalme at aitiofinland.com> wrote:
>>
>>> Hi!
>>>
>>> With direct access grants and Basic auth you should authenticate with
>>> the first request, then rely on the HttpSession for the subsequent ones.
>>> Every request with the Basic auth header opens a new SSO session within
>>> Keycloak.
>>>
>>> Best regards,
>>> Thomas
>>>
>>> On Nov 7, 2016 11:33 PM, "Alan Gibson" <alan.gibson at gmail.com> wrote:
>>>
>>> Hello all,
>>>
>>> During load testing the REST API of a Spring Boot based microservice, we
>>> noticed that Keycloak was forming a huge bottleneck. We had 3 instances
>>> of
>>> Keycloak (running in clustered mode), each of which was consuming 100%
>>> of 8
>>> Xeon CPUs, while only hitting about 80 API calls per second. The load
>>> test
>>> itself used 800 concurrent users, each doing 1 HTTP request every 100
>>> milliseconds.
>>>
>>> It looks like every time a POST is made to the REST API, Spring Boot
>>> makes
>>> a call to Keycloak to (re)authenticate the user. The Keycloak logs are
>>> filled with:
>>>
>>> 2016-11-06 11:48:07,819 DEBUG [org.jboss.resteasy.resteasy_jaxrs.i18n]
>>> (default task-74) RESTEASY002315: PathInfo:
>>> /realms/proxy/protocol/openid-
>>> connect/token
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> AUTHENTICATE CLIENT
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> client authenticator: client-secret
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> client authenticator SUCCESS: client-secret
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> Client devicereportreceiver authenticated by client-secret
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> AUTHENTICATE ONLY
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> processFlow
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> check execution: direct-grant-validate-username requirement: REQUIRED
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> authenticator: direct-grant-validate-username
>>> 2016-11-06 11:48:07,820 DEBUG [org.keycloak.services] (default task-74)
>>> invoke authenticator.authenticate
>>> 2016-11-06 11:48:07,821 DEBUG [org.keycloak.services] (default task-74)
>>> authenticator SUCCESS: direct-grant-validate-username
>>> 2016-11-06 11:48:07,821 DEBUG [org.keycloak.services] (default task-74)
>>> check execution: direct-grant-validate-password requirement: REQUIRED
>>> 2016-11-06 11:48:07,821 DEBUG [org.keycloak.services] (default task-74)
>>> authenticator: direct-grant-validate-password
>>> 2016-11-06 11:48:07,821 DEBUG [org.keycloak.services] (default task-74)
>>> invoke authenticator.authenticate
>>> 2016-11-06 11:48:07,821 DEBUG
>>> [org.hibernate.engine.transaction.internal.TransactionImpl]
>>> (default task-74) begin
>>> 2016-11-06 11:48:07,821 DEBUG
>>> [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool]
>>> (default task-74) KeycloakDS: getConnection(null,
>>> WrappedConnectionRequestInfo at 25df8309[userName=postgres]) [0/20]
>>> 2016-11-06 11:48:09,560 DEBUG [org.keycloak.services] (default task-74)
>>> authenticator SUCCESS: direct-grant-validate-password
>>> 2016-11-06 11:48:09,560 DEBUG [org.keycloak.services] (default task-74)
>>> check execution: direct-grant-validate-otp requirement: OPTIONAL
>>> 2016-11-06 11:48:09,560 DEBUG [org.keycloak.services] (default task-74)
>>> authenticator: direct-grant-validate-otp
>>> 2016-11-06 11:48:09,569 DEBUG [org.keycloak.services] (default task-74)
>>> invoke authenticator.authenticate
>>> 2016-11-06 11:48:09,569 DEBUG [org.keycloak.services] (default task-74)
>>> authenticator ATTEMPTED: direct-grant-validate-otp
>>> 2016-11-06 11:48:09,569 DEBUG [org.keycloak.services] (default task-74)
>>> Using full scope for client
>>> 2016-11-06 11:48:09,569 DEBUG [org.keycloak.services] (default task-74)
>>> Using full scope for client
>>> 2016-11-06 11:48:09,739 DEBUG [org.keycloak.events] (default task-74)
>>> type=LOGIN, realmId=REMOVED, clientId=REMOVED, userId=REMOVED,
>>> ipAddress=REMOVED, auth_method=openid-connect, token_id=REMOVED,
>>> grant_type=password, refresh_token_type=Refresh,
>>> refresh_token_id=REMOVED,
>>> client_auth_method=client-secret, username=REMOVED
>>> 2016-11-06 11:48:09,739 DEBUG
>>> [org.hibernate.engine.transaction.internal.TransactionImpl]
>>> (default task-74) committing
>>> 2016-11-06 11:48:09,751 DEBUG
>>> [org.jboss.jca.core.connectionmanager.pool.strategy.OnePool]
>>> (default task-74) KeycloakDS: returnConnection(2aab4b06, false) [0/20]
>>>
>>> The Spring Boot application.properties looks like
>>>
>>> keycloak.realm=REMOVED
>>> keycloak.realmKey=REMOVED
>>> keycloak.auth-server-url=${KEYCLOAK_AUTHENTICATION_SERVER}
>>> keycloak.ssl-required=none
>>> keycloak.resource=REMOVED
>>> #keycloak.use-resource-role-mappings=true
>>> keycloak.enable-basic-auth=true
>>> keycloak.credentials.secret=${KEYCLOAK_CLIENT_SECRET}
>>> keycloak.cors=true
>>> keycloak.cors-allowed-headers=x-requested-with,origin,conten
>>> t-type,accept,
>>> authorization
>>> keycloak.cors-allowed-methods=GET,POST,DELETE,PUT,OPTIONS
>>> keycloak.cors-max-age=3600
>>> keycloak.expose-token=true
>>> keycloak.bearer-only=true
>>> keycloak.securityConstraints[0].securityCollections[0].name=REMOVED
>>> keycloak.securityConstraints[0].securityCollections[0].authRoles[0]=user
>>> keycloak.securityConstraints[0].securityCollections[0].patte
>>> rns[0]=/REMOVED
>>> keycloak.securityConstraints[1].securityCollections[0].name=REMOVED
>>> keycloak.securityConstraints[1].securityCollections[0].authR
>>> oles[0]=DEVICE
>>> keycloak.securityConstraints[1].securityCollections[0].
>>> patterns[0]=/REMOVED/*
>>>
>>> So my questions are:
>>>
>>> 1. Would you expect to see this kind of high utilization with my test
>>> scenario?
>>>
>>> 2. Should the Keycloak Spring Boot adapter be reauthenticating with every
>>> request, as opposed to caching the authentication results for a short
>>> period of time, or just relying on normal HTTP sessions?
>>>
>>> Br,
>>> Alan
>>> _______________________________________________
>>> keycloak-user mailing list
>>> keycloak-user at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/keycloak-user
>>>
>>>
>>>
>>
>
>


More information about the keycloak-user mailing list