Sto aggiungendo Apache Shiro alla mia domanda e mi chiedo se il seguente messaggio di errore è veramente accurata:Un SecurityManager non associato è davvero una configurazione di applicazione non valida in Shiro?
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessibile al codice chiamante, sia legato a il org.apache.shiro.util.ThreadContext o come un singleton vm statico. Questa è una configurazione di applicazione non valida.
Ho guardato attraverso il codice sorgente di un po 'e l'impressione che ho è che fino a quando non sto usando SecurityUtils
e io sono disposto a passare un SecurityManager
ai componenti che ne hanno bisogno, io don In realtà, è necessario assegnare lo SecurityManager
al singleton statico utilizzato da SecurityUtils
.
La cosa specifica che voglio evitare è che Shiro inserisca qualsiasi cosa nello ThreadLocal
o che abbia Shiro che usa la sua classe di supporto ThreadContext
. Sto usando Apache Thrift e non voglio impegnarmi in un design di rete a thread singolo per richiesta. Le mie richieste di Shiro sono piuttosto ridotte, quindi mostrerò cosa sto facendo qui sotto.
Sto utilizzando Guice nella mia richiesta, ma sono non utilizzando shiro-guice
perché la roba Shiro AOP dipende da avere un Subject
associato ad un ThreadContext
. Invece, comincio con un modulo Guice estremamente semplice.
public class ShiroIniModule extends AbstractModule {
@Override
protected void configure() {}
@Provides
@Singleton
public SecurityManager provideSecurityManager() {
return new DefaultSecurityManager(new IniRealm("classpath:shiro.ini"));
}
}
Questo non è esattamente un setup di realm/security manager di qualità di produzione, ma è abbastanza buono per me testarlo. Successivamente, creo le mie classi di manager con un ambito molto limitato che vengono utilizzati dai componenti della mia applicazione. Ho due di questi; a ThriftAuthenticationManager
e a ThriftAuthorizationManager
. Ecco il primo:
@Singleton
public class ThriftAuthenticationManager {
private final Logger log = LoggerFactory.getLogger(ThriftAuthenticationManager.class);
private final SecurityManager securityManager;
@Inject
public ThriftAuthenticationManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
public String authenticate(String username, String password) throws TException {
try {
Subject currentUser = new Subject.Builder(securityManager).buildSubject();
if (!currentUser.isAuthenticated()) {
currentUser.login(new UsernamePasswordToken(username, password));
}
String authToken = currentUser.getSession().getId().toString();
Preconditions.checkState(!Strings.isNullOrEmpty(authToken));
return authToken;
}
catch (AuthenticationException e) {
throw Exceptions.security(SecurityExceptions.AUTHENTICATION_EXCEPTION);
}
catch(Throwable t) {
log.error("Unexpected error during authentication.", t);
throw new TException("Unexpected error during authentication.", t);
}
}
}
E quest'ultimo:
@Singleton
public class ThriftAuthorizationManager {
private final Logger log = LoggerFactory.getLogger(ThriftAuthorizationManager.class);
private final SecurityManager securityManager;
@Inject
public ThriftAuthorizationManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
public void checkPermissions(final String authToken, final String permissions)
throws TException {
withThriftExceptions(new Callable<Void>() {
@Override
public Void call() throws Exception {
securityManager.checkPermission(getPrincipals(authToken), permissions);
return null;
}
});
}
public void checkPermission(final String authToken, final Permission permission)
throws TException {
withThriftExceptions(new Callable<Void>() {
@Override
public Void call() throws Exception {
securityManager.checkPermission(getPrincipals(authToken), permission);
return null;
}
});
}
private Subject getSubject(String authToken) {
return new Subject.Builder(securityManager).sessionId(authToken).buildSubject();
}
private PrincipalCollection getPrincipals(String authToken) {
return getSubject(authToken).getPrincipals();
}
private void withThriftExceptions(Callable<Void> callable) throws TException {
try {
callable.call();
}
catch(SessionException e) {
throw Exceptions.security(SecurityExceptions.SESSION_EXCEPTION);
}
catch(UnauthenticatedException e) {
throw Exceptions.security(SecurityExceptions.UNAUTHENTICATED_EXCEPTION);
}
catch(AuthorizationException e) {
throw Exceptions.security(SecurityExceptions.AUTHORIZATION_EXCEPTION);
}
catch(ShiroException e) {
throw Exceptions.security(SecurityExceptions.SECURITY_EXCEPTION);
}
catch(Throwable t) {
log.error("An unexpected error occurred during authorization.", t);
throw new TException("Unexpected error during authorization.", t);
}
}
}
miei servizi Thrift utilizzano queste due classi per l'autenticazione e l'autorizzazione. Ad esempio:
@Singleton
public class EchoServiceImpl implements EchoService.Iface {
private final Logger log = LoggerFactory.getLogger(EchoServiceImpl.class);
private final ThriftAuthorizationManager authorizor;
@Inject
public EchoServiceImpl(ThriftAuthorizationManager authorizor) {
this.authorizor = authorizor;
}
@Override
public Echo echo(String authToken, Echo echo) throws TException {
authorizor.checkPermissions(authToken, "echo");
return echo;
}
}
Quindi, suppongo di avere effettivamente alcune missioni.
L'errore che ho citato è effettivamente un errore o solo un messaggio di registro troppo zelante?
Devo preoccuparmi che Shiro si affidi a qualsiasi cosa in un
ThreadContext
se non utilizzo maiShiroUtils
?C'è qualche danno nell'uso di
SecurityUtils#setSecurityManager
se non posso garantire un ambiente a thread singolo per richiesta?Non ho ancora provato a utilizzare le autorizzazioni avanzate di Shiro (
org.apache.shiro.authz.Permission
). Si affidano a qualsiasi cosa in unThreadContext
o fanno qualcosa di strano che dovrei esaminare prima?Ho fatto qualcos'altro che potrebbe causarmi problemi o potrei migliorare qualcosa?