| Filename | /usr/share/perl5/Authen/CAS/Client.pm |
| Statements | Executed 24 statements in 3.85ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1.56ms | 3.12ms | Authen::CAS::Client::BEGIN@8 |
| 1 | 1 | 1 | 1.23ms | 1.27ms | Authen::CAS::Client::BEGIN@11 |
| 1 | 1 | 1 | 210µs | 210µs | Authen::CAS::Client::BEGIN@10 |
| 1 | 1 | 1 | 26µs | 529µs | Authen::CAS::Client::BEGIN@12 |
| 1 | 1 | 1 | 25µs | 50µs | Authen::CAS::Client::BEGIN@6 |
| 1 | 1 | 1 | 24µs | 24µs | Authen::CAS::Client::BEGIN@9 |
| 1 | 1 | 1 | 18µs | 22µs | Authen::CAS::Client::BEGIN@5 |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::_error |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::_parse_auth_response |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::_parse_proxy_response |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::_server_request |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::_url |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::_v20_validate |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::login_url |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::logout_url |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::new |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::proxy |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::proxy_validate |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::service_validate |
| 0 | 0 | 0 | 0s | 0s | Authen::CAS::Client::validate |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Authen::CAS::Client; | ||||
| 2 | |||||
| 3 | 1 | 39µs | require 5.006_001; | ||
| 4 | |||||
| 5 | 3 | 28µs | 2 | 26µs | # spent 22µs (18+4) within Authen::CAS::Client::BEGIN@5 which was called:
# once (18µs+4µs) by C4::Auth_with_cas::BEGIN@26 at line 5 # spent 22µs making 1 call to Authen::CAS::Client::BEGIN@5
# spent 4µs making 1 call to strict::import |
| 6 | 3 | 57µs | 2 | 74µs | # spent 50µs (25+25) within Authen::CAS::Client::BEGIN@6 which was called:
# once (25µs+25µs) by C4::Auth_with_cas::BEGIN@26 at line 6 # spent 50µs making 1 call to Authen::CAS::Client::BEGIN@6
# spent 25µs making 1 call to warnings::import |
| 7 | |||||
| 8 | 3 | 195µs | 1 | 3.12ms | # spent 3.12ms (1.56+1.55) within Authen::CAS::Client::BEGIN@8 which was called:
# once (1.56ms+1.55ms) by C4::Auth_with_cas::BEGIN@26 at line 8 # spent 3.12ms making 1 call to Authen::CAS::Client::BEGIN@8 |
| 9 | 3 | 259µs | 1 | 24µs | # spent 24µs within Authen::CAS::Client::BEGIN@9 which was called:
# once (24µs+0s) by C4::Auth_with_cas::BEGIN@26 at line 9 # spent 24µs making 1 call to Authen::CAS::Client::BEGIN@9 |
| 10 | 3 | 66µs | 1 | 210µs | # spent 210µs within Authen::CAS::Client::BEGIN@10 which was called:
# once (210µs+0s) by C4::Auth_with_cas::BEGIN@26 at line 10 # spent 210µs making 1 call to Authen::CAS::Client::BEGIN@10 |
| 11 | 3 | 228µs | 1 | 1.27ms | # spent 1.27ms (1.23+41µs) within Authen::CAS::Client::BEGIN@11 which was called:
# once (1.23ms+41µs) by C4::Auth_with_cas::BEGIN@26 at line 11 # spent 1.27ms making 1 call to Authen::CAS::Client::BEGIN@11 |
| 12 | 3 | 2.97ms | 2 | 1.03ms | # spent 529µs (26+502) within Authen::CAS::Client::BEGIN@12 which was called:
# once (26µs+502µs) by C4::Auth_with_cas::BEGIN@26 at line 12 # spent 529µs making 1 call to Authen::CAS::Client::BEGIN@12
# spent 502µs making 1 call to XML::LibXML::import |
| 13 | |||||
| 14 | 1 | 2µs | our $VERSION = '0.05'; | ||
| 15 | |||||
| 16 | |||||
| 17 | #====================================================================== | ||||
| 18 | # constructor | ||||
| 19 | # | ||||
| 20 | |||||
| 21 | sub new { | ||||
| 22 | my ( $class, $cas, %args ) = @_; | ||||
| 23 | |||||
| 24 | my $self = { | ||||
| 25 | _cas => URI->new( $cas ), | ||||
| 26 | _ua => LWP::UserAgent->new( agent => "Authen-CAS-Client/$VERSION" ), | ||||
| 27 | _fatal => $args{fatal} ? 1 : 0, | ||||
| 28 | }; | ||||
| 29 | |||||
| 30 | bless $self, $class; | ||||
| 31 | } | ||||
| 32 | |||||
| 33 | |||||
| 34 | #====================================================================== | ||||
| 35 | # private methods | ||||
| 36 | # | ||||
| 37 | |||||
| 38 | sub _error { | ||||
| 39 | my ( $self, $error, $doc ) = @_; | ||||
| 40 | |||||
| 41 | die $error | ||||
| 42 | if $self->{_fatal}; | ||||
| 43 | |||||
| 44 | Authen::CAS::Client::Response::Error->new( error => $error, doc => $doc ); | ||||
| 45 | } | ||||
| 46 | |||||
| 47 | sub _parse_auth_response { | ||||
| 48 | my ( $self, $xml ) = @_; | ||||
| 49 | |||||
| 50 | my $doc = eval { XML::LibXML->new->parse_string( $xml ) }; | ||||
| 51 | return $self->_error( 'Failed to parse XML', $xml ) | ||||
| 52 | if $@; | ||||
| 53 | |||||
| 54 | my ( $node, $response ); | ||||
| 55 | |||||
| 56 | eval { | ||||
| 57 | if( $node = $doc->find( '/cas:serviceResponse/cas:authenticationSuccess' )->get_node( 1 ) ) { | ||||
| 58 | $response = eval { | ||||
| 59 | my $user = $node->find( './cas:user' )->get_node( 1 )->textContent; | ||||
| 60 | |||||
| 61 | my $iou = $node->find( './cas:proxyGrantingTicket' )->get_node( 1 ); | ||||
| 62 | $iou = $iou->textContent | ||||
| 63 | if( defined $iou ); | ||||
| 64 | |||||
| 65 | my $proxies = $node->findnodes( './cas:proxies/cas:proxy' ); | ||||
| 66 | $proxies = [ map $_->textContent, @$proxies ] | ||||
| 67 | if defined @$proxies; | ||||
| 68 | |||||
| 69 | Authen::CAS::Client::Response::AuthSuccess->new( | ||||
| 70 | user => $user, | ||||
| 71 | iou => $iou, | ||||
| 72 | proxies => $proxies, | ||||
| 73 | doc => $doc, | ||||
| 74 | ); | ||||
| 75 | }; | ||||
| 76 | |||||
| 77 | $response = $self->_error( 'Failed to parse authentication success response', $doc ) | ||||
| 78 | if $@; | ||||
| 79 | } | ||||
| 80 | elsif( $node = $doc->find( '/cas:serviceResponse/cas:authenticationFailure' )->get_node( 1 ) ) { | ||||
| 81 | $response = eval { | ||||
| 82 | die | ||||
| 83 | unless $node->hasAttribute( 'code' ); | ||||
| 84 | my $code = $node->getAttribute( 'code' ); | ||||
| 85 | |||||
| 86 | my $message = $node->textContent; | ||||
| 87 | s/^\s+//, s/\s+\z// | ||||
| 88 | for $message; | ||||
| 89 | |||||
| 90 | Authen::CAS::Client::Response::AuthFailure->new( | ||||
| 91 | code => $code, | ||||
| 92 | message => $message, | ||||
| 93 | doc => $doc, | ||||
| 94 | ); | ||||
| 95 | }; | ||||
| 96 | |||||
| 97 | $response = $self->_error( 'Failed to parse authentication failure response', $doc ) | ||||
| 98 | if $@; | ||||
| 99 | } | ||||
| 100 | else { | ||||
| 101 | die; | ||||
| 102 | } | ||||
| 103 | }; | ||||
| 104 | |||||
| 105 | $response = $self->_error( 'Invalid CAS response', $doc ) | ||||
| 106 | if $@; | ||||
| 107 | |||||
| 108 | return $response; | ||||
| 109 | } | ||||
| 110 | |||||
| 111 | sub _parse_proxy_response { | ||||
| 112 | my ( $self, $xml ) = @_; | ||||
| 113 | |||||
| 114 | my $doc = eval { XML::LibXML->new->parse_string( $xml ) }; | ||||
| 115 | return $self->_error( 'Failed to parse XML', $xml ) | ||||
| 116 | if $@; | ||||
| 117 | |||||
| 118 | my ( $node, $response ); | ||||
| 119 | |||||
| 120 | eval { | ||||
| 121 | if( $node = $doc->find( '/cas:serviceResponse/cas:proxySuccess' )->get_node( 1 ) ) { | ||||
| 122 | $response = eval { | ||||
| 123 | my $proxy_ticket = $node->find( './cas:proxyTicket' )->get_node( 1 )->textContent; | ||||
| 124 | |||||
| 125 | Authen::CAS::Client::Response::ProxySuccess->new( | ||||
| 126 | proxy_ticket => $proxy_ticket, | ||||
| 127 | doc => $doc, | ||||
| 128 | ); | ||||
| 129 | }; | ||||
| 130 | $response = $self->_error( 'Failed to parse proxy success response', $doc ) | ||||
| 131 | if $@; | ||||
| 132 | } | ||||
| 133 | elsif( $node = $doc->find( '/cas:serviceResponse/cas:proxyFailure' )->get_node( 1 ) ) { | ||||
| 134 | $response = eval { | ||||
| 135 | die | ||||
| 136 | unless $node->hasAttribute( 'code' ); | ||||
| 137 | my $code = $node->getAttribute( 'code' ); | ||||
| 138 | |||||
| 139 | my $message = $node->textContent; | ||||
| 140 | s/^\s+//, s/\s+\z// | ||||
| 141 | for $message; | ||||
| 142 | |||||
| 143 | Authen::CAS::Client::Response::ProxyFailure->new( | ||||
| 144 | code => $code, | ||||
| 145 | message => $message, | ||||
| 146 | doc => $doc, | ||||
| 147 | ); | ||||
| 148 | }; | ||||
| 149 | $response = $self->_error( 'Failed to parse proxy failure response', $doc ) | ||||
| 150 | if $@; | ||||
| 151 | } | ||||
| 152 | else { | ||||
| 153 | die; | ||||
| 154 | } | ||||
| 155 | }; | ||||
| 156 | |||||
| 157 | $response = $self->_error( 'Invalid CAS response', $doc ) | ||||
| 158 | if $@; | ||||
| 159 | |||||
| 160 | return $response; | ||||
| 161 | } | ||||
| 162 | |||||
| 163 | sub _server_request { | ||||
| 164 | my ( $self, $path, $params ) = @_; | ||||
| 165 | |||||
| 166 | my $url = $self->_url( $path, $params )->canonical; | ||||
| 167 | my $response = $self->{_ua}->get( $url ); | ||||
| 168 | |||||
| 169 | unless( $response->is_success ) { | ||||
| 170 | return $self->_error( | ||||
| 171 | 'HTTP request failed: ' . $response->code . ': ' . $response->message, | ||||
| 172 | $response->content | ||||
| 173 | ); | ||||
| 174 | } | ||||
| 175 | |||||
| 176 | return $response->content; | ||||
| 177 | } | ||||
| 178 | |||||
| 179 | sub _url { | ||||
| 180 | my ( $self, $path, $params ) = @_; | ||||
| 181 | |||||
| 182 | my $url = $self->{_cas}->clone; | ||||
| 183 | |||||
| 184 | $url->path( $url->path . $path ); | ||||
| 185 | $url->query_param_append( $_ => $params->{$_} ) | ||||
| 186 | for keys %$params; | ||||
| 187 | |||||
| 188 | return $url; | ||||
| 189 | } | ||||
| 190 | |||||
| 191 | sub _v20_validate { | ||||
| 192 | my ( $self, $path, $service, $ticket, %args ) = @_; | ||||
| 193 | |||||
| 194 | my %params = ( service => $service, ticket => $ticket ); | ||||
| 195 | |||||
| 196 | $params{renew} = 'true' | ||||
| 197 | if $args{renew}; | ||||
| 198 | $params{pgtUrl} = URI->new( $args{pgtUrl} )->canonical | ||||
| 199 | if defined $args{pgtUrl}; | ||||
| 200 | |||||
| 201 | my $content = $self->_server_request( $path, \%params ); | ||||
| 202 | return $content | ||||
| 203 | if ref $content; | ||||
| 204 | |||||
| 205 | return $self->_parse_auth_response( $content ); | ||||
| 206 | } | ||||
| 207 | |||||
| 208 | |||||
| 209 | #====================================================================== | ||||
| 210 | # public methods | ||||
| 211 | # | ||||
| 212 | |||||
| 213 | sub login_url { | ||||
| 214 | my ( $self, $service, %args ) = @_; | ||||
| 215 | |||||
| 216 | my %params = ( service => $service ); | ||||
| 217 | |||||
| 218 | for ( qw/ renew gateway / ) { | ||||
| 219 | $params{$_} = 'true', last | ||||
| 220 | if $args{$_}; | ||||
| 221 | } | ||||
| 222 | |||||
| 223 | return $self->_url( '/login', \%params )->canonical; | ||||
| 224 | } | ||||
| 225 | |||||
| 226 | sub logout_url { | ||||
| 227 | my ( $self, %args ) = @_; | ||||
| 228 | |||||
| 229 | my %params; | ||||
| 230 | |||||
| 231 | $params{url} = $args{url} | ||||
| 232 | if defined $args{url}; | ||||
| 233 | |||||
| 234 | return $self->_url( '/logout', \%params )->canonical; | ||||
| 235 | } | ||||
| 236 | |||||
| 237 | sub validate { | ||||
| 238 | my ( $self, $service, $ticket, %args ) = @_; | ||||
| 239 | |||||
| 240 | my %params = ( service => $service, ticket => $ticket ); | ||||
| 241 | |||||
| 242 | $params{renew} = 'true' | ||||
| 243 | if $args{renew}; | ||||
| 244 | |||||
| 245 | my $content = $self->_server_request( '/validate', \%params ); | ||||
| 246 | return $content | ||||
| 247 | if ref $content; | ||||
| 248 | |||||
| 249 | my $response; | ||||
| 250 | |||||
| 251 | if( $content =~ /^no\n\n\z/ ) { | ||||
| 252 | $response = Authen::CAS::Client::Response::AuthFailure->new( code => 'V10_AUTH_FAILURE', doc => $content ); | ||||
| 253 | } | ||||
| 254 | elsif( $content =~ /^yes\n([^\n]+)\n\z/ ) { | ||||
| 255 | $response = Authen::CAS::Client::Response::AuthSuccess->new( user => $1, doc => $content ); | ||||
| 256 | } | ||||
| 257 | else { | ||||
| 258 | $response = $self->_error( 'Invalid CAS response', $content ); | ||||
| 259 | } | ||||
| 260 | |||||
| 261 | return $response; | ||||
| 262 | } | ||||
| 263 | |||||
| 264 | sub service_validate { | ||||
| 265 | my ( $self, $service, $ticket, %args ) = @_; | ||||
| 266 | return $self->_v20_validate( '/serviceValidate', $service, $ticket, %args ); | ||||
| 267 | } | ||||
| 268 | |||||
| 269 | sub proxy_validate { | ||||
| 270 | my ( $self, $service, $ticket, %args ) = @_; | ||||
| 271 | return $self->_v20_validate( '/proxyValidate', $service, $ticket, %args ); | ||||
| 272 | } | ||||
| 273 | |||||
| 274 | sub proxy { | ||||
| 275 | my ( $self, $pgt, $target ) = @_; | ||||
| 276 | |||||
| 277 | my %params = ( pgt => $pgt, targetService => URI->new( $target ) ); | ||||
| 278 | |||||
| 279 | my $content = $self->_server_request( '/proxy', \%params ); | ||||
| 280 | return $content | ||||
| 281 | if ref $content; | ||||
| 282 | |||||
| 283 | return $self->_parse_proxy_response( $content ); | ||||
| 284 | } | ||||
| 285 | |||||
| 286 | |||||
| 287 | 1 | 6µs | 1 | ||
| 288 | __END__ |