Domanda

Sto scrivendo un'applicazione Web Java che hanno bisogno di effettuare login tramite un webservice. Naturalmente, nessuno dei regni in dotazione con il server di applicazione che utilizzo (GlassFish V2) può fare il trucco. Ho dovuto quindi scrivere il mio. Sembra tuttavia, che l'attuazione regno che ho scritto è completamente legato alla Glassfish e non può essere usato come è in qualsiasi altro application server.

C'è un modo standard o ampiamente supportato per implementare un Reame personalizzato? E 'in ogni modo possibile per distribuire quel regno da un .war, o che ha bisogno sempre di essere caricato dal proprio percorso di classe del server?

È stato utile?

Soluzione

NOTA: La risposta che segue è valida solo per Java EE 5. Come è stato portato alla mia attenzione in una delle altre risposte, Java EE 6 non supporta questa. Quindi, se si sta utilizzando Java EE 6, non leggere questa risposta, ma leggere l'altra relativa risposta.

Dalla mia ricerca e dalle risposte a questa domanda la risposta che ho trovato è il seguente: Anche se JAAS è un'interfaccia standard, non c'è modo uniforme di scrivere, implementare e integrare un Reame JAAS + LoginModule in diversi server applicativi.

Glassfish v2 richiede di estendere alcune delle sue classi interne che implementano LoginModule o Realm stessi. È possibile, tuttavia, non personalizzare l'intero processo di login, perché molti metodi dell'interfaccia LoginModule sono contrassegnati finale nella superclasse di Glassfish. Le classi LoginModule e Realm personalizzati devono essere collocati nel percorso di classe AS (non dell'applicazione), e il regno devono essere registrati manualmente (senza distribuzione dal possibile .war).

La situazione sembra essere un po 'meglio per Tomcat, che vi permetterà di codificare il proprio Reame e LoginModule completamente, e poi configurare nel server delle applicazioni utilizzando il proprio JAASRealm (che delegare il lavoro effettivo alle vostre implementazioni di Realm e LoginModule). Tuttavia, anche Tomcat non consente la distribuzione vostro regno personalizzato dal .war.

Si noti che nessuno dei server di applicazione che ha mostrato i miei risultati sembrano essere in grado di sfruttare appieno tutte le JAAS richiamate. Tutti loro sembrano supportare solo lo schema di nome utente + password di base. Se avete bisogno di qualcosa di più complicato di così, allora si avrà bisogno di trovare una soluzione che non è gestito dal container Java EE.

Per riferimento, e perché è stato chiesto nei commenti a mia domanda, ecco il codice che ho scritto per GlassfishV2.

Prima di tutto, ecco l'attuazione Realm:

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;
}
}

E poi l'attuazione LoginModule:

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;
}
}

, infine, nel regno deve essere legato al LoginModule. Questo viene fatto a livello di file di configurazione JAAS, che a sua v2 GlassFish è alla yourDomain / config / login.conf. Aggiungere le seguenti righe alla fine del file:

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

Questo è quello che ha ottenuto le cose che lavorano per me su GlassFish. Ancora una volta, questa soluzione non è portabile su application server, ma per quanto ne so, non esiste una soluzione portatile esistente.

Altri suggerimenti

  

C'è un modo standard o ampiamente supportato per implementare un personalizzato   Regno? E 'in ogni modo possibile per distribuire quel regno da un .war, o   ne ha bisogno sempre di essere caricato dal proprio percorso di classe del server?

assolutamente C'è un modo standard per implementare un Reame personalizzato, o più in generale di un modulo di autenticazione personalizzato. Ciò può essere fatto tramite il JASPIC / Jaspi / JSR 196 SPI / API . JASPIC è una parte standard di qualsiasi piena applicazione Java EE 6, ma purtroppo non fa parte del Java EE 6 Web profilo.

Tuttavia, nonostante JASPIC essere una parte di Java EE 6, è non essere ottimale supportata dai fornitori. GlassFish e WebLogic sembrano avere ottime implementazioni, JBoss AS e Geronimo sono un po 'più problematico. L'ingegnere capo da JBoss su questo argomento (Anil Saldhana) ha anche dichiarato che rifiuta di attivare JASPIC di default per il momento. Alcuni dei più gravi bug in JBoss AS 7.1 sono stati recente fisse , ma come non ci sono rilasci pubblici JBoss 7.1.x in programma più e JBoss AS 7.2 è ancora un po 'di tempo lontano vuol dire fin d'ora almeno su JBoss JASPIC è fastidioso.

Un altro problema spiacevole è che il modulo di autenticazione reale può essere standardizzato, ma non c'è modo dichiarativo (leggere il file XML) per configurarlo che è standardizzato.

  

E 'in ogni modo possibile per distribuire quel regno da un .war, o lo fa   devono sempre essere caricati dal proprio percorso di classe del server?

Con JASPIC, il modulo di autenticazione ( 'regno') può infatti essere caricati da un .war. Io non sono sicuro al 100% se questo è garantito dalle specifiche, ma delle 4 server che ho provato (GlassFish, WebLogic, Geronimo e JBoss AS), tutti hanno sostenuto questo. Geronimo ha purtroppo una sorta di condizione di competizione nella sua registrazione programmatico, quindi è necessario un brutto soluzione facendo un'implementare caldo due volte, ma alla fine se viene caricato il modulo dalla .war.

Come dei meccanismi proprietari, almeno JBoss AS ha sempre sostenuto caricamento del modulo (ad esempio una sottoclasse di org.jboss.security.auth.spi.AbstractServerLoginModule) dal .war o .ear.

I scritto un post sul blog su questo argomento di recente che ha ancora un po ' i dettagli.

Non si può mai distribuire un regno da una guerra, perché il regno non è un artefatto di applicazione, si tratta di una delle risorse del contenitore (quindi la "sicurezza basata contenitore" frase). È possibile configurare la vostra applicazione per utilizzare un ambito specifico, come previsto dal contenitore, ma l'applicazione non può fornire questa stessa.

Detto questo, mentre tutti i contenitori sono diversi, e questi regni non sono portabili, semplice buon senso ridurrà le differenze per quel po 'di codice collante necessario integrare con il contenitore, se siete alla ricerca di portabilità.

Avere ha un rapido sguardo a documentazione Suns sembra che si dovrà scrivere un LoginModule personalizzato che si estende la loro classe specifica application server. Questo sembra un po 'indietro per me e una limitazione di Glassfish.

Se si vuole fare questo più portabile, io suggerirei di mettere il grosso della implementazione in un LoginModule personalizzata sviluppata contro l'interfaccia JavaEE standard (s) e poi avere uno strato sottile di attuazione specifiche per Glassfish che i delegati allo standard , implementazione portatile.

Scopri articolo di Sun su questo argomento .

Non ho mai realmente fatto questo io stesso, ma sono abbastanza fiducioso ogni AS ti dà la possibilità di registrare nuovi regni (domini di sicurezza) su di esso.

Probabilmente non sarà portatile 100%, e per ogni AS potrebbe essere necessario un diverso XML di configurazione, ma in fondo, non v'è alcun motivo per il codice per essere diverso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top