Frage

Ich schreibe eine Java-Web-Anwendung, die Anmeldung über einen Webservice ausführen müssen. Natürlich keiner der mit dem Anwendungsserver geliefert Realms kann ich verwende (Glassfish v2) den Trick. Ich hatte also meine eigenen zu schreiben. Es scheint jedoch, dass der Bereich Implementierung, die ich vollständig zu Glassfish und kann nicht verwendet werden, gebunden schrieb wie in allen anderen Anwendungsservern ist.

Gibt es eine Standard- oder breit abgestützte Weise eine benutzerdefinierte Realm zu implementieren? Ist es in irgendeiner Weise möglich, dass Reich von einem .war zu implementieren, oder ist es immer vom Server des eigenen Classpath geladen werden müssen?

War es hilfreich?

Lösung

Hinweis: Die Antwort unten gilt nur für Java EE 5. Wie in einer der anderen Antworten auf meine Aufmerksamkeit gebracht, Java EE 6 dies nicht unterstützt. Also, wenn Sie Java EE verwenden 6, nicht über diese Antwort gelesen, aber die andere relevante Antwort lesen.

Aus meiner eigenen Forschung und aus den Antworten auf diese Frage die Antwort, die ich die folgenden gefunden: Obwohl JAAS eine Standardschnittstelle ist, gibt es keine einheitliche Art und Weise zu schreiben, zu implementieren und zu integrieren, einen JAAS Realm + Loginmodule in verschiedenen Anwendungsservern.

Glassfish v2 erfordert, dass Sie einen Teil seiner eigenen internen Klassen zu erweitern, die Loginmodule oder Realm selbst implementieren. Sie können jedoch nicht den gesamten Login-Prozess anpassen, da viele Methoden der Schnittstelle Loginmodule markiert sind in Glassfish des übergeordneten Klasse endgültig. Die benutzerdefinierten Loginmodule und Realm-Klassen müssen im AS Classpath platziert werden (nicht die Anwendung), und der Bereich manuell registriert werden muss (kein Einsatz von .war möglich).

Die Situation scheint für Tomcat ein bisschen besser zu sein, was Sie Ihren eigenen Realm und Loginmodule vollständig codieren lassen, und sie dann in den Anwendungsserver konfigurieren seine eigene JAASRealm mit (die die eigentliche Arbeit an Ihre Implementierungen von Realm delegieren und Loginmodule). Allerdings ist auch Kater nicht zulassen, dass Ihr benutzerdefinierten Bereich aus Ihrem .war bereitstellen.

Beachten Sie, dass keine der Anwendungsserver, die meine Ergebnisse auftauchten scheinen alle Vorteile von der JAAS Rückrufe nehmen zu können. Alle von ihnen scheinen den Grund Benutzername + Passwort-Schema nur zu unterstützen. Wenn Sie etwas komplizierter als das benötigen, dann müssen Sie eine Lösung finden, die nicht von Ihrem Java EE Container verwaltet wird.

Als Referenz und weil es in den Kommentaren zu meiner Frage gestellt wurde, hier ist der Code, den ich für glassfishv2 schrieb.

Zunächst einmal ist hier die Realm Umsetzung:

public class WebserviceRealm extends AppservRealm {

private static final Logger log = Logger.getLogger(WebserviceRealm.class.getName());

private String jaasCtxName;
private String hostName;
private int port;
private String uri;

@Override
protected void init(Properties props) throws BadRealmException, NoSuchRealmException {
    _logger.info("My Webservice Realm : init()");

    // read the configuration properties from the user-supplied properties,
    // use reasonable default values if not present
    this.jaasCtxName = props.getProperty("jaas-context", "myWebserviceRealm");
    this.hostName = props.getProperty("hostName", "localhost");
    this.uri = props.getProperty("uri", "/myws/EPS");

    this.port = 8181;
    String configPort = props.getProperty("port");
    if(configPort != null){
        try{
            this.port = Integer.parseInt(configPort);
        }catch(NumberFormatException nfe){
            log.warning("Illegal port number: " + configPort + ", using default port (8181) instead");
        }
    }
}

@Override
public String getJAASContext() {
    return jaasCtxName;
}

public Enumeration getGroupNames(String string) throws InvalidOperationException, NoSuchUserException {
    List groupNames = new LinkedList();
    return (Enumeration) groupNames;
}

public String getAuthType() {
    return "My Webservice Realm";
}

public String getHostName() {
    return hostName;
}

public int getPort() {
    return port;
}

public String getUri() {
    return uri;
}
}

Und dann die Loginmodule Implementierung:

public class WebserviceLoginModule extends AppservPasswordLoginModule {

// all variables starting with _ are supplied by the superclass, and must be filled
// in appropriately

@Override
protected void authenticateUser() throws LoginException {
    if (_username == null || _password == null) {
        throw new LoginException("username and password cannot be null");
    }

    String[] groups = this.getWebserviceClient().login(_username, _password);

    // must be called as last operation of the login method
    this.commitUserAuthentication(groups);
}

@Override
public boolean commit() throws LoginException {
    if (!_succeeded) {
        return false;
    }

    // fetch some more information through the webservice...

    return super.commit();
}

private WebserviceClient getWebserviceClient(){
    return theWebserviceClient;
}
}

Schließlich hat im Reich an die Loginmodule gebunden werden. Dies wird in der JAAS-Konfigurationsdatei Ebene durchgeführt, die in Glassfish v2 liegt bei yourdomain / config / login.conf. Fügen Sie die folgenden Zeilen am Ende der Datei:

myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
    my.auth.login.WebserviceLoginModule required;
};

Dies ist, was wurde es für mich auf Glassfish arbeiten. Auch diese Lösung ist nicht tragbar über Anwendungsserver ist, aber soweit ich das beurteilen kann, gibt es keine bestehende tragbare Lösung.

Andere Tipps

  

Gibt es eine Standard- oder breit abgestützte Weg, um eine Gewohnheit zu implementieren   Reich? Ist es in irgendeiner Weise möglich, dass Reich von einem .war zu implementieren, oder   ist es immer vom Server des eigenen Classpath geladen werden muß?

Es ist absolut eine standardisierte Möglichkeit ein eigenes Reich, oder ganz allgemein ein eigenes Authentifizierungsmodul zu implementieren. Dies kann über die JASPIC / Jäspi / JSR 196 SPI / API erfolgen. JASPIC ist ein Standard-Bestandteil jeder vollen Java EE 6 Implementierung, aber leider nicht Teil der Java EE 6 Web Profile.

Doch trotz JASPIC ein Teil der Java EE 6 ist, ist es nicht optimal von Anbietern unterstützt wird. Glassfish und WebLogic scheinen sehr gute Implementierungen zu haben, JBoss AS und Geronimo etwas problematisch sind. Der leitende Ingenieur von JBoss zu diesem Thema (Anil Saldanha) hat sogar erklärt, dass er JASPIC standardmäßig aktivieren verweigert für den Moment. Einige der schwersten Fehler in Jboss AS 7.1 haben vor kurzem festgelegt , aber da gibt es keine öffentlichen Freisetzungen JBoss 7.1.x geplant mehr und JBoss AS 7.2 ist noch einige Zeit, es bedeutet, weg ab sofort zumindest auf JBoss JASPIC ist mühsam.

Ein weiteres unglückliches Problem ist, dass die eigentliche Authentifizierungsmodul standardisiert werden kann, aber es gibt keine deklarativ (XML-Datei lesen) zu konfigurieren, dass standardisierte wird.

  

Ist es in irgendeiner Weise möglich, dass Reich von einem .war zu implementieren, oder tut es   immer müssen vom Server des eigenen Classpath geladen werden?

Mit JASPIC, das Authentisierungsmodul ( ‚Bereich‘) kann in der Tat von einem .war geladen werden. Ich bin nicht 100% sicher, ob dies durch die Spezifikation garantiert, aber der 4-Server I getestet (Glassfish, WebLogic, Geronimo und JBoss AS), sie alle diese unterstützt. Geronimo hat leider eine Art Race-Bedingung in seiner programmatischen Registrierung, so müssen Sie eine hässliche Abhilfe durch einen Hot Deploy zweimal zu tun, aber es am Ende, wenn das Modul von der .war nicht geladen werden.

AS der proprietären Mechanismen zumindest JBoss AS immer unterstützt hat Laden des Moduls (beispielsweise eine Unterklasse von org.jboss.security.auth.spi.AbstractServerLoginModule) von der .war oder .ear.

schrieb einen Blog-Post zu diesem Thema vor kurzem, dass hat einige mehr Details.

Sie können nie ein Reich aus einem IST einsetzen, weil das Reich keine Anwendung Artefakt ist, es ist ein Container Artifact (daher der Begriff „Container basierte Sicherheit“). Sie können Ihre Anwendung konfigurieren, um einen bestimmten Bereich zu verwenden, wie sie durch den Behälter zur Verfügung gestellt, aber die Anwendung kann diese selbst nicht anbieten.

Das heißt, während alle Container verschieden sind, und diese Bereiche sind nicht tragbar, einfach der gesunde Menschenverstand, die Unterschiede zu den wenig Glue Code reduzieren, die notwendig mit dem Behälter zu integrieren, wenn Sie für die Portabilität suchen.

Mit hat einen kurzen Blick auf Sonnen-Dokumentation sieht es aus wie Sie eine benutzerdefinierte Loginmodule schreiben müssen, die ihre App-Server bestimmte Klasse erweitert. Dies scheint ein wenig zu mir nach hinten und einer Begrenzung von Glasfischen.

Wenn Sie dies mehr tragbar machen wollen, würde ich vorschlagen, die größten Teil der Umsetzung in einem benutzerdefinierten Loginmodule gegen den Standard JavaEE-Schnittstelle entwickelt Putting (en) und dann eine dünne Schicht Implementierung spezifisch für Glassfish mit, dass die Delegierten die Norm , tragbare Umsetzung.

Überprüfen Sie heraus Sun Artikel zu diesem Thema .

ich nie tat eigentlich diese selbst, aber ich bin ziemlich sicher, jeder, wie Sie eine Option gibt neue Bereiche (Sicherheitsdomänen) auf sie zu registrieren.

Es wird wahrscheinlich nicht zu 100% tragbar sein, und für jeden AS Sie könnte eine andere Konfiguration XML benötigen, aber im Grunde gibt es keinen Grund für den Code anders sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top