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.
Related
I'd like my spring boot application to serve a protected frontend, as well as being an API resource server for said frontend at the same time, but I can't get the oauth stuff working.
What I want is the spring boot application to return a 302 redirect to the oauth server (gitlab in my case) when the browser requests the index.html without a token, so the user is sent to the login form. But I also want that the API to return a 401 when the API is called without a token, as I think a 302 redirect to a login page is not very useful there.
In pseudo code:
if document_url == /index.html and token not valid
return 302 https//gitlab/loginpage
if document_url == /api/restcall and token not valid
return 401
server document_url
I am working with spring boot 2.1, regarding oauth my pom.xml contains
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
This is my naive try in the SecurityConfig
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/index.html").authenticated()
.and()
.oauth2Login().loginPage("/oauth2/authorization/gitlab")
.and()
.authorizeRequests().antMatchers("/api/restcall").authenticated()
.and()
.oauth2ResourceServer().jwt();
}
}
Both configurations (oauth2Login and oauth2ResourceServer) work fine for themself. But as soon as I combine them the last one wins (so in the above example there would be no 302 and the browser would also see a 401 for the index.html). I presume they share some configuration objects so the last write wins.
Is there an (easy) way to get what I want? I know spring can do almost anything, but I would very much not to end up manually configuring a gazillion beans ...
Update:
I've made a minimal example (including #dur's suggestion) of my code here
You need to create multiple configurations and restrict them only to specific URL patterns using requestMatcher. Based on your example, your configurations should look like this:
SecurityConfigHTML
public class SecurityConfigHTML extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/index.html")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2Login().loginPage("/oauth2/authorization/gitlab");
}
}
SecurityConfigAPI
public class SecurityConfigAPI extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/api/call")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
}
}
SecurityConfigHTML
I think we should include /oauth2/** into the request matchers, otherwise the oauth2Login will not work.
404 http://localhost:8080/oauth2/authorization/gitlab
public class SecurityConfigHTML extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.requestMatchers().antMatchers("/index.html", "/oauth2/**")
.and()
.authorizeRequests()
.antMatchers("/oauth2/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
// #formatter:on
}
}
I'm trying to use spring security to secure a rest/stateless api using JWT tokens. From the research I've been seeing, it involves turning off the spring security session management and then adding some custom filters to handle the user logging in as well as checking for the jwt token.
The problem I'm having is that once i add a filter, it's run on every instead of just the endpoints I want it on. I need to open up the login endpoint as well as a few others that will facilitate enrollment and reference data that doesn't need to be secured.
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/user").permitAll()
.anyRequest().authenticated().and()
.addFilterBefore(new StatelessAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
;
}
}
All StatelessAuthenticationFilter does is print "in here". I'm only expecting to see that message print when you go to localhost:8080/api/order, but i see it show up when you go to localhost:8080/api/user.
Is there a way to get this behavior?
The way you configured, the HttpSecurity will be applied to all the URLs including the user endpoint.
authorizeRequests() .antMatchers("/api/user").permitAll() line won't prevent "user" endpoint from authentication filter being called.
It just says that any authenticated user can call it.
You need to apply the filter to "order" endpoint only. Like this:
http .requestMatchers().antMatchers("/api/user") .and() .authorizeRequests().
#tsolakp's answer sorta works for me. I ended up overriding the
configure(Websecurity) method though
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/user");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated().and()
.addFilterBefore(new StatelessAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
;
}
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?
I'm creating a Spring boot application with Spring Web,Spring Security and Spring social. The application contains rest services that utilizes basic authentication for security. I"m trying to configure Spring to make the application stateless, however when I use the browser to make requests to the web services the browser prompts for user credential but all prior request use the same user credential because of session creation. I have configured the application to stop this from happening but still having the problem. \
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#override
protected void configure(HttpSecurity http) throws Exception{
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**")
.hasRole("USER")
.andBasic();
}
#override
protected void configure(AuthenticatioinManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("some#gmail.com")
.password("12345")
.role("USER");
}
}
What should I change or add to get this functionality.
Spring security is based on something called the SecurityContext. This something is a ThreadLocal, e.g only exists on one thread at a time. Each request will be on it's own thread and will have no access to any protected resource unless that SecurityContext is set to contain the appropriate roles. So even though you just logged in, which behind the scenes inserted roles into the SecurityContext, that security context is gone just as though it had been a different user. Tokens are how you want to deal with this issue. Or base64 encode your username and password into every request, whatever floats your boat.
Look at this:
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() //allow CORS option calls
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
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