File Coverage

blib/lib/Dancer2/Plugin/Auth/Extensible/Provider/ActiveDirectory.pm
Criterion Covered Total %
statement 18 48 37.5
branch 0 14 0.0
condition 0 6 0.0
subroutine 6 11 54.5
pod 3 3 100.0
total 27 82 32.9


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::Auth::Extensible::Provider::ActiveDirectory;
2              
3 1     1   46050 use feature qw/state/;
  1         2  
  1         71  
4 1     1   4 use Carp qw/croak/;
  1         1  
  1         39  
5 1     1   435 use Dancer2::Core::Types qw/HashRef Str Int/;
  1         7656  
  1         84  
6 1     1   440 use Auth::ActiveDirectory;
  1         107697  
  1         28  
7              
8 1     1   470 use Moo;
  1         6600  
  1         4  
9             with "Dancer2::Plugin::Auth::Extensible::Role::Provider";
10 1     1   1471 use namespace::clean;
  1         7791  
  1         4  
11              
12             our $VERSION = '0.02';
13              
14             =head1 NAME
15              
16             Dancer2::Plugin::Auth::Extensible::Provider::ActiveDirectory - ActiveDirectory authentication provider for Dancer2::Plugin::Auth::Extensible
17              
18             =head1 DESCRIPTION
19              
20             This class is an ActiveDirectory authentication provider.
21              
22             See L<Dancer2::Plugin::Auth::Extensible> for details on how to use the
23             authentication framework.
24              
25             =head1 ATTRIBUTES
26              
27             =head2 host
28              
29             The ActiveDirectory host name or IP address passed to L<Auth::ActiveDirectory>.
30              
31             Required.
32              
33             =cut
34              
35             has host => (
36             is => 'ro',
37             isa => Str,
38             required => 1,
39             );
40              
41             =head2 port
42              
43             The ActiveDirectory port. Defaults to 389.
44              
45             =cut
46              
47             has port => (
48             is => 'ro',
49             isa => Int,
50             default => 389,
51             );
52              
53             =head2 timeout
54              
55             Connection timeout in seconds. Defaults to 60.
56              
57             =cut
58              
59             has timeout => (
60             is => 'ro',
61             isa => Int,
62             timeout => 60,
63             );
64              
65             =head2 domain
66              
67             The ActiveDirectory domain.
68              
69             Required.
70              
71             =cut
72              
73             has domain => (
74             is => 'ro',
75             isa => Str,
76             required => 1,
77             );
78              
79             =head2 principal
80              
81             The ActiveDirectory principal.
82              
83             Required.
84              
85             =cut
86              
87             has principal => (
88             is => 'ro',
89             isa => Str,
90             required => 1,
91             );
92              
93             =head1 METHODS
94              
95             =head2 authenticate_user $username, $password
96              
97             =cut
98              
99             sub authenticate_user {
100 0     0 1   my ( $self, $username, $password ) = @_;
101              
102 0 0 0       croak "username and password must be defined"
103             unless defined $username && defined $password;
104              
105 0 0         my $ad = $self->_active_directory or return;
106              
107 0           my $user = $ad->authenticate( $username, $password );
108              
109 0           $self->_user_cache($username, $user);
110              
111 0           return !!$user;
112             }
113              
114             =head2 get_user_details $username
115              
116             =cut
117              
118             sub get_user_details {
119 0     0 1   my ( $self, $username ) = @_;
120              
121 0 0         croak "username must be defined" unless defined $username;
122              
123 0           my $user = $self->_user_cache($username);
124 0 0         if (!$user) {
125 0           $self->plugin->app->log( debug => "User information not found: $username" );
126             }
127              
128             return {
129             username => $user->uid,
130             display_name => $user->display_name,
131             firstname => $user->firstname,
132             surname => $user->surname,
133             email => $user->mail,
134 0           roles => [ map { $_->name } @{ $user->groups } ],
  0            
  0            
135             };
136             }
137              
138             =head2 get_user_roles
139              
140             =cut
141              
142             sub get_user_roles {
143 0     0 1   my ( $self, $username ) = @_;
144              
145 0 0         croak "username must be defined"
146             unless defined $username;
147              
148 0           my $user = $self->_user_cache($username);
149 0 0         if (!$user) {
150 0           $self->plugin->app->log( debug => "User information not found: $username" );
151 0           return;
152             }
153              
154 0           return [ map { $_->name } @{ $user->groups } ];
  0            
  0            
155             }
156              
157             =head1 PRIVATE METHODS
158              
159             =head2 _active_directory
160              
161             Returns a connected L<Auth::ActiveDirectory> object.
162              
163             =cut
164              
165             sub _active_directory {
166 0     0     my $self = shift;
167              
168 0   0       my $ad = Auth::ActiveDirectory->new(
169             host => $self->host,
170             port => $self->port,
171             timeout => $self->timeout,
172             domain => $self->domain,
173             principal => $self->principal,
174             ) || croak "ActiveDirectory connect failed for: " . $self->host;
175              
176 0           return $ad;
177             }
178              
179             =head2 _user_cache $username [, $value]
180              
181             Implements the user data cache. As we can only receive the user
182             information from L<Auth::ActiveDirectory> when authenticating,
183             we save it in the cache and can use it when asked via the get_user_details or get_user_roles methods.
184              
185             =cut
186              
187             sub _user_cache {
188 0     0     my ( $self, $username, $value ) = @_;
189 0           state $usercache = {};
190 0 0         return $usercache->{$username} if not defined $value;
191 0           return $usercache->{$username} = $value;
192             }
193              
194             1;
195              
196             =head1 TODO
197              
198             I was not able to create useful tests for this module. I tried to adopt the tests
199             from L<Dancer2::Plugin::Auth::Extensible::Provider::LDAP>, but I was not able to fill
200             the mock object with the correct data for the Test App to work. Please tell me if you
201             can help out.
202              
203              
204             =head1 AUTHOR
205              
206             Dominic Sonntag, C<< <dsonntag at cpan.org> >>
207              
208             =head1 BUGS
209              
210             Please report any bugs or feature requests to C<bug-dancer2-plugin-auth-extensible-provider-activedirectory at rt.cpan.org>, or through
211             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Dancer2-Plugin-Auth-Extensible-Provider-ActiveDirectory>. I will be notified, and then you'll
212             automatically be notified of progress on your bug as I make changes.
213              
214              
215              
216              
217             =head1 SUPPORT
218              
219             You can find documentation for this module with the perldoc command.
220              
221             perldoc Dancer2::Plugin::Auth::Extensible::Provider::ActiveDirectory
222              
223             If you want to contribute to this module, write me an email or create a
224             Pull request on Github: L<https://github.com/sonntagd/Dancer2-Plugin-Auth-Extensible-Provider-ActiveDirectory>
225              
226              
227             =head1 ACKNOWLEDGEMENTS
228              
229              
230             =head1 LICENSE AND COPYRIGHT
231              
232             Copyright 2016 Dominic Sonntag.
233              
234             This program is free software; you can redistribute it and/or modify it
235             under the terms of the the Artistic License (2.0). You may obtain a
236             copy of the full license at:
237              
238             L<http://www.perlfoundation.org/artistic_license_2_0>
239              
240             Any use, modification, and distribution of the Standard or Modified
241             Versions is governed by this Artistic License. By using, modifying or
242             distributing the Package, you accept this license. Do not use, modify,
243             or distribute the Package, if you do not accept this license.
244              
245             If your Modified Version has been derived from a Modified Version made
246             by someone other than you, you are nevertheless required to ensure that
247             your Modified Version complies with the requirements of this license.
248              
249             This license does not grant you the right to use any trademark, service
250             mark, tradename, or logo of the Copyright Holder.
251              
252             This license includes the non-exclusive, worldwide, free-of-charge
253             patent license to make, have made, use, offer to sell, sell, import and
254             otherwise transfer the Package with respect to any patent claims
255             licensable by the Copyright Holder that are necessarily infringed by the
256             Package. If you institute patent litigation (including a cross-claim or
257             counterclaim) against any party alleging that the Package constitutes
258             direct or contributory patent infringement, then this Artistic License
259             to you shall terminate on the date that such litigation is filed.
260              
261             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
262             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
263             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
264             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
265             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
266             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
267             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
268             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
269              
270              
271             =cut
272              
273             1; # End of Dancer2::Plugin::Auth::Extensible::Provider::ActiveDirectory