File Coverage

blib/lib/Auth/Kokolores/Plugin/CheckPassword.pm
Criterion Covered Total %
statement 47 79 59.4
branch 11 28 39.2
condition 0 9 0.0
subroutine 10 13 76.9
pod 0 12 0.0
total 68 141 48.2


line stmt bran cond sub pod time code
1             package Auth::Kokolores::Plugin::CheckPassword;
2              
3 2     2   1949 use Moose;
  2         3  
  2         14  
4              
5             # ABSTRACT: kokolores plugin for checking passwords
6             our $VERSION = '1.00'; # VERSION
7              
8             extends 'Auth::Kokolores::Plugin';
9              
10             has 'method' => ( is => 'ro', isa => 'Str', default => 'plain' );
11             has 'method_from' => ( is => 'ro', isa => 'Maybe[Str]' );
12              
13             sub get_method {
14 6     6 0 9 my ( $self, $r ) = @_;
15 6 50       191 if( defined $self->method_from ) {
16 0         0 return $r->get_info( $self->method_from );
17             }
18 6         164 return $self->method;
19             }
20              
21             has 'password_from' => ( is => 'ro', isa => 'Str', required => 1 );
22              
23             sub get_password {
24 6     6 0 5 my ( $self, $r ) = @_;
25 6         170 return $r->get_info( $self->password_from );
26             }
27              
28             has 'cost' => ( is => 'ro', isa => 'Int', default => 1 );
29             has 'cost_from' => ( is => 'ro', isa => 'Maybe[Str]' );
30              
31             sub get_cost {
32 0     0 0 0 my ( $self, $r ) = @_;
33 0 0       0 if( defined $self->cost_from ) {
34 0         0 return $r->get_info( $self->cost_from );
35             }
36 0         0 return $self->cost;
37             }
38              
39             has 'salt' => ( is => 'ro', isa => 'Maybe[Str]' );
40             has 'salt_from' => ( is => 'ro', isa => 'Maybe[Str]' );
41             sub get_salt {
42 0     0 0 0 my ( $self, $r ) = @_;
43 0 0       0 if( defined $self->salt_from ) {
44 0         0 return $r->get_info( $self->salt_from );
45             }
46 0         0 return $self->salt;
47             }
48              
49             has 'supported_methods' => (
50             is => 'ro', isa => 'ArrayRef[Str]',
51             default => sub { [ 'plain' ] },
52             traits => [ 'Array' ],
53             handles => {
54             add_supported_method => 'push',
55             },
56             );
57              
58             sub is_supported_method {
59 6     6 0 9 my ( $self, $method ) = @_;
60 6 50       8 if( grep { $method eq $_ } @{$self->supported_methods} ) {
  18         29  
  6         168  
61 6         12 return 1;
62             }
63 0         0 return 0;
64             }
65              
66             has 'additional_methods' => (
67             is => 'ro', isa => 'HashRef[Str]',
68             default => sub { {
69             pbkdf2 => 'Crypt::PBKDF2',
70             bcrypt => 'Crypt::Eksblowfish::Bcrypt',
71             bcrypt_fields => 'Digest::Bcrypt',
72             } },
73             );
74              
75             sub load_additional_methods {
76 2     2 0 3 my $self = shift;
77 2         65 my $am = $self->additional_methods;
78              
79 2         7 foreach my $method ( keys %$am ) {
80 6         9 my $module = $am->{$method};
81 6         295 eval "require $module;"; ## no critic
82 6 50       111459 if( $@ ) {
83 0         0 $self->log(1, "method $method not available. (install ".$am->{$method}.')');
84 0         0 next;
85             }
86 6         232 $self->add_supported_method( $method );
87             }
88              
89 2         5 return;
90             }
91              
92             sub init {
93 2     2 0 2301 my ( $self ) = @_;
94 2         6 $self->load_additional_methods();
95 2         4 $self->log(1, 'supported password methods: '.join(', ', @{$self->supported_methods}));
  2         62  
96 2         667 return;
97             }
98              
99             sub authenticate {
100 6     6 0 181 my ( $self, $r ) = @_;
101              
102 6         17 my $method = $self->get_method( $r );
103 6 50       30 if( ! defined $method ) {
    50          
104 0         0 $self->log(1, 'no password method defined');
105 0         0 return 0;
106             } elsif( $self->is_supported_method( $method ) ) {
107 6         13 my $call = "authenticate_$method";
108 6         19 return $self->$call( $r );
109             } else {
110 0         0 $self->log(1, 'unsupported password method: '.$method);
111             }
112              
113 0         0 return 0;
114             }
115              
116             sub authenticate_plain {
117 2     2 0 3 my ( $self, $r ) = @_;
118 2         5 my $pw = $self->get_password( $r );
119              
120 2 100       57 if( $r->password eq $pw ) {
121 1         5 return 1;
122             }
123 1         4 return 0;
124             }
125              
126             has 'pbkdf2' => (
127             is => 'ro', isa => 'Crypt::PBKDF2', lazy => 1,
128             default => sub { Crypt::PBKDF2->new },
129             );
130              
131             sub authenticate_pbkdf2 {
132 2     2 0 3 my ( $self, $r ) = @_;
133 2         7 my $hash = $self->get_password( $r );
134              
135 2 100       83 if( $self->pbkdf2->validate($hash, $r->password) ) {
136 1         5668 return 1;
137             }
138 1         5567 return 0;
139             }
140              
141             sub authenticate_bcrypt {
142 2     2 0 3 my ( $self, $r ) = @_;
143 2         7 my $hash = $self->get_password( $r );
144 2         51 my $pw = $r->password;
145              
146 2 100       7 if( Crypt::Eksblowfish::Bcrypt::bcrypt( $pw, $hash ) eq $hash ) {
147 1         90580 return 1;
148             }
149              
150 1         90202 return 0;
151             }
152              
153             sub authenticate_bcrypt_fields {
154 0     0 0   my ( $self, $r ) = @_;
155 0           my $hash = $self->get_password( $r );
156 0           my $pw = $r->password;
157              
158 0           my %params = (
159             cost => $self->get_cost($r),
160             salt => $self->get_salt($r),
161             );
162 0           foreach my $param ( 'cost', 'salt' ) {
163 0 0         if( ! defined $params{$param} ) {
164 0           $self->log("parameter $param is not defined");
165 0           return 0;
166             }
167             }
168              
169 0           my $bcrypt = Digest::Bcrypt->new( %params );
170 0           $bcrypt->add( $pw );
171              
172 0           my $hashlen = length( $hash );
173 0 0 0       if( $hashlen == 31
    0 0        
    0 0        
174             && $pw eq $bcrypt->b64digest ) {
175 0           return 1;
176             } elsif( $hashlen == 46
177             && $pw eq $bcrypt->hexdigest ) {
178 0           return 1;
179             } elsif( $hashlen == 23
180             && $pw eq $bcrypt->digest ) {
181 0           return 1;
182             }
183              
184 0           return 0;
185             }
186              
187             1;
188              
189             __END__
190              
191             =pod
192              
193             =encoding UTF-8
194              
195             =head1 NAME
196              
197             Auth::Kokolores::Plugin::CheckPassword - kokolores plugin for checking passwords
198              
199             =head1 VERSION
200              
201             version 1.00
202              
203             =head1 AUTHOR
204              
205             Markus Benning <ich@markusbenning.de>
206              
207             =head1 COPYRIGHT AND LICENSE
208              
209             This software is Copyright (c) 2016 by Markus Benning <ich@markusbenning.de>.
210              
211             This is free software, licensed under:
212              
213             The GNU General Public License, Version 2, June 1991
214              
215             =cut