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