1#!/usr/bin/perl 2 3use strict; 4use warnings; 5 6use Test::More; 7use Test::MockObject::Extends; 8use Test::Exception; 9use Net::LDAP::Entry; 10use lib 't/lib'; 11 12use_ok("Catalyst::Authentication::Store::LDAP::Backend"); 13 14 15my $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}); 24is $back_without_use_roles->use_roles, 1, 'use_roles enabled be default'; 25 26my $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}); 36is $back_with_use_roles_disabled->use_roles, 0, 'use_roles disabled when set 37to 0'; 38 39my $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}); 49is $back_with_use_roles_enabled->use_roles, 1, 'use_roles enabled when set to 501'; 51 52my (@searches, @binds); 53for 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} 116is_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'); 124is_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 150done_testing; 151