Client, Auth Server and Logout - spring

So, i have a standalone OAuth2 auth server and client app (web-based), all using Spring OAuth2.
I have a login form host on the Auth server with redirection etc from the client app using Spring setup (via the login form).
All good so far.
I added a logout setup on the client:
.and()
.logout()
.addLogoutHandler(oauth2LogoutHandler())
.logoutSuccessUrl("/")
.clearAuthentication(true)
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
That all 'seems' to be fine.
However, if i then hit the 'login' link on my client, when it redirects to the Authorisation app i dont get the login screen, but simply the redirection handshake occurs and i'm back in the client app.
So, the question is, what is it need to 'clear' in the Auth server when i logout on the client app? Somehow session info is persisting on the auth app but i cant find how that session is being picked up when i hit login? is there a clean way to propagate a 'logout' to the Auth Server?
Many Thanks
Martin

https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v#the-logout-experience describes essentially the same problem for a notoriously tricky problem.
The Logout Experience
If you click on the “logout” link you will see that the home page changes (the greeting is no longer displayed) so the user is no longer authenticated with the UI server. Click back on “login” though and you actually don’t need to go back through the authentication and approval cycle in the authorization server (because you haven’t logged out of that). Opinions will be divided as to whether that is a desirable user experience, and it’s a notoriously tricky problem (Single Sign Out: Science Direct article and Shibboleth docs). The ideal user experience might not be technically feasible, and you also have to be suspicious sometimes that users really want what they say they want. “I want ‘logout’ to log me out” sounds simple enough, but the obvious response is, “Logged out of what? Do you want to be logged out of all the systems controlled by this SSO server, or just the one that you clicked the ‘logout’ link in?” We don’t have room to discuss this topic more broadly here but it does deserve more attention. If you are interested then there is some discussion of the principles and some (fairly unappetising) ideas about implementations in the Open ID Connect specification.
Here's a PR I submitted on github for an Spring-based OpenID Connect (an extention of OAuth2) project to implement an "End Session Endpoint" on the Authorization Server: https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/pull/972. It implements part of the https://openid.net/specs/openid-connect-session-1_0.html#RPLogout spec for RP-initiated (or client-initiated) logout.
I don't think Spring has a built-in mechanism for this. There are other specifications, other than the one I partially implemented, for logout. Whichever you chose, it's probably a good idea to follow a documented spec.

You should enable the logout extending the WebSecurityConfigurerAdapter and create a logout page that send a post to /logout in the Authorization App
Logout page: (resources/templates/logout.ftl)
<html>
<head>
<title>Logout Page</title>
</head>
<body>
<form role="form" action="logout" method="post">
Logout
<input type="hidden" id="csrf_token" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="hidden" id="redirect" name="redirect" value="${RequestParameters['redirect']!'/login'}"/>
<button type="submit">Logout</button>
</form>
</html>
The redirect input hidden will redirect to the client application after logout

Related

Tomcat disable session not working

I have several apps deployed in Tomcat 7, and use Keycloak to manage user login and logout of these apps. Logout does not work i.e., does not log the user out and redirect to Keycloak's login page. Then I found the JSESSIONID cookie is still present, once I deleted the JSESSIONID cookie, the logout link works as expected. So I tried to disable Tomcat's session by putting
<%# page session="false" %>
in the header of my apps' JSP pages. Unfortunately, this still does not seem to disable Tomcat's session, I still see JSESSIONID cookie present. I am wondering if anyone has a solution to this problem? I believe the presence of the Tomcat session interferes with the Keycloak's SSO session, and causes Keycloak logout to not work. This has to be a common problem Keycloak users encounter, Tomcat is so widely used for web apps.
Would appreciate any tips on how we should handle this!
I don't have specific experience with Keycloak, however, there's a principle that applies to most if not all Single-Sign-On (or external authentication) solutions:
SSO identifies a user and removes the burden of knowing passwords from typical applications. When a user signs in, an application server is often detached from the actual SSO system, thus it will need to cache the user once they're identified, just as if the user identified itself with a classic login.
On the logout side, you can either log out of the application itself (tomcat in this case) or you can log out of the SSO system (which seems to be what you're doing here). With the later approach, you're running into the problem of "Single Sign Out": Logging out of the SSO system should invalidate all sessions that once were initiated with the associated login. As I know it, the SSO system needs to keep track of all of the systems that have signed on through it and trigger an explicit logout there.
I can't tell you how to implement this in Keycloak, but hope that the general principle helps guiding you towards the solution:
The use or non-use of a session on Tomcat's side has nothing to do with the problem: You might have applications that legitimately store information in a session in addition to the signed in user - those applications should continue to work even if you're not comparing passwords in tomcat itself.
Edit, after your comment:
If this one page doesn't trigger the use of a session, any other code (e.g. the code that processes your login) still might trigger a session and then later delegate to the page that doesn't want to use a session.
I'd expect that you'll have to disable sessions in Tomcat's configuration e.g. through providing a custom "Manager" implementation. It looks like the default ones do not expect you to completely ignore sessions. As I've outlined above, I'd also expect sessions to be required even if you're not logging in through Tomcat itself.
Another way to avoid sessions (this is the indicator why I don't expect "no session" config to work) is to avoid calling any method on request/response that would trigger the automatic creation of a session. And it seems that you have such a method somewhere in your app.
(someone correct me if I'm wrong. This is mostly my educated expectation as I've never looked at this requirement)

Cross site forgery on AJAX service

I'm a little confused as to how to prevent cross site forgeries. Still. I know there is a wealth of information out there, but I'm confused.
In Steven Anderson's post he describes a form like this:
<body onload="document.getElementById('fm1').submit()">
<form id="fm1" action="http://yoursite/UserProfile/SubmitUpdate" method="post">
<input name="email" value="hacker#somewhere.evil" />
<input name="hobby" value="Defacing websites" />
</form>
</body>
On someone else's site.
The solution given is a "anti-forgery" token, generated by the server, that is POST-ed back to with any requests in a hidden form. That's cool, but what is to stop the hacker just downloading the form page, extracting the token and POSTing it?
My application for this is: On the sign-up for to my website I'd like a AJAX function that sends the currently entered Username to the server which should respond "True/False" if it is available or not. This happens onKey so the user can pick a username that has not been used already. The Submit button will enable when all the conditions for "new user" are met.
Clearly this is an opportunity for a hacker to use the service to "test" lots of usernames to see if they available - I know it's not exactly internet-banking level sort of risk, but I'd still like to service only requests from my application, not a hacker.
Any ideas how about these queries?
UPDATE:
So in my scenario. I generate a Token (say some hashed value of the client's IP address) and the service expects to receive this back if it is give the information about whether the username is available or not.
-- The problem remains, someone off domain simply calls the service e.g. /generateToken This looks at the client's IP... could be a hacker who knows.
Returns
{ token: 4uru32br }
Which is then submitted to the /isUsernameAvailable?token=4uru32br&partialUsername=usernam
Where does that get me?
what is to stop the hacker just downloading the form page, extracting the token and POSTing it?
The same-origin policy, that's what.
I'd like a AJAX function that sends the currently entered Username to the server which should respond "True/False" if it is available or not.
That's a user-enumeration vulnerability right there.
Any ideas how about these queries?
Here's your new process:
Use email addresses for usernames.
Use CAPTCHA to prevent automation on registration forms.
Email username does not exist:
Show "success" message. Send email to address with one-time link. Register user after returns to your site with that link.
Email username does exist:
Show "success" message. Send email to that address with message saying "someone is trying to create an account with this address but it already exists".
You're mixing up CSRF and user enumeration.
The solution given is a "anti-forgery" token, generated by the server,
that is POST-ed back to with any requests in a hidden form. That's
cool, but what is to stop the hacker just downloading the form page,
extracting the token and POSTing it?
Say Bob is a normal user on your site.
Chuck is an evil attacker.
Bob goes on your site and submits the comments form (in your code example). If there is CSRF protection, a token is included in this form too:
<input type="hidden" name="csrf_token" value="zxcvbnnmm1235152" />
Bob's session has token zxcvbnnmm1235152 stored for him server-side.
Chuck also has a login to your site because he has registered.
However, when he goes to this page he gets this token instead:
<input type="hidden" name="csrf_token" value="lklkljlk898977" />
If Chuck downloads the page, gets Bob somehow (e.g. sends him an email) to access this page on Chuck's server, because the csrf_token doesn't match Bob's, Chuck can't post the message as Bob.
Bob can continue just fine, because the token in the form matches the one associated with his session.
CSRF is about stopping Chuck from submitting stuff as Bob, using Bob's browsing session.
My application for this is: On the sign-up for to my website I'd like
a AJAX function that sends the currently entered Username to the
server which should respond "True/False" if it is available or not.
This happens onKey so the user can pick a username that has not been
used already. The Submit button will enable when all the conditions
for "new user" are met.
Clearly this is an opportunity for a hacker to use the service to
"test" lots of usernames to see if they available - I know it's not
exactly internet-banking level sort of risk, but I'd still like to
service only requests from my application, not a hacker.
Yes, this is your user enumeration vulnerability.
Have username as email, and follow this answer on how to make this secure.
The anti-forgery token is not a random code. Nor a reused token for several requests.
Rather, the server couples the token with the callers ip-address or session, for example by encrypting the ip+salt with a server-key.
Thus, if the attacker tries to download the token from your site, it won't be usable by the real client

Spring security, AJAX and SiteMinder

I am implementing Spring Security login and I am trying to understand something, here is the scenario I want to implement:
For initial login show login page and let user in.
If after some inactivity session expired and user makes some action show him popup window to authenticate (js-based popup in browser). Continue with the action like there was no login form.
Implementing form is easy, but how do I make the popup work - let's say I make the request to some protected URL after session expired, how do I make sure it's not forwarded to login page, but to my login handler that shows popup window?
Another issue - I need to integrate with SiteMinder, so I would need to read the Login/Password combination and after it's read, forward to SiteMinder for authentication, after that's done I want to return without forwarding.
Answer to SiteMinder issue:
Siteminder is generally installed on a Webserver behind your servlet container.
Also, Siteminder manages the authentication and an application does not have access to a user password at all.
To integrate with Siteminder use this filter:
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#d0e6295.
Answer to the login with the popup issue: since you need to integrate with Siteminder, I would not recommend to implement the login via the popup.
The sample given on the above springsource website is quite primitive and can break in several use cases. Using the SM_USER header alone has several caveats, see my answer here: How to validate SM_USER header in Spring Security preauthentication for siteminder
CA SSO aka SiteMinder, as well as other traditional html-form-request-response SSO systems, have a hard time dealing with Single Page Applications and protecting the web services that you invoke via AJAX, without breaking the flow of your application.

How to recover from a Spring Social ExpiredAuthorizationException

I am trying to implement Google Oauth2 with Spring Social and spring-social-google. Initial authentication works fine. However after some time the authentication expires and I am hit by
org.springframework.social.ExpiredAuthorizationException: The authorization has expired.
How can you recover from this exception? Is it possible to somehow refresh the authorization?
Try to send additional access_type=offline paramter during authorization. It may looks something like this:
<form ...>
.....
<input type="hidden" name="access_type" value="offline"/>
</form>
Normally in this case authorization will be refreshed automatically for you. See this entry for more details.

From HTTP to HTTPS, the sooner the better?

If I have this page in "http://example.com/login" with GET verb:
<form action="https://example.com/login" method="post">
<input type="text" name="login"/>
<input type="password" name="pass"/>
<input type="submit" value="Login"/>
</form>
Is it a security flaw? I mean, the page is HTTP but when sending the data it uses HTTPS. I have read several times that I should require HTTPS already in the login page, but I don't clearly see why.
Yes, it's flawed. What you have is secure as far as it goes, as long as it's your login form the user is seeing.
Because your login form isn't secured, I can come along and substitute my own spoof login form and collect your users' login details, eg. via a man-in-the-middle attack. A login system is only secure if both the login form and the target page use SSL.
Also, it doesn't look secure to the user. Users look for the padlock symbol on the login form, and yours doesn't have one.
Yes, it is a security flaw.
Since the form is served over HTTP, it is subject to being edited along the way. This edit could be, for example, the additional of JavaScript that sends the credentials to a server that the attacker controls as well as letting the browser log in normally.

Resources