Spring WebSecurityConfigurerAdapter API - java

I've been playing around with Spring for the last few days and things are getting to be fun. I'm working with security right now and I've run into a slight snag. Basically, I want the authentication to happen via an API call rather than a form. Is there a neat way to do this?
I've extended the WebSecurityConfigurerAdapter like so -
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/openapi/**").hasRole("USER")
.anyRequest().authenticated();
http
.formLogin()
.defaultSuccessUrl("/hello")
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
authManagerBuilder.inMemoryAuthentication()
.withUser("manager").password("password").roles("MANAGER");
}
}
Is there a way to pick up the the usernames and passwords from a database and can I perform the authentication with an API call?

Spring Security 3 database authentication with Hibernate
This seems promising. It needs a custom authentication manager created.

You can use jdbc authentication with Java configuration as described in the reference http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#jc-authentication-jdbc

Related

Springboot override x-frame-options from external library (currently adding multiple)

I am having an issue in my spring app, basically I have overridden the configure method for WebSecurity in angular to use SAMEORIGIN as the X-FRAME-OPTION which works and applies the header.
#EnableWebSecurity
#Order(95)
public class CCWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN));
}
}
However I include a usersecurity library which also overrides the configure method, the method for this can be seen below:
Am I correct in saying it is the 'csrf().disable()' that is responsible for the X-FRAME-OPTIONS - DENY being applied?
Ideally I wanted to avoid changing the usersecurity library as there are many other of my spring apps relying on this.
You can allow multiple URLs as follows, But I don't know weather this is the proper way or not. but it works properly.
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable().authorizeRequests().anyRequest().permitAll()
.and()
.headers().defaultsDisabled()
.and()
.cors()
.and()
.headers()
.cacheControl()
.and()
.contentTypeOptions()
.and()
.httpStrictTransportSecurity().disable()
.and()
.headers()
.frameOptions().disable()
.addHeaderWriter(new StaticHeadersWriter("X-FRAME-OPTIONS",
"ALLOW-FROM example1.com",
"ALLOW-FROM example2.com",
"ALLOW-FROM example3.com",
"ALLOW-FROM example4.com",
"ALLOW-FROM example5.com"));
}

Confusion with Spring Security in Spring Boot

I'm working with Spring Boot 1.4.2.RELEASE, Spring Security 4.1.3.RELEASE, and Java 8.
For the security configuration I have the following class:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**", "/logout", "/login");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement() // 1
.sessionFixation() // 2
.migrateSession() // 3
.maximumSessions(1) // 4
.maxSessionsPreventsLogin(true).expiredUrl("/login").and() // 5
.invalidSessionUrl("/login") // 6
.and() // 7
.authorizeRequests()
.antMatchers("/app/**").authenticated()
.antMatchers("/about").permitAll()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/login").permitAll()
.loginProcessingUrl("/auth").permitAll()
.defaultSuccessUrl("/app/index", true)
.failureUrl("/login?error")
.usernameParameter("uid")
.passwordParameter("pwd").and()
.logout()
.permitAll()
.invalidateHttpSession(true)
.logoutUrl("/logout").permitAll()
.logoutSuccessUrl("/login").permitAll()
.clearAuthentication(true).and()
.exceptionHandling().and()
.csrf().disable()
.headers().frameOptions().disable()
.cacheControl().and();
}
}
When try access to "/about" (permit all everyone), redirects me to "/login". I try it a second time and now it allows me to access "/about".
I have changed the authorization order of requests in the configuration class but don't works. When I delete the lines of sessionManagement (1 to 7), everything works normally.
Do I need any extra configuration?
When you are testing this, did you clear your browser's cookie with regard to your testing site? The session management filter sets a jsessionid cookie, which gets sent back. Your browser has no idea that you reset your server, so thinks the cookie is just fine, and you send back an invalid session.
You may want to take a look at your session creation policies to see whether or not it suits your purpose.

Spring Security authorization for certain URL and deny all others

I have below configuration class where I would like to authorize certain requests and deny all others.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/phx-config-rest/dev/master").hasRole("DEV")
.anyRequest().authenticated()
.and()
.csrf()
.disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.
inMemoryAuthentication()
.withUser("devuser")
.password("dev")
.roles("DEV");
}
}
As per this code my impression was, Spring will only allow me to access /phx-config-rest/dev/master using the user 'devuser' and If I try access /phx-config-rest/prod/master or any other url, request would considered as un-authorized access. BTW, this code piece is regarding Spring cloud config server. Any thought?
change the
.anyRequest().authenticated()
to
.anyRequest().denyAll()
You restrict only URL /phx-config-rest/dev/master to users with role DEV, but all other URLs are accessible for every logged in user (including user devuser) with any role,
see ExpressionUrlAuthorizationConfigurer.AuthorizedUrl#authenticated:
Specify that URLs are allowed by any authenticated user.
You have to use ExpressionUrlAuthorizationConfigurer.AuthorizedUrl#denyAll instead of authenticated:
Specify that URLs are not allowed by anyone.

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.

Separate authentication providers for two realms in Spring Security

We use the Spring MVC framework (incl. Spring Security) to implement both a web page and a REST web service. Both are supposed to support username/password authentication. However, they should implement two separate security realms with separate user databases.
The problem we're facing is that Spring security merges the two separate authentication providers into a single list of authentication providers and checks all username/password pairs against both providers. How can we have separate authentication providers for the two realms?
We have tried to separate the realms by using separate roles/authorities. However, if the credentials of the web pages are used to authenticate against the web service, it results in a 403 error (Forbidden) instead of a 401 error (Unauthorized). And since we have to keep perfect backward compatibility with pre-Spring implementation, this is a problem.
Furthermore, we've also tried to split the configuration into several non-inner classes (as proposed in https://stackoverflow.com/a/32756938/413337). However, that didn't help either.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
#Order(1)
public static class WebServiceConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new WebServiceUsernamePasswordAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/service/**")
.hasRole("SERVICE")
.and()
.anonymous().disable()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class WebPagesConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new WebPagesUsernamePasswordAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/", false);
}
}
}
Update:
We have implemented a solution by creating a copy of the BasicAuthenticationFilter and UsernamePasswordAuthenticationToken class and using them for the web service only. However, we would still prefer a solution without code duplication. Could the approach be to create separate authentication manager instances for the two realms?

Categories

Resources