Commit | Line | Data |
405489b5 |
1 | #!/usr/bin/perl |
2 | |
3 | use strict; |
4 | use warnings; |
5 | use Catalyst::Exception; |
6 | |
e385da71 |
7 | use Test::More; |
405489b5 |
8 | use Test::MockObject::Extends; |
d94851da |
9 | use Test::Exception; |
405489b5 |
10 | use Net::LDAP::Entry; |
11 | use lib 't/lib'; |
12 | |
e385da71 |
13 | eval "use Catalyst::Model::LDAP"; |
14 | plan skip_all => "Catalyst::Model::LDAP not installed" if $@; |
405489b5 |
15 | |
e385da71 |
16 | use_ok("Catalyst::Authentication::Store::LDAP::Backend"); |
405489b5 |
17 | |
06d130c2 |
18 | |
19 | my $back_without_use_roles = Catalyst::Authentication::Store::LDAP::Backend->new({ |
20 | ldap_server => 'ldap://127.0.0.1:555', |
21 | binddn => 'anonymous', |
22 | bindpw => 'dontcarehow', |
23 | user_basedn => 'ou=foobar', |
24 | user_filter => '(&(objectClass=inetOrgPerson)(uid=%s))', |
25 | user_scope => 'one', |
26 | user_field => 'uid', |
27 | }); |
28 | is $back_without_use_roles->use_roles, 1, 'use_roles enabled be default'; |
29 | |
30 | my $back_with_use_roles_disabled = Catalyst::Authentication::Store::LDAP::Backend->new({ |
31 | ldap_server => 'ldap://127.0.0.1:555', |
32 | binddn => 'anonymous', |
33 | bindpw => 'dontcarehow', |
34 | user_basedn => 'ou=foobar', |
35 | user_filter => '(&(objectClass=inetOrgPerson)(uid=%s))', |
36 | user_scope => 'one', |
37 | user_field => 'uid', |
38 | use_roles => 0, |
39 | }); |
40 | is $back_with_use_roles_disabled->use_roles, 0, 'use_roles disabled when set |
41 | to 0'; |
42 | |
43 | my $back_with_use_roles_enabled = Catalyst::Authentication::Store::LDAP::Backend->new({ |
44 | ldap_server => 'ldap://127.0.0.1:555', |
45 | binddn => 'anonymous', |
46 | bindpw => 'dontcarehow', |
47 | user_basedn => 'ou=foobar', |
48 | user_filter => '(&(objectClass=inetOrgPerson)(uid=%s))', |
49 | user_scope => 'one', |
50 | user_field => 'uid', |
51 | use_roles => 1, |
52 | }); |
53 | is $back_with_use_roles_enabled->use_roles, 1, 'use_roles enabled when set to |
54 | 1'; |
55 | |
e385da71 |
56 | my (@searches, @binds); |
57 | for my $i (0..1) { |
405489b5 |
58 | |
e385da71 |
59 | my $back = Catalyst::Authentication::Store::LDAP::Backend->new({ |
60 | 'ldap_server' => 'ldap://127.0.0.1:555', |
61 | 'binddn' => 'anonymous', |
62 | 'bindpw' => 'dontcarehow', |
63 | 'start_tls' => 0, |
64 | 'user_basedn' => 'ou=foobar', |
65 | 'user_filter' => '(&(objectClass=inetOrgPerson)(uid=%s))', |
66 | 'user_scope' => 'one', |
67 | 'user_field' => 'uid', |
68 | 'use_roles' => 1, |
69 | 'role_basedn' => 'ou=roles', |
70 | 'role_filter' => '(&(objectClass=posixGroup)(memberUid=%s))', |
71 | 'role_scope' => 'one', |
72 | 'role_field' => 'userinrole', |
73 | 'role_value' => 'cn', |
74 | 'role_search_as_user' => $i, |
75 | }); |
76 | $back = Test::MockObject::Extends->new($back); |
77 | my $bind_msg = Test::MockObject->new; |
78 | $bind_msg->mock(is_error => sub {}); # Cause bind call to always succeed |
79 | my $ldap = Test::MockObject->new; |
80 | $ldap->mock('bind', sub { shift; push (@binds, [@_]); return $bind_msg}); |
81 | $ldap->mock('unbind' => sub {}); |
82 | $ldap->mock('disconnect' => sub {}); |
83 | my $search_res = Test::MockObject->new(); |
84 | my $search_is_error = 0; |
85 | $search_res->mock(is_error => sub { $search_is_error }); |
86 | $search_res->mock(entries => sub { |
87 | return map |
88 | { my $id = $_; |
89 | Test::MockObject->new->mock( |
90 | get_value => sub { "quux$id" } |
91 | ) |
92 | } |
93 | qw/one two/ |
94 | }); |
95 | my @user_entries; |
96 | $search_res->mock(pop_entry => sub { return pop @user_entries }); |
97 | $ldap->mock('search', sub { shift; push(@searches, [@_]); return $search_res; }); |
98 | $back->mock('ldap_connect' => sub { $ldap }); |
99 | my $user_entry = Net::LDAP::Entry->new; |
100 | push(@user_entries, $user_entry); |
101 | $user_entry->dn('ou=foobar'); |
102 | $user_entry->add( |
103 | uid => 'somebody', |
104 | cn => 'test', |
105 | ); |
106 | my $user = $back->find_user( { username => 'somebody' } ); |
107 | isa_ok( $user, "Catalyst::Authentication::Store::LDAP::User" ); |
108 | $user->check_password('password'); |
109 | is_deeply( [sort $user->roles], |
110 | [sort qw/quuxone quuxtwo/], |
111 | "User has the expected set of roles" ); |
405489b5 |
112 | |
e385da71 |
113 | $search_is_error = 1; |
114 | lives_ok { |
115 | ok !$back->find_user( { username => 'doesnotexist' } ), |
116 | 'Nonexistent user returns undef'; |
117 | } 'No exception thrown for nonexistent user'; |
d94851da |
118 | |
405489b5 |
119 | } |
e385da71 |
120 | is_deeply(\@searches, [ |
121 | ['base', 'ou=foobar', 'filter', '(&(objectClass=inetOrgPerson)(uid=somebody))', 'scope', 'one'], |
122 | ['base', 'ou=roles', 'filter', '(&(objectClass=posixGroup)(memberUid=test))', 'scope', 'one', 'attrs', [ 'userinrole' ]], |
123 | ['base', 'ou=foobar', 'filter', '(&(objectClass=inetOrgPerson)(uid=doesnotexist))', 'scope', 'one'], |
124 | ['base', 'ou=foobar', 'filter', '(&(objectClass=inetOrgPerson)(uid=somebody))', 'scope', 'one'], |
125 | ['base', 'ou=roles', 'filter', '(&(objectClass=posixGroup)(memberUid=test))', 'scope', 'one', 'attrs', [ 'userinrole' ]], |
126 | ['base', 'ou=foobar', 'filter', '(&(objectClass=inetOrgPerson)(uid=doesnotexist))', 'scope', 'one'], |
127 | ], 'User searches as expected'); |
128 | is_deeply(\@binds, [ |
129 | [ undef ], # First user search |
130 | [ |
131 | 'ou=foobar', |
132 | 'password', |
133 | 'password' |
134 | ], # Rebind to confirm user |
135 | [ |
136 | undef |
137 | ], # Rebind with initial credentials to find roles |
138 | [ undef ], # Second user search |
139 | # 2nd pass round main loop |
140 | [ undef ], # First user search |
141 | [ |
142 | 'ou=foobar', |
143 | 'password', |
144 | 'password' |
5a9aba6e |
145 | ], # Rebind to confirm user |
146 | [ |
147 | 'ou=foobar', |
148 | 'password', |
149 | 'password' |
150 | ], # Rebind with user credentials to find roles |
e385da71 |
151 | [ undef ], # Second user search |
152 | ], 'Binds as expected'); |
153 | |
154 | done_testing; |