File Coverage

blib/lib/Lemonldap/NG/Portal/IssuerDBCAS.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             ## @file
2             # CAS Issuer file
3              
4             ## @class
5             # CAS Issuer class
6             package Lemonldap::NG::Portal::IssuerDBCAS;
7              
8 1     1   14509 use strict;
  1         2  
  1         43  
9 1     1   814 use Lemonldap::NG::Portal::Simple;
  0            
  0            
10             use Lemonldap::NG::Portal::_CAS;
11             use base qw(Lemonldap::NG::Portal::_CAS Lemonldap::NG::Portal::_LibAccess);
12              
13             our $VERSION = '1.4.2';
14              
15             ## @method void issuerDBInit()
16             # Nothing to do
17             # @return Lemonldap::NG::Portal error code
18             sub issuerDBInit {
19             my $self = shift;
20              
21             return PE_OK;
22             }
23              
24             ## @apmethod int issuerForUnAuthUser()
25             # Manage CAS request for unauthenticated user
26             # @return Lemonldap::NG::Portal error code
27             sub issuerForUnAuthUser {
28             my $self = shift;
29              
30             # CAS URLs
31             my $issuerDBCASPath = $self->{issuerDBCASPath};
32             my $cas_login = 'login';
33             my $cas_logout = 'logout';
34             my $cas_validate = 'validate';
35             my $cas_serviceValidate = 'serviceValidate';
36             my $cas_proxyValidate = 'proxyValidate';
37             my $cas_proxy = 'proxy';
38              
39             # Called URL
40             my $url = $self->url();
41             my $url_path = $self->url( -absolute => 1 );
42             $url_path =~ s#^//#/#;
43              
44             # 1. LOGIN
45             if ( $url_path =~ m#${issuerDBCASPath}${cas_login}# ) {
46              
47             $self->lmLog( "URL $url detected as an CAS LOGIN URL", 'debug' );
48              
49             # GET parameters
50             my $service = $self->getHiddenFormValue('service')
51             || $self->param('service');
52             my $renew = $self->getHiddenFormValue('renew') || $self->param('renew');
53             my $gateway = $self->getHiddenFormValue('gateway')
54             || $self->param('gateway');
55              
56             # Keep values in hidden fields
57             $self->setHiddenFormValue( 'service', $service );
58             $self->setHiddenFormValue( 'renew', $renew );
59             $self->setHiddenFormValue( 'gateway', $gateway );
60              
61             # Gateway
62             if ( $gateway eq 'true' ) {
63              
64             # User should already be authenticated
65             $self->lmLog(
66             "Gateway authentication requested, but user is not logged in",
67             'error' );
68              
69             # Redirect user to the service
70             $self->lmLog( "Redirect user to $service", 'debug' );
71              
72             $self->{urldc} = $service;
73              
74             return $self->_subProcess(qw(autoRedirect));
75              
76             }
77              
78             }
79              
80             # 2. LOGOUT
81             if ( $url_path =~ m#${issuerDBCASPath}${cas_logout}# ) {
82              
83             $self->lmLog( "URL $url detected as an CAS LOGOUT URL", 'debug' );
84              
85             # GET parameters
86             my $logout_url = $self->param('url');
87              
88             if ($logout_url) {
89              
90             # Display a link to the provided URL
91             $self->lmLog( "Logout URL $logout_url will be displayed", 'debug' );
92              
93             $self->info( "<h3>" . $self->msg(PM_BACKTOCASURL) . "</h3>" );
94             $self->info("<p><a href=\"$logout_url\">$logout_url</a></p>");
95             $self->{activeTimer} = 0;
96              
97             return PE_CONFIRM;
98             }
99              
100             return PE_LOGOUT_OK;
101              
102             }
103              
104             # 3. VALIDATE [CAS 1.0]
105             if ( $url_path =~ m#${issuerDBCASPath}${cas_validate}# ) {
106              
107             $self->lmLog( "URL $url detected as an CAS VALIDATE URL", 'debug' );
108              
109             # GET parameters
110             my $service = $self->param('service');
111             my $ticket = $self->param('ticket');
112             my $renew = $self->param('renew');
113              
114             # Required parameters: service and ticket
115             unless ( $service and $ticket ) {
116             $self->lmLog( "Service and Ticket parameters required", 'error' );
117             $self->returnCasValidateError();
118             }
119              
120             $self->lmLog(
121             "Get validate request with ticket $ticket for service $service",
122             'debug' );
123              
124             unless ( $ticket =~ s/^ST-// ) {
125             $self->lmLog( "Provided ticket is not a service ticket (ST)",
126             'error' );
127             $self->returnCasValidateError();
128             }
129              
130             my $casServiceSession = $self->getCasSession($ticket);
131              
132             unless ($casServiceSession) {
133             $self->lmLog( "Service ticket session $ticket not found", 'error' );
134             $self->returnCasValidateError();
135             }
136              
137             $self->lmLog( "Service ticket session $ticket found", 'debug' );
138              
139             # Check service
140             unless ( $service eq $casServiceSession->data->{service} ) {
141             $self->lmLog(
142             "Submitted service $service does not match initial service "
143             . $casServiceSession->data->{service},
144             'error'
145             );
146             $self->returnCasValidateError();
147             }
148              
149             $self->lmLog( "Submitted service $service math initial servce",
150             'debug' );
151              
152             # Check renew
153             if ( $renew eq 'true' ) {
154              
155             # We should check the ST was delivered with primary credentials
156             $self->lmLog( "Renew flag detected ", 'debug' );
157              
158             unless ( $casServiceSession->data->{renew} ) {
159             $self->lmLog(
160             "Authentication renew requested, but not done in former authentication process",
161             'error'
162             );
163             $self->returnCasValidateError();
164             }
165             }
166              
167             # Open local session
168             my $localSession =
169             $self->getApacheSession( $casServiceSession->data->{_cas_id}, 1 );
170              
171             unless ($localSession) {
172             $self->lmLog(
173             "Local session "
174             . $casServiceSession->data->{_cas_id}
175             . " notfound",
176             'error'
177             );
178             $self->returnCasValidateError();
179             }
180              
181             # Get username
182             my $username =
183             $localSession->data->{ $self->{casAttr} || $self->{whatToTrace} };
184              
185             $self->lmLog( "Get username $username", 'debug' );
186              
187             # Return success message
188             $self->returnCasValidateSuccess($username);
189              
190             # We should not be there
191             return PE_ERROR;
192             }
193              
194             # 4. SERVICE VALIDATE [CAS 2.0]
195             # 5. PROXY VALIDATE [CAS 2.0]
196             if ( ( $url_path =~ m#${issuerDBCASPath}${cas_serviceValidate}# )
197             || ( $url_path =~ m#${issuerDBCASPath}${cas_proxyValidate}# ) )
198             {
199              
200             my $urlType = (
201             $url_path =~ m#${issuerDBCASPath}${cas_serviceValidate}#
202             ? 'SERVICE'
203             : 'PROXY'
204             );
205              
206             $self->lmLog( "URL $url detected as an CAS $urlType VALIDATE URL",
207             'debug' );
208              
209             # GET parameters
210             my $service = $self->param('service');
211             my $ticket = $self->param('ticket');
212             my $pgtUrl = $self->param('pgtUrl');
213             my $renew = $self->param('renew');
214              
215             # PGTIOU
216             my $casProxyGrantingTicketIOU;
217              
218             # Required parameters: service and ticket
219             unless ( $service and $ticket ) {
220             $self->lmLog( "Service and Ticket parameters required", 'error' );
221             $self->returnCasServiceValidateError( 'INVALID_REQUEST',
222             'Missing mandatory parameters (service, ticket)' );
223             }
224              
225             $self->lmLog(
226             "Get "
227             . lc($urlType)
228             . " validate request with ticket $ticket for service $service",
229             'debug'
230             );
231              
232             # Get CAS session corresponding to ticket
233             if ( $urlType eq 'SERVICE' and !( $ticket =~ s/^ST-// ) ) {
234             $self->lmLog( "Provided ticket is not a service ticket (ST)",
235             'error' );
236             $self->returnCasServiceValidateError( 'INVALID_TICKET',
237             'Provided ticket is not a service ticket' );
238             }
239             elsif ( $urlType eq 'PROXY' and !( $ticket =~ s/^(P|S)T-// ) ) {
240             $self->lmLog(
241             "Provided ticket is not a service or proxy ticket ($1T)",
242             'error' );
243             $self->returnCasServiceValidateError( 'INVALID_TICKET',
244             'Provided ticket is not a service or proxy ticket' );
245             }
246              
247             my $casServiceSession = $self->getCasSession($ticket);
248              
249             unless ($casServiceSession) {
250             $self->lmLog( "$urlType ticket session $ticket not found",
251             'error' );
252             $self->returnCasServiceValidateError( 'INVALID_TICKET',
253             'Ticket not found' );
254             }
255              
256             $self->lmLog( "$urlType ticket session $ticket found", 'debug' );
257              
258             # Check service
259             unless ( $service eq $casServiceSession->data->{service} ) {
260             $self->lmLog(
261             "Submitted service $service does not match initial service "
262             . $casServiceSession->data->{service},
263             'error'
264             );
265              
266             # CAS protocol: invalidate ticket if service is invalid
267             $self->deleteCasSession($casServiceSession);
268              
269             $self->returnCasServiceValidateError( 'INVALID_SERVICE',
270             'Submitted service does not match initial service' );
271             }
272              
273             $self->lmLog( "Submitted service $service match initial servce",
274             'debug' );
275              
276             # Check renew
277             if ( $renew eq 'true' ) {
278              
279             # We should check the ST was delivered with primary credentials
280             $self->lmLog( "Renew flag detected ", 'debug' );
281              
282             unless ( $casServiceSession->data->{renew} ) {
283             $self->lmLog(
284             "Authentication renew requested, but not done in former authentication process",
285             'error'
286             );
287             $self->returnCasValidateError();
288             }
289              
290             }
291              
292             # Proxies (for PROXY VALIDATE only)
293             my $proxies = $casServiceSession->data->{proxies};
294              
295             # Proxy granting ticket
296             if ($pgtUrl) {
297              
298             # Create a proxy granting ticket
299             $self->lmLog(
300             "Create a CAS proxy granting ticket for service $service",
301             'debug' );
302              
303             my $casProxyGrantingSession = $self->getCasSession();
304              
305             if ($casProxyGrantingSession) {
306              
307             my $PGinfos;
308              
309             # PGT session
310             $PGinfos->{type} = 'casProxyGranting';
311             $PGinfos->{service} = $service;
312             $PGinfos->{_cas_id} = $casServiceSession->data->{_cas_id};
313             $PGinfos->{_utime} = $casServiceSession->data->{_utime};
314              
315             # Trace proxies
316             $PGinfos->{proxies} = (
317             $proxies
318             ? $proxies . $self->{multiValuesSeparator} . $pgtUrl
319             : $pgtUrl
320             );
321              
322             my $casProxyGrantingSessionID = $casProxyGrantingSession->id;
323             my $casProxyGrantingTicket =
324             "PGT-" . $casProxyGrantingSessionID;
325              
326             $casProxyGrantingSession->update($PGinfos);
327              
328             $self->lmLog(
329             "CAS proxy granting session $casProxyGrantingSessionID created",
330             'debug'
331             );
332              
333             # Generate the proxy granting ticket IOU
334             my $tmpCasSession = $self->getCasSession();
335              
336             if ($tmpCasSession) {
337              
338             $casProxyGrantingTicketIOU = "PGTIOU-" . $tmpCasSession->id;
339             $self->deleteCasSession($tmpCasSession);
340             $self->lmLog(
341             "Generate proxy granting ticket IOU $casProxyGrantingTicketIOU",
342             'debug'
343             );
344              
345             # Request pgtUrl
346             if (
347             $self->callPgtUrl(
348             $pgtUrl,
349             $casProxyGrantingTicketIOU,
350             $casProxyGrantingTicket
351             )
352             )
353             {
354             $self->lmLog(
355             "Proxy granting URL $pgtUrl called with success",
356             'debug' );
357             }
358             else {
359             $self->lmLog(
360             "Error calling proxy granting URL $pgtUrl",
361             'warn' );
362             $casProxyGrantingTicketIOU = undef;
363             }
364             }
365              
366             }
367             else {
368             $self->lmLog(
369             "Error in proxy granting ticket management, bypass it",
370             'warn' );
371             }
372             }
373              
374             # Open local session
375             my $localSession =
376             $self->getApacheSession( $casServiceSession->data->{_cas_id}, 1 );
377              
378             unless ($localSession) {
379             $self->lmLog(
380             "Local session "
381             . $casServiceSession->data->{_cas_id}
382             . " notfound",
383             'error'
384             );
385             $self->returnCasServiceValidateError( 'INTERNAL_ERROR',
386             'No session associated to ticket' );
387             }
388              
389             # Get username
390             my $username =
391             $localSession->data->{ $self->{casAttr} || $self->{whatToTrace} };
392              
393             $self->lmLog( "Get username $username", 'debug' );
394              
395             # Return success message
396             $self->returnCasServiceValidateSuccess( $username,
397             $casProxyGrantingTicketIOU, $proxies );
398              
399             # We should not be there
400             return PE_ERROR;
401             }
402              
403             # 6. PROXY [CAS 2.0]
404             if ( $url_path =~ m#${issuerDBCASPath}${cas_proxy}# ) {
405              
406             $self->lmLog( "URL $url detected as an CAS PROXY URL", 'debug' );
407              
408             # GET parameters
409             my $pgt = $self->param('pgt');
410             my $targetService = $self->param('targetService');
411              
412             # Required parameters: pgt and targetService
413             unless ( $pgt and $targetService ) {
414             $self->lmLog( "Pgt and TargetService parameters required",
415             'error' );
416             $self->returnCasProxyError( 'INVALID_REQUEST',
417             'Missing mandatory parameters (pgt, targetService)' );
418             }
419              
420             $self->lmLog(
421             "Get proxy request with ticket $pgt for service $targetService",
422             'debug' );
423              
424             # Get CAS session corresponding to ticket
425             unless ( $pgt =~ s/^PGT-// ) {
426             $self->lmLog(
427             "Provided ticket is not a proxy granting ticket (PGT)",
428             'error' );
429             $self->returnCasProxyError( 'BAD_PGT',
430             'Provided ticket is not a proxy granting ticket' );
431             }
432              
433             my $casProxyGrantingSession = $self->getCasSession($pgt);
434              
435             unless ($casProxyGrantingSession) {
436             $self->lmLog( "Proxy granting ticket session $pgt not found",
437             'error' );
438             $self->returnCasProxyError( 'BAD_PGT', 'Ticket not found' );
439             }
440              
441             $self->lmLog( "Proxy granting session $pgt found", 'debug' );
442              
443             # Create a proxy ticket
444             $self->lmLog( "Create a CAS proxy ticket for service $targetService",
445             'debug' );
446              
447             my $casProxySession = $self->getCasSession();
448              
449             unless ($casProxySession) {
450             $self->lmLog( "Unable to create CAS proxy session", 'error' );
451             $self->returnCasProxyError( 'INTERNAL_ERROR',
452             'Error in proxy session management' );
453             }
454              
455             my $Pinfos;
456             $Pinfos->{type} = 'casProxy';
457             $Pinfos->{service} = $targetService;
458             $Pinfos->{_cas_id} = $casProxyGrantingSession->data->{_cas_id};
459             $Pinfos->{_utime} = $casProxyGrantingSession->data->{_utime};
460             $Pinfos->{proxies} = $casProxyGrantingSession->data->{proxies};
461              
462             $casProxySession->update($Pinfos);
463              
464             my $casProxySessionID = $casProxySession->id;
465             my $casProxyTicket = "PT-" . $casProxySessionID;
466              
467             $self->lmLog( "CAS proxy session $casProxySessionID created", 'debug' );
468              
469             # Return success message
470             $self->returnCasProxySuccess($casProxyTicket);
471              
472             # We should not be there
473             return PE_ERROR;
474             }
475              
476             return PE_OK;
477             }
478              
479             ## @apmethod int issuerForAuthUser()
480             # Manage CAS request for unauthenticated user
481             # @return Lemonldap::NG::Portal error code
482             sub issuerForAuthUser {
483             my $self = shift;
484              
485             # CAS URLs
486             my $issuerDBCASPath = $self->{issuerDBCASPath};
487             my $cas_login = 'login';
488             my $cas_logout = 'logout';
489             my $cas_validate = 'validate';
490             my $cas_serviceValidate = 'serviceValidate';
491             my $cas_proxyValidate = 'proxyValidate';
492             my $cas_proxy = 'proxy';
493              
494             # Called URL
495             my $url = $self->url();
496             my $url_path = $self->url( -absolute => 1 );
497             $url_path =~ s#^//#/#;
498              
499             # Session ID
500             my $session_id = $self->{sessionInfo}->{_session_id} || $self->{id};
501              
502             # Session creation timestamp
503             my $time = $self->{sessionInfo}->{_utime} || time();
504              
505             # 1. LOGIN
506             if ( $url_path =~ m#${issuerDBCASPath}${cas_login}# ) {
507              
508             $self->lmLog( "URL $url detected as an CAS LOGIN URL", 'debug' );
509              
510             # GET parameters
511             my $service = $self->getHiddenFormValue('service')
512             || $self->param('service');
513             my $renew = $self->getHiddenFormValue('renew') || $self->param('renew');
514             my $gateway = $self->getHiddenFormValue('gateway')
515             || $self->param('gateway');
516             my $casServiceTicket;
517              
518             # Renew
519             if ( $renew eq 'true' ) {
520              
521             # Authentication must be replayed
522             $self->lmLog( "Authentication renew requested", 'debug' );
523             $self->{updateSession} = 1;
524             $self->{error} = $self->_subProcess(
525             qw(issuerDBInit authInit issuerForUnAuthUser extractFormInfo
526             userDBInit getUser setAuthSessionInfo setSessionInfo
527             setMacros setGroups setPersistentSessionInfo
528             setLocalGroups authenticate store authFinish)
529             );
530              
531             # Return error if any
532             if ( $self->{error} > 0 ) {
533             $self->lmLog( "Error in authentication renew process",
534             'error' );
535             return $self->{error};
536             }
537             }
538              
539             # If no service defined, exit
540             unless ( defined $service ) {
541             $self->lmLog( "No service defined in CAS URL", 'debug' );
542             return PE_OK;
543             }
544              
545             # Check access on the service
546             my $casAccessControlPolicy = $self->{casAccessControlPolicy};
547              
548             if ( $casAccessControlPolicy =~ /^(error|faketicket)$/i ) {
549             $self->lmLog( "CAS access control requested on service $service",
550             'debug' );
551              
552             if ( $self->_grant($service) ) {
553             $self->lmLog( "CAS service $service access allowed", 'debug' );
554             }
555              
556             else {
557             $self->lmLog( "CAS service $service access not allowed",
558             'error' );
559              
560             if ( $casAccessControlPolicy =~ /^(error)$/i ) {
561             $self->lmLog(
562             "Return error instead of redirecting user on CAS service",
563             'debug'
564             );
565             return PE_CAS_SERVICE_NOT_ALLOWED;
566             }
567              
568             else {
569             $self->lmLog(
570             "Redirect user on CAS service with a fake ticket",
571             'debug' );
572             $casServiceTicket = "ST-F4K3T1CK3T";
573             }
574             }
575             }
576              
577             unless ($casServiceTicket) {
578              
579             # Check last authentication time to decide if
580             # the authentication is recent or not
581             my $casRenewFlag = 0;
582             my $last_authn_utime = $self->{sessionInfo}->{_lastAuthnUTime} || 0;
583             if (
584             time() - $last_authn_utime < $self->{portalForceAuthnInterval} )
585             {
586             $self->lmLog(
587             "Authentication is recent, will set CAS renew flag to true",
588             'debug'
589             );
590             $casRenewFlag = 1;
591             }
592              
593             # Create a service ticket
594             $self->lmLog( "Create a CAS service ticket for service $service",
595             'debug' );
596              
597             my $casServiceSession = $self->getCasSession();
598              
599             unless ($casServiceSession) {
600             $self->lmLog( "Unable to create CAS session", 'error' );
601             return PE_ERROR;
602             }
603              
604             my $Sinfos;
605             $Sinfos->{type} = 'casService';
606             $Sinfos->{service} = $service;
607             $Sinfos->{renew} = $casRenewFlag;
608             $Sinfos->{_cas_id} = $session_id;
609             $Sinfos->{_utime} = $time;
610              
611             $casServiceSession->update($Sinfos);
612              
613             my $casServiceSessionID = $casServiceSession->id;
614             $casServiceTicket = "ST-" . $casServiceSessionID;
615              
616             $self->lmLog( "CAS service session $casServiceSessionID created",
617             'debug' );
618             }
619              
620             # Redirect to service
621             my $service_url = $service;
622             $service_url .= (
623             $service =~ /\?/
624             ? '&ticket=' . $casServiceTicket
625             : '?ticket=' . $casServiceTicket
626             );
627              
628             $self->lmLog( "Redirect user to $service_url", 'debug' );
629              
630             $self->{urldc} = $service_url;
631              
632             return $self->_subProcess(qw(autoRedirect));
633             }
634              
635             # 2. LOGOUT
636             if ( $url_path =~ m#${issuerDBCASPath}${cas_logout}# ) {
637              
638             $self->lmLog( "URL $url detected as an CAS LOGOUT URL", 'debug' );
639              
640             # GET parameters
641             my $logout_url = $self->param('url');
642              
643             # Delete linked CAS sessions
644             $self->deleteCasSecondarySessions($session_id);
645              
646             # Delete local session
647             unless (
648             $self->_deleteSession( $self->getApacheSession( $session_id, 1 ) ) )
649             {
650             $self->lmLog( "Fail to delete session $session_id ", 'error' );
651             }
652              
653             if ($logout_url) {
654              
655             # Display a link to the provided URL
656             $self->lmLog( "Logout URL $logout_url will be displayed", 'debug' );
657              
658             $self->info( "<h3>" . $self->msg(PM_BACKTOCASURL) . "</h3>" );
659             $self->info("<p><a href=\"$logout_url\">$logout_url</a></p>");
660             $self->{activeTimer} = 0;
661              
662             return PE_CONFIRM;
663             }
664              
665             return PE_LOGOUT_OK;
666              
667             }
668              
669             # 3. VALIDATE [CAS 1.0]
670             if ( $url_path =~ m#${issuerDBCASPath}${cas_validate}# ) {
671              
672             $self->lmLog( "URL $url detected as an CAS VALIDATE URL", 'debug' );
673              
674             # This URL must not be called by authenticated users
675             $self->lmLog(
676             "CAS VALIDATE URL called by authenticated user, ignore it",
677             'info' );
678              
679             return PE_OK;
680             }
681              
682             # 4. SERVICE VALIDATE [CAS 2.0]
683             if ( $url_path =~ m#${issuerDBCASPath}${cas_serviceValidate}# ) {
684              
685             $self->lmLog( "URL $url detected as an CAS SERVICE VALIDATE URL",
686             'debug' );
687              
688             # This URL must not be called by authenticated users
689             $self->lmLog(
690             "CAS SERVICE VALIDATE URL called by authenticated user, ignore it",
691             'info'
692             );
693              
694             return PE_OK;
695             }
696              
697             # 5. PROXY VALIDATE [CAS 2.0]
698             if ( $url_path =~ m#${issuerDBCASPath}${cas_proxyValidate}# ) {
699              
700             $self->lmLog( "URL $url detected as an CAS PROXY VALIDATE URL",
701             'debug' );
702              
703             # This URL must not be called by authenticated users
704             $self->lmLog(
705             "CAS PROXY VALIDATE URL called by authenticated user, ignore it",
706             'info' );
707              
708             return PE_OK;
709             }
710              
711             # 6. PROXY [CAS 2.0]
712             if ( $url_path =~ m#${issuerDBCASPath}${cas_proxy}# ) {
713              
714             $self->lmLog( "URL $url detected as an CAS PROXY URL", 'debug' );
715              
716             # This URL must not be called by authenticated users
717             $self->lmLog( "CAS PROXY URL called by authenticated user, ignore it",
718             'info' );
719              
720             return PE_OK;
721             }
722              
723             return PE_OK;
724             }
725              
726             ## @apmethod int issuerLogout()
727             # Destroy linked CAS sessions
728             # @return Lemonldap::NG::Portal error code
729             sub issuerLogout {
730             my $self = shift;
731              
732             # Session ID
733             my $session_id = $self->{sessionInfo}->{_session_id} || $self->{id};
734              
735             # Delete linked CAS sessions
736             $self->deleteCasSecondarySessions($session_id);
737              
738             return PE_OK;
739             }
740              
741             1;
742              
743             __END__
744              
745             =head1 NAME
746              
747             =encoding utf8
748              
749             Lemonldap::NG::Portal::IssuerDBCAS - CAS IssuerDB for LemonLDAP::NG
750              
751             =head1 DESCRIPTION
752              
753             CAS Issuer implementation in LemonLDAP::NG
754              
755             =head1 SEE ALSO
756              
757             L<Lemonldap::NG::Portal>,
758             L<http://www.jasig.org/cas/protocol>
759              
760             =head1 AUTHOR
761              
762             =over
763              
764             =item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
765              
766             =item François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
767              
768             =item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
769              
770             =back
771              
772             =head1 BUG REPORT
773              
774             Use OW2 system to report bug or ask for features:
775             L<http://jira.ow2.org>
776              
777             =head1 DOWNLOAD
778              
779             Lemonldap::NG is available at
780             L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
781              
782             =head1 COPYRIGHT AND LICENSE
783              
784             =over
785              
786             =item Copyright (C) 2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
787              
788             =item Copyright (C) 2012 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
789              
790             =item Copyright (C) 2010, 2011, 2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
791              
792             =back
793              
794             This library is free software; you can redistribute it and/or modify
795             it under the terms of the GNU General Public License as published by
796             the Free Software Foundation; either version 2, or (at your option)
797             any later version.
798              
799             This program is distributed in the hope that it will be useful,
800             but WITHOUT ANY WARRANTY; without even the implied warranty of
801             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
802             GNU General Public License for more details.
803              
804             You should have received a copy of the GNU General Public License
805             along with this program. If not, see L<http://www.gnu.org/licenses/>.
806              
807             =cut