File Coverage

blib/lib/WebService/TicketAuth.pm
Criterion Covered Total %
statement 12 36 33.3
branch 0 4 0.0
condition 0 2 0.0
subroutine 4 11 36.3
pod 6 6 100.0
total 22 59 37.2


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             WebService::TicketAuth - Ticket-based authentication module for SOAP services
5              
6             =head1 SYNOPSIS
7              
8             @WebService::MyService::ISA = qw(WebService::TicketAuth);
9              
10             =head1 DESCRIPTION
11              
12             B is an authentication system for SOAP-based web
13             services, that provides a signature token (like a cookie) to the client
14             that it can use for further interactions with the server. This means
15             that the user can login and establish their credentials for their
16             session, then use various tools without having to provide a password for
17             each operation. Sessions can be timed out, to mitigate against a ticket
18             being used inappropriately.
19              
20             This is similar in philosophy to authenticated web sessions where the
21             user logs in and gains a cookie that it can use for further
22             interactions. For example, see Apache::AuthTicket. However, such
23             systems require a web server such as Apache to handle the
24             authentication. This module provides a mechanism that can be used
25             outside of a web server. In particular, it is designed for use with
26             a SOAP daemon architecture.
27              
28             This module was originally developed by Paul Kulchenko in 2001. See
29             guide.soaplite.com for more info.
30              
31             =head1 FUNCTIONS
32              
33             =cut
34              
35             package WebService::TicketAuth;
36              
37             # we will need to manage Header information to get a ticket
38             @WebService::TicketAuth::ISA = qw(SOAP::Server::Parameters);
39              
40 1     1   29586 use strict;
  1         3  
  1         46  
41 1     1   6 use Digest::MD5 qw(md5);
  1         2  
  1         82  
42              
43 1     1   7 use vars qw($VERSION %FIELDS);
  1         5  
  1         206  
44             our $VERSION = '1.05';
45              
46 1         9 use fields qw(
47             _error_msg
48             _debug
49 1     1   1112 );
  1         2131  
50              
51             my $calculateAuthInfo = sub {
52             return md5(join '', 'WebService::TicketAuth', $VERSION, @_);
53             };
54              
55             my $makeAuthInfo = sub {
56             my $username = shift;
57             my $duration = shift || 20*60;
58              
59             if (! $username) {
60             return undef;
61             }
62              
63             # Length of time signature will be valid
64             my $time = time() + $duration;
65              
66             # Create the signature
67             my $signature = $calculateAuthInfo->($username, $time);
68              
69             return +{time => $time, username => $username, signature => $signature};
70             };
71              
72             my $checkAuthInfo = sub {
73             my $authInfo = shift;
74             if (! $authInfo) {
75             return undef;
76             }
77              
78             my $signature = $calculateAuthInfo->(@{$authInfo}{qw(username time)});
79              
80             if ($signature ne $authInfo->{signature}) {
81             return undef;
82             } elsif (time() > $authInfo->{time}) {
83             return undef;
84             } else {
85             return $authInfo->{username};
86             }
87             };
88              
89              
90             =head2 new()
91              
92             Creates a new instance of TicketAuth. Establishes several private member
93             functions for authentication, to calculate, make, and check the authInfo.
94              
95             =cut
96              
97             sub new {
98 0     0 1   my WebService::TicketAuth $self = shift;
99 0 0         if (! ref $self) {
100 0           $self = fields::new($self);
101             }
102 0           return $self;
103             }
104              
105             # Internal routine for setting the error message
106             sub _set_error {
107 0     0     my $self = shift;
108 0           $self->{'_error_msg'} = shift;
109             }
110              
111             =head2 get_error()
112              
113             Returns the most recent error message. If any of this module's routines
114             return undef, this routine can be called to retrieve a message about
115             what happened. If several errors have occurred, this will only return
116             the most recently encountered one.
117              
118             =cut
119              
120             sub get_error {
121 0     0 1   my $self = shift;
122 0           return $self->{'_error_msg'};
123             }
124              
125             =head2 ticket_duration($username)
126              
127             This routine defines how long a ticket should last. Override it to
128             customize the ticket lengths. The username is provided when requesting
129             this information, to permit applications to vary ticket length based
130             on the user's access level, if desired. If $username is undef, then a
131             generic duration should be returned.
132              
133             By default, the ticket duration is defined to be 20 minutes (or 20*60
134             seconds).
135              
136             =cut
137              
138             sub ticket_duration {
139 0     0 1   my $self = shift;
140 0           my $username = shift;
141 0           return 20*60;
142             }
143              
144              
145             =head2 get_username($header)
146              
147             Retrieves the username from the auth section of the SOAP header
148              
149             =cut
150              
151             sub get_username {
152 0     0 1   my $self = shift;
153 0   0       my $header = shift || return undef;
154              
155 0           return $checkAuthInfo->($header->valueof('//authInfo'));
156             }
157              
158             =head2 is_valid($username, $password)
159              
160             Routine to determine if the given user credentials are valid. Returns 1
161             to indicate if the credentials are accepted, or undef if not. Error
162             messages can be retrieved from the get_error() routine.
163              
164             Override this member function to implement your own authentication system.
165             This base class function always returns false.
166              
167             =cut
168              
169             sub is_valid {
170 0     0 1   my $self = shift;
171 0           my ($username, $password) = @_;
172              
173 0           $self->_set_error("Error: Base class is_valid() called. ".
174             "Validation must be performed by a derived class.\n");
175              
176 0           return undef;
177             }
178              
179             =head2 login()
180              
181             This routine is called by users to establish their credentials. It
182             returns an AuthInfo ticket on success, or undef if the login failed
183             for any reason. The error message can be retrieved from get_error().
184              
185             It checks credentials by calling the is_valid() routine, which should be
186             overridden to hook in your own authentication system.
187              
188             =cut
189              
190             sub login {
191 0     0 1   my $self = shift;
192              
193 0           pop; # Last parameter is the SOAP envelope - we ignore it
194 0           my ($username, $password) = @_;
195              
196             # Check credentials
197 0 0         if (! $self->is_valid($username, $password)) {
198 0           return undef;
199             } else {
200 0           return $makeAuthInfo->($username, $self->ticket_duration());
201             }
202             }
203              
204              
205             1;
206             __END__