pgina-ldap

Provo ad utilizzare il plugin ldap del progetto pgina, su windows7, sfruttando come backend ldap quello creato negli scorsi articoli su ldap.

Db principale

Db Accesso

TEST 1
Gina 3.0, bind diretto di un utente
(User DN Pattern: uid=%u,ou=People,dc=rete,dc=net)

3_0_config_ldap

 

Quindi, così configurato gina manda le credenziali con cui l'utente cerca di loggarsi in windows a ldap e si affida ad esso per l' autentica. Se ldap risponde positivamente allora crea un account locale sulla base delle credenziali che gli tornano da ldap (magari alterandole) e effettua il login su windows.

Log128
=> access_allowed: result not in cache (userPassword)
=> access_allowed: auth access to "uid=sarti,ou=People,dc=rete,dc=net" "userPassword" requested
=> acl_get: [1] attr userPassword
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "userPassword" requested
=> acl_mask: to value by "", (=0)
<= check a_dn_pat: self
<= check a_dn_pat: anonymous
<= acl_mask: [2] applying auth(=xd) (stop)
<= acl_mask: [2] mask: auth(=xd)
=> slap_access_allowed: auth access granted by auth(=xd)
=> access_allowed: auth access granted by auth(=xd)

Log256

conn=1000 fd=15 ACCEPT from IP=192.168.0.4:49443 (IP=0.0.0.0:389)
conn=1000 op=0 BIND dn="uid=sarti,ou=People,dc=rete,dc=net" method=128
conn=1000 op=0 BIND dn="uid=sarti,ou=People,dc=rete,dc=net" mech=SIMPLE ssf=0
conn=1000 op=0 RESULT tag=97 err=0 text=
conn=1000 op=1 UNBIND
conn=1000 fd=15 closed

TEST 2
Gina 3.1 Search e bind con un'altro utente.

(Serach for DN:
Search DN cn=utente1,dc=access,dc=net
Search password: utente1
Search Filter: uid=%u
Search Context(s); ou=People,dc=retre,dc=net
)

 

3_1_config_ldap_search

In questo caso l'utente da le sue credenziali su windows, gina si binda al db ldap con "utente1//utente1" cerca un uid corrispondente alle credenziali che gli arrivano e, trovandolo, si ri-binda con questo utente.Se ldap risponde positivamente allora crea un account locale sulla base delle credenziali che gli tornano da ldap (magari alterandole) e effettua il login su windows.

Log128
=> access_allowed: result not in cache (userPassword)
=> access_allowed: auth access to "cn=utente1,dc=access,dc=net" "userPassword" requested
=> acl_get: [1] attr userPassword
=> acl_mask: access to entry "cn=utente1,dc=access,dc=net", attr "userPassword" requested
=> acl_mask: to value by "", (=0)
<= check a_dn_pat: self
<= check a_dn_pat: anonymous
<= acl_mask: [2] applying auth(=xd) (stop)
<= acl_mask: [2] mask: auth(=xd)
=> slap_access_allowed: auth access granted by auth(=xd)
=> access_allowed: auth access granted by auth(=xd)
=> access_allowed: search access to "ou=People,dc=rete,dc=net" "entry" requested
=> acl_get: [2] attr entry
=> acl_mask: access to entry "ou=People,dc=rete,dc=net", attr "entry" requested
=> acl_mask: to all values by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: search access granted by read(=rscxd)
=> access_allowed: search access granted by read(=rscxd)
=> access_allowed: search access to "uid=sarti,ou=People,dc=rete,dc=net" "uid" requested
=> acl_get: [2] attr uid
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "uid" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: search access granted by read(=rscxd)
=> access_allowed: search access granted by read(=rscxd)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "entry" requested
=> acl_get: [2] attr entry
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "entry" requested
=> acl_mask: to all values by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (uid)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "uid" requested
=> acl_get: [2] attr uid
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "uid" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (cn)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "cn" requested
=> acl_get: [2] attr cn
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "cn" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (objectClass)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "objectClass" requested
=> acl_get: [2] attr objectClass
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "objectClass" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result was in cache (objectClass)
=> access_allowed: result was in cache (objectClass)
=> access_allowed: result was in cache (objectClass)
=> access_allowed: result not in cache (userPassword)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "userPassword" requested
=> acl_get: [1] attr userPassword
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "userPassword" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: self
<= check a_dn_pat: anonymous
<= check a_dn_pat: *
<= acl_mask: [3] applying none(=0) (stop)
<= acl_mask: [3] mask: none(=0)
=> slap_access_allowed: read access denied by none(=0)
=> access_allowed: no more rules
send_search_entry: conn 1000 access to attribute userPassword, value #0 not allowed
=> access_allowed: result not in cache (shadowLastChange)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "shadowLastChange" requested
=> acl_get: [1] attr shadowLastChange
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "shadowLastChange" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: self
<= check a_dn_pat: anonymous
<= check a_dn_pat: *
<= acl_mask: [3] applying none(=0) (stop)
<= acl_mask: [3] mask: none(=0)
=> slap_access_allowed: read access denied by none(=0)
=> access_allowed: no more rules
send_search_entry: conn 1000 access to attribute shadowLastChange, value #0 not allowed
=> access_allowed: result not in cache (shadowMin)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "shadowMin" requested
=> acl_get: [2] attr shadowMin
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "shadowMin" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (shadowMax)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "shadowMax" requested
=> acl_get: [2] attr shadowMax
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "shadowMax" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (shadowWarning)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "shadowWarning" requested
=> acl_get: [2] attr shadowWarning
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "shadowWarning" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (loginShell)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "loginShell" requested
=> acl_get: [2] attr loginShell
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "loginShell" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (uidNumber)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "uidNumber" requested
=> acl_get: [2] attr uidNumber
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "uidNumber" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (gidNumber)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "gidNumber" requested
=> acl_get: [2] attr gidNumber
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "gidNumber" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (homeDirectory)
=> access_allowed: read access to "uid=sarti,ou=People,dc=rete,dc=net" "homeDirectory" requested
=> acl_get: [2] attr homeDirectory
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "homeDirectory" requested
=> acl_mask: to value by "cn=utente1,dc=access,dc=net", (=0)
<= check a_dn_pat: cn=utente1,dc=access,dc=net
<= acl_mask: [1] applying read(=rscxd) (stop)
<= acl_mask: [1] mask: read(=rscxd)
=> slap_access_allowed: read access granted by read(=rscxd)
=> access_allowed: read access granted by read(=rscxd)
=> access_allowed: result not in cache (userPassword)
=> access_allowed: auth access to "uid=sarti,ou=People,dc=rete,dc=net" "userPassword" requested
=> acl_get: [1] attr userPassword
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "userPassword" requested
=> acl_mask: to value by "", (=0)
<= check a_dn_pat: self
<= check a_dn_pat: anonymous
<= acl_mask: [2] applying auth(=xd) (stop)
<= acl_mask: [2] mask: auth(=xd)
=> slap_access_allowed: auth access granted by auth(=xd)
=> access_allowed: auth access granted by auth(=xd)

Log256
conn=1000 fd=15 ACCEPT from IP=192.168.0.4:49449 (IP=0.0.0.0:389)
conn=1000 op=0 BIND dn="cn=utente1,dc=access,dc=net" method=128
conn=1000 op=0 BIND dn="cn=utente1,dc=access,dc=net" mech=SIMPLE ssf=0
conn=1000 op=0 RESULT tag=97 err=0 text=
conn=1000 op=1 SRCH base="ou=People,dc=rete,dc=net" scope=2 deref=0 filter="(uid=sarti)"
conn=1000 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text=
conn=1000 op=2 BIND anonymous mech=implicit ssf=0
conn=1000 op=2 BIND dn="uid=sarti,ou=People,dc=rete,dc=net" method=128
conn=1000 op=2 BIND dn="uid=sarti,ou=People,dc=rete,dc=net" mech=SIMPLE ssf=0
conn=1000 op=2 RESULT tag=97 err=0 text=
conn=1000 op=3 UNBIND
conn=1000 fd=15 closed

 

Da questi corposi log si può notare come come in questa modalità gina vada a cercare non solo uid e userPassword ma legga parecchi altri campi: Immagino che poi gli serviranno per meglio caratterizzare l'account windows locale che andrà a creare per permettere l'accesso.

NOTA molto importante, dalla documentazione di pgina.
"Note that pGina does not actually log the user on to the machine. It is the Windows OS itself that does that. This means that if a local account does not exist that matches the credentials, the logon will fail, even if the pGina plugins have registered success. Therefore, it is often the case that one of the plugins will be responsible for creating a local (often temporary) account."
Quindi sostanzialmente sta "imbrogliando": Non sta utilizzando chissà quale meccanismo per leggere delle credenziali windows (pensa al sambaSAM) memorizzate su un ldap e autenticare l'utente tramite ntlm  (per esempio) ma sta utilizzando ldap per una semplice autenticazione a bind e, se poi il tutto va bene, crea un account in locale e con le stesse credenziali che hanno funzionato su ldap lascia a windows l'autenticazione. E' un sistema davvero molto ingenioso.

.

NOTA 2: Quale che sia il metodo scelto è evidente che l'utente di cui stiamo cercando di verificare le credenziali deve potersi bindare a ldap perchè l'autentica abbia successo: Affinchè ciò avvenga i permessi MINORI possibili sul db principale (dove ci sono le credenziali utente) sono “to attrs=userPassword by anonymous auth”. Senza questi nessuna delle 2 modalità può funzionare, questo il log che lo mostra chiaramente
=> acl_mask: access to entry "uid=sarti,ou=People,dc=rete,dc=net", attr "userPassword" requested
=> acl_mask: to value by "", (=0)
<= check a_dn_pat: self
<= check a_dn_pat: anonymous
<= acl_mask: [2] applying auth(=xd) (stop)
<= acl_mask: [2] mask: auth(=xd)
=> slap_access_allowed: auth access granted by auth(=xd)
=> access_allowed: auth access granted by auth(=xd)

In sostanza bisogna quindi pensare al permesso auth come "L'entity (l'utente) che cerca di accedere ha permesso di autenticarsi sulla entry di cui sta chiedendo il permesso"

NOTA 3: Perchè usare la modalità di ricerca e doppio bind al posto  di provare a bindarsi direttamente? Voglio dire, non è un problema di credenziali perchè comunque l'utente poi si dovrà bindare ugualmente quindi ci deve essere un'altro motivo. Dopo mesi sono arrivato a capire quale.

Mettiamo di avere una entry del db ldap così fatta:

dn: cn=Simona sant,ou=People,dc=merli,dc=lab
uid: ssant
cn: Simona sant
[Tutto il resto non ci importa]

Il dn, ovvero il nome esatto della entry con cui bindarsi è "dn: cn=Simona sant,ou=People,dc=merli,dc=lab". Mettiamo che io però come nome utente non voglia utilizzare il cn (Simona sant) ma l'uid (ssant). Se utilizzo la modalità di bind diretto non c'è soluzione, DEVO bindarmi col dn e quindi utilizzare cn come nome utente. Se invece utilizzo la modalità con doppio bind, con l'utente di accesso farò una ricerca nel db di una entry in un certo albero (search context) il cui uid sia ssant. La troverò e si chiamerà "dn: cn=Simona sant,ou=People,dc=merli,dc=lab", e questa utilizzerò per fare il bind.

Questi i log di gina che mi hanno chiarito il tutto

2013-05-21 15:20:23,023 [1|DEBUG] LdapPlugin: Received username: ssant
2013-05-21 15:20:23,023 [1|DEBUG] LdapPlugin: Attempting authentication for ssant
2013-05-21 15:20:23,023 [1|DEBUG] LdapServer: Attempting bind as cn=accesso1,dc=access,dc=lab
2013-05-21 15:20:23,023 [1|DEBUG] LdapServer: Successful bind to 192.168.0.100 as cn=accesso1,dc=access,dc=lab
2013-05-21 15:20:23,023 [1|DEBUG] LdapServer: Searching for DN using filter uid=ssant
2013-05-21 15:20:23,023 [1|DEBUG] LdapServer: Searching context ou=People,dc=merli,dc=lab
2013-05-21 15:20:23,023 [1|DEBUG] LdapServer: Found DN: cn=Simona sant,ou=People,dc=merli,dc=lab
2013-05-21 15:20:23,033 [1|DEBUG] LdapServer: Attempting to bind with DN cn=Simona sant,ou=People,dc=merli,dc=lab
2013-05-21 15:20:23,033 [1|DEBUG] LdapServer: Attempting bind as cn=Simona sant,ou=People,dc=merli,dc=lab
2013-05-21 15:20:23,033 [1|DEBUG] LdapServer: Successful bind to 192.168.0.100 as cn=Simona sant,ou=People,dc=merli,dc=lab
2013-05-21 15:20:23,033 [1|DEBUG] LdapServer: LDAP DN cn=Simona sant,ou=People,dc=merli,dc=lab successfully bound to server, return success

Stessa effetto se avessi provato con squid_ldap_auth facendo così

Quindi così facendo posso utilizzare il valore contenuto in un campo qualunque (purchè mi identifichi univocamente un dn) come nome utente per il login in windows (o in qualunque altro programma che verifichi le credenziali).

NOTA 4: Questi i plugin selezionati per le varie prove

3_1_plugin_selection

Print Friendly, PDF & Email