2016-06-13 4 views
0

Ich versuche Method Security mit @ PreAuthorize zu implementieren.Spring Security scheint einen bestimmten Service zu ignorieren

Frühling Version: 4.2.3.Release Spring Security: 4.0.3.Release

Ich habe eine CustomPermissionEvaluator umgesetzt. Ich habe festgestellt, dass es funktioniert, außer für 1 Dienst, wo die hasPmerission nicht aufgerufen wird. Ich weiß das, weil ich das eine Logging-Nachricht von hasPermission/oder in der falschen Fall nicht bekommen, das Protokoll erhalten:

public boolean hasPermission(Authentication authentication, Object o, Object o1) { 
    logger.info("Call to hasPermission with "+o+" and "+o1); 
... 
} 

My Spring-Konfiguration ist wie folgt:

@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; 
} 
} 

Methode 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; 
} 

Der Dienst in Frage:

@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()); 
    } 
} 

Und die Steuerung von dem ich die Dienstschicht nennen:

@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(); 
} 

Wenn api/Stakeholder/types“mit Aufruf der Methode = POST Dies ist meine Debug-Ausgabe:

Add Stakeholder type in controller 
Create stakeholder type in service layer 
INSERT INTO prefix_http_www_ontorais_de_stakeholdertype(id,stakeholderName) VALUES(DEFAULT,'TESTEWRTERETE'); 

Wie Sie das Protokoll von hasPermission nicht vorhanden zu sehen ist -> nicht genannt. Ich kann sehen, dass die Methode von meinen anderen Methoden-Sicherheitsannotationen in anderen Dienstobjekten aufgerufen wird.

Ein ähnlicher Dienst, die hasPermission richtig ruft als Vergleich nur für erwartete:

@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)); 
} 

Irgendwelche Hinweise auf das, was ich tue, falsch/fehlt/bin blind für sehr willkommen Dank.

Benedict

+0

'OntoRais. *' Ist nicht ein gültiger Paketname'StakeholderService' implementiert keine Schnittstelle. Um' @ PreAuthorize' zu ​​verwenden, muss eine Bibliothek wie cglib oder javassist eingebunden werden. Was ist der Unterschied zwischen Ihren Dienstleistungen? – zeroflagL

+0

Ok änderte meine Component-Scan '@ComponentScan ({ "OntoRais.api", "OntoRais.datalayer.database.service", "OntoRais.security", "OntoRais.datalayer.ontology.ontop", „OntoRais .datalayer.ontology.service ", " OntoRais.config " })'. Keines meiner Dienste implementiert eine Schnittstelle. Sollte das Problem nicht in allen meinen Diensten auftreten? Ich kann keinen Unterschied in den Diensten finden. Ich werde nur einen Arbeitsdienst in die ursprüngliche Frage aufnehmen, um sicher zu gehen. – bwright

+0

Wenn kein Dienst eine Schnittstelle implementiert, ist das Problem natürlich etwas anderes. Ich denke '' ComponentScan ({"OntoRais"}) 'sollte reichen. In 'StakeholderController', wie lautet der Code für' getStakeholderService() '? Wenn es den gesicherten Proxy nicht zurückgibt, wäre das das Problem. Sie können in Ihrer Servicemethode einen Haltepunkt hinzufügen und sich den Aufruf-Stack ansehen. – zeroflagL

Antwort

0

Ok ich das Problem gefunden, und eine Lösung.

Das Problem war, dass mein CustomPermissionEvaluator von einer Methode innerhalb des StakeholderService abhing. Auch wenn diese Methode nicht gesichert war, konnte Spring das Objekt nicht proxy-fähig machen und somit Sicherheitsüberprüfungen verhindern.

Auch wenn es eine schlechte Idee ist, ein Service-Layer-Objekt in dem PermissionEvaluator zu verwenden, vielleicht jemand auf den genauen Auswirkungen erarbeiten könnte, wie ich bin definitiv kein Experte im Frühjahr sercurity