4.2. Struttura del database

Le informazioni in LDAP sono conservate sotto forma di oggetti (entries) caratterizzati da attributi, ogni attributo ha un id ben definito ed univoco detto OID.

Gli oggetti sono mantenuti in modo gerarchico secondo il loro distinguished name (abbreviato in dn). Gli oggetti "figli" ereditano il dn del genitore ponendolo come suffisso al loro stesso dn. La struttura che ne deriva è dunque disposta ad albero.

Con un albero di questo tipo

			o=Anarchy
			 \-- dc=org
			     \-- dc=infra
      
il dn dell'oggetto investici risulta dunque essere
	dc=infra, dc=org, o=Anarchy
      

Ciascun oggetto può avere differenti attributi a seconda delle classi a cui appartiene. L'ereditarietà in LDAP può essere multipla (cioè un oggetto può appartenere a più classi contemporaneamente). Ciascuna classe definisce attributi, necessari od opzionali, che devono (o possono) essere presenti nell'oggetto. Queste strutture sono descritte negli schemi di LDAP.

4.2.1. Contenuto del database

Nella struttura che abbiamo adottato, per isolare l'albero con i nostri dati da quelli di eventuali altre virtual organizations come la nostra, i dati relativi al nostro sistema saranno interamente collocati al di sotto dell'oggetto dc=infra, dc=org, o=Anarchy (questa è una nomenclatura standard).

Il database comprende varie tipologie differenti di utenze e di altri oggetti, memorizzati in rami differenti dell'albero LDAP collocati al di sotto di dc=infra, dc=org, o=Anarchy:

4.2.2. Utenze virtuali

Intendiamo qui di seguito "utente" nel significato di "contatto", concetto che introduciamo per poter raggruppare i servizi che fanno capo ad un'unica entità, sia persona che organizzazione o altro, scelta in modo da agevolare l'amministrazione dei servizi.

Ciascun utente è rappresentato nel database da un oggetto identificato dalla chiave uid. Possiamo scegliere per questi oggetti la nomenclatura che preferiamo: nel nostro caso facciamo l'esempio di nominare gli utenti con il loro indirizzo email principale (es: uid=phasa@dominio.org) Volendo raggruppare i servizi relativi ad esempio ad un'organizzazione intera, anziché un singolo utente, potremmo scegliere di creare un oggetto con un nome di dominio uid=organizzazione.it o qualunque altra cosa ci sembri significativa (una volta scelto uno schema).

A ciascuno di questi oggetti possono essere associati diversi servizi, che saranno oggetti collocati al di sotto dell'oggetto "utente". Il tipo di questi oggetti corrisponderà al tipo di servizio. Per esempio queste sono alcune strutture possibili:


* un singolo utente con casella di posta

  ou=People
  \-- uid=utente@dominio.org                    shadowAccount
      \-- mail=utente@dominio.org               virtualMailUser

* utente con casella di posta e sito web (e dunque account ftp)

  ou=People
  \-- uid=utente@dominio.org                    shadowAccount              
      +-- mail=utente@dominio.org               virtualMailUser
      +-- alias=sitoutente                      subSite
      \-- ftpname=utente                        ftpAccount

* organizzazione con piu' account, sito web e dominio proprio

  ou=People
  \-- uid=organiz.org                           shadowAccount
      +-- mail=utente1@organiz.org              virtualMailUser
      +-- mail=utente2@organiz.org              virtualMailUser
      +-- cn=www.organiz.org                    virtualHost
      \-- ftpname=organiz                       ftpAccount
Sulla destra di ciascun oggetto è specificata la classe cui appartiene. In particolare gli oggetti utente appartengono alla classe shadowAccount (uno standard POSIX) che, seppure non venga mai utilizzata per l'autenticazione, permette di risolvere i lookup NSS e dunque gestire le quote più facilmente (potendo specificare direttamente il nome dell'utente anziché solo la uid numerica).

4.2.3. Autenticazione

Nella struttura sopra descritta ciascun servizio che necessita autenticazione la effettua direttamente sull'oggetto "figlio" del tipo relativo. Dunque le credenziali di autenticazione presenti nell'oggetto shadowAccount che identifica l'utente, benché presenti perché richieste dallo schema, non sono mai utilizzate direttamente.

Tramite opportuni filtri di query dunque si fa in modo che per esempio il demone IMAP effettui l'autenticazione degli utenti su un oggetto di tipo virtualMailUser, con la sua propria password. Questo meccanismo permette, volendolo, di avere password differenziate per i vari servizi. La possibilità di fare ciò rientra nelle policy che vanno imposte attraverso gli strumenti di amministrazione, in quanto LDAP, al contrario di un database relazionale, non ha dei meccanismi propri per specificare, appunto, particolari relazioni tra oggetti diversi (tranne quella gerarchica): per questo è impossibile (o estremamente contorto) specificare in LDAP concetti come il fatto che un oggetto debba avere la stessa password di quello che lo contiene; questo fatto porta naturalmente ad una certa ridondanza dei dati presenti nello schema (non elevata, però).

Vedremo ora a grandi linee come sono configurati i vari servizi (relativamente all'autenticazione sul database LDAP). Per ogni servizio sono specificati quali sono i files di configurazione relativi all'autenticazione, e qual è il tipo di query effettuata - costituita da una base che limita la ricerca e una query (detta anche filtro) che cerca un oggetto specifico:

ssh

ssh si autentica tramite PAM con un file specifico di configurazione che seleziona solamente il ramo ou=Admins del database ldap.

query: &(uid=*)(objectClass=posixAccount)

base: ou=Admins, dc=infra, dc=org, o=Anarchy

files:

  /etc/pam.d/common-auth
  auth  sufficient  pam_ldap.so config=/etc/pam_ldap_admin.conf
  auth  required    pam_unix.so use_first_pass
	      

  /etc/pam_ldap_admin.conf
  host 127.0.0.1
  base ou=Admins,dc=infra,dc=org,o=Anarchy
  ldap_version 3
  rootbinddn cn=manager,o=Anarchy
  pam_password crypt
	      

vsftpd

il demone FTP utilizza sempre PAM ma con un altro file di configurazione, che cerca oggetti con attributo objectClass=ftpAccount e host uguale al nome della macchina.

query: &(ftpname=*)(objectClass=ftpAccount)(host=server1)

base: ou=People, dc=infra, dc=org, o=Anarchy

files:

   /etc/pam.d/vsftpd
   auth  required  pam_ldap.so config=/etc/pam_ldap_ftp.conf
	      

   /etc/pam_ldap_ftp.conf
   host 127.0.0.1
   base ou=People,dc=infra,dc=org,o=Anarchy
   ldap_version 3
   rootbinddn cn=manager,o=Anarchy
   scope sub
   pam_login_attribute ftpname
   pam_filter &(host=test1)(status=active)
   pam_password crypt
	      

dovecot

dovecot e' il demone IMAP, ed autentica gli utenti di posta. Non usa PAM ma dei meccanismi propri.

query: &(objectClass=virtualMailUser)(host=server1)

base: ou=People, dc=infra, dc=org, o=Anarchy

files:

   /etc/dovecot/dovecot-ldap.conf
   ldap_version = 3
   scope = subtree
   dn = cn=dovecot,ou=Operators,dc=infra,dc=org,o=Anarchy
   dnpass = blablabla
   base = ou=People,dc=infra,dc=org,o=Anarchy
   user_attrs = mail,mailMessageStore,mailMessageStore,,uidNumber,gidNumber
   user_filter = (&(objectClass=virtualMailUser)(status=active)(mail=%u))
   pass_attrs = mail,userPassword
   pass_filter = (&(objectClass=virtualMailUser)(status=active)(mail=%u))
	      

saslauthd

SASL serve ad autenticare gli utenti che spediscono i loro messaggi con SMTP. saslauthd è il demone che effettua l'autenticazione. La configurazione di questo programma è differente dalle altre in quanto è possibile saltare PAM ed effettuare direttamente una query LDAP, questo però richiede un formato diverso del file di configurazione. Inoltre dato che autentichiamo utenti con nome E dominio, bisogna ricordarsi di dare al programma l'opzione -r (per non scartare il realm), e di creare il socket nella chroot di Postfix...

query: &(mail=*)(objectClass=virtualMailUser)

base: ou=People, dc=infra, dc=org, o=Anarchy

files:

   /etc/default/saslauthd
   START=yes
   MECHANISMS="ldap"
   PWDIR=/var/spool/postfix/var/run/saslauthd
   PIDFILE="$PWDIR/saslauthd.pid"
   PARAMS="-r -m $PWDIR"
	      

   /etc/saslauthd.conf
   ldap_servers: ldap://127.0.0.1/
   ldap_bind_dn: cn=ring0op,ou=Operators,dc=infra,dc=org,o=Anarchy
   ldap_password: blablabla
   ldap_search_base: ou=People,dc=infra,dc=org,o=Anarchy
   ldap_filter: (&(status=active)(objectClass=virtualMailUser)(mail=%u))
   ldap_auth_method: custom
	      

Nota: tutte le query sopra descritte confrontano la password fornita con quella memorizzata nell'attributo userPassword. Anche su questo è il caso di precisare una cosa che può risultare utile: le password possono venir memorizzate nel database LDAP codificate in modi differenti, contraddistinti da un prefisso posto prima della password tra parentesi graffe, ad esempio

	  {crypt}dlkj8h23dU9j1
	
Altri metodi oltre a crypt (che utilizza la funzione crypt di sistema) sono MD5 e SSHA, che utilizzano semplicemente un hash della password. Molti comandi comuni (ad esempio ldappasswd) impostano la password con uno di questi ultimi meccanismi, considerati più sicuri. Questo è rilevante dal momento che c'è più di una possibilità per verificare l'autenticazione: molti servizi utilizzano il cosiddetto bind LDAP, ovvero semplicemente tentano l'accesso al database LDAP usando le credenziali fornite: in questo caso è il server LDAP medesimo a verificare la password, ma esistono altri servizi (un esempio per tutti è dovecot) che fanno le cose in modo differente: ottengono la password dal server LDAP e la verificano autonomamente, e bisogna fare molta attenzione al fatto che generalmente non sono in grado di verificare correttamente le password memorizzate con meccanismi diversi da crypt!