The University directory system Bob Dowling 26 th October 2005
Outline 1.Why give this seminar? 2.A bit about LDAP 3.Guided tour of the LDAP database 4.Configuring clients 5.LDAP queries and filters 6.Scripted access to the directory
Underlying LDAP database ● Lightweight Directory Access Protocol ● Based on ISODE X.500 ● Protocol lightweight compared to X.500 ● Not a good database ● Fundamental misconception in design: “Organisations can be represented as tree structures.”
Classic LDAP tree
Nodes in the tree ● Distinguished name (“DN”) – cn=Joe Blow,ou=Engineering, o=ACME Corporation ● Node's attributes: – cn – sn – ou – etc.
Not applicable to the University ● Not a tree! – UCS reports to Council and General Board ● People's names not unique – even within a department or college – “add an initial” – existing undergraduates vs. new professors – CRS ID !
The lookup tree
The lookup tree structure ● Flattish – parentInstID – contact rows ● User and institution keys – from Jackdaw – CRS ids – institution keys – drags history with it
LDAP object classes ● Nodes in an LDAP tree have object classes – define mandatory attributes – define permissible attributes ● Standard object classes – inetOrgPerson – organizationalUnit ● Expected by the clients ● Appears as an attribute
Cambridge object classes ● extend inetOrgPerson – camAcUkPerson ● extend organizationalUnit – camAcUkOrganizationalUnit ● all new – contactRow – camAcUkGroup ● Details not important – Keep this for reference
camAcUkPerson ● sn ● cn ● displayName ● uid ● soundex ● instID ● ou ● telephoneNumber ● labeledURI ● jpegPhoto ● mail ● mailAlternative ● suppression ● suppressAttribute ● cancelled
camAcUkorganizationalunit ● ou ● stem ● instID ● parentInstID ● postalAddress ● telephoneNumber ● labelledURI ● jpegPhoto ● mail ● mgrGroupID
contactRow ● rowTitle ● cn ● collationOrder ● rowStyle ● uid ● telephoneNumber ● labeledURI ● mail
camAcUkGroup ● groupID ● groupTitle ● mgrGroupID ● uid ● visibility ● mail ● description
Q & A Questions about the tree or any attributes?
LDAP clients ● Getting data out of lookup ● GUI ● Hermes webmail ● Command line ● Scripting languages
Configuring LDAP clients (1) ● Server – ldap.lookup.cam.ac.uk ● Port – 389 – The default ● Base DN – o=University of Cambridge, dc=cam,dc=ac,dc=uk – white space is significant!
Configuring LDAP clients (2) ● Anonymous bind ● Not SSL ● Any host in *.cam.ac.uk – Reverse DNS checks done – Unregistered hosts can't use it
Configuring GUIs ● “It's intuitive and you're in control.” – All different ● Demonstrations: – thunderbird – webmail ●
Thunderbird: configuring ● Address book ● File -> New -> LDAP directory ● General tab – “Find” button doesn't work? ● Do not try to download copy for offline use ● Advanced defaults don't need changing
Thunderbird
Thunderbird: addressbook
Thunderbird: LDAP directory
Thunderbird: lookup settings
Thunderbird: using ● Contacts ● Address book: lookup ● Search for: surname ● Select ● Add to To:
Thunderbird: compose window
Thunderbird: contacts
Thunderbird: surname search
Thunderbird: “Add to To:”
Hermes webmail: using ● Already configured! ● Compose window ● Address book ● Surname search ● Mark To:/cc:/bcc: ● Add marked to draft ● Compose window
Hermes webmail: compose
Hermes webmail: address book
Hermes webmail: search results
Hermes webmail: select target
Hermes webmail: compose
Q & A Questions about clients?
Command line tools ● Gentle introduction to LDAP filters ● Why? ● Because you're worth it! ● Needed for “advanced” searches ● But feel free to run away!
Unix LDAP tools ● /etc/openldap/ldap.conf – Common configuration file – Used by almost all Unix LDAP clients – Just two lines long ● Warning: /etc/ldap.conf exists but is different BASEo=University of Cambridge,dc=cam,dc=ac,dc=uk URIldap://ldap.lookup.cam.ac.uk/
ldapsearch -xSimple authentication -tStore binary data in files -LCuts down on noise in the output ● All you typically need if ldap.conf set ● RTFM for more ● Anonymous access ● Hosts in *.cam.ac.uk
ldapsearch example ldapsearch -x '(&(objectClass=inetOrgPerson) (uid=rjd4))' uid cn sn mail instID ou ● ldapsearch- The command ● -x- Options ● 'filter'- What we are looking for ● attributes- Once we've found it
Demonstration: ldapsearch ● Output in LDIF ● “LDAP Data Interchange Format” ● -L option: cuts down on the noise – -L – -LL – -LLL
LDAP filters ● Used for the command lines ● Used in “advanced use” in GUIs ● Syntax isn't too terrible.
Simple filters ● (attribute=value) – nodes having that attribute with that value – e.g. “(uid=rjd4)” ● (objectClass=inetOrgPerson) – typical use to identify “people nodes” ● Don't forget the brackets!
Looking for Ian Lewis (1) ● ldapsearch -x '(sn=Lewis)' uid displayName ● Every object with surname “Lewis” ● 80 hits
Looking for Ian Lewis (2) ● ldapsearch -x '(instID=CS)' uid displayName ● Every object with instID “CS” ● 130 hits ● And they're not all people!
Looking for Ian Lewis (3) ● ldapsearch -x '(&(sn=Lewis)(instID=CS))' uid displayName ● Every object with – surname “Lewis” – and – instID “CS” ● One hit! ● (And only people have surnames.)
Compound filters ● (& filter 1 filter 2 filter 3 ) – All the subfilters must match ● (| filter 1 filter 2 filter 3 filter 4 ) – Any one or more of them must match ● (! filter) – The subfilter must not match
Demonstration: Who is rjd4? ldapsearch -x '(&(objectClass=inetOrgPerson) (uid=rjd4))' uid cn ou ● Asking for uid, cn, ou ● from all objects that – are person objects – and – have CRS ID “rjd4”
Demonstration: Other Dowlings? ldapsearch -x '(& (sn=Dowling) (!(uid=rjd4)))' uid cn ou ● Asking for uid, cn, ou ● from all objects that – have surname “Dowling” – and – do not have CRS ID “rjd4”
Demonstration: ldapsearch ldapsearch -x -t '(& (objectClass=inetOrgPerson) (uid=rjd4) )' uid cn jpegPhoto ● jpegPhoto:< file:///tmp/ldapsearch-jpegPhoto-L1DMRW ● Binary data placed in a file
More than equality tests ● (sn=Dowling) ● (!(sn=Dowling)) ● (sn=Dowl*) ● (sn=*ling) ● (sn=*owlin*) ● (sn~=Dowling) ● (sn=*)
Q&A Questions about filters? (or ldapsearch?)
Scripting interfaces ● Languages – Shell – Perl – Python ● Example – LDAP -> CSV
Shell scripting ● shell plus – ldapsearch – grep – awk – sed ● Probably better off with – perl – python
Perl scripting - software ● Net::LDAP module – (requires Convert::ASN1) – CPAN ● perl-ldap package – (requires perl-Convert-ASN1)
Net::LDAP - Connection (perl) use Net::LDAP; $ldap_db = Net::LDAP->new('ldap.lookup.cam.ac.uk'); $message = $ldap_db->bind; $message->code && die $message->code;...do stuff... $message = $ldap_db->unbind; $message->code && die $message->code;
Net::LDAP - Doing stuff (perl) $message = $ldap_db->search( base => 'o=University of Cambridge,dc=cam,dc=ac,dc=uk', filter => '(&(objectClass=organizationalUnit)(instID=CS))' ); $message->code && die $message->code; foreach $entry ($message->all_entries) { print $entry->get_value('uid'), "\t"; print join("\t", $entry->get_value('telephoneNumber')), "\n"; }
Python scripting - software ● ldap module – Standard LDAP module ● python-ldap package
ldap - Connection (python) import ldap ldap_db = ldap.open('ldap.lookup.cam.ac.uk') ldap_db.simple_bind_s()...do stuff... ldap_db.unbind()
ldap - Doing stuff (python) results = ldap_db.search_s( base_dn, ldap.SCOPE_SUBTREE, '(&(objectClass=organizationalUnit)(instID=CS))', [] ) for (dn, attrs) in results: print '%s\t%s\n' % ( attrs['uid'][0], string.join(attrs['telephoneNumber'], '\t') )
Scripting issues ● Don't forget LDAP is anonymous ● You don't see suppressed data ● Better programmatic access required ● Example LDAP->CSV script
Scripting issues ● Don't forget LDAP is anonymous ● You don't see suppressed data ● Better programmatic access required ● Example LDAP->CSV script
Q & A Questions about scripting?
All the attributes ● Boring ● Keep for reference ● Person ● Institution ● Contact row ● Group
Person objects uid=rjd4, ou=people, o=University of Cambridge. dc=cam, dc=ac, dc=uk
Person: names (1) ● cn – “common name” – e.g. “R.J. Dowling” – registered name in Jackdaw ● sn – “family name” or “surname” – e.g. “Dowling” ● Deriving cn and sn from Jackdaw was “fun” – Jackdaw registered name was a “comment”
Person: names (2) ● displayName – what the user wants displayed – defaults to cn ● Both suppressible & editable
Person: CRS ID ● uid – “user id” ● Why is it mandatory? – not mandatory in inetOrgPerson – used in DN – so required ● Not editable ● Not suppressible
Person: institution (1) ● ou – “organizational unit name” – e.g. “University Computing Service” ● Displayed by clients to identify users ● Not suppressible ● Not editable (by the user) – Institutions add/remove users – Users don't add/remove institutions
Person: institution (2) ● instID – e.g. “CS” – Cambridge extension – Same key as is used for institutional nodes ● Must match the ou – Our problem ● Not suppressible
Person: (1) ● mail – standard, multi-valued attribute – MUAs can't cope with multiple values – we restrict it to being single valued – e.g. ● Need to put other addresses somewhere ● Need to identify this one over the alternatives
Person: (2) ● mailAlternative – Cambridge extension – multi-valued – put other addresses here ● We initialised mail addresses – tracking the ex-directory flag ● Web combines mail and mailAlternative ● User suppressible and editable – mail and mailAlternative tied
Person: web pages ● labeledURI – “ work page” ● Presented on the web as – text “work page” – link to ● Multi-valued ● User suppressible and editable ● Edited as URL + “comment”
Person: phone numbers ● telephoneNumber ● Multi-valued ● But how to label the choices? ● We cheat! – “34710 (Office)” – “34600 (Reception)” ● Edited as number + “comment”
Person: address ● postalAddress ● Uses dollars for line breaks ● No terminal line break ● e.g. “New Museum Site $ Pembroke Street $ CB2 3QH” ● We take care of the mapping
Person: photograph ● jpegPhoto ● Warning: binary data ● Validation: – 300×300 pixels – must be JPEG ● No validation: – JPEG trojans – right person – decent
Person: suppression ● suppressAttribute – the name of suppressed attributes as values ● suppressed – set or unset – records the default suppression status
Person: object class ● objectClass ● Two values: – inetOrgPerson – camAcUkPerson ● Mandatory in all objects
Institution objects instID=CS, ou=insts, o=University of Cambridge, dc=cam, dc=ac, dc=uk
Institution: name (1) ● ou – Organizational unit name – e.g. “University Computing Service” ● stem – e.g “univers”, “comput” – “computer” -> “comput” – “computing” -> “comput” – Used for searching
Institution: name (2) ● instID – Cambridge extension – Used in the DN – e.g. “CS” – Jackdaw node name
Institution: other attributes ● jpegPhoto ● postalAddress ● mail ● labeledURI
Contact rows cn=546, instID=CS, ou=insts, o=University of Cambridge, dc=cam, dc=ac, dc=uk
What are they for? ● Institutional contacts ● Fashioned after bits of the phone book ● Avoiding clutter on the main page ● Primarily visual rather than semantic – Web page – Phone lists
Contact row: unseen attributes ● cn – arbitrary number (unique in inst'l set) – just to give them names ● collationOrder – non-negative integer – order down screen – lowest first ● You don't need to see these
Contact row: Title ● rowTitle ● Mandatory ● Names the row – “Reception” – “Help Desk”
Contact row: contact details ● uid ● telephoneNumber ● mail ● labeledURI ● e.g. rowTitle=Director – uid=ijl20 – telephoneNumber=34702 –
Groups groupID=123456, ou=groups, o=University of Cambridge, dc=cam, dc=ac, dc=uk
Group attributes ● groupID ● mgrGroupID ● uid ● visibility – members – managers ● mail