Spring security: Apply filter to only an endpoint - spring

Currently, I've two kind of endpoints into my service:
/portal/**: I need to add a filter PortalAuthorizationFilter
The other ones: I need to add a filter OthersAuthorizationFilter
It's important that OthersFilter has not to be applied on /portal/** calls.
I've created a WebSecurityConfigurerAdapter. My current code is:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JWTExceptionHandlerFilter(objectMapper, messageSource), BasicAuthenticationFilter.class)
.cors().and()
.csrf().disable()
.antMatcher("/portal/**")
.addFilter(new PortalAuthorizationFilter())
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilter(new OthersAuthorizationFilter());
}
}
I've debugged this code when a call is made to /portal/**, PortalAuthorizationFilter is reached, but then OthersAuthorizationFilter is reached as well.
I don't quite figure out how to solve it.
Any ideas?

You need to create another configuration class which will also extend WebSecurityConfigurerAdapter, there you match your url with antMatchers and add your filter. Whichever pattern match will run that security configuration
Read this post

#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/portal/**").... //the configuration only
//applies when sb hitting /portal/**
}
}
if you want another configuration for another url you need overwrite another WebSecurityConfigurerAdapter:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
#Order(101) //#Order(100) is default
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http... //without antMatcher(...) default will be used "/**",
//so it take all request. So the order of this class should be
// higher
}
}
If you want use filter approach (.addFilter(new OthersAuthorizationFilter()); )then in your doFilter method you should implement:
doFilter(...) {
if(match(request, "/portal/**")
....
}
Unfortunately AuthenticationProvider will not give you such possibility, it doesn't know about url, just credentials. If you want more read spring-security-architecture.
But I thing you want to delegate authorization

Another option is to use a delegate pattern. Imagine if you have a filter that looks like this
public class PickAndChooseFilter extends OncePerRequestFilter {
private AntPathRequestMatcher matcher = new AntPathRequestMatcher("/portal/**");
private final Filter portalAuthorizationFilter;
private final Filter othersAuthorizationFilter;
public PickAndChooseFilter(Filter portalAuthorizationFilter, Filter othersAuthorizationFilter) {
this.portalAuthorizationFilter = portalAuthorizationFilter;
this.othersAuthorizationFilter = othersAuthorizationFilter;
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (matcher.matches(request)) {
portalAuthorizationFilter.doFilter(request, response, filterChain);
} else {
othersAuthorizationFilter.doFilter(request, response, filterChain);
}
}
}
then instead of
.addFilter(new PortalAuthorizationFilter())
.addFilter(new OthersAuthorizationFilter())
you'd simply have
.addFilter(new PickAndChooseFilter(
new PortalAuthorizationFilter(),
new OthersAuthorizationFilter()
)

Related

obtain request parameter in Spring security Filter

Can someone help in in obtaining request parameter
in WebsecurityConfig Httpsecurity configure method ? I need to extract the request parameter in the below case acr=loa3 that is coming from request
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.maximumSessions(1)
.expiredUrl(this.uiUri + "/expired")
.maxSessionsPreventsLogin(true)
.and()
.invalidSessionUrl(this.uiUri + "/expired")
.and()
.csrf().disable().cors()
.and()
.authorizeRequests()
.antMatchers("/expired").permitAll()
.anyRequest().authenticated()
.and()
//Can some one help me here on how to extract request param coming in the url for example xyz.com/login?acr=loa3 ? I need to send that as acr value before the configureOIDCfilter executes
.addFilterBefore(configureOIDCfilter(http, acrValue),
AbstractPreAuthenticatedProcessingFilter.class)
.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(this.redirectUri));
}
}
#Bean
public OIDCAuthenticationFilter configureOIDCfilter(HttpSecurity http, String acrValue) throws Exception {
OIDCAuthenticationFilter filter = new OIDCAuthenticationFilter();
StaticSingleIssuerService issuerService = new StaticSingleIssuerService();
issuerService.setIssuer(issuerUrl);
filter.setServerConfigurationService(new DynamicServerConfigurationService());
StaticClientConfigurationService clientService = new StaticClientConfigurationService();
RegisteredClient client = new RegisteredClient();
client.setClientId(clientId);
client.setDefaultACRvalues(ImmutableSet.of(acrValue));
return filter;
}
What you showed in your code is configuration. This is done at startup time and cannot catch any request parameters at this time. However, if you want to need to do something by request, you may want to implement a filter as I wrote in my recent blog post.
You could extend from a filter like this:
public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public MyAuthenticationFilter(AuthenticationManager authenticationManager) {
this.setAuthenticationManager(authenticationManager);
}
}
Then, try to find what methods you want to override. In example:
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
...
}
In the above method you can access the http request parameters.
This filter needs to be added to your configuration as well:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilter(new MyAuthenticationFilter()).
}
A filter will be called for any request and is the only way to receive request parameters (to my knowledge).

Get request is not authorized when CSRF is disabled in Spring Security

Spring Security basic authentication works if I don't add the following
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
After I add this code piece a GET request without an Authorization header gets the response while I expect a response saying Unauthorized. Before adding this configuration GET response gets 401.
The only change is the above class; nothing else was changed.
Try to add .anyRequest().authenticated(), it means, all request must be authenticated. If you want to add an exemption add something like .antMatchers(HttpMethod.GET, "/", "/js/**", "/css/*", "/images/**").permitAll() this will not be authenticated.
Sample Code:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.GET, "/", "/js/**", "/css/*", "/images/**").permitAll()
.anyRequest().authenticated();
}
}

Spring security: How can I enable anonymous for some matchers, but disable that for the rest?

I am trying to enable the anonymous access to some part of my rest api, but disable that to the rest.
I tried config looks like:
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anonymous().and()
.antMatchers(SOME_URL).authenticated()
.and()
.anoymous().disable()
.antMatchers(OTHER_URL).authenticated();
}
But later, I realized that the later anonymous().disable will cover the previous setting.
So is anyone can give me some suggestion that how can I enable the anonymous for part of my url?
Many thanks!!!
You can define a RequestMatcher, one for public urls and other for protected urls. Then, override the configure method which accepts WebSecurity as param. In this method, you can configure web to ignore your public urls.
private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/public/**")
);
private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);
#Override
public void configure(final WebSecurity web) {
web.ignoring().requestMatchers(PUBLIC_URLS);
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.exceptionHandling()
// this entry point handles when you request a protected page and you are not yet
// authenticated
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.anyRequest()
.authenticated();
// and other clauses you would like to add.
}

Spring Boot: Authenticating both a Stateless REST API and a Stateful "Login" Web Controller in the same project?

So I have an application that contains a REST API which is used by a custom java application on an IOT device with no user interaction.And I also have a web app which needs a stateful session for maintaining user login.
Is it possible to use Spring Security to authenticate requests to my API and web controller differently?What form of authentication should I be using for the REST API?
One way to achieve what you are looking for is to have 2 configurations in your spring security. E.g.
Pay attention to antMatcher (matcher not matchers). The antMatcher will control on what set of url your entire config applies i.e. FormLoginWebSecurityConfigurerAdapter in below example will apply only to uri matching /api/test/**. Of course, you can define the antMatcher only in one of the configs say config1 and the other config in that case will be a catch all (i.e catch everything that does not match config1)
#EnableWebSecurity
#Configuration
public class SecurityConfig {
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
}
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http
.antMatcher("/api/v1/**")
.authorizeRequests()
.antMatchers("/api/v1/**").authenticated()
.and()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("user").roles("USER");
auth.inMemoryAuthentication().withUser("admin1").password("admin").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); // CONFIGURE TYPE OF SESSION POLICY
http
.antMatcher("/api/test/**")
.authorizeRequests()
.antMatchers("/api/test/**").authenticated()
.and()
.formLogin();
}
}
}

Spring Security Java Config - dynamic IP list for a Request URL

I have two configuration. The first would like to achieve that all requests from(/api/**) must come only from a determined ip.
like Following...
.authorizeRequests().antMatchers("/api/**").hasIpAddress("dynamic List of IPs");
It should be checked whether the IP is stored in the database, otherwise the access is to be denied.
And the secound config takes care of the rest.
#EnableWebSecurity
public class AppSecurityConfig {
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new CustomUserDetailsService()).passwordEncoder(new Md5PasswordEncoder());
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().disable()
.authorizeRequests().antMatchers("/api/**").hasIpAddress("dynamic List of IPs");
}
}
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().maximumSessions(1)
.expiredUrl("/error/expired.xhtml").and()
.invalidSessionUrl("/Anmeldung.xhtml?check=invalid");
http
.csrf().disable()
.headers().disable()
.formLogin().loginPage("/Anmeldung/").loginProcessingUrl("/j_spring_security_check").successHandler(new CustomAuthenticationSuccessHandler())
.failureUrl("/Anmeldung.xhtml?check=error").usernameParameter("j_username").passwordParameter("j_password")
.and()
.exceptionHandling().accessDeniedPage("/error/403.xhtml")
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/Anmeldung.xhtml?check=logout").invalidateHttpSession(false).deleteCookies("JSESSIONID").permitAll();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry interceptUrlRegistry = http.authorizeRequests();
interceptUrlRegistry.antMatchers("/Administrator/*").hasAnyAuthority("ROLE_ADMIN");
interceptUrlRegistry.antMatchers("/*").hasAnyAuthority("ROLE_USER");
interceptUrlRegistry.antMatchers("/Anmeldung/index.xhtml").anonymous();
interceptUrlRegistry.antMatchers("/template/*").denyAll();
interceptUrlRegistry.antMatchers("/resources/**").permitAll();
}
}
}
Thanks for your help.
You can dynamically configure httpsecurity object inside for loop like the code referenced below.
for (Entry<String, String> entry : hasmapObject) {
String url = entry.getKey().trim();
String ips= entry.getValue().trim();
http.authorizeRequests().and().authorizeRequests().antMatchers(url).hasIpAddress(ips);
}
This worked for me. The hashmap object had the dynamic list of url's and their corresponding ips to give access.
"http.authorizeRequests().and()" this and() is needed to indent like we use in xml configuration to configure http child elements in XML.
Please let me know if this helps.

Resources