SpringSession SecurityContext Auth token not persisting - spring-mvc

I'm working on implementing SpringSession on an application with SpringSecurity using xml configuration. I followed this guide and the application is working 95%, confirmed that it is hitting the redis backend: http://docs.spring.io/spring-session/docs/current/reference/html5/guides/security.html
The application stores some information in a custom authentication token that extends UsernamePasswordAuthenticationToken. After implementing spring session, it seems like the data stored in the token is going to the wrong place or not persisting. The flow is like this:
Request is made and mapped to the Controller
The Controller gets the AuthorenticationToken in a fashion like this SecurityContextHolder.getContext().getAuthentication()
This token is the custom token that extends UsernamePasswordAuthenticationToken and a custom field is set like token.setFoo("bar")
The controller is finished and returns a ModelAndView with a redirect command like this redirect:/nextController
In the logs I see after the controller is finished, Chain processed normally and SecurityContextHolder now cleared and later, Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT
At this point, the field that I set in the auth token inside the SecurityContext, token.setFoo("bar"), is null.
If I disable the SpringSession configuration I can see that application uses a cookie called JSESSIONID instead of a cookie called SESSION and that the authentication token is populated and persists correctly.
Any help on this very troublesome bug would be greatly appreciated, thanks!

Related

Create session with BASIC authentication

I want to write a servlet with which I can create a new session.
The servlet requires the user to authenticate with BASIC authentication and returns the standard session cookie (using HttpServletRequest#getSession(true)). However, if the client uses the received session cookie in his next request instead of BASIC authentication it is not authenticated. The server recognizes the session but it doesn't contain the user information.
I'm using Tomcat and after a bit of debugging the reason is also obvious: the user information (Principal) is added to session upon authentication. However when the first BASIC authentication is taking place no session exists yet as this will be created by the servlet. Does anyone have idea how to solve this problem?
After one night of sleep [1] I believe I have come up with a working solution myself. The following snippet (using JAX-RS, but it shouldn't be too difficult to translate it to plain servlet code) does the trick if the calling client will follow redirects:
public Response getSessionCookie() {
boolean sessionExists = m_servletRequest.getSession(false) != null;
if (sessionExists) {
return Response.noContent().build();
} else {
HttpSession session = m_servletRequest.getSession();
return Response.status(Status.TEMPORARY_REDIRECT)
.header("Location",
m_uriInfo.getAbsolutePathBuilder().matrixParam("jsessionid", session.getId()).build())
.build();
}
}
The first request will create a session and redirect the client to the same address but with the session ID in the URL (which is important). The client will follow the request and send the same BASIC authentication data again but now it will be registered in the existing session. The second invocation of the method above will simply return an empty response with the session cookie that can now be used for subsequent requests.
Note that the session cookie is different for me in the second response but looking at Tomcat code this seems to be deliberate (successful authentication will always create a new session).
[1] Sleep is highly underestimated!

Spring-Security-OAuth2 - how to add fields to access token request?

I have a Spring Boot application, that is using Spring Security with OAuth 2.0. Currently, it is operating against an Authentication Server based on Spring Example code. However, running our own Auth Server has always been a short-term target to facilitate development, not a long-term goal. We have been using the authorization_code grant type and would like to continue using that, irrespective of the Auth Server implementation.
I am attempting to make changes to use OAuth 2.0 Endpoints in Azure Active Directory, to behave as our Authentication Server. So far, I have a successful call to the /authorize endpoint. But the call to get the /token fails with an invalid request error. I can see the requests going out.
It appears that parameters that Azure states as mandatory are not being populated in the POST request. Looking at the Azure doco, it expects the client_id to be defined in the body of the message posted to the endpoint, and that is not added, by default, by Spring.
Can anyone point me in the right direction for how I can add fields to the Form Map that is used when constructing the Access Token request? I can see where the AccessTokenRequest object is being setup in OAuth2ClientConfiguration....
#Bean
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
protected AccessTokenRequest accessTokenRequest(#Value("#{request.parameterMap}")
Map<String, String[]> parameters, #Value("#{request.getAttribute('currentUri')}")
String currentUri) {
DefaultAccessTokenRequest request = new DefaultAccessTokenRequest(parameters);
request.setCurrentUri(currentUri);
return request;
}
Should I be trying to define the map in a request.parameterMap spring property? If so, I'm not too sure how that works.
Or should I be using one of the interfaces defined in the AuthorizationServerConfigurerAdapter class?
I have the information to include when sending the AccessTokenRequest, I just don't know the best way to configure Spring to include it? Thanks for any help.
Actually, I found this out. I needed to change the client authentication scheme. Simply adding the following to my application properties added the client_id to the form....
security.oauth2.client.clientAuthenticationScheme=form
If you're using yaml, then yaml-ize it. Thank you Spring!

Implementing Authorization in a Self Hosted SignalR Server accessed from Web

I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] – only authenticated users
[Authorize(Roles = "Admin,Manager")] – only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] – only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated

HttpServletResponse: Keep, Save or Persist the response for later use...?

I am using Spring to create my webapp. I have a scenario like:
An ExternalService sends a GET request to my Controller that has a mapping /DoOperation with some user info as param. I get the param check the user if he is logged into my system or not if NOT i send him to OpenId verification with returnUrl, which is in same webapp say /Authenticated.
The ExternalService does not provide a returnUrl (Not related to OpenId returnUrl) and forces to respond the same request it made at /DoOperation.
Now, How could I keep the very HttpServletResponse (if there is a way, apparently there is not) so that I can write a response once I have gone somewhere else e.g. at OpenID page to verify user and then /Authenticate in this case... so that ExternalService could read it.
Could Servlet Filter help here?

Is it possible to forward the current user's FormsAuthentication Identity to another Controller action?

I'd like to use ASP.NET MVC's views as mail template engine. For that, I am calling one controller action from another controller action using a System.ComponentModel.Component.WebClient, parse the returned web page and send it via e-mail.
In this scenario, is it possible to forward the current user's login credentials (I am using FormsAuthentication) to the controller action requested by the WebClient? User passwords are encrypted, so I can't just create a new NetworkCredentials instance with his user name and password.
Yes, you can just copy the .ASPXAUTH cookie from your current Request object to the WebClient
EDIT: I haven't actually tried this myself, so maybe the .ASPXAUTH cookie is removed from the Request object for security reasons.
But since you have access to the machine key, you can create your own cookies on the fly. Here's the code that should do it (I can't find the project where I actually did that)
var ticket = new FormsAuthenticationTicket(User.Identity.Name, true, 5);
string aspxAuthCookieValue = FormsAuthentication.Encrypt(ticket);
This code creates a forms authentication cookie for your current user name and with an expiration time of 5 minutes.
Instead of performing a http request, aren't you looking for something like "rendering a view to a string"

Resources