Ho pubblicato a detailed article sull'implementazione di Run-As in combinazione con @PreAuthorize
.
1) Implementare il proprio RunAsManager
che crea l'Authentication
da utilizzare durante l'esecuzione del metodo in base a qualsiasi logica personalizzata. L'esempio che segue utilizza un'annotazione personalizzata che fornisce il ruolo in più:
public class AnnotationDrivenRunAsManager extends RunAsManagerImpl {
@Override
public Authentication buildRunAs(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
if(!(object instanceof ReflectiveMethodInvocation) || ((ReflectiveMethodInvocation)object).getMethod().getAnnotation(RunAsRole.class) == null) {
return super.buildRunAs(authentication, object, attributes);
}
String roleName = ((ReflectiveMethodInvocation)object).getMethod().getAnnotation(RunAsRole.class).value();
if (roleName == null || roleName.isEmpty()) {
return null;
}
GrantedAuthority runAsAuthority = new SimpleGrantedAuthority(roleName);
List<GrantedAuthority> newAuthorities = new ArrayList<GrantedAuthority>();
// Add existing authorities
newAuthorities.addAll(authentication.getAuthorities());
// Add the new run-as authority
newAuthorities.add(runAsAuthority);
return new RunAsUserToken(getKey(), authentication.getPrincipal(), authentication.getCredentials(),
newAuthorities, authentication.getClass());
}
}
Questa implementazione cercherà una consuetudine @RunAsRole
annotazioni su un metodo protetto (ad es @RunAsRole("ROLE_AUDITOR")
) e, se trovato, si aggiungerà l'autorità data (ROLE_AUDITOR
in questo caso) all'elenco delle autorità concesse. RunAsRole
stesso è solo una semplice annotazione personalizzata.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RunAsRole {
String value();
}
2) un'istanza della manager:
<bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl">
<property name="key" value="my_run_as_key"/>
</bean>
3) Registrati è:
<global-method-security pre-post-annotations="enabled" run-as-manager-ref="runAsManager">
<expression-handler ref="expressionHandler"/>
</global-method-security>
4) Esempio di utilizzo in un controllore:
@Controller
public class TransactionLogController {
@PreAuthorize("hasRole('ROLE_REGISTERED_USER')") //Authority needed to access the method
@RunAsRole("ROLE_AUDITOR") //Authority added by RunAsManager
@RequestMapping(value = "/transactions", method = RequestMethod.GET) //Spring MVC configuration. Not related to security
@ResponseBody //Spring MVC configuration. Not related to security
public List<Transaction> getTransactionLog(...) {
... //Invoke something in the backend requiring ROLE_AUDITOR
{
... //User does not have ROLE_AUDITOR here
}
EDIT: Il valore di key
in RunAsManagerImpl
può essere qualsiasi cosa tu voglia. Ecco l'estratto da Spring docs il suo uso:
Per garantire codice dannoso non crea un RunAsUserToken
e presente per l'accettazione garantita dalla RunAsImplAuthenticationProvider
, l'hash di una chiave è memorizzato in tutti i token generato. Il RunAsManagerImpl
e RunAsImplAuthenticationProvider
viene creato nel contesto di fagioli con la stessa chiave:
<bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl">
<bean id="runAsAuthenticationProvider"
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
Utilizzando la stessa chiave , ogni RunAsUserToken
possono essere convalidati è stato creato da un approvato RunAsManagerImpl
.RunAsUserToken
è immutabile dopo la creazione di per motivi di sicurezza.
Che cosa è esattamente usato per "my_run_as_key"? - Non riesco a capirlo. Probabilmente ho letto la stessa guida che hai citato qui, ma questa chiave non ha alcun senso per me. –
@DanielBo Il valore può essere qualsiasi cosa tu voglia. È fondamentalmente una password. Ho aggiornato la risposta per citare i documenti di Spring sul perché è necessario. – kaqqao