[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Understanding LDAP structures [LONG]



On Sat, 2003-04-19 at 13:51, Alan Chandler wrote:

 ... snip ldap questions...

First of all, a quick ldap tutorial.

An entry in an ldap directory is basically a set of key/value pairs. In
theory, those keys could be anything if your ldap server is not
validating the entries. I.e., the following is a perfectly valid entry
in a non-validating server:

 cn: My Name
 iLikeFrogs: yes
 fuzzyRabbits: cute

In addition to the data in the entry, an entry also has to have a
name. Think of it as a filesystem: there's two important pieces of
information in the filesystem, the file's name and the file's
contents. In LDAP, the name is called the "distinguished name", or DN
(this is the name that distinguishes this entry from all others).

The DN of the above entry could be

  something=foo, somethingelse=bar, andsomethingelse=bat

Note that nothing in the DN actually matches the contents of the entry
above. This is also technically OK, although I believed that later
versions of openldap have started disallowing this. Also, you read the
path from right to left, so 'andsomethingelse=bat' is the top of the
hierarchy.

Also, just like your filesystem needs a root name (/), so does an LDAP
directory. Since there are thousands of LDAP directories in the world,
they can't all use /, so you have to pick something else. The current
practice is to use dc=mydomain, dc=com (assuming that your domain name
is mydomain.com; dc means domain component). This is a guideline, and is
important if your directory will ever merge with someone else's. But,
you don't have to use your domain name; you can choose anything. For
example, using 'o=My House' is a perfectly valid root. The technical
name for this root is the "Base Distinguished Name" or BaseDN.

Getting back to the contents of a directory entry, it's usually bad
practice to allow any king of data in there, because mistakes can be
made, and inconsistencies can be found. Thus, enter the schema. The
schema just describes what data can be stored in the directory. An LDAP
schema describes two things:

1. What kind of attributes are allowed. This is things like cn, ou, etc,
   plus what syntax they have, how the should be compared (i.e., case
   sensitive or not) and a bunch of other stuff.

2. What king of objects are allowed. This is things like   
   organizationalUnit, country, locality, etc.

A schema definition starts by defining the attributes, then defining the
object classes. An object class tells ldap what attributes are allowed
in that class. For example, the country object class requires the 'c'
(country) attribute, and also allows the 'searchGuide' and 'description'
attributes.

If your ldap server is enforcing a schema, all entries must belong to at
least one object class. This is what the entry's objectClass attribute
is for. Second, for each object class that the entry belongs to, it will
be required to have certain attributes (specified in the class
definition), it may be allowed to have certain other optional
attributes, and it is not allowed to have any attributes that the object
classes don't allow.

You can use any schema you want, but the standard ldap schema is
typically what you want to use. In Debian, this is defined in
slapd.conf, which in turn includes files in /etc/ldap/schema. The most
important one is core.schema, which codifies the Internet RFC's for LDAP
schemas. Other interesting ones are inetorgperson.schema and nis.schema.

Object classes allow inheritance, and in the standard schema, every
object class inherits from a class called 'top'. For you, the most
interesting object class is probably inetOrgPerson, which describes a
person in an organization that's connected to the Internet. 
inetOrgPerson allows a whole bunch of attributes, including mail,
givenName, homePhone, etc. In addition, it inherits from
'organizationalPerson', which allows a whole bunch of other attributes,
including street, ou (organizational unit, i.e., department), etc. In
turn, organizationalPerson inherits from 'person' which allows sn
(surname) and cn (common name), and which in turn inberits from 'top'.

Reading a schema file isn't that hard. Skip past all the the
attributetype stuff and find the objectclass definitions. Those list
what attributes an entry in that objectclass must have, and what
attributes it may have. For example, the "person" object class looks
like

  objectclass ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL
        MUST ( sn $ cn )
        MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )

This says that "person" inherits from top, and an entry with objectclass
of "person" must have sn and cn attributes, and may also have
userPassword, telephoneNumber, seeAlso and description attributes. Any
other attributes are not allowed. So, a person could look like:

  objectclass: person
  sn: Carrigan
  cn: Dave Carrigan
  userPassword: foobar

I can't have a mail attribute in this entry, because 'person'
objectclass doesn't allow 'mail' attribute. However, all I need to do is
add inetOrgPerson object class to the entry, and this lets me add a
whole bunch new attributes, including mail:

  objectclass: person
  objectclass: inetOrgPerson
  sn: Carrigan
  cn: Dave Carrigan
  userPassword: foobar
  mail: dave@rudedog.org
  initials: dhc

Technically, I can lose the objectclass: person, because inetorgperson's
inheritance tree can trace back to person. Some versions of openldap
require both, however, while I believe that later versions will actually
disallow both.

Once you've decided on the contents of the entry, you have to give it a
name. Just like a filesystem, you can go flat (all the files in the root
directory) or you can go deep. 

If your directory is small, then just go flat for simplicity's sake. So,
for the above entry, pick one attribute that's likely to be unique, and
use that for its name. Your Base DN is configured in slapd.conf (the
suffix attribute). All names must be rooted at your base DN. Assuming
that I configured my directory with a Base DN of "o=Chez Carrigan" ('o'
means "organization"), then the name of the above entry could be

  dn: cn=Dave Carrigan, o=Chez Carrigan

With the above entry, the following names would be just as valid:

  dn: sn=Carrigan, o=Chez Carrigan
  dn: cn=Dave Carrigan, o=Chez Carrigan
  dn: userPassword=foobar, o=Chez Carrigan
  dn: mail=dave@rudedog.org, o=Chez Carrigan
  dn: initials=dhc, o=Chez Carrigan

Some of these are better choices than others. For example, I don't
recommend using userPassword in the DN :-) 

Also, you don't have to use the same attribute with every every entry in
the directory. For example, I could have the following two entries:

  dn: cn=Dave Carrigan, o=Chez Carrigan
  dn: mail=fred@rudedog.org, o=Chez Carrigan

If you want to go deep, it's just a question of adding more
"subdirectories":

  dn: cn=Dave Carrigan, ou=Mail Stuff, o=Chez Carrigan

Here, ou is organizationalUnitName, which is commonly used as a
placeholder for lots of different things. You can use any attribute you
want, but ou is usually a good choice.

I seem to recall that later versions of openldap require that you create
the intermediate entries (i.e. you need to create a ou=Mail Stuff
entry):

  dn: ou=Mail Stuff, o=Chez Carrigan
  objectclass: organizationalUnit
  ou: Mail Stuff

For simplicity, don't go deep until you know what you're doing.

Going back to your original queries:

A. Admin access

Create an entry for the administrator:

  dn: cn=admin, o=Chez Carrigan
  objectClass: organizationalRole
  objectClass: simpleSecurityObject
  cn: admin
  userPassword: somepass

I use organizationalRole because I need a cn attribute, and I use
simpleSecurityObject because I need a userPassword attribute.

Second, in slapd.conf, set an acl on that entry so that it can change
stuff in the directory:

  access to * by dn="cn=admin,o=Chez Carrigan" write by * read

B. Samba general account

I haven't done anything with ldap and samba, so I don't know.

C. Unix accounts

You will need to set up your nsswitch.conf and pam.d stuff to use ldap,
plus you need to create ldap entries with object classes of posixAccount
and shadowAccount, defined in nis.schema, plus create posixGroup entries
to represent the unix groups. A lot depends on which software you're
planning to use. For example, cyrus imap uses saslauthd, which can be
configured with a ldap backend, and doesn't use pam at all.

D. Mail forwarding

Very dependent on your mail software. I use Postfix in conjunction with
the inetLocalMailRecipient schema to control delivery. Every mail
address resolves to either a standard RFC822 address, or it resolves to
name@local.transport. The relevant fragment of the ldap entry for
forwarding mail is

  dn: mailLocalAddress=unclejoe@rudedog.org, o=Chez Carrigan
  objectClass: inetlocalmailrecipient
  mailLocalAddress: unclejoe@rudedog.org
  mailRoutingAddress: unclej@some.otherisp.com

The relevant fragment for local delivery is

  dn: cn=Dave Carrigan
  objectClass: inetlocalmailrecipient
  mailLocalAddress: dave@rudedog.org
  mailRoutingAddress: dave@local.cyrus

The relevant fragment of /etc/postfix/transport is

  local.cyrus             lmtp:unix:/var/spool/cyrus/socket/lmtp

I define a bunch of other transports, such as local.file,
local.autoresponder, etc., and 

The relevant fragment of /etc/postfix/main.cf is

 virtual_maps=ldap:ldapvdomains
 ldapvdomains_server_host=pern
 ldapvdomains_search_base=o=Chez Carrigan
 ldapvdomains_query_filter=(&(|(objectclass=inetlocalmailrecipient)(objectclass=groupofuniquenames))(maillocaladdress=%s))
 ldapvdomains_domain=hash:/etc/postfix/ldap-domains
 ldapvdomains_result_attribute=mailroutingaddress,mgrprfc822mailmember
 ldapvdomains_special_result_attribute=member,uniquemember

And /etc/postfix/ldap-domains contains

 rudedog.org     rudedog.org

Before setting up your mail software to use ldap for mail routing, you
will definitely need to get a solid grasp on ldap and your mail
software, because there is no real standard in that area.

E. Web access.

With Apache, you will need something like auth_ldap at
http://www.rudedog.org/auth_ldap/ (shameless plug). The Debian package
is named libapache-auth-ldap. I usually do something like this in
httpd.conf:

  AuthLDAPUrl ldap:://ldap.rudedog.org/o=Chez Carrigan?cn??ou=Protected Area 1
  require valid-user

Then, the fragment of the ldap entry looks like:

  dn: cn=Dave Carrigan, o=Chez Carrigan
   ...
  ou: Protected Area 1

To sign on to Apache, I use my cn (Dave Carrigan) for my user name.

F. Complicated ssh stuff with keys.

Wait a while until you understand ldap better :-)

G. Address book. 

This is just a question of adding inetOrgPerson entries for anyone you
want in your address book. Give them extra ou entries in order to
classify them in other ways.

-----

As a postscript, in case you're interested, here's my LDAP entry at work
that covers a lot of the above stuff. It does include attributes from
locally-created schemas, in addition to some of the standard
schemas, so just ignore the pda* attributes and object classes. I've
also munged the mail addresses to thwart spam harvesters.

dn: uid=dave, ou=People, dc=pdaverticals, dc=com
objectClass: pdamailaccount
objectClass: pdaperson
objectClass: posixaccount
objectClass: shadowaccount
objectClass: inetlocalmailrecipient
sn: Carrigan
uid: dave
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/dave
loginShell: /bin/bash
telephoneNumber: +1 000 000 0000
title: Lead Technical Architect
ou: PDA Verticals Personnel
ou: Vertical Database Administrator
gecos: Dave Carrigan
userPassword: <elided>
pdaEmployeeType: staff
givenName: Dave
mailRoutingAddress: dave@local.cyrus
mailLocalAddress: hostmaster@pdaxvxexrxticals.com
mailLocalAddress: domain-administrator@pdaxvxexrxticals.com
mailLocalAddress: domain-technical@pdaxvxexrxticals.com
mailLocalAddress: postmaster@pdaxvxexrxticals.com
mailLocalAddress: postmaster@pxdxaxmd.com
mailLocalAddress: postmaster@pxdxaxre.com
mailLocalAddress: postmaster@pxdxaxjd.com
mailLocalAddress: postmaster@pxdxaxfn.com
mailLocalAddress: dave@pdaxvxexrxticals.com
mailLocalAddress: dave@pxdxaxmd.com
mailLocalAddress: dave@pxdxaxjd.com
mailLocalAddress: dave@pxdxaxre.com
mailLocalAddress: dave@pxdxaxfn.com
mailLocalAddress: ca@pdaxvxexrxticals.com
mailLocalAddress: www-data@pdaxvxexrxticals.com
mailLocalAddress: www-data@pxdxaxmd.com
mailLocalAddress: www-data@pxdxaxjd.com
mailLocalAddress: www-data@pxdxaxre.com
mailLocalAddress: www-data@pxdxaxfn.com
mailLocalAddress: dave@qxuxixzapp.com
mailLocalAddress: csmanual@pdaxvxexrxticals.com
mailLocalAddress: security@pdaxvxexrxticals.com
mailLocalAddress: domain-billing@pdaxvxexrxticals.com
mailLocalAddress: domain-billing@pxdxaxmd.com
mailLocalAddress: cricket@pdaxvxexrxticals.com
mailLocalAddress: postgres@pdaxvxexrxticals.com
mailLocalAddress: csbounces@pdaxvxexrxticals.com
pdalegalName: David
mail: dave@pdaxvxexrxticals.com
cn: Dave Carrigan
cn: David Carrigan

dn: cn=dave, ou=Groups, dc=pdaverticals, dc=com
objectClass: posixgroup
cn: dave
gidNumber: 1000

-- 
Dave Carrigan
Seattle, WA, USA
dave@rudedog.org | http://www.rudedog.org/ | ICQ:161669680
UNIX-Apache-Perl-Linux-Firewalls-LDAP-C-C++-DNS-PalmOS-PostgreSQL-MySQL



Reply to: