File Coverage

blib/lib/Plack/Middleware/Auth/Negotiate.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package Plack::Middleware::Auth::Negotiate;
2              
3 1     1   22594 use 5.006;
  1         5  
  1         55  
4 1     1   6 use strict;
  1         3  
  1         37  
5 1     1   6 use warnings;
  1         34  
  1         32  
6              
7 1     1   1253 use parent 'Plack::Middleware';
  1         297  
  1         5  
8 1     1   17407 use Plack::Util::Accessor 'keytab';
  1         2  
  1         4  
9 1     1   35 use Scalar::Util;
  1         2  
  1         34  
10 1     1   731 use MIME::Base64;
  1         710  
  1         58  
11 1     1   357 use GSSAPI;
  0            
  0            
12              
13             =head1 NAME
14              
15             Plack::Middleware::Auth::Negotiate - Negotiate authentication middleware (SPNEGO)
16              
17             =head1 VERSION
18              
19             Version 0.02
20              
21             =cut
22              
23             our $VERSION = '0.02';
24              
25             sub prepare_app {
26             my $self = shift;
27             }
28              
29             sub call {
30             my($self, $env) = @_;
31              
32             my $auth = $env->{HTTP_AUTHORIZATION}
33             or return $self->unauthorized;
34              
35             if ($auth =~ /^Negotiate (.*)$/) {
36             my $data = MIME::Base64::decode($1);
37             $ENV{KRB5_KTNAME} = $self->keytab if $self->keytab;
38             my $user = gssapi_verify($data);
39             if ($user) {
40             $env->{REMOTE_USER} = $user;
41             return $self->app->($env);
42             }
43             }
44              
45             return $self->unauthorized;
46             }
47              
48             my $UNAUTH_MSG = q{
49            
50             401 Authorization Required
51            
52            

Authorization Required

53            

This server could not verify that you

54             are authorized to access the document
55             requested. Either you supplied the wrong
56             credentials (e.g., bad password), or your
57             browser doesn't understand how to supply
58             the credentials required.

59            
60             };
61              
62             sub unauthorized {
63             my $self = shift;
64             return [
65             401,
66             [ 'Content-Type' => 'text/html',
67             'Content-Length' => length $UNAUTH_MSG,
68             'WWW-Authenticate' => 'Negotiate' ],
69             [ $UNAUTH_MSG ],
70             ];
71             }
72              
73             sub gssapi_verify {
74             my $gss_input_token = shift;
75             my $server_context;
76             my $status = GSSAPI::Context::accept(
77             $server_context,
78             GSS_C_NO_CREDENTIAL,
79             $gss_input_token,
80             GSS_C_NO_CHANNEL_BINDINGS,
81             my $gss_client_name,
82             my $out_mech,
83             my $gss_output_token,
84             my $out_flags,
85             my $out_time,
86             my $gss_delegated_cred);
87              
88             $status or return gss_exit("Unable to accept security context", $status);
89             my $client_name;
90             $status = $gss_client_name->display($client_name);
91             $status or return gss_exit("Unable to display client name", $status);
92             return $client_name;
93             }
94              
95             sub gss_exit {
96             my $errmsg = shift;
97             my $status = shift;
98              
99             my @major_errors = $status->generic_message();
100             my @minor_errors = $status->specific_message();
101              
102             print STDERR "$errmsg:\n";
103             foreach my $s (@major_errors) {
104             print STDERR " MAJOR::$s\n";
105             }
106             foreach my $s (@minor_errors) {
107             print STDERR " MINOR::$s\n";
108             }
109             return;
110             }
111              
112             =head1 SYNOPSIS
113              
114             use Plack::Builder;
115             my $app = sub { ... };
116              
117             builder {
118             enable 'Auth::Negotiate', keytab => 'FILE:www.keytab';
119             $app;
120             };
121              
122             =head1 DESCRIPTION
123              
124             Plack::Middleware::Auth::Negotiate provides Negotiate (SPNEGO) authentication
125             for your Plack application (for use with Kerberos).
126              
127             This is a very alpha module, and I am still testing some of the security corner
128             cases. Help wanted.
129              
130             =head1 CONFIGURATION
131              
132             =over 4
133              
134             =item * keytab: path to the keytab to use. This value is set as
135             C<$ENV{KRB5_KTNAME}> if provided.
136              
137             =back
138              
139             Note that there is no option for matching URLs. You can do this yourself with
140             L's C syntax (for L).
141              
142             =head1 TODO
143              
144             =over 4
145              
146             =item * More security testing.
147              
148             =item * Ability to specify a list of valid realms. If REALM.EXAMPLE.COM trusts
149             REALM.FOOBAR.COM, and we don't want to allow REALM.FOOBAR.COM users, we have to
150             check after accepting the ticket.
151              
152             =item * Option to automatically trim the @REALM.EXAMPLE.COM portion of the user
153             value.
154              
155             =item * Method to also provide Basic auth if Negotiate fails.
156              
157             =item * Some way to cooperate with other Auth middleware. C is your
158             best bet right now (with different URLs for each type of authentication, and
159             writing a session).
160              
161             =item * Better interaction with L, since this
162             authentication is slow in my experience.
163              
164             =item * Better implementation of the actual RFC.
165              
166             =item * Custom "Authorization Required" message
167              
168             =back
169              
170             =head1 SEE ALSO
171              
172             L, L, L
173              
174             L, mod_auth_kerb
175              
176             =head1 ACKNOWLEDGEMENTS
177              
178             This code is based off of L and a sample script
179             provided with L.
180              
181             =head1 AUTHOR
182              
183             Adrian Kreher, C<< >>
184              
185             =head1 BUGS
186              
187             Please report any bugs or feature requests to
188             C, or through the web
189             interface at
190             L.
191             I will be notified, and then you'll automatically be notified of progress on
192             your bug as I make changes.
193              
194             =head1 SUPPORT
195              
196             You can find documentation for this module with the perldoc command.
197              
198             perldoc Plack::Middleware::Auth::Negotiate
199              
200              
201             =head1 LICENSE AND COPYRIGHT
202              
203             Copyright 2011 Adrian Kreher.
204              
205             This program is distributed under the (Revised) BSD License:
206             L
207              
208             Redistribution and use in source and binary forms, with or without
209             modification, are permitted provided that the following conditions
210             are met:
211              
212             * Redistributions of source code must retain the above copyright
213             notice, this list of conditions and the following disclaimer.
214              
215             * Redistributions in binary form must reproduce the above copyright
216             notice, this list of conditions and the following disclaimer in the
217             documentation and/or other materials provided with the distribution.
218              
219             * Neither the name of Adrian Kreher's Organization
220             nor the names of its contributors may be used to endorse or promote
221             products derived from this software without specific prior written
222             permission.
223              
224             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225             "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
226             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
227             A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
228             OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
230             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231             DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232             THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
233             (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
234             OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
235              
236              
237             =cut
238              
239             1; # End of Plack::Middleware::Auth::Negotiate