File Coverage

blib/lib/PlugAuth/Plugin/DBIAuth.pm
Criterion Covered Total %
statement 20 63 31.7
branch 0 28 0.0
condition 0 9 0.0
subroutine 7 14 50.0
pod 7 7 100.0
total 34 121 28.1


line stmt bran cond sub pod time code
1             package PlugAuth::Plugin::DBIAuth;
2              
3 1     1   557 use strict;
  1         2  
  1         23  
4 1     1   4 use warnings;
  1         1  
  1         19  
5 1     1   13 use 5.010;
  1         3  
6 1     1   1111 use DBI;
  1         12352  
  1         51  
7 1     1   699 use Log::Log4perl qw/:easy/;
  1         36270  
  1         5  
8 1     1   1476 use Role::Tiny::With;
  1         4991  
  1         71  
9 1     1   567 use Crypt::PasswdMD5 qw( unix_md5_crypt apache_md5_crypt );
  1         971  
  1         886  
10              
11             with 'PlugAuth::Role::Plugin';
12             with 'PlugAuth::Role::Auth';
13              
14             # ABSTRACT: DBI Authentication back end for PlugAuth
15             our $VERSION = '0.06'; # VERSION
16              
17              
18             sub init
19             {
20 0     0 1   my($self) = @_;
21 0           my %db = $self->plugin_config->db;
22 0           my %sql = $self->plugin_config->sql;
23              
24             $self->{dbh} = DBI->connect($db{dsn}, $db{user}, $db{pass},
25 0           { RaiseError => 1, AutoCommit => 1 }
26             );
27            
28             $self->{dbh}->do($sql{init})
29 0 0         if defined $sql{init};
30            
31 0           foreach my $name (qw( check_credentials all_users create_user change_password delete_user ))
32             {
33             $self->{$name} = $self->{dbh}->prepare($sql{$name})
34 0 0         if defined $sql{$name};
35             }
36            
37 0           $self->{encryption} = $self->plugin_config->encryption(default => 'apache_md5');
38             }
39              
40              
41             sub check_credentials
42             {
43 0     0 1   my($self, $user, $pass) = @_;
44              
45 0 0         if(defined $self->{check_credentials})
46             {
47 0           $self->{check_credentials}->execute($user);
48 0           my($encrypted) = $self->{check_credentials}->fetchrow_array;
49 0           $self->{check_credentials}->finish;
50 0 0         if($encrypted)
51             {
52 0           my $tmp = crypt($pass, $encrypted);
53 0 0 0       return 1 if (defined $tmp) && ($tmp eq $encrypted);
54            
55 0 0         if($encrypted =~ /^\$(\w+)\$/)
56             {
57 0 0 0       return 1 if $1 eq 'apr1' && apache_md5_crypt( $pass, $encrypted ) eq $encrypted;
58 0 0 0       return 1 if $1 eq '1' && unix_md5_crypt ( $pass, $encrypted ) eq $encrypted;
59             }
60             }
61             }
62              
63 0           $self->deligate_check_credentials($user, $pass);
64             }
65              
66              
67             sub all_users
68             {
69             my($self) = @_;
70            
71             my @list;
72            
73             if(defined $self->{all_users})
74             {
75             $self->{all_users}->execute;
76             while(my $row = $self->{all_users}->fetchrow_arrayref)
77             {
78             push @list, $row->[0];
79             }
80             }
81            
82             @list;
83             }
84              
85              
86             sub create_user {
87 0     0 1   my($self, $user, $pass) = @_;
88            
89 0 0         if(defined $self->{create_user})
90             {
91 0           $self->{create_user}->execute($user, $self->created_encrypted_password($pass));
92 0           return 1;
93             }
94             else
95             {
96 0           return 0;
97             }
98             }
99              
100              
101             sub change_password {
102 0     0 1   my($self, $user, $pass) = @_;
103            
104 0 0         if(defined $self->{change_password})
105             {
106 0           $self->{change_password}->execute($self->created_encrypted_password($pass), $user);
107 0           return 1;
108             }
109             else
110             {
111 0           return 0;
112             }
113             }
114              
115              
116             sub delete_user {
117 0     0 1   my($self, $user) = @_;
118            
119 0 0         if(defined $self->{delete_user})
120             {
121 0           $self->{delete_user}->execute($user);
122 0           return 1;
123             }
124             else
125             {
126 0           return 0;
127             }
128             }
129              
130              
131 0     0 1   sub dbh { shift->{dbh} }
132              
133              
134             sub created_encrypted_password
135             {
136 0     0 1   my($self, $plain) = @_;
137 0           my $salt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
138 0 0         if($self->{encryption} eq 'apache_md5')
    0          
    0          
139             {
140 0           return apache_md5_crypt($plain, $salt);
141             }
142             elsif($self->{encryption} eq 'unix_md5')
143             {
144 0           return unix_md5_crypt($plain, $salt);
145             }
146             elsif($self->{encryption} eq 'unix')
147             {
148 0           return crypt($plain, $salt);
149             }
150             else
151             {
152 0           die "unknown encryption " . $self->{encryption};
153             }
154             }
155              
156             1;
157              
158             __END__
159              
160             =pod
161              
162             =encoding UTF-8
163              
164             =head1 NAME
165              
166             PlugAuth::Plugin::DBIAuth - DBI Authentication back end for PlugAuth
167              
168             =head1 VERSION
169              
170             version 0.06
171              
172             =head1 SYNOPSIS
173              
174             In your PlugAuth.conf file:
175              
176             ---
177             plugins:
178             - PlugAuth::Plugin::DBIAuth:
179             db:
180             dsn: 'dbi:SQLite:dbname=/path/to/dbfile.sqlite'
181             user: ''
182             pass: ''
183             sql:
184             init: 'CREATE TABLE IF NOT EXISTS users (username VARCHAR UNIQUE, password VARCHAR)'
185             check_credentials: 'SELECT password FROM users WHERE username = ?'
186             all_users: 'SELECT username FROM users'
187              
188             =head1 DESCRIPTION
189              
190             This plugin provides an authentication mechanism for PlugAuth using any
191             database supported by DBI as a backend. It is configured as above, with
192             two hashes, db and sql.
193              
194             =head2 encryption
195              
196             Specifies the encryption method to use. This is only used when creating
197             new users, or changing their passwords. Existing passwords will remain
198             in their existing formats and will be decrypted automatically in the
199             correct format.
200              
201             If provided, must be one of:
202              
203             =over 4
204              
205             =item * unix
206              
207             Traditional UNIX crypt()
208              
209             =item * unix_md5
210              
211             UNIX MD5
212              
213             =item * apache_md5 [ default ]
214              
215             Apache MD5
216              
217             =back
218              
219             =head2 db
220              
221             The db hash provides the required parameters for the plugin needed to
222             connect to the database.
223              
224             =head3 dsn
225              
226             The DNS passed into DBI. See the documentation for your database driver
227             for the exact format (L<DBD::SQLite>, L<DBD::Pg>, L<DBD::mysql> ... ).
228              
229             =head3 user
230              
231             The database user.
232              
233             =head3 pass
234              
235             The database password.
236              
237             =head2 sql
238              
239             The sql hash provides SQL statements which are executed for each
240             operation. They are all optional. The examples shown here assumes
241             a simple table with usernames and passwords:
242              
243             CREATE TABLE IF NOT EXISTS users (
244             username VARCHAR UNIQUE,
245             password VARCHAR
246             );
247              
248             =head3 init
249              
250             Arbitrary SQL executed when the plugin is started.
251              
252             =head3 check_credentials
253              
254             The SQL statement used to fetch the encrypted password of a
255             user. The username is the first bind value when executed.
256             Example:
257              
258             SELECT password FROM users WHERE username = ?
259              
260             =head3 all_users
261              
262             The SQL statement used to fetch the list of users. Example:
263              
264             SELECT username FROM users
265              
266             =head3 create_user
267              
268             The SQL statement used to create a new user. Example:
269              
270             INSERT INTO users (username, password) VALUES (?,?)
271              
272             =head3 change_password
273              
274             The SQL statement used to change the password of an existing user. Example:
275              
276             UPDATE users SET password = ? WHERE username = ?
277              
278             =head3 delete_user
279              
280             The SQL statement used to delete an existing user. Example:
281              
282             DELETE FROM users WHERE username = ?
283              
284             =head3 dbh
285              
286             Returns the dbh handle used to query the database.
287              
288             =head3 created_encrypted_password
289              
290             Given a new plain text password, return the encrypted version.
291              
292             =head1 SEE ALSO
293              
294             L<DBI>,
295             L<PlugAuth>
296              
297             =head1 AUTHOR
298              
299             Graham Ollis <gollis@sesda3.com>
300              
301             =head1 COPYRIGHT AND LICENSE
302              
303             This software is copyright (c) 2015 by Graham Ollis.
304              
305             This is free software; you can redistribute it and/or modify it under
306             the same terms as the Perl 5 programming language system itself.
307              
308             =cut