Ich füge Apache Shiro meine Anwendung und ich frage mich, wenn die folgende Fehlermeldung wirklich korrekt ist:Ist ein nicht gebundener SecurityManager wirklich eine ungültige Anwendungskonfiguration in Shiro?
org.apache.shiro.UnavailableSecurityManagerException: Nein Security zugänglich für die Telefonvorwahl, entweder gebunden an org.apache.shiro.util.ThreadContext oder als statischer vm-Singleton. Dies ist eine ungültige Anwendungskonfiguration.
Ich habe ein bisschen und der Eindruck durch den Quellcode sehe, dass ich ist erhalten, dass, solange ich nicht SecurityUtils
mit und ich bin bereit, eine SecurityManager
zu Komponenten zu übergeben, die es, ich don brauchen muss den SecurityManager
nicht dem statischen Singleton zuweisen, der von SecurityUtils
verwendet wird.
Die spezifische Sache, die ich vermeiden möchte, ist Shiro legte alles in ThreadLocal
oder mit Shiro verwenden Sie seine ThreadContext
Support-Klasse. Ich benutze Apache Thrift und möchte mich nicht für ein One-Thread-pro-Request-Netzwerkdesign einsetzen. Meine Anforderungen von Shiro sind ziemlich minimal, also werde ich zeigen, was ich unten mache.
Ich verwende Guice in meiner Anwendung, aber ich bin nicht mit shiro-guice
weil die Shiro AOP Sachen ein Subject
auf, die in Verbindung mit einem ThreadContext
abhängen. Stattdessen beginne ich mit einem sehr einfachen Guice-Modul.
public class ShiroIniModule extends AbstractModule {
@Override
protected void configure() {}
@Provides
@Singleton
public SecurityManager provideSecurityManager() {
return new DefaultSecurityManager(new IniRealm("classpath:shiro.ini"));
}
}
Das ist nicht gerade eine Produktionsqualität Bereich/Security Manager-Setup, aber es ist gut genug für mich mit zu testen. Als nächstes erstelle ich eigene Manager-Klassen mit einem sehr begrenzten Umfang, die von den Komponenten meiner Anwendung verwendet werden. Ich habe zwei davon; a ThriftAuthenticationManager
und ThriftAuthorizationManager
. Hier ist die ehemalige:
@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);
}
}
}
Und dieser:
@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);
}
}
}
Meine Thrift Dienste verwenden, um die beiden oben genannten Klassen für die Authentifizierung und Autorisierung. Zum Beispiel:
@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;
}
}
Also, ich denke, ich habe tatsächlich ein paar Quests.
Ist der Fehler, den ich zitiert habe, tatsächlich ein Fehler oder nur eine übereifrige Protokollnachricht?
Muss ich mir Sorgen machen, dass sich Shiro auf irgendetwas in einem
ThreadContext
verlässt, wenn ich nieShiroUtils
verwende?Gibt es einen Schaden bei der Verwendung von
SecurityUtils#setSecurityManager
, wenn ich keine One-Thread-pro-Request-Umgebung garantieren kann?Ich habe noch nicht die erweiterten Berechtigungen von Shiro (
org.apache.shiro.authz.Permission
) versucht. Verlassen sie sich auf irgendetwas in einemThreadContext
oder machen Sie etwas Unheimliches, das ich früher oder später untersuchen sollte?Habe ich irgendetwas anderes gemacht, das mir Probleme bereiten könnte oder könnte ich etwas verbessern?