We’ve been using SS for about 6 years now on the same project, and in that time have encountered the following issue about 5 times.
An already logged in user, or one that logs into their account, sees another users account instead.
At first I brushed it off as there was minimal info to go on (and still kinda is). However, it’s happened twice in the last few months and there must be something behind it.
Here’s what I have to go on - and how we current have SS setup.
We use JWT authentication and redis for SS caching. Every service endpoint fetches from the cache the user session info which is used to verify the data passed in is valid for that user to edit etc.
The times we have noticed the issue seem to be linked by a production update, with reported incidents happening with a short time of the update.
Today it occurred 3 minutes after the update. We do not clear redis during a production update.
The one additional detail we found today was the the two users is the both logged in within 1000th of a second.
Any thoughts on the cause or where to dig into SS code if necessary would be greatly appreciated. Although a rare occurrence, it’s a big deal.
If I had to guess I’d say it sounds like you’re authenticating when you’re already authenticated where it will merge the accounts together, but I wont know without being able to repro.
To avoid this you should logout to clear the existing login.
Interesting. I’ll try to investigate that further this week/next. I agree it’s a tough one to figure out since I can’t reproduce it and have seen it only a handful of times after millions of logins.
Can you point me at the code that does the merging in such an instance. I want to further understand the situations in which it happens and try to repeat what we’ve seen.
As far as logout, are you suggesting automatically logging out users somehow? One thing we want to avoid is logging users out after a production update if there is no need.
The implementation is in each Auth Repository which for OrmLite is at:
Users shouldn’t have to logout, I’m saying if you’re already authenticated and you re-authenticate it can merge the accounts together. I’m not sure if that’s what’s happening, I’m just thinking of a possibility of behavior you might have seen.
Or if you’re running multiple apps on the same address (e.g http://localhost:5000) then it could be authenticated using your JWT from a different App that was previously running at that location, I’ve seen that behavior before. (Again you’d need to logout to clear the existing token/session).
So, to my happy surprise we were able to create a unit test that duplicated the issue as we currently have experienced it. It’s a race condition in The credentials auth provider. If you try and login multiple users with minimal time separation, we had a class variable holding user information that would get overwritten and the same “user” used in both login sessions.
I believe this is not an issue in existing SS auth providers as we have a custom auth provider in which the error was discovered. The auth provider is registered in IOC as a singleton which lead to the race condition.
We are still facing the above mentioned issue raised by @tracstarr. Currently we are using ServiceStack 6.1.0 along with JWT Authentication and Redis for caching. Also we have implemented a CustomAuthProvider for Two Factor Authentication in our Application.
@tracstarr How did you handle the race condition? Is there any way to avoid this “The auth provider is registered in IOC as a singleton which lead to the race condition.”
@mythz Does ServiceStack has any updates regarding this?
This isn’t an issue in the built-in Auth Providers AFAIK.
FYI this is how we resolve the AuthProviders internally:
Which is resolved from AppHost GetAuthRepositoryAsync():
var authRepo = (IUserAuthRepositoryAsync)
HostContext.AppHost.GetAuthRepositoryAsync(request);
i.e. it will call .Dispose/Async() if your Auth Repository requires it which should support singleton or transient registered Auth Repositories. If your Auth Repository is registered as a singleton it should be thread-safe.
Also make sure you’re not maintaining any state in the custom AuthProvider, any request state should be maintained in IRequest.Items or user session.