Keycloak configuration and data is stored in a relational database, which is usally persisted to the hard disk. This includes data like realm settings, users, group- and role-memberships, auth flows and so on. But the user sessions will only be stored in an ephemeral in-memory infinispan cache. Therefore the session data in this cache is lost, when the keycloak server restarts.
There are many reasons why a restart of the Keycloak server is required. Major OS upgrades, Keycloak server upgrades to new versions, applying changes to keycloak e-mail templates or re-scheduling keycloak pods to other worker nodes in kubernetes or other cloud-based environments.
How to persist the session data to survive restarts. Ideally without having to maintain a custom infinspan server or using keycloak "offline sessions".
One solution could be to simply use so-called keycloak "offline sessions", but these sessions also have huge disadvantages:
they remain valid, even if the user logs out
logging out users with the keycloak admin console is no longer possible
See: https://www.keycloak.org/docs/latest/server_admin/#_offline-access
Will this problem still be present when keycloak > 17 is out and uses the all new quarkus distribution? Because in the following articles claim goals like Container-First Approach, Zero-Downtime Upgrade and Storage re-architecture.
https://www.keycloak.org/2021/10/keycloak-x-update
https://www.keycloak.org/2020/12/first-keycloak-x-release.adoc
Related
We have several web applications using the same identity provider (which we also manage), most of them (including identity provider) are using .NET core.
Requirement is that if user is logged in in two or more applications at the same time (in one browser), and is actively using one app, it automatically extends the session lifetime in all of the applications.
So while he's using at least one application, he doesn't get logged out of neither of them. Which is another requirement: auto-logout after certain time of inactivity (this part is easy of course)
I thought of using Redis server to manage this shared session lifetime, using SessionId that each app would receive from identity server via claims. So each time user does some action, backend contacts Redis and check if user's session is still active and extend the session lifetime if it is. Logout user if it's not.
Problem is, applications are not allowed to access this Redis server directly (security reasons). So I thought of adding a separate web service for these apps to contact using standard HTTP endpoint. So basically just a middleman between Redis and web app.
Is there any better way to do it? Not sure how common of a requirement is this.
Redis usually belongs in the Distributed cache, which means that it is located on another server farm. Therefore, your application has restrictions because it is not allowed to access an external server.
If your application is under development or if it is still in the growth phase my recommendation is to use InMemory cache or consider response caching middleware.
Also, these are very small amounts of data, and if you are going to store only that in the cache for a start you would definitely consider InMemory.
Of course, I understand your need for a Redis and that is it:
Is coherent (consistent) across requests to multiple servers.
Survives server restarts and app deployments. And that's because
your cache is usually in a different location (e.g. Azure)
Doesn't use local memory.
Is scalable
etc.
For larger applications Consider replacing InMemory cache with the Distributed memory cache. It is mostly similar to the InMemory cache because both the InMemory and the Distributed cache are located on the server farm where the application was run. Only the InMemory cache requires a sticky session, and the Distributed memory cache does not.
The stateless web application seems promising. How to make one? Especially with Spring WebMvc? Any guidelines?
Here are a few things on my mind:
Avoid creating session
Use a centralized storage for state info and share that among web application instances.
ADD 1
I think it is not a question of whether to keep state info or not. State info is always necessary if you want to do something useful. It is actually a question where/how to keep the state info. This article is useful. It mentioned in-proc/out-of-proc session, data cache, and why not to use session.
Related:
Use Spring MVC for Stateless web application development (no response yet)
Stateless Spring MVC
How to make a java web application fully stateless
How do I make my Web Application stateless yet still do something useful?
http://brockallen.com/2012/04/07/think-twice-about-using-session-state/
Here are some contributions. I'm not familiar with Java and Spring, but I believe these guidelines are valid regardless of your technology stack.
Stay away from sessions for authentication
As you anticipated in your question, avoid using a session to authenticate users. Sessions are peremptory and it's very difficult to replicate it consistently in a distributed, scalable infrastructure.
Also, load balancers don't work well with sessions: see Problem with Session State timeing out on Load Balanced Servers.
Use a token-based authentication system
A stateless app will preferably use a token-based authentication system. Firebase is a good example. Map the immutable user ID extracted from the token to the user data persisted in whatever storing mechanism you want to use. Since this user ID won't change, you'll be fine in a distributed database.
Don't confuse stateless with 'data persistence'-less
Sometimes people think that, by mapping a user ID to user data in a database, you are making a stateful app. It's not true. Let me make it clear:
An application that persists user information in a database and has dynamic responses for authenticated users IS NOT NECESSARILY STATEFUL. Stateless means the app won't have to distribute mutable authentication sessions across multiple servers and won't change its internal state to a particular client depending on session data.
The trick of stateless is: once a user validated its token by logging in, the server don't have to distribute anything new across the database servers and it won't change its state to that client. It can extract user info from the token and carry out what's needed to answer the request. If the token expires, the client will require a new authentication, which will generate a new token, but this is isolated from the app server, since the user ID will remain the same.
Use cookies for caching while remaining stateless
If caching in cookies some frequently requested data will improve performance, that's fine, go ahead and cache. Just make sure the cookie isn't connected to any server state and your app will not break if the client loses the cookie.
I´ve started using spring session successfully with one nginx, two tomcats and one redis server to implement clustered sessions and some questions have arisen.
First of all, I mean two completely applications when I talk about different applications, I don´t talk about two instances of the same application.
May I use two or more different spring-session applications to store sessions with only one redis server in production?
These applications can run in different tomcats instances?
How Spring session avoid session id conflict between different applications with one redis server?
Is it necessary to append suffix or prefix id to avoid this problem?
Spring Session does not natively support for scoping sessions at this time. See gh-166 for details on tracking this.
Spring Session generates a secure random id with high level of entropy for session id's so there is extremely low probability that you will get collisions.
This means that you can use the same Redis instance for multiple applications using Spring Session so long as you are ok with the following statement:
A malicious user can use Application A's session id with Application B. Why is this important? Consider the following scenario:
Application A is a public application which any user can create an account for.
Application B is a private application which only users who are invited can sign up.
The malicious user creates an account and authenticates with Application A
The user copies their session id for Application A. They navigate to Application B and paste the session id into their cookies for Application B and are now authenticated.
This might not be a problem for you. For example, good security practice would ensure that the user is properly authorized by looking for an ADMIN role in Application B. Application A would not populate that role, so while the user is authenticated with Application B they are not authorized to use it.
The Problem
I'm creating an application that runs on Glassfish 3.1.2.2 and exposes a RESTful API in an environment where authentication is expensive. Passing the credentials and authenticating every request isn't feasible - I need a session-based approach.
I'm looking at using BASIC auth and in-memory session replication (the app needs to support deployment in a cluster). In-memory replication seems expensive considering I'm only sharing "logged in" state - every other component of the applicaiton is stateless.
My question is: Is there a better alternative?
e.g. Can I configure Glassfish to persist session state to a database, instead of using in-memory replication?
I've considered a "session as a resource" approach e.g. POST to /session to login, DELETE /session/{id} to logout. This provides more control, however it's more difficult for the service consumers (vs something like BASIC auth).
If we scale up (add an instance to ELB), could we redirect some existing requests to the new instance. So that, The users that we force to a new server will be asked to login again
If we scale down (remove an instance from ELB), then all users from that server will automatically be redirected by ELB to other remaining servers. These user should not be aked to login again.
Is this possible (including the redirect of request)? How?
Any ideas are welcome but I presume this can be solved using a central session store. I just don't know how to implement it .
And what are the options in using a central session store? simpledb? redis? memcached?
Our application is just a simple web application hosted in apache. We have two instances of it added unto the Amazon ELB, and we are using PHP.
Any ELB php specific suggestions? when a scale down/up happens that no user-visible symptomps should be shown?
For the most part, this should be completely transparent to your end users without many changes on your end.
The biggest aspect to look at on your side will be ensuring that sessions are persisted / available through the addition / removal of instances.
You can do this by setting a cookie on the client (default behavior in session_start() and ensuring all of your web servers with PHP have the facility to obtain information about the session id.
Some people will use memcached to do this ... and there is native integration in PHP for sessions to be stored in memcached ...
There are quite a bunch of ways to have a centralized session management. Some of them are listed below:
DB:
http://ocklin.org/session_management_cluster.html
Memcache:
http://www.migrate2cloud.com/blog/how-to-configure-memcached-on-aws-ec2-a-starters-guide (make sure the hosts are able to connect without any problem),
http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/
http://php.net/manual/en/memcached.sessions.php
Msession:
http://in.php.net/manual/en/ref.msession.php