Django cycles between authenticated and unauthenticated session state - django

When browsing through my website or when I refresh page, it happens that Django forgets about the authentication state and returns the page that an anonymous user would see. When the page is refreshed again it either returns to a logged in session or still shows the unauthenticated state. It's random.
I checked the request headers that are sent by the browser and sessionid is there on every request. Even when the cycle changes from authenticated → unauthenticated → authenticated the sessionid stays the same. So the session is not deleted or purged from the session backend because the session id can still be used after seeing a page in anonymous state. The session is just not picked up by Django.

The website is hosted on render.com, a platform-as-a-service just like Heroku or fly.io. In the application logs I noticed a message Session data corrupted. The metrics showed that autoscaling kicked in and there had been three instances of the application.
This means that one of the three instances was able to return a page in authenticated state belonging to the session cookie while the other two instances were not and instead returned Session data corrupted.
Django uses settings.SECRET_KEY for signing session cookies. Unfortunately I had made the mistake to set a random secret key:
SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", get_random_secret_key())
This meant not only that on every deploy, a new SECRET_KEY would be generated, killing all existing sessions. But also that instances are not able to use the session another instance created because the signing wouldn't match and thus users would cycle between authenticated and unauthenticated state.
Defining SECRET_KEY in the environment is the solution to this problem.

Related

How to detect the logged in user from Keycloak OpenID logout_token on back channel logout?

First let me describe the setup:
We have a frontend Angular based product from a different client team (not part of code we can easily modify), and a backend django based API server.
The front end logs in to a keycloak server, and when logged in, the backend gets an Auth header with a bearer token in every request.
From this, we are able to identify the logged in user as follows (using python-keycloak):
ret = keycloak.userinfo(bearer_token)
username = ret['preferred_username']
This is obviously very wasteful since it needs an extra network request to keycloak everytime - so we create a django user session instead and use that for session management.
Now when it comes to logging out, when the user logs out from the front end, we need to void the django session.
I've setup the "Back channel logout URL" on the keycloak realm settings to call some endpoint on the django server.
The endpoint gets called on logout, and it gets a "logout_token" value in the arguments.
Now I'm not sure how I am supposed to identify which user is logging out based on this token. How can this be done?
Thanks in advance...
I am not 100% sure about the soundness of you architecture. Nonetheless, regarding your particular question:
ret = keycloak.userinfo(bearer_token)
username = ret['preferred_username']
From the Keycloak book:
preferred_username This is the username of the authenticated user. You should avoid this
as a key for the user as it may be changed, and even refer to a
different user in the future. Instead, always use the sub field for
the user key.
From the OpenID connect specification one can read that:
OPs send a JWT similar to an ID Token to RPs called a Logout Token to
request that they log out. ID Tokens are defined in Section 2 of
[OpenID.Core].
The following Claims are used within the Logout Token:
iss REQUIRED. Issuer Identifier, (...)
sub OPTIONAL. Subject Identifier,(...)
aud REQUIRED. Audience(s), (...)
iat REQUIRED. Issued at time, (...)
jti REQUIRED. Unique identifier for the token, (...)
(...)
sid OPTIONAL. Session ID - String identifier for a Session. This represents a Session of a User Agent or device for a logged-in End-User at an RP. (..)
A Logout Token MUST contain either a sub or a sid Claim, and MAY contain both. If a sid Claim is not present, the intent is that all sessions at the RP for the End-User identified by the iss and sub Claims be logged out.
So you can try to use the claim 'sub', which is the unique identifier of the authenticated user. You would (probably) need to create the mapping between 'sub' and 'user' in your backend. Alternatively, you could use the same logic but applying it to 'sid' instead. There you would map the ID session of Keycloak to your own ID session.
However, my question is:
The front end logs in to a keycloak server, and when logged in, the
backend gets an Auth header with a bearer token in every request.
From that bearer token (which I am assuming to be an access token) can't you simply get 'preferred_username' (or better the 'sub' claim) from there? that would not require any extra call to the Keycloak server.

Authentication error because of session timeout on login page of WSO2IS

Whenever I leave the login page for more than one minute, and then try to login, i am getting the following error:
Authentication error!
Something went wrong during the authentication process. Please try signing in again.
And the logs are saying the following:
TID: [-1234] [] [2019-09-26 11:15:46,065] ERROR {org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.DefaultRequestCoordinator} - Context does not exist. Probably due to invalidated cache
I've already enabled the Session Persistence on identity.xml , even tried changing the values of the
<TimeConfig>
<SessionIdleTimeout>15</SessionIdleTimeout>
<RememberMeTimeout>20160</RememberMeTimeout>
</TimeConfig>
Are there any files that can over write this option? Right now, the session timeout is after a minute and I can't figure out where to modify this.
There are two kinds of sessions in the WSO2 IS. The session during the authentication flow and the session created after the user gets authenticated successfully. The first one is identified by the "sessionDataKey" which is passed along with the other parameters in the flow like username, password. The second kind of session is identified with the "commonauthId" cookie.
"Idle Session Timeout" is talking about the second type, how long the user's SSO session will be kept. When we consider about your issue, it is not related to this "Idle Session Timeout". There we have to consider the authentication context.
So, we have to focus on "SessionDataPersist" in the identity.xml. Make sure it is enabled and temporary is set to true. Otherwise, temporary data on the authentication flow will not be persisted into the DB and delayed requests could be failing if the cached data got cleared soon.
<SessionDataPersist>
<Enable>true</Enable>
<Temporary>true</Temporary>
If we have enabled temporary session data persistent correctly, it will keep the authentication context information in the DB until the DataCleanUp task cleans up the old entries from the DB.
For the super tenant, the "SessionIdleTimeout" is read from the identity.xml in the first server startup only. For other tenants, it is read from the config file while creating the tenant. Later the configuration is stored in the database and changes to the config file will not get applied.
Therefore, you have to update the "Idle Session Time Out" value under the resident identity provider from the Management console.

Preventing multiple simultaneous logins with Cognito

We have React Native app that uses Cognito for authentication. We would like to prevent the same user ID from logging in simultaneously from multiple devices.
We were hopefully that we could use a Cognito pre-authentication trigger for this. Unfortunately it seems that we can't just call globalSignOut for the user since that wouldn't invalidate tokens that have already been issued and are currently active (see https://github.com/amazon-archives/amazon-cognito-identity-js/issues/21#issuecomment-331472144).
The other idea was to reject the login if the user is logged in elsewhere. But we can't see a reliable way to tell whether the user is already logged in. We can see if there are valid tokens issued for that user but not if they are currently associated with an active session.
We also thought of maintaining our own DB of active sessions but there is no sign-out trigger so we wouldn't know when to remove a session from the DB.
You can use a token authentication system,
Issue a brand new token for each login, and check for available tokens.
if any token is available for the user that means He/She is logged in some other device, for this case you can prompt user that You are logged in other device.. are you sure you want to log out from that device ? and after clicking yes, you can clear all tokens for that user. And issue a brand new token.
AUTO LOGOUT : this token should be passed all over the back-end i.e. in headers of each and every API call token should be there... and should be checked before doing anything in back-end. if token is not available then throw 401. In your app if any API throws 401 then it means user is UNAUTHORIZED and should be logged out.
or
your app should be listening to one socket that responds to log out when it receives a message of same. so whenever your user logs in, a logout message will be passed across sockets and appropriate device with some token id or unique id will get that message and will log out a particular user from all other devices.
or
have a notification receiver which will be used to log out whenever necessary same as socket.
Reading the link you provided the API token / session system seems being faulty by design since long time already.
So without an own token-system inside cognito you won't have reliable results probably, at least in the current state of the system (as the repository is archived it won't be developed further by the owner).
What I propose is an own field in the database-table for users where each login is honored with an own token. A second own field in the same table with a timestamp, where the last access is saved.
If last access is older than a predefined time of 30, 60 or 120 minutes any user gets logged out.
If the last access is younger than the time-limit then the login-mask has to provide a random access token which is compared with that in the database:
- if the access-token in the database is too old for an active session, or just no access-token is stored, then access can be granted which means login is successful.
- the comparison of the current time with the time-stamp saved in the database is for cases where users never have been logged out by purpose but just by being disconnected or passive. I think this case will happen regularly, so it's no exception.
- logging out by click on a button should destroy the access-token in the database, so that the user can immediately login from any device, even from another one then before.
- if there exists a valid access-token in the database then no new access will be granted and the user should get shown a message that he has to sign out first at another login.
- The access-token could be stored together with a third own field for the session-id to make it more reliable and safe. On logout that session-token-field can be cleared too. The session-token can be copied from the global session if required to be saved in the user-record.
- Any checks are only done on login, tokens never have to be included on every page.
- On active logout the token(s) have to be destroyed to allow a direct login again, else the users had to wait till the max. age of the time-limit is reached to login again - at least on another device then before.
As the login itself is currently done independent from the check that has to be implemented, it would be possible to leave the new access-token completely away but use only the session-id as that differs on any device and browser. But perhaps there exists a situation where one of session-id and access-token can change but the other one not - I don't think so but perhaps I missed something in my considerations.
If you provide the access-token on every page like proposed by #Jadeep Galani or in a cookie - beside the corresponding check - you also can offer a button to sign out from all devices. This would enable the users to change login any time even without logging out at the last used device. Without access-token on every page or in a cookie this general logout-function solution is not possible as else access is only checked on login but not on all pages.
A general question is if it's still worth it to rely on the buggy cognito for login or just replace it completely by an own solution. You even could implement the desired authentication in your site in form of a wrapper-class and the concrete login-system could be replaced without changing that implementation.
You can use the UUID of the device to identify whether it is the same user. Add a UUID to each request header to record it in the DB, and then you can do what you want.

Limit concurrent sessions per user in WSO2IS

We are using WSO2 IS as our enterprise identity platform. One of our tenants must restrict the number of concurrent sessions per user for security reasons.
The expected behaviour is the following: when a user logs in, if he/she already has logged in previously and the session is still valid, the new session must overwrite the previous one, so the login ends ok and he/she gets logged out from the first device/browser. Summing up: the new session always invalidates the old one.
I've been researching sites like this or http://soasecurity.org/ searching for answers, but I couldn't find any.
I think that I need to store the WSO2 IS session id (the one that comes in the commonauthId cookie and gets stored in session cache/persistence store) in the user store, so I can check what's the current user session and log out the user if the cookie id and the store id don't match. But there are two main concerns:
Where do I store the user session id? My main user store is LDAP, but I'd like to avoid one extra attribute there, because it's shared with many other applications and promote changes like this could be difficult for many reasons. Is there any way to put this data into a secondary store?
What's the most appropiate extension point in WSO2 IS to add code for storing the session id in a user store? I've been looking through the authentication framework and found that the method concludeFlow in DefaultAuthenticationRequestHandler class is where new sessions are created when there isn't a previously cached one available. It seems a bit "tricky" to extend that method, but I couldn't find a better solution. Maybe you can customize the authenticator or the user store, but I think that's not a good point of extension inside the authentication flow, because the new sessions are created later, in the request handler.
Thanks in advance.
The WSO2 identity server actually doesn't care about the number of open sessions. IMHO the identity server is not the best enforcement point where to check for the open sessions. Once the user is already logged in, you don't have much control over the framework and the user assertions (or an Oauth token) are returned.
Where do I store the user session id?
If you enable the session persistence, the session information (user session, saml SP sessions, ...) are stored in the database. However - it is intended for internal use. If the user logs out or closes the browser, the records may be still there. There's no information about the user web session.
Just a hint - we've used a VPN proxy (Juniper SA as SP) and WSO2IS as IdP to enforce a unique user session (for a new session the old one is invalidated).
Have fun

How to authorize user in RESTful request?

From the posts about REST services, I see that it should not be used sessions together with REST, and with every request there is need to send user credentials to the REST service. But I don't see that somebody continues then how to make the authorization in next requests after login.
In my project, I authenticate (login) the user, checking his credentials from database server.
If with every REST request also comes user credentials again, does this mean that, for any need of authorization after login, I need to check the credentials again from the database?
This means, after login, with almost every click and surfing pages, I need to access to the database to check the user credentials, just like I do it for login.
Or...
Am I missing some thing?
Is there another way to remember in the server side that the user had already logged in before and thus is authorised?
Do I keep some secret key related to the user in the server, and then check this etc.? But, does not this mean keeping a session?
REST => Not Session => Send credentials with every request
Does the above mean, => Authorize the user just like in the authentication ?
Or what are other alternatives?
Thank you for clarifications.
I think that this is the best approach:
REST => Not Session => Send credentials with every request
Take a look on OAuth. The version 1.0 may be useful for you.
Spring Security already have implementations for OAuth in Java.
If with every REST request also comes user credentials again, does this mean that, for any need of authorization after login, I need to check the credentials again from the database?
You have to authenticate user on each request, but whether authentication uses database or not depends on implementation. By the way, you also have to then authorize the request for the authenticated user.
Do I keep some secret key related to the user in the server, and then check this etc.? But, does not this mean keeping a session?
You can have some secret key known only to the user as an alternative to username-password pair and use this secret key for authentication.
The presence of a secret key doesn't mean keeping a session, because it is not necessarily change on a per session basis.
In my project, I authenticate (login) the user, checking his credentials from database server.
Login is not authentication, it's usually a request for a secret key / session key done using username-password pair for authentication