2009-04-05 9 views
13

Sto scrivendo un'applicazione web Java che deve eseguire l'accesso tramite un servizio web. Ovviamente, nessuno dei domini forniti con il server delle applicazioni che sto usando (glassfish v2) può fare il trucco. Ho quindi dovuto scrivere il mio. Sembra, tuttavia, che l'implementazione del regno che ho scritto sia completamente legata a glassfish e non possa essere utilizzata come in nessun altro server di applicazioni.Applicazione Web Java: utilizzo di un dominio personalizzato

Esiste un modo standard o ampiamente supportato per implementare un reame personalizzato? È in ogni modo possibile implementare quel dominio da un .war, o deve sempre essere caricato dal proprio classpath del server?

+0

potresti pubblicare un esempio del tuo codice di dominio? –

risposta

9

NOTA: la risposta seguente è valida solo per Java EE 5. Come è stato segnalato in una delle altre risposte, Java EE 6 supporta questo. Quindi, se stai utilizzando Java EE 6, non leggere questa risposta, ma leggi l'altra risposta pertinente.

Dalla mia ricerca e dalle risposte a questa domanda la risposta che ho trovato è la seguente: Sebbene JAAS sia un'interfaccia standard, non esiste un modo uniforme per scrivere, distribuire e integrare un Realm + LoginModule JAAS in vari server applicazioni .

Glassfish v2 richiede l'estensione di alcune delle proprie classi interne che implementano LoginModule o Realm. Tuttavia, non è possibile personalizzare l'intero processo di accesso perché molti metodi dell'interfaccia LoginModule sono contrassegnati come finali nella superclasse di Glassfish. Le classi LoginModule e Realm personalizzate devono essere posizionate nel classpath AS (non nell'applicazione) e il dominio deve essere registrato manualmente (nessuna distribuzione da .war possibile).

La situazione sembra essere un po 'migliore per Tomcat, che ti permetterà di codificare completamente il tuo Realm e LoginModule, e poi configurarli nel server delle applicazioni usando il suo JAASRealm (che delegherà il lavoro effettivo alle tue implementazioni di Realm e LoginModule). Tuttavia, anche tomcat non consente la distribuzione del tuo dominio personalizzato dal tuo .war.

Si noti che nessuno degli Application Server che hanno mostrato i miei risultati sembra essere in grado di sfruttare appieno tutti i callback JAAS. Tutti sembrano supportare solo lo schema utente base + password. Se hai bisogno di qualcosa di più complicato, dovrai trovare una soluzione che non sia gestita dal tuo contenitore Java EE.

Per riferimento, e poiché è stato chiesto nei commenti alla 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 al livello del file di configurazione JAAS, che in glassfish v2 si trova su yourDomain/config/login.conf. Aggiungere le seguenti righe alla fine di quel file:

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

Questo è ciò che ha funzionato per me su glassfish. Ancora una volta, questa soluzione non è portabile tra i server delle applicazioni, ma per quanto posso dire, non esiste una soluzione portatile esistente.

-2

Check out Sun's article on this subject.

In realtà non l'ho mai fatto, ma sono abbastanza sicuro che ogni AS ti dia un'opzione per registrare nuovi domini (domini di sicurezza) su di esso.

Probabilmente non sarà portatile al 100%, e per ogni AS potrebbe essere necessario un XML di configurazione diverso, ma in pratica non c'è alcuna ragione per cui il codice sia diverso.

1

Dopo aver dato una rapida occhiata alla documentazione di Suns, sembra che si debba scrivere un LoginModule personalizzato che estende la classe specifica del proprio server delle applicazioni. Questo mi sembra un po 'arretrato e una limitazione di Glassfish.

Se si desidera rendere questo più portatile, suggerirei di mettere la maggior parte dell'implementazione in un LoginModule personalizzato sviluppato rispetto alle interfacce JavaEE standard e quindi avere uno strato di implementazione sottile specifico per Glassfish che delega al implementazione standard e portatile.

+0

Sì, è già quello che ho fatto. Mi sentivo piuttosto schifoso, quindi mi chiedevo se ci fosse un altro modo. Ma sembra che non ci sia un altro modo (almeno non con glassfish) – LordOfThePigs

+0

sì, non ricordo di dover fare qualcosa di questo hacky quando ne ho scritto uno per JBoss. Scusa non ho potuto aiutare di più – BenM

2

Non è mai possibile distribuire un dominio da una GUERRA perché il regno NON è un artefatto dell'applicazione, è un artefatto contenitore (quindi la frase "sicurezza basata sul contenitore"). Puoi configurare la tua app per utilizzare un ambito specifico come previsto dal contenitore, ma l'applicazione non può fornirlo da solo.

Detto questo, mentre tutti i contenitori sono diversi, e questi reami NON sono portabili, il semplice buon senso ridurrà le differenze con il pezzettino di codice di colla necessario per l'integrazione con il contenitore, se stai cercando portabilità .

+1

So che questa è una risposta molto vecchia, ma anche nel 2009 vari server hanno permesso l'implementazione del "realm" (o qualsiasi altro nome utilizzato da un server, poiché il nome stesso non è standardizzato) essere dentro la guerra o l'orecchio. Almeno JBoss AS ha permesso questo dalla versione 5, forse anche prima. –

6

Esiste un modo standard o ampiamente supportato per implementare un dominio personalizzato ? È in ogni modo possibile implementare tale dominio da un file .war o deve sempre essere caricato dal proprio percorso di classe del server?

Esiste un modo standard per implementare un dominio personalizzato o, in termini più generali, un modulo di autenticazione personalizzato. Questo può essere fatto tramite il JASPIC/JASPI/JSR 196 SPI/API. JASPIC è una parte standard di qualsiasi implementazione Java EE 6 completa, ma sfortunatamente non fa parte del profilo Web Java EE 6.

Tuttavia, nonostante JASPIC sia parte di Java EE 6, non viene supportato in modo ottimale dai fornitori. GlassFish e WebLogic sembrano avere ottime implementazioni, JBoss AS e Geronimo sono un po 'più problematici. L'ingegnere capo di JBoss su questo argomento (Anil Saldhana) ha addirittura dichiarato che per il momento è il refuses to activate JASPIC by default. Alcuni dei bug più gravi in ​​Jboss AS 7.1 sono stati recently fixed, ma poiché non ci sono più versioni pubbliche di JBoss 7.1.x pianificate e JBoss AS 7.2 è ancora lontano, significa che almeno ora su JBoss JASPIC è fastidioso .

Un altro problema sfortunato è che il modulo di autenticazione effettivo può essere standardizzato, ma non esiste un modo dichiarativo (leggi file XML) per configurarlo che è standardizzato.

E 'in ogni modo possibile per distribuire quel regno da un .war, o ha sempre bisogno di essere caricato dal proprio percorso di classe del server?

Con JASPIC, il modulo di autenticazione ('realm') può essere effettivamente caricato da un file .war. Non sono sicuro al 100% se questo sia garantito dalle specifiche, ma dei 4 server che ho testato (GlassFish, WebLogic, Geronimo e JBoss AS), hanno supportato tutto questo. Geronimo sfortunatamente ha una specie di condizione di competizione nella sua registrazione programmatica, quindi hai bisogno di una brutta soluzione alternativa eseguendo una hot deployment due volte, ma alla fine se carica il modulo dal file .war.

Come per i meccanismi proprietari, almeno JBoss AS ha sempre supportato il caricamento del modulo (ad esempio una sottoclasse di org.jboss.security.auth.spi.AbstractServerLoginModule) da .war o .ear.

I wrote a blog post su questo argomento recentemente che ha qualche dettaglio in più.

+0

Fantastico! Questo è nuovo in J2EE 6? Perché sono abbastanza sicuro che non fosse possibile in J2EE 5. – LordOfThePigs

+0

@LordOfThePigs essere pedante per primo, non c'è mai stato né un J2EE 5 o 6. È diventato Java EE;) Ma in effetti, JASPIC è stato introdotto con Java EE 6 La specifica stessa ha una lunga storia ed è stata a sua volta rilasciata qualche tempo prima di Java EE 6. Poiché i produttori indipendenti potevano implementarla volontariamente, il che non significa molto per una specifica che mira a portare la portabilità dei moduli auth a tutti i fornitori. –

Problemi correlati