=head1 NAME

OpenInteract2::Manual::LDAP - OpenInteract and LDAP

=head1 SYNOPSIS

Discussion of how you can use LDAP with OpenInteract.

=head1 DESCRIPTION

With OpenInteract 1.2+ and SPOPS 0.50+, you can now use LDAP not only
as a datastore for your objects, but also for authenticating users and
determining group membership. This document explains how.

If you can, read this document and follow its instructions before you
install and use OpenInteract. Otherwise actions like schema changes
can become more difficult.

=head2 The Pieces

=over 4

=item *

L<SPOPS::LDAP|SPOPS::LDAP> provides the serialization logic and
behavior

=item *

L<OpenInteract2::LDAP|OpenInteract2::LDAP> provides centralized
connection management

=item *

L<OpenInteract2::SPOPS::LDAP|OpenInteract2::SPOPS::LDAP> should be the
parent of any OI LDAP data object class as it provides common
behaviors. (This is done autmatically in OI2.)

=back

Additionally, two packages (base_group and base_user) offer options
for storing users and groups in LDAP and doing authentication from
there. See below for more.

=head2 Overall Configuration

First, install L<SPOPS|SPOPS> version 0.50 or higher and run its tests
to ensure that the LDAP portion (L<SPOPS::LDAP|SPOPS::LDAP>) is
functioning properly with your LDAP server.

Next, install OpenInteract 1.2 or higher. This includes functionality
to manage multiple datasources and connect to LDAP directories.

Next, make the following modifications to the server configuration
file:

=over 4

=item *

Add relevant connection information to the C<ldap_info> key. This
describes one or more LDAP datasources you will use with your
system. The usual suspects -- host, port, base DN -- are there, and
you can provide a standard bind DN and password as well. (Examples
below.)

=item *

Set the key C<datasource.default_connection_ldap> to the connection to
be used when an LDAP object doesn't specify a datasource.

=back

You can test your connection information from C<oi2_manage>:

 $ oi2_manage test_ldap --website_dir=/path/to/mysite


This will go through each of the defined datasources and try to
connect and bind given the information in the server configuration
file.

=head2 User/Group Storage and Authentication

Storing users and groups for use in OpenInteract authentication makes
things a little trickier. This is supported but still in its infancy,
so you might scare up a few gotchas here and there.

You should only need to do the following:

=over 4

=item *

Modify the SPOPS configuration files for both users
(C<base_user-x.xx/conf/spops_user.ini>) and groups
(C<base_group-x.xx/conf/spops_group.ini>) or use and tweak the ones
supplied under the same path but named C<ldap_spops_user.ini> and
C<ldap_spops_group.ini>.

=item *

Change the key C<login.crypt_password> to '0' (LDAP takes care of this
for you)

=item *

Modify the server configuration file to set the values for both the
C<id.user_type> and C<id.group_type> keys to 'char'. Do this before
installing OpenInteract since these keys inform the datatypes of other
tables, such as C<sys_error> which stores errors.

=item *

Modify the server configuration file to set the values for the system
users and groups. You can map these to existing users or create new
ones. The keys you'll need to modify are:

 default_objects.superuser
 default_objects.supergroup
 default_objects.public_group
 default_objects.site_admin_group<

See the discussion about 'Object Security' below for more information
about this.

=item *

Note that the 'sasl' key in the C<ldap_info.$datasource> entry has not
yet been tested, primarily because we need to setup a development
server that has SASL/CRAM-MD5 support properly compiled in..

=back

If you're having issues authenticating, try the following simple
script, setting the variables to appropriate values:

   1: #!/usr/bin/perl
   2: 
   3: use strict;
   4: use Net::LDAP;
   5: 
   6: my $host          = 'localhost';
   7: my $port          = 389;
   8: my $bind_dn       = 'cn=Manager,dc=MyCompany,dc=com';
   9: 
  10: my $bind_password = 'password';
  11: 
  12: my $ldap = Net::LDAP->new( $host, port => 389 );
  13: die "Cannot make LDAP connection\n" unless ( $ldap );
  14: 
  15: my $ldap_msg = $ldap->bind( dn => $bind_dn, password => $bind_password );
  16: if ( my $code = $ldap_msg->code ) {
  17:     die "Error during bind (Code: $code)\n", $ldap_msg->error, "\n";
  18: }
  19: print "Connect/bind ok.";

=head1 OBJECT SECURITY

=head2 Security for Existing Data

You might be using LDAP because you have a directory of
existing information. If you are doing this, then you need to
tell OpenInteract about the security for the objects already in
the system.

The C<base_security> package has a script for automating this
fairly common action. You'll need to run the script
C<create_object_security.pl> found in that package. Here's a sample:

   1: $ export OPENINTERACT2=/path/to/mysite
   2: $ cd pkg/base_security-2.xx/script
   3: $ perl create_object_security.pl \
   4:     --class=OpenInteract2::User \
   5:     --scope=world \
   6:     --level=read
   7: $ perl create_object_security.pl \
   8:     --class=OpenInteract2::User \
   9:     --scope=group \
  10:     --scope_id='site admin' \
  11:     --level=write
  12: $ perl create_object_security.pl \
  13:     --class=OpenInteract2::Group \
  14:     --scope=world \
  15:     --level=read
  16: $ perl create_object_security.pl \
  17:     --class=OpenInteract2::Group \
  18:     --scope=group \
  19:     --scope_id='site admin' \
  20:     --level=write

You will have to modify 'site admin' to the ID of your site admin
group -- whatever you set in the 'default_objects.site_admin_group'
key of your server configuration.

These commands will create entries in the security table so
that the 'world' security for all users and groups is 'read' and
that the site admin group has read/write privileges to all users
and groups.

Run the script with the parameter '--help' to get more
information about how to run it.

=head2 Object Creation Security

As opposed to OI 1.x you should not need to modify the entry in
'creation_security' for every secured SPOPS object. Instead of
hardcoding object IDs you can list a key pointing to the
'default_objects' area of the server configuration. For instance,
you'll often see a creation security policy declared like this:

   1: [object creation_security]
   2: user  =
   3: group = site_admin_group:WRITE
   4: world = READ

The 'site_admin_group' gets replaced at server startup by the server
configuration entry 'default_objects.site_admin_group'. So no matter
whether you use LDAP or DBI you just need to change that value and
restart.

=head1 EXAMPLES

=head2 Server Configuration

The following defines two connections: 'main_ldap' and
'auth_ldap'. The first describes a connection using an anonymous bind,
while the second specifies a bind DN and password. The second also
uses a different port than the first.

   1: [datasource_type LDAP]
   2: connection_manager = OpenInteract2::Datasource::LDAP
   3: spops_config       = OpenInteract2::SPOPS::LDAP
   4: 
   5: [datasource main_ldap]
   6: type          = LDAP
   7: spops         = SPOPS::LDAP
   8: host          = ldap.myco.com
   9: port          = 389
  10: bind_dn       =
  11: bind_password =
  12: base_dn       = dc=MyCo,dc=com
  13: timeout       = 120
  14: version       = 2
  15: sasl          = 0
  16: debug         = 0
  17: 
  18: [datasource auth_ldap]
  19: type          = LDAP
  20: spops         = SPOPS::LDAP
  21: host          = ldap.myco.com
  22: port          = 3890
  23: bind_dn       = cn=Manager,dc=MyCo,dc=com
  24: bind_password = crystalline
  25: base_dn       = dc=MyCo,dc=com
  26: timeout       = 120
  27: version       = 2
  28: sasl          = 0
  29: debug         = 0

=head2 Object Configuration

Here's a sample configuration, from the 'base_user' package. One
important thing to note: you B<do not> need to use a full DN for
C<ldap_base_dn> --
L<OpenInteract2::SPOPS::LDAP|OpenInteract2::SPOPS::LDAP> overrides the
method C<base_dn()> and prepends the value from C<ldap_base_dn> to the
value from C<base_dn> in your datasource.

So if we were to use the example below with the 'main' datasource, the
base DN of these objects would be:

   1:                ou=People --> From the object
   2:         + dc=MyCo,dc=com --> From the 'main' datasource
   3:         ================
   4: ou=People,dc=MyCo,dc=com --> Base DN used

If you're using multiple datasources, C<ldap_base_dn> needs to be a
hashref with the keys as datasources and the values as the partial
base DN for that datasource. See
L<SPOPS::LDAP::MultiDatasource|SPOPS::LDAP::MultiDatasource> for more
information.

   1: [user]
   2: class                   = OpenInteract2::User
   3: code_class              = OpenInteract2::User::LDAP
   4: isa                     = OpenInteract2::User
   5: is_secure               = yes
   6: field                   = cn
   7: field                   = sn
   8: field                   = givenname
   9: field                   = mail
  10: field                   = userpassword
  11: field                   = uid
  12: field                   = objectclass
  13: multivalue              = objectclass
  14: id_field                = cn
  15: ldap_base_dn            = ou=People
  16: ldap_object_class       = top
  17: ldap_object_class       = person
  18: ldap_object_class       = inetOrgPerson
  19: ldap_object_class       = organizationalPerson
  20: ldap_fetch_object_class = person
  21: name                    = full_name
  22: object_name             = User
  23: 
  24: [user field_map]
  25: last_name  = sn
  26: first_name = givenname
  27: password   = userpassword
  28: login_name = uid
  29: email      = mail
  30: user_id    = uid
  31: 
  32: [user links_to]
  33: OpenInteract::Group = uniquemember
  34: 
  35: [user creation_security]
  36: user  = 
  37: group = site_admin_group:WRITE
  38: world = READ
  39: 
  40: [user track]
  41: create = 0
  42: update = 1
  43: remove = 1
  44: 
  45: [user display]
  46: ACTION = user
  47: TASK   = display

=head1 MULTIPLE DATASOURCES

You can use multiple datasources in two different ways

=over 4

=item *

Use multiple datasources for the same class. This enables you to
search for an entry once and have the search get executed on multiple
directories. Read about how this works and how you set it up in
L<SPOPS::LDAP::MultiDatasource|SPOPS::LDAP::MultiDatasource>

=item *

Use a single datasource per a class but have multiple directories
available. For instance, you might run one LDAP directory for all
equipment in your organization and another for all employees and
groups.

For this, you simply need to configure all datasources in your server
configuration, then tell each SPOPS class which datasource it should
use. To tell a class, you need to use the C<datasource> key in its
configuration:

   1: [myequipment]
   2: class      = My::Equipment
   3: datasource = equipment
   4: ...

This class would use the connection information stored under the key
'equipment' in your server configuration.

There are other configuration details to be aware of -- please see
L<SPOPS::LDAP::MultiDatasource|SPOPS::LDAP::MultiDatasource> for more
infromation.

=back

=head1 COPYRIGHT

Copyright (c) 2001-2004 Chris Winters. All rights reserved.

=head1 AUTHORS

Chris Winters E<lt>Chris@cwinters.comE<gt>
