Autenticazione nativa Windows Active Directory in Tomcat

Postato da ROb | nella categoria Java, Sviluppo web | venerdì, 22 luglio 2011

0

Per un interessante progetto a cui sto lavorando, ho avuto la necessità di configurare Tomcat per poter autenticare nativamente i client (con browser IE7 e IE8 e Firefox) attraverso il repository Active Directory di Windows 2003 Server.

Per farlo ci sono a disposizione, come spesso avviene, numerose possibilità.
Dopo averne provate un paio alla fine ho scelto la soluzione proposta dalla libreria spnego.

spnego implementa il protocollo Kerberos/SPNEGO invece del classico NTLM per dialogare con i domain controller e, attraverso un filtro inserito nella nostra web application, ci offre la possibilità di verificare l’identità degli utenti (attraverso la chiamata java request.getRemoteUser() ) già autenticati in Windows dopo un logon positivo nel dominio di Active Directory.

La guida offerta dal sito della libreria per il raggiungimento di tale integrazione è molto ben fatta. Qui sotto in breve voglio riassumere i miei passi, che in larga parte seguono appunto tale guida.

  • creazione di un utente in Active Directory, che sarà utilizzato dal filtro per loggarsi al dominio e verificare le credenziali degli utenti.
  • creazione del file krb5.conf (all’interno della directory di esecuzione di Tomcat, nel mio caso la bin) con tale contenuto:
    [libdefaults]
    	default_realm = <NOME_DOMINIO>
    	default_tkt_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    	default_tgs_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    	permitted_enctypes   = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    
    [realms]
    	<NOME_DOMINIO>  = {
    		kdc = <DOMAIN_CONTROLLER>
    		default_domain =  <NOME_DOMINIO>
    }
    
    [domain_realm]
    	. <NOME_DOMINIO> =  <NOME_DOMINIO>
    
  • creazione del file login.conf (nella stessa posizione del file krb5.conf) con il seguente contenuto
    spnego-client {
    	com.sun.security.auth.module.Krb5LoginModule required;
    };
    
    spnego-server {
    	com.sun.security.auth.module.Krb5LoginModule required
    	storeKey=true
    	isInitiator=false;
    };
    
  • creazione di una web application (nel mio caso il suo nome è testad) con dentro solamente la directory WEB-INF con dentro una cartella lib con la libreria jar di spnego (nel mio caso l’ultima versione disponibile era la 7, spnego-r7.jar) e il file web.xml con il seguente contenuto (rimpiazzate opportunamente l’utente e la password dell’utente di Active Directory):
    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
       version="2.5">
    
      <filter>
        <filter-name>SpnegoHttpFilter</filter-name>
        <filter-class>net.sourceforge.spnego.SpnegoHttpFilter</filter-class>
    
        <init-param>
            <param-name>spnego.allow.basic</param-name>
            <param-value>true</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.allow.localhost</param-name>
            <param-value>false</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.allow.unsecure.basic</param-name>
            <param-value>true</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.login.client.module</param-name>
            <param-value>spnego-client</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.krb5.conf</param-name>
            <param-value>krb5.conf</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.login.conf</param-name>
            <param-value>login.conf</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.preauth.username</param-name>
            <param-value>utentead</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.preauth.password</param-name>
            <param-value>password_utentead</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.login.server.module</param-name>
            <param-value>spnego-server</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.prompt.ntlm</param-name>
            <param-value>true</param-value>
        </init-param>
    
        <init-param>
            <param-name>spnego.logger.level</param-name>
            <param-value>1</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>SpnegoHttpFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    </web-app>
    

    aggiungete anche il file index.jsp nella root della web application con il seguente contenuto:

    <%@page import="java.security.Principal" %>
    <html>
     <head>
      <title>Protected Page for Examples</title>
     </head>
     <body bgcolor="white">
      You are logged in as remote user <b><%= request.getRemoteUser() %></b> in session <b><%= session.getId() %></b>
      <br><br>
      <%
    	if (request.getUserPrincipal() != null) {
      %>
      Your user principal name is <b><%= request.getUserPrincipal().getName() %></b>.
      <br><br>
      <%
       } else {
      %>
       No user principal could be identified.
       <br><br>
      <%
      }
      %>
      <%
      String role = request.getParameter("role");
      if (role == null)
        role = "";
      if (role.length() > 0) {
        if (request.isUserInRole(role)) {
      %>
      You have been granted role <b><%= role %></b>.
      <br><br>
      <%
       } else {
      %>
      You have <i>not</i> been granted role <b><%= role %></b>.
      <br><br>
      <%
       }
      }
      %>
      To check whether your username has been granted a particular role, enter it here:
      <form method="GET" action='<%= response.encodeURL("index.jsp") %>'>
       <input type="text" name="role" value="<%= role %>">
      </form>
      <br><br>
      You can logoff by clicking
      <a href='<%= response.encodeURL("index.jsp?logoff=true") %>'>here</a>.
      This should cause automatic re-logon with Waffle and a new session ID.
      <br>
     </body>
    </html>
    
  • a questo punto inserite questa web application nelle applicazioni del vostro Tomcat
  • per completare il processo bisogna lanciare nel domain controller un paio di istruzioni per abilitare il tab delegation all’utente Active Directory che effettuerà la verifica dei token del Kerberos.
    setspn.exe -A HTTP/<sito> utentead
    setspn.exe -A HTTP/<sito_con_dominio> utentead
    

    poi aprendo le proprietà dell’utente, nel tab “Delegation”, abilitare la funzione “Trust this user for delegation to any service (Kerberos only)”.

  • per permettere al browser di passare le credenziali al server bisognerà, nel caso di IE, inserire il sito all’interno dell’Area Intranet e verificare che sotto la voce Autenticazione Utente (dentro livello personalizzato) sia impostato come “Accesso automatico solo nell’area Internet”, mentre per Firefox (testato con il 3.x) bisogna impostare le seguenti chiavi con il valore del vostro sito web
    network.negotiate-auth.delegation-uris = http://<sito>
    network.negotiate-auth.trusted-uris = http://<sito>
    
  • riavviate ora Tomcat e accedete alla root della vostra nuova web application
  • il filtro di spnego proteggerà tutti i file della web application e chiederà l’autenticazione nativa (o eventualmente l’autenticazione basic tramite prompt). Se l’autenticazione avverrà correttamente accederete al file index.jsp e leggerete il vostro nome utente nella pagina.

Grazie per l’attenzione e buon lavoro!

Allungare il tempo delle sessioni in un’applicatione web

Postato da ROb | nella categoria Java, Sviluppo web | giovedì, 15 aprile 2010

0

Per aumentare la durata di una sessione in un’applicazione web Java J2EE è sufficiente inserire una particolare direttiva all’interno del file web.xml dell’applicazione stessa.

Ecco la sintassi:

  ...
  <session-config>
    <session-timeout>120</session-timeout>
  </session-config>
  ...

dove il numero rappresenta i minuti.

Fare debugging di applicazioni web Java con Tomcat ed Eclipse

Postato da ROb | nella categoria Java, Sviluppo web | mercoledì, 10 febbraio 2010

2

Qualche anno fa ritenevo impossibile fare debugging di applicazioni web.
Mi chiedevo in particolar modo come fosse possibile raggruppare all’interno di un unico debugger la componente client side (cioè il mix di codice html+css+javascript eseguito nel browser) con la componente server side (in qualsiasi forma si presentasse: php, java, dot.net).

Eclipse, compagno di debug

Ultimamente molti framework, così come importanti application server con il loro IDE associato, sono riusciti a colmare questa mancanza ed ad offire a noi poveri sviluppatori il nostro caro e provvidenziale debugger.

In realtà in questo articolo non spiegherò come sia possibile fare debugging di entrambe le componenti (client e server) in un’unico IDE bensì mi concentrerò solamente sulla parte server, che ho sempre considerato la più spinosa.
La parte client, in realtà, dà spesso meno noie. Il suo comportamento è più facilmente intuibile e spesso è sufficiente fare delle stampe extra di codice html o qualche alert javascript per poter venire a capo dei problemi (anche se non dobbiamo dimenticare l’utilissimo Firebug in Firefox, di cui ho parlato anche ieri, che permette di fare debugging anche del Javascript lato client).

Oggi voglio parlare del debugging server side di applicazioni web per il mondo Java e in particolare della modalità fornita da Eclipse chiamata “Remote Java Application”. E’ una modalità tale per cui è possibile avviare la JVM con un demone in ascolto su una determinata porta. A questa porta, IDE opportunamente istruiti (quale ad esempio Eclipse), possono collegarsi e dialogare con la JVM stessa.
La JVM segnala all’IDE la riga in quel momento in esecuzione e riceve dall’IDE stesso dei comandi in merito all’esecuzione del codice: breakpoint, step-into, step-over, stato delle variabili, …

Per arrivare a poter debuggare la nostra JVM remota, dobbiamo essenzialmente eseguire due passi: avviare la JVM di Tomcat con degli opportuni parametri per la modalità “remote instance” e indicare al nostro IDE, per il nostro progetto da debuggare, qual è la porta della JVM a cui collegarsi.

Cominciamo con la parte di modifica dell’avvio di Tomcat:

  • scegliere una porta libera su cui mettere in ascolto la JVM di Tomcat. Per questo esempio useremo la porta 5050
  • individuare il file startup.sh all’interno della nostra distribuzione Tomcat (la versione di Tomcat di questo post è la 6, ma tale procedura è ugualmente applicabile alla versione 5.5)
  • modificare l’ultima riga di tale file in questo modo
    # vecchia riga
    # exec "$PRGDIR"/"$EXECUTABLE" start "$@"
    # nuova riga
    export JPDA_TRANSPORT=dt_socket
    export JPDA_ADDRESS=5050
    exec "$PRGDIR"/"$EXECUTABLE" jpda start "$@"
    
  • controllare che, dopo aver avviato Tomcat, la JVM sia effettivamente in ascolto
    telnet localhost 5050
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    

Abbiamo terminato con le modifiche alla sequenza di avvio di Tomcat. Passiamo ora ad Eclipse.
Dopo aver scelto il progetto che vogliamo debuggare, le cui classi compilate devono essere in esecuzione all’interno di una webapp del nostro application server Tomcat, dobbiamo creare una nuova istanza di compilazione di tipo “Remote Java Application“.

  • dal menu “Run” di Eclipse scegliamo la voce: “Debug…”
  • scorriamo fino alla voce “Remote Java Application” e scegliamo “New” utilizzando il tasto destro del mouse


    Nuova istanza di debug JVM remota

  • diamo un nome alla nostra istanza di debug e modifichiamo la porta di default con la porta scelta 5050


    Modifica delle impostazioni standar, istanza remota java

  • a questo punto clicchiamo su Debug. Se tutto va bene Eclipse dovrebbe essere in grado di connettersi e dialogare con la nostro JVM in esecuzione con Tomcat

Ora viene la parte più bella!

Iniziamo a impostare dei breakpoint nei punti di codice che vogliamo controllare e facciamo sì che il flusso di esecuzione arrivi in quel punto.
Magicamente potremmo vedere tutti i nostri oggetti Java materializzarsi. Possiamo esaminarne tutte le proprietà, impostare delle espressioni di controllo, entrare e uscire dalle funzioni.

Un aspetto decisamente divertente è l’interazione con il browser. Interrompendo il flusso di esecuzione della JVM interrompiamo ovviamente anche la risposta del server verso il browser. Il cursore di attesa del nostro amato Firefox girerà finché non avremo terminato il controllo del nostro codice e lanceremo il nostro ultimo F8.

Nel caso di debug di applicazioni web AJAX tale possibilità di sviluppo facilita ulteriormente le cose. In questi casi infatti è meno banale controllare i dati restituiti dal server in quanto non compongono quasi mai una pagina html ispezionabile bensì solamente delle porzioni di codice XML o del Javascript serializzato in formato JSON.

Spero che l’articolo vi sia tornato utile; commenti e osservazioni sono sempre molto ben accetti.