Commit | Line | Data |
405489b5 |
1 | #!/usr/bin/perl |
2 | |
3 | use strict; |
4 | use warnings; |
5 | use Catalyst::Exception; |
6 | |
7 | use Test::More tests => 7; |
8 | use Test::MockObject::Extends; |
9 | use Net::LDAP::Entry; |
10 | use lib 't/lib'; |
11 | |
12 | SKIP: { |
13 | |
14 | eval "use Catalyst::Model::LDAP"; |
15 | if ($@) { |
16 | skip "Catalyst::Model::LDAP not installed", 7; |
17 | } |
18 | |
19 | use_ok("Catalyst::Authentication::Store::LDAP::Backend"); |
20 | |
21 | my (@searches, @binds); |
22 | for my $i (0..1) { |
23 | |
24 | my $back = Catalyst::Authentication::Store::LDAP::Backend->new({ |
25 | 'ldap_server' => 'ldap://127.0.0.1:555', |
26 | 'binddn' => 'anonymous', |
27 | 'bindpw' => 'dontcarehow', |
28 | 'start_tls' => 0, |
29 | 'user_basedn' => 'ou=foobar', |
30 | 'user_filter' => '(&(objectClass=inetOrgPerson)(uid=%s))', |
31 | 'user_scope' => 'one', |
32 | 'user_field' => 'uid', |
33 | 'use_roles' => 1, |
34 | 'role_basedn' => 'ou=roles', |
35 | 'role_filter' => '(&(objectClass=posixGroup)(memberUid=%s))', |
36 | 'role_scope' => 'one', |
37 | 'role_field' => 'userinrole', |
38 | 'role_value' => 'cn', |
39 | 'role_search_as_user' => $i, |
40 | }); |
41 | $back = Test::MockObject::Extends->new($back); |
42 | my $bind_msg = Test::MockObject->new; |
43 | $bind_msg->mock(is_error => sub {}); # Cause bind call to always succeed |
44 | my $ldap = Test::MockObject->new; |
45 | $ldap->mock('bind', sub { shift; push (@binds, [@_]); return $bind_msg}); |
46 | $ldap->mock('unbind' => sub {}); |
47 | $ldap->mock('disconnect' => sub {}); |
48 | my $search_res = Test::MockObject->new(); |
49 | $search_res->mock(is_error => sub {}); # Never an error |
50 | $search_res->mock(entries => sub { |
51 | return map |
52 | { my $id = $_; |
53 | Test::MockObject->new->mock( |
54 | get_value => sub { "quux$id" } |
55 | ) |
56 | } |
57 | qw/one two/ |
58 | }); |
59 | my @user_entries; |
60 | $search_res->mock(pop_entry => sub { return pop @user_entries }); |
61 | $ldap->mock('search', sub { shift; push(@searches, [@_]); return $search_res; }); |
62 | $back->mock('ldap_connect' => sub { $ldap }); |
63 | my $user_entry = Net::LDAP::Entry->new; |
64 | push(@user_entries, $user_entry); |
65 | $user_entry->dn('ou=foobar'); |
66 | $user_entry->add( |
67 | uid => 'somebody', |
68 | cn => 'test', |
69 | ); |
70 | my $user = $back->find_user( { username => 'somebody' } ); |
71 | isa_ok( $user, "Catalyst::Authentication::Store::LDAP::User" ); |
72 | $user->check_password('password'); |
73 | is_deeply( [sort $user->roles], |
74 | [sort qw/quuxone quuxtwo/], |
75 | "User has the expected set of roles" ); |
76 | } |
77 | is_deeply(\@searches, [ |
78 | ['base', 'ou=foobar', 'filter', '(&(objectClass=inetOrgPerson)(uid=somebody))', 'scope', 'one'], |
79 | ['base', 'ou=roles', 'filter', '(&(objectClass=posixGroup)(memberUid=test))', 'scope', 'one', 'attrs', [ 'userinrole' ]], |
80 | ['base', 'ou=foobar', 'filter', '(&(objectClass=inetOrgPerson)(uid=somebody))', 'scope', 'one'], |
81 | ['base', 'ou=roles', 'filter', '(&(objectClass=posixGroup)(memberUid=test))', 'scope', 'one', 'attrs', [ 'userinrole' ]], |
82 | ], 'User searches as expected'); |
83 | is_deeply(\@binds, [ |
84 | [ undef ], # First user search |
85 | [ |
86 | 'ou=foobar', |
87 | 'password', |
88 | 'password' |
89 | ], # Rebind to confirm user |
90 | [ |
91 | undef |
92 | ], # Rebind with initial credentials to find roles |
93 | # 2nd pass round main loop |
94 | [ undef ], # First user search |
95 | [ |
96 | 'ou=foobar', |
97 | 'password', |
98 | 'password' |
99 | ] # Rebind to confirm user _and_ lookup roles; |
100 | ], 'Binds as expected'); |
101 | } |