Commit | Line | Data |
---|---|---|
f7fdbaad | 1 | package Apache2::Authen::Passphrase 0.001001; |
f4cc782b MG |
2 | |
3 | use 5.014000; | |
4 | use strict; | |
5 | use warnings; | |
6 | use parent qw/Exporter/; | |
7 | ||
8 | use constant +{ | |
9 | USER_REGEX => qr/^\w{2,20}$/pa, | |
10 | PASSPHRASE_VERSION => 1, | |
11 | INVALID_USER => "invalid-user\n", | |
12 | BAD_PASSWORD => "bad-password\n", | |
13 | }; | |
14 | ||
15 | use Apache2::RequestRec; | |
16 | use Apache2::Access; | |
17 | use Apache2::Const qw/OK HTTP_UNAUTHORIZED/; | |
18 | use Authen::Passphrase; | |
19 | use Authen::Passphrase::BlowfishCrypt; | |
20 | use YAML::Any qw/LoadFile DumpFile/; | |
21 | ||
22 | our @EXPORT_OK = qw/pwset pwcheck pwhash USER_REGEX PASSPHRASE_VERSION INVALID_USER BAD_PASSWORD/; | |
23 | ||
24 | ################################################## | |
25 | ||
26 | our $rootdir; | |
27 | ||
28 | sub pwhash{ | |
29 | my ($pass)=@_; | |
30 | ||
31 | my $ppr=Authen::Passphrase::BlowfishCrypt->new( | |
32 | cost => 10, | |
33 | passphrase => $pass, | |
34 | salt_random => 1, | |
35 | ); | |
36 | ||
37 | $ppr->as_rfc2307 | |
38 | } | |
39 | ||
40 | sub pwset{ | |
41 | my ($user, $pass)=@_; | |
42 | ||
f7fdbaad | 43 | my $file = "$rootdir/$user.yml"; |
f4cc782b MG |
44 | my $conf = eval { LoadFile $file } // undef; |
45 | $conf->{passphrase}=pwhash $pass; | |
46 | $conf->{passphrase_version}=PASSPHRASE_VERSION; | |
47 | DumpFile $file, $conf; | |
48 | ||
49 | chmod 0660, $file; | |
50 | } | |
51 | ||
52 | sub pwcheck{ | |
53 | my ($user, $pass)=@_; | |
54 | die INVALID_USER unless $user =~ USER_REGEX; | |
55 | $user=${^MATCH};# Make taint shut up | |
f7fdbaad | 56 | my $conf=LoadFile "$rootdir/$user.yml"; |
f4cc782b MG |
57 | |
58 | die BAD_PASSWORD unless keys $conf;# Empty hash means no such user | |
59 | die BAD_PASSWORD unless Authen::Passphrase->from_rfc2307($conf->{passphrase})->match($pass); | |
60 | pwset $user, $pass if $conf->{passphrase_version} < PASSPHRASE_VERSION | |
61 | } | |
62 | ||
63 | sub handler{ | |
64 | my $r=shift; | |
f7fdbaad | 65 | local $rootdir = $r->dir_config('AuthenPassphraseRootdir'); |
f4cc782b MG |
66 | |
67 | my ($rc, $pass) = $r->get_basic_auth_pw; | |
68 | return $rc unless $rc == OK; | |
69 | ||
70 | my $user=$r->user; | |
71 | unless (eval { pwcheck $user, $pass; 1 }) { | |
72 | $r->note_basic_auth_failure; | |
73 | return HTTP_UNAUTHORIZED | |
74 | } | |
75 | ||
76 | OK | |
77 | } | |
78 | ||
79 | 1; | |
80 | __END__ | |
81 | ||
82 | =head1 NAME | |
83 | ||
84 | Apache2::Authen::Passphrase - basic authentication with Authen::Passphrase | |
85 | ||
86 | =head1 SYNOPSIS | |
87 | ||
88 | use Apache2::Authen::Passphrase qw/pwcheck pwset pwhash/; | |
f7fdbaad | 89 | $Apache2::Authen::Passphrase::rootdir = "/path/to/user/directory" |
f4cc782b MG |
90 | my $hash = pwhash $username, $password; |
91 | pwset $username, "pass123"; | |
92 | eval { pwcheck $username, "pass123" }; | |
93 | ||
94 | # In Apache2 config | |
95 | <Location /secret> | |
96 | PerlAuthenHandler Apache2::Authen::Passphrase | |
f7fdbaad | 97 | PerlSetVar AuthenPassphraseRootdir /path/to/user/directory |
f4cc782b MG |
98 | AuthName MyAuth |
99 | Require valid-user | |
100 | </Location> | |
101 | ||
102 | =head1 DESCRIPTION | |
103 | ||
104 | Apache2::Authen::Passphrase is a perl module which provides easy-to-use Apache2 authentication. It exports some utility functions and it contains a PerlAuthenHandler. | |
105 | ||
106 | =head1 FUNCTIONS | |
107 | ||
108 | =over | |
109 | ||
110 | =item B<pwhash>() | |
111 | ||
112 | Takes the password as a single argument and returns the password hash. | |
113 | ||
114 | =item B<pwset>(I<$username>, I<$password>) | |
115 | ||
116 | Sets the password of $username to $password. | |
117 | ||
118 | =item B<pwcheck>(I<$username>, I<$password>) | |
119 | ||
120 | Checks the given username and password, throwing an exception if the username is invalid or the password is incorrect. | |
121 | ||
122 | =item B<handler> | |
123 | ||
124 | The PerlAuthenHandler for use in apache2. It uses Basic Access Authentication. | |
125 | ||
126 | =item B<USER_REGEX> | |
127 | ||
128 | A regex that matches valid usernames. Usernames must be at least 2 characters, at most 20 characters, and they may only contain word characters (C<[A-Za-z0-9_]>). | |
129 | ||
130 | =item B<INVALID_USER> | |
131 | ||
132 | Exception thrown if the username does not match C<USER_REGEX>. | |
133 | ||
134 | =item B<BAD_PASSWORD> | |
135 | ||
136 | Exception thrown if the password is different from the one stored in the user's yml file. | |
137 | ||
138 | =item B<PASSPHRASE_VERSION> | |
139 | ||
140 | The version of the passphrase. It is incremented each time the passphrase hashing scheme is changed. Versions so far: | |
141 | ||
142 | =over | |
143 | ||
144 | =item Version 1 B<(current)> | |
145 | ||
146 | Uses C<Authen::Passphrase::BlowfishCrypt> with a cost factor of 10 | |
147 | ||
148 | =back | |
149 | ||
150 | =back | |
151 | ||
152 | =head1 AUTHOR | |
153 | ||
154 | Marius Gavrilescu, E<lt>marius@ieval.roE<gt> | |
155 | ||
156 | =head1 COPYRIGHT AND LICENSE | |
157 | ||
158 | Copyright (C) 2013 by Marius Gavrilescu | |
159 | ||
160 | This library is free software; you can redistribute it and/or modify | |
161 | it under the same terms as Perl itself, either Perl version 5.14.2 or, | |
162 | at your option, any later version of Perl 5 you may have available. | |
163 | ||
164 | ||
165 | =cut |