#Preauthrize and #Secured annotations are not working in Spring Oauth (All examples I've referred to are for Spring basic security and not for Oauth protocol):
What I've done is:
I enabled global security in spring_security.xml
I used Preauthrize tag in service but it is not working.
Just add
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
To one of your configurations. I have added to my Resource Server Config
#Configuration
#EnableResourceServer
#Order(2)
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("Sample");
}
#Override
public void configure(HttpSecurity http) throws Exception {
//restrict access using #Secured or #PreAuthorize annotation
http.authorizeRequests().anyRequest().permitAll();
}
}
Worked flawlessly
Related
Using Spring boot 2.2.4.RELEASE, spring-security-oauth2-2.3.3, spring-security-web-5.2.1.
I have set up successfully my oauth2 server and secured my endpoints using WebSecurityConfigurerAdapter and ResourceServerConfigurer.
The problem I'm having is that when I use addFilterBefore(customFilter(), AbstractPreAuthenticatedProcessingFilter.class) in my ResourceServerConfigurer. Calling unsecured paths still try to authenticate instead of being ignored, the request tries to pass through my customFilter().
I did set up all my custom filters manually and not as beans so they won't be added automatically by spring to the filter chain, but I still get this behavior.
I also used ("/rest/**", "/api/**") ant matchers so customFilter() applies only when encountering these paths, but I also still get this behavior.
On server startup I do see this, which is intended:
org.springframework.security.web.DefaultSecurityFilterChain - Creating filter chain: Ant [pattern='/usecured*'], []
org.springframework.security.web.DefaultSecurityFilterChain - Creating filter chain: Ant [pattern='/unsecured2*'], []
org.springframework.security.web.DefaultSecurityFilterChain - Creating filter chain: Ant [pattern='/usecured3*'], []
My WebSecurityConfigurerAdapter
#EnableWebSecurity
#Configuration
#Order(1) // order 1 so it applies before ResourceServerConfigurer paths
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class ApiSecurityRestLoginConfig extends WebSecurityConfigurerAdapter {
//...
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/usecured*","/unsecured2*","/usecured3*");
}
}
My ResourceServerConfigurer
#EnableResourceServer
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class ApiSecurityResourceServerConfig implements ResourceServerConfigurer {
//...
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/rest/**", "/api/**").authenticated()
.and()
//..
.addFilterBefore(customFilter(), AbstractPreAuthenticatedProcessingFilter.class) // <-- when I remove this line, web.ignoring() works, otherwise it doesn't.
//..
}
}
Is this a bug or I'm approaching it the wrong way?
For reference
I updated my web.ignoring() code to this
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/usecured*/**","/unsecured2*/**","/usecured3*/**");
}
and it worked.
I have working spring boot application in which csrf is enabled but now I want to disable it only for localhost. any request from other domain must underpass csrf security but for localhost, I want to disable it. how can I achieve that?
I know how to disable it by changing
#Configuration
#EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf.disable();
}
}
the above code disabled csrf but I want to disable csrf for the only localhost.
Can you please help me?
EDIT: I know how to do it by two profile. Thanks #daren for your detailed answer.
You could use Spring Profiles to achieve what you are looking to do.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
At it's simplest you could have two configurations
#Configuration
#EnableWebMvcSecurity
#Profile("!deployed") //Not(!) deployed profile
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf.disable();
}
}
And in deployed regions active the deployed profile.
#Configuration
#EnableWebMvcSecurity
#Profile("deployed")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf.enable();
}
}
Depending on what security configuration you are doing you could do the inverse of this and active a local profile by default which would do the disabling.
You can use the CsrfConfigurer#requireCsrfProtectionMatcher method and use a RequestMatcher which checks the request local vs remote address e.g.
private RequestMatcher csrfProtectionMatcher() {
final Set<String> allowedMethods = ImmutableSet.of("GET", "HEAD", "TRACE", "OPTIONS");
return request -> !allowedMethods.contains(request.getMethod()) && !(request.getLocalAddr().equals(request.getRemoteAddr()));
}
I want my server be a ResourceServer, which can accept a Bearer Access token
However, If such token doesn't exist, I want to use the OAuth2Server to authenticate my user.
I try to do like:
#Configuration
#EnableOAuth2Sso
#EnableResourceServer
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}
However, in this case, only the #EnableResourceServer annotation works. It returns
Full authentication is required to access this resource
And do not redirect me to the login page
I mentioned that the #Order is important, if I add the #Order(0) annotation,
I will be redirect to the login page, however, I cannot access my resource with the access_token in Http header:
Authorization : Bearer 142042b2-342f-4f19-8f53-bea0bae061fc
How can I achieve my goal? I want it use Access token and SSO at the same time.
Thanks~
Using both configuration on same request would be ambiguous. There could be some solution for that, but more clear to define separate request groups:
OAuth2Sso: for users coming from a browser, we want to redirect them to the authentication provider for the token
ResourceServer: usually for api requests, coming with a token they got from somewhere (most probably from same authentication provider)
For achieving this, separate the configurations with request matcher:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Bean("resourceServerRequestMatcher")
public RequestMatcher resources() {
return new AntPathRequestMatcher("/resources/**");
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.requestMatcher(resources()).authorizeRequests()
.anyRequest().authenticated();
}
}
And exclude these from the sso filter chain:
#Configuration
#EnableOAuth2Sso
public class SsoSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("resourceServerRequestMatcher")
private RequestMatcher resources;
#Override
protected void configure(final HttpSecurity http) throws Exception {
RequestMatcher nonResoures = new NegatedRequestMatcher(resources);
http
.requestMatcher(nonResoures).authorizeRequests()
.anyRequest().authenticated();
}
}
And put all your resources under /resources/**
Of course in this case both will use the same oauth2 configuration (accessTokenUri, jwt.key-value, etc.)
UPDATE1:
Actually you can achieve your original goal by using this request matcher for the above configuration:
new RequestHeaderRequestMatcher("Authorization")
UPDATE2:
(Explanation of #sid-morad's comment)
Spring Security creates a filter chain for each configuration. The request matcher for each filter chain is evaluated in the order of the configurations.
WebSecurityConfigurerAdapter has default order 100, and ResourceServerConfiguration is ordered 3 by default. Which means ResourceServerConfiguration's request matcher evaluated first. This order can be overridden for these configurations like:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration configuration;
#PostConstruct
public void setSecurityConfigurerOrder() {
configuration.setOrder(3);
}
...
}
#Configuration
#EnableOAuth2Sso
#Order(100)
public class SsoSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}
So yes, request matcher is not needed for SsoSecurityConfiguration in the above sample. But good to know the reasons behind :)
I am trying to add ACL capabilities to my server. I have configured spring security using java file and would like to add ACL in the same manner. How should I do it? All the tutorials I found used XML file.
SecurityInit:
#Order(1)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfig
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
#Component
#ComponentScan(basePackages = {"test.package"})
public class SecurityConfig extends
WebSecurityConfigurerAdapter {
...
#Autowired
protected void registerAuthentication(UserDetailsService userDetailsService, AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
// http://stackoverflow.com/a/21100458/162345
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().disable()
.addFilterBefore(...)
.addFilterBefore(...)
// TODO: create a better way to differentiate login to signup
.exceptionHandling()
.authenticationEntryPoint(noRedirectForAnonymous)
.and()
.formLogin()
.successHandler(restAuthenticationSuccessHandler)
.failureHandler(restAuthenticationFailureHandler)
.and()
.logout()
.logoutSuccessHandler(noRedirectLogoutSuccessHandler)
.and()
.authorizeRequests()
.antMatchers("/api/keywords/**").permitAll()
.antMatchers("/api/**").authenticated();
}
}
You can configure spring acl with Java configuration class as follow
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class ACLConfig extends GlobalMethodSecurityConfiguration {
#Autowired
DataSource dataSource;
EhCacheBasedAclCache aclCache() {
EhCacheFactoryBean factoryBean = new EhCacheFactoryBean();
EhCacheManagerFactoryBean cacheManager = new EhCacheManagerFactoryBean();
factoryBean.setName("aclCache");
factoryBean.setCacheManager(cacheManager.getObject());
return new EhCacheBasedAclCache(factoryBean.getObject());
}
LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ACL_ADMIN"),
new SimpleGrantedAuthority("ROLE_ACL_ADMIN"),
new SimpleGrantedAuthority("ROLE_ACL_ADMIN"));
}
#Bean
JdbcMutableAclService aclService() {
JdbcMutableAclService service = new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
service.setClassIdentityQuery("select currval(pg_get_serial_sequence('acl_class', 'id'))");
service.setSidIdentityQuery("select currval(pg_get_serial_sequence('acl_sid', 'id'))");
return service;
}
#Bean
AclMasterService masterService() {
return new AclMasterService();
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler(){
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));
return expressionHandler;
}
}
The important aspect of the configuration are extend from
GlobalMethodSecurityConfiguration
override the method
createExpressionHandler
and enable the Pre and Post anotations with the follow anotation at the begining of the class
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled =
true)
Now you can use anotations like
#PreAuthorize('hasPermission(#object,read)')
see the Contact sample of Spring Security or the spring security reference guide for more uses of #Pre and #Post anotations.
This configuration class was tested on Spring 4 , Spring Security 4.0.1 and Spring Security ACL 3.1.2. If you want configure the authentication you can use a different Java class or override the configure method from this. If you already have a configured ehcache this configuration could not work correctly due to the ehcache is a singleton class and this configuration try to create a new one.
There is no way to configure spring acl without xml file. This is mentioned in spring docs itself.Refer to spring documentation.
I'm new to Spring Security so I probably miss out on something. I have a Spring Application that starts a Jetty with a WebApplication I want to secure using Spring Security. The webapp is running and reachable, but not restricted. I've tried a lot of stuff but nothing worked so I broke it down to a minimal setup, but still no chance.
the webapp is configured by the following java configuration:
#EnableWebMvc
#Configuration
#Import(SecurityConfiguration.class)
#ComponentScan(useDefaultFilters = false, basePackages = { "myapp.web" }, includeFilters = { #ComponentScan.Filter(Controller.class) })
public class SpringMvcConfiguration extends WebMvcConfigurerAdapter {
/**
* Allow the default servlet to serve static files from the webapp root.
*/
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
and Spring Security configured here:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("ADMIN")
.authorities("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.hasAuthority("ADMIN");
}
}
and some controller like this:
#Controller
public class SecuredController {
#RequestMapping(value = "/secure", method = RequestMethod.GET)
#ResponseBody
public String secured() {
return "you should not see this unless you provide authentication";
}
}
Everything starts up all right, the log tells me, that the controller is mapped...
[2014-10-01 20:21:29,538, INFO ] [main] mvc.method.annotation.RequestMappingHandlerMapping:197 - Mapped "{[/secure],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String myapp.web.SecuredController.secured()
...and that security is in place as well...
[2014-10-01 20:21:30,298, INFO ] [main] gframework.security.web.DefaultSecurityFilterChain:28 - Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#352c308, org.springframework.security.web.context.SecurityContextPersistenceFilter#2af616d3, org.springframework.security.web.header.HeaderWriterFilter#1a2e2935, org.springframework.security.web.csrf.CsrfFilter#64f857e7, org.springframework.security.web.authentication.logout.LogoutFilter#bc57b40, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#3deb2326, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7889a1ac, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#7d373bcf, org.springframework.security.web.session.SessionManagementFilter#5922ae77, org.springframework.security.web.access.ExceptionTranslationFilter#7e1a1da6, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#1051817b]
... but the /secure url of my controller is unconditionally reachable. What am I doing wrong?
ps. I want to avoid xml config
In order to integrate Spring Security with Spring MVC you have to use #EnableWebMvcSecurity annotation instead of #EnableWebSecurity in SecurityConfiguration class.
I figured, I had to move the initialization of the Spring Security configuration to the root context, not the dispatcher-servlet context, and add the following line where i configure the context of my embedded Jetty:
context.addFilter(new FilterHolder(new DelegatingFilterProxy("springSecurityFilterChain")), "/*", EnumSet.allOf(DispatcherType.class));