I'm looking at implementing an OpenID provider ('OP') using Java + Tomcat/JBoss.
Now one of the key things about OpenID is that
The user communicates with both the OP and the RP and has a session with both sites.
The OP and RP communicate with each other to ensure the user hasn't faked anything.
A subject I've not been able to find any documentation on is the question on how to correctly implement this in a load balanced situation.
The generic issue I fear is that the RP connects to the OP and ends up on a different application server than the user.
My questions:
What is the right way to handle this?
What is the 'best' OpenID library to
use?
Thanks.
The generic issue I fear is that the RP connects to the OP and ends up on a different application server than the user.
Save the conversation state in a shared storage. That is, database or distributed cache. Cache would be faster, and you don't need much of persistence anyway.
Load-balancing with sticky sessions (all consequent request from the same client come to the same server) would reduce the number of cache updates.
(Clustered HTTP sessions that I intended to advice initially wouldn't work as the same conversation is spread between two sessions: user's and application's.)
On the OP side, the only OpenID-specific state that really needs to be shared among the machines in your cluster is the associations (the shared secrets and their handles). And that's pretty cacheable; the secret for a given association handle never changes, they have a well-defined lifetime, and there shouldn't be that many of them. (Unless, perhaps, you operate with some high-volume RPs that use stateless mode.)
Depending on your feature set and user interface, there may be some other session state for the user, but that shouldn't need to apply to the direct RP-OP communications and you can use your standard bag of tricks.
Related
We have the following setup.
STM (Stingrey Traffic Manager) does load balancing + session stickiness
Weblogic 'cluster'
Auth handled by a third party tool
Therefore I do not have to worry about session with regards to horizontal scaling/ running multiple instances of the application. STM/ Weblogic cluster makes sure that the subsequent request come to same managed server.
What we currently have is a monolithic application and we are trying to move to microservices. Also we do not wan't to move out of current infrastructure (i.e. STM/ Weblogic cluster/ Auth tool). What we have planned is:
A Gateway WAR which routes requests to other microservices
N x Microservices (WAR) for each functional sub-domain
Only the API Gateway receives user requests and other microservices are not accessible from outside
So my question is
Should API Gateway be state-full while other microsevices are stateless?
If so, how should the user session data be shared between API Gateway and microservices?
Please suggest any better alternatives and resources/links as well. Thanks.
Let me share my opinion.
First of all, if you can keep your application stateless, by all means do so :)
It will be the best solution in terms of both performance and scalability.
Now, if its impossible, then you should maintain some distributed session management layer.
The gateway responsible for authentication could generate some unique session identifier which could later be used as a key.
This key could be propagated to all the microservices and be a part of the API or something.
In order to access the session, the microservice could 'get' value by key and work with it.
In terms of implementation: I would take a look on NoSQL solutions. Some of them that can suit your need are:
Redis. Take a look on ''hset'' there
Hazelcast. Its more a in-memory grid but if the solution is java only, you can also implement the required functionality
Memcache.d. It will give you an old good map, just distributed :)
There are also other solutions I believe.
Now, the performance is crucial here, otherwise the whole solution will be just too slow. So In my understanding, using an RDBMS would be not be good here, moreover potentially it would be harder to scale it out.
Hope this helps
1)Should API Gateway be state-full while other microservices are stateless?
Yes, As in 12 Factor App guide lines all the services should be stateless.
2)If so, how should the user session data be shared between API Gateway and microservices?
Your API should be stateless therefore do not share the session state to the microservices. The recommended approach is to set up a Redis cache to store session data.
I'm designing a poker webapp with multiple users sharing a game, and distributed across many servers. Assuming I want to maintain the state of the game in a single server - is there a way I can 'route' or 'guide' logged in users interact with the machine that is hosting the game? The game involves lots of interactive responses via AJAX, and so coordinating state in the database across multiple servers is not an option. (If your view is that this the state can be maintained across multiple servers using a distributed cache - then I'm open to that too).
To make it simpler, assume the webapp is implemented in Java.
If you could provide example libraries and information about routing in your answer that would be helpful. (Eg why or why Apache Zookeeper is an appropriate way of dealing with this problem).
At a load balancer level, there is the concept of sticky sessions, supported by load balancers like HAProxy, which will ensure that the same user will always be routed to the same server (with https it may be harder).
However, it is hard to ensure that 2 users which logged to different servers finally are playing on the same server. And this also means that if the server goes down, the game is lost for both players. Perhaps you should persist the game on a distributed cache and handle failures?
As far as I understand, in HAProxy, it is possible to use the query string to route the request to the appropriate server.
http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
But you'd better use stateless requests and be able to deal with requests from many servers.
I've been tasked with making an enterprise application multi-tenant. It has a Java/Glassfish BLL using SOAP web services and a PostgreSQL backend. Each tenant has its own database, so (in my case at least) "multi-tenant" means supporting multiple databases per application server.
The current single-tenant appserver initializes a C3P0 connection pool with a connection string that it gets from a config file. My thinking is that now there will need to be one connection pool per client/database serviced by the appserver.
Once a user is logged in, I can map it to the right connection pool by looking up its tenant. My main issue is how to get this far - when a user is first logged in, the backend's User table is queried and the corresponding User object is served up. It seems I will need to know which database to use with only a username to work with.
My only decent idea is that there will need to be a "config" database - a centralized database for managing tenant information such as connection strings. The BLL can query this database for enough information to initialize the necessary connection pools. But since I only have a username to work with, it seems I would need a centralized username lookup as well, in other words a UserName table with a foreign key to the Tenant table.
This is where my design plan starts to smell, giving me doubts. Now I would have user information in two separate databases, which would need to be maintained synchronously (user additions, updates, and deletions). Additionally, usernames would now have to be globally unique, whereas before they only needed to be unique per tenant.
I strongly suspect I'm reinventing the wheel, or that there is at least a better architecture possible. I have never done this kind of thing before, nor has anyone on my team, hence our ignorance. Unfortunately the application makes little use of existing technologies (the ORM was home-rolled for example), so our path may be a hard one.
I'm asking for the following:
Criticism of my existing design plan, and suggestions for improving or reworking the architecture.
Recommendations of existing technologies that provide a solution to this issue. I'm hoping for something that can be easily plugged in late in the game, though this may be unrealistic. I've read about jspirit, but have found little information on it - any feedback on it or other frameworks will be helpful.
UPDATE: The solution has been successfully implemented and deployed, and has passed initial testing. Thanks to #mikera for his helpful and reassuring answer!
Some quick thoughts:
You will definitely need some form of shared user management index (otherwise you can't associate a client login with the right target database instance). However I would suggest making this very lightweight, and only using it for initial login. Your User object can still be pulled from the client-specific database once you have determined which database this is.
You can make the primary key [clientID, username] so that usernames don't need to be unique across clients.
Apart from this thin user index layer, I would keep the majority of the user information where it is in the client-specific databases. Refactoring this right now will probably be too disruptive, you should get the basic multi-tenant capability working first.
You will need to keep the shared index in sync with the individual client databases. But I don't think that should be too difficult. You can also "test" the synchronisation and correct any errors with an batch job, which can be run overnight or by your DBA on demand if anything ever gets out of sync. I'd treat the client databases as the master, and use this to rebuild the shared user index on demand.
Over time you can refactor towards a fully shared user management layer (and even in the end fully shared client databases if you like. But save this for a future iteration.....
Ruby on Rails has supported signed cookie-based sessions for quite some time, with a few encrypted implementations springing up since then. Python and PHP also have implementations.
Does such a beast exist for the Java servlet containers Jetty or Tomcat?
We've received significant performance gains over RDBMS-based sessions with the PHP implementation in our clustered environment, and I'd be interested in trying something similar with one of our Java applications (which currently uses Jetty 7).
I'm aware of other ways to achieve this goal (memcached, synchronized in-memory caches) but I believe that for our particular needs the limitations of this storage method (sessions finalization before output, in-efficient storage after the 4K cookie size limit, reliance on an ultra-secret server-side key) are outweighed by the simpler deployment environment for this particular application.
If an implementation doesn't exist, does anybody have any ideas why it wouldn't? (e.g. Java sessions are typically larger than 4K, and so aren't as amenable to this storage method)
We have implemented the Session-In-Cookie and used it successfully in a Tomcat cluster to allow session-sharing among 20 nodes and thus enable zero-outage deployments. I have just written the first part of a two-part series on the implementation here: http://blog.shinetech.com/2012/12/18/simple-session-sharing-in-tomcat-cluster-using-the-session-in-cookie-pattern/. This part deals with the basic implementation, the security aspects will be covered in the second part.
I'm not aware of anything in either container that would serialize a HttpSession to a cookie for you. You could achieve this sort of thing by implementing a Filter that would be able to serialize session state to a cookie on a response to a web client and deserialize it on the request. You are still bound to any client side cookie limitations and you should carefully consider the security implications of the state you are storing client side and/or how much you trust the client presenting the cookie.
It seems like there are two questions here:
Java/J2EE implementations of effectively stateless session-management.
Secure session implementations.
Regarding the first question: Yes, depending on the size of the session-graph (deep nesting of all session variables/objects) the cookie size limitation (which is effectively an HTTP Header limitation) is a significant factor. If the session-graph neatly fits inside the HTTP Header limitation (which is to some extent configurable on the web-server side) and/or can be augmented with REST based URL query parameters (to alleviate some of the state information on the server) ... then a cookie implementation is possible. This would be programmatic versus container-managed however.
Regarding the second question: Securing sessions is another matter. The notorious JSESSIONID common cookie in Java/J2EE systems is a simple token key to the in-memory or disk-cached session on the application server. It is just a map key. With that key, anyone can steal or impersonate the user-session. This is probably one of the weakest links in the entire container-managed session apparatus. There are commercial secure-session products available that prevent session-hijacking by cookie stealing, prevent replay-attacks (that can defeat SSL by capturing the replaying the encrypted login conversation to obtain a session) and other attack vectors. One product I am aware of can do this with no changes to the code (via a security filter). However, I am not aware of any general frameworks or open-source initiatives to plug this hole, probably because it requires a level of expertise that is beyond general application development.
I want the clients of several related web apps to hold their own authentication state. This improves scalability, because no session replication between cluster nodes is needed. And it makes integration of different server technologies like Java Servlets and PHP easier.
My plan is as follows:
Set a signed and encrypted cookie with the user name and session expiration time after client authentication.
When the client sends a request, the server decrypts and validates the cookie and grants or denies access depending on the cookie values.
The session expiration will be updated through resetting the cookie.
All servers that want to use the session have only to know the cookie mechanism and the decryption key. See also: Session state in the client tier
Is this approach ok? Would it be possible to integrate it into a servlet container / application Server so that it is transparent to the applications? A servlet should be able to use HttpServletRequest#getRemoteUser() for example. Is this possible? Or would I need something above the container level like Spring Security? Are there any existing libraries for client side session management?
Not a good idea. Storing vital data like session expiry and user name entirely on client side is too dangerous IMO, encrypted or not. Even if the concept is technically safe in itself (I can't answer that in depth, I'm no encryption expert), a break-in could be facilitated without compromising your server, just by acquiring your encryption key.
Somebody who gets hold of the key could generate session cookies at will, impersonating any user for any length of time, something the classical session concept is designed to prevent.
There are better and scalable solutions for this problem. Why not, for instance, set up a central session verification instance that all associated servers and services can poll? Look around on the web, I am 100% sure there are ready-made solutions addressing your needs.
I disagree with the posters saying this approach is not secure. Variants of it are used in a number of well respected frameworks, such as Rails and Play!, for precisely the reasons you outline, and it's perfectly secure when implemented correctly.
This improves scalability, because no session replication between cluster nodes is needed.
First, using HTTP Session doesn't really prevent you from scaling, even when using HTTP Session State replication (some mechanisms are smarter than others by the way, for example WebLogic's in-memory replication doesn't have a big overhead). Second, do you really need it? Most applications (the majority) don't need Session replication. Third, am I understanding right: do you plan to not use HTTP Session at all?
(...) Set a signed and encrypted cookie with the user name and session expiration time after client authentication.
Don't do this! Don't store a username and other sensible data used by the server in a cookie, this is a very bad idea! You actually need to admit that it's just a matter of time before someone figures out how your system works and breaks it (especially if your cookie is candidate for crib attacks). Sor, really, you should store data in the Session on the server-side and only an ID in the cookie, like things are actually working. This is much more secure.
Is this approach ok?
No. And you don't need this for interoperable single-sign on (if this is what you are trying to build). Just use a centralized authentication solution like CASJasig which has libraries for various technologies.
This is not really how Sessions are implemented. The cookie itself doesn't need to carry any data of the session itself, it's just a reference to it.
What the Cookie holds is usually a Session ID which is then linked to the data on the server.
If you don't have a central data session server for the other servers to access, I suggest to get one :).
You can avoid duplication of data in a clustered environment by using a state server - a server that is well known by all the nodes in the clusters and maintains the session data for all the users. Every time a user performs a request, it send a cookie with session id to the applications server; this one should retrieve the session from the state server. This is possible for asp.net development, but I'm not sure how easy Java supports this approach.
As Pekka said, not a good idea. One can intercept your cookie with sensitive session data. Even with SSL, by using fiddler2 one can decrypt the traffic