Filter for Url Pattern without authentification? - spring

Help me please a little with setting up Spring Security.
I found something similar, but it somehow does not work very well for me ..
https://stackoverflow.com/a/36875726/1590594
The configuration specifies that each request must be authenticated.
It is necessary to do the following, that on the specified URL ("/ push") worked only one filter. The filter does the appropriate checking and skips the request further or rejecting. Without authentication.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().
sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().
authorizeRequests()
.anyRequest().authenticated().
and().
anonymous().disable().
exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint());
http.addFilterBefore(new UserAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
http.authorizeRequests().antMatchers(HttpMethod.POST, "/push").authenticated().and().addFilterBefore(new RPushFilter(),BasicAuthenticationFilter.class);
}
and filter
public class RPushFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
//IF NOT httpResponse.sendError(HttpStatus.BAD_REQUEST.value(), "Access denied");
chain.doFilter(request, response);
}
}

Related

Spring Security check api key in query

I have a service with a few endpoints and for all endpoints, there is a token in the header and the auth mechanism works just fine.
Now I have a new endpoint and the api_key for this endpoint will be sent in the query instead of the header. Is there anyway I can configure my filter to achieve this ?
I created a new filter which can authenticate apikey in query
public class SimpleFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if (!request.getQueryString().equals("API_KEY=abcd")) {
// throw exception
}
chain.doFilter(req, res);
}
#Override
public void destroy() {}
#Override
public void init(FilterConfig arg) {}
This is my configuration
http
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/new-api-with-key-in-query")
With this config, there is no auth check for my new api, but my question is, how do I enable my new filter just for the one api with keys in query.

Onboarding filter in Spring Boot and Spring Security

I'm trying to create a filter in order to redirect logged users to the onboarding page in case they haven't completed the process before.
This is my filter so far:
#Component
#Order(110)
public class OnboardingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// cast the request and response to HTTP
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession session = httpRequest.getSession(false);
SecurityContextImpl securityContext = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT");
// if there's a logged user
if (securityContext != null) {
UserPrincipal principal = (UserPrincipal) securityContext.getAuthentication().getPrincipal();
if (!principal.hasOnboarded()) {
httpResponse.sendRedirect("/onboarding");
}
}
// continue with the filter chain
chain.doFilter(httpRequest, httpResponse);
}
I've tried different values for #Order but in every case the http response generates a downloadable content instead of showing the actual requested URL or sending the redirect. Any ideas?
I'm getting this exception:
Caused by: java.lang.IllegalStateException: Committed
at org.eclipse.jetty.server.HttpChannel.resetBuffer(HttpChannel.java:917)
HttpChannel.java:917
at org.eclipse.jetty.server.HttpOutput.resetBuffer(HttpOutput.java:1423)
HttpOutput.java:1423
at org.eclipse.jetty.server.Response.resetBuffer(Response.java:1182)
Response.java:1182
at org.eclipse.jetty.server.Response.sendRedirect(Response.java:534)
Response.java:534
at org.eclipse.jetty.server.Response.sendRedirect(Response.java:543)
Response.java:543
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:130)
HttpServletResponseWrapper.java:130
at org.springframework.security.web.firewall.FirewalledResponse.sendRedirect(FirewalledResponse.java:43)
FirewalledResponse.java:43
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:130)
HttpServletResponseWrapper.java:130
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.java:135)
OnCommittedResponseWrapper.java:135
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:130)
HttpServletResponseWrapper.java:130
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.java:135)
OnCommittedResponseWrapper.java:135
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:130)
HttpServletResponseWrapper.java:130
at org.springframework.web.servlet.view.RedirectView.sendRedirect(RedirectView.java:627)
RedirectView.java:627
at org.springframework.web.servlet.view.RedirectView.renderMergedOutputModel(RedirectView.java:314)
RedirectView.java:314
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316)
AbstractView.java:316
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1373)
DispatcherServlet.java:1373
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1118)
DispatcherServlet.java:1118
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057)
DispatcherServlet.java:1057
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
DispatcherServlet.java:943
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
FrameworkServlet.java:1006
... 94 common frames omitted
What about adding a return in:
httpResponse.sendRedirect("/onboarding");
return;
Otherwise you are continuing with the filter chain:
chain.doFilter(httpRequest, httpResponse);
Not 100% sure if this is already solving your issue, but might be also a problem.
I finally solved this by implementing an Spring context-aware GenericFilterBean as follows:
public class OnboardingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (SecurityContextHolder.getContext().getAuthentication() != null) {
// some business logic
httpResponse.sendRedirect("/onboarding");
}
else {
chain.doFilter(httpRequest, httpResponse);
}
}
}
Don't forget to add it to the security filter chain:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(new OnboardingFilter(), UsernamePasswordAuthenticationFilter.class)...

Set cookie in every request - SPRING

Im now developing simple spring boot web app..
Is there something in spring(filter) that check every request(headers)..
I want to check if there is cookie..
If there is cookie- nothing happend..
But if there is not it would create cookie...
Do i have to do this manually, so i put this in every function?
Or can i do something like global function, that got executed with every other request?
Thanks for help.
yes you have to use filters
you can try doing something like this
public class MyCookieFilter extends GenericFilterBean {
public static final String MY_COOKIE_NAME = "your-cookie-name";
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
checkCookie(httpServletRequest, httpServletResponse);
filterChain.doFilter(servletRequest, servletResponse);
}
private void checkCookie(HttpServletRequest request, HttpServletResponse servletResponse) {
boolean cookieExists = Arrays.stream(request.getCookies()).anyMatch(cookie -> cookie.getName().equalsIgnoreCase(MY_COOKIE_NAME));
if (!cookieExists) {
String cookieValue = "your-cookie-value";
Cookie newCookie = new Cookie(MY_COOKIE_NAME, cookieValue);
servletResponse.addCookie(newCookie);
}
}
}
then add it in your security config
#Override
public void configure(HttpSecurity http) throws Exception {
http
...
.addFilter(new MyCookieFilter())
...
}

JwtAuthorizationFilter implementtaion not working

In summary JwtAuthorizationFilter is not working.
If I leave //filterChain.doFilter(request, response) commented out I correctly get a 200 but the body is empty, which means two things:
1) The Controller/Response from the controller is executed but not the logic on it.
2) The function getAuthentication() correctly reads the Claims/token
The issue happens if I uncomment the line //filterChain.doFilter(request, response) because I get a 405. That line should be uncommented for the filter chain to exeute completely and get a response body with content.
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
if (authentication == null) {
filterChain.doFilter(request, response);
return;
}
SecurityContextHolder.getContext().setAuthentication(authentication);
**//filterChain.doFilter(request, response);**
}
Function in the controller:
#GetMapping("/foo")
#ResponseStatus(code = HttpStatus.OK)
public MyObject retrieve(#RequestBody MyModel obj) {
//code here is never called
}
For reference, this is my security config:
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/bar").permitAll()
.anyRequest().authenticated().and().addFilter(new AnotherFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
What Am I doing wrong?
Just to say that I clean up the build, restart the IDE and worked.
Maybe there was some cache not allowing the JWT filter to work properly.
Thanks,

Why is this spring security configuration blocks all paths?

public class AuthenticationFilter extends GenericFilterBean {
SecureService secureService;
public AuthenticationFilter(SecureService secureService) {
this.secureService=secureService;
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest=(HttpServletRequest)servletRequest;
Authentication authentication=secureService.getAuthentication(httpServletRequest);
if(authentication!=null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(servletRequest, servletResponse);
SecurityContextHolder.getContext().setAuthentication(null);
}
}
}
#Configuration
#EnableWebSecurity
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
SecureService secureService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new AuthenticationFilter(secureService), BasicAuthenticationFilter.class)
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/businesses/**").permitAll()
.antMatchers(HttpMethod.GET, "/users/login").permitAll()
.antMatchers(HttpMethod.POST, "/users/").permitAll()
.antMatchers(HttpMethod.GET, "/reviews/").permitAll()
.antMatchers(HttpMethod.GET, "/reviews/search").permitAll()
.antMatchers(HttpMethod.GET, "/reviews/**").permitAll()
.antMatchers("/").permitAll().and()
.authorizeRequests().anyRequest().authenticated();
}
#Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
what's wrong with this configuration? I followed with this link to write url authentications. But my app keeps blocking all requests, ignoring all the matchers specified in the code. I googled and someone said the order of rules matters. But even though I change the order, AuthenticationFilter gets invoked all the time and keeps blocking all requests.
The problem is that you interrupt the filter chain. do it as the following and it should work.
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
Authentication authentication = secureService.getAuthentication(httpServletRequest);
if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(servletRequest, servletResponse);
SecurityContextHolder.getContext().setAuthentication(null);
}
Another thing is that you throw a UserNotFoundException inside your SecureService if the HttpServlerRequest does not contain an Authentication.
In the AuthenticationFilter you seem to expect null in this case? So return null in the SecureService if no Authentication exists:
public Authentication getAuthentication(HttpServletRequest httpServletRequest) {
final String token=httpServletRequest.getHeader(Headers.AUTH_HEADER_NAME);
if(token!=null){
final User user=parseToken(token);
if(user!=null){
return new UserAuthentication(user);
}
}
return null;
}
if you want to keep the UserNotFoundException then only change the doFilterMethod to the following:
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
try {
Authentication authentication = secureService.getAuthentication(httpServletRequest);
if (authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}catch(UserNotFoundException e){
}finally {
filterChain.doFilter(servletRequest, servletResponse);
SecurityContextHolder.getContext().setAuthentication(null);
}
}

Resources