1 | package Catalyst::Authentication::Credential::La; |
---|
2 | |
---|
3 | use strict; |
---|
4 | use warnings; |
---|
5 | use MIME::Base64; |
---|
6 | |
---|
7 | sub new { |
---|
8 | my ($class) = @_; |
---|
9 | return bless({}, $class); |
---|
10 | } |
---|
11 | |
---|
12 | sub _search_user { |
---|
13 | my ($self, $c) = @_; |
---|
14 | |
---|
15 | my $attribute = $c->config->{ssl}->{ATTRIBUTE_ID} || 'mail'; |
---|
16 | my $sslid = $c->config->{ssl}->{SSL_ID} || 'HTTP_SSL_CLIENT_S_DN_EMAIL'; |
---|
17 | my $value = $ENV{$sslid} or do { |
---|
18 | $c->log->debug("Cannot find user: ENV{$sslid} is empty"); |
---|
19 | return; |
---|
20 | }; |
---|
21 | |
---|
22 | my $base = $c->model('Accounts')->db; |
---|
23 | # quick prefilter |
---|
24 | my @res = $base->search_objects( |
---|
25 | 'user', |
---|
26 | sprintf('%s~%s', $attribute, $value) |
---|
27 | ); |
---|
28 | |
---|
29 | @res = grep { |
---|
30 | my $o = $base->get_object('user', $_); |
---|
31 | $o && grep { lc($_) eq lc($value) } $o->get_attributes($attribute); |
---|
32 | } @res; |
---|
33 | |
---|
34 | if (@res == 1) { |
---|
35 | return $res[0]; |
---|
36 | } else { |
---|
37 | $c->log->error(sprintf |
---|
38 | "Can't identify `%s' user from `%s' attributes, multiple user found: %s", |
---|
39 | $value, |
---|
40 | $attribute, |
---|
41 | join(', ', @res), |
---|
42 | ); |
---|
43 | return; |
---|
44 | } |
---|
45 | } |
---|
46 | |
---|
47 | sub _ssl_filter { |
---|
48 | my ($self, $c, $realm, $authinfo) = @_; |
---|
49 | |
---|
50 | foreach my $f (@{ $c->config->{ssl}->{filters} }) { |
---|
51 | my $matchtype = $f->{op} || '='; |
---|
52 | my $var = $ENV{$f->{var}}; |
---|
53 | if ($matchtype eq '=') { |
---|
54 | do { |
---|
55 | $c->log->debug(sprintf |
---|
56 | 'Filter failed: %s = %s', |
---|
57 | $var, $f->{value} |
---|
58 | ); |
---|
59 | return; |
---|
60 | } unless($var eq $f->{value}); |
---|
61 | } |
---|
62 | elsif ($matchtype eq 're') { |
---|
63 | my $value = $f->{value}; |
---|
64 | do { |
---|
65 | $c->log->debug(sprintf |
---|
66 | 'Filter failed: %s match %s', |
---|
67 | $var, $f->{value} |
---|
68 | ); |
---|
69 | return; |
---|
70 | } unless($var =~ m/$value/); |
---|
71 | } |
---|
72 | else { |
---|
73 | $c->log->error(sprintf 'Wrong filter op: %s', $matchtype); |
---|
74 | return; |
---|
75 | } |
---|
76 | } |
---|
77 | |
---|
78 | return 1; |
---|
79 | } |
---|
80 | |
---|
81 | sub _ssl_auth { |
---|
82 | my ($self, $c, $realm, $authinfo) = @_; |
---|
83 | |
---|
84 | if ($c->config->{ssl}->{filters}) { |
---|
85 | if (!$self->_ssl_filter($c, $realm, $authinfo)) { |
---|
86 | return; |
---|
87 | } |
---|
88 | } |
---|
89 | |
---|
90 | if (my $u = $self->_search_user($c)) { |
---|
91 | $c->log->info(sprintf 'SSL auth for %s', $u); |
---|
92 | $authinfo->{username} = $u; |
---|
93 | return 1; |
---|
94 | } else { |
---|
95 | return; |
---|
96 | } |
---|
97 | } |
---|
98 | |
---|
99 | sub _login_auth { |
---|
100 | my ($self, $c, $realm, $authinfo) = @_; |
---|
101 | my $authheader = $c->req->headers->header('Authorization') |
---|
102 | or do { |
---|
103 | $c->log->debug('No Authorization header found'); |
---|
104 | return; |
---|
105 | }; |
---|
106 | # TODO check auth type |
---|
107 | my ($type, $base64) = $authheader =~ /(\w+) (\S+)/; |
---|
108 | ($authinfo->{username}, $authinfo->{password}) |
---|
109 | = decode_base64($base64) =~ /^([^:]+):(.*)/; |
---|
110 | |
---|
111 | if($c->model('Accounts')->db->connect( |
---|
112 | $authinfo->{username}, |
---|
113 | $authinfo->{password} |
---|
114 | )) { |
---|
115 | $c->log->info(sprintf 'basic auth for %s', $authinfo->{username}); |
---|
116 | return $realm->find_user($authinfo) |
---|
117 | } else { |
---|
118 | return; |
---|
119 | $c->log->error(sprintf |
---|
120 | 'Invalid password or user for user %s', |
---|
121 | $authinfo->{username} || |
---|
122 | '(none)' |
---|
123 | ); |
---|
124 | } |
---|
125 | } |
---|
126 | |
---|
127 | sub authenticate { |
---|
128 | my ($self, $c, $realm, $authinfo) = @_; |
---|
129 | if (! ( |
---|
130 | $self->_ssl_auth ($c, $realm, $authinfo) || |
---|
131 | $self->_login_auth($c, $realm, $authinfo) |
---|
132 | )) { return; } |
---|
133 | |
---|
134 | $c->model('Accounts')->db->{_user} = $authinfo->{username}; |
---|
135 | return $realm->find_user($authinfo); |
---|
136 | } |
---|
137 | |
---|
138 | 1; |
---|