mail us  |  mail this page

contact us
training  | 
tech stuff  | 

Chapter 5. OpenLDAP Samples

5.4 Creating & Adding Objects

Contents

5.1 Simple Directory

5.1.1 Designing the DIT
5.1.2 Select the STRUCTURAL objectClass
5.1.3 slapd.conf File
5.1.4 LDIF File
5.1.5 Loading the LDIF
5.1.6 Adding New Entries using LDIF
5.1.7 Modifying Entries using LDIF
5.1.8 Just Fooling Around

5.2 Securing the Directory

5.2.1 Security Policy
5.2.2 Adding Groups
5.2.3 ACL slapd.conf Access Definitions
5.2.4 Testing the ACL

5.3 Expanded Hierarchy

5.3.1 Requirement
5.3.2 Implementation
5.3.3 LDIF
5.3.4 ACL slapd.conf Access Definitions
5.3.5 Testing the ACL

5.4 Creating & Adding Objects

5.4.1 Requirement
5.4.2 Implementation
5.4.3 Attribute Definitions
5.4.4 objectClass & Schema Definition
5.4.5 ACL slapd.conf Access Definitions
5.4.6 LDIF
5.4.7 Testing the Changes

5.5 Single Sign On
5.6 Referral and Replication

5.4 Creating & Adding Objects

In this section we create a number of attributes, an objectclass and a schema to package them for the future.

Up Arrow

5.4.1 Requirement

As part of the corporate analysis to exploit still further the wildly successful adoption of LDAP our corporate masters have decided that we will add the following capabilities to our currently operational directory:

  1. a dohicky attribute. This attribute is a boolean value. It can only be seen and updated by the owner and any member of the hrpeople group.

  2. an ageAtBirth attribute (note the especially stupid pseudo-Hungarian a.k.a. CamelCase notation - this is the last time you will see it). This attribute is a numeric value. It can only be seen and updated by the owner and any member of the hrpeople group.

  3. a gobbledegook attribute. This attribute is a string value and is publicly visible to all authenticated users. It can be updated only by the owner and any member of the hrpeople group. It will allow searching using <= or >= search filters.

  4. As part of our move to single sign-on (SSO) we will add the standard posixAccount objectclass to each user. The record will be visible only to the itpeople group.

Up Arrow

5.4.2 Implementation

We have striven mightily to see if we can re-use any existing attributes (essentially, use an existing attribute with the right SYNTAX even though its original 'purpose' was designed for another usage) of the inetorgperson objectClass and failed miserably. We will have to roll-our-own objects. Here is what we decided, or in most cases had, to do:

  1. The dohicky attribute. Create our own using the existing boolean syntax OID.

  2. The ageAtBirth attribute. Create our own using the existing integer syntax OID.

  3. The gobbledegook attribute. Create our own using the existing PrintableString syntax OID. But to allow for the use of <= and >= search filters we need to use an ORDERING matchingRule (caseIgnoreOrderingMatch).

  4. We will create a new objectclass for these attributes which we will call ourObject (pretty creative name). Because we already have a STRUCTURAL object in each entry (inetorgperson) we will use an AUXILIARY objectclass.

    If we had required a STRUCTURAL object we would have had to make them all children of our current inetorgperson entries just like we did with our private addressbook enhancement. Alternatively, we could have made ourObject STRUCTURAL and used sup inetOrgPerson in the definition thus adding it to the end of the Person ->organizationalPerson ->inetOrgPerson objectClass hierarchy (see objectClass definition .

  5. We are creating both an objectclass and attributes which will require to be globally unique. These examples use a globally unique OID which you can safely use FOR THE PURPOSES OF TESTING THIS EXAMPLE. DO NOT BE TEMPTED TO REUSE EITHER THIS OR ANY OTHER OID. Obtaining your own enterprise number that allows you to define your own attributes and objectclasses is a trivial and zero cost process via IANA. It is a VERY BAD THING™ to re-use existing OIDs.

  6. Since our beloved and esteemed corporate masters are unlikely to stop here we have decided to package these thingies (attributes and objectclass) into a schema which we will call ourco.schema (original or what).

  7. The posixAccount objectclass is - thank goodness - an AUXILIARY class. Since some of the attributes are shared with other objectclasses we will re-interpret the draconic directive to limit access to posixAccount attributes to only itpeople to only the unique attributes of this objectclass - specifically homedirectory, gidnumber, uidnumber, loginshell and gecos.

Up Arrow

5.4.3 Attribute Definitions

We create the following attribute definitions:

dohicky - boolean

attributetype ( 1.3.6.1.4.1.6863.2.3.107 NAME 'dohicky'
  EQUALITY booleanMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )

The attribute's OID uses the suggested numbering convention. We use the standard boolean data type syntax OID. The matchingRules is only EQUALITY. For more information on defining attributes.

ageAtBirth - integer

attributetype ( 1.3.6.1.4.1.6863.2.3.108 NAME 'ageAtBirth'
  EQUALITY integerMatch
  ORDERING integerOrderingMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

The attribute's OID uses the suggested numbering convention. We use the standard integer data type syntax OID. The matchingRules are both EQUALITY and ORDERING. For more information on defining attributes.

gobbledegook - PrintableString

You will occasionally see references to gobbledigook and even gobbledygook - ignore them - this is the real spelling!

attributetype ( 1.3.6.1.4.1.6863.2.3.109 NAME 'gobbledegook'
  EQUALITY caseIgnoreMatch
  SUBSTR caseIgnoreSubstringsMatch
  ORDERING caseIgnoreOrderingMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{200} )

The attribute's OID uses the suggested numbering convention. We use the standard PrintableString data type syntax OID and we define a maximum length of 200 characters (in braces or curly brackets) for the attribute. The matchingRules are EQUALITY, SUBSTR and ORDERING. For more information on defining attributes.

Up Arrow

5.4.4 objectClass & Schema Definition

objectclass ( 1.3.6.1.4.1.6863.2.4.57 NAME 'ourObject'
  DESC 'A very useful object'
  SUP top AUXILIARY 
  MUST ( dohicky $ gobbledegook )
  MAY ageAtBirth )

The objectClass's OID uses the suggested numbering convention.

SUP top terminates the objectclass hierarchy using the convenience objectClass top.

AUXILIARY allows us to associate this objectClass with ANY STRUCTURAL objectClass.

MUST ( dohicky $ gobbledegook ) defines that the attributes dohicky and gobbledegook have to be present when the objectclass is added. Whereas MAY ageAtBirth indicates that this attribute is optional.

For more information on defining objectclases.

Finally we add all the above stuff into a file and save it as ourco.schema in the same directory as the distribution schemas. You can save these schemas anywhere its just easier if they are all in the same place.

Squirrels: The DESC clause of most objects and attributetypes is normally about as meaningful as ours in the above examples. There are many annoying things in this life but one of them is what we call the 'squirrel complex' which is defined as being a unnatural desire to hide things - like meaning and usage. Lord Byron, the poet, was reputedly asked once about the meaning of a line from one of his poems. He replied "When I wrote that, God and I knew what it meant - now only God does". Memory is finite. Why not add a few words of meaningful, descriptive text. Especially when significant limitations or specific usage is envisaged by the designers.

# EXAMPLE.COM SCHEMA FILE
# takes values:
# true = wears clean socks on monday
# false = does not wear clean socks on monday
attributetype ( 1.3.6.1.4.1.6863.2.3.107 NAME 'dohicky'
  EQUALITY booleanMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )

# if present must take the value = 0
attributetype ( 1.3.6.1.4.1.6863.2.3.108 NAME 'ageAtBirth'
  EQUALITY integerMatch
  ORDERING integerOrderingMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

# string used to describe the height of the person in either feet/inches or meters
# may be expressed as xfyi e.g. 5f7i (5 feet 7 inches) or x.ym e.g. 1.95m (1.95 meters)
# the values f, i, m above are case insensitive 
attributetype ( 1.3.6.1.4.1.6863.2.3.109 NAME 'gobbledegook'
  EQUALITY caseIgnoreMatch
  SUBSTR caseIgnoreSubstringsMatch
  ORDERING caseIgnoreOrderingMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{200} )

# objectclass used with people address book to define required information
# for State Law 5.7.3 - data is defined by law to be private - limited access allowed
objectclass ( 1.3.6.1.4.1.6863.2.4.57 NAME 'ourObject'
  DESC 'A very useful object'
  SUP top AUXILIARY 
  MUST ( dohicky $ gobbledegook )
  MAY ageAtBirth )

Up Arrow

5.4.5 Slapd.conf Changes

We need to modify the slapd.conf file first to fix ACL permissions but specifically OpenLDAP knows nothing about our new objectclass and will choke when it sees a dohicky attribute without the include /usr/local/etc/openldap/schema/ourco.schema which contains its definition. The modified slapd.conf file is here:

#
###### SAMPLE 4 - DIRECTORY with home-grown objectclass & attributes ############
#
# NOTES: inetorgperson picks up attributes and objectclasses
#        from all three schemas
#        devices objectclass is in core.schema
#        posixAccount is in nis.schema
#        add ourco.schema
#
# NB: RH Linux schemas in /etc/openldap
#
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
include /usr/local/etc/openldap/schema/nis.schema
include /usr/local/etc/openldap/schema/ourco.schema
# NO REFERRALS

# DON'T bother with ARGS file
# pidfle allows scripts for stopping slapd to work
pidfile /var/run/slapd.pid

# enable a lot of logging - we might need it
loglevel 	-1 

# NO dynamic backend modules

# NO TLS-enabled connections

#######################################################################
# bdb database definitions
# 
# replace example and com below with a suitable domain
# 
# If you don't have a domain you can leave it since example.com
# is reserved for experimentation or change them to My and inc
#######################################################################

database bdb
suffix "dc=example, dc=com"
# ACL1
# only owner and itgroup can see or update
access to attrs=userpassword
  by self       write
  by anonymous  auth
  by group.exact="cn=itpeople,ou=groups,dc=example,dc=com" write
  by *          none

# ACL1A
# only itgroup can see and update
access to attrs=homedirectory,uidnumber,gidnumber,loginshell,gecos
  by group.exact="cn=itpeople,ou=groups,dc=example,dc=com" write
  by *          none
	
# ACL2
# allow read of addressbook by owner and itpeople; no-one else see it
access to dn.regex="^ou=addressbook,cn=([^,]+),ou=people,dc=example,dc=com$"
    attrs=entry
  by dn.exact,expand="cn=$1,ou=people,dc=example,dc=com" read
  by group.exact="cn=itpeople,ou=groups,dc=example,dc=com" write
  by users none

# ACL3
# allows itgroup to create addressbook but not see entries
access to dn.regex="cn=[^,]+,ou=people,dc=example,dc=com$"
   attrs=children
  by group.exact="cn=itpeople,ou=groups,dc=example,dc=com" write
  by users none break

# ACL4
# allow user to create entries in own addressbook; no-one else can access it
# needs write access to the entries ENTRY attribute (ACL5)
# and the entries CHILDREN (ACL4)
access to dn.regex="ou=addressbook,cn=([^,]+),ou=people,dc=example,dc=com$"
   attrs=children
  by dn.regex,expand="cn=$1,ou=people,dc=example,dc=com" write
  by users none

# ACL5
# allow one to create entries in its own addressbook; no-one else can access it
# needs write access to the entries ENTRY attribute (ACL5)
# and the entries CHILDREN (ACL4)
access to dn.regex="ou=addressbook,cn=([^,]+),ou=people,dc=example,dc=com$"
   attrs=entry
  by dn.regex,expand="cn=$1,ou=people,dc=example,dc=com" write
  by users none

# ACL6
# allow access to all entries in own addressbook; no-one else can access it
access to dn.regex="ou=addressbook,cn=([^,]+),ou=people,dc=example,dc=com$"
   filter=(objectclass=inetorgperson)
  by dn.regex,expand="cn=$1,ou=people,dc=example,dc=com" write
  by users none

# LDAP 2.2+ replace ACL5 and ACL6 with
#access to dn.regex="ou=addressbook,cn=([^,]+),ou=people,dc=example,dc=com$"
#   attrs=entry,@inetorgperson
#  by dn.regex,expand="cn=$1,ou=people,dc=example,dc=com" write
#  by users none

# ACL7
# allows sales to create entries in customers
# authenticated user can only read
access to dn.one="ou=customers,dc=zytrax,dc=com"
   attr=children
  by group.exact="cn=salespeople,ou=groups,dc=example,dc=com" write
  by users read

# ACL8
access to attr=carlicense,homepostaladdress,homephone,dohicky,ageatbirth
  by self       write
  by group.exact="cn=hrpeople,ou=groups,dc=example,dc=com" write
  by *          none

# ACL8A - control access to equipment
access to dn.one="ou=equipment,dc=example,dc=com"
  by group.exact="cn=itpeople,ou=groups,dc=example,dc=com" write
  by users      read
	by *          none
# ACL9
access to *
  by self       write
  by group.exact="cn=hrpeople,ou=groups,dc=example,dc=com" write
  by users      read
  by *          none
# root or superuser
rootdn "cn=jimbob, dc=example, dc=com"
rootpw dirtysecret
# The database directory MUST exist prior to running slapd AND 
# change path as ncessary
directory	/var/db/openldap/example-com

# Indices to maintain for this directory
# unique id so equality match only
index	uid	eq
# allows general searching on commonname, givenname and email
index	cn,gn,mail eq,sub
# allows multiple variants on surname searching
index sn eq,sub
# sub above includes subintial,subany,subfinal
# optimise department searches
index ou eq
# if searches will include objectClass uncomment following
# index objectClass eq
# shows use of default index parameter
index default eq,sub
# indices missing - uses default eq,sub
index telephonenumber

# other database parameters
# read more in slapd.conf reference section
cachesize 10000
checkpoint 128 15

Get sample file as text (use save as in your browser).

Notes:

  1. We added includes for the schemas nis.schema (for posixAccount) and ourco.schema (for ourObject and the various attributes).

  2. We added an access directive (ACL1A) to limit access to the itgroup only of the attributes homedirectory, uidnumber and gidnumber as required by our policy. In OpenLdap 2.2+ we could have used the syntax attr=@posixaccount (all the attributes of the posixAccount objectclass) but in this position it would also have had the minor side effect of limiting access to cd! Not really what we want.

  3. We added dohickey and ageatbirth to the access directive (ACL8) to limit access to the hrgroup and the owner.

We now need to stop OpenLDAP and restart to pick up this new slapd.conf file. Use something like the following commands:

# stop and start OpenLDAP (slapd)
# on Linux/Redhat
/etc/rc.d/init.d/ldap restart

# on BSD
[bsd] /usr/local/etc/openldap/slapd.sh stop
# then
[bsd] /usr/local/etc/rc.d/slapd.sh start

# confirm slapd is running
ps ax | grep slapd

Up Arrow

5.4.6 LDIF

The LDIF below updates our entries by adding the posixAccount objectclass and its MUST attributes and the ourObject object class and its MUST attributes:

None of the LDAP browsers we used allowed us to add new AUXILIARY objects - LDIF is the only way to do this apparently.

version: 1

dn: cn=john smith,ou=people,dc=example,dc=com
changetype: modify
objectclass: inetorgperson
objectclass: posixaccount
uidnumber: 200
gidnumber: 203
homedirectory: /var/mail/example.com/jsmith
objectclass: ourObject
dohicky: false
gobbledegook: john
ageatbirth: 0

dn: cn=sheri smith,ou=people,dc=example,dc=com
changetype: modify
objectclass: inetorgperson
objectclass: posixaccount
uidnumber: 201
gidnumber: 203
homedirectory: /var/mail/example.com/ssmith
objectclass: ourObject
dohicky: true
gobbledegook: sheri

dn: cn=robert smith,ou=people,dc=example,dc=com
changetype: modify
objectclass: inetorgperson
objectclass: posixaccount
uidnumber: 202
gidnumber: 203
homedirectory: /var/mail/example.com/rsmith
objectclass: ourObject
dohicky: false
gobbledegook: robert
ageatbirth: 17

Notes:

  1. The changetype directive is not strictly necessary when ldapmodify is used since this is assumed to be the default.

  2. The objectclass: inetorgperson is necessary since it tells OpenLDAP which STRUCTURAL objectclass the AUXILIARY objectclasses will use.

  3. The MUST attributes for each objectclass need to be present. The MAY objects are entirely optional.

Assuming we save the above LDIF as modify.ldif in our /tmp directory we load the LDIF file using ldapmodify with a command like this (line below is split for HTML formatting reasons only and should be on a single line):

ldapmodify -H ldap://ldaphost.example.com -x -D "cn=jimbob,dc=example,dc=com" 
 -f /tmp/modify.ldif -w dirtysecret

The ldaphost.example.com should be replaced with whatever hostname your LDAP directory is located on. If the ldap host is the same system as the one from which the command is issued the -H and parameter can be omitted. The -x indicates we do not use SASL security and is required since OpenLDAP 2.x. The -D is the binding and is the rootdn - the superuser gets to do everything. The -w followed by the password is, to say the least, insecure and you could use -W which will prompt for the password.

Up Arrow

5.4.7 Test the Changes

We now need to test our new update. To test the ACL use your LDAP Browser and:

  1. Configure your LDAP browser to bind or authenticate using dn: cn=Robert Smith, ou=people, dc=example, dc=com with a userpassword of rJsmitH (case sensitive) and because this entry has hrpeople privileges it will see and be able to modify all entries including carlicense, homepostaladdress and homephone but not userpassword (except for his own entry) and can read the customers and equipment entries but cannot write to them. Robert Smith can also see and add to his own addressbook entries but can only guess if anyone else has an addressbook (cannot see addressbook for anyone else). He cannot see the attributes of the posixAccount objectclass homedirectory, guidnumber, gidnumber, loginshell and gecos of his own or any other entry.

  2. Configure your LDAP browser to bind or authenticate using dn: cn=Sheri Smith, ou=people, dc=example, dc=com with a userpassword of sSmitH (case sensitive) and because this entry has itpeople privileges it will see and be able to modify the userpassword,homedirectory, guidnumber, gidnumber, loginshell and gecos attribute of all entries but cannot see carlicense, homepostaladdress and homephone for any entry except her own. This entry can read the customers entries but cannot write to them but can read and write equipment entries . Sheri Smith can also see and add to her own addressbook entries and can see addressbook (but not the entries) for everyone. She can also delete addresbook for each entry (and if you have just tried it - can also add it back again!).

  3. Configure your LDAP browser to bind or authenticate using dn: cn=John Smith, ou=people, dc=example, dc=com with a userpassword of jSmitH (case sensitive) and because this entry has no privileges it cannot see carlicense, homepostaladdress, homephone and userpassword for any entry except his own (which he can also modify). This entry because it is a member of the salespeople group can read and write the customers entries but can only read equipment entries . John Smith can also see and add to his own addressbook entries but can only guess if anyone else has an addressbook (cannot see addressbook for anyone else). He cannot see the attributes of the posixAccount objectclass homedirectory, guidnumber, gidnumber, loginshell and gecos of his own or any other entry.

  4. Configure your LDAP browser for anonymous access and confirm that access is denied.

  5. Authenticate as our rootdn or superuser (defined in the slapd.conf as cn=jimbob,dc=example,dc=com, password dirtysecret) and confirm this overrides all our privileges and can see and modify everything.

  6. It may be useful at this time to export the current state of the directory to an LDIF using either your LDAP browser's export feature or slapcat.

Note:: In all of the above tests you should be able to see with your LDAP Browser the customers, equipment and groups branch and their entries. If you cannot then you may have set your Base DN (or Root DN depending on your browser) fields in the LDAP browser to ou=people,dc=example,dc=com, set this to dc=example,dc=com and you should now be able to see all the entries.

Up Arrow

Step 5 - Single Sign-On (SSO)

Go to Arrow



Problems, comments, suggestions, corrections (including broken links) or something to add? Please take the time from a busy life to 'mail us' (at top of screen), the webmaster (below) or info-support at zytrax. You will have a warm inner glow for the rest of the day.

Contents

tech info
guides home
intro
contents
1 objectives
big picture
2 concepts
3 ldap objects
quickstart
4 install ldap
5 samples
6 configuration
7 replica & refer
reference
8 ldif
9 protocol
10 ldap api
operations
11 howtos
12 trouble
13 performance
14 ldap tools
security
15 security
appendices
notes & info
ldap resources
rfc's & x.500
glossary
ldap objects
change log

Creative Commons License
This work is licensed under a Creative Commons License.

If you are happy it's OK - but your browser is giving a less than optimal experience on our site. You could, at no charge, upgrade to a W3C STANDARDS COMPLIANT browser such as Firefox

[an error occurred while processing this directive]

Site

CSS Technology SPF Record Conformant Domain
Copyright © 1994 - 2024 ZyTrax, Inc.
All rights reserved. Legal and Privacy
site by zytrax
hosted by javapipe.com
web-master at zytrax
Page modified: March 24 2023.