How to ignore certain endpoints using Spring Security Oauth - java

I am using Spring security, oauth in the following way:
#Configuration
#EnableAuthorizationServer
#EnableResourceServer
public class AuthServerOAuth2Config extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.jdbc(jdbcTemplate.getDataSource());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
configurer.tokenStore(tokenStore())
.reuseRefreshTokens(true)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
I want to now make certain URL's public, so that no token is required to access those resources. For example /public/**
How would I do this? Do I need to use a WebSecurityConfigurerAdapter? Thanks for any help!
UPDATE
I added the WebSecurityConfigurerAdapter as pointed out below. So now the /public/** URL is accessible without any tokens. However, all other endpoints are no longer accessible, and respond with 403 Forbidden

For making the path public/** open without authentication, you can configure the WebSecurityConfigurerAdapter like the following:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/public/**").permitAll()
.and()
.authorizeRequests().anyRequest().authenticated();
}
}

you should have something like this
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login*").permitAll();
}

This is how I solved it:
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(HttpMethod.GET, "/public/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
}
}

Related

Spring Security Ldap, log in only users in specified group

Just like in title, I want that only users of spec. Here is my authentication code:
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userSearchFilter("(sAMAccountName={0})")
.contextSource(contextSource());
}
I found that there are functions like groupSearchFilter and groupSearchBase or groupRoleAttribute but I have no idea how to use them
I made some modifications on Megha's solution
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://ip:port/DC=xxxx,DC=yyyy");
contextSource.setUserDn("user_service_account");
contextSource.setPassword("password_user_service_account");
contextSource.setReferral("follow");
contextSource.afterPropertiesSet();
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();
ldapAuthenticationProviderConfigurer
.userSearchBase("OU=Users,OU=Servers")
.userSearchFilter("(&(cn={0})(memberOf=CN=GROUP_NAME,OU=Groups,OU=Servers,DC=xxxx,DC=yyyy))")
.contextSource(contextSource);
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").authenticated().and()
.httpBasic();
}
}
"(sAMAccountName={0})"
should be replaced with following
"(&(objectCategory=Person)(sAMAccountName=*)(memberOf=cn=entergroup,ou=users,dc=company,dc=com))"
where cn, ou,dc are the specifications of the group in directory
It depends on how your group membership is set up. Something like the following might work, replacing your group dn and objectclasses as necessary:
groupSearchBase("cn=yourgroup,ou=groups")
groupSearchFilter("(uniqueMember={0})")

spring-security returns 401 despite authorizeRequests().anyRequest().permitAll()

I'm using spring-security and spring-security-oauth2 (JWT access tokens) for authentication and authorization. The idea is to let all requests through, but to be able to distinguish between authenticated users and unauthenticated users. As soon as I enable #EnableResourceServer my configured HttpSecurity seems to get ignored. And requests return 401:
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
Here's the config:
#SpringBootApplication
#EnableJpaRepositories
#ComponentScan
#EntityScan
#EnableWebSecurity
public class Application {
public static void main(final String[] args) {
new SpringApplicationBuilder(Application.class).bannerMode(Banner.Mode.OFF).run(args);
}
#EnableResourceServer
public static class SecurityConfig extends WebSecurityConfigurerAdapter implements JwtAccessTokenConverterConfigurer {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().permitAll();
}
#Override
public void configure(final JwtAccessTokenConverter converter) {
final DefaultAccessTokenConverter conv = new DefaultAccessTokenConverter();
conv.setUserTokenConverter(userAuthenticationConverter());
converter.setAccessTokenConverter(conv);
}
#Bean
public UserAuthenticationConverter userAuthenticationConverter() {
return new ResourceAuthenticationConverter();
}
}
You're almost there. It's an easy fix - the javadoc of #EnableResourceServer provides the answer:
Users should add this annotation and provide a #Bean of type
ResourceServerConfigurer (e.g. via ResourceServerConfigurerAdapter)
that specifies the details of the resource (URL paths and resource
id).
You're using a WebSecurityConfigurerAdapter however. Just change it to ResourceServerConfigurerAdapter and enhance the visibility of configure:
#EnableResourceServer
public static class SecurityConfig extends ResourceServerConfigurerAdapter implements JwtAccessTokenConverterConfigurer {
// snip
#Override
public void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().permitAll();
}
// snip

Spring Boot OAuth2 with custom security filter

I have a spring boot setup with an OAuth2 authorization and resource server. The user is able to acquire tokens by making a POST request to /oauth/token. So far, so good.
However, I don't want to protect /oauth/token via BASIC auth but by means of a custom security filter.
I tried the following but DemoAuthenticationFilter is never called:
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
// ...
#Override
public void configure(HttpSecurity http) throws Exception {
// ...
http.addFilterBefore(new DemoAuthenticationFilter(), BasicAuthenticationFilter.class);
http.authorizeRequests().antMatchers("/oauth/token").authenticated();
}
}
Also, if I try to add it to WebSecurityConfigurerAdapter the filter is only called after the request is authenticated via OAuth2:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// ...
#Override
protected void configure(HttpSecurity http) throws Exception {
// ...
http.addFilterBefore(new DemoAuthenticationFilter(), BasicAuthenticationFilter.class);
http.authorizeRequests().antMatchers("/oauth/token").authenticated();
}
}
Some simple example how to achieve this would be really helpful. Thank you!
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients().addTokenEndpointAuthenticationFilter(new AligenieFilter());
}
//....
}
It works for me.

Spring OAuth2 restrict user to authenticate via a client

I am implementing a Spring OAuth2 application where I have different clients using a resource.
The clients are mobile applications, so I use the Resource Owner Password Flow.
There are 2 roles in my application: normal users and managers. Respectively there are 2 clients, one for the normal users and one for managers.
I don't want to apply logic on the mobile applications (clients) to check if the user has the necessary roles to access the application. As I understood the tokens should be opaque to the client.
I already restrict the resources with user roles, but I don't want the auth server to provide the client with an access code when the user is not supposed to use that client.
How can I restrict authorization for some users on some clients?
Thanks in advance!
oauth config:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().access("#oauth2.clientHasRole('ROLE_MANAGER') and hasRole('ROLE_MANAGER')");
}
}
#Configuration
#EnableWebSecurity
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("demo").password("password").roles("USER")
.and()
.withUser("manager").password("password").roles("MANAGER");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("manager-client")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_MANAGER")
.scopes("trust")
.resourceIds(RESOURCE_ID);
}
}
}

Security Method Annotations with Java Configuration and Spring Security 3.2

I am having some issues getting my application set up using method level annotation controlled by #EnableGlobalMethodSecurity I am using Servlet 3.0 style initialization using
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(MultiSecurityConfig.class);
}
}
I have attempted 2 different ways of initialising an AuthenticationManager both with their own issues. Please note that not using #EnableGlobalMethodSecurity results in a successful server start up and all of the form security executes as expected. My issues arise when I add #EnableGlobalMethodSecurity and #PreAuthorize("hasRole('ROLE_USER')") annotations on my controller.
I am attempting to set up form-based and api-based security independently. The method based annotations need only work for the api security.
One configuration was the following.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class MultiSecurityConfig {
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**").httpBasic();
}
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
#Configuration
public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**","/status");
}
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().hasRole("USER").and()
.formLogin().loginPage("/login").permitAll();
}
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
}
This is not ideal as I really want only a single registration of the authentication mechanism but the main issue is that it results in the following exception:
java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []
As far as I am aware #EnableGlobalMethodSecurity sets up its own AuthenticationManager so I'm not sure what the problem is here.
The second configuration is as follows.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class MultiSecurityConfig {
#Bean
protected AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN").and()
.and()
.build();
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**").httpBasic();
}
}
#Configuration
public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**","/status");
}
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().hasRole("USER").and()
.formLogin().loginPage("/login").permitAll();
}
}
}
This config actually starts successfully but with an exception
java.lang.IllegalArgumentException: A parent AuthenticationManager or a list of AuthenticationProviders is required
at org.springframework.security.authentication.ProviderManager.checkState(ProviderManager.java:117)
at org.springframework.security.authentication.ProviderManager.<init>(ProviderManager.java:106)
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.performBuild(AuthenticationManagerBuilder.java:221)
and when I test I found that the security doesn't work.
I've been looking at this for a couple of days now and even after diving into spring security implementation code I can't seem to find what is wrong with my configuration.
I am using spring-security-3.2.0.RC1 and spring-framework-3.2.3.RELEASE.
When you use the protected registerAuthentication methods on WebSecurityConfigurerAdapter it is scoping the Authentication to that WebSecurityConfigurerAdapter so EnableGlobalMethodSecurity cannot find it. If you think about this...it makes sense since the method is protected.
The error you are seeing is actually a debug statement (note the level is DEBUG). The reason is that Spring Security will try a few different ways to automatically wire the Global Method Security. Specifically EnableGlobalMethodSecurity will try the following ways to try and get the AuthenticationManager:
If you extend GlobalMethodSecurityConfiguration and override the registerAuthentication it will use the AuthenticationManagerBuilder that was passed in. This allows for isolating the AuthenticationManager in the same way you can do so with WebSecurityConfigurerAdapter
Try to build from the global shared instance of AuthenticationManagerBuilder, if it fails it logs the error message you are seeing (Note the logs also state "This is ok for now, we will try using an AuthenticationManager directly")
Try to use an AuthenticationManager that is exposed as a bean.
For your code, you are going to be best off using something like the following:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class MultiSecurityConfig {
// Since MultiSecurityConfig does not extend GlobalMethodSecurityConfiguration and
// define an AuthenticationManager, it will try using the globally defined
// AuthenticationManagerBuilder to create one
// The #Enable*Security annotations create a global AuthenticationManagerBuilder
// that can optionally be used for creating an AuthenticationManager that is shared
// The key to using it is to use the #Autowired annotation
#Autowired
public void registerSharedAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
// Since we didn't specify an AuthenticationManager for this class,
// the global instance is used
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.httpBasic();
}
}
#Configuration
public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
// Since we didn't specify an AuthenticationManager for this class,
// the global instance is used
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/static/**","/status");
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
}
}
NOTE: More documentation around this will be getting added to the reference in the coming days.

Categories