HttpSecurity With Spring, differentiate urls permission - spring-security

I would like that for every url that is not under path /cobrands and /fdt a request for password. If I'm asking for example for /fdt/name I should not be asked for the http authentication.
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
/** code **/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(entryPoint()).and()
.authorizeUrls()
.antMatchers("/**").hasAnyAuthority("wf_cobrand_lettura", "wf_cobrand_fdt")
.antMatchers("/cobrands/*").permitAll()
.antMatchers("/fdt/*").permitAll()
.and()
.httpBasic();
}
}

Matchers are processed in order, so your
.antMatchers("/**")
catches all requests and the two remaining matchers are never evaluated.
Put it this way round:
http.exceptionHandling().authenticationEntryPoint(entryPoint()).and()
.authorizeUrls()
.antMatchers("/cobrands/*").permitAll()
.antMatchers("/fdt/*").permitAll()
.antMatchers("/**").hasAnyAuthority("wf_cobrand_lettura", "wf_cobrand_fdt")
.and()
.httpBasic();

Related

Configuring Multiple Spring Security [duplicate]

This question already has answers here:
Spring Security : Multiple HTTP Config not working
(2 answers)
Closed 1 year ago.
I have the following configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Configuration
#Order(1)
public static class SamlConfig extends WebSecurityConfigurerAdapter {
#Value("${enable_csrf}")
private Boolean enableCsrf;
#Autowired
private SamlUserService samlUserService;
public SamlWebSecurityConfig() {
super();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/sso").permitAll()
.antMatchers("/saml/**").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.userDetailsService(samlUserService)
.serviceProvider()
.keyStore()
.storeFilePath("path")
.password("password")
.keyname("alias")
.keyPassword("password")
.and()
.protocol("https")
.hostname(String.format("%s:%s","localhost", "8080"))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath("metadata");
if (!enableCsrf) {
http.csrf().disable();
}
}
}
#Configuration
#Order(2)
public static class BasicConfig extends WebSecurityConfigurerAdapter {
public BasicWebSecurityConfig() {
super();
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/basic").permitAll()
.anyRequest().authenticated();
if (!enableCsrf) {
http.csrf().disable();
}
}
}
This works for the SAML, but the basic login returns an error: 403 forbidden.
I modified the BasicConfig with this, and SAML doesn't work anymore but basic authentication works. All the endpoints are for both SAML and basic authentication, just different login page.
public static class BasicConfig extends WebSecurityConfigurerAdapter {
public BasicWebSecurityConfig() {
super();
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/basic").permitAll()
.antMatchers("/**").permitAll()
.anyRequest().authenticated();
if (!enableCsrf) {
http.csrf().disable();
}
}
}
For some reasons sometimes it works, sometimes not. I also tried to modify the #Order and still not working.
In Spring Security, there are two things that are alike but do things completely differently, requestMatchers().antMatchers() and authorizeRequests().antMatchers().
The requestMatchers tells HttpSecurity to only invoke the SecurityFilterChain if the provided RequestMatcher was matched.
The authorizeRequests allows restricting access based upon the HttpServletRequest using RequestMatcher implementations.
In your case, you have two SecurityFilterChains. But only the one with the highest priority is being invoked, this happens because you did not give any requestMatchers to it, therefore it will match every request. And only one SecurityFilterChain is called per request, thus it will not invoke the next one.
So, you should inform the requestMatchers for your configurations, like so:
http
.requestMatchers((requests) -> requests
.antMatchers("/secure/sso", "/saml/**")
)
.authorizeRequests()
.antMatchers("/secure/sso").permitAll()
.antMatchers("/saml/**").permitAll()
.anyRequest().authenticated()
...
http
.requestMatchers((requests) -> requests
.antMatchers("/secure/basic", "/**")
)
.authorizeRequests()
.antMatchers("/secure/basic").permitAll()
.anyRequest().authenticated();

Spring boot Multiple routes with multiple JWT

I need to implement spring JWT security for my end points.. I have 2 routes - 1 for internal and 2nd for external. I tried to add the code below but both my filters are executing for any requests..
I can add a logic in the filter based on the url.. But I didnt feel thats the right approach. Please let me know what would be the right approach and how to solve it?
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/internal/**")
.authenticated()
.and()
.addFilterBefore(jwtAuthenticationInternalFilter(), BasicAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/external/**")
.authenticated()
.and()
.addFilterBefore(jwtAuthenticationExternalFilter(), BasicAuthenticationFilter.class);
public class ExternalAuthenticationFilter extends OncePerRequestFilter {
#Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("Its hitting here - External");//GET THE Information and build Authentication object..
// SecurityContextHolder.getContext().setAuthentication(token);
filterChain.doFilter(request, response);
}
}
public class InternalAuthenticationFilter extends OncePerRequestFilter {
#Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("Its hitting here - Internal");//GET THE Information and build Authentication object..
// SecurityContextHolder.getContext().setAuthentication(token);
filterChain.doFilter(request, response);
}
}
Both internal and external code is executing for any request.
sample request
/internal/abc,
/external/xyz .. Both cases both filters are being called..
Please suggest
You can split your security settings into two different configuration classes and mark them with e.g. #Order(1) and #Order(2) annotations. One config will deal with the /internal endpoints and one with the /external. In the configure(HttpSecurity http) method, first specify which endpoints you wish to configure and then apply your settings.
See example of one config bellow, the second config will be anological:
#EnableWebSecurity
#Order(1)
public class ExternalEndpointsSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/internal/**")
.authorizeRequests()
.authenticated()
.and()
.addFilterBefore(jwtAuthenticationInternalFilter(), BasicAuthenticationFilter.class)
}
}

Spring Boot Security not ignoring certian url via WebSecurity

I am using Spring boot 1.3.2 with Spring Security.
I have following configure(HttpSecurity http) method to inforce authentication
protected void configure(HttpSecurity http) throws Exception {
RequestMatcher csrfRequestMatcher = new RequestMatcher() {
private AntPathRequestMatcher[] requestMatchers = {
new AntPathRequestMatcher("/iams/w/*")
};
#Override
public boolean matches(HttpServletRequest request) {
for (AntPathRequestMatcher rm : requestMatchers) {
if (rm.matches(request)) { return true; }
}
return false;
} // method matches
};
http
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.httpBasic();
}
and I have following configure(WebSecurity web) method to ignore some of the urls as below;
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/myapp/docs/**",
"/myapp/docs/*",
"/myapp/docs/index.html",
"/resources/**",
"/static/**");
}
But http request to http://127.0.0.1:9000/myapp/docs/index.html still reuires username/password ( authentication ) and returns "status":401,"error":"Unauthorized"...
Actually none of the ignore url on WebSecurity is working since it also requires authentication. If I provide the auth then it works. How can I simply ignore some urls (like "/myapp/docs/**" ) here. I have following definition in the SecurityConfig class
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
What am I missing ? Please Advise.
It would probably be easier to use as simple a set of patterns as possible to leave unsecured, and then simply say that everything else IS secured.
This may be closer to what you want:
public static final String[] NOT_SECURED = {"/iams/docs/**","/static/**"};
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(NOT_SECURED);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(NOT_SECURED).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.csrf().disable();
}
There is an error order in your code.
http
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.httpBasic();
Therefore, any request is needed to be authenticated. You can directly use antMatchers.
http
.authorizeRequests()
.antMatchers("/iams/w/*")
.authenticated()
.and()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.csrf().disable()
I hope it's helpful for you.
Thank you for your response but with your suggestion, my "/iams/w/*" is not protected at all. I can get to all these urls; "/iams/docs/**" , "/iams/w/" and "/iams/api/" without basic auth. Below is the set up as per your suggestion. Here I want to protect "/iams/w" and "/iams/api/" with username/password but let everyone get to "/iams/docs/*" without username/password. This is spring boot restful based implementation but want to expose some urls like docs so that it can be accessed by all and not the api calls.
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/iams/docs/**",
"/iams/docs/*",
"/iams/docs/index.html",
"/static/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/iams/api/**","/iams/api/v1/*")
.authenticated()
.and()
.httpBasic()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.csrf().disable();
}

Can Spring Boot application have separate security for REST APIs?

We would like to apply Oauth2 based security for the Rest Controllers while the rest of the application will have Spring Security. Will that be possible? Can you provide any examples please?
It seems like WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter conflicting when both configured.
Thank you in advance.
Yes it's possible. Here the example template configuration code is given. Please change the required configs to your need. The key is to define Sub static classes of configuration with different order. Here i have considered any requests which is orginating from \api as a REST API call.
I have not checked the code by compiling it.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Order(1)
#Configuration
public static class ApiWebSecurityConfig extends OAuth2ServerConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//Write the AuthenticationManagerBuilder codes for the OAuth
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.apply(new OAuth2ServerConfigurer())
.tokenStore(new InMemoryTokenStore())
.resourceId(applicationName);
}
}
}
#Order(2)
#Configuration
public static class FormWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
//Write the AuthenticationManagerBuilder codes for the Normal authentication
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //HTTP with Disable CSRF
.authorizeRequests() //Authorize Request Configuration
.anyRequest().authenticated()
.and() //Login Form configuration for all others
.formLogin()
.loginPage("/login").permitAll()
.and() //Logout Form configuration
.logout().permitAll();
}
}
}

need spring security java config example showing basic auth only

My current java security config looks as follows:
#Configuration
#EnableWebSecurity
public class RootConfig extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("tester").password("passwd").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
When I perform a GET request using a browser, I'll get an error 403.
I would expect to get a browser popup asking me for a username / password.
What might be the problem?
UPDATE: This is fixed in Spring Security 3.2.0.RC1+
This is a bug in the Security Java Configuration that will be resolved for the next release. I have created SEC-2198 to track it. For now, a work around is to use something like the following:
#Bean
public BasicAuthenticationEntryPoint entryPoint() {
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName("My Realm");
return basicAuthEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(entryPoint())
.and()
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
PS: Thanks for giving Spring Security Java Configuration a try! Keep the feedback up :)
With Spring Security 4.2.3 and probably before you can simply use this configuration:
#Configuration
#EnableWebSecurity
public class CommonWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Autowired
public void dlcmlUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("tom").password("111").roles("USER");
}
}

Resources