Why my custom PermissionEvaluator isn't invoked? - java

I'm struggling with my Spring Security configuration which I wasn't able to make it works so far.
I don't know why my custom PermissionEvaluator is not getting invoked and my #PreAuthorize annotation using hasPermission expression are ignored.
I'm using Spring 4.2.4 and Spring security 4.1.0
Her is my code :
Web Security configuration
#Configuration
#EnableWebSecurity
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http //
.addFilterBefore(wafflePreAuthFilter(), AbstractPreAuthenticatedProcessingFilter.class) //
.authenticationProvider(preauthAuthProvider()) //
.csrf().disable() //
.authorizeRequests() //
.antMatchers("/ui/**").authenticated() //
.anyRequest().permitAll();
}
#Bean
public WafflePreAuthFilter wafflePreAuthFilter() throws Exception {
WafflePreAuthFilter filter = new WafflePreAuthFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
#Bean
public PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
PreAuthenticatedAuthenticationProvider preauthAuthProvider = new PreAuthenticatedAuthenticationProvider();
preauthAuthProvider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
return preauthAuthProvider;
}
#Bean
public UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> userDetailsServiceWrapper() {
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper = new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>();
wrapper.setUserDetailsService(myUserDetailsService());
return wrapper;
}
#Bean
public UserDetailsService myUserDetailsService() {
return new myUserDetailsService();
}
}
Method Security configuration
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class MyServiceMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Bean
public PermissionEvaluator myPermissionEvaluator() {
return new DcePermissionEvaluator();
}
#Override
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(myPermissionEvaluator());
return expressionHandler;
}
}
PermissionEvaluator
public class MyPermissionEvaluator implements PermissionEvaluator {
#Autowired
private MyService myAutowiredService;
#Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
// checking permissions
return true;
}
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
// checking permissions
return true;
}
}
Anyone can give me an hint on what to do ?
By the way if I change MyServiceMethodSecurityConfig into this, then myPermissionEvaluator is processed but dependencies injection doesn't work as it isn't managed by Spring :
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = false)
public class MyServiceMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
public MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new DcePermissionEvaluator());
return expressionHandler;
}
}

I ran into this issue. It seemed to be caused by the annotation #EnableGlobalMethodSecurity being specified in multiple places.
Once I removed it from locations other than above my implementation of GlobalMethodSecurityConfiguration things started working as expected.

Related

Authentication manager missing in custom security class

I have a security jar that I am implementing in my project. I am extending the BasicSecurityConfig which extends WebSecurityConfigurerAdapter and has all the filters. I was told that all I need is to extend the BasicSecurityConfig and call super().configure which will call the parent's configure method. However, I am getting this error,
Field authenticationManager in com.custom.security.CustomSecurityFilter required a bean of type 'org.springframework.security.authentication.AuthenticationManager' that could not be found.
The parent class already has an AuthenticationManager bean, I shouldn't need to define it in the child class too.
My Security Class
public class SecurityConfiguration extends BasicSecurityConfig {
private static final String PAYMONEYROLE = "(hasRole('EE'))";
#Override
protected void configure(HttpSecurity http) throws Exception {
// must call super first
super.configure(http);
http.authorizeRequests()
.antMatchers(HttpMethod.POST, "/v1/cart/validate").authenticated()
.antMatchers(HttpMethod.POST, "/v1/cart/validate").access(PAYMONEYROLE)
.and().cors().and().csrf().disable();
}
#Bean
public FilterRegistrationBean invalidResourceFilterRegistration(InvalidResourceFilter invalidResourceFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean(invalidResourceFilter);
registration.setEnabled(false);
invalidResourceFilter.setDisabled(true);
return registration;
}
#Bean
public FilterRegistrationBean customSecurityFilterRegistration(CustomSecurityFilter customSecurityFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean(customSecurityFilter);
registration.setEnabled(false);
return registration;
}
}
Custom Security Jar
public class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private InvalidResourceFilter invalidResourceFilter;
public BasicSecurityConfig() {
}
protected void configure(HttpSecurity http) throws Exception {
((HttpSecurity)((HttpSecurity)http.addFilterBefore(this.customSecurityFilter(), AbstractPreAuthenticatedProcessingFilter.class).addFilterAfter(this.invalidResourceFilter, FilterSecurityInterceptor.class).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()).exceptionHandling().authenticationEntryPoint(this.authenticationEntryPoint()).accessDeniedHandler(this.customDeniedHandler()).and()).authorizeRequests().accessDecisionManager(this.accessDecisionManager());
}
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(new String[]{"/docs**/**", "/swagger-ui.html**/**", "/webjars**/**", "/swagger-resources**/**", "/api-docs**/**", "/v2/api-docs**", "/version.json**"});
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(this.customAuthenticationProvider());
}
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler() {
return new CustomWebSecurityExpressionHandler();
}
#Bean
public CustomSecurityFilter customSecurityFilter() {
return new CustomSecurityFilter();
}
#Bean
public AuthenticationProvider customAuthenticationProvider() {
return new CustomAuthenticationProvider();
}
#Bean
public AuthenticationSuccessHandler customSuccessHandler() {
return new CustomSuccessHandler();
}
#Bean
public AccessDeniedHandler customDeniedHandler() {
return new CustomAccessDeniedHandler();
}
#Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return new CustomAuthenticationEntryPoint();
}
#Bean
public CustomSystemUserAuthVoter customSystemUserAuthVoter() {
return new CustomSystemUserAuthVoter();
}
#Bean
public WebExpressionVoter webExpressionVoter() {
WebExpressionVoter wev = new WebExpressionVoter();
wev.setExpressionHandler(this.defaultWebSecurityExpressionHandler());
return wev;
}
#Bean
public AccessDecisionManager accessDecisionManager() {
return new ExplicitDecisionManager(Arrays.asList(this.customSystemUserAuthVoter(), this.webExpressionVoter()));
}
}
As per your error, CustomSecurityFilter is supposed to have authenticationManager injected. But it is created without authenticationManager as below.
#Bean
public CustomSecurityFilter customSecurityFilter() {
return new CustomSecurityFilter();
}
If you can modify BasicSecurityConfig, then update the method as follows:
#Bean
public CustomSecurityFilter customSecurityFilter() {
//If it has a constructor which accept AuthenticationManager
return new CustomSecurityFilter(authenticationManagerBean());
//If it has a setter for AuthenticationManager instead
CustomSecurityFilter filter = new CustomSecurityFilter();
filter.setAuthenticationManager(authenticationManagerBean())
return filter;
}
If you cannot modify BasicSecurityConfig, then create it in SecurityConfiguration with Primary
#Bean
#Primary
public CustomSecurityFilter customSecurityFilter() {
//If it has a constructor which accept AuthenticationManager
return new CustomSecurityFilter(authenticationManagerBean());
//If it has a setter for AuthenticationManager instead
CustomSecurityFilter filter = new CustomSecurityFilter();
filter.setAuthenticationManager(authenticationManagerBean())
return filter;
}

Intermittent issue with Spring security #PreAuthorize annoation

I am currently working on Spring boot project which is acting as datasource for UI layer and all endpoint within project are protected using OIDC.
Everything is working as expected however when i try to protect any controller endpoint by putting #PreAuthorize annotation it works well in local development environment (JDK 8) but when things gets deployed over cloud (PCF, OpenJDK) it having weird behavior as 8 out of 10 times it works and 2 times it allows user to bypass security at method level and get desired output.Not sure how to fix this, i am suspecting something do with AOP proxy here but not sure.
Any pointer will be much appreciated.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true, jsr250Enabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
Security config class for reference.
#Configuration
#EnableWebSecurity(debug = true)
public class SecurityConfig extends ResourceServerConfigurerAdapter {
#Value("${jwt-token.audience}")
private String resourceId;
#Value("${jwt-token.issuer-uri}")
private String issuer;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(resourceId).stateless(false);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/swagger-ui/**", "/v3/api-docs", "/swagger-ui.html").permitAll().anyRequest()
.authenticated().and().oauth2ResourceServer().jwt().decoder(jwtDecoder())
.jwtAuthenticationConverter(new CustomJwtAuthenticationConverter());
// #formatter:on
}
#Bean
JwtDecoder jwtDecoder() {
//omitted for brevity
return jwtDecoder;
}
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
}

Spring Boot: Configure custom MethodSecurityExpressionOperations?

I am trouble shooting a spring boot security configuration that I once had working, but now is not recognizing my custom definitions. My goal was to protect all of our Services with method level security in Spring with custom annotations.
When I start the service my CustomMethodSecurityConfig is instantiated and does call createExpressionHandler(), but when I make the request to the service it does not call createSecurityExpressionRoot(...) on my CustomMethodSecurityExpressionHandler, but on the DefaultWebSecurityExpressionHandler.
I appreciate any insights anyone may be able to provide as to why Spring Security is not recognizing my expressions defined in my CustomMethodSecurityExpressionRoot.
Here is a snippet of my GlobalMethodSecurityConfiguration class
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class CustomMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
private final MyService1 myService1;
private final MyService2 myService2;
private final MyService3 myService3;
#Autowired
public CustomMethodSecurityConfig(MyService1 myService1, MyService2 myService2,
MyService3 myService3) {
this.myService1 = myService1;
this.myService2 = myService2;
this.myService3 = myService3;
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler expressionHandler =
new CustomMethodSecurityExpressionHandler(myService1, myService2, myService3);
expressionHandler.setPermissionEvaluator(permissionEvaluator());
return expressionHandler;
}
}
Here is a snippet of my DefaultMethodSecurityExpressionHandler class
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
private final MyService1 myService1;
private final MyService2 myService2;
private final MyService3 myService3;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
public CustomMethodSecurityExpressionHandler(MyService1 myService1, MyService2 myService2,
MyService3 myService3) {
this.myService1 = myService1;
this.myService2 = myService2;
this.myService3 = myService3;
}
#Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication,
myService1,
myService2,
myService3);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
Here is the snippet of my SecurityExpressionRoot, this is where I am defining my SpEL expressions which I use in annotations on my Services. I have only included a simplified, isUser as an example. What these methods do isn't important, but the fact that they are visible.
public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot
implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
private MyService1 myService1;
private MyService2 myService2;
private MyService3 myService3;
public CustomMethodSecurityExpressionRoot(
Authentication authentication,
MyService1 myService1,
MyService2 myService2,
MyService3 myService3) {
super(authentication);
this.myService1 = myService1;
this.myService2 = myService2;
this.myService3 = myService3;
}
#Override
public Object getFilterObject() {
return this.filterObject;
}
#Override
public Object getReturnObject() {
return this.returnObject;
}
#Override
public void setFilterObject(Object obj) {
this.filterObject = obj;
}
#Override
public void setReturnObject(Object obj) {
this.returnObject = obj;
}
#Override
public Object getThis() {
return this;
}
//All custom SpEL methods
public boolean isUser(Long userId) {
SecurityUser user = (SecurityUser) this.getPrincipal();
return user.getUserId() == userId;
}
...
}
And finally here is a snippet of my WebSecurityConfigurerAdapter which is used in tandem, it verifies the external authentication token from our UAA server.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
prePostEnabled = true,
proxyTargetClass = true)
public class ServiceSecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenCheckService _tokenCheckService;
#Autowired
ServiceSecurityConfig(TokenCheckService tokenCheckService) {
_tokenCheckService = tokenCheckService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new TokenAuthenticationProvider(_tokenCheckService));
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/api/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.disable()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new UnAuthorizedEntryPoint())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().authenticated();
http.addFilterBefore(new AuthenticationTokenFilter(), BasicAuthenticationFilter.class);
}
}
Edit:
I seem to think it is an issue with my WebDecisionVoters being overridden during intialization. If I have a breakpoint in the Affirmative constructor
AffirmativeBased(List<AccessDecisionVoter<? extends Object>> decisionVoters)
I can see AffirmativeBased being instantiated with 3 decision voters, one of which is a PreInvocationAuthorizationAdviceVoter, which contains a reference to my expression handler. I believe this is being created by bean instantiation of the methodSecurityInterceptor.
When I continue the breakpoint I again hit the same Affirmative based constructor, but with only one decision voter, a WebExperssionVoter with a reference to an instance of DefaultWebSecurityExpressionHandler. I believe this is being created by bean instantiation of the springSecurityFilterChain.
I was able to resolve this issue by following the steps in Custom SecurityExpression with Service. The issue appears to have been with my autowired services that were separate from security. MyService1, MyService2, and MyService3 causing the issues and removing them allowed security to work.
Any additional services must be set in createSecurityExpressionRoot of the class that extends DefaultMethodSecurityExpressionHandler.
#Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
// Other initialization
root.setMyService1(applicationContext.getBean(MyService1.class));
root.setMyService2(applicationContext.getBean(MyService2.class));
root.setMyService3(applicationContext.getBean(MyService3.class));
return root;
}

Spring Security seems to be ignoring a certain service

I am trying to implement Method Security using #PreAuthorize.
Spring Version: 4.2.3.Release
Spring Security: 4.0.3.Release
I have implemented a CustomPermissionEvaluator. I have noticed that it seems to be working fine except for 1 service where the hasPmerission is not called.
I know this because I get the a logging message from hasPermission / or in the erroneous case do not get the log:
public boolean hasPermission(Authentication authentication, Object o, Object o1) {
logger.info("Call to hasPermission with "+o+" and "+o1);
...
}
My Spring configuration is as follows:
#Configuration
#ComponentScan
public class RootConfiguration {
}
MVC Config
#EnableWebMvc
#Configuration
#ComponentScan({"OntoRais.*"})
#PropertySource("classpath:application.properties")
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean(name="multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(50000000);
return commonsMultipartResolver;
}
}
Method Security Config:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
private CustomPermissionEvaluator permissionEvaluator;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler
= new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
public CustomPermissionEvaluator getPermissionEvaluator() {
return permissionEvaluator;
}
public void setPermissionEvaluator(CustomPermissionEvaluator permissionEvaluator) {
this.permissionEvaluator = permissionEvaluator;
}
}
Initializer:
#Configuration
#EnableSpringConfigured
public class MessageWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(org.springframework.web.context.request.RequestContextListener.class);
super.onStartup(servletContext);
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { MvcConfiguration.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new HiddenHttpMethodFilter(),
new OpenEntityManagerInViewFilter(),
new DelegatingFilterProxy("springSecurityFilterChain")
};
}
}
Security Config:
#Configuration
#EnableWebSecurity
#ComponentScan
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
OntoRAISUserDetailsService ontoRAISUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
formLogin().
and().
logout().
and().
authorizeRequests().
antMatchers("/login").permitAll().
anyRequest().authenticated().
and().csrf().disable();
}
#Autowired
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(ontoRAISUserDetailsService);
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(ontoRAISUserDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public OntoRAISUserDetailsService getOntoRAISUserDetailsService() {
return ontoRAISUserDetailsService;
}
public void setOntoRAISUserDetailsService(OntoRAISUserDetailsService ontoRAISUserDetailsService) {
this.ontoRAISUserDetailsService = ontoRAISUserDetailsService;
}
The Service in question:
#Service
public class StakeholderService {
#Autowired
private OntopManager om;
private static final Logger logger = LoggerFactory.getLogger("OntoRais");
public OntopManager getOm() {
return om;
}
public void setOm(OntopManager om) {
this.om = om;
}
#PreAuthorize("hasPermission(#stakeholderType, 'Create_StakeholderType')")
public void createStakeholderType(StakeholderType stakeholderType) {
try {
logger.info("Create stakeholder type in service layer");
List<OBDADataSource> sources = om.getObdaModel().getSources();
OBDAMappingAxiom mapping = om.getObdaModel().getMapping(new URI("genertatedURI"), MappingList.StakheholderType());
HashMap<String, String> values = new HashMap<>();
values.put("stakeholderName", stakeholderType.getLabel());
String query = ClassSQLHelper.generateSQLCreateSatement(mapping.getSourceQuery(), values);
SQLHelper.executeSQL(query, sources.get(0));
} catch (URISyntaxException e) {
logger.error(e.getMessage());
}
}
And the controller from which i call the service layer:
#Api(description = "Operations related to Stakeholders")
#RestController
public class StakeholderController {
#Autowired
private OntopManager om;
#Autowired
StakeholderService stakeholderService;
#Autowired
ProjectService projectService;
private static final Logger logger = LoggerFactory.getLogger("OntoRais");
...
/**
* Add a new Stakeholder Type
*
* #param stakeholdertype The new Stakeholder to be added.
* #return
*/
#ApiOperation(value = "Add new stakeholder type",
notes = "",
response = ResponseResource.class,
responseContainer = "Object")
#JsonView(Views.Details.class)
#RequestMapping(value = "/api/stakeholder/types", method = RequestMethod.POST)
public ResponseEntity<List<StakeholderType>> addStakeholderType(#RequestBody StakeholderType stakeholdertype) {
logger.info("Add Stakeholder type in controller");
getStakeholderService().createStakeholderType(stakeholdertype);
return getStakeholderTypes();
}
When calling api/stakeholder/types" with method = POST
This is my debug output:
Add Stakeholder type in controller
Create stakeholder type in service layer
INSERT INTO prefix_http_www_ontorais_de_stakeholdertype(id,stakeholderName) VALUES(DEFAULT,'TESTEWRTERETE');
As you can see the log from hasPermission is not present -> not called.
I can see that the method is called from my other method sercurity annotations in other service objects.
A similar Service which correctly invokes hasPermission as expected just for comparison:
#Service
public class OrganisationService {
private static final Logger logger = LoggerFactory.getLogger("OntoRais");
#Autowired
private OntopManager om;
#Autowired
private ProjectService projectService;
...
#PreAuthorize("hasAuthority('Add_Organisation')")
public void addOrganisation(Organisation organisation) {
List<OBDADataSource> sources = om.getObdaModel().getSources();
OBDAMappingAxiom mapping = null;
try {
mapping = om.getObdaModel().getMapping(new URI("genertatedURI"), MappingList.OrganisationMapping());
} catch (URISyntaxException e) {
e.printStackTrace();
}
HashMap<String, String> valueMap = new HashMap<>();
valueMap.put("organisationName", organisation.getName());
valueMap.put("organisationDescription", organisation.getDescription());
String query = ClassSQLHelper.generateSQLCreateSatement(mapping.getSourceQuery(), valueMap);
SQLHelper.executeSQL(query, sources.get(0));
}
Any hints on what I am doing wrong/missing/am blind for are very welcome thanks.
Benedict
Ok I found the problem, and a solution.
The Problem was that my CustomPermissionEvaluator depended on a method within the StakeholderService. Even though that method was not secured this resulted in the Spring not being able to proxy the object, therefore preventing any security checks.
Even though it is a bad idea to use a service layer object in the PermissionEvaluator, perhaps someone could elaborate on the exact implications, as i am definately not an expert in spring sercurity

Can not get #EnableGlobalMethodSecurity working

I'm trying to configure #EnableGlobalMethodSecurity on a java based configuration, but the methods being annotated are being ignored by the aspect. I've covered all the problems usually encountered with the same XML config, my annotation is on a security configuration part of the root context, and my service classes are also managed under the root context.
In the following TestService is an interface containing my #PreAuthorize annotation which I also have a corresponding implementation that I have also tried annotating directly.
AppInitializer.java
public class AppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{
RootConfig.class,
SecurityConfig.class
};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
RootConfig.java
#Configuration
#ComponentScan(basePackages = {"com.acme.app.service"})
public class RootConfig {
}
SecurityConfig.java
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("pass").roles("USER", "ADMIN");
}
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter
extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/static/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll().defaultSuccessUrl("/")
.and().logout().logoutUrl("/logout")
.logoutSuccessUrl("/");
}
#Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
#Bean
public UserDetailsService userDetailsServiceBeanCreation() {
Collection<UserDetails> users = new ArrayList<>();
users.add(getUser("user", "password", "USER"));
users.add(getUser("admin", "pass", "ADMIN", "USER"));
UserDetailsService uds = new InMemoryUserDetailsManager(users);
return uds;
}
private UserDetails getUser(String user, String pass, String... roles) {
// impl omitted...
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter
extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic().realmName("com.acme.app")
.and().sessionManagement();
}
#Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
}
WebConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.acme.app.config",
"com.acme.app.controllers"},
excludeFilters = {
#Filter(type = ASSIGNABLE_TYPE,
value = {
WebConfig.class,
SecurityConfig.class
})
})
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/");
}
#Bean
public CookieLocaleResolver getLocaleResolver() {
CookieLocaleResolver bean = new CookieLocaleResolver();
bean.setCookieName("clientlanguage");
bean.setCookieMaxAge(100000);
return bean;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
registry.addInterceptor(lci);
}
#Bean
public TilesConfigurer getTilesConfigurer() {
CustomTilesInitializer ti = new CustomTilesInitializer();
TilesConfigurer res = new TilesConfigurer();
res.setCompleteAutoload(true);
res.setDefinitions("/WEB-INF/**/tiles.xml");
return res;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.tiles();
registry.enableContentNegotiation(new MappingJackson2JsonView());
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
registry.addRedirectViewController("/home", "/");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/aboutme").setViewName("aboutme");
}
}
TestService.java
public interface TestService {
#PreAuthorize("hasAuthority('ROLE_DUMMY_ROLE')")
BasicData getDataSecured();
}
Note that I also have spring-aop in my pom.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
Your RootConfig is included when scanning is done for the DispatcherServlet.
I would (in this case) exclude all #Configuration classes from being detected automatically. Due to the detection your component scan is again instantiating beans those beans aren't covered by the security aspect as they live in different contexts.

Categories

Resources