2012-04-11 10 views
5

Scrivo un server socket (nessuna applicazione Web!) E voglio utilizzare la sicurezza basata sui metodi per gestire le mie esigenze di ACL. ho seguito un piccolo tutorial che ho trovato spring security by examplePreAuthorize non funziona

finora ho configurato:

<security:global-method-security pre-post-annotations="enabled"> 
    <security:expression-handler ref="expressionHandler" /> 
</security:global-method-security> 
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"> 
    <property name="permissionEvaluator"> 
     <bean id="permissionEvaluator" class="myPermissionEvaluator" /> 
    </property> 
</bean> 

<security:authentication-manager id="authenticationmanager"> 
    <security:authentication-provider ref="authenticationprovider" /> 
</security:authentication-manager> 
<bean id="authenticationprovider" class="myAuthenticationProvider" /> 

Con un fagiolo di servizio:

@Named 
public class ChannelService { 
    @PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')") 
    public void writeMessage(Channel channel, String message) { ... } 
} 

Tutto compila e si avvia l'applicazione e funziona bene, ma senza il controllo degli accessi . Il mio registro di debug mostra che il mio valutatore non viene mai chiamato.

Quando ho provato qualcosa di simile con un'annotazione @Secured l'annotazione è stata valutata e l'accesso è stato negato. ma la semplice sicurezza basata sui ruoli non è abbastanza per le mie esigenze.

EDIT ha fatto alcuni altri test: quando configuro solo garantiti-annotazioni = opere di sicurezza in base al ruolo "abilitato". quando si configura pre-post-annotations = "enabled" in ADDITION né protetto né preautorizzato funziona. quando configuro solo le pre-post-annotazioni, non funziona ancora.

EDIT2

alcuni altri test: con solo secured_annotations = "Enabled" la chiamata alla mia channelservice passa attraverso la Cglib2AopProxy non appena posso attivare pre-post-annotazioni delle terre chiamata direttamente nella channelservice . nessun intercettore, nessun proxy, niente.

Sto diventando sorta di disperata ...

Edit3

I debug-registrato le mie testruns qui è la parte per la primavera-sicurezza

con solo-annotazioni garantiti =" enabled"

2012-04-12 13:36:46,171 INFO [main] o.s.s.c.SpringSecurityCoreVersion - You are running with Spring Security Core 3.1.0.RELEASE 
2012-04-12 13:36:46,174 INFO [main] o.s.s.c.SecurityNamespaceHandler - Spring Security 'config' module version is 3.1.0.RELEASE 
2012-04-12 13:36:49,042 DEBUG [main] o.s.s.a.m.DelegatingMethodSecurityMetadataSource - Caching method [CacheKey[mystuff.UserService; public void mystuff.UserService.serverBan(java.lang.String,mystuff.models.User,org.joda.time.DateTime)]] with attributes [user] 
2012-04-12 13:36:49,138 DEBUG [main] o.s.s.a.i.a.MethodSecurityInterceptor - Validated configuration attributes 
2012-04-12 13:36:49,221 DEBUG [main] o.s.s.a.m.DelegatingMethodSecurityMetadataSource - Caching method [CacheKey[mystuff.ChannelService; public void mystuff.ChannelService.writeMessage(mystuff.models.Channel,java.lang.String)]] with attributes [blubb] 
2012-04-12 13:36:51,159 DEBUG [main] o.s.s.a.ProviderManager - Authentication attempt using mystuff.GlobalchatAuthenticationProvider 
2012-04-12 13:36:56,166 DEBUG [Timer-1] o.s.s.a.ProviderManager - Authentication attempt using mystuff.GlobalchatAuthenticationProvider 
2012-04-12 13:36:56,183 DEBUG [Timer-1] o.s.s.a.i.a.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public void mystuff.ChannelService.writeMessage(mystuff.models.Channel,java.lang.String); target is of class [mystuff.ChannelService]; Attributes: [blubb] 
2012-04-12 13:36:56,184 DEBUG [Timer-1] o.s.s.a.i.a.MethodSecurityInterceptor - Previously Authenticated: org.springframew[email protected]312e8aef: Principal: [email protected]; Credentials: [PROTECTED]; Authenticated: true; Details: null; Not granted any authorities 
Exception in thread "Timer-1" org.springframework.security.access.AccessDeniedException: Access is denied 
    at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70) 
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:88) 
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205) 
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:59) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) 
    at mystuff.ChannelService$$EnhancerByCGLIB$$3ad5e57f.writeMessage(<generated>) 
    at mystuff.run(DataGenerator.java:109) 
    at java.util.TimerThread.mainLoop(Timer.java:512) 
    at java.util.TimerThread.run(Timer.java:462) 
2012-04-12 13:36:56,185 DEBUG [Timer-1] o.s.s.access.vote.AffirmativeBased - Voter: [email protected], returned: 0 
2012-04-12 13:36:56,185 DEBUG [Timer-1] o.s.s.access.vote.AffirmativeBased - Voter: [email protected]a7, returned: 0 

con pre-post-annotazioni = "enabled"

2012-04-12 13:39:54,926 INFO [main] o.s.s.c.SpringSecurityCoreVersion - You are running with Spring Security Core 3.1.0.RELEASE 
2012-04-12 13:39:54,929 INFO [main] o.s.s.c.SecurityNamespaceHandler - Spring Security 'config' module version is 3.1.0.RELEASE 
2012-04-12 13:39:54,989 INFO [main] o.s.s.c.m.GlobalMethodSecurityBeanDefinitionParser - Using bean 'expressionHandler' as method ExpressionHandler implementation 
2012-04-12 13:39:59,812 DEBUG [main] o.s.s.a.ProviderManager - Authentication attempt mystuff.GlobalchatAuthenticationProvider 
2012-04-12 13:39:59,850 DEBUG [main] o.s.s.a.i.a.MethodSecurityInterceptor - Validated configuration attributes 

Per quanto ne so, questa molla di uscita del registro non si rende conto che i miei bean devono essere sottoposti a proxy, quindi non lo sono e quindi non ottengo la sicurezza.

edit4

I debug-registrato l'avvio sprint completo ... (questo è un unico grande log) e non ci trovo:

2012-04-12 14:40:41,385 INFO [main] o.s.c.s.ClassPathXmlApplicationContext - Bean 'channelService' of type [class mystuff.ChannelService] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 

c'è un modo per capire perché? perché per quanto ho capito a causa di @preauthorize, il bean dovrebbe essere idoneo. con solo secure-annotations = "enabled" ottengo un log di post-elaborazione.

+0

Quale versione di Spring and Spring Security stai usando? – Roadrunner

+0

@Roadrunner spring 3.1.0.RELEASE su tutto. – Laures

+1

È possibile eseguire il debug se "PrePostAnnotationSecurityMetadataSource # getAttributes()" viene chiamato per il metodo quando viene inizializzato Spring? – Luciano

risposta

5

Questa configurazione ha funzionato esattamente come previsto per me:

<bean id="securityExpressionHandler" 
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" /> 

<bean id="preInvocationAdvice" 
    class="org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice" 
    p:expressionHandler-ref="securityExpressionHandler" /> 

<util:list id="decisionVoters"> 
    <bean class="org.springframework.security.access.vote.AuthenticatedVoter" /> 
    <bean class="org.springframework.security.access.vote.RoleVoter" /> 
    <bean class="org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter" 
     c:pre-ref="preInvocationAdvice" /> 
</util:list> 

<bean id="accessDecisionManager" 
    class="org.springframework.security.access.vote.UnanimousBased" 
    c:decisionVoters-ref="decisionVoters" /> 

<sec:global-method-security 
    authentication-manager-ref="authenticationManager" 
    access-decision-manager-ref="accessDecisionManager" 
    pre-post-annotations="enabled" /> 

ho ottenuto il messaggio di registro:

WARN org.springframework.security.access.expression.DenyAllPermissionEvaluator - 
    Denying user jack permission 'CHANNEL_WRITE' on object Channel[ name=null ] 

e un'eccezione:

org.springframework.security.access.AccessDeniedException: Access is denied 

Da un semplice test:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:META-INF/spring/application-context.xml") 
public class SpringSecurityPrePostTest { 

    @Autowired 
    ChannelService channelService; 

    @Test 
    public void shouldSecureService() throws Exception { 
     Authentication authentication = new UsernamePasswordAuthenticationToken("jack", "sparrow"); 
     SecurityContext securityContext = SecurityContextHolder.getContext(); 
     securityContext.setAuthentication(authentication); 

     channelService.writeMessage(new Channel(), "test"); 
    } 
} 

Una cosa che ho fatto differente è stato quello di usare l'interfaccia su un servizio e deleghe JDK invece di cglib:

public interface ChannelService { 

    void writeMessage(Channel channel, String message); 
} 

e:

@Component 
public class ChannelServiceImpl implements ChannelService { 

    private static final Logger LOG = LoggerFactory.getLogger(ChannelServiceImpl.class); 

    @Override 
    @PreAuthorize("isAuthenticated() and hasPermission(#channel, 'CHANNEL_WRITE')") 
    public void writeMessage(Channel channel, String message) { 
     LOG.info("Writing message {} to: {}" , message, channel); 
    } 

} 

Update1:


Con questa configurazione semplificata ottengo lo stesso risultato:

<bean id="securityExpressionHandler" 
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" /> 

<sec:global-method-security 
    authentication-manager-ref="authenticationManager" 
    pre-post-annotations="enabled"> 
    <sec:expression-handler ref="securityExpressionHandler" /> 
</sec:global-method-security> 

UPDATE2:


Il messaggio di debug da Modifica4 indica che channelService potrebbe non avere alcun proxy proxy dato che è stato classificato come not eligible for auto-proxying. This qiestion risponde a un problema simile: prova a non utilizzare @Autowired o qualsiasi altro meccanismo basato su BeanPostProcessors per impostare i bean coinvolti nei controlli di sicurezza (ad esempio myPermissionEvaluator).


Update3:


È non può uso assicurata risorse (cioè servizi) all'interno di fagioli responsabili dei controlli di sicurezza! Questo crea un ciclo di dipendenza ed è un errore nella tua configurazione. È necessario utilizzare l'accesso a livello di amante (ad esempio DAO) per controllare le autorizzazioni, tutto ciò che è non protetto! L'implementazione dei controlli di sicurezza utilizzando le risorse protette è non quello che si desidera fare.

Se nonostante l'utilizzo di risorse non protette con @Autowired, le cose non funzionano come previsto, provare a utilizzare lo stile di confiurazione XML della vecchia scuola per tutti i bean coinvolti nei controlli di sicurezza.Ricorda inoltre che <context:component-scan /> è in realtà un BeanDefinitionRegistryPostProcessor e introduce i bean digitalizzati nello BeanFactory dopo che tutti quelli dichiarati in XML sono già presenti.

+0

nel mio PermissionEvaluator è utilizzare il servizio Canale e Utente perché utente permi le ssioni su questi oggetti sono memorizzate in questi oggetti. Ma "@inject" di questi bean fa sì che questi due servizi vengano creati prima di PrePostAnnotationSecurityMetadataSource. quando li rimuovo, il mio valutatore viene chiamato correttamente. ora devo solo capire come iniettare i miei servizi proxy nel valutatore senza causare questo. – Laures

+0

@Laures vedere la mia risposta estesa per ulteriori suggerimenti. – Roadrunner

+0

i metodi che utilizzo per verificare le autorizzazioni non sono protetti (e non lo saranno) ma fanno parte del servizio che ha metodi sicuri. Ho risolto il problema cercando l'oggetto servizio dal contesto dell'applicazione quando ne ho avuto la necessità. forse non è la soluzione più pulita ma nel mio caso non c'è un livello di accesso più basso. – Laures

-1

funziona, assicurarsi di avere <sec:global-method-security pre-post-annotations="enabled"/> nel vostro servlet primavera (cioè dove si può avere la vostra <mvc:annotation-driven/>)

"sec" è da xmlns:sec="http://www.springframework.org/schema/security"

+0

come si può vedere ho già il tag di sicurezza del metodo globale configurato e questa non è un'applicazione web, quindi niente servlet o nulla. – Laures

+0

@ Laure è l'annotazione denominata che stai usando? Non è un'annotazione di primavera, forse dovresti provare con Component anntotation –

+0

di nome è un'annotazione jsr330 che in modo basico significa lo stesso come componente, ma è specifico e non specifico per la molla. implementato entro la primavera – Laures