Cookie based SSO - single-sign-on

How can I implement a cookie based single sign on without a sso server?
I would to share the user logged in across multiple applications using
only a cookie on the browser.
In my mind it's working like this:
user logs in an application
the application verifies the credentials and then it setting up a cookie on
the browser storing the username (that could be coded with a private key)
if the user opens another application, it searches the cookie and reads
the username on the value (using the key for decode the string)
In this solution a user may see the browser cookie (of a another user)
and take the string codified of the username. Then he could adding it on
an own cookie (no good!).
There's some secure way to do this? With a timestamp based control or
something like this?
Thanks in advance.
Bye
P.S.
I know that my english isn't very well.. sorry for this!

This is impossible. Cookies are unique to each domain, and one domain cannot read another domain's cookies.

I think the answer comes a little late, but maybe I can help someone.
You can have a cookie / localStorage in an intermediate domain connected to the home page using an iframe
1) Login
The login form in any of your domains deposits the identification token in a cookie on sso.domain.com by an event (postMessage)
2) Verification
domain1 and domain2 include a iframe pointing to sso.domain.com, which reads the token and notifies the home page
To simplify development, we have released recently a cross domain SSO with JWT at https://github.com/Aralink/ssojwt

There is a simple solution without using an sso server, but not with 1 common cookie, as we know that cookie's are not shared between domains.
When the user authenticates on site-a.com, you set a cookie on site-a.com domain. Then on site-b.com, you link a dynamic javascript from site-a.com, generated by server side script (php, etc) who has access to the created cookie, and then copy the same cookie on site-b.com on the client-side using js. Now both sites have the same cookie, without the need of asking the user to re-login.
You may encrypt/encode the cookie value using a method that both site-a and site-b knows how to decode, so that site-b will be able to validate his cookie copy. Use a common shared secret that without it will be impossible to encode or decode.
You see that on the 1st page load of site-b.com, the cookie is not present, therefore if you see necessary, you may want to do a page reload after setting the cookie.

I have done something similar. There is a PHP application where the user logs in, the system contact a web service and then the service checks the user's credentials on the Active Directory. When the user is authenticated, his PHP session is stored in the DB. Another web application can read the PHP session from the cookies and uery a web service in the PHP applicaiton, the PHP application check the session in the database and return the user id. In this way I have a SSO using SOA.
Do not rely on the user id stored in the browser, is a security error, at least encrypt the id.
The best solution would be to put the login form and session storage in the same application, then this application can provide services to other applications.
And use HTTPS for the kind of infomation exchange.
The cookies can be read only if the belongs to the same domain, for instance:
intranet.example.com
crm.example.com
example.com/erp

You can access cookies across subdomains, but I do not think using browser cookies is a great solution. You really don't need a "SSO server" to implement a single sign-on. It is fairly easy to come up with a payload that both applications recognize. I have seen custom SSO solutions that transmit the payload using XML over HTTPS.

Here is a solution (which will hopefully get heavily scrutinized by security gurus on here):
Have each domain store user data in a similar cookie, and when a user want to jump from one domain to another without authenticating themselves on the new domain, provide a "jumplink" with an encrypted token in the query string. The new domain would decrypt the cookie, and figure out who the user is, then issue them a new cookie for that domain. You would want the "jumplink" to have a very short expiration date, so I would not generate them right into the page, but generate links to a "jumplink" generator and re-director.
This might not be necessary, but the receiving page for the "jumplink" could make a web service call back to the originating domain, to verify the authenticity of the encrypted token and the whether it's expired.
I think this solution would be susceptible to man-in-the-middle attacks (not sure if it would be more so than other auth mechanisms which are currently popular), but you could incorporate a client MAC address and IP address into the encrypted token for extra security.

Related

JWT default GET action limitation?

I've successfully used cookies before and I'd like to begin using JWT. My biggest question is how to pass your token to a website during the initial GET operation, for example when a user types your domain into their address bar or clicks on a link from some other website like google.
When using cookies for example, if you type stackoverflow.com into your web browser, the persistent cookie is sent to the website which seamlessly allows your own stackoverflow session to be automatically authorized.
I am aware that I can programatically pass my JWT token via a javascript GET through the HTTP headers but how do you pass the token when a visitor types in your URL into their web browser?
Possible solution #1
My thoughts have been to have javascript code check if 'authorized'. If not, check for a JWT token in local storage. If found, redirect to the same address. The problem of course would be that there is no way to pass the token during a redirect.
Possible solution #2
Similar to above but not issuing a redirect, I would update the current page to reflect the 'authorized' state.
Possible solution #3
Use a permanent cookie containing the JWT token. I am thinking that this 3rd option would be the best. If I did this, there would be no need to pass the JWT via an HTTP header.
I've thought about this for a few days, read up on JWT and here are my conclusions for avoiding JWT in my particular case:
No easy way to authorize a user who opens their browser and types in your website. With cookies, your server immediately knows how to respond to this headerless GET request.
No way to easily change the JWT token signature. All users are immediately affected by such a change, essentially forcing everyone to authenticate again.
No way to easily invalidate a specific JWT token. The best you can do is to maintain and check a banned signature list on the server. This of course would require a centralized or distributed server method almost identical to a cookie session management system. This would force a coupling between the token and the server, no longer stateless as intended by JWT.
SUMMARY
Cookie management requires more server infrastructure but you have much greater session control. State is seamless (in the case of #1 above). You can instantly invalidate state. For example, the user can log out (deleting the session at the server level) or the session can be instantly banned by an administrator by simply deleting the session.
I also see the benefits to JWS:
no need to hit the db or cache system when authorizing.
simple authorization between multiple servers having the secret key.
simple authorization, no session management programming and no db session state storage required.
...but the drawbacks stated previously are too great for my particular needs.

Restrict front client connexion with groups / roles in a realm

I'm looking for a way to restrict user access to specific clients in a realm.
I know I can do it with client where Authorization is enabled (fine-grained authorization support) but it doesn't work when trying to connect from front (client need to be public and not confidential).
I'm using a javascript application to login from front-end.
Is there a way to enable Authorization for public client or a work around ?
Thanks.
I'm not sure if this will totally answer your question because it's still not specific enougth but it may give you some further help.
In case you're new to the topic, please see difference between public and confidential clients here.
The current best practice for public clients like HTML/Javascipt applications is to use OpenId Connect with the Authorization Code Flow + PKCE. HTTPS is of course a must have. I recommend you use a javascript openid connect adapter for this like the following for example:
https://github.com/panva/node-openid-client
Basically your authentication / authorization flow is shown here:
When the user wants to login from your frontend client application first a unique verifier is generated which is only available to the exact user / browser session. This value get's hashed as a code challege. Then the user gets redirected to the login page of your authorization server (Keycloak for example) passing some parameters like a redirect uri and the challenge.
With successful login the user get's a session at the keycloak server which also stores the hashed challenge. Then the user gets redirected to given redirect uri (a path in your application) together with a code to obtain an access token. Back in your application you application uses the original value together with the code to get the actual token. The authorization server ckecks the value against the stored challenge and geturns the access token if it matches. You see the extra verifier is to prevent that anybody compromises your code fragment to obtain a token on your behalf.
Now you have an encoded access token in your browser app. Note the token itself is normally only encoded not encrypted but it can be signed. Those signatures can later be used from your backend to ckeck the token integrity but we will come to that soon. Roles, claimes, scopes and so on included in your access token tell you the privileges of the user/identity. You can of course use them to enable/disable functions in your app, block routes etc. but in the end client protection is never really effective so your real authorization ande resource protection happens at your resource server which is your backend (node, .net core, java etc.) maybe a restful Web Api. You pass your access token as a part of the http request header with every request to the backend. Now your backend checks the token integrity (optional) expiration time etc. analyzes scopes, claimes and roles to restrict the resource access.
For example a simple GET myapi/car/{1} may only need a token or can even be annonymous while a POST myapi/cars or PUT myapi/car/{1} may need a special role or higher privileges.
Does that help you out?

How to authenticate without hitting the database?

A comment below an answer about state and REST recently piqued my interest. For clarity I'll quote the comment in full:
Nothing in my answer implies a solution based on database access on every request, if you think it does, it is a failing on your part to understand authentication and authorization at that scale. The authentication can be implicit in the state, do you think that facebook does a "database access" on every request of its REST API? Or Google for that matter? hint: no
I tried to think how one might authenticate without checking a user-provided value against a centrally-held one, even if one to know what data to display to the user, and came up blank. i freely admit this is a failing on my part to understand authentication and authorization at that scale. My question is therefore: how do sites like Facebook and Google accomplish this?
One way is claims based authentication. Simplified and somewhat loosely interpreted, it boils down to this;
Instead of the server application authenticating the user itself, an un-authenticated user is redirected to a separate authentication server.
The authentication server validates the user in any way it wants to (login+password, certificate, domain membership etc) and creates a signed "document" with the relevant user info (user id, name, roles, ...) It then redirects the user back to the server application with the document enclosed.
The server application validates the signature of the document, and if it trusts the signature, it can use the document contents to assume who the user is instead of accessing the database.
Normally, the server application caches the document in a cookie/session or similar so that the next access to the application does not have to bounce through the authentication server.
In this way, the server application does not need to concern itself with how the user is authenticated, just whether it trusts the judgement of the authentication server. If the authentication server (and possibly the client unless it's a browser) adds Facebook login support, the server application will automatically "just work" with the new login type.

Login to a website from iphone application

I am working on iPhone application which have login form to access application functionality same as website. now i want to add one button in iphone application that redirects user in to website in safari browser with successfully login.
After success login in to iPhone application, user want to check website in browser so i just need to add functionality that user can directly login in his account and redirect on particular page.
i have some basic idea for that we can do with encrypted username and password with url.
like http://xyz.com/login/username=abc&password=abc
but i know that its not secure way to pass username and password with url.
So please suggest me any other way if possible.
Any idea or alternative that how to implement this.
Thanks in advance.
There are a few ways to do it.
Any time you send password information over the Internet you want it to be encrypted over SSL. This will require an SSL Certificate for your web server though and it's not always possible.
You can also encrypt the username and password yourself in a way that only your web server will know how to decrypt. So the username "foo" could be turned into "oof" and the password "bar" could be turned into "rab". That way if someone intercepted your requests, they couldn't know what the username and password were without knowing how you changed them.
Why not pass the session id?
Here's what I mean: When you log in to a web site, typically you're assigned (or already have) a "session cookie" which essentially tells the server "This visitor has session ID 'XYZ'", and allows it to retrieve the server side information stored for that user (like who they are, that they authenticated, or whatever else you store in the session store.
One of the easier ways of moving to/from applications is to make sure that all logins generate a server side session, and provide a script which will overwrite the user's session cookie and redirect them to the proper page.
session_restore.php?sessionId=12345&redirect=HOME
The doubters here will argue that providing such a script is tenement to a security breach, but I would argue that all of this information is stored client side already, and can be accomplished without the server's intervention anyway. (session hijacking plugins for popular web sites exist for firefox that will grab session IDs from wireless networks - no technical skill needed)
Doing it this way just makes the process friendlier to the user, and if your site provides SSH access (which you really should be doing anyway) then the risk is very minimal.

SiteMinder and HTTP Client - User Login Info

We have a Portlet running on Java/J2EE technology. It interacts with another application/system through HTTP request that requires user authentication. The current solution retrieves logged in user's user name and password from the Portal, and passes this information to back end systems using "HTTPClient" API's to retrieve content based on user's authentication and authorization.
There are efforts to enable site minder for the Portal. With site minder enablement, the Portal no longer provides logged in user's user name and password. The ideal way would be that back end application also has site minder enabled so that Portlet could pass the login token or cookie value.
Looking for interim approaches until the back end application is SiteMinder enabled. Is there a way we can enable/force user to enter user name and password ? I cannot think of such possibility because the Portlet code (using HTTP Client accesses the back end URL of the application, its not the browser). One possible way I can think of is, develop a new screen(UI) to have user enter user name and password within the Portlet and use that to authenticate with back end system through Java code. Please let me know if any other ideas.
Also, let me know if the question is confusing, I will provide more details.
Thanks
Siteminder can provide user information dynamically to connected applications in HTTP headers (uid, email address, etc.). This behaviour is configured on the Siteminder Policy Server. By default, the HTTP header SM_USER (or similar) contains the username of the authenticated user.
Then, you have to adapt your portlet code to fetch those headers from the request and feed it to the back-end application like you used to.
I wouldn't advise the use of the SM_USER header for tracking users. SM_USER contains the ID that was provided to the credential collector, and will change based on the type of authentication scheme used.
Example:
If you have an HTML forms based auth scheme that collects email address instead of UserID, the email address will be sent in the SM_USER header. In the case of an X.509 auth scheme the SubjectDN from the certificate will be in the SM_USER header.
The better choice would be to use the SM_UNIVERSALID header as that will always contain the Universal ID attribute. The Universal ID attribute is configured in the User Directory object (typically this is set to "uid").