I have some resources that I have in a Spring Boot setup that a user needs to have a session for.
Right now, these endpoints in need of defense all look like this.
#RequestMapping(value = "/SomeEndpoint", method = RequestMethod.POST)
public ResponseEntity<SomePacket> Foot(#RequestBody Dummy dummy,
HttpServletRequest request,
HttpServletResponse response) throws IOException, RestSessionException {
if (session.getAttribute("clientId") == null) {
throw new RestSessionException("No Client");
}
Each.and.every.one.of.them...
What I would like to do is reduce the amount of duplication throughout my codebase with checking for a "clientId" on the session. I've read about WebSecurityConfigurerAdapters, but they seem to revolve more around the fluent interface, and not so much around retrieving session values.
Does anyone know how I can check session properties for certain endpoints in a WebSecurityConfigurerAdapter?
Any help is greatly appreciated.
WebSecurityConfigurerAdapters is implementation of spring security and which provides functionality for authorisation and authentication for your endpoints. For more info about WebSecurityConfigurationAdapter read this
Your requirement can simply achieve by adding filter and applying required logic of checking clientId in doFilter method.
Related
Using spring boot to integrate spring session and spring actuator at the same time. Due to the use of prometheus monitoring, it will periodically initiate http requests for health checks and performance monitoring, but each request will generate a new session, due to the use of session sharing. The session is stored in redis, which produces a large number of useless sessions. Is there any better solution at present?
I found a similar problem in github, and the problem is still open, but someone has already proposed a solution in the problem, the link is as follows: Is it possible to exclude some url from the SessionRepositoryFilter.
The sample code use filter set SessionRepositoryFilter.FILTERED.
#Component
#Order(Integer.MIN_VALUE)
public class ExcludeSessionRepositoryFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
FilterChain filterChain) throws ServletException, IOException {
if (/* here goes your logic to exclude the session repository filter, probably depending on the request uri */) {
httpRequest.setAttribute("org.springframework.session.web.http.SessionRepositoryFilter.FILTERED", Boolean.TRUE);
}
filterChain.doFilter(httpRequest, httpResponse);
}
}
Of course, there is another solution to complete the integration of springboot and spring security. After the integration is completed, the SessionCreationPolicy enumeration parameters can be adjusted due to the existence of the SessionManagementConfigurer, and the session creation strategy can be adjusted. Its default value is SessionCreationPolicy.IF_REQUIRED, only after testing After logging in, the session will be synchronized to redis, which is more in line with the concept of session sharing.
I am learning how secure my endpoints, but everything i searched for contains pretty complicated examples, that didn't really answerd my question, and for now, just for the sake of this example project, i was looking for something simple.
My current solution is to make endpoints return like this:
return authenticate(request.headers) ? cityService.getCity() : utils.unauthenticatedResponse();
Where authenticate(request.headers) checks for token in header.
The thing i want to improve is to have that authenticate method run before every request to my endpoints (aside from login and register), so i can just return cityService.getCity(), and i won't have to make that check every time.
Will appreciate every answers, but please make it easy yo understand, since i am just a beginner.
Since you need to run the authenticate method before every request, you need to implement a Filter. It's pretty straightforward and you can get the steps and template to implement a filter here.
Every request to an endpoint will first pass through the filter (this is configurable), where you can have the authenticate method and then allow it further accordingly.
For starters, you can implement a filter like below:
#Component
public class AuthFilter implements Filter {
#Override
public void doFilter
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(authenticate(req.getHeaders)){
chain.doFilter(request, response);
} else {
//else logic, ie throw some exception in case authenticate returns false
}
}
}
The advantages that this provides are :
You can implement multiple filters
You can provide Order/priority to filters
You can configure which endpoints need to pass through the filter and which ones do not.
You can use ContainerRequestFilter (if you are using Spring/Tomcat)
Every request coming to the server will go through this filter, so you can implement your code in it.
In a spring mvc application i need to capture an additional 'location' parameter on login screen and use it for authentication in addition to username. I came across few approaches suggested to achieve this but none of it is straight forward and involves extending and/or implementing number of spring classes and interfaces. I somehow achieved it by extending UsernamePasswordAuthenticationFilter and by retrieving and putting location parameter in session.
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
final Long locationId = Long.parseLong(request.getParameter("locations"));
request.getSession().setAttribute("LOCATION_ID", locationId);
return super.attemptAuthentication(request, response);
}
}
This approach seems like a hack and doesn't seem too elegant. On top of that, now since i am using a custom AuthenticationFilter i have to manually configure this filter by injecting number of dependencies.
#Bean
public CustomAuthenticationFilter customAuthenticationFilter () {
CustomAuthenticationFilter filter= new CustomAuthenticationFilter();
filter.setRequiresAuthenticationRequestMatcher(
new AntPathRequestMatcher("/login","POST"));
filter.setAuthenticationManager(authenticationManagerBean());
filter.setUsernameParameter("username");
filter.setPasswordParameter("password");
filter.setAuthenticationSuccessHandler(simpleUrlAuthenticationSuccessHandler());
filter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
filter.setRememberMeServices(persistentTokenBasedRememberMeServices());
return filter;
}
Eventually, capturing location and using it in authentication works but then it creates new issues if i want to use remember-me feature. I explained the problem here Spring remember-me with extra login parameter.
Using extra login parameters must be a common requirement. Spring framework known for being pluggable and extensible i wish there was a more user friendly way to use additional parameters.
Can anyone please suggest me a better approach here to use extra parameter and get remember-me working as well. Thanks
The classes of spring security are really complicated.
Use AbstractPreAuthenticatedProcessingFilter as your superclass.
Than you can return an Object instead of a String in
getPreAuthenticatedPrincipal
getPreAuthenticatedCredentials
there you read whatever you need from the HttpRequest and return an object that contains all the data you need (as you need it as principal or credential wherever location belongs.). Maybe you create a simple class for the return type.
Than you create a subclass of org.springframework.security.authentication.AuthenticationProvider
.In the method public Authentication authenticate(Authentication authentication)
you can access the objects you returned in AbstractPreAuthenticatedProcessingFilter using authentication.getCredentials() and authentication.getPrincipal()
with this you create one or more new SimpleGrantedAuthority(role), one for each role the user has.Collect them in a List grantedAuthorities;
And finally create a
Authentication auth=new new UsernamePasswordAuthenticationToken(authentication.getPrincipal(),authentication.getCredentials(),grantedAuthorities)
which you return.
I'm trying to build an api with Google Cloud Endpoints.
As Cloud Endpoints does not provide authentication beside Googles own OAuth I try to build my own. Therefore I want to access the parameters provided for the API (for example #Named("token") token) inside a servlet filter.
Unfortunately I cannot find any of the provided information inside the httpRequest. Is that normal? Is there a possibility to access the parameters?
I would appreciate if someone could help me!
UPDATE:
With the infos from jirungaray I tried to build an authentication using headers but ran into the same problem. Used a REST-Client to send some headers as I could not figure out how to do this with the API Explorer. Inside my filter I try to access the token from the headers:
#Override
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader(Constants.AUTH_TOKEN);
...
chain.doFilter(request, response);
}
The reason why I try to do something like this, is that I'm using Guice for Dependency Injection and want my token to be injected inside another object.
With Guice I have the following Provider using the token to inject a FacebookClient (using the token) per request.
#Provides
public FacebookClient getFacebookClientProvider(#Named("fbToken") Provider<String> fbToken) {
return new DefaultFacebookClient(fbToken.get(), Version.VERSION_2_2);
}
As described in the Guice wiki (SevletModule) this uses a sevlet filter to get the information from the request.
Is there any solution to achieve this kind of DI with Cloud Endpoints?
Philip,
Yes, it does makes sense you are getting an empty request. Your endpoint calls are first handled by Google (they receive the API calls) and then those are processed and sent to a handler in your app. As this is all done in the background it's very easy to miss that your endpoints aren't actually getting the same request you sent, they get a completely different request sent from Google's infrastructure.
Even though your approach should work including tokens info in url makes them easier to sniff, even if you use SSL or encrypt your params the token is there in plain sight.
For what you are trying to achieve I recommend you include the token as a header in your request and retrieve that header by accessing the HTTPRequest directly on the endpoint, this is injected automatically if you include an HTTPServletRequest param in you endpoint method.
eg.
public APIResponse doSomething(SomeComplexRquestModel request,
HttpServletRequest rawRequest) {
}
If you still feel you should go with your original approach just comment and I'll help you debug the issue.
I have a java webapp using Spring 3.1. My Spring security context defines multiple authentication filters, each corresponding to a different authentication path (e.g. username/password vs. Single Sign On). Each auth filter defines its own AuthenticationSuccessHandler. Now, I want to inject 2 additional actions to take upon successful authentication, and they should apply across all authentication types:
set a tracking event code for Google Analytics to use on the front-end
update the user's preferred locale in our database
These could be any actions that you want a hook for, after the user has been successfully authenticated. The important point is that, unlike the regular AuthenticationSuccessHandlers (which are different for each authentication path), they don't forward or redirect the request. So it's safe to call a bunch of them.
Is there a clean way to integrate these additional authentication success "actions", using Spring Web/Security 3.1?
I looked into implementing an ApplicationListener<AuthenticationSuccessEvent>, but my events need to access the request, and all AuthenticationSuccessEvent provides is the Authentication object itself.
I couldn't find a way, so I decided to roll my own proxy:
public class AuthenticationSuccessHandlerProxy implements AuthenticationSuccessHandler {
private List<AuthenticationSuccessHandler> authenticationSuccessHandlers;
public AuthenticationSuccessHandlerProxy(List<AuthenticationSuccessHandler> successHandlers) {
this.authenticationSuccessHandlers = successHandlers;
}
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
for (AuthenticationSuccessHandler successHandler : this.authenticationSuccessHandlers) {
successHandler.onAuthenticationSuccess(request, response, authentication);
}
}
}
After looking breafly into the source code of AbstractAuthenticationProcessingFilter and all other places where AuthenticationSuccessHandler.onAuthenticationSuccess(...) is called I do not see any possibility to do it using Spring Security.
As a workaround you can try to wrap your success handlers into some AspectJ or AOP pointcut and then apply this pointcut to AuthenticationSuccessHandler.onAuthenticationSuccess(...) execution. Maybe like this you can target all authentication types.