I am implementing OAuth2 in my App. The problem is that I want to open some endpoints to make them accessible without any authentication or role. The file that is giving problems is this: (I want to open an endpoint that is "/api/someRoute/parameters")
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/api/**")
.and()
.authorizeRequests().antMatchers("/api/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
.and()
.exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
} ```
This should work -
.authorizeRequests().antMatchers("/api/someRoute/parameters").permitAll()
Related
I know that there are some similar topics but they are about implementation difficulties, whereas my question is more architect wise.
And it is generally not springframework related.
Let's say there is an application that implements both client\resource (in terms of OAuth2) behaviors.
Also it supports Basic auth with for testing purposes (ans it has its own set of static\ldap users ).
Auth provider is done as a separate application.
This "three-type" auth is reached by
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE)
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(request -> {
String auth = request.getHeader("Authorization");
return (auth != null && auth.startsWith("Basic"));
})
.authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable()
.httpBasic()
;
}
....
}
then goes
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final static Logger logger = LoggerFactory.getLogger(OAuth2ResourceServerConfig.class);
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatcher(request -> {
String auth = request.getHeader("Authorization");
return (auth != null && auth.startsWith("Bearer"));
})
.authorizeRequests()
.anyRequest().authenticated();
}
....
}
and then
#Configuration
#EnableOAuth2Sso
#Order(4)
public class OAuth2SsoConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/", "/login**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable()
;
}
....
}
all in one package (altogether with UI).
That works pretty well. But.
Is that good at all to have it like that?
Some systems which this app integrates with already have "client" behavior itself (like SalesForce), so UI and #EnableOAuth2Sso configuration seem to be dead weight.
Am I missing something in terms of security vulnerabilities? I was able to see that once one bearer token is accepted by app, it creates session and postman sends cookie back to the app on the next request and app manages this session even if another bearer token(for another user) has been applied to the Authorization header.
Does it make sense to customize this via maven profiles or via splitting it to the separate apps (pure UI&client and Resource API)?
Three options as I see it:
Thanks.
I would like to configure web security layer based on my request type.
If the request starts with /rest then it should use Basic authentication with stateless session management and for login authentication then it should use CSRF with stateful session management.
I have tried below code.
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/rest/**").hasRole("SUPER_ADMIN")
.anyRequest().fullyAuthenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin().and().logout().permitAll();
}
It works with basic authentication but it doesn't work for the login request because the session is not stateful. Can anyone please help me to configure Spring security. I am new to Spring security.
You need
1. Rest API's to be authenticated by basic authentication
2. Your web application be authenticated by form login.
And authorization is other part in both cases that you can set it as per your requirement.
Let me explain what was wrong with your approach. By your approach you can achieve only one authentication entry point from one configuration. i.e, you can't achieve multiple authentication entry point.
Now coming to your first requirement of achieving multiple authentication entry point.
1. For Rest API resources -- authentication by HttpBasicAuthentication for antMatcher /rest/**
2. For WebApp resources -- authentication by Form Login for antMatcher other than /rest/**
To achieve this
1. You need to have implementation of WebSecurityConfigurerAdapter of different configuration order and different antMatcher patterns.
2. Order of each configuration is important.
- wildcard pattern(/**) should be placed last order
- non wildcard pattern or restricted pattern(/rest/**) should be placed first order
3. As those configuration classes are static and inner classes for a class which is annotated #EnableWebSecurity you should be careful while defining bean using #bean and autowiring using #Autowired.
Note:
Most of people makes mistake by not defining antmather for authorizeRequest()
If first configuration #Order(1) class is configured as below
http.authorizeRequests()
2nd configuration will become dead configuration because
http.authorizeRequests() => http.antMatcher("/**").authorizeRequests()
And all URL's will be configured only for first configuration only.
Refer code given below for better understanding.
#Configuration
#EnableWebSecurity
public class SpringSecurityConfiguration
{
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Configuration
#Order(1)
public static class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("superadmin")
.password(passwordEncoder.encode("superadmin#123#"))
.roles("SUPER_ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.antMatcher("/rest/**")
.authorizeRequests()
.antMatchers("/rest/**").hasRole("SUPER_ADMIN")
.and().httpBasic();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
#Configuration
#Order(2)
public static class LoginFormSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder.encode("user#123#"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.antMatcher("/**") //wild card i.e, allow all (But already /rest/** is filtered by 1st config)
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/**").authenticated()
.and().formLogin()
.defaultSuccessUrl("/app/user/dashboard")
.and().exceptionHandling()
.accessDeniedPage("/403")
.and().logout()
.invalidateHttpSession(true);
http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired");
}
}
}
This question has requirement of different sets of URL's(/rest/** and other than /rest/**) for different authentication filters. Here user's (for both basic auth and form login) may be authenticated against a single table (say user_details) or multiple tables (say api_users and web_users)
If you have requirement like there is no different set of URL's but two sets of users say customer and employees(staff) both are accessing same application but they needs to be authenticated against different tables(say users and customer table) in that case refer my another answer Spring Security user authentication against customers and employee table
You have to allow users to access login page without authentication and same you can do with static pages. See below configuration.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
Agenda: To create an authorization and resource server such that.
Rest clients can authenticate and authorize and use tokens to fetch resources about the user.
this worked. accessing resources defined at /rest/user endpoint is working fine
Web clients can SSO using this authorization server
I tried using #EnableOAuth2Sso and also using #EnableOAuth2Client. Both didn't work.
When using EnableOAuth2Sso redirect to oauth server's login happened but redirection back to the app didn't happen.
Users can directly log into the authorization server and see if they have an account.
this is working but it is skipping authentication and authorization and the page is getting displayed immediately
I have a OAuth server with ResourceConfig and WebSecurityConfig
#Configuration
#EnableWebSecurity
#Order(1)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired private AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired private AuthenticationFailureHandler authenticationFailureHandler;
#Autowired
#Qualifier("userAccountDetailsService")
UserAccountDetailsService userAccountDetailsService;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.csrf().disable()
.anonymous().disable()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.antMatchers("/**", "/css/**", "/js/**", "/images/**").permitAll()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/userPage/*").hasAnyRole("USER", "HRADMIN")
.antMatchers("/adminPage/*").hasRole("HRADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/login")
.failureHandler(authenticationFailureHandler)
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout");
// #formatter:on
}
#Autowired
protected void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userAccountDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
#Configuration
#EnableResourceServer
#Order(2)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_rest_api";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/rest/user/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
Isn't it possible to combine and use web resource and oauth resources in the same server?
I'm using
Spring Boot: 2.2.0.BUILD-SNAPSHOT and
Spring security-oauth2-autoconfigure: 2.1.3.RELEASE
The whole source is available in github
Authorization and Resource server:
https://github.com/john77eipe/SpringSecurityDrills/tree/master/securestore-oauth
Spring Web client using EnableOAuth2Client:
https://github.com/john77eipe/SpringSecurityDrills/tree/master/securestore-web-resource-1
Spring Web client using EnableOAuth2Sso:
https://github.com/john77eipe/SpringSecurityDrills/tree/master/securestore-web-resource-2
I configure WebSecurityConfig, create user in memory
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("username")
.password(passwordEncoder().encode("password"))
.authorities("READ_ORDERS")
.roles("USER");
}
configure WebSecurityConfig
#Configuration
#Order(1)
public static class BasicAuthenticationAdapter extends WebSecurityConfigurerAdapter {
private final AuthenticationEntryPoint authEntryPoint;
#Autowired
public BasicAuthenticationAdapter(AuthenticationEntryPoint authEntryPoint) {
this.authEntryPoint = authEntryPoint;
}
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/orders**")
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.csrf().disable()
.httpBasic().authenticationEntryPoint(authEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
When i try to Authorise with invalid credentials first time - 401 exception, it's ok.
But after successful authorization, when i use invalid username and password,
i also authorised.
What can be the problem ?
That is how basic authentication works. As soon as you have logged in successfully the valid credentials will always be posted.
Spring security works with SessionCreationPolicy, and default policy is IF_REQUIRED. It means spring creates session if it does not have and is required.
In order to solve your issue you have to change this policy.
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Restart your server and try again.
The Spring Security Tutorial has an example of configuring an LDAP Server:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.formLogin();
}
#Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=groups")
.contextSource().ldif("classpath:test-server.ldif");
}
}
}
However, I'm looking for a way to initialize the the LDAP server dynamically, not in the configuration file. I can't seem to find any examples. The purpose of this is to implement SSO for a login form.
I found it easier to work with a lower-level directory, ldaptive, to solve this problem.