Spring security configuration; both Basic Auth and SiteMinder - java

I have a Spring boot web app that serves up both web content and exposes REST Services. The web content is protected by SiteMinder, the REST Services are protected by "Basic Auth".
I using Springs security 4.2.3. My Java code is extending the class WebSecurityConfigurerAdapter, my configure(HttpSecurity) method looks like:
#Override
protected void configure(HttpSecurity http) throws Exception {
RequestHeaderAuthenticationFilter siteMinderFilter = new RequestHeaderAuthenticationFilter();
siteMinderFilter.setAuthenticationManager(authenticationManager());
http
// Error page is for everyone
.authorizeRequests()
.antMatchers("/error.html")
.permitAll()
.anyRequest()
.anonymous()
// Basic Auth for our REST services
.and()
.authorizeRequests()
.antMatchers("/services/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
// Site-Minder protection for the web content
.and()
.addFilter(siteMinderFilter)
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().hasRole(ApplicationConstants.SITE_MINDER_AUTHORITY);
http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class);
}
Is there something wrong with my configuration? Does my configuration create three separate filters? Maybe my question should be, how do I create the three filters?
When I attempt to call the REST Service using PostMan / "Basic Auth", I get the error message:
org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException: SM_USER header not found in request.
I expect the service to get called, instead I get the SiteMinder filter firing.

Related

Restrict security authentication for read access

I created a web application using a sample project in GitHub. However, it required authentication for all crud operations. I want to restrict this security checking for all read DB operations. What changes do I need?
These are the related classes:
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
As far as i know there is no way to magically create a read only user.However, you can create a role such as ROLE_UPDATE and make all of your methods that perform creates/updates/deletes be secured via #Secured("ROLE_UPDATE"). Then, if a user is not granted the ROLE_UPDATE authority, they will not be able to call any of the 'writing' methods, and therefore it will be restricted to only call 'read' methods.
Generally, Spring Security doesn't have such feature. You can do as #Alien suggested create some role (ex. ROLE_WRITE and then check on the resources if the user who is trying to access the resource has the correct role
#PreAuthorize("hasRole('ROLE_WRITE')")
public String someWriteOperation() {
}
The other way (but it's only applying when your JPA framework allows you such feature) it's create a Filter in spring and then before processing your request further in the chain create transaction read-only:
#Component
#Order(1)
public class TransactionFilter implements Filter {
#Override
public void doFilterServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//Create read only transaction
// ex. if(isUserReadOnly(Security ....getUser())) {DBSession.setReadOnly(true);}
//Remember it will work only if your JPA framework have the feature - explore your code/framework before
chain.doFilter(request, response);
}
}
Remember filter order should be after Spring Security Filter

Secure an Angular JS app with Spring Security

I have created a Spring Boot app and I have my front-end app in the /resources/static folder.
For the routing, I am using Angular JS UI Router library.
I have defined a route, which I only want to be accessed by the admin and now I am trying to secure it using Spring Security.
Here is my WebSecurity Configuration class:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/#/admin").hasRole("ADMIN")
.and()
.formLogin()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/member", "/member/**").permitAll()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/**/**/*.css",
"/**/**/*.js",
"/**/**/*.html",
"/**/**/**/*.css",
"/**/**/**/*.js",
"/**/**/**/*.html",
"/**/**/**/**/*.css",
"/**/**/**/**/*.js"
).permitAll()
.antMatchers("/auth/**", "/member/**", "/account/**").permitAll()
.and()
.csrf().disable();
}
}
The route I am trying to secure can be accessed through http://localhost:8080/#/admin.
However, whenever I am accessing that route, no login is requested and the page can be viewed by anyone.
Is it there another approach I should follow?
The URL: http://localhost:8080/#/admin is mapped to / in your permitAll list instead of the /#/admin rule, since #/admin part is just URL fragment, and usually not the business of the server side.
You have to define an API between your frontend and backend. Usually in RESTful web services form, and serve at /api/* path. Secure the path, and let your frontend talk to your backend through those APIs only.
It is eaiser to fix your issue,
Update
.antMatchers(HttpMethod.GET, "/#/admin").hasRole("ADMIN")
To
.antMatchers(HttpMethod.GET, "/#/admin").hasRole("ADMIN").anyRequest().authenticated()
For every matchers, you always need with permitAll() or authenticated() for it.

How to get URL hit by user in Spring security config file

Im working in a java-springs web application with custom security evaluator method,
i need to pass the URL hit by user as a parameter for the method permissionEvaluator.canUserAccessPage(URLHitByUser).
How to get URL hit by user.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
//.antMatchers("/view/**").permitAll()
.antMatchers("/assets/**").permitAll()
.antMatchers("/view/admin.html").access("#permissionEvaluator.canUserAccessPage(URLHitByUser)")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/index")
.permitAll()
// [...]
}
If you intention is controlling the access to certain roles,this can be achieved by using sec:intercept-url in applicationContext-security-preauth.xml.
Thanks

X-CSRF-TOKEN is not generated by Spring Boot

I followed the guide here: http://spring.io/guides/gs/rest-service/ to build my rest service example and now I am trying to enable the CSRF protection. I read that it should be enabled by default, so if I DON'T include:
http.csrf().disable()
in my WebSecurityConfigurerAdapter configuration, the CSRF protectection should be enabled by default, but it does not seem to to be the case. The problem is that the X-CSRF-TOKEN is not generated and not included in my HTTP response in any way.
What am I expected to do, to have the x-csrf-token generated and included in the response and, of course, the csrf protection fully working?
I noticed that, with a similar spring mvc configuration, I get the x-csrf-token generated simply including:
< security:csrf disabled="false"/>
in my security configuration file. But, with spring boot maybe I am getting something wrong and there is no way to have the csrf token generated. Can anybody help me, perhaps pointing me to a working example? My security configuration is:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
// .csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.and()
.formLogin()
.successHandler(new RestAuthenticationSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutSuccessHandler(new RestLogoutSuccessHandler());
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(restUserDetailService);
}
To include the CSRF Token in your csrf protection, you can include CSRFTokenRepository to generate tokens. To illustrate in your case adding a simple line is enough:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) //HERE ! Defaults XSRF-TOKEN as cookie name and X-XSRF-TOKEN as header name
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.and()
.formLogin()
.successHandler(new RestAuthenticationSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and()
.logout()
.logoutSuccessHandler(new RestLogoutSuccessHandler());}
Using Spring security 5.3.0.Final, one of the ways you can generate the CSRF token is by setting it in the cookie using the following code below.
http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
You also need to include the generated CSRF token in your request for the server to authorize.
<form>
<input type="hidden" name="_csrf" value="${cookie['XSRF-TOKEN'].getValue()}" />
//Code goes here
</form>
In the event you're using a JS framework, you need to include the token by setting it in the request header.
Here is an example for a JQuery ajax call.
// Get the CSRF token from the cookie
const csrfCookie= document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');
// Add the CSRF token to each ajax request header
settings.beforeSend = function(xhr) {
xhr.setRequestHeader('X-XSRF-TOKEN', springCsrfCookie);
};
$.ajax(settings);
There are other implementations that will suit your needs documented in the following link by Spring | https://docs.spring.io/spring-security/site/docs/5.3.0.RELEASE/reference/html5/#servlet-csrf
We had pretty similar issue during our security tests where we suspected that we accidentally disable csfr in configure method of websecurityconfig class,by default it is enabled. by changing the congfigure method as shown below , we had spring automatically generate csfr tokens.
websecurityconfig class configure method==>
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login","/loginError","/home","/interruption").permitAll()
.antMatchers("/admin").hasAuthority(Roles.ROLE_PREFIX.role()+Roles.HALLEYYNT01.role())
.antMatchers("/requests").hasAuthority(Roles.ROLE_PREFIX.role()+Roles.CCHALLEYLOGIN.role())
.antMatchers("/solrequests").hasAuthority(Roles.ROLE_PREFIX.role()+Roles.SOLHALLEYLOGIN.role())
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
//.failureUrl("/loginError")
.loginProcessingUrl("/authenticate")
.defaultSuccessUrl("/")
.and()
.logout().clearAuthentication(true).invalidateHttpSession(true).deleteCookies("JSESSIONID")
.logoutSuccessUrl("/login");
//.and()
//.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}

Disable BasicAuth on specific sub paths

I know there are some question on stackoverflow, but nothing helped...
http
.addFilterBefore(RestConfiguration.getCorsFilter(), ChannelProcessingFilter.class)
.authorizeRequests() //Authorize Request Configuration
.antMatchers("/api/**").hasRole("API")
.antMatchers("/api/confirm/**").permitAll()
.antMatchers("/api/version").permitAll()
.anyRequest().authenticated()
.and() //HTTP basic Authentication only for API
.antMatcher("/api/**").httpBasic()
.and() // angularjs requires csrf
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf().disable();
I've a api path with some sub paths. But I want to access two of them without basic auth (confirm/** and version).
How can I do that? I always get the login dialog.
You should use antMatchers("/api/**").hasRole("API") rule after /api/confirm/** and /api/version. Current ordering is not quite right:
.antMatchers("/api/confirm/**").permitAll()
.antMatchers("/api/version").permitAll()
.antMatchers("/api/**").hasRole("API")
To sum up, if you want to only secure /api/* and let public access on /api/confirm/**, /api/version and all other paths without api prefix, you should have a HttpSecurity config like this:
http
// Same as before
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/confirm/**").permitAll()
.antMatchers("/api/version").permitAll()
.antMatchers("/api/**").hasRole("API")
.anyRequest().permitAll();
// Same as before

Categories

Resources