Friday, August 22, 2008

LDAP, catalyst, roles and groups

After a day or so of effort, I've got LDAP authorization working for groups/roles. I'm posting my config files here, since they worked for me and someone else may stumble across them and find them useful:

my ldif file is as follows:


dn: o=example.org
objectclass: top
objectclass: organization
o: example.org

dn: cn=admin,o=example.org
objectClass: simpleSecurityObject
objectclass: organizationalRole
cn: admin
description: LDAP Administrator
userPassword: 123

dn: ou=groups,o=example.org
objectClass: organizationalUnit
ou: groups
description: generic groups branch

dn: ou=people,o=example.org
ou: people
description: All people in organisation
objectclass: organizationalunit

dn: cn=researchers,ou=groups,o=example.org
objectClass: groupofnames
cn: researchers
member: uid=richard,ou=people,o=example.org

dn: uid=lionel,ou=people,o=example.org
objectClass: top
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: Lionel Porcheron
sn: Porcheron
userPassword: password
mail: l@a.b
title: Just a person
initials: LP
ou: people

dn: uid=richard,ou=people,o=example.org
objectClass: top
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: Richard Richard
sn: Richard
userPassword: password
mail: r@a.b
title: Researcher and person
initials: R
ou: people
ou: researchers

This LDIF file creates a group: researchers and a couple of people: richard and lionel. Richard is added to the group of researchers.


# Config for Store::LDAP
authentication:
default_realm: ldap
realms:
ldap:
credential:
class: Password
password_field: password
password_type: self_check
store:
class: LDAP
ldap_server: localhost
ldap_server_options:
timeout: 10
binddn: anonymous
bindpw: dontcare
start_tls: 0
start_tls_options:
verify: none
user_basedn: o=example.org
user_filter: (&(objectClass=organizationalPerson)(uid=%s))
user_scope: sub
user_field: uid
use_roles: 1
role_basedn: ou=groups,o=example.org
role_filter: (member=%s)
role_scope: one
role_field: cn
role_value: dn
role_search_options:
deref: always

This is my config file for catalyst.


sub list : Local {
my ($self, $c) = @_;
$c->assert_user_roles( qw/researchers/ ); # only researchers and view a list.
my $people : Stashed = $c->model('AddressDB::People');
$c->stash->{template} = 'person/list.tt2';
}


and this is a chunk of text from my controller.

Hope this is helpful - and saves you some time.

ldap thoughts

I have spent the last day or so trying to get my head around LDAP/Catalyst role authorization. For this project, authentication, authorization and auditing are important considerations.

LDAP seems like a suitable choice for the first two, there is someone else who is worrying about provenance and auditing - all I have to do is make sure the hooks are in place.

My struggle with LDAP and Catalyst was metaphorically like building of the channel tunnel: working from two foreign lands and meeting in the middle. The benefit of this process is that I have a much better understanding of LDAP, and ultimatly, the system works.

LDAP is powerful and it is not obvious that this is the right tool for this deployment.

PROS:
  • It is mature, stable and well documented.
  • It is scalable and can be integrated into existing infrastructure.
  • Many tools support it.
CONS:
  • It is complicated to administer.
LDAP will allow this project to relate to exsting web applications which have been deployed already. There is a considerable problem with 'account' creep. Each new application requires the same users to create a new account: username/password - and this is a pain. LDAP provides a foundation apon which this can be centralised and ultimatly - single-sign-on can be implemented.

The mature, stable and widly deployed nature of LDAP means that the administration can be centralised.

Friday, August 15, 2008

centralised configuration

I should be obvious, but today's lesson for me is to centralise configuration at all cost.

And Catalyst should make this easy; and it does.

Next week I should have some machines in the data centre to start building the system on.

Thursday, August 14, 2008

LDAP + catalyst.

LDAP in Catalyst is as easy as it should be... however, just because I'm using Catalyst, dosen't mean I'm doing it right.

On average thought, I think Catalyst will keep things modular so that someone will be able to pick up the work once I've left.

This brings me onto the point of this work: prepare for departure.

Nothing much else to report.

Wednesday, August 13, 2008

LDAP, there must be an upside

LDAP is a fairly natural choice for a organisation who will be distributed over a number of sites and have users with differing roles.

So I thought I'd have a play with it to get a feel for how it would work for us.

That play took a while (two days) but I'm beginning to get a feel for it. While I normally like the command line for alot of sys-admin stuff, I really wanted a graphical browser to surf around entries and make changes.

It took half a day to track down and configure jxplorer, but this did what I wanted and my search ended there. Other candidates which I tried out included:
  • directory_administrator old school X11 interface, does not currently work with OpenLDAP 2.2 or newer - which was a problem for me.
  • lat which was a prone to crashing at my hand: I think due to my incompetence.
  • luma which I couldn't get configured - probably for the same reason I had problems with lat.
after all this tinkering with LDAP, i'm starting to see the benifits though: using tools which support it. The first of these will likely be an ftp server.

The upside: One directory of users with roles, all the services use this directory. Centralised and manageable.

Thursday, August 7, 2008

enhancement to the code

Well, I wondered if this should be part of the catalyst book errerta, but in the end I decided that the code in the book worked, so it wasn't in error.

I have been working through the book using Pg instead of SQLite. The big difference with Pg is that a user/pass are needed. I've navigated a few hurdles on the way, and this afternoon I found another one.

When including a script within your catalyst app, it is The Book has an excellent example which properly integrates your script with the existing config files.

If you construct a DSN in the following way, you can also use the user/pass conbination from your config file!

my @dsn = @{$config->{'Model::AddressDB'}->{connect_info}};

my $HOME = dir($Bin, '..');
$dsn[0] =~ s/__HOME__/$HOME/;

my $schema = AddressBook::Schema::AddressDB->connect(@dsn)
or die "Failed to connect to database at $dsn[0]";

config files

I'm using a config file as I work through the tutorial. This is an obvious thing to do and I completely agree with it. However, when I introduce this structure, I don't really want it to 'over-ride' existing values - I want to delete all the values which are now to be stored only in the config file.

I had to play around a bit. My model previously contained database connection information. When I introduce the config file, the values were taken from the file. However, when I deleted all of the relevant section from the Model, it broke the app. I needed to leave in a minimal stub:

__PACKAGE__->config(
schema_class => 'AddressBook::Schema::AddressDB');

Friday, August 1, 2008

day two, hurdle navigated

Well this is my second day working through the JROCK Catalyst book.

It has been a little frustrating - but this has reinforced some of the paradigms behind MVC and Catalyst so it can be thought of as useful.

Todays TIP: find_or_new does not return and empty model if it fails. The new it returns has the primary key which it failed to find. This could be 'undef' or 'null', and this object is not suitable for a subsequent: update_or_insert. Instead, do a find, if that fails, create a new object.