Dopo aver visto come configurare OpenAM per ottenere un modulo di autenticazione che faccia Single Sign On su un Active Directory e un Data Store che si occupi della lettura del profilo di un utente dallo stesso Active Directory, con questo post passeremo alla configurazione di Apache Syncope.
Dopo aver visto come configurare OpenAM per ottenere un modulo di autenticazione adibito per il Single Sign On su un Active Directory e, un Data Store che si occupi della lettura del profilo di un utente dallo stesso Active Directory, con questo post passeremo alla configurazione di Apache Syncope; in questo articolo analizzeremo i passi da seguire sul codice dell'IDM per demandare il processo di autenticazione su OpenAM. Più precisamente, in questo post, ci occuperemo dell'agent di OpenAM e del core di Syncope; nel post successivo analizzeremo nel dettaglio le modifiche da apportare alla sua console.
Prima di procedere con la descrizione dei passi per arrivare all'obiettivo del post, sembra opportuno fare una piccola digressione tecnica su come è stato sviluppato, dal punto di vista architetturale del software, Syncope.
Una delle caratteristiche più importanti di Apache Syncope è quella di poter essere customizzato, classe per classe, in modo molto semplice grazie agli overlay di Maven. In questo modo, come vedremo nel nostro caso, è possibile riscrivere qualsiasi classe Java che compone Syncope, ricompilare il progetto scaricato, deployare i war ottenuti come qualsiasi altra applicazione web.
Ho fatto questa premessa perché, come vedremo successivamente in questo post e nei post successivi, per ottenere il risultato cercato sono state modificate le seguenti classi per le diverse fasi:
Seguendo i passi suggeriti dal wiki si procede alla creazione del progetto di Syncope. Alla fine di questa operazione, avremo sul nostro file system la directory dell'overlay di Syncope; compilando con Maven questa directory, otterremo i file war di default di Syncope e della sua console; quello che inceve noi faremo, sarà creare, e poi sviluppare, all'interno di essa "i nostri" file che poi verranno ricompilati e inseriti nel war da deployare. In questo caso la root directory da me creata è sso.ad e questo è il suo contenuto:
ls -lrt sso.ad
totale 20
-rw-r--r-- 1 massi massi 4818 10 dic 15.20 pom.xml
drwxr-xr-x 4 massi massi 4096 9 gen 10.40 target
drwxr-xr-x 4 massi massi 4096 9 gen 10.40 core
drwxr-xr-x 4 massi massi 4096 9 gen 10.41 console
Senza addentrarci nel merito dell'installazione dell'agent, l'unica cosa da sottolinerare è che la sua installazione e configurazione non è stata fatta su tutto il Tomcat dove sarà deployato Syncope e la sua console. L'installazione e la configurazione dell'agent sono state fatte solamente sulla webapp della console di Syncope.
Come descritto precedentemente, essendo il nostro progetto di Syncope un overlay, l'unico modo che abbiamo per rendere le modifiche del web.xml permanenti è quello di inserire nell'overlay la nostra copia di web.xml con l'aggiunta del filtro dell'agent di OpenAM. Quindi all'interno della directory sso.ad andiamo a creare il file ./console/src/main/webapp/WEB-INF/web.xml al quale aggiungeremo le seguenti righe di codice relative al filtro dell'agent:
<filter>
<filter-name>Agent</filter-name>
<display-name>Agent</display-name>
<description>SJS Access Manager Tomcat Policy Agent Filter</description>
<filter-class>com.sun.identity.agents.filter.AmAgentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Agent</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Per eseguire questa operazione bisogna modificare il processo di autenticazione interno di Syncope; per ottenere questo, bisogna modificare sia il core che la console del software. Per ragioni di sicurezza la comunicazione tra la console e il core vengono effettuate con il protocollo https.
Il processo di autenticazione di Apache Syncope è basato su Spring Security e la basic authentication.
Nel nostro esempio, per velocizzare lo sviluppo del progetto, non si è deciso di togliere l'intero processo di autenticazione o di disabilitarlo, semplicemente si è modificata la classe che implementa org.springframework.security.authentication.AuthenticationProvider per fare in modo che la console risulti sempre autenticata sul core. Questo permette di mantenere inalterati i meccanismi alla base del funzionamento del core; un esempio su tutti la ricerca degli entitlements di un utente. Questa operazione viene effettuata attraverso il metodo getOwnedEntitlementNames della classe org.apache.syncope.core.util.EntitlementUtil:
public static Set<String> getOwnedEntitlementNames() {
final Set<String> result = new HashSet<String>();
final SecurityContext ctx = SecurityContextHolder.getContext();
if (ctx != null && ctx.getAuthentication() != null && ctx.getAuthentication().getAuthorities() != null) {
for (GrantedAuthority authority : ctx.getAuthentication().getAuthorities()) {
result.add(authority.getAuthority());
}
}
return result;
}
Il metodo ritrova l'utente connesso all'interno del security context di Spring. Questo processo può rimanere inalterato proprio per quanto spiegato precedentemente.
Quindi, andando ad analizzare nel dettaglio il codice della classe org.apache.syncope.core.security.SyncopeAuthenticationProvider si può notare come, semplicemente, sia stato modificato solo il codice per il match tra username e password dell'utente
Prima
if (adminUser.equals(username)) {
passwordUser.setPassword(authentication.getCredentials()
.toString(), CipherAlgorithm.MD5, 0);
authenticated = adminMD5Password.equalsIgnoreCase(
passwordUser.getPassword());
} else {
user = userDAO.find(username);
if (user != null) {
if (user.getSuspended()) {
throw new DisabledException(
"User " + user.getUsername() + " is suspended");
}
passwordUser.setPassword(authentication.getCredentials()
.toString(), user.getCipherAlgoritm(), 0);
authenticated = user.getPassword().equalsIgnoreCase(
passwordUser.getPassword());
}
}
Dopo
if (adminUser.equals(username)) {
authenticated = true;
} else {
user = userDAO.find(username);
if (user != null) {
if (user.getSuspended()) {
throw new DisabledException(
"User " + user.getUsername() + " is suspended");
}
authenticated = true;
}
}
Dopo la modifica, la variabile boolean Authenticated risulta sempre true.
In questo post, riuscendo ad avere anche in modo più chiara l'architettura che si vuole realizzare, si nota come Apache Syncope abbia la capacità di adattarsi, con un minimo sforzo, ad architetture pre-esistenti.
Lavorando ormai da diversi anni nell'ambito dello IAM, una delle difficoltà più grandi alle quali siamo stati quasi sempre chiamati ad adattarci è stato proprio il riuscire ad "inserire" all'interno di un'architettura esistente, un prodotto come un idendity manager che, di per sé, è un prodotto invasivo all'interno di una struttura di IT. Nel caso di questo esempio, che rispecchia fedelmente la struttura di una qualsiasi Intranet, bisogna adattare Apache Syncope a quanto già esistente, cioè un Active Directory che possiamo immaginare essere, a torto o ragione (non è questo l'argomento di discussione), il punto centrale dei profili aziendali.
Syncope, grazie alla sua customizzazione, può essere inserito in questo contesto in modo, PRATICAMENTE, indolore; dove il contesto di riferimento è ovviamente la soddisfazione del cliente finale che chiede: "Questo è quello che ho e non deve essere toccato; l'IDM dovrà fare quello che fanno tutte le altre applicazioni, cioè autenticarsi sull'Active Directory senza che quest'ultimo sia modificato di una virgola; e visto che ci siamo realizziamo anche il Single Sign On tra i due prodotti!"