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