Issuu on Google+

Integrazione di un software repository in un ambiente centralizzato di autenticazione

Università degli Studi di Ferrara Facoltà di Ingegneria Corso di Laurea in Ingegneria Informatica

INTEGRAZIONE DI UN SOFTWARE REPOSITORY IN UN AMBIENTE CENTRALIZZATO DI AUTENTICAZIONE

Tesi di Laurea di: MATTEO SERAFIN Relatore: Prof.ssa ELEONORA LUPPI Correlatore: Prof. ALBERTO GIANOLI

Anno Accademico 2007 - 2008 Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-1-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-2-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

INDICE GENERALE

CAPITOLO 1 - INTRODUZIONE...............................................................................................7 1.1 - Prefazione.........................................................................................................................7 1.2 - La strategia adottata..........................................................................................................8 CAPITOLO 2 - ANALISI E SPECIFICA DEI REQUISITI.......................................................11 2.1 - Dall'intervista alla stesura del documento.......................................................................11 2.2 - Apache Web Server.........................................................................................................13 2.2.1 - Una panoramica generale su Apache .....................................................................13 2.2.2 - I servizi web ...........................................................................................................14 2.2.3 - Installazione e file di configurazione ......................................................................14 2.2.4 - La gestione del servizio ..........................................................................................16 2.2.5 - La configurazione delle funzionalità di base ..........................................................17 2.2.6 - La gestione dei file di log .......................................................................................25 2.3 - PostgreSQL.....................................................................................................................26 2.3.1 - Introduzione............................................................................................................26 2.3.2 - Installazione di PostgreSQL....................................................................................26 2.3.3 - Un po' di storia su PostgreSQL...............................................................................27 2.3.4 - Fondamenti sull'architettura....................................................................................29 2.4 - OpenSSL.........................................................................................................................29 2.4.1 - Introduzione a OpenSSL.........................................................................................29 2.4.2 - Installazione di OpenSSL........................................................................................30 2.4.3 - Configurazione di OpenSSL:..................................................................................30 2.4.4 - Procedura per ottenere un certificato......................................................................31 2.4.5 - Creazione di un file di dati casuali..........................................................................31 2.4.6 - Chiave privata.........................................................................................................32 2.4.7 - Richiesta di certificazione.......................................................................................32 2.4.8 - Creazione di un certificato fittizio...........................................................................33 2.4.9 - Creazione del certificato per INFN.........................................................................34 2.4.10 - Cos'è X.509...........................................................................................................34 2.4.11 - Storia ed utilizzo ...................................................................................................34 2.4.12 - Certificati...............................................................................................................34 2.4.13 - Struttura di un certificato......................................................................................35 2.5 - Il pacchetto mod_ssl.......................................................................................................36 2.5.1 - L'installazione di mod_ssl.......................................................................................36 Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-3-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.5.2 - Cos'è mod_ssl.........................................................................................................36 2.6 - Stunnel............................................................................................................................37 2.6.1 - Cos'è Stunnel...........................................................................................................37 2.6.2 - Installazione di Stunnel...........................................................................................37 2.6.3 - Configurazione di Stunnel.......................................................................................38 2.6.4 - Informazioni di configurazione...............................................................................39 2.6.5 - La configurazione usata per Stunnel.......................................................................39 2.7 - PHP.................................................................................................................................40 2.7.1 - Installazione di PHP:...............................................................................................40 2.7.2 - Cos'è PHP................................................................................................................41 2.7.3 - Il file di configurazione PHP.ini..............................................................................42 2.7.4 - La configurazione adottata:.....................................................................................43 2.8 - Il pacchetto mod_dav_svn..............................................................................................52 2.9 - Cos'è Gforge?..................................................................................................................54 2.9.1 - Installazione di GForge...........................................................................................54 2.9.2 - Configurazione di GForge ......................................................................................55 2.9.3 - Configurazione del Database PostgreSQL..............................................................55 2.9.4 - Creazione del Database per Gforge.........................................................................57 2.9.5 - Creazione dell'utente gforge:...................................................................................57 2.9.6 - Configurazione di PHP per GForge........................................................................57 2.9.7 - Configurazione di Apache per Gforge....................................................................58 2.9.8 - Configurazione di PHP per Apache:.......................................................................58 2.9.9 - Creazione dell'utente Amministratore di GForge...................................................59 2.9.10 - Customizing home di Gforge................................................................................59 2.10 - OpenLDAP per testing di GFORGE.............................................................................60 2.10.1 - Cosa è OpenLDAP................................................................................................60 2.10.2 - Installazione di OpenLDAP..................................................................................60 2.10.3 - Configurazione del file slapd.conf........................................................................62 2.10.4 - Il comando LDAPADD ........................................................................................63 2.10.5 - Creare una Organizational Unit (OU) su LDAP....................................................64 2.10.6 - Creazione di un utente su LDAP...........................................................................64 2.10.7 - Il comando LDAPSEARCH.................................................................................64 2.10.8 - Il comando LDAPMODIFY.................................................................................65 2.10.9 - Il comando LDAPDELETE..................................................................................65 2.11 - Il demone slapd ...........................................................................................................65 2.11.1 - Creazione degli utenti di prova.............................................................................66 2.12 - Il plugin di GForge ldap-ext-auth.................................................................................66 2.12.1 - Cos'è il plugin ldap-ext-auth.................................................................................66 2.12.2 - Installazione del plugin:........................................................................................67 2.12.3 - Le modifiche al codice di GForge.........................................................................67 2.12.4 - GForge su LDAP di Mailman.fe.infn.it................................................................68 2.12.5 - Conclusione dell'installazione...............................................................................68 CAPITOLO 3 - INTEGRAZIONE DEL SOFTWARE...............................................................69 3.1 - Utilizzo del web server e creazione degli utenti di prova...............................................69 3.2 - Analisi e studio delle caratteristiche di GForge..............................................................70 Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-4-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

3.2.1 - Situazione dopo l'installazione del plugin ldapextauth...........................................72 3.2.2 - Le mancanze del pacchetto standard rispetto ai requisiti richiesti..........................77 3.3 - Le modifiche apportate...................................................................................................78 3.3.1 - Modifica del flusso di dati durante l'operazione di login. ......................................78 3.3.2 - La ricerca ricorsiva in LDAP...................................................................................83 3.3.3 - La ricerca ricorsiva per gli username degli utenti...................................................85 3.3.4 - Cambio password solo per LDAP...........................................................................86 3.3.5 - Riconoscimento di un utente con privilegi di admin in LDAP...............................88 3.3.6 - Modifica del campo mail per gli utenti:..................................................................90 3.3.7 - Eliminazione della possibilità di registrazione via web di nuovi utenti..................90 3.3.8 - Iscrizione degli utenti a nuovi progetti...................................................................91 CAPITOLO 4 - CONCLUSIONI..............................................................................................103 BIBLIOGRAFIA.......................................................................................................................105

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-5-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-6-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

CAPITOLO 1 - INTRODUZIONE

1.1 - Prefazione

Questo lavoro è un progetto che servirà all'Istituto Nazionale di Fisica Nucleare ed è stato richiesto dal Dipartimento INFN di Ferrara. I primi colloqui con la responsabile prof. Luppi sono cominciati a dicembre 2007. Il correlatore è stato il prof. Gianoli che si è rivelato anche un prezioso collaboratore per la riuscita del lavoro. Lo scopo di questo progetto consiste nell'ottenere un applicativo che funga da software repository in grado di gestire il ciclo di vita dello sviluppo di software integrato con un directory service. Questo sistema risulta fondamentale per una collaborazione scientifica che si trova nella situazione di dover sviluppare una notevole mole di software divisi in progetti diversi [1]. Questo applicativo è considerato uno strumento necessario per lo sviluppo di un nuovo esperimento di fisica delle particelle e a regime dovrà servire a una comunità stimata di 200 sviluppatori distribuiti in diversi Paesi e un migliaio di utilizzatori finali [2]. Vi è quindi la necessità di un pacchetto collaborativo per gestire le fasi di vita del software come sviluppo, test, rilascio aggiornamenti, ecc. Esistono sul mercato, anche opensource, applicativi come Cvs o Subversion ma mancano di molte funzionalità richieste come messaggistica, avviso release, interfaccia web e molto altro. E' di vitale importanza che questo servizio abbia la capacità di integrarsi con il servizio di directory LDAP per l'autenticazione degli utenti. Si è fatta una ricerca sugli applicativi che forniscono funzionalità il più vicino possibili alle esigenze elencate e si è scelto quindi di optare per il progetto GForge. GForge è un progetto molto più ampio di Cvs o SubVersion perché oltre ad essere un repository di software puro mette a disposizione anche altre caratteristiche come messaggistica e gestione delle varie release che, alla luce di quanto richiesto, è importante. Non è stato di certo trascurato il fatto che questo progetto sia opensource e venga rilasciato sotto licenza GPL. Per GForge esistono una moltitudine di plugin che forniscono le funzionalità più disparate e si è notato sin da subito che non esisteva ancora un plugin che ottimizzasse le richieste e le necessità che si avevano. Nonostante una abbondante sezione del progetto GForge riguardasse proprio l'integrazione tra il front end e il servizio di directory, nessuno di questi era compatibile con l'analisi dei requisiti che si era affrontata. GForge nella configurazione standard usa pesantemente, per la gestione del codice condiviso e degli utenti, il proprio database che può essere MySQL o PostgreSQL. I plugin di GForge rilasciati per integrarsi con LDAP invece danno la possibilità di gestire tutto ciò interamente con quest'ultimo servizio di directory. Questa soluzione era si funzionante ma non funzionale per i nostri scopi e quindi inaccettabile. L'utilizzo dell'albero LDAP sarebbe stato altamente invasivo poichè lo si sarebbe caricato di troppe informazioni che non avrebbero riguardato strettamente gli utenti presenti. Inoltre LDAP viene utilizzato dal Dipartimento INFN per qualsiasi operazione che necessita di autenticazione come posta, accesso ai vari servizi, ecc. Quindi il volere inserire in questo albero troppe informazioni, che comunque avrebbero riguardato solo una parte di utenti dedita al servizio GForge, non è parsa

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-7-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

subito una strada percorribile. Si è scelto quindi di percorrere una via alternativa: una via che la si può definire mista. Si è cercato di lasciare divise, per quanto possibile, le informazioni relative all'autenticazione e quelle relative alla gestione e allo sviluppo di software condiviso. Si è cercato quindi di ragionare sui dati e non sugli utenti, cosa che è parsa più logica. Il flusso di dati utilizzato da GForge è stato così analizzato ed è stato diviso logicamente: le informazioni relative all'autenticazione vengono gestite da LDAP, le informazioni relative e proprie di GForge invece vengono gestite dal database opportunamente creato in PostgreSQL. L'autorizzazione viene in questo modo gestita dal database di supporto di GForge salvo il ruolo di admin che viene gestito direttamente da un ruolo di LDAP. Questa soluzione è risultata fin da subito valida anche perché il sistema di autenticazione è già attivo e funzionante. Quindi il dover ricreare un sistema di autenticazione con la necessità di dover reinserire tutti gli utenti con conseguente duplicazione e ridondanza dei dati non sarebbe stata di certo una buona idea. Inoltre in fase di analisi si è dato rilevanza al fatto che in questo sistema ci dovevano essere minimi cambiamenti onde evitare malfuzionamenti e/o blackout del servizio, anche se temporanei. Questa soluzione mista ha garantito l'assenza di questo tipo di inconveniente, grazie al fatto che le modifiche sui sistemi preesistenti, che venivano utilizzati quotidianamente da altri utenti, sono state praticamente nulle. Inoltre, a regime, qualsiasi utente ha avuto la possibilità di utilizzare le proprie credenziali per accedere e per utilizzare il front end di GForge senza nessuna variazione sul sistema di directory LDAP. Solo per gli utenti admin si è reso necessario introdurre uno speciale campo per effettuare correttamente la query di login come admin del sistema. Inoltre l'installazione standard di GForge prevedeva l'obbligo da parte degli utenti al primo utilizzo di registrarsi sul sito. Non era infatti prevista la possibilità di importare in una qualche maniera gli utenti preesistenti per farli accedere al nuovo servizio. Il fatto di utilizzare LDAP come unico punto di autenticazione e autorizzazione per gli admin ha eliminato questo obbligo e ha dato questa possibilità. Così tutti gli utenti già presenti in LDAP anche al primo utilizzo non hanno dovuto effettuare alcuna registrazione e hanno potuto accedere al sistema come se ne avessero sempre fatto parte. Le difficoltà di questo progetto, oltre a quelle inerenti agli strumenti applicativi alcuni nuovi, altri meno, con cui si è lavorato sono state soprattutto legate al fatto che la documentazione praticamente non esisteva. Soprattutto per quanto riguardava la struttura del database che viene utilizzato non esistevano manuali o schemi. Anche il flusso dei dati era sconosciuto, quindi per prima cosa dopo aver installato il necessario si è dovuto analizzare effettuando una operazione di reengineering del software esistente e poi di engineering del software modificato. In molti casi si è proceduto quasi ad occhi chiusi soprattutto per quanto riguardava il plugin di autenticazione di LDAP. Questo plugin è stato sviluppato da terze parti rispetto a GForge e durante il suo sviluppo non si sono certamente seguiti i crismi di ingegnerizzazione del software. Anche alla prima lettura il codice è apparso confuso, non funzionale e poco auto esplicativo anche se sicuramente funzionante. Inoltre la parte di GForge relativa all'interazione con i vari database è sviluppata a layer ed è infatti facile e comodo passare da MySQL a PostgreSQL senza intoppi. La parte relativa all'autenticazione invece non segue questi crismi e, le chiamate, sono sparse per il codice. Il voler cambiare questa parte significa intervenire in profondità nel codice stesso. Quindi l'opera di analisi e di modifica è stata davvero complessa.

1.2 - La strategia adottata. La strategia adottata è stata quella, sia per un questione di praticità, sia per una questione di sicurezza, di ricreare il sistema finale in locale. Quindi il primo passo dell'installazione è stato quello di installare Apache e di configurarlo. Anche per LDAP si è scelto di installarlo localmente per capirne meglio il funzionamento e poter aver un terreno di prova senza incorrere nel pericolo di creare danni al sistema reale. Non ci si è quindi, almeno per la fase iniziale, appoggiati sul server LDAP di INFN, bensì su una versione simile locale. In locale si è usato quindi OpenLDAP come banco di prova del sistema e degli utenti. Alla fine, quando il sistema è stato completamente creato e configurato in maniera ottimale si è proceduto a testare il sistema, sempre locale, con l'albero LDAP usato da INFN. Verificato che questa configurazione non avesse problemi si è poi proceduto a migrare il pacchetto creato dalla versione locale alla versione esterna e resa quindi accessibile e utilizzabile da tutti gli utenti di INFN. Questa parte Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-8-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

relativa alla migrazione non è contemplata in queste pagine in quanto di facile esecuzione e non relativa ai fini dell'esperienza. Il progetto in esame è quindi cominciato con l'analisi dei requisiti.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

-9-


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 10 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

CAPITOLO 2 - ANALISI E SPECIFICA DEI REQUISITI

2.1 - Dall'intervista alla stesura del documento

La prima fase del progetto è stata l'analisi dei requisiti. In ingegneria del software, l'analisi dei requisiti rappresenta una delle prime fasi nel ciclo di vita di un prodotto software. Questa fase ha l'obiettivo principale di stabilire che cosa il sistema deve fare. L'analisi dei requisiti è stata sviluppata in particolare con il Professor Gianoli correlatore del lavoro. Dopo vari incontri durante i quali si è cercato di capire il più possibile riguardo le esigenze che aveva il Dipartimento di INFN, si è passati alla stesura dei requisiti: 1.

Creare un front end in grado di gestire il ciclo di vita di più software attraverso la condivisione tra più utenti dello stesso. 2. Creazione di un repository del codice elaborato e condiviso. 3. Il front end deve fornire agli utenti un servizio di messaggistica, avviso release, interfaccia web 4. Ove possibile si andrà a utilizzare o riutilizzare servizi già attivi e preesistenti. Il front end in questione andrà installato su macchine UNIX preesistenti. 5. E' necessario che il sistema tenga traccia delle varie modifiche apportate e delle release intermedie rilasciate. 6. Il sistema deve essere in grado di autenticare e autorizzare gli utenti tramite ruoli 7. L'autenticazione e l'autorizzazione per gli utenti admin deve essere gestita dal servizio LDAP che per INFN è già funzionante.L'autorizzazione per tutti gli altri utenti può essere gestita anche esternamente da LDAP. 8. L'albero LDAP non deve essere modificato salvo eventuali variazioni strettamente necessarie. Questo vincolo è stato introdotto per evitare eventuali problemi agli utenti che utilizzano quotidianamente per altri servizi e per evitare un sovraccarico di informazioni non necessarie all'autorizzazione. 9. Gli utenti devono utilizzare il proprio username e password già presenti in LDAP. 10. Gli utenti, se possibile, non devono effettuare alcuna procedura di registrazione nella fase iniziale di utilizzo del frontend ma devono semplicemente loggarsi nel server web. Il sistema deve essere in grado di gestire autonomanente i nuovi utenti e gli utenti già registrati in maniera del tutto trasparente per gli stessi.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 11 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Altri requisiti aggiunti work in progress 11. Se la password o il nome utente vengono eventualmente modificati in LDAP, queste modifiche devono valere anche per GForge. Quindi è preferibile avere un unico punto di accesso per l'autenticazione. 12. Il sistema deve essere in grado di gestire in automatico lo status di “admin” di un utente solamente leggendolo da un ruolo indicato in LDAP. 13. L'utente può cambiare la propria password all'interno del sistema e questa modifica deve influire anche su LDAP. 14. L'utente non può cambiare la propria mail. 15. La ricerca di utente all'interno dell'albero LDAP deve essere di tipo ricorsivo. Dopo aver steso questa breve specifica dei requisiti si è cominciato a cercare se e quali prodotti software con caratteristiche simili fossero già presenti sul mercato. Si è visto che il progetto rilasciato sotto licenza GPL chiamato GForge rispecchiava parecchi punti dell'analisi. Le alternative a GForge erano applicativi come CVS o SubVersion ma questi erano più limitativi rispetto al primo in quanto viene fornito principalmente il solo servizio di repository del codice. Con GForge invece viene data la possibilità di gestire anche la community di utenti e sviluppatori che vogliono aderire attraverso servizi come messaggistica, forum, avvisi di rilascio release e molto altro. Da qui la volontà di usufruire di GForge come core del sistema. GForge è un servizio ormai consolidato e robusto con un miriade di utenti che lo stanno già utilizzando e testando. Il problema che fin da subito è parso importante è quello di riuscire a far integrare questo servizio con LDAP. Inoltre se non si voleva sovraccaricare LDAP di informazioni estranee all'autenticazione e all'autorizzazione il pacchetto così fornito non rispecchiava l'analisi dei requisiti stilata. In ogni caso si è scoperto che per GForge sono stati implementati e rilasciati diversi plugin dalla community di sviluppatori, alcuni dei quali presumevano una integrazione dello stesso con LDAP. Dalle prime letture dei forum, soprattutto quello ufficiale relativo ai problemi, si è però subito capito che così come è stato rilasciato non faceva al caso nostro [3]. Infatti tutta le gestione e le informazioni relative al codice sviluppato concorrentemente dagli utenti andava ad incidere pesantemente sull'albero. In pratica con questo plugin tutte le informazioni non venivano più inserite nel database creato in MySQL o PostgreSQL bensì nell'albero LDAP, solo il codice scritto veniva inserito nel database di supporto. Concettualmente e logicamente questa caratteristica è in contrasto con il servizio che fornisce e deve fornire LDAP che non è un database ma è un servizio di directory. Quindi è, a livello logico, non condivisibile il voler inserire nell'albero LDAP informazioni relative alla condivisione e al repository del codice con servizi annessi. Il plugin di GForge per interfacciarsi con LDAP andava infatti ad inserire informazioni e dati quali la messaggistica, i forum e la partecipazione ai vari progetti nell'albero stesso. Questo non è ammissibile poichè la funzione principale di LDAP è quella di fornire un servizio di autorizzazione. Inoltre anche volendo in ogni caso percorrere questa strada, logicamente non corretta, non si è trovato alcun documenti .ldif che indicasse cosa il sistema GForge si aspetti dall'albero di supporto a livello di struttura. Con queste caratteristiche questo plugin così rilasciato non è risultato utilizzabile poichè contravviene alla richiesta espressa in fase di analisi dei requisiti di variare il meno possibile l'albero LDAP. Si è così pensato di praticare una terza via che rappresenta una soluzione mista rispetto alle due praticate da GForge ma che rispetta la specifica dei requisiti. Si sono così analizzati i dati che venivano gestiti da GForge: quelli relativi alla condivisione del codice sono stati trattati dal database PostgreSQL così come viene fatto dall'installazione originaria. I soli dati relativi invece all'autenticazione e all'autorizzazione degli utenti admin sono gestiti nell'albero LDAP, in quanto già presenti al suo interno, come indicato in figura 1. Con questa soluzione si sono evitati così problemi di ridondanza e di replica dei dati. L'autenticazione per tutti gli altri utenti del sistema avviene come per la configurazione standard attraverso il database di appoggio. A questo punto, dopo aver scelto GForge come base del nostro sistema, manca solo una scelta da effettuare. GForge necessita di un database di appoggio come accennato precedentemente per poter funzionare. Gli sviluppatori hanno lasciato due strade aperte: PostgreSQL e MySQL. Entrambi i DBMS possono andare bene in quanto opensource e compatibili con l'ambiente UNIX senza problemi. La scelta è ricaduta su PostgreSQL in quanto nel sistema nel quale verrà poi installato e reso funzionante vi è già una installazione attiva. Per questo motivo la scelta di PostgreSQL è sembrata la scelta più logica.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 12 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 1: I dati necessari a GForge vengono così distribuiti in LDAP e in PostgreSQL Ora si andrà a descrivere la procedura di installazione del sistema e le configurazioni adottate per crearlo. Sempre per rispettare il concetto di riutilizzare servizi già attivi e presenti, nel sistema finale si vuole usufruire del server web Apache già presente. Nel seguito si andrà a descriverne comunque l'installazione da zero dello stesso Apache in quanto questa operazione nella configurazione in locale è stata comunque effettuata. Si è partiti dall'installazione del Server Web Apache.

2.2 - Apache Web Server Apache è il nome dato alla piattaforma server Web più diffusa, in grado di operare da sistemi operativi UNIXLinux e Microsoft. Apache è un software che realizza le funzioni di trasporto delle informazioni, di internetwork e di collegamento, ha il vantaggio di offrire anche funzioni di controllo per la sicurezza come quelli che compie il proxy. Il progetto Apache nacque nel 1995. A quel tempo, il server Web più diffuso era il daemon HTTP pubblico sviluppato da Rob McCool al NCSA (National Center for Supercomputing Application), Università dell'Illinois. Dal momento però che a partire dal 1994 lo sviluppo di questo server. Il team di sviluppo di Apache ha iniziato a sviluppare patch in maniera autonoma e prese come punto di partenza la versione 1.3 del demone HTTP e aggiunsero una serie di patch e di correzioni. La prima release pubblica di Apache, la 0.6.2, venne rilasciata nell'aprile del 1995. Il nome Apache, nasce dal fatto che inizialmente il server era semplicemente una raccolta di patch da applicare al server NCSA. Dal nome amichevole "a patchy server" nacque quindi Apache. Una nuova architettura server fu integrata poco dopo nella versione 0.8.8 a cui fu dato il nome in codice di Shambala. La versione 1.0 fu pubblicata l'1 dicembre 1995. Nel giro di un anno, la sua diffusione aveva già superato quella del server NCSA da cui era derivato. La versione 2.0 di Apache venne rilasciata durante la conferenza ApacheCon, tenutasi nel marzo 2000 a Orlando, in Florida. Operativamente, è composto da un demone, in ambiente UNIX, o da un servizio, in ambiente Microsoft, che sulla base delle impostazioni contenute nel file di configurazione httpd.conf permette l'accesso a un o più siti, gestendo varie caratteristiche di sicurezza e potendo ospitare diverse estensioni per pagine attive (o dinamiche), come PHP o Jakarta/Tomcat.

2.2.1 -

Una panoramica generale su Apache

Apache è un server web potente e flessibile, pienamente conforme ad HTTP/1.1; la sua struttura modulare lo rende altamente configurabile e estendibile. Inoltre è estremamente portabile ed è disponibile per Windows, Netware, OS/2 e su quasi tutte le piattaforme UNIX, compreso ovviamente GNU/Linux. Tra le tante caratteristiche un breve elenco delle più rilevanti è il seguente:

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 13 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

1. 2. 3. 4. 5. 6. 7.

permette di avere pagine ad accesso autenticato con diversi meccanismi. consente i server side include. consente l’utilizzo dei CGI. permette di gestire infiniti alias e infinite regole di rewrite. permette la negoziazione dei contenuti in base alle capacità del client. ha un supporto completo per i domini virtuali é altamente configurabile per quanto riguarda la gestione dei file di log.

Nella situazione attuale il progetto Apache mantiene stabilmente tre diverse versioni del server. La più diffusa come dispiegamento sul campo resta la versione 1.3, che anche se classificata come “legacy”, viene mantenuta mente per la correzione dei bug. Dato che comunque si tratta di una versione stabilissima e molto completa, questa versione è disponibile in molte distribuzioni. La versione da utilizzare in prevalenza nelle nuove installazioni è invece la 2.0, che è stata completamente rinnovata nella sua architettura. In particolare è stato introdotto l’uso dei thread che ne migliora notevolmente le prestazioni sotto Windows (ed in certe condizioni anche con Linux), e sono stati introdotti molti cambiamenti anche nelle configurazioni e nuove funzionalità [4].

2.2.2 -

I servizi web

La versione stabile più recente è la 2.2, che però è stata rilasciata da poco, questa versione non viene utilizzata da nessuna delle principali distribuzioni dato che pur essendo dichiarate stabile (ed essendolo per le funzionalità di base), non altrettanto vale per tutte le estensioni ed i moduli che in realtà vanno a costituire la gran parte delle funzionalità evolute di Apache. Questa ultima versione introduce cambiamenti molto più ridotti rispetto alla 2.0, ed alcune nuove funzionalità. Gran parte della sintassi delle direttive di configurazione è sostanzialmente identica per tutte le versioni citate, ma ci sono alcune differenze dovute ad i cambiamenti introdotti.

2.2.3 -

Installazione e file di configurazione

Essendo uno dei pacchetti di software libero di uso più comune Apache è presente praticamente in tutte le distribuzioni, per cui in genere tutto quello che c'è da fare è utilizzare il sistema di gestione dei pacchetti della propria distribuzione e richiederne l’installazione (sempre che questa non sia già stata eseguita di default). Nel caso in esame infatti, dovo aver lanciato yumex e e ricercato il pacchetto, si è visto che questo era già presente nel nostro sistema, come indicato in figura 2.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 14 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 2: Il server Apache httpd risulta già installato - Il server Apache httpd risulta già installato -Per Apache 2.0 il progetto è passato all’uso estensivo degli Autotools del progetto GNU; per cui è disponibile solo la procedura standard, e la configurazione dettagliata viene fatta attraverso le opzioni passate allo script di configurazione configure. In questo caso la directory di installazione viene passata attraverso l’opzione --prefix, mentre i vari moduli delle estensioni vengono abilitati da una serie di direttive --enable-modulename, dove modulename è il nome del rispettivo modulo. In questo modo il codice del modulo sarà compilato staticamente ed inglobato direttamente nel binario del server, se si vuole che un modulo sia compilato come libreria dinamica per consentirne il caricamento a richiesta, si dovrà specificarlo passando all’opzione il parametro shared. Un esempio di configurazione che usa questa opzione è: ./configure --prefix=/opt/apache --enable-rewrite=shared

Qualora invece si vogliano disabilitare alcuni dei moduli che sono preimpostati di default, si può utilizzare la corrispondente direttiva --disable-modulename. La più grossa innovazione di Apache 2.0 rispetto alla precedente versione 1.3 è stata l’introduzione dei cosiddetti MPM (Multi-Processing Modules), che portano la modularizzazione del sistema fino alle funzionalità più elementari del server, consentendo di ottimizzarne il funzionamento rispetto a diverse possibili condizioni di lavoro o all’installazione su diversi tipi di sistemi operativi. Modulo MPM e sua descrizione: prefork realizza il modello classico di Apache 1.3, basato sull’uso dei processi. worker nuovo modulo ottimizzato per le prestazioni basato sull’uso dei thread. perchild consente di assegnare a utenti diversi i vari processi del server. threadpool una variante sperimentale del modulo worker. leader un’altra variante sperimentale del modulo worker. mpm_winnt modulo ottimizzato per Windows NT. Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 15 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

In questo caso si tratta in sostanza di scegliere che “tipo” di server utilizzare fra le diverse possibilità fornite dai vari MPM, per cui al contrario dei moduli delle estensioni, è possibile compilare Apache scegliendo un solo MPM alla volta. Questo viene fatto passando allo script configure l’opzione --with-mpm=name, dove name indica il nome dell’MPM scelto. Un elenco di quelli disponibili è riportato precedentemente; se non se ne specifica nessuno viene utilizzato come default prefork, che realizza un server analogo al modello classico usato da Apache 1.3. Questa è la scelta fatta nel nostro progetto. In generale si sceglie il modulo prefork quando si vuole privilegiare la massima stabilità e compatibilità con le funzionalità presenti in Apache 1.3, mentre si usa worker quando si vogliono il massimo delle prestazioni e della scalabilità. Una volta installato il server il suo comportamento è controllato da un file di configurazione principale. In origine i file di configurazione di Apache erano tre: httpd.conf per la configurazione del server, access.conf per la gestione degli accessi e srm.conf per la gestione dei tipi di file e documenti. Dalla versione 1.3 si fa riferimento ad un unico file di configurazione httpd.conf, dal quale è comunque possibile includere altri file con la direttiva Include. Nel nostro caso è sotto /etc/httpd. Lo stesso file può essere usato anche per Apache 2.0, ma in questo caso viene installato sotto /etc/apache2.

2.2.4 -

La gestione del servizio

Di norma, per non penalizzarne le prestazioni, il server Apache viene lanciato direttamente, e non si ricorre ad inetd come intermediario. La situazione normale pertanto prevede l’utilizzo di un opportuno script di avvio del servizio che prende gli usuali parametri utilizzati dal sistema di inizializzazione di System V. Il programma può comunque anche essere eseguito direttamente; a seconda delle distribuzioni lo si può lanciare con httpd o direttamente come apache. Per lanciare il servizio quindi viene usato: service httpd start

Al suo avvio Apache legge il file di configurazione, apre i file di log, si pone in ascolto sulla porta 80 (porta di default) e poi fa partire un certo numero di processi in attesa di richieste. In questo modo solo il processo iniziale ha i diritti di amministratore, mentre i processi che rispondono alle richieste girano con i privilegi dell’utente specificato in sede di configurazione. -d imposta la directory radice del server (viene sovrascritto dal valore della direttiva ServerRoot). -D definisce un parametro di configurazione. -f imposta un file di configurazione alternativo a quelle od default. -h stampa una schermata di aiuto con breve sommario delle opzioni. -l stampa una lista dei moduli compilati all’interno del server. -L stampa una lista delle direttive di configurazioni disponibili con i moduli compilati nel server. -S esegue la scansione dei Virtual Host. -t esegue un controllo della sintassi del file di configurazione. -T identico a -t ma non controlla le directory dei documenti. -X esegue il server in modalità interattiva, il server non si stacca dal terminale e non esegue figli. -V stampa i parametri con cui si è compilato il server. -v stampa la versione del server. - Il significato delle diverse opzioni di Apache -

In genere l’invocazione diretta del comando viene fatta solo a scopo di test; in questo caso con l’opzione -X lo si può fare eseguire in modalità interattiva e senza l’esecuzione di processi figli, in modo da avere tutti i risultati stampati sul terminale corrente; con -f inoltre si può indicare un file di configurazione alternativo rispetto a quello di default. Con -t, si effettua un controllo sulla sintassi della configurazione mentre -T esegue lo stesso controllo senza però verificare la Document Root. Il controllo è puramente formale, e non assicura nulla sulla validità della configurazione. L’opzione -S permette di eseguire una scansione della configurazione per elencare i Virtual Host, in essa presenti. Infine con -V si potranno stampare a video i parametri con cui si è compilato il server, il comando è:

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 16 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

httpd -v Server version: Apache/2.2.3 Server built: Jan 16 2008 09:39:56 - Output del comando httpd -

Oltre all’invocazione diretta del comando o all’uso dello script di avvio, il pacchetto di Apache fornisce un programma di controllo apposito, apachectl, che permette di gestire, a server avviato, le varie operazioni. start: Avvia il servizio. stop: Ferma il servizio. restart: Avvia il servizio se non attivo, altrimenti causa la rilettura della configurazione con l’invio di un SIGHUP. status: Stampa un breve rapporto sullo stato del server. Richiede la presenza del browser testuale lynx e l’attivazione di mod_status. fullstatus: Stampa un rapporto più esteso sullo stato del server. Richiede la presenza del browser testuale lynx e l’attivazione di mod_status. graceful: Riavvia il servizio attendendo la conclusione di tutte le connessioni pendenti. configtest: Esegue un controllo della configurazione. Si tenga conto che viene solo controllata la sintassi formale. - Significato dei comandi di controllo disponibili con apachectl -

In genere il comando si usa per avviare e fermare il server ma rispetto all’invocazione diretta fornisce alcune funzionalità ulteriori, permettendo ad esempio di riavviare il server completando prima di fermarlo le connessioni sospese o controllando preventivamente la configurazione. L’elenco dei comandi di controllo da passare al programma si ottiene con direttamente con apachectl help

2.2.5 -

La configurazione delle funzionalità di base

Verranno esaminate in maggiore profondità in questa sezione la configurazione delle funzionalità di base di Apache, trattando in dettaglio il formato del file di configurazione ed esaminando le direttive usate per controllare le principali caratteristiche del server ed alcune delle funzionalità utilizzate più comunemente. La sintassi del file di configurazione di Apache è leggermente più complessa rispetto a quella di un normale file di configurazione, il programma infatti supporta diversi tipi di direttive. La prima classificazione è fra direttive “semplici ” ed i cosiddetti container. Una direttiva semplice ha una forma del tipo: DirettivaSemplice1 valore DirettivaSemplice2 valore2 altrovalore2

e consiste in una riga in cui si specifica il nome della direttiva, a cui seguono, separati da uno o più spazi, uno o più valori; se una riga non è sufficiente si può utilizzare come ultimo carattere della stessa un “\” per proseguire la lista dei valori sulla successiva. I nomi delle direttive sono case insensitive, ma vengono usualmente scritti, per aumentarne la leggibilità, nel cosiddetto camel case, seguendo la convenzione in cui le singole parole che compongono il nome sono scritte in maiuscolo, come nell’esempio precedente; i parametri delle direttive invece sono spesso case sensitive. Come accennato oltre alle direttive semplici esistono i cosiddetti container che sono delle direttive speciali che permettono di definire dei “contenitori” per delle altre direttive, in modo che sia possibile applicare queste ultime ad una classe di oggetti nel suo insieme; in tal caso la sintassi cambia ed assume una forma simile all’HTML con qualcosa del tipo: <DirettivaContenitore argomento> SottoDirettiva1 valore1 SottoDirettiva2 valore2 SottoDirettiva3 valore3 altrovalore3 </DirettivaContenitore>

si ha un marcatore per segnare l’inizio del contenitore ed un altro per chiuderlo, ed all’interno una serie di direttive normali che si applicano agli oggetti identificati dallo stesso. Infine le righe vuote, e quelle inizianti per “#”, che sono considerate commenti, vengono ignorate. Le direttive semplici poi vengono a loro volta suddivise in tre categorie, quelle generali (o server-level ), che controllano le caratteristiche del server in quanto tale, e che pertanto possono essere usate soltanto nella configurazione generica dello stesso; quelle locali che specificano funzionalità Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 17 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

che hanno senso solo all’interno degli oggetti raccolti in un container (non avendo significato per il server in quanto tale) e quelle locali e globali che se specificate in un container si applicano solo agli oggetti cui questo fa riferimento, mentre al di fuori assumono il significato di valore di default usato dal server. Nella tabella sotto si sono elencate le direttive standard che definiscono dei container. Si ricordi che ciascuna di essa prende un argomento che definisce gli oggetti a cui le regole inserite all’interno del container verranno applicate. Si tenga presente inoltre che alcune di queste direttive possono essere annidate una all’interno dell’altra. Directory: definisce una directory ed il sottostante ramo dell’albero dei file cui si applicano le direttive specificate; prende come argomento il pathname della directory in questione (ad esempio /var/www/gapil) ed accetta anche i caratteri jolly del filename globbing. DirectoryMatch: analoga alla precedente,26 ma permette di specificare un insieme di directory attraverso una espressione regolare (ad esempio con qualcosa come /var/www/www.*. (com|it)). Files: simile a directory, ma serve a selezionare dei file; anche in questo caso accetta come argomento una stringa con i caratteri jolly del filename globbing. FilesMatch: analogo al precedente ma permette di specificare un insieme di file usando una espressione regolare. Location: definisce un insieme di risorse cui applicare le direttive; è simile a Directory, ma opera nello spazio dei nome delle URI richieste dal client, che non è assolutamente detto debbano corrispondere ad un qualche file presente su disco; in questo caso l’argomento specifica una sezione in forma di pathname, e supporta l’uso dei caratteri jolly. LocationMatch: analoga a Location ma permette l’uso di espressioni regolari per la selezione. VirtualHost: definisce un dominio virtuale. Limit: permette di restringere l’effetto delle direttive di controllo di accesso ai soli metodi HTTP citati nella lista passata come argomento. LimitExcept: permette di restringere l’effetto delle direttive di controllo di accesso ai metodi HTTP che non rientrano nella lista specificata come argomento. - Le direttive che definiscono i container nella configurazione di Apache -

Oltre a quelle nella tabella qui sopra esistono altre due direttive che seguono la sintassi dei marcatori come quelle dei container, che vengono trattate a parte in quanto esse non servono affatto a definire dei contenitori per altre direttive quanto piuttosto a permettere di gestire in maniera più flessibile la configurazione attraverso l’uso di blocchi condizionali che attivano o disattivano delle funzionalità. Queste sono valutate solo all’avvio del server. La prima di queste direttive è IfModule, che consente di eseguire le regole di configurazione inserite al suo interno qualora il modulo da essa specificato sia attivo. Dato che molti moduli implementano delle funzionalità controllate da direttive specifiche che sono riconosciute dal server solo quando il modulo è attivo, l’uso di IfModule consente di utilizzare lo stesso file di configurazione anche se il modulo non è attivo, mantenendo all’interno di un blocco condizionale tutte le direttive di configurazione relative al modulo stesso, che così che se esso non è attivo non saranno considerate e non daranno errori. La direttiva prende come argomento il nome del modulo indicato dal nome del file che ne contiene il codice, così come specificato nelle direttive AddModule nella configurazione della compilazione del server o come indicato nell’output del comando con l’opzione -l. Un esempio di questa direttiva condizionale è il seguente: <IfModule mod_status.c> ExtendedStatus On </IfModule>

La seconda direttiva è <IfDefine>, che è più propriamente utilizzata per realizzare delle configurazioni con sezioni opzionali; essa utilizza i valori dei parametri di configurazione che vengono passati al server sulla riga di comando con l’opzione -D , pertanto si potranno inserire nella configurazione delle sezioni come: <IfDefine DEBUG> LogLevel debug </IfDefine>

che saranno utilizzate solo qualora si sia avviato il server con un comando del tipo di apache -D DEBUG.

Infine c’é una direttiva specifica, Include, che attiene direttamente alla gestione dei file di configurazione, consentendo di utilizzare il contenuto di altri file all’interno di un file di configurazione. In questo modo diventa possibile suddividere la configurazione delle varie funzionalità in parti diverse, distribuendole su file diversi, in Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 18 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

maniera da facilitarne la gestione. La direttiva prende come argomento il nome di un file, il cui contenuto sarà letto come se fosse stato scritto al posto della direttiva. Si possono anche specificare gruppi di file utilizzando la sintassi dei caratteri jolly della shell, nel qual caso saranno inclusi nell’ordine di corrispondenza. Come esempio di uso della direttiva si considera il seguente estratto, preso dalla configurazione eseguita: Include /etc/apache/conf.d

In generale quello che si deve fare per una configurazione di base di un sito gestito da Apache è impostare alcuni parametri fondamentali e cioé: 1. 2. 3. 4. 5.

la porta, ed eventualmente l’indirizzo IP (se se ne usa più di uno) su cui mettere in ascolto il server. l’utente ed il gruppo con cui eseguire i processi del server. il nome a dominio con cui si contatta il server (se ci sono più domini si dovranno usare i Virtual Host). la directory contenente le pagine HTML e le altre risorse messe a disposizione del server. l’indirizzo di posta dell’amministratore del server (questo non è obbligatorio ma è sempre bene definirlo).

Apache 2.0 utilizza la direttiva Listen che permette di indicare in soluzione unica sia l’indirizzo che la porta. Specificando solo un numero si seleziona solo la porta, mettendosi in ascolto su tutti gli indirizzi. La forma generica è però quella in cui si può specificare un indirizzo IP specifico insieme alla porta, con un argomento nella forma “indirizzo:porta”. Oltre alle direttive precedenti, necessarie per mettere in ascolto il server sulla rete, ci sono altre direttive di base che vengono usate per impostare il funzionamento del server a livello generale, come quelle che permettono di specificare la collocazione dei vari file di cui il server ha bisogno o l’utente ed il gruppo per conto del quale vengono eseguiti i processi. Queste direttive non si andrà a descriverle poichè nel progetto in esame sono state lasciate ai valori di default. Un terzo gruppo di direttive è quello che riguarda le modalità di uso della rete, che consentono di impostare l’indirizzo e la porta su cui il server si pone in ascolto; queste altre direttive invece permettono di impostare altre caratteristiche del comportamento del server sulla rete; a differenza delle precedenti oltre che a livello generale possono essere usate anche a livello di singolo dominio virtuale. Anche queste impostazioni non vengono descritte in quanto lasciate ai valori di default. Il server inoltre è in grado di aumentare e diminuire a seconda del carico il numero di questi processi, e anche queste funzionalità sono controllate da direttive di questo gruppo. Le direttive sono disponibili solo nel caso si stia usando l’MPM prefork e pertanto sono usualmente protette da una appropriata direttiva condizionale di tipo IfModule. L’elenco delle piu significative è il seguente: MaxClients: indica il numero massimo di richieste contemporanee che il server può soddisfare, significa in pratica che il server non metterà mai in esecuzione più processi del numero specificato da questa direttiva (il default è 256, ma tutte le distribuzioni usano un valore inferiore, ad esempio 150). Tutte le richieste che eccedono questo limite vengono accodate (si veda la successiva ListenBacklog) e saranno esaudite non appena uno dei processi del server diventa disponibile. Il valore da assegnare dipende in sostanza dalla quantità di RAM disponibile, un valore troppo alto infatti può esaurire la RAM causando l’uso della swap, peggiorando così terribilmente le tutte prestazioni del server (che sarà impegnato a spostare dati da e verso il disco, invece che a inviarli sulla rete). Questa situazione deve essere assolutamente evitata; se ci sono troppe richieste rispetto al numero dei processi è preferibile farle accodare, in modo da avere comunque il server impegnato nell’invio dei dati sulla rete per quelle che è in grado di gestire. Si può calcolare un valore ragionevole per questo parametro andando a dividere la RAM totale per la dimensione media dei processi di Apache (da esaminare con un qualunque programma come top). StartServers: indica il numero di processi figli che vengono lanciati all’avvio, il valore di default è 5, e dato che il numero dei processi viene aggiustato dinamicamente (aumentando se ci sono molte richieste) non ci sono motivi significativi per modificarlo, se non quella, qualora si abbia già un’idea del carico e questo sia molto più alto, di evitare di perdere tempo nel periodo iniziale di aggiustamento dopo l’avvio del server. MinSpareServers: indica il numero minimo di processi in più rispetto a quelli già attivi che devono restare fermi in attesa di connessione; quando il numero corrente è inferiore a questo limite il server inizia a creare nuovi processi (così da poterli utilizzare per una risposta immediata). Il valore di default è 5, in genere non è necessario modificarlo, se non per siti molto trafficati con rapide variazioni nei picchi di traffico. Un valore molto alto è sempre sconsigliabile (si tiene occupata inutilmente della memoria). Originariamente questo avveniva ad una frequenza massima di uno al secondo, con siti con molto traffico (e

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 19 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

molte connessioni simultanee) questo poteva comportare tempi di reazione all’avvio del server piuttosto lenti, per risolvere il problema, il numero di nuovi processi creati viene raddoppiato tutte le volte che la creazione non supera il limite (fino ad un massimo di 32 al secondo). MaxSpareServers: indica il numero massimo di processi fermi in attesa di connessione, quando si supera questo valore i processi in eccesso vengono terminati. Il valore di default è 15 e di nuovo, se non nel caso di siti con molto traffico, non è il caso di modificarlo. Anche in questo caso non è mai il caso di tenerlo su un valore molto alto. MaxRequestsPerChild: indica il numero massimo di richieste che un processo deve servire, dopo le quali viene terminato. Il valore di default è 0, che significa un numero illimitato. L’utilizzo può essere utile in caso di perdite di memoria (caso piuttosto raro, a meno di non usare moduli sperimentali), e per ridurre più velocemente il numero di processi quando il carico diminuisce. In generale queste direttive, che servono ad impostare le funzionalità generali del server, vengono scritte all’inizio del file di configurazione.

Una delle caratteristiche più interessanti di Apache è la sua modularità; il server cioé è in grado di fornire nuove funzionalità caricando al suo interno dei moduli di espansione anche quando è già in esecuzione, usando quello che viene chiamato il supporto DSO (acronimo di Dynamic Shared Object), in cui i moduli possono essere distribuiti separatamente dal server come librerie dinamiche (negli opportuni file .so). E' attraverso questi moduli che si possono gestire una gran quantità di funzionalità diverse, che vanno dall’interazione di Apache con linguaggi di scripting, alla possibilità di utilizzare il potente motore di per la riscrittura degli indirizzi, al supporto di pressoché infiniti meccanismi di autenticazione di accesso alle risorse. Il meccanismo dei moduli permette di non dover ricompilare Apache ogni volta che si ha bisogno di una funzionalità nuova, e permette anche di cambiare al volo la configurazione (richiedendo semplicemente, grazie alla presenza della direttiva IfModule, la rilettura della configurazione) e di avere diverse istanze di Apache che girano sulla stessa macchina con configurazioni profondamente diverse. A parte gli MPM, che sono un caso particolare, le modalità di utilizzo dei moduli sono due, questi possono essere compilati all’interno del server, e venire attivati e disattivati, oppure possono essere caricati dinamicamente a server attivo da file esterni; ovviamente quest’ultima è la modalità preferita in quanto permette una maggiore flessibilità nella gestione, ed un minore consumo di memoria. Come visto precedentemente l’opzione -l di apache ci consente di vedere quali sono i moduli compilati nel server; in genere questi sono mantenuti al minimo essenziale. Il fatto che un modulo sia stato compilato nel server non comporta necessariamente che questo sia attivo; per questo motivo in fase di avvio si deve stabilire quali moduli attivare; questo viene fatto con una serie di direttive AddModule, questa prende come argomento il nome del modulo da attivare, come riportato nell’esempio precedente (si possono specificare anche più nomi, anche se è uso usare un nome solo per direttiva e ripetere le direttive). Si tenga presente che l’ordine in cui si attivano i moduli (e cioé quello in cui sono scritte le varie direttive AddModule nel file di configurazione) è importante e questi devono essere ordinati al rovescio rispetto alla loro priorità, in quanto un modulo caricato successivamente può soprassedere le funzionalità di un precedente; ad esempio se mod_userdir.c segue mod_alias.c non potranno usare gli alias con le directory degli utenti. All’avvio del server prevede la presenza di una lista predefinita di moduli attivi, dato che non è detto debbano servire tutti in genere si usa la direttiva ClearModuleList per cancellare la lista, e poi si ricrea da capo la lista con una serie di direttive AddModule. Fin qui si è trattato solo il caso dei moduli compilati all’interno del server, ma come dicevamo è possibile far caricare al server i moduli in fase di avvio o di rilettura del file di configurazione; anche questa funzionalità viene fornita attraverso un modulo, mod_so.c, che generalmente vienesempre compilato nel server. Con questo modulo diventa disponibile la direttiva LoadModule che permette di caricare un modulo nel server eseguendo il link del codice dello stesso ed attivarne al contempo l’utilizzo. La direttiva vuole come primo argomento un identificatore del modulo e come secondo argomento il file (nella forma di uno shared object ) che contiene il relativo codice. La convenzione vuole che se il codice sorgente del modulo è ad esempio mod_NOME.c la stringa identificativa sia NOME_module ed il codice sia mantenuto in un file mod_NAME.so in una opportuna directory. Per la gestione dei moduli si è fatto ricorso alle impostazioni mantenute in un file a parte (nel caso /etc/httpd/modules.conf) caricato con una direttiva Include; se esaminiamo il contenuto di questo file troveremo qualcosa del tipo: # Autogenerated file - do not edit! # This file is maintained by the apache package. # To update it, run the command: Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 20 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

# /usr/sbin/apache-modconf apache ClearModuleList AddModule mod_so.c AddModule mod_macro.c LoadModule config_log_module /usr/lib/apache/1.3/mod_log_config.so LoadModule mime_magic_module /usr/lib/apache/1.3/mod_mime_magic.so LoadModule mime_module /usr/lib/apache/1.3/mod_mime.so LoadModule negotiation_module /usr/lib/apache/1.3/mod_negotiation.so LoadModule status_module /usr/lib/apache/1.3/mod_status.so LoadModule autoindex_module /usr/lib/apache/1.3/mod_autoindex.so LoadModule dir_module /usr/lib/apache/1.3/mod_dir.so LoadModule cgi_module /usr/lib/apache/1.3/mod_cgi.so LoadModule userdir_module /usr/lib/apache/1.3/mod_userdir.so LoadModule alias_module /usr/lib/apache/1.3/mod_alias.so LoadModule rewrite_module /usr/lib/apache/1.3/mod_rewrite.so LoadModule access_module /usr/lib/apache/1.3/mod_access.so LoadModule auth_module /usr/lib/apache/1.3/mod_auth.so LoadModule expires_module /usr/lib/apache/1.3/mod_expires.so LoadModule setenvif_module /usr/lib/apache/1.3/mod_setenvif.so

Il problema di questo approccio è che tutti i pacchetti che devono installare un modulo per attivarlo devono andare a manipolare questo stesso file; per questo con Apache 2.0 è stato adottato un approccio diverso, in cui invece di fare riferimento ad un singolo file, si include il contenuto di una intera directory. Una volta che si sono attivati i moduli se ne possono usare le funzionalità; una delle modalità tipiche per fare questo è all’interno di una direttiva IfModule così da evitare errori all’avvio qualora il modulo non fosse presente; un esempio si trova nel file di configurazione di default, nella forma: <IfModule mod_status.c> ExtendedStatus On </IfModule>

In questo caso si utilizzano le funzionalità del modulo mod_status.c che crea una pagina dinamica (la cui posizione dovrà essere definita con un container ad esso dedicato utilizzando la funzionalità degli handler) contenente le informazioni relative allo stato del server. Il modulo definisce una direttiva ExtendedStatus che quando attivata con l’argomento On permette di ottenere un maggior numero di informazioni. Infine è da sottolineare che grazie alla semplicità dell’interfaccia di estensione, sono stati sviluppati una enorme quantità di altri moduli anche da soggetti esterni, in grado di fornire le funzionalità più varie. Alcuni di questi, come quelli per la gestione delle comunicazioni cifrate, sono stati riportati in seguito all’interno del progetto, altri, come quelli per l’esecuzione diretta di programmi scritti in vari linguaggi come il PHP, continuano ad essere sviluppati esternamente. In generale attraverso una opportuna scelta dei moduli diventa possibile di estendere in maniera enorme le funzionalità del server. La funzionalità essenziale di un server web è quella di rispondere alle richieste HTTP eseguite da un client fornendo le risorse richieste da quest’ultimo. Come già accennato benché le risorse identificate dalle URI siano espresse come dei pathname, non è assolutamente detto che queste corrispondano al contenuto di un file; anzi una delle caratteristiche più interessanti di Apache è quello del supporto di una lunga serie di estensioni che permettono di restituire contenuti dinamici Il caso più semplice resta comunque quello in cui ad una richiesta il server risponde inviando il file (in genere una pagina HTML) ad essa direttamente corrispondente; in questo caso la URI viene vista dal server proprio come il pathname di un file. Vedremo in seguito come sia possibile manipolare le modalità con cui il server interpreta la URI. Nel caso più semplice comunque questa non indica altro che il nome del file a partire dalla directory radice dei documenti, che si è specificata con la direttiva DocumentRoot. I primi server web erano in grado soltanto di restituire come risorsa il contenuto di un file, ed anche Apache, se se ne utilizza soltanto il nucleo essenziale, non è in grado di fare molto di più. Le funzionalità disponibili nell’accesso alle risorse vengono controllate, in fase di configurazione, dalle direttive definite nel modulo che le implementa, in molti casi queste direttive possono essere indicate direttamente, nel qual caso l’impostazione sarà applicata a tutti i contenuti forniti dal server. Una delle caratteristiche più interessanti di Apache è però quella delle direttive container con le quali è possibile associare funzionalità diverse a diversi insiemi di risorse e di file, ottenendo un controllo molto raffinato sul comportamento del server. Per questo motivo in genere l’uso delle risorse e delle funzionalità ad esse associate viene configurato sempre all’interno di un container. Normalmente questo può essere di tipo Directory se si vuole effettuare la selezione in base al nome di un file sul filesystem, o di tipo Location se si vuole effettuare la selezione in base al nome della risorsa espresso nella URI. Ad esempio nel file di configurazione di default si usa una sintassi del tipo:

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 21 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

<Directory/> Options SymLinksIfOwnerMatch AllowOverride None </Directory>

per impostare in maniera generale le funzionalità da utilizzare nell’accesso a tutti i file. Oltre alle impostazioni specificate nei container Apache implementa un ulteriore meccanismo di configurazione che permette una decentralizzazione attraverso l’uso di file mantenuti direttamente all’interno dell’albero in cui sono situate le risorse. Il nome di questi file viene impostato con la direttiva AccessFileName, che può essere specificata o a livello generale per tutto il server o per un Virtual Host; il valore di default (che non c’é nessun motivo di cambiare) è .htaccess. All’interno di questi file si possono inserire delle direttive, come se si trattasse di un container, e queste saranno applicate alla directory in cui si è inserito il file e a tutte quelle da essa contenute. Dato che il contenuto di .htaccess può soprassedere (anche se in maniera limitata) la configurazione del server è sempre il caso di usarlo con parsimonia e solo per le situazioni in cui è strettamente necessario, specie se si consente ad altri di modificarne il contenuto, dato che questo può costituire un problema di sicurezza. Occorre quindi valutare sempre se sia effettivamente necessario fornire questi privilegi aggiuntivi agli utenti e considerare i pro ed i contro della scelta. Inoltre con l’uso di .htaccess si peggiorano le prestazioni dato che il server dovrà cercarlo in tutte le directory (comprese quelle di livello superiore), e leggerlo tutte le volte che si richiede un documento. Per questo motivo questa funzionalità, per quanto molto comoda, non andrebbe mai usata fintanto che è possibile eseguire le stesse impostazioni usando il file di configurazione principale; in particolare non è il caso di mantenere le informazioni di autenticazione all’interno di .htaccess. Lo scopo del meccanismo infatti è quello di permettere una decentralizzazione delle impostazioni tutte le volte che questa è necessaria per semplicità amministrativa, ad esempio per consentire anche agli utenti di personalizzare le proprie configurazioni senza dover ricorrere ad una modifica del file di configurazione generale del server. La possibilità di utilizzare i file .htaccess è controllata dalla direttiva AllowOverride che deve essere utilizzata all’interno di un container di tipo Directory per specificare quali delle configurazioni che si sono impostate possono essere sovrascritte dal contenuto di .htaccess. La direttiva prende come argomento una lista di valori che indicano diversi gruppi di funzionalità che è possibile impostare all’interno di .htaccess soprassedendo quelli definiti nel file di configurazione del server. Il valore di default è All, che li attiva tutti, mentre l’uso del valore None disabilita completamente l’uso .htaccess. L’utilizzo dei container e dei file .htaccess consente grande flessibilità e dettaglio nel controllo delle funzionalità e delle risorse messe a disposizione, ma ha anche un certo grado di complessità, occorre allora ben presente come si comporta il server quando le direttive impostate all’interno di diversi container (e nei file .htaccess) si sovrappongono e si vanno ad applicare alle stesse risorse. Il procedimento che determina il risultato finale è allora il seguente: 1. in prima istanza vengono processate le direttive dei container di tipo Directory che non usano espressioni regolari, a partire da quello che utilizza il pathname più breve per finire con quello applicato al pathname più lungo; se AllowOverride lo consente, vengono processati contestualmente gli eventuali contenuti di .htaccess. Se due container si applicano alla stessa directory vengono processati nell’ordine in cui sono scritti. 2. in seconda istanza vengono processate le direttive dei container di tipo Directory e di tipo DirectoryMatch (cioé che usano espressioni regolari), in caso di sovrapposizione sulle stesse risorse vale l’ordine in cui le si sono scritte. 3. in terza istanza vengono processate le direttive dei container di tipo File e FileMatch, di nuovo in caso di sovrapposizione sulle stesse risorse vale l’ordine in cui le si sono scritte. alla fine vengono processate le direttive dei container di tipo Location, come negli altri casi (eccettuato Directory) se si ha sovrapposizione sulle stesse risorse vale l’ordine in cui le si sono scritte. Infine, a completamento di questa sequenza, si deve precisare che tutte le direttive impostate all’interno dei container di tipo VirtualHost vengono processate sempre nella sequenza precedente ma dopo tutte le altre impostazioni presenti in container dello stesso tipo fatte al di fuori di dei VirtualHost, in questo modo le impostazioni di un Virtual Host hanno la precedenza rispetto a quelle generiche. Il risultato finale è quello che risulta dal procedimento appena illustrato, tenendo conto che una direttiva processata Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 22 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

dopo un’altra ne soprassiederà gli effetti. Questo vuol dire ad esempio che se si effettua una configurazione all’interno di una Directory che concerne le stesse risorse configurate all’interno di una Location, indipendentemente dall’ordine in cui le si sono scritte, quest’ultima avrà la precedenza. Per illustrare meglio l’effetto dell’ordinamento si consideri allora il seguente esempio: <Files /var/www/files.html> Direttiva5 </Files> <Location /prima/seconda> Direttiva6 </Location> <VirtualHost *> <Directory /var/www/prima/seconda> Direttiva3 </Directory> </VirtualHost> <DirectoryMatch "^www.*$"> Direttiva4 </DirectoryMatch> <Directory /var/www/prima/seconda> Direttiva2 </Directory> <Directory /var/www/> Direttiva1 </Directory>

in questo caso prima sarà processata Direttiva1 in quanto si applica alla directory di livello più alto, a cui segue Direttiva2 e poi, essendo dentro un VirtualHost, Direttiva3, segue poi Direttiva4 che è all’interno di un DirectoryMatch e Direttiva5 che è all’interno di un Files, chiude Direttiva6 dato che compare all’interno di una Location. Una volta sviscerate le modalità con cui le direttive si applicano alle risorse, possiamo passare alla trattazione di quelle più utilizzate. Tutta una serie di funzionalità, quelle più comuni, sono gestite collettivamente attraverso una unica direttiva, Options, che permette di abilitarle o disabilitarle. La direttiva è strettamente integrata con l’uso dei container; se utilizzata direttamente come nell’esempio precedente essa prevede come argomento solo la lista dei valori delle funzionalità da attivare, e queste varranno per tutte le risorse messe a disposizione del server. Qualora invece la si utilizzi all’interno di un container le funzionalità saranno attivate solo per le risorse da esso specificate, e se esso è di tipo Directory le impostazioni saranno ereditate da una directory a tutte quelle in essa contenute. Per quanto appena illustrato sulle modalità di applicazione delle direttive, se per una directory si hanno più direttive Options assegnate tramite dei container di tipo Directory varranno quelle indicate nel container più specifico che sono processate per ultime, se cioé si ha una configurazione del tipo: <Directory /var/www> Options MultiViews AllowOverride None </Directory> <Directory /var/www/data> Options Indexes FollowSymLinks AllowOverride None </Directory>

per tutto quello che sta sotto /var/www/data varranno le opzioni Indexes e FollowSymLinks e non MultiViews; la direttiva Options però supporta anche una sintassi ulteriore in cui, considerando l’ereditarietà delle configurazioni ottenute dalle directory superiori, si possono aggiungere o togliere opzioni apponendo un segno + o - al nome della stessa; se allora si ha una configurazione del tipo: <Directory /var/www> Options MultiViews AllowOverride None </Directory> <Directory /var/www/data> Options +Indexes +FollowSymLinks AllowOverride None </Directory> <Directory /var/www/data/images> Options -MultiViews AllowOverride None </Directory>

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 23 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

in questo caso a /var/www/data si applicheranno tutte e tre le opzioni Indexes, FollowSymLinks e MultiViews, mentre a /var/www/data/images si applicheranno solo le opzioni Indexes e FollowSymLinks, avendo rimosso MultiViews. Una delle funzionalità la cui disponibilità è gestita da Options è quella della indicizzazione delle directory, questa entra in gioco tutte le volte che un client richiede una URI corrispondente ad una directory, come nel caso classico un cui si richiede la pagina principale di un sito specificando il solo nome a dominio. In casi come questo si pone il problema di quale risorsa fornire come risposta, dato che non è stato richiesto un file specifico; le modalità con cui Apache gestisce la situazione sono due: o viene restituito uno specifico file (in genere index.html) presente in quella directory, o viene generata direttamente dal server una pagina che di norma contiene una lista dei file presenti nella directory. Nel primo caso il modulo mod_dir consente di scegliere quale file restituire come risposta e si può utilizzare la direttiva DirectoryIndex per impostare il nome di questo file. Il valore di default è appunto index.html, ma la direttiva permette di specificare una lista di valori che indicano delle possibili alternative, nel caso verrà restituito il primo file presente nella directory che corrisponde ad uno di quelli nella lista, secondo l’ordine in cui sono scritti; una configurazione di default con questa direttiva è la seguente: <IfModule mod_dir.c> DirectoryIndex index.html index.htm index.shtml index.cgi </IfModule>

Se però si avessero ad esempio delle pagine scritte in PHP, e si volesse usare una di queste come documento di default, si dovrebbe aggiungere alla lista precedente un altro file, ad esempio index.php. Qualora non si trovi nessuno dei file specificati con DirectoryIndex il server restituisce un errore, a meno che per la directory in questione non si sia abilitata l’opzione Indexes; in tal caso verranno utilizzate le funzionalità provviste dal modulo mod_autoindex (occorre ovviamente averlo caricato) per generare automaticamente una pagina HTML contenente una lista dei file contenuti nella directory stessa. Il modulo fornisce delle funzionalità molto avanzate che permettono di controllare ogni aspetto della generazione della pagina con la lista dei file. Di nuovo estraiamo dal file di configurazione standard un esempio di uso delle varie direttive fornite da mod_autoindex: in questo caso la URI corrispondente è semplicemente /. <IfModule mod_autoindex.c> IndexOptions FancyIndexing NameWidth=* AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip AddIconByType (TXT,/icons/text.gif) text/* AddIconByType (IMG,/icons/image2.gif) image/* AddIconByType (SND,/icons/sound2.gif) audio/* AddIconByType (VID,/icons/movie.gif) video/* AddIcon /icons/binary.gif .bin .exe AddIcon /icons/binhex.gif .hqx AddIcon /icons/tar.gif .tar AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip AddIcon /icons/a.gif .ps .ai .eps AddIcon /icons/layout.gif .html .shtml .htm .pdf AddIcon /icons/text.gif .txt AddIcon /icons/c.gif .c AddIcon /icons/p.gif .pl .py AddIcon /icons/f.gif .for AddIcon /icons/dvi.gif .dvi AddIcon /icons/uuencoded.gif .uu AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl AddIcon /icons/tex.gif .tex AddIcon /icons/bomb.gif core AddIcon /icons/deb.gif .deb AddIcon /icons/back.gif .. AddIcon /icons/hand.right.gif README AddIcon /icons/folder.gif "DIRECTORY" AddIcon /icons/blank.gif "BLANKICON" DefaultIcon /icons/unknown.gif ReadmeName README.html HeaderName HEADER.html IndexIgnore .??*

Le direttive controllano i vari aspetti della visualizzazione della lista; un elenco delle principali è il seguente, al solito la documentazione completa è fornita sul sito di Apache, ed in particolare all’indirizzo http://httpd.apache.org/docs/mod/mod_autoindex.html: Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 24 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.2.6 -

La gestione dei file di log

Benché la problematica sia rilevante per l’amministrazione di qualunque servizio, nel caso di Apache la gestione dei file di log assume un’importanza particolare, dato che questi consentono di tenere traccia di tutte le transazioni HTTP che il server esegue. E' così possibile controllare nei dettagli l’attività dello stesso, ed oltre a rilevare gli eventuali errori si possono ottenere sia le statistiche di utilizzo che i dati riguardanti l’accesso, che sono informazioni di grande utilità nella gestione di un sito web. In generale si distinguono due tipi di messaggi prodotti dal server, che devono essere registrati nei file di log: quelli di errore e quelli di accesso. I messaggi di errore vengono generati comunque; la gestione della loro registrazione è affidata alle seguenti direttive: ErrorLog indica il nome del file su cui salvare i messaggi di errore generati dal server. Se si usa un pathname relativo esso è preso a partire dalla directory indicata da ServerRoot; dato che in genere questa è sotto /etc e non è scrivibile in genere si specifica un pathname assoluto per far scrivere il file sotto /var/log/. Nel caso in esame si usa /var/log/httpd/error.log . La direttiva supporta anche l’uso della forma syslog:facility al posto del nome del file per inviare i messaggi di errore al sistema del syslog, nella facility specificata. LogLevel associata alla precedente permette di stabilire la quantità di informazioni da inviare sui log specificati da ErrorLog. Sono definiti gli stessi livelli utilizzati dal sistema del syslog (al solito si può fare riferimento al testo citato o alla pagina di manuale di syslog.conf); il valore di default è warn. Normalmente è opportuno utilizzare ErrorLog a livello di configurazione generale del server per raccogliere in un solo luogo tutti i messaggi di errore, è però possibile usare queste stesse direttive per creare dei file di log separati per ciascun Virtual Host presenti nel sistema, inserendo le stesse direttive all’interno di un container del suddetto tipo. Come per ErrorLog anche le direttive per la registrazione delle informazioni di accesso possono essere specificate o a livello generale per tutto il server o per i singoli Virtual Host. TransferLog definisce un file su cui verranno registrati i dati di accesso; la direttiva permette solo di usare il formato di default (quello stabilito dalla più recente impostazione effettuata con LogFormat) e prende come unico argomento o il nome di un file (se relativo viene risolto rispetto a ServerRoot) o il carattere “|” seguito dal pathname di un programma che sarà eseguito e riceverà i dati in ingresso. Un esempio di questa direttiva potrebbe essere la seguente: TransferLog /var/log/apache/access.log

CustomLog è la principale direttiva di registrazione, rispetto alla precedente TransferLog permette di specificare il formato dei dati e di eseguire registrazioni condizionali (in base al valore delle variabili di ambiente gestite da mod_setenvif). La direttiva prevede un primo argomento identico a quello di TransferLog, a cui segue un secondo argomento che indica una etichetta associata ad un certo formato dei file di log, definito con una opportuna direttiva LogFormat. Infine è possibile specificare una condizione opzionale nella forma env=variabile che consente di eseguire o meno la registrazione di un certa richiesta sulla base della presenza o meno nell’ambiente di una certa variabile (queste vengono impostate a parte dalla direttiva SetEnvIf), la condizione può anche essere invertita se specificata come env=!valore. Un esempio di questa direttiva potrebbe essere il seguente: CustomLog /var/log/apache/access.log combined

LogFormat il formato dei dati registrati nei log viene configurato da questa direttiva, questa può assumere due forme con uno o due argomenti. Nel primo caso l’argomento specifica il formato delle informazioni da registrare, e quello diventa il formato di default (e sarà utilizzato da TransferLog. Se invece si specificano due argomenti il secondo deve essere una stringa che fa da una etichetta per identificare il formato definito nel primo argomento, che poi potrà essere riutilizzata nelle direttive CustomLog. Un esempio di questa direttiva è il seguente, che definisce il cosiddetto Common Log Format : LogFormat "%h %l %u %t \"%r\" %>s %b" common

Per usare in maniera efficace le capacità di registrazione di Apache occorre approfondire il formato del primo argomento della direttiva LogFormat che specifica quali dati saranno registrati. L’argomento deve essere passato come stringa delimitata da virgolette, pertanto per poter utilizzare queste ultime all’interno delle stringa si dovrà proteggerle con il carattere “\”; questo consente anche di inserire all’interno della stringa anche caratteri speciali Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 25 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

come la tabulazione ed il ritorno a capo con sequenze del tipo di \t e \n. Gli altri caratteri sono convertiti letteralmente mentre il carattere “%” viene usato per identificare delle direttive di formattazione che vengono tradotte in una serie di dati relativi alla richiesta. Un esempio di vari formati usati nella registrazione dei dati di accesso è quello che si ha nel seguente estratto del file di configurazione di default, in cui si è preso (al solito eliminando i commenti) la sezione dedicata alle direttive per i log: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"% {forensic-id}n\" %T %v" full LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"% {forensic-id}n\" %P %T" debug LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"% {forensic-id}n\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b \"%{forensic-id}n"" forensic LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent CustomLog /var/log/apache/access.log combined

Altrimenti è possibile scegliere di usare altri strumenti creati per la gestione dei log dei server web, ad esempio Cronolog, che permette di avere i log suddivisi in base al mese o alla settimana a cui si riferiscono, il tutto in modo completamente automatico.

2.3 - PostgreSQL

2.3.1 -

Introduzione

Il secondo passo, dopo aver installato in locale Apache, è stato quello di procedere all'installazione e alla configurazione del database che GForge utilizzerà per gestire la condivisione del software e altre informazioni importanti. PostgreSQL è stato installato anch'esso in locale per avere un ambito di prova sicuro. In seguito a configurazione e sviluppo delle modifiche ultimate si è proceduto alla migrazione del solo database dal locale all'installazione di INFN già presente. Per questa operazione di backup e di ripristino sono state utilizzate le funzionalità che si andranno ad introdurre in seguito.

2.3.2 -

Installazione di PostgreSQL

Per attivare il servizio di DBMS completo e corrispondente alle richieste indicate precedentemente nella specifica dei requisiti dovranno essere installati più pacchetti: 1. PostgreSQL 8.1.11.1.el5-1.1 2. PostgreSQL-Server 3. PHP-PGSQL PostgreSQL 8.1.11.1.el5-1.1 gestisce il lato client ed è nella distribuzione utilizzata già presente. Per tanto si è semplicemente verificato il funzionamento. Il secondo pacchetto, come dal nome indicato, gestisce il lato server del database e naturalmente rappresenterà il cuore dell'applicazione Gforge che lo utilizzerà. Questa pacchetto non è presente nella distribuzione usata e lo si è dovuto quindi scaricare e installare. Il servizio PostgreSQL-Server lo si può lanciare con il seguente comando (da root)

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 26 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

/etc/init.d/postgresql start

Come indicato precedentemente l'ultimo pacchetto installato è stato PHP-PGSQL ovvero una libreria per PHP per dare la possibilità di integrare nel codice PHP chiamate di sistema, procedure e altro ancora per il database postgresql. Questo pacchetto è importante poichè si andrà più avanti ad implementare le modifiche necessarie proprio richiamando queste librerie.

Figura 3: Installazione di php-pgsql con le relative dipendenze Come si può vedere dalla figura 3, l'applicazione yumex ha trovato delle dipendenze per il pacchetto php-pgsql e ha installato quindi anche: php-common php-pdo

Il primo è un pacchetto contenente delle utility generiche per php, il secondo è un'astrazione dell'accesso al database. Il DBMS è ora configurato, l'installazione e la configurazione del database che verrà poi utilizzato da GForge viene trattata successivamente.

2.3.3 -

Un po' di storia su PostgreSQL

PostgreSQL è un completo database relazionale ad oggetti con licenza libera stile. Inizialmente il dbms si chiamava Ingres ed era un progetto del Berkeley. Nel 1982 il capo progetto, Michael Stonebraker, ha lasciato il Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 27 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Berkeley per commercializzare il prodotto, ma in seguito è tornato all'accademia. Nel 1985 l'ha lasciata nuovamente per dare vita a un progetto post-Ingres (Postgres) che superasse gli evidenti limiti dei prodotti concorrenti dell'epoca. La base dei sorgenti di Ingres e di Postgres erano, e sono rimasti nel tempo, ben distinti [5]. Il nuovo progetto puntava a fornire un supporto completo ai tipi di dati, in particolare la possibilità di definire nuovi tipi di dati (UDF, User Defined Types). Vi era anche la possibilità di descrivere la relazione tra le entità (tabelle), che fino ad allora veniva lasciata completamente all'utente. Perciò non solo Postgres preservava l'integrità dei dati, ma era in grado di leggere informazioni da tabelle relazionate in modo naturale, seguendo le regole definite dall'utente. Dal 1986 gli sviluppatori diffusero un gran numero di articoli che descrivevano il nuovo sistema e nel 1988 venne rilasciato un primo prototipo funzionante. La versione 1 venne rilasciata nel giugno del 1989 per un numero di utenti contenuto. Seguì una versione 2 nel giugno del 1990, in cui il sistema delle regole venne completamente riscritto. Nella versione 3, del 1991, questo sistema venne riscritto ancora, ma venne aggiunto anche il supporto a gestori multipli di immagazzinamento dei dati e un motore di query migliorato. Nel 1993 vi era già un numero di utenti notevole che inondava il team di sviluppo con richieste di supporto e di nuove features. Dopo aver rilasciato la versione 4, che fu principalmente un ripulimento del codice, il progetto terminò Un rapido esame di PostgreSQL potrebbe suggerire che sia simile agli altri database. PostgreSQL usa il linguaggio SQL per eseguire delle query sui dati. Questi sono conservati come una serie di tabelle con foreign keys che servono a collegare i dati correlati [6]. La programmabilità di PostgreSQL è il suo principale punto di forza ed il principale vantaggio verso i suoi concorrenti: PostgreSQL rende più semplice costruire applicazioni per il mondo reale, utilizzando i dati prelevati dal database. I database SQL conservano dati semplici in "flat tables", richiedendo che sia l'utente a prelevare e raggruppare le informazioni correlate utilizzando le query. Questo contrasta con il modo in cui sia le applicazione che gli utenti utilizzano i dati: come ad esempio in un linguaggio di alto livello con tipi di dato complessi dove tutti i dati correlati operano come elementi completi, normalmente definiti oggetti o record (in base al linguaggio). Convertire le informazioni dal mondo SQL a quello della programmazione orientata agli oggetti, presenta difficoltà dovute principalmente al fatto che i due mondi utilizzano modelli di organizzazione dei dati molto differenti. L'industria chiama questo problema "impedance mismatch" (discrepanza di impedenza): mappare i dati da un modello all'altro può assorbire fino al 40% del tempo di sviluppo di un progetto. Un certo numero di soluzioni di mappatura, normalmente dette "object-relational mapping", possono risolvere il problema, ma tendono ad essere costose e ad avere i loro problemi, causando scarse prestazioni o forzando tutti gli accessi ai dati ad aver luogo attraverso il solo linguaggio che supporta la mappatura stessa. PostgreSQL può risolvere molti di questi problemi direttamente nel database. PostgreSQL permette agli utenti di definire nuovi tipi basati sui normali tipi di dato SQL, permettendo al database stesso di comprendere dati complessi. Per esempio, si può definire un indirizzo come un insieme di diverse stringhe di testo per rappresentare il numero civico, la città, ecc. Da qui in poi si possono creare facilmente tabelle che contengono tutti i campi necessari a memorizzare un indirizzo con una sola linea di codice. PostgreSQL, inoltre, permette l'ereditarietà dei tipi, uno dei principali concetti della programmazione orientata agli oggetti. Ad esempio, si può definire un tipo codice_postale, quindi creare un tipo cap (codice di avviamento postale) o un tipo us_zip_code basato su di esso. Gli indirizzi nel database potrebbero quindi accettare entrambi i tipi, e regole specifiche potrebbero validare i dati in entrambi i casi. Nelle prime versioni di PostgreSQL, implementare nuovi tipi richiedeva scrivere estensioni in C e compilarle nel server di database. Dalla versione 7.4 è diventato molto più semplice creare ed usare tipi personalizzati attraverso il comando "CREATE DOMAIN". Punti di forza della programmabilità di PostgreSQL: 1. Incremento delle prestazioni, in quanto la logica viene applicata direttamente dal server di database in una volta, riducendo il passaggio di informazioni tra il client ed il server. 2. Incremento dell'affidabilità, dovuto alla centralizzazione del codice di controllo sul server, non dovendo gestire la sincronizzazione della logica tra molteplici client e i dati memorizzati sul server. 3. Inserendo livelli di astrazione dei dati direttamente sul server, il codice del client può essere più snello e semplice.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 28 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.3.4 -

Fondamenti sull'architettura

PostgreSQL usa un modello client/server. una sessione PostgreSQL consiste in una cooperazione di processi (applicazioni): un processo server, che governa i file di database, accetta connsessioni al database da parte delle applicazioni client ed esegue le azioni sul database richieste dai client. Tale processo si chiama postgres. E' l'applicazione client di front end, ossia di acquisizione dei dati, che fa la richiesta al server. Le applicazioni client possono essere molto diverse nella loro natura: un client può essere un editor di testo, un'applicazione grafica, un server web che accede al database per mostrare le pagine html o ancora un programma specifico per la manutenzione di database. Alcune applicazioni client sono già supportate nelle attuali distribuzioni di PostgreSQL; la maggior parte stata implementata dagli utenti stessi. Come e' tipico delle applicazioni client/server, il client e il server possono essere host differenti. In questo caso essi comunicano tra loro tramite una connessionte TCP/IP. E' buona norma ricordarselo, perchè i file che sono accessibili su una macchina client potrebbero non esserlo (o esserlo solo usando un utente differente) sulla macchina server [7]. Il server PostgreSQL può mantenere molteplici connessioni con i client. A questo proposito apre un nuovo processo ("forks") per ogni connessione. Da questo punto in avanti, il client e il server comunicano senza l'intervento del processo postgres inizile. Infatti questo processo continua ad agire in remoto, aspettando che i client si connettano, mentre altri client continuano ad interagire con gli altri processi. PostgreSQL è un DBMS ovvero un database management system. Questo significa che è un sistema in grado di gestire dati all'interno di relazioni. Relazione è essenzialmente un collegamento tra tabelle. L'idea di immagazzinare dati in tabelle è molto comune oggi e può sembrare anche ovvia ma esistono diverse maniere per organizzare i database. Files e directory nei sistemi Unix sono un esempio di database gerarchico. Uno sviluppo più moderno è dato dai database orientati agli oggetti Ogni tabella è costituita da una collezione di righe e da uno stesso set di colonne, ognuna delle quali è specificata da un tipo di dato. Più tabelle sono ragguppate in un database, una collezione di database viene gestita da un singolo server PostgreSQL [8].

2.4 - OpenSSL L'installazione di OPENSSL si è resa necessaria poichè il server LDAP di INFN, nel particolare un Fedora Directory Service, accetta solamente connessioni sicure. Per un primo momento, dopo l'installazione, SSL è stato accantonato in quanto le prove sono state poi eseguite sull'OPENLDAP installato in locale che non necessitava di tale livello di sicurezza. Il servizio SSL è stato utilizzato in seguito, durante la fase di testing, dopo la fase di sviluppo. La fase finale di testing è stata fatta connettendosi su LDAP di INFN e poichè questo albero accetta in entrata solo connessioni “sicure” era necessario utilizzare questo servizio.

2.4.1 -

Introduzione a OpenSSL

OpenSSL è una realizzazione in forma di software libero dei protocolli SSL/TLS (Secure Socket Layer e Transport Layer Security) per la certificazione e la comunicazione cifrata. Inizialmente, il progetto si chiamava SSLeay, ma da quando l'autore originale lo ha dovuto interrompere, questo è stato ripreso da un gruppo indipendente che lo ha ribattezzato in OpenSSL [9] [10]. OpenSSL si compone di alcune librerie che permettono di incorporare le funzionalità dei protocolli SSL/TLS all'interno di programmi di comunicazione, e di una serie di programmi di utilità per la gestione delle chiavi e dei certificati, arrivando eventualmente anche alla gestione di un'autorità di certificazione.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 29 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.4.2 -

Installazione di OpenSSL

Il pacchetto OPENSSL è già presente nella distribuzione utilizzata, quindi non si sono effettuate operazioni di installazione. Il pacchetto installato è la versione 0.9_8b_8.3.el5_0.2 come si può vedere dalla figura 4.

Figura 4: Il toolkit OpenSSL è già installato Si è lanciato yumex e dopo aver ricercato openssl si è visto che il pacchetto in questione è già installato.

2.4.3 -

Configurazione di OpenSSL:

Non esiste una definizione ben precisa di dove devono essere collocati i file che compongono la configurazione e gli strumenti di OpenSSL. Quando si installa OpenSSL da un pacchetto fatto per la propria distribuzione GNU/Linux, è importante scoprire dove vengono collocati i file delle chiavi e dei certificati, e dove si trova il file di configurazione `openssl.cnf'. Intuitivamente si potranno cercare questi file a partire dalla directory `/etc/'; in particolare, le chiavi potrebbero essere collocate a partire da `/etc/ssl/' o da `/etc/openssl/'. Quando gli strumenti di OpenSSL sono organizzati in un solo eseguibile monolitico, la sintassi per i comandi relativi si esprime sinteticamente nel modo seguente: openssl openssl openssl openssl openssl openssl

req ca crl genrsa rsa x509

Gestione delle richieste di certificazione. Gestione relativa all'autorità di certificazione. Gestione del certificato delle revoche. Generazione di parametri RSA. Conversione del formato di una chiave privata o di un certificato. Gestione dei dati dei certificati X.509.

- Alcuni comandi di OpenSSL con relativa descrizione -

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 30 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

La tabella precedente elenca brevemente alcuni dei comandi più importanti. Per avere una guida rapida alle opzioni di ogni comando, basta utilizzare un'opzione non valida, per esempio `-h': $ openssl ca -h

L'esempio mostra in che modo ottenere l'elenco delle opzioni del comando `openssl ca'; comunque, in mancanza di altra documentazione, conviene stampare e tenere a portata di mano queste guide: $ $ $ $ $

openssl openssl openssl openssl openssl

req -h > guida.txt crl -h >> guida.txt ca -h >> guida.txt genrsa -h >> guida.txt x509 -h >> guida.txt

Alcuni di questi comandi hanno in comune delle opzioni, che vale la pena di descrivere subito, prima di mostrare degli esempi, nei quali si potrà concentrare l'attenzione sulle altre opzioni specifiche. La tabella qui sotto mostra questo elenco di opzioni tipiche. -in <file> Definisce un file in ingresso adatto al contesto. -out <file> Definisce un file in uscita adatto al contesto. -noout Non emette il risultato. -text Emette le informazioni in forma di testo leggibile. -hash Emette il codice di controllo relativo al contesto. -inform <formato> Specifica il formato dei dati in ingresso. -outform <formato> Specifica il formato dei dati in uscita. - Alcune opzioni frequenti nei comandi di OpenSSL e relativa descrizione -

Prima di descrivere la configurazione di OpenSSL, viene mostrato tecnicamente il modo per richiedere un certificato, o per realizzarne un proprio senza valore. Infatti, in generale, la configurazione standard dovrebbe essere più che sufficiente per il raggiungimento di questo obiettivo. È il caso di ricordare che un certificato è un file contenente la chiave pubblica del suo titolare, firmata da un'autorità di certificazione che garantisce la sua validità e anche la correttezza degli altri dati. I certificati digitali sono, quindi, strumenti di identificazione elettronica che vincolano una persona fisica o giuridica a una coppia di chiavi software che possono essere utilizzate per cifrare e sottoscrivere comunicazioni digitali. I certificati digitali sono necessari per effettuare una connessione sicura di tipo SSL che è l'unica che LDAP di mailman.fe.infn.it è in grado di accettare.

2.4.4 -

Procedura per ottenere un certificato

Per mettere in piedi un servizio che utilizzi i protocolli SSL/TLS, occorre predisporre dei file contenenti chiavi e certificati. Di solito, quando si installano servizi che utilizzano questi protocolli, la procedura di installazione si prende cura di predisporre automaticamente i file necessari per consentire il funzionamento, senza che le certificazioni che si ottengono abbiano alcun valore. In generale si comincia dalla creazione o dalla definizione di un file contenente dati casuali, come punto di partenza per generare una chiave privata, quindi si passa alla creazione di una richiesta di certificazione, oppure alla creazione di un certificato auto-firmato, senza valore.

2.4.5 -

Creazione di un file di dati casuali

Per creare personalmente un certificato è possibile partire dalla generazione di un file di dati casuali. Questo file può essere creato in vari modi, per esempio mettendo assieme alcuni file: $ cat file_a file_b file_c > file_casuale

magari rielaborandoli in qualche modo, oppure prelevando un po' di caratteri dal file `/dev/random': $ dd if=/dev/random of=file_casuale bs=1b count=1k

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 31 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.4.6 -

Chiave privata

Per generare una chiave privata in chiaro, si utilizza il comando `openssl genrsa', in un modo simile a quello seguente, dove in particolare viene utilizzato il file `file_casuale' come origine di dati casuali, e si ottiene il file `chiave_privata.pem' di 1024 bit: $ openssl genrsa -rand file_casuale -out chiave_privata.pem 1024

Eventualmente, per creare una chiave privata cifrata, basta aggiungere un'opzione a scelta tra `-des', `-des3' e `idea', che stanno indicare rispettivamente gli algoritmi DES, DES-triplo e IDEA. Ecco di seguito come usare l'opzione `-des3': $ openssl genrsa -des3 -rand file_casuale -out chiave_privata_protetta.pem 1024 Enter PEM passphrase: ******** Verifying password - Enter PEM pass phrase: ********

Volendo riportare la chiave privata in chiaro, si usa il comando `openssl rsa', in modo simile all'esempio seguente: $ openssl rsa -in chiave_privata_protetta.pem -out chiave_privata.pem Enter PEM passphrase: ********

In modo analogo funziona l'operazione di protezione di una chiave; in pratica si aggiunge l'opzione attraverso cui si specifica il tipo di algoritmo: $ openssl rsa -des3 -in chiave_privata.pem -out chiave_privata_protetta.pem

2.4.7 -

Richiesta di certificazione

Teoricamente, il certificato che identifica e garantisce l'identità del servizio che si gestisce, deve essere fornito da un'autorità di certificazione. In questo caso, per farlo, deve ricevere un documento intermedio, definibile come una richiesta di certificazione. La chiave pubblica che vi viene inserita si ottiene a partire dalla chiave privata, e gli altri dati necessari per il certificato che si vuole ottenere, si inseriscono in modo interattivo. È interessante vedere come avviene: $ openssl req -new -key chiave_privata.pem -out richiesta.pem Country Name (2 letter code) [AU]:IT State or Province Name (full name) [Some-State]:Italia Locality Name (eg, city) []:Rovigo Organization Name (eg, company) [Internet Widgits Pty Ltd]:prova Organizational Unit Name (eg, section) []:. Common Name (eg, YOUR name) []:prova.it Email address []:prova@prova.it Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:password An optional company name []:company

Le informazioni che si inviano in questo modo sono molto importanti, e il significato preciso varia a seconda del contesto per il quale si richiede la certificazione. Sarà l'autorità per la certificazione a stabilire quali informazioni servono precisamente. Per verificare il contenuto del certificato, che nel suo formato PEM non è leggibile direttamente, si può usare il comando `openssl req' con l'opzione `-text':

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 32 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

$ openssl req -text -in richiesta.pem Certificate Request: Data: Version: 0 (0x0) Subject: C=IT, ST=Italia, L=Rovigo, O=prova, CN=prova.it... Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:ce:0d:cd:08:86:fd:b5:cb:14:56:51:04:73:38: 15:77:39:2d:3b:10:17:06:7c:64:0d:69:14:67:cd: ... 67:f7:ef:b1:71:af:24:77:64:66:64:0f:85:a6:64: 16:c2:69:26:59:0a:d9:4b:8d Exponent: 65537 (0x10001) Attributes: unstructuredName :Dinkel challengePassword :super segretissimo Signature Algorithm: md5WithRSAEncryption 8f:25:9f:68:3a:67:4c:6d:e6:eb:52:4a:ca:73:74:47:85:14: ca:d6:6c:6d:24:3b:6c:37:59:ec:f8:fb:0b:a9:74:d6:1c:0f: ... 02:60:16:fd:2e:9b:09:af:11:03:82:74:16:ae:57:a7:90:f5: e1:a5

2.4.8 -

Creazione di un certificato fittizio

Per generare in proprio il certificato auto-firmato, in modo da attivare ugualmente il servizio anche se non si può dimostrare di essere chi si afferma di essere, si può aggiungere l'opzione `-x509'. Anche in questo caso vengono richieste tutte le informazioni già viste. $ openssl req -new -x509 -key chiave_privata.pem -out richiesta.pem

In alcuni casi può essere necessario fondere assieme la chiave privata, in chiaro, e il certificato; questo accade in particolare quando si allestisce un servente HTTP Apache-SSL. Di solito la chiave privata non può essere cifrata, perché deve essere letta da un servizio autonomo che non può interrogare un utente. Si deve ottenere una cosa simile a quella seguente: -----BEGIN RSA PRIVATE KEY----MIICXQIBAAKBgQDzUS4vA9NPNGAhHp71jGLk9lyJ6GffK2R+AtMmWDKWvwhVOA8l eY13ouz6XW0ts7s91FYlSTbp0Ed5tLKHZFu8guuza3jzpqFE/wrW/eJ7/RYW0cOZ ... +7JyXBGaA4Srn/iw9cUCQQDEr5yuQa426I6psxfvUiK+HKS2kfRBbKKHj2NYh6nv GgMhY9NiG+SGEDfkOw9rIVifb9yXs6f4CajQTb4qVl2X -----END RSA PRIVATE KEY---------BEGIN CERTIFICATE----MIICMTCCAZoCAQAwDQYJKoZIhvcNAQEEBQAwYTELMAkGA1UEBhMCcXExCzAJBgNV BagTAnd3MQswCQYDVQQHEwJlZTELMAkGA1UEChMCcnIxCzAJBgNVBAsTAnR0MQsw ... 3kNqIB5Iun0kdDqdJYQj9G5Ca+dlRCxrPY6bVCnlD3A8+RULjyGrT6D45QtoXKx+ quIhIni++XBHqe+RyWBD70XTWvw0+zoyrHNHG96k9eLlPIgHrQ== -----END CERTIFICATE-----

L'aggregazione può essere fatta a mano (attraverso `cat'), oppure si può utilizzare un comando unico che crea la chiave privata (di dimensione predefinita) e anche il certificato autoprodotto: $ openssl req -new -x509 -nodes -out certificato.pem -keyout certificato.pem

In questo esempio è stata usata l'opzione `-keyout' per dirigere la chiave privata nello stesso file del certificato, e anche l'opzione `-nodes', per evitare la protezione della chiave che in questi casi deve essere usata in chiaro. Come mostrato anche in seguito, il file del certificato, con o senza la chiave privata acclusa, deve essere raggiungibile attraverso un nome corrispondente al suo codice di controllo, con l'aggiunta dell'estensione `.0'. Questo valore si ottiene con un comando simile a quello che si vede: Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 33 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

$ openssl x509 -hash -noout -in certificato.pem

Per generare un collegamento simbolico come si fa di solito, si potrebbe usare il comando seguente: $ ln -s certificato.pem `openssl x509 -hash -noout -in certificato.pem`.0

2.4.9 -

Creazione del certificato per INFN

Per la creazione del certificato per OpenSSL si è proceduto come indicato appena sopra. Dopo aver ottenuto e copiato la chiave privata dal sito di INFN si è creato il file INFN-CA.PEM e lo si è salvato in /etc/pki/tls/certs ottenendo quindi: /etc/pki/tls/certs/INFN-CA.PEM. Si è poi ottenuto il certificato attraverso il comando OPENSSL: $ openssl x509 -hash -noout -in INFN-CA.pem Successivamente, attraverso la procedura indicata precedentemente, si è ottenuto il link al certificato appena creato: $ ln -s INFN-CA.pem `openssl x509 -hash -noout -in INFN-CA.pem`.0

2.4.10 -

Cos'è X.509

In crittografia, X.509 è uno standard ITU-T per le infrastrutture a chiave pubblica (PKI). X.509 definisce, fra le altre cose, formati standard per i certificati a chiave pubblica ed un certification path validation algorithm.

2.4.11 -

Storia ed utilizzo

X.509 venne presentato per la prima volta nel 1988 e il suo sviluppo cominciò insieme allo standard X.500. La prima versione presupponeva uno stretto sistema di gerarchie di certificate authority (CA) per presentare e garantire un certificato, in contrasto con il modello della rete di fiducia (web of trust), utilizzato da PGP, dove chiunque (non solo CA particolari) può firmare e quindi attestare (certificare) la validità delle chiavi altrui. La Versione 3 di X.509 include flessibilità tipiche di altre tipologie di reti e filtri: può essere utilizzato in una rete di fiducia peer-to-peer come quella di OpenPGP, anche se raramente è implementata in questo modo. Il sistema X.500 non è mai stato totalmente implementato, e l'IETF ed i public-key infrastructure working group hanno adattato lo standard con una struttura più flessibile adatta ad internet. Infatti il termine certificato X.509 si riferisca generalmente al profilo di certificato PKI e di revoca del certificato (CRL) dell'IETF dello standard X.509 v3, come descritto nella RFC 3280.

2.4.12 -

Certificati

Nel sistema X.509, una CA rilascia un certificato che accoppia una chiave pubblica ad un Nome Distintivo (Distinguished Name) seguendo la tradizione del X.500, oppure ad un Nome Alternativo (Alternative Name) come potrebbe essere un indirizzo e-mail o un record DNS. Un root certificate fidato di un'azienda può essere distribuito a tutti i dipendenti, per far si che possano usare la PKI aziendale. Browser come Internet Explorer, Netscape/Mozilla ed Opera vengono distribuiti con alcuni root certificate preinstallati, rendendo possibile il funzionamento dei certificati SSL di alcuni grossi distributori che hanno pagato per questo servizio; in pratica chi sviluppa il browser determina quali CA sono terze parti fidate. Nonostante questi root certificate possano essere eliminati o disabilitati, raramente gli utenti lo fanno. X.509 include anche gli standard per le implementazioni di certificate revocation list (CRL, liste di revoca di certificati), un aspetto spesso sottovalutato dei sistemi PKI. La modalità di controllo della validità di un certificato approvata dall'IETF si chiama Online Certificate Status Protocol (OCSP).

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 34 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.4.13 -

Struttura di un certificato

La struttura di un certificato digitale X.509 v3 è la seguente: 1. Certificato 2. Versione 3. Numero seriale 4. ID dell'algoritmo 5. Ente emettitore 6. Validità A Non prima B Non dopo 7. Soggetto 8. Informazioni sulla chiave pubblica del soggetto A Algoritmo per l'utilizzo della chiave pubblica B Chiave pubblica 9. Codice identificativo univoco dell'emittente (facoltativo) 10. Codice identificativo univoco del soggetto (facoltativo) 11. Estensioni (facoltativo) 12. Algoritmo di firma del certificato 13. Firma del certificato I codici identificativi univoci dell'emettitore e del soggetto sono stati introdotti nella versione 2, le "Estensioni" nella versione 3. Estensioni comuni per i file contententi i certificati X.509: * .CER - certificato codificato con DER, a volte sequenze di certificati; * .DER - certificato codificato con DER;* .PEM - certificato codificato con Base64, racchiuso tra "-----BEGIN CERTIFICATE-----" e "-----END CERTIFICATE-----"; * .P7B - vedi .p7c * .P7C - struttura SignedData PKCS#7 senza dati, solo il/i certificato/i o la/le CRL (Certificate revocation list); * .PFX - vedi .p12 * .P12 - PKCS#12, può contenere certificati e chiavi pubbliche e private (protette da password);

Un file .PEM può contenere certificati o chiavi private, racchiusi tra le apposite linee BEGIN/END. Le entità presenti nel X.509 sono: 1. Certification Autority (CA): emette certificati, genera CRL, genera la coppia chiave Pb e Pr, conferma che ogni utente che richiede l’emissione del proprio certificato è in possesso della corrispondente chiave privata, verifica l’unicità della chiave Pb. 2. Local Registration Authorities: alcune CA richiedono la presenza fisica dell’utente finale e quindi una LRA gioca il ruolo di intermediario, che risolve questo problema. 3. Root Authority: è l’autorità che è in carica per approvare la politica di certificazione globale. Usata solitamente per certificare altre CA, non utenti. 4. Policy certification Authority: permette di creare,per alcuni gruppi di utenti, estensioni di politiche di certificazione stabilite originalmente. 5. L’utente finale: genera e verifica documenti firmati

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 35 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.5 - Il pacchetto mod_ssl

2.5.1 -

L'installazione di mod_ssl

Per prima cosa si è verificato che il pacchetto mod_ssl fosse già presente nella distribuzione usata ma non è stato rilevato. Quindi attraverso yumex si è proceduto alla sua installazione.

Figura 5: Installazione di mod_ssl con dipendenze Come si può vedere dalla figura 5, il pacchetto installato è la versione 1.2.2.3-11.sl5.3 che ha richiesto l'installazione anche della dipendenza distcache. Il pacchetto distcache serve a gestire la cache per la versione distribuita di mod_ssl.

2.5.2 -

Cos'è mod_ssl

Questo pacchetto rappresenta una delle possibilità per Apache di creare servizi sicuri secondo il protocollo SSL appena descritto. Una volta installato il pacchetto come descritto precedentemente sono già abilitate le connessioni Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 36 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

sicure senza ulteriori parametri da configurare [11].

2.6 - Stunnel

2.6.1 -

Cos'è Stunnel

Stunnel è un software libero multi-piattaforma, usato per fornire un servizio TLS/SSL universale. Stunnel può essere utilizzato per fornire connessioni sicure per client e server che non supportano nativamente TLS o SSL. Funziona su vari sistemi operativi, tra cui la maggior parte dei sistemi Unix-like e Windows. Utilizza una libreria separata come OpenSSL o SSLeay per implementate i sottostanti protocolli TLS o SSL. Se linkata alla libwrap, può essere configurata in modo da agire da proxy-firewall.Stunnel viene rilasciato sotto licenza GPL.

2.6.2 -

Installazione di Stunnel

Attraverso il solito comando yumex si è verificato l'eventuale presenta nel sistema del pacchetto stunnel. Tale pacchetto è già installato come si può vedere in figura 6, la versione presente è la 4-15.2

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 37 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 6: Installazione del Wrapper SSL

2.6.3 -

Configurazione di Stunnel

--sysconfdir=/etc: questo parametro forza la directory di configurazione in /etc invece che /usr/etc. --localstatedir=/var/lib/stunnel: questo parametro fa sì che il processo di installazione crei /var/lib/stunnel/stunnel invece di /usr/var/stunnel. make: questo comando costruisce il pacchetto e, se non si copia un file stunnel.pem nella directory dei sorgenti tools/, richiederà le informazioni necessarie a crearne uno. Assicurarsi di rispondere al prompt

Common Name (FQDN of your server) [localhost]:

con il nome o l'indirizzo IP che si userà per accedere al servizio. Il file contenente tutte le informazioni relative alla configurazione è: /etc/stunnel/stunnel.conf

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 38 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.6.4 -

Informazioni di configurazione

E' necessario creare un file di configurazion /etc/stunnel/stunnel.conf di base usando i seguenti comandi: cat >/etc/stunnel/stunnel.conf << "EOF" # File: /etc/stunnel/stunnel.conf pid = /run/stunnel.pid chroot = /var/lib/stunnel client = no setuid = stunnel setgid = stunnel EOF

Successivamente è necessario aggiungere il servizio che si vuole cifrare al file di configurazione. Il formato è il seguente: [[service]] accept = [hostname:portnumber] connect = [hostname:portnumber]

Se si usa Stunnel per crittografare un demone avviato da [x]inetd si potrebbe avere la necessità di disabilitare questo demone nel file /etc/[x]inetd.conf e abilitare un corrispondente servizio [service]_stunnel. Si potrebbe dover aggiungere anche un campo appropriato in /etc/services. Per avviare automaticamente il demone stunnel quando il sistema è riavviato installare lo script di avvio /etc/rc.d/init.d/stunnel dal pacchetto blfs-bootscripts-6.0.

2.6.5 -

La configurazione usata per Stunnel

client = yes [LDAPS] accept = 127.0.0.1:12345 connect = mailman.fe.infn.it:636

Per far partire il servizio di stunnel: /usr/sbin/stunnel /etc/stunnel/stunnel.conf

Come si può vedere dalle semplici istruzioni riportare qui sopra, stunnel opera un servizio per una connessione sicura di tipo SSL che viene richiesta dal server LDAP di INFN all'indirizzo mailman.fe.infn.it. Si può notare che il tunnel virtuale creato parte da localhost alla porta 12345 e reindirizza il traffico verso mailman.fe.infn.it alla porta 636. Questo concetto è stato schematizzato in figura 7. Questa configurazione associata a quella di GForge, in particolare nel file local.inc, riproposto nel Capitolo 2.9 si può capire come si integrano e interagiscono i due servizi.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 39 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 7: Schema di connessione di stunnel tra la macchina locale e mailman

Tutta la parte relativa alla cifratura e alla creazione di una connessione è stata implementata in questa fase e accontata all'inizio poichè le prime prove sono state effettuate sull'albero di prova locale che non necessitava di particolari configurazioni di sicurezza. Questi servizi invece sono stati poi adoperati in seguito poichè necessari al termine della fase di deingegnerizzazione e di reingegnerizzazione quando si è spostato il banco di prova dall'albero locale all'albero LDAP di INFN.

2.7 - PHP

2.7.1 -

Installazione di PHP:

Il pacchetto PHP che gestisce il linguaggio di scripting HTML integrato non è presente nel nostro sistema e quindi si è provveduto alla sua installazione. Attraverso yumex si è installata la versione 5.16.20.el5 ed è necessaria per avere il supporto al linguaggio php nel server di Apache. E' stato installato, come si può vedere dalla figura Error: Reference source not found, il pacchetto php-cli che contiene il supporto a php per la linea di comando. Si è inoltre installato il pacchetto php-mbstring necessario per maneggiare le stringhe multi-byte, come si può vedere dalla figura 8.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 40 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 8: Installazione del pacchetto php-mbstring

2.7.2 -

Cos'è PHP

PHP è un linguaggio di scripting interpretato, con licenza open source, originariamente concepito per la realizzazione di pagine web dinamiche. Attualmente è utilizzato principalmente per sviluppare applicazioni web lato server ma può essere usato anche per scrivere script a linea di comando o applicazioni standalone con interfaccia grafica. Il suo nome è un acronimo ricorsivo che sta per PHP: Hypertext Preprocessor (PHP: preprocessore di ipertesti). Il linguaggio PHP è nato nel 1994 ad opera del danese Rasmus Lerdorf, PHP era in origine una raccolta di script CGI che permettevano una facile gestione delle pagine personali. Per questo motivo il significato originario dell'acronimo pare fosse Personal Home Page (sull'origine dell'acronimo ci sono tuttora alcuni dubbi, alimentati dallo stesso Lerdorf che ha contribuito volontariamente a generare attorno al nome questo alone di mistero) [12]. A questo punto il linguaggio cominciò a godere di una certa popolarità tra i progetti open source del web, e venne così notato da due giovani programmatori: Zeev Suraski e Andi Gutmans. I due collaborarono nel 1998 con Lerdorf allo sviluppo della terza versione di PHP riscrivendone il motore che fu battezzato Zend da una contrazione dei loro nomi. Le caratteristiche chiave della versione PHP 3.0 frutto del loro lavoro, erano la straordinaria estensibilità, la connettività ai database e il supporto iniziale per il paradigma a oggetti. Verso la fine del 1998 PHP 3.0 era installato su circa il 10% dei server web presenti su Internet. PHP diventò a questo punto talmente maturo da competere con ASP, linguaggio lato server analogo a PHP sviluppato da Microsoft, e cominciò ad essere usato su larga scala. La versione 4 di PHP venne rilasciata nel 2000 e prevedeva notevoli migliorie. Attualmente siamo alla quinta versione, sviluppata da un team di programmatori, Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 41 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

che comprende ancora Lerdorf, oltre a Suraski e Gutmans. La popolarità del linguaggio PHP è in costante crescita grazie alla sua flessibilità: nel Giugno 2001, ha superato il milione di siti che lo utilizzano. Nell'ottobre 2002, più del 45% dei server Apache usavano PHP [13]. Nel gennaio 2005 è stato insignito del titolo di "Programming Language of 2004" dal TIOBE Programming Community Index, classifica che valuta la popolarità dei linguaggi di programmazione sulla base di informazioni raccolte dai motori di ricerca. Nel 2005 la configurazione LAMP (Linux, Apache, MySQL, PHP) supera il 50% del totale dei server sulla rete mondiale. PHP riprende per molti versi la sintassi del C, come peraltro fanno molti linguaggi moderni, e del Perl. È un linguaggio a tipizzazione debole e dalla versione 5 migliora il supporto al paradigma di programmazione ad oggetti. Certi costrutti derivati dal C, come gli operatori fra bit e la gestione di stringhe come array, permettono in alcuni casi di agire a basso livello; tuttavia è fondamentalmente un linguaggio di alto livello, caratteristica questa rafforzata dall'esistenza delle sue moltissime API, oltre 3000 funzioni del nucleo base. PHP è in grado di interfacciarsi a innumerevoli database tra cui MySQL, PostgreSQL, Oracle, Firebird, IBM DB2, Microsoft SQL Server, solo per citarne alcuni, e supporta numerose tecnologie, come XML, SOAP, IMAP, FTP, CORBA. Si integra anche con altri linguaggi/piattaforme quali Java e .NET e si può dire che esista un wrapper per ogni libreria esistente, come CURL, GD, Gettext, GMP, Ming, OpenSSL ed altro [14] [15]. Fornisce un'API specifica per interagire con Apache, nonostante funzioni naturalmente con numerosi server web. È anche ottimamente integrato con il database MySQL, per il quale possiede più di una API. Per questo motivo esiste un'enorme quantità di script e librerie in PHP, disponibili liberamente su Internet. La versione 5, comunque, integra al suo interno un piccolo database embedded, SQLite. Dispone di un archivio chiamato PEAR che mette a disposizione un framework di librerie riusabili per lo sviluppo di applicazioni PHP e di PECL che raccoglie tutte le estensioni conosciute scritte in C. Il PHP permette il passaggio di parametri da una pagina all'altra attraverso tre array di variabili: $_GET, $_POST e $_SESSION. Il primo tipo di parametro viene passato tramite la stringa che compare nella barra dell'indirizzo del browser; il secondo viene passato in background, mentre il terzo rimane persistente durante la sessione.

2.7.3 -

Il file di configurazione PHP.ini

Il file php.ini è un insieme di funzioni e caratteristiche che regolano il funzionamento del protocollo php. Ecco una breve panoramica del significato dei parametri più importarti che fanno parte della configurazione. Alcuni di questi parametri che si vedrà in seguito sono stati modificati e configurati. asp_tags: impostato di default a 'off', permette di aprire e chiudere codice PHP con i tag <% e %>. display_errors: impostato su 'on' mostra gli errori sul browser. Se lo si imposta su 'off' si deve modificare l'attributo che segue. doc_root =: Qui si deve impostare la directory di apache dove sono contenuti i file. error_reporting: è il 'livello' di errori che vengono notificati da PHP. Impostare 'E_ALL' per avere notizia di tutti gli errori. extension: questo parametro indica le estensioni che PHP deve caricare. Si dovrà valorizzarne uno per ogni estensione che ci interessa. Il file php.ini possiede già una lista precompilata di queste estensioni. A questo punto la libreria corrispondente dovrà trovarsi nella cartella che abbiamo indicato con 'extension_dir': in caso contrario si genera un errore all'avvio del web server. extension_dir: indica il percorso sulla nostra macchina della directory dove risiedono le estensioni PHP per l'utilizzo di librerie gd per lavorare con le immagini, le librerie pdf per manipolare documenti pdf, o ancora quando vogliamo collegarci (non attraverso ODBC) a database diversi da MySql, come PostgresSql, Oracle, Sql Server ecc. Tali funzioni richiedono infatti la presenza di apposite librerie. log_errors ed error_log: se display_errors è impostato su 'off' si deve impostare su 'on' questo attributo ed indicare in error_log il nome del file in cui si vuole registrare gli errori con percorso completo. E' importante che il web server abbia il permesso per scrivere su questo file. max_execution_time: impostato di default a 30 secondi, è il tempo limite concesso a PHP per l'esecuzione di uno script, oltrepassato il quale si blocca. Utile se esistono loop su cicli errati. precision: Indica la precisione dei valori in virgola mobile. In default 12, vuol dire che per operazioni con risultati in virgola mobile restituisce fino a 12 valori. register_globals: impostato di default a 'off', non ci permette di utilizzare come variabili globali quelle che arrivano dalla query string o dai moduli inviati dagli utenti. Possiamo avere problemi se si utilizzano script che sono stati concepiti per utilizzare Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 42 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

queste variabili come globali. In questo caso si deve impostarlo a 'on'. session.save_path: Questo parametro indica la cartella nella quale PHP salva i files di sessione: di default impostato '/tmp', può assumere qualunque nome di cartella. short_open_tag: impostato di default a 'on', permette di aprire e chiudere codice PHP con i tag <? e ?>.

2.7.4 -

La configurazione adottata:

Per quanto riguarda la configurazione di PHP del progetto si è adottata la configurazione di default che è funzionante per un web server standard che supporti questo linguaggio. In realtà ci sono state delle piccole modifiche al file che contiene tutti le configurazioni ovvero php.ini ma verranno proposte in seguito nella sezione dedicata alla configurazione particolare per GForge. Qui di seguito il php.ini standard: [PHP] ;;;;;;;;;;; ; WARNING ; ;;;;;;;;;;; ; This is the default settings file for new PHP installations. ; By default, PHP installs itself with a configuration suitable for ; development purposes, and *NOT* for production purposes. ; For several security-oriented considerations that should be taken ; before going online with your site, please consult php.ini-recommended ; and http://php.net/manual/en/security.php. ;;;;;;;;;;;;;;;;;;; ; About this file ; ;;;;;;;;;;;;;;;;;;; ; This file controls many aspects of PHP's behavior. In order for PHP to ; read it, it must be named 'php.ini'. PHP looks for it in the current ; working directory, in the path designated by the environment variable ; PHPRC, and in the path that was defined in compile time (in that order). ; Under Windows, the compile-time path is the Windows directory. The ; path in which the php.ini file is looked for can be overridden using ; the -c argument in command line mode. ; ; The syntax of the file is extremely simple. Whitespace and Lines ; beginning with a semicolon are silently ignored (as you probably guessed). ; Section headers (e.g. [Foo]) are also silently ignored, even though ; they might mean something in the future. ; ; Directives are specified using the following syntax: ; directive = value ; Directive names are *case sensitive* - foo=bar is different from FOO=bar. ; ; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one ; of the INI constants (On, Off, True, False, Yes, No and None) or an expression ; (e.g. E_ALL & ~E_NOTICE), or a quoted string ("foo"). ; ; Expressions in the INI file are limited to bitwise operators and parentheses: ; | bitwise OR ; & bitwise AND ; ~ bitwise NOT ; ! boolean NOT ; ; Boolean flags can be turned on using the values 1, On, True or Yes. ; They can be turned off using the values 0, Off, False or No. ; ; An empty string can be denoted by simply not writing anything after the equal ; sign, or by using the None keyword: ; ; foo = ; sets foo to an empty string ; foo = none ; sets foo to an empty string ; foo = "none" ; sets foo to the string 'none' ; ; If you use constants in your value, and these constants belong to a ; dynamically loaded extension (either a PHP extension or a Zend extension), ; you may only use these constants *after* the line that loads the extension. ; ; All the values in the php.ini-dist file correspond to the builtin ; defaults (that is, if no php.ini is used, or if you delete these lines, ; the builtin defaults will be identical). ;;;;;;;;;;;;;;;;;;;; ; Language Options ; ;;;;;;;;;;;;;;;;;;;; Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 43 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; Enable the PHP scripting language engine under Apache. engine = On ; Allow the <? tag. Otherwise, only <?php and <script> tags are recognized. short_open_tag = Off ; Allow ASP-style <% %> tags. asp_tags = Off ; The number of significant digits displayed in floating point numbers. precision = 14 ; Enforce year 2000 compliance (will cause problems with non-compliant browsers) y2k_compliance = Off ; Output buffering allows you to send header lines (including cookies) even ; after you send body content, at the price of slowing PHP's output layer a ; bit. You can enable output buffering during runtime by calling the output ; buffering functions. You can also enable output buffering for all files by ; setting this directive to On. If you wish to limit the size of the buffer ; to a certain size - you can use a maximum number of bytes instead of 'On', as ; a value for this directive (e.g., output_buffering=4096). output_buffering = Off ; You can redirect all of the output of your scripts to a function. For ; example, if you set output_handler to "ob_gzhandler", output will be ; transparently compressed for browsers that support gzip or deflate encoding. ; Setting an output handler automatically turns on output buffering. output_handler = ; The unserialize callback function will called (with the undefind class' ; name as parameter), if the unserializer finds an undefined class ; which should be instanciated. ; A warning appears if the specified function is not defined, or if the ; function doesn't include/implement the missing class. ; So only set this entry, if you really want to implement such a ; callback-function.unserialize_callback_func= ; Transparent output compression using the zlib library ; Valid values for this option are 'off', 'on', or a specific buffer size ; to be used for compression (default is 4KB) ; ; Note: output_handler must be empty if this is set 'On' !!!! ;zlib.output_compression = Off ; Implicit flush tells PHP to tell the output layer to flush itself ; automatically after every output block. This is equivalent to calling the ; PHP function flush() after each and every call to print() or echo() and each ; and every HTML block. Turning this option on has serious performance ; implications and is generally recommended for debugging purposes only.implicit_flush = Off ; Whether to enable the ability to force arguments to be passed by reference ; at function call time. This method is deprecated and is likely to be ; unsupported in future versions of PHP/Zend. The encouraged method of ; specifying which arguments should be passed by reference is in the function ; declaration. You're encouraged to try and turn this option Off and make ; sure your scripts work properly with it in order to ensure they will work ; with future versions of the language (you will receive a warning each time ; you use this feature, and the argument will be passed by value instead of by ; reference). allow_call_time_pass_reference = On ; Safe Mode ; safe_mode = Off ; By default, Safe Mode does a UID compare check when ; opening files. If you want to relax this to a GID compare, ; then turn on safe_mode_gid. safe_mode_gid = Off ; When safe_mode is on, UID/GID checks are bypassed when ; including files from this directory and its subdirectories. ; (directory must also be in include_path or full path must ; be used when including) safe_mode_include_dir = ; When safe_mode is on, only executables located in the safe_mode_exec_dir ; will be allowed to be executed via the exec family of functions.safe_mode_exec_dir = ; open_basedir, if set, limits all file operations to the defined directory ; and below. This directive makes most sense if used in a per-directory ; or per-virtualhost web server configuration file. ; ;open_basedir = ; Setting certain environment variables may be a potential security breach. ; This directive contains a comma-delimited list of prefixes. In Safe Mode, ; the user may only alter environment variables whose names begin with the ; prefixes supplied here. By default, users will only be able to set ; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR). ;

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 44 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; Note: If this directive is empty, PHP will let the user modify ANY ; environment variable! safe_mode_allowed_env_vars = PHP_ ; This directive contains a comma-delimited list of environment variables that ; the end user won't be able to change using putenv(). These variables will be ; protected even if safe_mode_allowed_env_vars is set to allow to change them. safe_mode_protected_env_vars = LD_LIBRARY_PATH ; This directive allows you to disable certain functions for security reasons. ; It receives a comma-delimited list of function names. This directive is ; *NOT* affected by whether Safe Mode is turned On or Off. disable_functions = ; Colors for Syntax Highlighting mode. Anything that's acceptable in ; <font color="??????"> would work. highlight.string = #CC0000 highlight.comment = #FF9900 highlight.keyword = #006600 highlight.bg = #FFFFFF highlight.default = #0000CC highlight.html = #000000 ; ; Misc ; ; Decides whether PHP may expose the fact that it is installed on the server ; (e.g. by adding its signature to the Web server header). It is no security ; threat in any way, but it makes it possible to determine whether you use PHP ; on your server or not. expose_php = On ;;;;;;;;;;;;;;;;;;; ; Resource Limits ; ;;;;;;;;;;;;;;;;;;; max_execution_time = 30 ; Maximum execution time of each script, in seconds memory_limit = 32M ; Maximum amount of memory a script may consume (8MB) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Error handling and logging ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; error_reporting is a bit-field. Or each number up to get desired error ; reporting level ; E_ALL - All errors and warnings ; E_ERROR - fatal run-time errors ; E_WARNING - run-time warnings (non-fatal errors) ; E_PARSE - compile-time parse errors ; E_NOTICE - run-time notices (these are warnings which often result ; from a bug in your code, but it's possible that it was ; intentional (e.g., using an uninitialized variable and ; relying on the fact it's automatically initialized to an ; empty string) ; E_CORE_ERROR - fatal errors that occur during PHP's initial startup ; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's ; initial startup ; E_COMPILE_ERROR - fatal compile-time errors ; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) ; E_USER_ERROR - user-generated error message ; E_USER_WARNING - user-generated warning message ; E_USER_NOTICE - user-generated notice message ; ; Examples: ; ; - Show all errors, except for notices ; error_reporting = E_ALL & ~E_NOTICE ; ; - Show only errors ; ;error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR ; ; - Show all errors except for notices ; ;error_reporting = E_ERROR ;error_reporting = E_ALL ; Print out errors (as a part of the output). For production web sites, ; you're strongly encouraged to turn this feature off, and use error logging ; instead (see below). Keeping display_errors enabled on a production web site ; may reveal security information to end users, such as file paths on your Web ; server, your database schema or other information. ;display_errors = Off display_errors = On ; Even when display_errors is on, errors that occur during PHP's startup

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 45 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; sequence are not displayed. It's strongly recommended to keep ; display_startup_errors off, except for when debugging. display_startup_errors = Off ; Log errors into a log file (server-specific log, stderr, or error_log (below)) ; As stated above, you're strongly advised to use error logging in place of ; error displaying on production web sites. log_errors = On ; Store the last error/warning message in $php_errormsg (boolean). track_errors = Off ; Disable the inclusion of HTML tags in error messages. ;html_errors = Off ; String to output before an error message. ;error_prepend_string = "<font color=ff0000>" ; String to output after an error message. ;error_append_string = "</font>" ; Log errors to specified file. ;error_log = filename ; Log errors to syslog (Event Log on NT, not valid in Windows 95). ;error_log = syslog ; Warn if the + operator is used with strings. warn_plus_overloading = Off ;;;;;;;;;;;;;;;;; ; Data Handling ; ;;;;;;;;;;;;;;;;; ; Note - track_vars is ALWAYS enabled as of PHP 4.0.3 ; The separator used in PHP generated URLs to separate arguments. ; Default is "&". ;arg_separator.output = "&amp;" ; List of separator(s) used by PHP to parse input URLs into variables. ; Default is "&". ; NOTE: Every character in this directive is considered as separator! ;arg_separator.input = ";&" ; This directive describes the order in which PHP registers GET, POST, Cookie, ; Environment and Built-in variables (G, P, C, E & S respectively, often ; referred to as EGPCS or GPC). Registration is done from left to right, newer ; values override older values. variables_order = "EGPCS" ; Whether or not to register the EGPCS variables as global variables. You may ; want to turn this off if you don't want to clutter your scripts' global scope ; with user data. This makes most sense when coupled with track_vars - in which ; case you can access all of the GPC variables through the $HTTP_*_VARS[], ; variables. ; ; You should do your best to write your scripts so that they do not require ; register_globals to be on; Using form variables as globals can easily lead ; to possible security problems, if the code is not very well thought of.register_globals = On ; This directive tells PHP whether to declare the argv&argc variables (that ; would contain the GET information). If you don't use these variables, you ; should turn it off for increased performance.register_argc_argv = On ; Maximum size of POST data that PHP will accept. post_max_size = 8M ; This directive is deprecated. Use variables_order instead. gpc_order = "GPC" ; Magic quotes ; ; Magic quotes for incoming GET/POST/Cookie data. magic_quotes_gpc = On ; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. magic_quotes_runtime = Off ; Use Sybase-style magic quotes (escape ' with '' instead of \'). magic_quotes_sybase = Off ; Automatically add files before or after any PHP document. auto_prepend_file = auto_append_file = ; As of 4.0b4, PHP always outputs a character encoding by default in ; the Content-type: header. To disable sending of the charset, simply ; set it to be empty. ; PHP's built-in default is text/html default_mimetype = "text/html" ;default_charset = "iso-8859-1" default_charset = "UTF-8" ; Always populate the $HTTP_RAW_POST_DATA variable. ;always_populate_raw_post_data = On ;;;;;;;;;;;;;;;;;;;;;;;;; ; Paths and Directories ; ;;;;;;;;;;;;;;;;;;;;;;;;;

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 46 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; UNIX: "/path1:/path2" ;include_path = ".:/php/includes"include_path=".:/var/www/gforge:/var/www/gforge/common/include:/var/www/gf orge/www/include:/var/www/gforge/etc" ; ; Windows: "\path1;\path2" ;include_path = ".;c:\php\includes" ; The root of the PHP pages, used only if nonempty. ; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root ; if you are running php as a CGI under any web server (other than IIS) ; see documentation for security issues. The alternate is to use the ; cgi.force_redirect configuration below doc_root = ; The directory under which PHP opens the script using /~usernamem used only ; if nonempty. user_dir = ; Directory in which the loadable extensions (modules) reside. ; extension_dir = /usr/lib/php extension_dir = /usr/lib/php/modules ; Whether or not to enable the dl() function. The dl() function does NOT work ; properly in multithreaded servers, such as IIS or Zeus, and is automatically ; disabled on them. enable_dl = On ; cgi.force_redirect is necessary to provide security running PHP as a CGI under ; most web servers. Left undefined, PHP turns this on by default. You can ; turn it off here AT YOUR OWN RISK ; **You CAN safely turn this off for IIS, in fact, you MUST.** ; cgi.force_redirect = 1 ; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape ; (iPlanet) web servers, you MAY need to set an environment variable name that PHP ; will look for to know it is OK to continue execution. Setting this variable MAY ; cause security issues, KNOW WHAT YOU ARE DOING FIRST. ; cgi.redirect_status_env = ; ;;;;;;;;;;;;;;;; ; File Uploads ; ;;;;;;;;;;;;;;;; ; Whether to allow HTTP file uploads. file_uploads = On ; Temporary directory for HTTP uploaded files (will use system default if not ; specified). ;upload_tmp_dir = ; Maximum allowed size for uploaded files. upload_max_filesize = 2M ;;;;;;;;;;;;;;;;;; ; Fopen wrappers ; ;;;;;;;;;;;;;;;;;; ; Whether to allow the treatment of URLs (like http:// or ftp://) as files. allow_url_fopen = On ; Define the anonymous ftp password (your email address) ;from="john@doe.com" ;;;;;;;;;;;;;;;;;;;;;; ; Dynamic Extensions ; ;;;;;;;;;;;;;;;;;;;;;; ; ; If you wish to have an extension loaded automatically, use the following ; syntax: ; extension=modulename.extension ; ; For example, on Windows: ; ; extension=msql.dll ; ; ... or under UNIX: ; ; extension=msql.so ; ; Note that it should be the name of the module only; no directory information ; needs to go here. Specify the location of the extension with the ; extension_dir directive above. ;Windows Extensions ;Note that MySQL and ODBC support is now built in, so no dll is needed for it. ; ;extension=php_bz2.dll ;extension=php_ctype.dll ;extension=php_cpdf.dll ;extension=php_curl.dll ;extension=php_cybercash.dll

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 47 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

;extension=php_db.dll ;extension=php_dba.dll ;extension=php_dbase.dll ;extension=php_dbx.dll ;extension=php_domxml.dll ;extension=php_dotnet.dll ;extension=php_exif.dll ;extension=php_fbsql.dll ;extension=php_fdf.dll ;extension=php_filepro.dll ;extension=php_gd.dll ;extension=php_gettext.dll ;extension=php_hyperwave.dll ;extension=php_iconv.dll ;extension=php_ifx.dll ;extension=php_iisfunc.dll ;extension=php_imap.dll ;extension=php_ingres.dll ;extension=php_interbase.dll ;extension=php_java.dll ;extension=php_ldap.dll ;extension=php_mbstring.dll ;extension=php_mcrypt.dll ;extension=php_mhash.dll ;extension=php_ming.dll ;extension=php_mssql.dll ;extension=php_mysql.dll ;extension=php_oci8.dll ;extension=php_odbc.dll ;extension=php_openssl.dll ;extension=php_oracle.dll ;extension=php_pdf.dll ;extension=php_pgsql.dll ;extension=php_printer.dll ;extension=php_sablot.dll ;extension=php_shmop.dll ;extension=php_snmp.dll ;extension=php_sockets.dll ;extension=php_sybase_ct.dll ;extension=php_tokenizer.dll ;extension=php_w32api.dl ;extension=php_xslt.dll ;extension=php_yaz.dll ;extension=php_zlib.dll ;Linux world ; ;extension=imap.so ;extension=ldap.so ;extension=mysql.so ;extension=odbc.so ;extension=pgsql.so ;extension=snmp.so ;extension=dbg.so ;;;;;;;;;;;;;;;;;;; ; Module Settings ; ;;;;;;;;;;;;;;;;;;; [debugger] debugger.enabled =

debugger.profiler_enabled debugger.JIT_enabled

= =

debugger.JIT_port

=

debugger.JIT_host

=

debugger.JIT_level

=

False

; enables dbg extension ; May cause problems when ; being acessed through a ; firewall, if the debugging ; port isn't allowed through ; hense it is off by default True ; enables dbg profiler True ; enables JIT sessions ; (auto-activated) 7869 ; default port to be used this ; should be the same as the ; port number opened by the ; dbg listener clienthost ; either real client IP or ; a keyword "clienthost" 3 ; JIT activation level ; 0 - disables JIT, ; 1 – E_CORE, ; 2 - E_CORE | E_ERROR | ; E_PARSE |

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 48 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; ; ; ; ;

E_COMPILE_ERROR | E_USER_ERROR 3 - E_ALL & ~(E_NOTICE | E_USER_NOTICE) 4 – E_ALL

[Syslog] ; Whether or not to define the various syslog variables (e.g. $LOG_PID, ; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In ; runtime, you can define these variables by calling define_syslog_variables(). define_syslog_variables = Off [mail function] ; For Win32 only. SMTP = localhost ; For Win32 only. sendmail_from = me@localhost.com ; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). sendmail_path = /usr/sbin/sendmail -t -i [Java] ;java.class.path = .\php_java.jar ;java.home = c:\jdk ;java.library = c:\jdk\jre\bin\hotspot\jvm.dll ;java.library.path = .\ [SQL] sql.safe_mode = Off [ODBC] ;odbc.default_db = Not yet implemented ;odbc.default_user = Not yet implemented ;odbc.default_pw = Not yet implemented ; Allow or prevent persistent links. odbc.allow_persistent = On ; Check that a connection is still valid before reuse. odbc.check_persistent = On ; Maximum number of persistent links. -1 means no limit. odbc.max_persistent = -1 ; Maximum number of links (persistent + non-persistent). -1 means no limit. odbc.max_links = -1 ; Handling of LONG fields. Returns number of bytes to variables. 0 means ; passthru. odbc.defaultlrl = 4096 ; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. ; See the documentation on odbc_binmode and odbc_longreadlen for an explanation ; of uodbc.defaultlrl and uodbc.defaultbinmode odbc.defaultbinmode = 1 [MySQL] ; Allow or prevent persistent links. mysql.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. mysql.max_persistent = -1 ; Maximum number of links (persistent + non-persistent). -1 means no limit. mysql.max_links = -1 ; Default port number for mysql_connect(). If unset, mysql_connect() will use ; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the ; compile-time value defined MYSQL_PORT (in that order). Win32 will only look ; at MYSQL_PORT. mysql.default_port = ; Default socket name for local MySQL connects. If empty, uses the built-in ; MySQL defaults. mysql.default_socket = ; Default host for mysql_connect() (doesn't apply in safe mode). mysql.default_host = ; Default user for mysql_connect() (doesn't apply in safe mode). mysql.default_user = ; Default password for mysql_connect() (doesn't apply in safe mode). ; Note that this is generally a *bad* idea to store passwords in this file. ; *Any* user with PHP access can run 'echo cfg_get_var("mysql.default_password") ; and reveal this password! And of course, any users with read access to this ; file will be able to reveal the password as well. mysql.default_password = [mSQL] ; Allow or prevent persistent links. msql.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. msql.max_persistent = -1 ; Maximum number of links (persistent+non persistent). -1 means no limit. Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 49 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

msql.max_links = [PostgresSQL]; Allow or prevent persistent links. pgsql.allow_persistent = On ; Detect broken persistent links always with pg_pconnect(). Need a little overhead. pgsql.auto_reset_persistent = Off ; Maximum number of persistent links. -1 means no limit. pgsql.max_persistent = -1 ; Maximum number of links (persistent+non persistent). -1 means no limit. pgsql.max_links = -1 [Sybase] ; Allow or prevent persistent links. sybase.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. sybase.max_persistent = -1 ; Maximum number of links (persistent + non-persistent). -1 means no limit. sybase.max_links = -1 ;sybase.interface_file = "/usr/sybase/interfaces" ; Minimum error severity to display. sybase.min_error_severity = 10 ; Minimum message severity to display. sybase.min_message_severity = 10 ; Compatability mode with old versions of PHP 3.0. ; If on, this will cause PHP to automatically assign types to results according ; to their Sybase type, instead of treating them all as strings. This ; compatability mode will probably not stay around forever, so try applying ; whatever necessary changes to your code, and turn it off. sybase.compatability_mode = Off [Sybase-CT] ; Allow or prevent persistent links. sybct.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. sybct.max_persistent = -1 ; Maximum number of links (persistent + non-persistent). -1 means no limit. sybct.max_links = -1 ; Minimum server message severity to display. sybct.min_server_severity = 10 ; Minimum client message severity to display. sybct.min_client_severity = 10 [bcmath] ; Number of decimal digits for all bcmath functions. bcmath.scale = 0 [browscap] ;browscap = extra/browscap.ini [Informix] ; Default host for ifx_connect() (doesn't apply in safe mode). ifx.default_host = ; Default user for ifx_connect() (doesn't apply in safe mode). ifx.default_user = ; Default password for ifx_connect() (doesn't apply in safe mode). ifx.default_password = ; Allow or prevent persistent links. ifx.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. ifx.max_persistent = -1 ; Maximum number of links (persistent + non-persistent). -1 means no limit. ifx.max_links = -1 ; If on, select statements return the contents of a text blob instead of its id. ifx.textasvarchar = 0 ; If on, select statements return the contents of a byte blob instead of its id. ifx.byteasvarchar = 0 ; Trailing blanks are stripped from fixed-length char columns. May help the ; life of Informix SE users. ifx.charasvarchar = 0 ; If on, the contents of text and byte blobs are dumped to a file instead of ; keeping them in memory.ifx.blobinfile = 0 ; NULL's are returned as empty strings, unless this is set to 1. In that case, ; NULL's are returned as string 'NULL'. ifx.nullformat = 0 [Session] ; Handler used to store/retrieve data. session.save_handler = files ; Argument passed to save_handler. In the case of files, this is the path ; where data files are stored. Note: Windows users have to change this ; variable in order to use PHP's session functions. session.save_path = /tmp ; Whether to use cookies. session.use_cookies = 1

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 50 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; Name of the session (used as cookie name). session.name = PHPSESSID ; Initialize session on request startup. session.auto_start = 0 ; Lifetime in seconds of cookie or, if 0, until browser is restarted. session.cookie_lifetime = 0 ; The path for which the cookie is valid. session.cookie_path = / ; The domain for which the cookie is valid. session.cookie_domain = ; Handler used to serialize data. php is the standard serializer of PHP. session.serialize_handler = php ; Percentual probability that the 'garbage collection' process is started ; on every session initialization. session.gc_probability = 1 ; After this number of seconds, stored data will be seen as 'garbage' and ; cleaned up by the garbage collection process. session.gc_maxlifetime = 1440 ; Check HTTP Referer to invalidate externally stored URLs containing ids. ; HTTP_REFERER has to contain this substring for the session to be ; considered as valid. session.referer_check = ; How many bytes to read from the file. session.entropy_length = 0 ; Specified here to create the session id. session.entropy_file = ;session.entropy_length = 16 ;session.entropy_file = /dev/urandom ; Set to {nocache,private,public} to determine HTTP caching aspects. session.cache_limiter = nocache ; Document expires after n minutes. session.cache_expire = 180 ; use transient sid support if enabled by compiling with â&#x20AC;&#x201C;enable-trans-sid. session.use_trans_sid = 1 url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" [MSSQL] ; Allow or prevent persistent links. mssql.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. mssql.max_persistent = -1 ; Maximum number of links (persistent+non persistent). -1 means no limit. mssql.max_links = -1 ; Minimum error severity to display. mssql.min_error_severity = 10 ; Minimum message severity to display. mssql.min_message_severity = 10 ; Compatability mode with old versions of PHP 3.0. mssql.compatability_mode = Off ; Valid range 0 - 2147483647. Default = 4096. ;mssql.textlimit = 4096 ; Valid range 0 - 2147483647. Default = 4096. ;mssql.textsize = 4096 ; Limits the number of records in each batch. 0 = all records in one batch. ;mssql.batchsize = 0 [Assertion] ; Assert(expr); active by default. ;assert.active = On ; Issue a PHP warning for each failed assertion. ;assert.warning = On ; Don't bail out by default. ;assert.bail = Off ; User-function to be called if an assertion fails. ;assert.callback = 0 ; Eval the expression with current error_reporting(). Set to true if you want ; error_reporting(0) around the eval(). ;assert.quiet_eval = 0 [Ingres II] ; Allow or prevent persistent links. ingres.allow_persistent = On ; Maximum number of persistent links. -1 means no limit. ingres.max_persistent = -1 ; Maximum number of links, including persistents. -1 means no limit. ingres.max_links = -1 ; Default database (format: [node_id::]dbname[/srv_class]). ingres.default_database = ; Default user. ingres.default_user =

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 51 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

; Default password. ingres.default_password = [Verisign Payflow Pro] ; Default Payflow Pro server. pfpro.defaulthost = "test-payflow.verisign.com" ; Default port to connect to. pfpro.defaultport = 443 ; Default timeout in seconds. pfpro.defaulttimeout = 30 ; Default proxy IP address (if required). ;pfpro.proxyaddress = ; Default proxy port. ;pfpro.proxyport = ; Default proxy logon. ;pfpro.proxylogon = ; Default proxy password. ;pfpro.proxypassword = [Sockets] ; Use the system read() function instead of the php_read() wrapper. sockets.use_system_read = On [com] ; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs ;com.typelib_file = ; allow Distributed-COM calls ;com.allow_dcom = true ; autoregister constants of a components typlib on com_load() ;com.autoregister_typelib = true ; register constants casesensitive ;com.autoregister_casesensitive = false ; show warnings on duplicate constat registrations ;com.autoregister_verbose = true [Printer] ;printer.default_printer = "" [mbstring] ;mbstring.internal_encoding = EUC-JP ;mbstring.http_input = auto ;mbstring.http_output = SJIS ;mbstring.detect_order = auto ;mbstring.substitute_character = none; [FrontBase] ;fbsql.allow_persistent = On ;fbsql.autocommit = On ;fbsql.default_database = ;fbsql.default_database_password = ;fbsql.default_host = ;fbsql.default_password = ;fbsql.default_user = "_SYSTEM" ;fbsql.generate_warnings = Off ;fbsql.max_connections = 128 ;fbsql.max_links = 128 ;fbsql.max_persistent = -1 ;fbsql.max_results = 128 ;fbsql.batchSize = 1000 ; Local Variables: ; tab-width: 4 ; End: - Il file di configurazione php.ini -

2.8 - Il pacchetto mod_dav_svn Il pacchetto mod_dav_svn non è presente nella distribuzione usata e quindi si è proceduto alla sua installazione. Sempre con l'utilizzo di yumex si è installata la versione di mod_dav_svn 1.4.2-2-el5 con la dipendenza richiesta di subversion, come si può vedere dalla figura 9. Mod_dav_svn è un pacchetto necessario per il server Apache per il server Subversion. Subversion (noto anche come svn, che è il nome del suo client a riga di comando) è un sistema di controllo versione progettato da CollabNet Inc. con lo scopo di essere il naturale successore di CVS, oramai considerato superato. E' un software Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 52 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

open source per il controllo della versione. Utilizzando Subversion è possibile registrare la storia del codice sorgente e dei documenti. È in grado di gestire l'evolversi di file e directory nel tempo. Nel repository centrale viene posizionato un albero di tutti i file. Il repository è come un server di file, tranne per il fatto che si ricorda qualsiasi cambiamento apportato.

Figura 9: Installazione di mod_dav_svn Una volta installato il pacchetto è necessario editare il file httpd.conf di apache e aggiungere una riga al LoadModule: vim /etc/httpd/conf/httpd.conf

Nella sezione LoadModule si devono inserire queste due righe in modo che il pacchetto mod_dav_svn venga caricato da httpd: LoadModule dav_svn_module LoadModule authz_svn_module

modules/mod_dav_svn.so modules/mod_authz_svn.so

Ora si deve creare una autenticazione HTTP a file e la si può ottenere con il seguente comando: htpasswd -cm /etc/svn-auth-file <username>

Ora si devono aggiungere nuovi utenti al file: htpasswd -m /etc/svn-auth-file <username>

Il file httpd.conf viene inoltre modificato con l'aggiunta di questa sezione per indicare il repository svn: <VirtualHost *:80> ServerName svn.prova.it <Location /> DAV svn SVNPath /var/www/apps/prova/repos Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 53 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

AuthType Basic AuthName "Authorization Realm" AuthUserFile /etc/absolute-auth-file Require valid-user </Location> </VirtualHost>

Ora si deve riavviare apache con il seguente comando: sudo /etc/init.d/httpd restart

2.9 - Cos'è Gforge? GForge è un tool software gratuito rilasciato sotto licenza GNU GPL in grado di gestire il management di progetti software e lo sviluppo collaborativo. GForge prevede l'hosting del software e di tutte le modifiche realizzate e supporta i servizi CVS e Subversion oltre a bug tracking e messaggistica. Tutte le informazioni di accesso vengono unificate in ruoli, questo evita all'amministratoe di dover impostare uno per uno i permessi.I ruoli predefiniti sono: Amministratore, Sviluppatore Senior, Sviluppatore Junior, Autore di documentazione, Supporto Tecnico. Per gli utenti non registrati esiste un ruolo generico chiamato "Osservatore". GForge offre un supporto completo del protocollo WebDAV che permette una più facile navigazione e gestione dei progetti attraverso una struttura a “directory”. Come detto nell'introduzione GForge rappresenterà il cuore del progetto e il tutto ruoterà attorno a questo applicativo.

2.9.1 -

Installazione di GForge

Dopo aver scaricato dal sito www.gforge.org l'ultimo release stabile, che era la versione 4.5.19 si è scompattato il tutto con privilegi da root nella directory /var/www/gforge con i comandi: bzip2 -dc gforge-4.5.tar.bz2 | tar xvf mv gforge-4.5 /var/www/gforge

Il download del pacchetto è inoltre disponibile attraverso CVS con i seguenti comandi: CVSROOT=:pserver:anonymous@cvs.gforge.org:/cvsroot/gforge; export CVSROOT cvs checkout -P -rBranch_4_5 gforge mkdir gforge/plugins cd gforge/plugins cvs checkout -P -rBranch_4_5 gforge-plugin-scmcvs ln -s gforge-plugin-scmcvs scmcvs cvs checkout -P -rBranch_4_5 gforge-plugin-scmsvn ln -s gforge-plugin-scmsvn scmsvn cvs checkout -P -rBranch_4_5 gforge-plugin-cvstracker ln -s gforge-plugin-cvstracker cvstracker cd ../www mkdir plugins cd plugins ln -s ../../plugins/scmcvs/www scmcvs ln -s ../../plugins/scmsvn/www scmsvn ln -s ../../plugins/cvstracker/www cvstracker

Per eseguire l'update all'ultima versione disponibile invece: cd gforge cvs -q update -Pd

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 54 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

cd plugins/gforge-plugin-scmcvs cvs -q update -Pd cd ../gforge-plugin-scmsvn cvs -q update -Pd cd ../gforge-plugin-cvstracker cvs -q update -Pd

Nella distribuzione di Gforge è possibile trovare in etc/ il file local.inc.example che è la base per la configurazione del pacchetto e bisogna ricopiarlo dopo averlo rinominato in /etc/gforge/local.inc. In questo file vengono gestiti i setting di configurazione di Gforge. Di solito questa cartella bisogna renderla leggibile dal webserver apache che deve potervi accedere. Per fare ciò questi di seguito sono i comandi: mkdir /etc/gforge chown root: /etc/gforge chmod 755 /etc/gforge cp /var/www/gforge/etc/local.inc.example /etc/gforge/local.inc chown apache:apache /etc/gforge/local.inc chmod 600 /etc/gforge/local.inc

L'utente apache, come si vede qui sopra è appunto apache con gruppo apache.

2.9.2 -

Configurazione di GForge

Per la configurazione di Gforge bisogna, come detto precedentemente, editare il file: /etc/gforge/local.inc e configurare i seguenti parametri: $sys_dbhost="localhost" $sys_dbname="gforge" $sys_dbuser="gforge" $sys_dbpasswd="gforge-password" $sys_urlroot="/var/www/gforge/www/"; $sys_themeroot="/var/www/gforge/www/themes/"; $sys_plugins_path="/var/www/gforge/plugins/";

Inoltre anche il parametro $sys_default_domain che contiene il nome del dominio del server di questo servizio, ad esempio: gforge.company.com. Nel caso specifico è stato indicato localhost poichè il server è la macchina stessa di lavoro.

2.9.3 -

Configurazione del Database PostgreSQL

Se il database non è inizializzato bisogna creare il cluster database di PostgreSQL con i seguenti comandi: # su - postgres $ initdb

E' necessario porre attenzione poichè questo comando inizializzerà il cluster database cancellando così ogni dato presente. L'utente postgres di postgreSQL è usato solo durante l'installazione. Di solito, questo utente può connettersi via socket UNIX e senza password: su - postgres psql template1

Se la connessione fallisce bisogna abilitare l'accesso al database editando il file pg_hba.conf contenuto in /var/lib/ pgsql/data/ # # # # #

PostgreSQL Client Authentication Configuration File =================================================== Refer to the PostgreSQL Administrator's Guide, chapter "Client Authentication" for a complete description. A short synopsis Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 55 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

# follows. # # This file controls: which hosts are allowed to connect, how clients # are authenticated, which PostgreSQL user names they can use, which # databases they can access. Records take one of these forms: # # local DATABASE USER METHOD [OPTION] # host DATABASE USER CIDR-ADDRESS METHOD [OPTION] # hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION] # hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION] # # (The uppercase items must be replaced by actual values.) # # The first field is the connection type: "local" is a Unix-domain socket, # "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an # SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket. # # DATABASE can be "all", "sameuser", "samerole", a database name, or # a comma-separated list thereof. # # USER can be "all", a user name, a group name prefixed with "+", or # a comma-separated list thereof. In both the DATABASE and USER fields # you can also write a file name prefixed with "@" to include names from # a separate file. # # CIDR-ADDRESS specifies the set of hosts the record matches. # It is made up of an IP address and a CIDR mask that is an integer # (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies # the number of significant bits in the mask. Alternatively, you can write # an IP address and netmask in separate columns to specify the set of hosts. # # METHOD can be "trust", "reject", "md5", "crypt", "password", # "krb5", "ident", or "pam". Note that "password" sends passwords # in clear text; "md5" is preferred since it sends encrypted passwords. # # OPTION is the ident map or the name of the PAM service, depending on METHOD. # # Database and user names containing spaces, commas, quotes and other special # characters must be quoted. Quoting one of the keywords "all", "sameuser" or # "samerole" makes the name lose its special character, and just match a # database or username with that name. # # This file is read on server startup and when the postmaster receives # a SIGHUP signal. If you edit the file on a running system, you have # to SIGHUP the postmaster for the changes to take effect. You can use # "pg_ctl reload" to do that. # Put your actual configuration here # ---------------------------------# # If you want to allow non-local connections, you need to add more # "host" records. In that case you will also need to make PostgreSQL listen # on a non-local interface via the listen_addresses configuration parameter, # or via the -i or -h command line switches. # # TYPE DATABASE USER CIDR-ADDRESS METHOD # "local" is for Unix domain socket connections only local all all ident sameuser # IPv4 local connections: host drupaldatabase apache 127.0.0.1/32 trust host drupaldatabase drupaluser 127.0.0.1/32 trust host gforge gforge 127.0.0.1/32 trust host all all 127.0.0.1/32 ident sameuser # IPv6 local connections: host all all ::1/128 ident sameuser local all postgres ident sameuser – Contenuto del file pg_hba.conf -

Nell'ultima riga qui sopra, si può notare che è stata inserita la seguente stringa: local all postgres ident sameuser

che risulta necessaria per abilitare a tutti gli utenti la possibilità di connettersi al database. Gforge, per connettersi al database PostgreSQL, utilizza l'utente gforge e accede con autenticazione al database che verrà creato di seguito e s chiamerà gforge. Questi parametri sono stati editati nel file local.inc Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 56 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Inoltre bisogna assicurarsi che il file pg_hba.conf contenga la seguente stringa per abilitare l'utente gforge ad accedere al database: host gforge gforge 127.0.0.1 255.255.255.255 md5

Questo comando assume che l'utente di Gforge accederà sempre al database PostgreSQL che si trova in localhost. Se il server si trovasse su di un altro indirizzo IP allora bisogna modificare questa linea di conseguenza. Inoltre è necessario configurare il file postgresql.conf abilitando la connessione TCP/IP al database mediante il seguente parametro: tcpip_socket = true

Dopo aver editato questi parametri è necessario riavviare il servizio PostgreSQL con il comando: service postgresql restart

2.9.4 -

Creazione del Database per Gforge

Con la seguente procedura si andrà a creare il database sul quale GForge si appoggerà. In questo database si andranno a memorizzare tutte le informazioni relative allo sviluppo e alla modifica del software oltre a quelle relative alla messaggistica interna, agli utenti, al bugtracking e molto altro. Innanzitutto bisogna creare l'utente per il servizio che si chiamerà gforge e il database che gestisce l'applicativo in questione che anche lui avrà come nome gforge.

2.9.5 -

Creazione dell'utente gforge:

Qui sotto i comandi per creare l'utente gforge con relativa password: # su - postgres $ psql template1 template1=# CREATE USER gforge NOCREATEUSER NOCREATEDB template1-# PASSWORD ’gforge-password’;

Per creare il database gforge invece: template1=# CREATE DATABASE gforge OWNER gforge ENCODING ’UNICODE’;

Si aggiungono poi i supporti PL/pgSQL con i comandi: # su - postgres $ createlang p pgsql gforge; E per concludere si installa il database: $ cd /var/www/gforge/db $ psql -a -U gforge -W -h localhost -f gforge.sql gforge &> /tmp/gforge.sql.log

2.9.6 -

Configurazione di PHP per GForge

E' necessario configurare PHP, in particolare il file di configurazione php.ini andando ad editare i seguenti parametri:

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 57 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

register_globals = On magic_quotes_gpc = On file_uploads = On include_path=".:/var/www/gforge:/var/www/gforge/www/include:/etc/gforge"

2.9.7 -

Configurazione di Apache per Gforge

Nei parametri $sys_apache_user e $sys_apache_group bisogna indicare rispettivamente quale utente e gruppo viene usato dal web server apache. Nel caso in esame è user=apache e gruppo=apache. Bisogna quindi editare ancora una volta il file httpd.conf per adattarlo e configurarlo per GForge. E' possibile usare il file etc/gforgehttpd.conf.example come template. Qui di seguito sono indicati i passi per creare un virtualhost di Apache per Gforge, ad esempio NameVirtualHost 1.2.3.4 <VirtualHost 1.2.3.4> # Put the rest of the directives here. </VirtualHost>

Il resto delle direttive da inserire nel virtualhost sono le seguenti: ServerName gforge.company.com

oppure come nel caso in esame: ServerAdmin webmaster@gforge.company.com

oppure come nel nostro la mail del webmaster temporaneo: matteo.serafin@student.unife.it

Andiamo poi a definire sempre nello stesso file di configurazione i file relativi al log: CustomLog "/var/log/gforge/gforge/access.log" combined ErrorLog "/var/log/gforge/gforge/error.log"

Se si vuole utilizzare la rotazione del log, ovvero un log per ogni giorno ecco i comandi: CustomLog "|/usr/bin/cronolog /var/log/gforge/gforge/%Y/%m/%d/access.log" combined ErrorLog "|/usr/bin/cronolog /var/log/gforge/gforge/%Y/%m/%d/error.log"

Si indica poi il DocumentRoot, ovvero la cartella dove risiedono le pagine: DocumentRoot "/var/www/gforge/www" <Directory "/var/www/gforge/www"> Options FollowSymLinks AllowOverride None Order allow,deny Allow from all ErrorDocument 404 /404.php </Directory>

2.9.8 -

Configurazione di PHP per Apache:

Bisogna assicurarsi che i moduli php vengano caricati, quindi le seguenti righe devono essere presenti: LoadModule php_module modules/libphp5.so AddModule mod_php.c AddType application/x-httpd-php .php <Location /projects> ForceType application/x-httpd-php </Location> <Location /users> ForceType application/x-httpd-php </Location>

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 58 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

<Files *.php> SetOutputFilter PHP SetInputFilter PHP AcceptPathInfo On LimitRequestBody 2097152 </Files> <Files projects> SetOutputFilter PHP SetInputFilter PHP AcceptPathInfo on </Files> <Files users> SetOutputFilter PHP SetInputFilter PHP AcceptPathInfo on </Files>

Per rendere effettivi i cambiamenti bisogna far ripartire apache. service httpd restart

2.9.9 -

Creazione dell'utente Amministratore di GForge.

L'amministratore del sito può essere chiunque abbia nella tabella “admin” con “group_id” = 1 e il campo di admin_flags con valore 'A'. L'utente deve essere già presente, quindi dopo aver registrato un nuovo utente che poi diverrà admin per il pacchetto Gforge bisogna fare l'update di questo parametro. Qui di seguito i passi per la creazione di un nuovo utente: 1. Connettersi a Gforge e registrare un nuovo account 2. Inserire una email valida per poter poi confermare la creazione dell'account.Una volta eseguita la procedura per la creazione di uno nuovo utente si riceverà una mail di sistema da Gforge, per abilitare l'utente si dovrà cliccare sul link presente all'interno. Si è scelto di avere come amministratore di gforge l'utente con username “gforge-admin”, quindi si è creato come descritto precedentemente un utente con queste carateristiche. Si è poi inserita una mail a nostra disposizione per confermare la creazione. Questa è la procedura standard per la creazione di un nuovo utente. Per aggiornare un utente senza privilegi di admin ad un utente con privilegi di admin qui di seguito i comandi: $ psql -U gforge -W -h localhost gforge gforge=> SELECT user_id FROM users WHERE user_name=’gforge-admin’;

Questo comando serve per conoscere lo user_id dell'utente interessato. La risposta è stata '102' quindi si è utilizzato questo valore per modificare il campo group_id. Qui di seguito l'aggiornamento della entry per rendere l'utente con privilegi di admin gforge=> INSERT INTO user_group (user_id,group_id,admin_flags) gforge-> VALUES (102,1,’A’);

2.9.10 -

Customizing home di Gforge

E' ora possibile costomizzare la home page di Gforge creando un nuovo index_std.php nella directory /etc/gforge/custom, partendo dall'originale presente in /var/www/gforge/www/index_std.php. Per abilitare questa nuova home page bisogna settare il seguente parametro di configurazione $sys_custom_path presente in /etc/gforge/local.inc indicando il percorso della home modificata.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 59 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.10 - OpenLDAP per testing di GFORGE In questo momento della installazione il sistema Gforge è pienamente funzionante e utilizza il database creato in PostgreSQL come appoggio. In questa configurazione gli utenti effettuano il login e realizzano l'autenticazione come detto con le informazioni sin lì raccolte nel database. Come da specifiche elencate nel primo capitolo si andrà ora a modificare questa parte e si userà un server LDAP locale di prova sul quale effettuare le autorizzazione e le autenticazioni. E' stato scelto, per verificare la corretta autenticazione di Gforge tramite LDAP, di non verificare subito l'accesso degli utenti sul server LDAP di INFN che contiene il servizio ufficiale. E' stata quindi introdotta questa fase di test per garantire la correttezza di LDAP di INFN che viene utilizzato quotidianamente e per avere a portata di mano un servizio più semplice da manipolare durante la fase di test. Una volta verificata le capacità e le caratteristiche di Gforge e dopo aver analizzato il sistema ed eseguito la reingegnerizzazione del software che gestisce il web server si è proceduto a migrare dall'albero locale LDAP a quello ufficiale di INFN.

2.10.1 -

Cosa è OpenLDAP

LDAP (Lightweight Directory Access Protocol) è uno standard aperto ed è un protocollo client-to-server che implementa un servizio di directory, una sorta di elenco telefonico dove per ciascun utente è possibile impostare diverse informazioni: indirizzo di posta elettronica, password cifrata, numeri di telefono, indirizzo, foto, posizione all'interno dell''azienda, etc. Le informazioni sono organizzate come all'interno di un database con la differenza che le informazioni sono basate su una serie di attributi. All'interno della 'Directory' ottimizzata per la lettura, le informazioni sono organizzate gerarchicamente ad albero e la gerarchia può essere ispirata per motivi geografici, aziendali o secondo diverse scelte [16] [17]. LDAP è noto anche come X.500 Lite. X.500, uno standard internazionale per le directory, include numerose caratteristiche interessanti, ma è molto complesso e richiede grandi risorse di elaborazione e uno stack OSI completo. LDAP, al contrario, funziona in modo corretto su ogni PC ed è compatibile con il protocollo TCP/IP. LDAP può accedere alle directory X.500, ma non supporta tutte le funzioni di X.500.

2.10.2 -

Installazione di OpenLDAP

Per prima cosa si è controllato se i componenti LDAP fossero già caricati. Attraverso il comando yumex si è verificato cosa fosse presente nel sistema. La versione di OpenLDAP numero 2.3.27-8.el5_2.4 è presente. Per poter usufruire del servizio è necessario inoltre installare: 1. openldap-clients- 2.3.27-8.el5_2.4 2. openldap-servers- 2.3.27-8.el5_2.4 Sono stati quindi installati sia il client che il server, come indicato nella figura 10.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 60 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 10: Installazione del client e del server di Openldap Il client contiene i programmi necessari per l'accesso e la modifica delle directory LDAP. Il server contiene i server slapd e slurpd, gli script di migrazione ed i file relativi. E' stato installato anche il pacchetto: nss_ldap-253-5

che contiene i client di accesso LDAP: nss_ldap e pam_ldap. Il primo è un insieme di estensioni per la libreria C che consente di utilizzare i server di directory X.500 e LDPA come sorgente primario di alias, gruppo, host, protocolli ecc invece di usare file piatti o NIS. Il secondo invece è un modulo per linux-pam che supporta le modifiche alle password, i clienti V2, le politiche password di DNS, l'autorizzazione di accesso e gli has crittografati. I principali file di riferimento di OpenLDAP sono i seguenti: 1. /etc/openldap/slapd.conf (file di configurazione di LDAP) 2. /etc/openldap/schema (directory dove sono contenute le strutture dei dati relative alle informazioni da assegnare ad ogni record) La directory contenente i databases LDAP è rispettivamente /var/lib/ldap Per gestire le voci di un database LDAP si utilizzano i seguenti comandi: 1. ldapadd (per popolare il database) 2. ldapmodify (per modificare le voci esistenti) 3. ldapdelete (per eliminare le voci esistenti) Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 61 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.10.3 -

Configurazione del file slapd.conf

Qui di seguito viene riportato il contenuto del file slapd.conf # # See slapd.conf(5) for details on configuration options. # This file should NOT be world readable. # include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/gforge.schema # Allow LDAPv2 client connections. allow bind_v2

This is NOT the default.

# Do not enable referrals until AFTER you have a working directory # service AND an understanding of referrals. #referral ldap://root.openldap.org pidfile argsfile

/var/run/openldap/slapd.pid /var/run/openldap/slapd.args

# # # # # # #

Load dynamic modulepath moduleload moduleload moduleload moduleload moduleload

backend modules: /usr/lib/openldap back_bdb.la back_ldap.la back_ldbm.la back_passwd.la back_shell.la

# # # # # # # # # # # # #

The next three lines allow use of TLS for encrypting connections using a dummy test certificate which you can generate by changing to /etc/pki/tls/certs, running "make slapd.pem", and fixing permissions on slapd.pem so that the ldap user or group can read it. Your client software may balk at self-signed certificates, however. TLSCACertificateFile /etc/pki/tls/certs/ca-bundle.crt TLSCertificateFile /etc/pki/tls/certs/slapd.pem TLSCertificateKeyFile /etc/pki/tls/certs/slapd.pem Sample security restrictions Require integrity protection (prevent hijacking) Require 112-bit (3DES or better) encryption for updates Require 63-bit encryption for simple bind security ssf=1 update_ssf=112 simple_bind=64

# # # # # # # # # # # # # # # # # # # #

Sample access control policy: Root DSE: allow anyone to read it Subschema (sub)entry DSE: allow anyone to read it Other DSEs: Allow self write accesss Allow authenticated users read access Allow anonymous users to authenticate Directives needed to implement policy: access to dn.base="" by * read access to dn.base="cn=Subschema" by * read access to * by self write by users read by anonymous auth if no access controls are present, the default policy allows anyone and everyone to read anything but restricts updates to rootdn. (e.g., "access to * by * read") rootdn can always read and write EVERYTHING!

####################################################################### # ldbm and/or bdb database definitions ####################################################################### database bdb suffix "dc=infn,dc=it" rootdn "cn=Manager,dc=infn,dc=it" # Cleartext passwords, especially for the rootdn, should

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 62 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

# be avoided. See slappasswd(8) and slapd.conf(5) for details. # Use of strong authentication encouraged. rootpw secret #rootpw {SSHA}TP2ysacwC8DyCswypb8tZYB8lJ5m59Pq # The database directory MUST exist prior to running slapd AND # should only be accessible by the slapd and slap tools. # Mode 700 recommended. directory /var/lib/ldap # Indices to maintain for this database index objectClass,uid,uidNumber,gidNumber,memberUid index cn,mail,surname,givenname

eq eq,subinitial

# Replicas of this database#replogfile /var/lib/ldap/openldap-master-replog #replica host=ldap-1.example.com:389 starttls=critical # bindmethod=sasl saslmech=GSSAPI

#

authcId=host/ldap-master.example.com@EXAMPLE.COM

- Contenuto del file slapd.conf -

Ora si spiegherà il contenuto del file slapd.conf riportato qui sopra.La riga suffix "dc=infn, dc=it” richiama il dominio per il quale il server LDAP fornisce le informazioni L'entry rootdn "cn=Manager,dc=infn,dc=it” è il Distinguished Name (DN) per un utente che non ha limitazioni nei controlli di accesso o nei parametri limite amministrativi impostati per le operazioni sulla directory LDAP. L'utente rootdn può essere considerato un utente root per la directory LDAP L'entry "rootpw {SSHA}..." rappresenta la password dell'utente rootdn di ldap. La direttiva directory /var/lib/ldap/ rappresenta la directory contenente i database di LDAP. Le entry LDAP vengono inserite sui database mediante l'impiego di appositi file ASCII in formato testo, denominati LDIF(LDAP Data Interchange Format), all'interno dei quali definiamo le entry e i loro attributi. I file che importano o esportano dati da un server LDAP, devono essere in formato LDIF. Un 'entry rappresenta una unità in una directory LDAP, identificata dal proprio e unico Distinguished Name (DN). Quindi, ogni entry possiede degli attributi, ovvero parti di informazione direttamente associate alla stessa entry. Per esempio, un'azienda denominata example.com, potrebbe essere un'entry LDAP. Il sito internet, l'indirizzo e-mail, numero di fax, l'indirizzo possono essere gli attributi associati a example.com Le persone potrebbero essere altre entry nella directory LDAP. Gli attributi legati alle persone sono il numero di telefono, l'indirizzo e-mail e così via. Alcuni attributi sono necessari, mentre altri sono facoltativi. Una objectclass evidenzia gli attributi necessari e quelli opzionali. Tutte le definizioni sintattiche degli attributi e le definizioni objectclass si trovano nei vari file schema all'interno della directory /etc/openldap/schema

2.10.4 -

Il comando LDAPADD

Ora si analizza il comando ldapadd che server per inserire una entry sul database riguardante il DC (Domain Component) infn.it ossia la Root LDAP entry Il file LDIF di infn.it si presenta come segue: dn: dc=infn,dc=it dc: infn description: Root LDAP entry for infn.it objectClass: dcObject objectClass: organizationalUnit ou: rootobject

Con il seguente comando si andrà ad aggiungere gli utenti contenuti nel file newrecord.ldif nell'albero LDIF. Il contenuto di questo file verrà analizzato poco sotto. # ldapadd -x -D "cn=admin,dc=infn,dc=it" -W -f /etc/openldap/newrecord.LDIF

Il sistema risponderà con: Enter LDAP Password:

quindi si dovrà inserire la password di admin. Se l'operazione andrà a buon fine gli utenti verranno aggiunti. Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 63 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

2.10.5 -

Creare una Organizational Unit (OU) su LDAP.

Ora si inserirà una Organization Unit (OU), denominata 'Utenti'; il file LDIF lo si chiamerà utenti.example.com.LDIF, ecco un esempio: dn: ou=Users, dc=infn,dc=it ou: Utenti description: Unità Organizzativa Utenti objectClass: organizationalUnit

Poi si dovrà eseguire il seguente comando da un terminale per creare la nuova OU: # ldapadd -x -D "cn=admin,dc=infn,dc=infn" -W -f /etc/openldap/newou.LDIF

Il sistema risponderà con: Enter LDAP Password: adding new entry "ou=Utenti, dc=infn,dc=it"

2.10.6 -

Creazione di un utente su LDAP.

Infine creiamo un utente denominato 'drigattieri' appartente all'Organization Unit(OU) 'Utenti'; la template del file LDIF è la seguente, il nome del file sarà new.utenti.LDIF. dn: uid=mserafin,ou=Utenti,dc=infn,dc=it uid: mserafin cn: mserafin objectClass: account objectClass: posixAccount objectClass: top objectClass: shadowAccount userPassword: {SSHA}LbnFzcqZwGSd7wvPifk9ft77H/iSiQIO shadowLastChange: 13209 shadowMax: 99999 shadowWarning: 7 loginShell: /bin/bash uidNumber: 501 gidNumber: 501 homeDirectory: /home/mserafin

Affinchè l'utente mserafin possa ritrovarsi sulla propria home directory dopo il processo di autenticazione, bisognare creare l'utente in questione sul server LDAP: # groupadd -g 200 utentildap # useradd -u 550 -g 200 -h /home/mserafin

La procedura per aggiungere questo utenti è analoga a quella indicata precedentemente, quindi: # ldapadd -x -D "cn=admin,dc=infn,dc=infn" -W -f /etc/openldap/ new.utenti.LDIF

2.10.7 -

Il comando LDAPSEARCH

Questo comando server per eseguire una ricerca di attributi all'interno del database LDAP. Di seguito alcuni esempi. Per effettuare una ricerca del dominio example.com: #

ldapsearch -x 'dc=infn'

Per ricercare l'OU Utenti: #

ldapsearch -x 'ou=Utenti'

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 64 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Per ricercare tutte le objectclass che contengono organizationalUnit: #

ldapsearch -x 'objectclass=organizationalUnit'

Per ricercare un utente, ad esempio mserafin: #

ldapsearch -x 'cn=mserafin'

Per visualizzare invece tutto il database LDAP: ldapsearch -x

2.10.8 -

Il comando LDAPMODIFY

Questo comando serve per aggiungere / modificare / rimuovere gli attributi di un'entry ldap. Per aggiungere un attributo all'interno di una entry, si crea un nuovo file LDIF chiamandolo ad esempio update.LDIF e si aggiungono le seguenti direttive: dn: uid=mserafin,ou=Utenti,dc=infn,dc=it changetype: modify add: description description: utente ldap

Per apportare la modifica bisogna digitare il seguente comando: #

ldapmodify -x -D "cn=admin,dc=infn,dc=it" -W -f /etc/openldap/update.LDIF

adesso verifichiamo la modifica apportata col seguente comando: #

ldapsearch -x 'cn=mserafin'

2.10.9 -

Il comando LDAPDELETE

Questo comando server per eliminare un'entry dal database ldap. Si supponga di voler eliminare l'utente 'mserafin' dal database. Ecco il comando: # ldapdelete -vx 'uid=mserafin,ou=Utenti,dc=infn,dc=it' -D "cn=admin,dc=infn,dc=it" -W

2.11 - Il demone slapd Il nome del denome di ldap è slpad. E' possibile far partire il servizio con il comando: /sbin/service ldap start

Creazione di nuovi utenti di prova con attraverso il file newrec.ldif di cui sotto il contenuto: dn: uid=paperino,ou=People,dc=infn,dc=it objectclass: top objectclass: person objectclass: inetorgperson objectclass: posixAccount Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 65 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

uid: paperino cn: paperino paperino sn: paperino userPassword: password givenname: paperino uidNumber: 101 gidNumber: 101 homeDirectory: /home/temp mail: paperino@localhost.fe.infn.it

Il record viene aggiunto a LDAP con il comando: ldapadd -W -x -D "cn=Manager,dc=infn,dc=it" -W -f newrec.ldif

Se si vuole controllare se il record sia stato correttamente inserito, ecco il comando: ldapsearch -x -b 'cn=paperino,dc=infn,dc=it'

Analogamente al precendente sono stati creati sempre tramite lo stesso meccanismo altri utenti di prova per verificare l'autenticazione tramite Gforge su OpenLDAP.

2.11.1 -

Creazione degli utenti di prova

Con i comandi precedentemente elencati sono stati creati degli utenti di prova per poi poterli utilizzare durante la fase di testing di Gforge. Sono stati creati diversi utenti, uno con credenziali di admin per il sistema di Gforge. Ecco un file di esempio: dn: uid=clarabella,ou=pd,dc=infn,dc=it objectclass: top objectclass: person objectclass: inetorgperson objectclass: posixAccount uid: clarabella cn: clarabella clarabella sn: clarabella userPassword: password givenname: clarabella uidNumber: 122 gidNumber: 122 homeDirectory: /home/temp mail: clarabella@localhost.fe.infn.it

Come si può notare dall'esempio qui sopra, gli utenti fanno parte del dn: dc=infn,dc=it e vengono poi suddivisi per organization unit secondo la sede di INFN. Questa caratteristica che verrà illustrata nel particolare nel prossimo capitolo inserirà la necessità di effettuare delle ricerche ricorsive durante la fase di Ldapsearch.

2.12 - Il plugin di GForge ldap-ext-auth

2.12.1 -

Cos'è il plugin ldap-ext-auth

Il plugin per GForge ldap-ext-auth consente agli utenti del webserver di autenticarsi tramite la maggiore parte dei server LDAP. Il funzionamento è del tipo tutto o niente ovvero con il plugin abilitato ogni informazione necessaria al sistema la memorizza nell'albero e non più nel database. Così facendo non solo vengono inserite nell'albero le informazioni degli utenti ma anche altre che seppur vitali al funzionamento di GForge non sono coerenti dal punto di vista logico con il significato dell'albero LDAP. Per questo motivo una volta installato e configurato l'albero di prova si procederà a reingegnerizzare il codice per scindere le informazioni da inserire nel database e nell'albero. A Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 66 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

modifiche concluse il sistema andrà a maneggiare i dati relativi agli utenti per l'autenticazione e l'autorizzazione nell'albero LDAP, tutte le altre informazioni di sistema saranno inserite nel database di appoggio creato in PostgreSQL. Nel prossimo capitolo verranno discusse la deingegnerizzazione del software e la successiva reingegnerizzazione con le modifiche apportate.

2.12.2 -

Installazione del plugin:

Il plugin contiene una cartella che va posizionata in /var/www/gforge/plugin. Una volta posizionata qui la cartella è necessario effettuare la registrazione e l'attivazione dello stesso in modo tale che GForge lo riconosca e lo possa utilizzare. Questa operazione deve essere eseguita via web accedendo nell'apposito menù di management. Per il corretto funzionamento inoltre è stato modificato il file di configurazione di gforge, ovvero: /etc/gforge/local.inc Nella realtà è stata creata una copia di questo file e si è lavorato su questa in modo tale da avere due configurazioni a portata di mano. La prima versione faceva lavorare GForge su PostgreSQL, l'altra su LDAP. Così facendo lo switching per poter passare da una connessione all'altra risulta particolarmente veloce. Nel particolare il punto di svolta per la connessione di GForge ad un albero LDAP risulta essere la presenza o meno delle righe riportate qui sotto. // // LDAP configurataion // $sys_plugins_path='/var/www/gforge/plugins/'; $sys_account_manager_type = 'UNIX'; // enable(1) or disable(0) ldap use altogether $sys_use_ldap=0; $sys_ldap_host='localhost'; $sys_ldap_port=389; //$sys_ldap_port=12345; $sys_ldap_version=3; // this is dn under which all information stored $sys_ldap_base_dn='dc=infn,dc=it'; // and this, how we do access it (add permission required) $sys_ldap_bind_dn='cn=Manager'; // admin dn - login dn which has permissions to delete entries // NOT used by web code, only by support utilities // note that password NOT stored here $sys_ldap_admin_dn='cn=admin,ou=People,dc=infn,dc=it'; $sys_ldap_passwd ='secret'; //$sys_ldap_passwd ='superbprova';

Le informazioni precedenti sono autodescrittive, si segnala in particolare la porta di ascolto di OpenLDAP che è la 389, la stringa attraverso la quale effettuare il binding come Manager e il relativo base dn dell'albero. Una informazione molto importante è la prima riga ovvero sys_account_manager_type che indica UNIX, ovvero indica che si utilizza il file UNIX.class presente in /var/www/gforge/common/include/system.

2.12.3 -

Le modifiche al codice di GForge.

L'installazione del plugin richiede inoltre che il codice del webserver venga modificato, in particolare sostituendo la relativa funziona in login.php con la seguente: if ($login) { $success=session_login_valid(strtolower($form_loginname),$form_pw); if ($success) { if ($GLOBALS['ldap_first_login']) { header ("Location: /account/"); } else { /* You can now optionally stay in SSL mode */ if ($return_to) { header ("Location: " . $return_to); exit; } else { Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 67 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

} }

}

}

header ("Location: /my/"); exit;

- Parte di codice della funzione index.php -

Un'altra sostituzione di funzione da effettuare nel file session.php è la seguente: $hook_params['passwd'] = $passwd ; plugin_hook ("session_before_login", $hook_params) ; if ($GLOBALS[forge:'ldap_auth_failed']) { return false; } elseif ($GLOBALS['ldap_first_login']) { if (session_login_valid_dbonly ($loginname, $passwd, $allowpending)) { header("Location: /account/"); return true; } else { return false; } } else { return session_login_valid_dbonly ($loginname, $passwd, $allowpending) ; } } - Parte di codice della funzione session.php -

2.12.4 -

GForge su LDAP di Mailman.fe.infn.it

Dallo stralcio del file local.inc proposto precendetemente si può vedere come sia facile effettuare lo switching tra i due alberi LDAP che si sono utilizzati. Indicando nel parametro sys_ldap_port la porta 389 ovvero quella di servizio dell'albero OpenLDAP in locale si raggiunge tale albero. Se invece sempre in tale paramtro si indica 12345 che è l'indirizzo di entrata dello stunnel verso mailman.fe.infn.it si raggiunge allora l'albero di INFN.

2.12.5 -

Conclusione dell'installazione

Con questi ultimi settaggi si è conclusa la fase di installazione e configurazione del sistema. Ora comincia la parte relativa alla deingegnerizzazione, studio e reingegnerizzazione del software. In questo momento il sistema è in grado di lavorare come da configurazione di default totalmente sul database di PostgreSQL oppure, modificando il file di Gforge local.inc, totalmente su LDAP. Lo switching da una all'altra via è facilmente ottenibile rinominando i file local.inc di Gforge e mantenendone così a portata di mano le due configurazioni (una per PostgreSQL, l'altra per LDAP) che differiscono solamente per le righe descritte sopra.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 68 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

CAPITOLO 3 - INTEGRAZIONE DEL SOFTWARE

3.1 - Utilizzo del web server e creazione degli utenti di prova Una volta completata la laboriosa procedura di installazione, GForge si è presentato come il più classico dei servizi web. Usufruendo di Apache installato come detto precedentemente ci si è collegati in localhost alla home page di GForge. Come da analisi fatta all'inizio si è studiato e cominciato a prendere visione del codice php che viene rilasciato sotto licenza GNU GPL. I licenziatari della GNU GPL che accettano le sue condizioni hanno la possibilità di modificare il software, di copiarlo e ridistribuirlo con o senza modifiche, sia gratuitamente sia a pagamento. Quest'ultimo punto distingue la GNU GPL dalle licenze che proibiscono la ridistribuzione commerciale. Se l'utente distribuisce copie del software, deve rendere disponibile il codice sorgente a ogni acquirente, incluse tutte le modifiche eventualmente effettuate (questa caratteristica è detta copyleft). Nella pratica, i programmi sotto GNU GPL vengono spesso distribuiti allegando il loro codice sorgente, anche se la licenza non lo richiede. Ci sono casi in cui viene distribuito solo il codice sorgente, lasciando all'utente il compito di compilarlo. Questa parte del progetto ovvero lo studio di un progetto esistente è stata particolarmente complessa poichè il codice è apparso fin da subito poco ordinato. In particolar modo la parte relativa al login utente risulta scarsamente leggibile anche perchè gli sviluppatori, lasciandosi aperta la strada per utilizzare plugin di terze parti, hanno complicato abbastanza la fluidità del codice. Inoltre il codice sorgente è scritto in php5 ad oggetti ma le chiamate delle funzioni sono la quasi totalità a semplice chiamata a procedura. Con questa scelta si è solamente complicato il tutto senza avere quel guadagno che uno sviluppo ad oggetti avrebbe comportato. In particolar modo le chiamate ai plugin sono sembrate sì funzionanti ma poco funzionali soprattutto perchè poco leggibili a causa delle numerose chiamate innestate che si poteva trovare. La prima operazione eseguita è stata quella di creare alcuni utenti di prova per il sistema. Seguendo la procedura indicata nel manuale si è creato un utente attraverso la sezione “nuovo utente”. Dopo aver compilato i campi il sistema ha mandato una mail all'indirizzo di posta indicato per ottenere una ulteriore approvazione da parte dell'utente stesso onde evitare spam. Dopo aver confermato attraverso un link riportato nella mail di notifica creato dal sistema l'utente di prova è stato creato. Così facendo si sono creati alcuni utenti di prova per testare il servizio.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 69 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

3.2 - Analisi e studio delle caratteristiche di GForge Questa fase dello studio è basata sull'avere come situazione iniziale il tool GForge senza installazione del plugin ldap-ext-auth. In pratica si è proceduti facendo si che il plugin per l'autorizzazione esterna a Ldap non sia attivo in modo tale da avere attive solo le funzionalità standard di Gforge. La terza e ultima parte del progetto è stata quella meno laboriosa ma sicuramente più complicata. Complicata perchè non si aveva a disposizione alcuna descrizione, manuale, flusso dei dati del software. Si è partita quindi con una fase conoscitiva dello strumento durante la quale si sono effettuati esperimenti e prove prima verso il database di PostgreSQL poi verso i due alberi LDAP che erano stati configurati. L'analisi è partita dall'homepage del sistema che è contenuta in account/login.php e la si è analizzata seguendo le varie chiamate che via via si incontravano. Un'altra difficoltà incontrata in questa fase è stata quella di aver incontrato del codice in php ad oggetti ma che in realtà veniva istanziato ed adoperato per lo più con normali chiamate a procedura. if ($login) { $success=session_login_valid(strtolower($form_loginname),$form_pw); //* la funzione session_login_valid e' in common/include/session.php if ($success) { /* You can now optionally stay in SSL mode */ if ($return_to) { header ("Location: " . $return_to); exit; } else { header ("Location: /my/"); exit; } } } - Particolare del codice di login.php -

Qui sopra viene riproposto la chiamata principale che viene effettuata durante la fase di login. Come si può notare anche dal commento viene proposta un'altra chiamata verso la funzione contenuta in common/include/session.php che si ripropone qui sotto: /** * session_login_valid() - Log the user to the system. * * High-level function for user login. Check credentials, and if they * are valid, open new session. * * @param string User name * @param string User password (in clear text) * @param bool Allow login to non-confirmed user account (only for confirmation of the very account) * @return true/false, if false reason is in global $feedback * @access public * */ function session_login_valid($loginname, $passwd, $allowpending=0) { global $feedback,$Language; if (!$loginname || !$passwd) { $feedback = $Language->getText('session','missingpasswd'); return false; } $hook_params = array () ; $hook_params['loginname'] = $loginname ; $hook_params['passwd'] = $passwd ; plugin_hook ("session_before_login", $hook_params) ; return session_login_valid_dbonly ($loginname, $passwd, $allowpending) ; } - Porzione di codice contenuta in session.php -

Interessante in questa porzione di codice è la chiamata a plugin_hook. Senza plugin installati questa chiamata Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 70 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

punta alla classe “Plugin.class” contenuta in common/include e va a gestire la situazione di default per i plugin. Il tutto tramite la classe PluginManager.class che funziona da factory ed è in grado di gestire più plugin assieme. Nella situazione iniziale non vi sono plugin installati, quindi il codice invocato è molto semplice e non restituisce un valore: /** * CallHook() - call a particular hook * * @param hookname - the "handle" of the hook * @param params - array of parameters to pass the hook */ function CallHook ($hookname, $params) { return true ; } - La funzione CallHook contenuta in PluginManager.class -

Quindi questo controllo su eventuali plugin che redirigono il codice verso altre chiamate è indifferente. Prima di chiudersi la funzione di session_login_valid va ad invocare la funzione session_login_valid_dbonly presente sempre in session.php e che qui sotto viene riproposta: function session_login_valid_dbonly ($loginname, $passwd, $allowpending) { global $feedback,$userstatus,$Language; // Try to get the users from the database using user_id and (MD5) user_pw $res = db_query(" SELECT user_id,status,unix_pw FROM users WHERE user_name='$loginname' AND user_pw='".md5($passwd)."' "); if (!$res || db_numrows($res) < 1) { // No user whose MD5 passwd matches the MD5 of the provided passwd // Selecting by user_name only $res = db_query("SELECT user_id,status,unix_pw FROM users WHERE user_name='$loginname'"); if (!$res || db_numrows($res) < 1) { // No user by that name $feedback=$Language->getText('session','invalidpasswd'); return false; } else { // There is a user with the provided user_name, but the MD5 passwds //do not match // We'll have to try checking the (crypt) unix_pw $usr = db_fetch_array($res); if (crypt ($passwd, $usr['unix_pw']) != $usr['unix_pw']) { // Even the (crypt) unix_pw does not patch // This one has clearly typed a bad passwd $feedback=$Language->getText('session','invalidpasswd'); return false; } // User exists, (crypt) unix_pw matches // Update the (MD5) user_pw and retry authentication // It should work, except for status errors $res = db_query ("UPDATE users SET user_pw='" . md5($passwd) . "' WHERE user_id='".$usr['user_id']."'"); return session_login_valid_dbonly($loginname, $passwd,$allowpending); } } else { // If we're here, then the user has typed a password matching the (MD5) //user_pw // Let's check whether it also matches the (crypt) unix_pw $usr = db_fetch_array($res); if (crypt ($passwd, $usr['unix_pw']) != $usr['unix_pw']) { // The (crypt) unix_pw does not match if ($usr['unix_pw'] == '') { // Empty unix_pw, we'll take the MD5 as authoritative // Update the (crypt) unix_pw and retry authentication // It should work, except for status errors $res = db_query ("UPDATE users SET unix_pw='" . account_genunixpw($passwd) . "' WHERE user_id='".$usr['user_id']."'"); return session_login_valid_dbonly($loginname, $passwd, Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 71 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

$allowpending) ; } else { // Invalidate (MD5) user_pw, refuse authentication $res = db_query ("UPDATE users SET user_pw='OUT OF DATE' WHERE user_id='".$usr['user_id']."'"); $feedback=$Language->getText('session','invalidpasswd'); return false; }

}

}

} // Yay. The provided password matches both fields in the database. // Let's check the status of this user // if allowpending (for verify.php) then allow $userstatus=$usr['status']; if ($allowpending && ($usr['status'] == 'P')) { //1; } else { if ($usr['status'] == 'S') { //acount suspended $feedback = $Language->getText('session','suspended'); return false; } if ($usr['status'] == 'P') { //account pending $feedback = $Language->getText('session','pending'); return false; } if ($usr['status'] == 'D') { //account deleted $feedback = $Language->getText('session','deleted'); return false; } if ($usr['status'] != 'A') { //unacceptable account flag $feedback = $Language->getText('session','notactive'); return false; } } //create a new session session_set_new(db_result($res,0,'user_id')); return true;

- La funzione session_login_valid_dbonly in session.php -

Il significato di questa funzione è molto semplice e il codice è autoesplicativo. In ogni caso si basa su di una semplice query su username e password criptata in md5 e in base al risultato ottenuto viene deciso se visualizzare o meno un messaggio di errore oppure se l'operazione va a buon fine. In questo secondo caso viene poi reinterrogato il database per conoscere lo status dell'utente e quali privilegi abbia. Si deve ricordare che in questa situazione gli utenti devono essere già presenti nel database ovvero devono aver eseguito la procedura di registrazione. Gli utenti che si affacciano a questa pagina per fare il loro login devono essere quindi già presenti e non, come accadrà dopo le modifiche, utilizzare delle credenziali che il sistema GForge conosce poichè presenti nell'albero LDAP. Ora si analizza la situazione non standard di GForge ma quella successiva alle modifiche introdotte dall'installazione del plugin ldap-ext-auth.

3.2.1 -

Situazione dopo l'installazione del plugin ldapextauth.

E' importante fare una prefazione a questo punto. Come indicato in precendenza è stato modificato il codice come riportato e il plugin oltre ad essere stato caricato nella cartella apposita plugins è stato anche installato via web. Questa operazione è di fondamentale importanza perchè fa conoscere al sistema l'esistenza di questo pacchetto. L'operazione di installazione quindi va a modificare i riferimenti all'interno soprattutto del file già visto Plugin.class in modo tale da instanziare altre chiamate rispetto a quelle standard. L'analisi parte ancora una volta dalla funzione di login all'interno di login.php:

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 72 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

if ($login) { $success=session_login_valid(strtolower($form_loginname),$form_pw); if ($success) { if ($GLOBALS['ldap_first_login']) { header ("Location: /account/"); } else { /* You can now optionally stay in SSL mode */

}

}

}

if ($return_to) { header ("Location: " . $return_to); exit; } else { header ("Location: /my/"); exit; }

- La funzione login di login.php dopo le modifiche richieste dal plugin -

Le modifiche richieste dal plugin per l'autenticazione tramite LDAP sono minime ma come si può vedere cambiano logica al software. La chiamata a session_login_valid di session.php è stata mostrata precedentemente ma si andrà a riproporla in quanto anch'essa è stata modificata come da indicazione di installazione del plugin. /** * * * * * * * *

session_login_valid() - Log the user to the system. High-level function for user login. Check credentials, and if they are valid, open new session. @param @param @param

string User name string User password (in clear text) bool Allow login to non-confirmed user account (only for confirmation of the very account) @return true/false, if false reason is in global $feedback @access public

* * * */ function session_login_valid($loginname, $passwd, $allowpending=0) global $feedback,$Language;

{

if (!$loginname || !$passwd) { echo('!$loginname || !$passwd'); $feedback = $Language->getText('session','missingpasswd'); return false; } $hook_params = array () ; $hook_params['loginname'] = $loginname ; $hook_params['passwd'] = $passwd ; plugin_hook ("session_before_login", $hook_params) ; //* in AuthUser di LDAPextAuthPlugin.class, in questa funzione viene effettuata l'autenticazione tramite INFN.class if (!$GLOBALS['ldap_auth_failed']) {

}

//login valido... mi leggo le informazioni da postgresql return session_login_valid_on_db ($loginname, $allowpending); } else { //login non valido return false; } - Contenuto di session.php dopo le modifiche del plugin-

La funzione plugin_hook analizzata precedentemente ora grazie a nuovi riferimenti creati dall'installazione del plugin punterà al file LDAPextAuthPlugin.class. In questa classe vengono in pratica ereditate delle funzioni che si sono già incontrate. Seguendo ancora meticolasemente il codice si arriva alla chiamata CallHook sempre attraverso alcune chiamate innestate in PluginManager.class. La funzione CallHook di LDAPextauthPlugin è diversa dalla precedente che rispondeva sempre con valore true, Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 73 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

ecco: function CallHook ($hookname, $params) { global $Language, $HTML ; $loginname = $params['loginname'] ; $passwd = $params['passwd'] ;

}

switch ($hookname) { case "session_before_login": // Authenticate against LDAP $this->AuthUser ($loginname, $passwd) ; break; case "blah": // Should not happen break; default: // Forgot something } - La funzione CallHook di LdapExtauthPlugin

Nonostante la presenza di un costrutto switch, il case selezionato è sempre il primo in quanto la variabile hookname viene impostata proprio con “session_before_login”. L'istanza creata per $this è proprio il modulo Ldapextauth stesso e quindi la funzione AuthUser richiamata è visibile qui sotto: function AuthUser ($loginname, $passwd) { global $feedback,$Language; if (!$this->ldap_conn) { $this->ldap_conn = ldap_connect ($this->ldap_server, $this->ldap_port); } if ($GLOBALS['sys_ldap_version']) { ldap_set_option ($this->ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $GLOBALS['sys_ldap_version']); } $u = user_get_object_by_name ($loginname) ; if ($u) { // User exists in DB //debug echo "<pre>"; print_r($this->ldap_conn); echo "<br />"; print_r($dn); echo "<br />"; print_r($passwd); echo "</pre>"; //die(); //this line is causing timeout problems. -adm, 2006-09-06 if (@ldap_bind($this->ldap_conn, $dn, $passwd)) { // Password from form is valid in LDAP if (session_login_valid_dbonly ($loginname, $passwd, false)) { // Also according to DB $GLOBALS['ldap_auth_failed']=false; return true ; } else { // Passwords mismatch, update DB's $u->setPasswd ($passwd) ; $GLOBALS['ldap_auth_failed']=false; return true ; } } else { // Wrong password according to LDAP $feedback=$Language->getText('session','invalidpasswd'); $GLOBALS['ldap_auth_failed']=true; return false ; } } else { // User doesn't exist in DB yet if (@ldap_bind($this->ldap_conn, $dn, $passwd)) { // User authenticated // Now get her info if ($this->ldap_kind=="AD"){ $res = ldap_search ($this->ldap_conn, $this->base_dn,

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 74 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

"sAMAccountName=".$loginname) ; } else { $res = ldap_read ($this->ldap_conn, $dn, "objectclass=*") ; } $info = ldap_get_entries ($this->ldap_conn,$res); $ldapentry = $info[0] ; $mappedinfo = plugin_ldapextauth_mapping ($ldapentry) ; // Insert into DB $u = new User () ; $unix_name = $loginname ; $firstname = '' ; $lastname = '' ; $password1 = $passwd ; $password2 = $passwd ; $email = '' ; $mail_site = 1 ; $mail_va = 0 ; $language_id = 1 ; $timezone = 'GMT' ; $jabber_address = '' ; $jabber_only = 0 ; $theme_id = 1 ; $unix_box = '' ; $address = '' ; $address2 = '' ; $phone = '' ; $fax = '' ; $title = '' ; $ccode = 'US' ; $send_mail = false ; if ($mappedinfo['firstname']) { $firstname = $mappedinfo['firstname'] ; } if ($mappedinfo['lastname']) { $lastname = $mappedinfo['lastname'] ; } if ($mappedinfo['email']) { $email = $mappedinfo['email'] ; } if ($mappedinfo['language_id']) { $language_id = $mappedinfo['language_id'] ; } if ($mappedinfo['timezone']) { $timezone = $mappedinfo['timezone'] ; } if ($mappedinfo['jabber_address']) { $jabber_address = $mappedinfo['jabber_address'] ; } if ($mappedinfo['address']) { $address = $mappedinfo['address'] ; } if ($mappedinfo['address2']) { $address2 = $mappedinfo['address2'] ; } if ($mappedinfo['phone']) { $phone = $mappedinfo['phone'] ; } if ($mappedinfo['fax']) { $fax = $mappedinfo['fax'] ; } if ($mappedinfo['title']) { $title = $mappedinfo['title'] ; } if ($mappedinfo['ccode']) { $ccode = $mappedinfo['ccode'] ; } if ($mappedinfo['themeid']) { $theme_id = $mappedinfo['themeid'] ; } if (!$u->create ($unix_name, $firstname, $lastname, $password1, $password2, $email, $mail_site, $mail_va,$language_id, $timezone, $jabber_address, $jabber_only, $theme_id, $unix_box, $address, $address2, $phone, $fax, $title, $ccode, $send_mail)) {

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 75 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

}

}

}

}

$GLOBALS['ldap_auth_failed']=true; $feedback = "<br>Error Creating User: ".$u>getErrorMessage(); return false; if (!$u->setStatus ('A')) { $GLOBALS['ldap_auth_failed']=true; $feedback = "<br>Error Activating User: ".$u>getErrorMessage(); return false; } $GLOBALS['ldap_auth_failed']=false; $GLOBALS['ldap_first_login']=true; return true ; } else { $GLOBALS['ldap_auth_failed']=true; $feedback=$Language->getText('session','invalidpasswd'); return false ; // Probably ignored, but just in case }

- La funzione AuthUser -

Si può notare che le prime righe servono per la connessione all'albero LDAP e, se riesce, continua con il settaggio delle impostazioni. Arrivati a questo punto vi è la chiamata molto importante a “plugin_ldapextauth_getdn ($this, $loginname)”, funzione che è contenuta sempre nel plugin ma nel file mapping.php e viene riproposta qui sotto: function plugin_ldapextauth_getdn ($plugin, $username) { return "uid=$username," . $plugin->base_dn ; //return 'DOMAIN\\' . "$username" ; // AD} - Contenuto del file mapping.php -

Questa funzione non fa altro che concatenare la stringa dello username ovvero il dato immesso durante il login dall'utente con il base_dn. Quest'ultimo parametro viene letto durante la fase iniziale in file local.inc ed eventualmente sovrascritto se presente anche in config.php e, per le nostre impostazioni, vale: $sys_ldap_base_dn='dc=infn,dc=it';

Questa stringa costruita servirà ora per eseguire l'operazione di matching e verificare che l'utente sia presente nel database di POSTRGRESQL. Ora il codice e le chiamate successive sono un po' confuse e per chiarezze ne viene esposto il flusso dei dati in figura 11.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 76 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 11: Schema flusso dei dati del pacchetto originale

3.2.2 -

Le mancanze del pacchetto standard rispetto ai requisiti richiesti.

Per quanto riguarda le specifiche dei requisiti il flusso dei dati e il codice dei dati funziona correttamente e al di là di una poca chiarezza potrebbe essere coerente per quanto riguarda il login integrato tra LDAP e PostgreSQL. Il plugin così come distribuito non è compatibile, per alcuni altri punti, con l'analisi delle specifiche, in particolare: 1. Il flusso dati originale non è lineare a causa dell'inserimento del plugin. Si andrà a modificarlo per avere un flusso dati diverso e più coerente con la fase di autenticazione e autorizzazione progettata. 2. Il cambio password avviene solamente per il database PostgreSQL e non per l'albero LDAP. Così facendo, primo cambio password, il sistema la cambierà solamente in PostgreSQL e il doppio match richiesto per il login non andrà mai a buon fine. 3. Ogni utente può cambiare la propria email contravvenendo alle specifiche. 4. L'iscrizione degli utenti a progetti esistenti non va a buon fine e restituisce un errore generico. 5. La creazione di un progetto, fondamentale per un applicativo del genere, è possibile ma tutte le informazioni del progetto legate agli utenti come la messaggistica vengono inserite in LDAP. 6. Viene, data nel caso attuale, precedenza al database di PostgreSQL durante la fase di autenticazione quando invece dovrebbe essere data a LDAP. Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 77 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

7. Le informazioni e lo status di un utente di livello admin per Gforge sono contenute solamente nel database GForge e non in LDAP. Come da specifica, un utente avrà privilegi di admin se e solo se presenterà un particolare ruolo in LDAP. 8. La query di ricerca per l'autenticazione degli utenti non è ricorsiva.

3.3 - Le modifiche apportate.

3.3.1 -

Modifica del flusso di dati durante l'operazione di login.

Figura 12: Schema del flusso dei dati dopo le modifiche apportate

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 78 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Prima di parlare delle modifiche al flusso dati apportate è necessario fare una premessa. E' importante sottolineare come il codice di GForge sia gestito a layer, in particolare lo si è notato quando si è studiato l'interfacciamento con il database che poteva essere a scelta MySQL o PostgreSQL. Infatti è sufficiente cambiare il layer più basso che si può migrare da un database all'altro senza problemi e in tempi rapidi. Non è così invece per quanto riguarda la parte di autenticazione e autorizzazione che non è assolutamente separata in layer e quindi per cambiare questa parte richiede un intervento in profondità e in diversi punti del codice. La soluzione meno invasiva consiste nel separare autenticazione e autorizzazione: l'autenticazione viene fatta eseguita usando LDAP come sorgente delle informazioni. Per l'autorizzazione si continua ad usare il db come sorgente di informazioni salvo per il discorso dell'utente admin che viene gestito da un ruolo di LDAP. Il flusso di dati originale, figura 11,è stato modificato sia perchè non coerente con la specifica dei requisiti stilata sia perchè con l'inserimento del plugin risultava essere poco chiaro. Ora il flusso di dati modificato, figura 12, risulta essere più snello in quanto le informazioni relative all'autenticazione e all'autorizzazione sono contenute solo nell'albero LDAP. Ogni altra informazione relativa al sistema che gestisce la produzione di software condiviso viene gestita dal database di supporto PostgreSQL. In particolare lo schema del flusso dei dati è stato modificato andando ad inserire come prima ricerca la query su username e password in LDAP per eseguire bind sugli utenti e non più in PostgreSQL. Una volta effettuata l'autenticazione e l'autorizzazione dell'utente si andrà a controllare se dello stesso siano già inserite delle informazioni nel database di supporto. In questo caso l'utente ha già effettuato in passato degli accessi, in caso contrario l'utente accede per la prima volta al sistema. In questa situazione verrà creato l'utente nel database andando a ricopiare le informazioni dello stesso presenti in LDAP. Al termine di questo controllo ve ne sarà un altro: se l'utente ha in LDAP un ruolo tale da indicare che questi abbia privilegi di admin in GForge. Ad ogni accesso quindi si procederà a verificare che l'utente sia admin oppure no, questo perchè è possibile che tale priviliegio sia stato tolto nel frattempo ad uno user conosciuto come admin oppure sia stato dato ad un utente senza tale privilegio. Il sorgente relativo al login è stato indicato precendetemente, ora si andrà ad esporre le modifiche introdotte sia a livello concettuale che di codice prodotto. La funzione di partenza contenuta in account/login.php è rimasta invariata cone quella originaria salvo le modifiche indicate dal plugin. Pertanto: if ($login) { $success=session_login_valid(strtolower($form_loginname),$form_pw); //* la funzione session_login_valid e' in common/include/session.php if ($success) { if ($GLOBALS['ldap_first_login']) { header ("Location: /account/"); } else { /* You can now optionally stay in SSL mode */ if ($return_to) { header ("Location: " . $return_to); exit; } else { header ("Location: /my/"); exit; } } } } - Codice di login.php contenuto in account -

La funzione session_login_valid presente in common/include/session.php è stata invece modificata così: function session_login_valid($loginname, $passwd, $allowpending=0) global $feedback,$Language;

{

if (!$loginname || !$passwd) { //echo('!$loginname || !$passwd'); $feedback = $Language->getText('session','missingpasswd'); return false; } $hook_params = array () ; $hook_params['loginname'] = $loginname ; $hook_params['passwd'] = $passwd ; plugin_hook ("session_before_login", $hook_params) ;

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 79 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

}

//* in AuthUser di LDAPextAuthPlugin.class, in questa funzione viene effettuata l'autenticazione tramite INFN.class if (!$GLOBALS['ldap_auth_failed']) { //login valido... mi leggo le informazioni da postgresql return session_login_valid_on_db ($loginname, $allowpending); } else { //login non valido return false; } - La funzione session_login_valid di session.php -

Come si può vedere viene utilizzato l'aggancio al plugin come precedentemente indicato attraverso la funzione AuthUser di LDAPExtAuthPlugin.class la quale esegue una ricerca ricorsiva per ottenere un distinguished name con il quale effettuare poi l'operazione di bind. Se questa operazione non va a buon fine viene segnalato errore attraverso la variabile $GLOBALS. Come si può vedere qui sopra si andrà poi, in caso di esito positivo, ad interrogare il database PostgreSQL relativamente all'utente per ottenere tutte le informazioni a lui legate che serviranno al sistema. La funzione AuthUser di LDAPExtAuthPlugin.class è stata modificata per essere coerente al nuovo flusso di dati ridisegnato: function AuthUser ($loginname, $passwd) { global $feedback,$Language,$sys_ldap_host, $sys_ldap_port,$sys_ldap_base_dn; if (!$this->ldap_conn) { $this->ldap_conn = ldap_connect ($sys_ldap_host, $sys_ldap_port); } if ($GLOBALS['sys_ldap_version']) { ldap_set_option ($this->ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $GLOBALS['sys_ldap_version']); } $dn = plugin_ldapextauth_getdn_after_search ($this->ldap_conn, $loginname) ; //cerco dn su LDAP //* plugin_ldapextauth_getdn_after_search in mapping.php if(empty($dn)) { //non ho l'utente su LDAP... esco $feedback=$Language->getText('session','invalidpasswd'); $GLOBALS['ldap_auth_failed']=true; return false; } if (!@ldap_bind($this->ldap_conn, $dn, $passwd)) {//bind utente ldap ko... pwd //sbagliata // Wrong password according to LDAP $feedback=$Language->getText('session','invalidpasswd'); $GLOBALS['ldap_auth_failed']=true; return false ; } $u = user_get_object_by_name ($loginname) ; //cerco l'utente sul db (in User.class) if (!$u) { //controllo se l'utente che e' gia' su ldap sia anche presente su //postgresql ... se non lo e' lo creo... // User doesn't exist in DB yet // User authenticated // Now get her info $res = ldap_read ($this->ldap_conn, $dn, "objectclass=*") ; $info = ldap_get_entries ($this->ldap_conn,$res); $ldapentry = $info[0] ; $mappedinfo = plugin_ldapextauth_mapping ($ldapentry) ; // Insert into DB on db ricopiando le info importanti da LDAP $u = new User () ; $unix_name = $loginname ; $firstname = '' ; $lastname = '' ; //*$password1 = $passwd ; //*$password2 = $passwd ; $password1 = 'inutile' ; //N.B. uso sempre e solo quella di LDAP per il l'autenticazione $password2 = 'inutile' ; Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 80 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

$email = '' ; $mail_site = 1 ; $mail_va = 0 ; $language_id = 1 ; $timezone = 'GMT' ; $jabber_address = '' ; $jabber_only = 0 ; $theme_id = 1 ; $unix_box = '' ; $address = '' ; $address2 = '' ; $phone = '' ; $fax = '' ; $title = '' ; $ccode = 'US' ; $send_mail = false ; if ($mappedinfo['firstname']) { $firstname = $mappedinfo['firstname'] ; } if ($mappedinfo['lastname']) { $lastname = $mappedinfo['lastname'] ; } if ($mappedinfo['email']) { $email = $mappedinfo['email'] ; } if ($mappedinfo['language_id']) { $language_id = $mappedinfo['language_id'] ; } if ($mappedinfo['timezone']) { $timezone = $mappedinfo['timezone'] ; } if ($mappedinfo['jabber_address']) { $jabber_address = $mappedinfo['jabber_address'] ; } if ($mappedinfo['address']) { $address = $mappedinfo['address'] ; } if ($mappedinfo['address2']) { $address2 = $mappedinfo['address2'] ; } if ($mappedinfo['phone']) { $phone = $mappedinfo['phone'] ; } if ($mappedinfo['fax']) { $fax = $mappedinfo['fax'] ; } if ($mappedinfo['title']) { $title = $mappedinfo['title'] ; } if ($mappedinfo['ccode']) { $ccode = $mappedinfo['ccode'] ; } if ($mappedinfo['themeid']) { $theme_id = $mappedinfo['themeid'] ; } if (!$u->create ($unix_name, $firstname, $lastname, $password1, $password2, $email, $mail_site, $mail_va, $language_id, $timezone, $jabber_address, $jabber_only, $theme_id, $unix_box, $address, $address2, $phone, $fax, $title, $ccode, $send_mail)) { $GLOBALS['ldap_auth_failed']=true; $feedback = "<br>Error Creating User: ".$u>getErrorMessage(); return false; } if (!$u->setStatus ('A')) { $GLOBALS['ldap_auth_failed']=true; $feedback = "<br>Error Activating User: ".$u >getErrorMessage(); return false; } }// fine if (!$u) $i = new INFN() ; if (plugin_ldapextauth_search_if_user_is_admin ($this->ldap_conn, $loginname)) { //l'utente e' gforge admin $i ->setUserAsGforgeAdmin($loginname); // in INFN.class

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 81 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

} else { //l'utente non e' gforge admin $i ->unsetUserAsGforgeAdmin($loginname); // in INFN.class } $GLOBALS['ldap_auth_failed']=false; //tutto ok return true; } //fine function auth user }//fine classe - La funzione AuthUser di LDAPExtAuthPlugin.class -

La funzione plugin_ldapextauth_getdn_after_search verrà discussa più avanti relativamente alla ricerca ricorsiva introdotta. Si soprassiede quindi per le prime righe, poi si troverà un costrutto “if ” che controllerò lo stato del distinguished name trovato. Se è vuoto vuol dire che il login non è andato a buon fine e la sessione non sarà valida. Il codice a seguire è stato quindi modificato per essere coerente con il nuovo flusso di dati. Le righe relative a: $u = user_get_object_by_name ($loginname) ; //cerco l'utente sul db (in User.class)

effettuano una semplice query sul db per verificare l'esistenza o meno dell'utente in esso: function &user_get_object_by_name($user_name,$res=false) { $user_name = strtolower($user_name); if (!$res) { $res=db_query("SELECT * FROM users WHERE user_name='$user_name'"); } return user_get_object(db_result($res,0,'user_id'),$res); }

A questa punto la situazione è la seguente: l'utente ha effettuato un login corretto e valido sul LDAP controllando sia lo username che la password, ora il sistema verificherà che l'utente sia già presente nel database. poichè la fase di registrazione via web è stata eliminata, come da specifiche, è possibile che in questa fase vi siano degli utenti presenti o meno nel database. Gli utenti saranno già presenti nel database se hanno già effettuato degli accessi. Le righe successive indicato proprio questo. Se la verifica sulla stringa $u precedente restituisce valore nullo allora si è nel caso che l'utente non abbia mai effettuato alcun accesso per cui deve essere inserito nel sistema ricopiando le informazioni come la mail o altro dall'albero LDAP: $res = ldap_read ($this->ldap_conn, $dn, "objectclass=*") ; $info = ldap_get_entries ($this->ldap_conn,$res); $ldapentry = $info[0] ; $mappedinfo = plugin_ldapextauth_mapping ($ldapentry) ; // Insert into DB on db ricopiando le info importanti da LDAP $u = new User () ; $unix_name = $loginname ; $firstname = '' ; $lastname = '' ; //*$password1 = $passwd ; //*$password2 = $passwd ; $password1 = 'inutile' ; //N.B. uso sempre e solo quella di LDAP per il l'autenticazione $password2 = 'inutile' ; $email = '' ; $mail_site = 1 ; $mail_va = 0 ; $language_id = 1 ; $timezone = 'GMT' ; $jabber_address = '' ; $jabber_only = 0 ; $theme_id = 1 ; $unix_box = '' ; $address = '' ; $address2 = '' ; $phone = '' ; $fax = '' ; $title = '' ; $ccode = 'US' ; $send_mail = false ; if ($mappedinfo['firstname']) { $firstname = $mappedinfo['firstname'] ; }

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 82 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

if ($mappedinfo['lastname']) { $lastname = $mappedinfo['lastname'] ; } if ($mappedinfo['email']) { $email = $mappedinfo['email'] ; } if ($mappedinfo['language_id']) { $language_id = $mappedinfo['language_id'] ; } if ($mappedinfo['timezone']) { $timezone = $mappedinfo['timezone'] ; } if ($mappedinfo['jabber_address']) { $jabber_address = $mappedinfo['jabber_address'] ; } if ($mappedinfo['address']) { $address = $mappedinfo['address'] ; } if ($mappedinfo['address2']) { $address2 = $mappedinfo['address2'] ; } if ($mappedinfo['phone']) { $phone = $mappedinfo['phone'] ; } if ($mappedinfo['fax']) { $fax = $mappedinfo['fax'] ; } if ($mappedinfo['title']) { $title = $mappedinfo['title'] ; } if ($mappedinfo['ccode']) { $ccode = $mappedinfo['ccode'] ; } if ($mappedinfo['themeid']) { $theme_id = $mappedinfo['themeid'] ; } if (!$u->create ($unix_name,$firstname,$lastname,$password1,$password2,$email, $mail_site, $mail_va, $language_id, $timezone, $jabber_address, $jabber_only,$theme_id, $unix_box, $address, $address2, $phone, $fax, $title, $ccode, $send_mail)) { $GLOBALS['ldap_auth_failed']=true; $feedback = "<br>Error Creating User: ".$u->getErrorMessage(); return false; } - La funzione ldap_read -

3.3.2 -

La ricerca ricorsiva in LDAP.

La struttura dell'albero LDAP prevede come root un nodo etichettato con dc=infn,dc=it. Con questo parametro, come visto in precedenza, concatenato con lo user_id dello utente si è in grado di fare delle query per estrapolare le informazioni relative al nodo. Questa operazione, come è possibile vedere dal codice integrato in precedenza, viene effettuata tramite le funzioni di libreria inserite dal pacchetto di php per ldap, in particolare: ldap_bind($this->ldap_conn, $dn, $passwd)

In figura 13 si possono notare le OrganizationalUnit gforge e people. Di quest'ultima ne fanno parte alcuni utenti di prova.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 83 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 13: LdapBrowser connesso sul server mailman

In figura 14, si può notare che gli utenti veri e proprio fanno parte di OrganizationalUnit diverse, una per ogni Dipartimento di INFN.

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 84 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 14: Altra immagine di LdapBrowser connesso a mailman Si può notare che la ricerca degli utenti può essere anche parecchio in profondità. Gli utenti possono far parte o meno di OrganizationalUnit diverse. Queste OrganizationalUnit sono rappresentate dal cartella ou = xx che incide sotto il nodo root precedentemente dichiarato che è dc=infn,dc=it. In linea di principio vi è una OrganizationalUnit per ogni dipartimento di INFN e ogni uid, come detto, è comunque univoco. Per le prime prove si è creata nell'albero LDAP di mailman.fe.infn.it un'altra OrganizationalUnit di prova chiamata gforge. Questa ne ha a suo volta un'altra denominata people che contiene gli utenti di prova. Questa situazione ha anche un livello di profondità in più rispetto a quello che si dovrebbe poi trovare con gli utenti veri e propri. Come si può vedere il paramentro necessario per l'operazione di bind è il dn ovvero il distinguished name oltre che la password e il parametro di connessione. Nell'albero INFN che è stato anche ricreato in locale la situazione è diversa. Esistono dei parametri OU ovvero Organization Unit inseriti sotto quello livello che vanno ad indicare le varie facoltà di INFN presenti. Esiste comunque un vincolo per gli utenti: ovvero che il loro uid che indica lo username è comunque univoco per tutto l'albero. Questo vincolo non è importante per l'albero stesso che accetterebbe comunque la presenza di utenti con lo stesso uid in Organization Unit diverse bensì per il database di PostgreSQL. Il fatto che lo username sia univoco per tutta INFN ci consente di non variare lo schema di PostgreSQL che utilizza proprio questo campo come chiave esterna. Quindi la ricerca per username deve essere di tipo ricorsivo andando a fare prima una ricerca grossolana sul distinguished name e sul base dn fornito. Questa query fornisce una lista di dn. In realtà solo il primo è valido poichè esiste il vincolo che gli utenti hanno uid univoci.

3.3.3 -

La ricerca ricorsiva per gli username degli utenti.

Nella funzione AuthUser di LdapExtauthPlugin.class è stata sostituita la funzione: $dn = plugin_ldapextauth_getdn ($this, $loginname) ;

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 85 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

con: $dn = plugin_ldapextauth_getdn_after_search ($this->ldap_conn, $loginname) ; su LDAP

//cerco dn

In particolare questa seconda funzione, che è stata creata: function plugin_ldapextauth_getdn_after_search ($ldap_conn, $username) { global $sys_ldap_base_dn; $filter = "uid=".$username; $result = ldap_search($ldap_conn, $sys_ldap_base_dn , $filter); //$count = ldap_count_entries($ldap_conn ,$result); $entry = ldap_first_entry($ldap_conn, $result); $dncalculate = ldap_get_dn($ldap_conn, $entry); return $dncalculate ; } - Sorgente della funzione plugin_ldapextauth_getdn_after_search -

Con la chiamata ldap_search delle librerie di php per ldap viene effettuata la ricerca ricorsiva e questa funzione fornirà una lista con più dn. Questa lista conterrà solamente gli username come da filtro creato all'inizio. In realtà se l'utente è presente, come detto precedentemente, la lista conterrà solamente un valore per cui è corretto far ritornare, come da funzione ldap_first_entry, solamente il primo elemento della lista. Ora si ha un campo entry che può contenere uno username valido oppure essere vuoto. A questo punto ci si trova nella situazione precedente le modifiche per cui con il comando ldap_get_dn si cerca nell'albero una entry che abbia come dn quello appena elaborato.

3.3.4 -

Cambio password solo per LDAP.

Come detto precedentemente nonostante il plugin di autenticazione per LDAP, si può modificare la password solamente per il database PostgreSQL. Ecco la funzione relativa originale contenuta in User.class : */ function setPasswd($passwd) { global $Language,$SYS; if (!account_pwvalid($passwd)) { $this->setError('Error: '.$GLOBALS['register_error']); return false; } db_begin(); $unix_pw = account_genunixpw($passwd); $res=db_query(" UPDATE users SET user_pw='" . md5($passwd) . "', unix_pw='$unix_pw' WHERE user_id='".$this->getID()."' "); if (!$res || db_affected_rows($res) < 1) { $this->setError('ERROR - Could Not Change User Password: '.db_error()); db_rollback(); return false; } db_commit(); return true; } - Sorgente di setPasswd di User.class -

Esiste quindi solo un update del database PostgreSQL, questa funzione crea quindi un problema grossolano, ovvero che una volta cambiata la pwd nel db ma non in LDAP il login non è più effettuabile. Questo perchè, come da flusso dati, indicato precedentemente il sistema effettua una doppia verifica su username e pwd sia su db che sull'albero che devono essere soddisfatte entrambe. Ma il db risulta aggiornato con la password “nuova”, l'albero invece contiene la password ancora da aggiornare.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 86 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Le modifiche inserite sono quindi state: function setPasswd($passwd) { global $Language,$SYS; if (!account_pwvalid($passwd)) { $this->setError('Error: '.$GLOBALS['register_error']); return false; } if ($SYS->sysCheckUser($this->getID())) { //**if (!$SYS->sysUserSetAttribute($this>getID(), "userPassword", '{crypt}'.$unix_pw)) { if (!$SYS->sysUserSetAttribute($this->getID(), "userPassword", $passwd)) { //* in sysUserSetAttribute di INFN.class $this->setError($SYS->getErrorMessage()); db_rollback(); return false; } return true; } } - La funzione setPasswd in User.class modificata -

In questa nuova funzione non vi è alcuna presenza di update della password per il database in quanto, come da specifiche, è importante e fondamentale che sia l'albero LDAP a fornire i parametri per la autenticazione. Per pulizia e fluidità del codice è stato creato un nuovo modulo denominato INFN.class in common/include/system che contiene le funzioni modificate e necessarie al progetto. In tale cartella esistono già altre classi di sistema che eseguono funzioni analoghe sotto il punto di vista logico. Ritornando al sorgente, dopo aver interrogato l'albero LDAP per verificare che l'utente fosse presente nell'albero attraverso la funzione sysCheckUser si è invocata la funzione sysUserSetAttribute contenuta in INFN.class: function sysUserSetAttribute($user_id,$attr,$value) { global $sys_ldap_base_dn,$sys_ldap_host, $sys_ldap_port; $user = &user_get_object($user_id); if (!$this->gfLdapConnect()) { return false; } $this->ldap_conn = ldap_connect ($sys_ldap_host, $sys_ldap_port); $dn = plugin_ldapextauth_getdn_after_search ($this->ldap_conn,$user->getUnixName()); //cerco dn utente $entry[$attr]=$value; if (!$this->gfLdapModifyIfExists($dn, $entry)) {//* in questa classe //modifica l'attributo $this->setError("ERROR: cannot change LDAP attribute '$attr' for user '". $user->getUnixName()."': ".$this->gfLdapError()."<br />"); return false; }

} return true; - La funzione sysUserSetAttribute di INFN.class -

Le prime righe, come nel caso precedente, servono per la connessione all'albero LDAP e per ricercare ed ottenere il distinguished name dell'utente dopo la ricerca ricorsiva. A questo punto, ottenuto il dn relativo dell'utente si può procedere alla modifica dei parametri dell'utente attraverso la funzione gfLdapModifyIfExists che si può trovare poco sotto: function gfLdapModifyIfExists($dn,$entry) { $res = $this->gfLdapModify($dn,$entry); if ($res) { return true ; } else { $err = ldap_errno ($ldap_conn) ; if ($err == 32) { return true ; } else { Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 87 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

}

};

}

return false ;

- La funzione di gfLdapModifyIfExists di INFN.class -

Questa funzione modifica semplicemente i parametri andando ad indicare però con un valore di ritorno diverso se la modifica è andata a buon fine oppure no.

3.3.5 -

Riconoscimento di un utente con privilegi di admin in LDAP.

Il pacchetto standard di GForge prevede naturalmente la possibilità che gli utenti possano avere dei privilegi di admin. Gli utenti admin sono coloro che amministrano il sistema e sono in grado di gestire gli utenti, i progetti e molto altro. La situazione standard prevede che un utente con privilegi normali possa diventare admin sono dopo un update del database di PostgreSQL eseguita manualmente. Questo non è coerente con le specifiche dei requisiti che sono state stilate durante la fase iniziale. Come indicato si deve avere la possibilità di cambiare semplicemente un ruolo in LDAP che rappresenti lo status o meno di admin senza dover propagare ad altri questo sistema. Ora il sistema GForge utilizza fortemente PostgreSQL per moltissime informazioni come ad esempio la gestione degli utenti. Infatti come indicato precedentemente quando si è andati a creare un utente admin si è visto che si doveva dare al database il seguente comando: gforge=> INSERT INTO user_group (user_id,group_id,admin_flags) gforge-> VALUES (102,1,’A’);

dove il valore “102” è lo user_id dell'utente che si vuol far diventare admin, e il valore “A” indica appunto lo status di admin. Ora avendo a disposizione durante la fase di login una lettura delle informazioni del nodo dell'albero relativo all'utente si è proceduto andando ad automatizzare questa operazione. E' stata quindi modificata la funzione di AuthUser di LdapExtAuthPlugin.class. Tale funzione, che è stata presentata anche in precedenza, dopo aver verificato l'autenticazione mediante LDAP controlla nel database di PostgreSQL se l'utente sia già presente oppure no. A questo punto sono state inserite le modifiche relative alla questione in discussione: if (plugin_ldapextauth_search_if_user_is_admin ($this->ldap_conn, $loginname)) { //l'utente e' gforge admin $i ->setUserAsGforgeAdmin($loginname); // in INFN.class } else { //l'utente non e' gforge admin $i ->unsetUserAsGforgeAdmin($loginname);// in INFN.class } - La funzione plugin_ldapextauth_search_if_user_is_admin di LdapExtAuthPlugin.class -

Con la funzione nuova plugin_ldapextauth_search_if_user_is_admin viene effettuata una ricerca in LDAP per verificare se l'utente (che si è già autenticato) abbia o meno i privilegi di admin. Il privilegio di essere admin lo si può verificare dalla presenza o meno di un ruolo relativo all'utente, questo valore viene memorizzato in una variabile apposita nel file local.inc: $sys_ldap_admin_ns_role ='cn=global-SuperB-gforge-admin,dc=infn,dc=it'; - Porzione di codice di local.inc indicante il ruolo di admin -

Gli utenti che hanno un ruolo analogo sono da considerarsi con privilegi di admin. Questa operazione di verifica viene effettuata ad ogni login in automatico come da specifiche in quanto viene lasciata la possibilitò di modificare come e quando si vuole l'albero LDAP. In questo modo si possono dare privilegi di admin a qualsiasi utente che è già presente nel sistema in ogni momento del ciclo di vita stesso. A seguire la funzione plugin_ldapextauth_search_if_user_is_admin contenuta in mapping.php: function plugin_ldapextauth_search_if_user_is_admin($ldap_conn, $username) { global $sys_ldap_base_dn,$sys_ldap_admin_ns_role; $filter ="(&(uid=".$username.")(nsrole=".$sys_ldap_admin_ns_role.")) "; $result = ldap_search($ldap_conn, $sys_ldap_base_dn , $filter); $count = ldap_count_entries($ldap_conn ,$result); Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 88 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

}

if (ldap_first_entry($ldap_conn, $result) ){ //*user is admin! return true; } else { //*user is not admin return false; } - La funzione plugin_ldapextauth_search_if_user_is_admin di mapping.php -

Questa funzione esegue una ricerca iterativa filtrata per due campi concatenati: lo username dell'utente e il ruolo che dovrebbe avere se ha privilegi di admin. La funzione restituisce valore true se il primo valore estrapolato dalla lista non è nullo quindi è un utente con un nsrole di admin altrimenti restituisce valore falso. Se l'utente ha privilegi di admin si proverà a fare un operazione di insert del record richiamando questa funzione: function setUserAsGforgeAdmin($loginname) { //*inserisco qui a parte la funzione per inserire l'admin di gforge e non nella // create perche' si possono inserire o modificare //*utenti di LDAP che sono gia presenti su Postgres ed hanno gia effettuato accessi //come utenti normali. $sql="SELECT user_id FROM users WHERE user_name = '" .$loginname. "' "; $result=db_query($sql); $rows = db_numrows($result); $id_utente = db_result($result,0,'user_id'); //id utente db_begin(); $sql="INSERT INTO user_group (user_id,group_id,admin_flags) VALUES ('" .$id_utente. "','1','A')"; $result=db_query($sql); if (!$result) {

}

//se il valore e' gia' inserito va avanti senza errore... //errore di chiave duplicata ignorato db_rollback(); } else { db_commit(); } return $result; - La funzione setUserAsGforgeAdmin di INFN.class -

Per prima cosa si cerca lo user_id dell'utente a cui si vogliono dare i privilegi di admin, dopo di che si esegue una precisa operazione di INSERT nella tabella user_group. L'operazione viene sempre eseguita anche se nella tabella vi è già inserito tale valore, se il valore è già presente allora si esegue una operazione di rollback, se invece il valore non è presente si effettua il commit di tale operazione. In questo seconda possibilità si è nel caso in cui un utente è già presente nel sistema ovvero ha già effettuato dei login ed è quindi già presente in PostgreSQL ma nel frattempo gli sono stati assegnati dei privilegi di admin indicati nell'albero LDAP. Analogamente vi è l'operazione di eliminazione dei privilegi di admin con la funzione: function unsetUserAsGforgeAdmin($loginname) { //*inserisco qui a parte la funzione per inserire l'admin di gforge e non nella // create perche' si possono inserire o modificare //*utenti di LDAP che sono gia presenti su Postgres ed hanno gia effettuato accessi //come utenti normali. $sql="SELECT user_id FROM users WHERE user_name = '" .$loginname. "' "; $result=db_query($sql); $rows = db_numrows($result); $id_utente = db_result($result,0,'user_id'); //id utente db_begin(); $sql="DELETE FROM user_group WHERE user_id = '" .$id_utente. "' "; $result=db_query($sql); if (!$result) { //se il valore non c'e va avanti senza errore... db_rollback();

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 89 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

}

} else { db_commit(); } return $result; - La funzione UnsetUserAsGforgeAdmin di INFN.class -

Anche qui si cerca per prima cosa lo user_id dell'utente dopo di che si effettua sempre una operazione di delete nella stessa tabella indicata precedentemente user_group. Se l'operazione di cancellazione non va a buon fine vuol dire che l'utente anche in precedenza non è un utente admin quindi si abortisce con un rollback. Se invece l'operazione va a buon fine significa che l'utente in precedenza era admin ma questi privilegi nel frattempo sono stati cancellati dal LDAP. In tal caso l'operazione di commit esegue realmente l'intenzione della cancellazione.

3.3.6 -

Modifica del campo mail per gli utenti:

Gli utenti, come da specifiche indicate, non devono avere la possibilità di modificare la propria mail. In fase di registrazione deve essere memorizzata quella di default presente in LDAP. GForge invece prevede attraverso un link e nuova pagina apposita la possibilità di modificare la propria mail anche se solamente in PostgreSQL. Questa situazione non era accettabile anche perché si veniva ad avere dei possibili stati inconsistenti in quanto si poteva modificare la mail di PostgreSQL ma non quella di LDAP. Gli utenti di INFN in ogni caso non hanno la possibilità e la facoltà di intervenire nell'albero LDAP per modificare tale campo ma lo può effettuare solamente l'admin del sistema. Per tale motivo il campo mail è da considerarsi in sola lettura da LDAP e la modifica dello stesso è stata disabilitata per gli utenti di GForge.

3.3.7 -

Eliminazione della possibilità di registrazione via web di nuovi utenti

Riprendendo l'analisi delle specifiche stilata in precedenza si può notare che uno dei punti del progetto GForge non ammissibile era la possibilità lasciata a qualsiasi utente di registrarsi al front-end. Questo non è ammissibile poichè devono poter accedere solo gli utenti che hanno delle credenziali inserite in LDAP e in base a queste devono effettuare l'autenticazione e l'autorizzazione. Il progetto si presenta così con un link nella home che rimanda ad una pagina dove appare un form per la registrazione di un nuovo utente. Dopo aver dato un “submit” il procedimento continuerà attraverso l'invio di una mail all'utente stesso che dovrò confermare. Questa procedura è stata così elaborata per evitare lo spam. Questa configurazione, come detto, non è accettabile e l'eliminazione della stessa è stata molto semplice. E' stata quindi rimossa la pagina stessa e il link oscurato. Così facendo, solo gli utenti con credenziali in LDAP possono effettuare il login e nessun nuovo utente può iscriversi via web. Nel caso in cui si voglia allargare il parco utenti allora è necessario inserire in LDAP un nuovo utente per tutto il sistema. Così facendo poi il nuovo utente in automatico verrà riconosciuto anche da GForge. In figura 15 si può notare la presenza del solo tasto “accedi” per gli utenti che desiderano effettuare il login.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 90 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 15: La homepage di GForge.

3.3.8 -

Iscrizione degli utenti a nuovi progetti

Un utente registrato può richiedere di partecipare ad un certo progetto se disponibile e pubblico. In ogni caso l'accettazione della sua richiesta è pendente la volontà dell'utente con livello di admin che approverà o meno tale richiesta. Questa operazione non era possibile in quanto veniva restituito errore proprio nel momento in cui si approvava tale richiesta. Il codice che dava problemi lo si può trovare in index.php contenuto in /var/www/gforge/admin e viene riproposto qui sotto: if ($submit) { if ($adduser) { /* add user to this project */ if (!$group->addUser($form_unix_name,$role_id)) { $feedback .= $group->getErrorMessage(); } else { $feedback = $Language->getText('project_admin','user_added'); } } else if ($rmuser) { /* Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 91 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

}

remove a user from this group */ if (!$group->removeUser($user_id)) { $feedback .= $group->getErrorMessage(); } else { $feedback = $Language->getText('project_admin','user_removed'); } } else if ($updateuser) { /* Adjust User Role */ if (!$group->updateUser($user_id,$role_id)) { $feedback .= $group->getErrorMessage(); } else { $feedback = $Language->getText('project_admin','user_updated'); } } elseif ($acceptpending) { /* add user to this project */ if (!$group->addUser($form_unix_name,$role_id)) { $feedback .= $group->getErrorMessage(); } else { $gjr=new GroupJoinRequest($group,$form_userid); if (!$gjr || !is_object($gjr) || $gjr->isError()) { $feedback .= 'Error Getting GroupJoinRequest'; } else { $gjr->delete(true); } $feedback = $Language->getText('project_admin','user_added'); } } elseif ($rejectpending) { /* reject adding user to this project */ $gjr=new GroupJoinRequest($group,$form_userid); if (!$gjr || !is_object($gjr) || $gjr->isError()) { $feedback .= 'Error Getting GroupJoinRequest'; } else { if (!$gjr->reject()) { exit_error('Error',$gjr->getErrorMessage()); } else { $feedback .= 'Rejected'; } } } - La funzione index.php contenuta in /var/www/gforge/admin -

Questo problema è stato semplicemente risolto andando a rimuovere l'oggetto invocato e dichiarando così quello corretto. Infatti la funzione AddUser come le altre più sotto sono contenute nella classe Group.class contenuta in common/include, l'oggetto invece a causa delle modifiche sin qui fatte puntava all'oggetto INFN.class. Ecco la funzione richiamata che va ad inserire nel database di PostgreSQL le informazioni relative l'utente e il gruppo a cui parteciperà: /** * addUser - controls adding a user to a group. * * @param string Unix name of the user to add OR integer user_id. * @param int The role_id this user should have. * @return boolean success. * @access public. */ function addUser($user_unix_name,$role_id) { global $Language,$SYS; /* Admins can add users to groups */ $perm =& $this->getPermission( session_get_user() ); if (!$perm || !is_object($perm) || !$perm->isAdmin()) { $this->setPermissionDeniedError(); return false; } db_begin(); Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 92 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

/* get user id for this user's unix_name */ if (eregi('[^0-9]',$user_unix_name)) { $res_newuser = db_query("SELECT * FROM users WHERE user_name='". strtolower($user_unix_name) ."'"); } else { $res_newuser = db_query("SELECT * FROM users WHERE user_id='". intval($user_unix_name) ."'"); } if (db_numrows($res_newuser) > 0) { // // make sure user is active // if (db_result($res_newuser,0,'status') != 'A') { $this->setError('User is not active. Only active users can be added.'); db_rollback(); return false; } // // user was found - set new user_id var // $user_id = db_result($res_newuser,0,'user_id'); // // if not already a member, add them // $res_member = db_query("SELECT user_id FROM user_group WHERE user_id='$user_id' AND group_id='". $this->getID() ."'"); if (db_numrows($res_member) < 1) { // // Create this user's row in the user_group table // $res=db_query("INSERT INTO user_group (user_id, group_id, admin_flags, forum_flags,project_flags, doc_flags, cvs_flags, member_role, release_flags,artifact_flags) VALUES ('$user_id','". $this->getID() ."','','0','0','0','1','100','0','0')"); //verify the insert worked if (!$res || db_affected_rows($res) < 1) { $this->setError('ERROR: Could Not Add User To Group: '.db_error()); db_rollback(); return false; } // // Add to all forums // $sql="INSERT INTO forum_perm (group_forum_id, user_id, perm_level) SELECT group_forum_id,$user_id,1 FROM forum_group_list WHERE group_id='".$this->getID()."'"; $res=db_query($sql); if (!$res) { $this->setError('Adding to forums: '.db_error()); db_rollback(); return false; } // // Add to all subprojects // $sql="INSERT INTO project_perm (group_project_id, user_id, perm_level) SELECT group_project_id,$user_id,2 FROM project_group_list WHERE group_id='".$this->getID()."'"; $res=db_query($sql); if (!$res) { $this->setError('Adding to subprojects: '.db_error()); db_rollback(); return false; } //

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 93 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

// Add to all trackers // $sql="INSERT INTO artifact_perm (group_artifact_id, user_id, perm_level) SELECT group_artifact_id,$user_id,2 FROM artifact_group_list WHERE group_id='".$this->getID()."'"; $res=db_query($sql); if (!$res) { $this->setError('Adding to subprojects: '.db_error()); db_rollback(); return false; } // // check and create if group doesn't exists // //echo "<h2>Group::addUser SYS->sysCheckCreateGroup(".$this>getID().")</h2>"; if (!$SYS->sysCheckCreateGroup($this->getID())){ $this->setError($SYS->getErrorMessage()); db_rollback(); return false; } // // check and create if user doesn't exists // //echo "<h2>Group::addUser SYS>sysCheckCreateUser($user_id)</h2>"; if (!$SYS->sysCheckCreateUser($user_id)) { $this->setError($SYS->getErrorMessage()); db_rollback(); return false; } // // Role setup // $role = new Role($this,$role_id); if (!$role || !is_object($role)) { $this->setError('Error Getting Role Object'); db_rollback(); return false; } elseif ($role->isError()) { $this->setError('addUser::roleget::'.$role>getErrorMessage()); db_rollback(); return false; } //echo "<h2>Group::addUser role->setUser($user_id)</h2>"; if (!$role->setUser($user_id)) { $this->setError('addUser::role::setUser'.$role>getErrorMessage()); db_rollback(); return false; } } else { // // user was already a member // make sure they are set up // $user=&user_get_object($user_id,$res_newuser); $user->fetchData($user->getID()); $role = new Role($this,$role_id); if (!$role || !is_object($role)) { $this->setError('Error Getting Role Object'); db_rollback(); return false; } elseif ($role->isError()) { $this->setError ('addUser::roleget::'.$role>getErrorMessage()); db_rollback(); return false; } //echo "<h2>Already Member Group::addUser role>setUser($user_id)</h2>"; if (!$role->setUser($user_id)) { $this->setError('addUser::role::setUser'.$role>getErrorMessage());

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 94 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

db_rollback(); return false; } // // set up their system info // //echo "<h2>Already Member Group::addUser SYS//>sysCheckCreateUser($user_id)</h2>"; if (!$SYS->sysCheckCreateUser($user_id)) { $this->setError($SYS->getErrorMessage()); db_rollback(); return false; } db_commit(); return true;

}

} } else { // //user doesn't exist //$this->setError('ERROR: User does not exist'); db_rollback(); return false; } // // audit trail // $this->addHistory('Added User',$user_unix_name); db_commit(); return true; - La funzione AddUser di Group.class -

Cambiando il riferimento a questo oggetto anche l'iscrizione di utenti a progetti funziona correttamente. In figura 16 si può otare che viene data solo la possibilità di effettuare il login con SSL.

Figura 16: Pagina del login

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 95 -

Figura 17: La home page dell'utente dopo aver effettuato il login


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Nella figura 17 si possono vedere tra le altre cose i progetti personali e il link per registrare nuovi progetti. La pagina per registrare un nuovo progetto viene riproposta nella immagine 18.

Figura 18: Pagina relativa alla registrazione di un nuovo progetto Una volta registrato un nuovo progetto, questi viene reso pubblico e ad esso si può richiedere di parteciparvi. La

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 96 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

partecipazione non è automatica ma deve essere approvata da un utente con privilegi di admin per quel gruppo. In figura 19 l'operazione per richiedere di partecipare ad un progetto esistente:

Figura 19: L'utente “ppallino” sta accedendo al progetto “pizza” per visualizzarne le informazioni. In questo caso l'utente “ppallino” vuole partecipare al progetto “pizza”. Invierà quindi un messaggio attraverso un form agli amministratori. Questi si ritroveranno di fronte ad una pagina indicata in figura 20.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 97 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Figura 20: In questa sezione vengono visualizzate le richieste pendenti del gruppo “pizza” In questa pagina gli utenti admin vedranno i membri del progetto che vi stanno già partecipando. In questo caso nessuno. Più sotto invece le richieste di partecipazione al gruppo ancora pendenti. Ora l'utente admin potrà approvare o rifiutare la richiesta pendente. Qui sotto viene riproposto in contenuto del file INFN.class <?php /** * INFN class * * Class to interact with the system * */ require_once('common/include/account.php'); require_once('common/include/system/UNIX.class'); class INFN extends UNIX { /** * INFN() * */ function INFN() { $this->UNIX(); return true; } /** * sysUserSetAttribute() - Set an attribute for a user * * @param int The user ID * @param string The attribute to set * @param string The new value of the attribute * @returns true on success/false on error * */ function sysUserSetAttribute($user_id,$attr,$value) { global $sys_ldap_base_dn,$sys_ldap_host, $sys_ldap_port; $user = &user_get_object($user_id); Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 98 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

if (!$this->gfLdapConnect()) { return false; } $this->ldap_conn = ldap_connect ($sys_ldap_host, $sys_ldap_port); $dn = plugin_ldapextauth_getdn_after_search ($this->ldap_conn, $user>getUnixName()) ; //cerco dn utente $entry[$attr]=$value; if (!$this->gfLdapModifyIfExists($dn, $entry)) {//* in questa classe //modifica l'attributo $this->setError("ERROR: cannot change LDAP attribute '$attr' for user '". $user->getUnixName()."': ".$this->gfLdapError()."<br />"); return false; } return true; } /** * gfLdapConnect() - Connect to the LDAP server * * @returns true on success/false on error * */ function gfLdapConnect() { global $sys_ldap_host,$sys_ldap_port; global $sys_ldap_bind_dn,$sys_ldap_passwd,$ldap_conn,$sys_ldap_version; if (!$ldap_conn) { $this->clearError(); $ldap_conn = @ldap_connect($sys_ldap_host,$sys_ldap_port); if (!$ldap_conn) { $this->setError('ERROR: Cannot connect to LDAP server<br />'); return false; } if ($sys_ldap_version) { ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $sys_ldap_version); } if (ldap_bind($ldap_conn,$sys_ldap_bind_dn,$sys_ldap_passwd)) { //connessione ok return true; } } return true; } /** * gfLdapModify() - Wrapper for ldap_modify() * * @param string dn * @param string entry * */ function gfLdapModify($dn,$entry) { global $ldap_conn; return @ldap_modify($ldap_conn,$dn,$entry); } /** * gfLdapModifyIfExists() - Wrapper for ldap_modify() * works like gfLdapModify, but returns true if the LDAP entry does not exist * * @param string dn * @param string entry * */ function gfLdapModifyIfExists($dn,$entry) { $res = $this->gfLdapModify($dn,$entry); if ($res) { return true ; } else { $err = ldap_errno ($ldap_conn) ;

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 99 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

if ($err == 32) { return true ; } else { return false ; } }; } /** * gfLdapError() - Wrapper for ldap_error() * * @see ldap_error() * */ function gfLdapError() { global $ldap_conn; return ldap_error($ldap_conn); } /** * gfLdapErrno() - Wrapper for ldap_errno() * * @see ldap_errno() * */ function gfLdapErrno($ldap_conn) { return ldap_errno($ldap_conn); } function setUserAsGforgeAdmin($loginname) { //*inserisco qui a parte la funzione per inserire l'admin di gforge e non //nella create perche' si possono inserire o modificare //*utenti di LDAP che sono gia presenti su Postgres ed hanno gia effettuato //accessi come utenti normali. $sql="SELECT user_id FROM users WHERE user_name = '" .$loginname. "' "; $result=db_query($sql); $rows = db_numrows($result); $id_utente = db_result($result,0,'user_id'); //id utente db_begin(); $sql="INSERT INTO user_group (user_id,group_id,admin_flags) VALUES ('" .$id_utente. "','1','A')"; $result=db_query($sql); if (!$result) { //se il valore e' gia' inserito va avanti senza errore... //errore di chiave duplicata ignorato db_rollback(); } else { db_commit(); } return $result; } function unsetUserAsGforgeAdmin($loginname) { //*inserisco qui a parte la funzione per inserire l'admin di gforge e non //nella create perche' si possono inserire o modificare //*utenti di LDAP che sono gia presenti su Postgres ed hanno gia effettuato //accessi come utenti normali. $sql="SELECT user_id FROM users WHERE user_name = '" .$loginname. "' "; $result=db_query($sql); $rows = db_numrows($result); $id_utente = db_result($result,0,'user_id'); //id utente db_begin(); $sql="DELETE FROM user_group WHERE user_id = '" .$id_utente. "' "; $result=db_query($sql); if (!$result) { //se il valore non c'e va avanti senza errore... db_rollback(); } else { db_commit(); } return $result; } // Local Variables: // mode: php

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 100 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

// c-file-style: "bsd" // End:} ?> - Il contenuto del file INFN.class -

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 101 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 102 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

CAPITOLO 4 - CONCLUSIONI

Il lavoro svolto per questa tesi è parte di un progetto di collaborazione internazionale per la realizzazione di un acceleratore e di un rivelatore di particelle. In particolare si trattava di realizzare un sistema collaborativo di gestione del codice, da inserire in un più ampio sistema di gestione delle attività dei partecipanti al progetto, alcune centinaia di ricercatori. Il tempo necessario non è stato poco, soprattutto a causa della scarsità della documentazione dei pacchetti che si era deciso di utilizzare. In particolare non c'era documentazione sui vari aspetti interni, come la struttura del database, il flusso dei dati, ecc. Inoltre, in molte parti, specialmente inerenti al plugin, il codice è confuso e assolutamente non auto-esplicativo. Una frazione consistente del tempo è stata quindi necessaria per fare il reverse engineering del codice e ricostruire il flusso delle informazioni. Sin dal primo utilizzo e studio del sistema ci si è accorti che l'integrazione di GForge con il servizio di directory è in realtà un lavoro ancora in fase di sviluppo e non funzionante in modo affidabile. Si è proceduto quindi ad analizzare il codice per vedere se fosse possibile estendere le funzionalità con un plugin. Anche questa strada è stata impraticabile poichè, mentre le funzioni per interagire con il database sono struttutate a layer, quelle per interfacciarsi con LDAP sono sparse nel codice. L'unica alternativa sarebbe stata il reverse engineering e il refactoring totale dell'applicativo ma sarebbe stato necssario un tempo incompatibile con le necesità della collaborazione. Alla luce di ciò si è quindi optato per intervenire direttamente nel codice in modo da integrare l'autenticazione mediante LDAP. L'applicativo GForge modificato funziona correttamente in base alle specifiche richieste stilate in fase di analisi dei requisiti. Il repository del codice è operativo così come tutti i servizi annessi di GForge che hanno spinto alla scelta di questo prodotto come la messaggistica, i forum, la gestione delle release, e molti altri.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 103 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 104 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

BIBLIOGRAFIA 1. The discovery potential of the SuperB Factory, di JoAnne Hewett, David G. Hitlin. Ed. Slac-R-709, 12.2004 2. SuperB – Conceptual design report. A high Luminosity Asymmetruc e+ e- Super Flavour Factory. Ed INFN/ AE. Slac 856, LAL 07-15. 03.2007 3. www.gforge.org 4. www.apache.org 5. http://www.psql.it/ 6. http://it.wikipedia.org/wiki/PostgreSQL 7. http://www.gentoo.org/doc/it/postgres-howto.xml 8. http://www.psql.it/manuale/8.3/ 9. http://www.openssl.org/ 10. http://it.wikipedia.org/wiki/OpenSSL 11. http://www.modssl.org/ 12. http://it.wikipedia.org/wiki/PHP 13. http://www.php.net/ 14. http://it.php.net/tut.php 15. http://www.php.net/docs.php 16. http://www.openldap.org/ 17. http://www.linuxguide.it/docs.php?Server:OpenLDAP

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 105 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

UniversitĂ  degli Studi di Ferrara â&#x20AC;&#x201C; Tesi di Laurea Magistrale in Ingegneria Informatica

- 106 -


Integrazione di un software repository in un ambiente centralizzato di autenticazione

Un sentito ringraziamento va alla mia famiglia che mi ha permesso di coltivare questo percorso e che mi ha sempre sostenuto durante questi anni. Un grazie quindi a papà Luciano e mamma Lauretta nonché ad Enrico per tutto quello che hanno fatto per me. Un pensiero anche per Jenny che mi è sempre stata vicino durante questo lungo cammino e alla zia Luciana. In questo momento di gaudio e felicità ho comunque un rimpianto: che a questa festa non sia riuscito a partecipare mio zio Beppi a cui sono sempre stato vicino e a cui devo molto soprattutto in gioventù. Sono comunque certo che è qui con noi, orgoglioso del nipote.

Università degli Studi di Ferrara – Tesi di Laurea Magistrale in Ingegneria Informatica

- 107 -


INTEGRAZIONE DI UN SOFTWARE REPOSITORY IN UN AMBIENTE CENTRALIZZATO DI AUTENTICAZIONE