mirror of https://github.com/jacekkow/uphpCAS

Jacek Kowalski
2015-08-17 2092d32d71d7e65111c7ae08ba95b4145631a10e
commit | author | age
64d82d 1 <?php
JK 2 // Thrown when internal error occurs
3 class JasigException extends Exception {}
4 // Thrown when CAS server return authentication error
5 class JasigAuthException extends JasigException {}
6
7 class JasigUser {
8     public $user;
9     public $attributes = array();
10 }
11
12 class uphpCAS {
13     const VERSION = '1.0';
14     protected $serverUrl = '';
15     protected $serviceUrl;
16     
17     function __construct($serverUrl = NULL, $serviceUrl = NULL) {
18         if($serverUrl != NULL) {
19             $this->serverUrl = rtrim($serverUrl, '/');
20         }
21         
22         if($serviceUrl != NULL) {
23             $this->serviceUrl = $serviceUrl;
24         } else {
25             $url = 'http://';
26             $port = 0;
27             if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
28                 $url = 'https://';
29                 if(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != '443') {
30                     $port = $_SERVER['SERVER_PORT'];
31                 }
32             } elseif(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != '80') {
33                 $port = $_SERVER['SERVER_PORT'];
34             }
35             
36             $url .= $_SERVER['SERVER_NAME'];
37             
38             if($port != 0) {
39                 $url .= ':'.$port;
40             }
41             $url .= $_SERVER['REQUEST_URI'];
42             
43             $this->serviceUrl = $url;
44         }
45     }
46     
47     public function setServerUrl($serverUrl) {
48         $this->serverUrl = $serverUrl;
49     }
50     
51     public function setServiceUrl($serviceUrl) {
52         $this->serviceUrl = $serviceUrl;
53     }
54     
55     public function loginUrl() {
2092d3 56         return $this->serverUrl.'/login?method=POST&service='.urlencode($this->serviceUrl);
64d82d 57     }
JK 58     
59     public function logoutUrl() {
60         return $this->serverUrl.'/logout';
61     }
62     
63     public function logout() {
64         session_start();
65         if(isset($_SESSION['uphpCAS-user'])) {
66             unset($_SESSION['uphpCAS-user']);
67         }
68         header('Location: '.$this->logoutUrl());
69         die();
70     }
71     
72     public function authenticate() {
73         session_start();
74         if(isset($_SESSION['uphpCAS-user'])) {
75             return $_SESSION['uphpCAS-user'];
2092d3 76         } elseif(isset($_REQUEST['ticket'])) {
JK 77             $user = $this->verifyTicket($_REQUEST['ticket']);
64d82d 78             $_SESSION['uphpCAS-user'] = $user;
JK 79             return $user;
80         } else {
81             header('Location: '.$this->loginUrl());
82             die();
83         }
84     }
85     
86     public function verifyTicket($ticket) {
87         $context = array(
88             'http' => array(
89                 'method' => 'GET',
90                 'user_agent' => 'uphpCAS/'.self::VERSION,
91                 'max_redirects' => 3,
92             ),
93             'ssl' => array(
94                 'verify_peer' => TRUE,
95                 'allow_self_signed' => FALSE,
96                 'verify_depth' => 5,
97                 'ciphers' => 'HIGH:-MD5:-aNULL:-DES',
98             ),
99         );
100         
101         $data = file_get_contents($this->serverUrl.'/serviceValidate?service='.urlencode($this->serviceUrl).'&ticket='.urlencode($ticket),
102                 FALSE, stream_context_create($context));
103         if($data === FALSE) {
104             throw new JasigException('Authentication error: CAS server is unavailable');
105         }
106         
107         $xmlEntityLoader = libxml_disable_entity_loader(TRUE);
108         $xmlInternalErrors = libxml_use_internal_errors(TRUE);
109         try {
110             $xml = new DOMDocument();
111             $xml->loadXML($data);
112             
113             foreach(libxml_get_errors() as $error) {
114                 $e = new ErrorException($error->message, $error->code, 1, $error->file, $error->line);
115                 switch ($error->level) {
116                     case LIBXML_ERR_ERROR:
117                         throw new Exception('Fatal error during XML parsing', 0, $e);
118                         break;
119                     case LIBXML_ERR_FATAL:
120                         throw new Exception('Fatal error during XML parsing', 0, $e);
121                         break;
122                 }
123             }
124         }
125         catch(Exception $e) {
126             throw new JasigException('Authentication error: CAS server response invalid - parse error', 0, $e);
127         } finally {
128             libxml_clear_errors();
129             libxml_disable_entity_loader($xmlEntityLoader);
130             libxml_use_internal_errors($xmlInternalErrors);
131         }
132         
133         $failure = $xml->getElementsByTagName('authenticationFailure');
134         $success = $xml->getElementsByTagName('authenticationSuccess');
135         
136         if($failure->length > 0) {
137             $failure = $failure->item(0);
138             if(!($failure instanceof DOMElement)) {
139                 throw new JasigException('Authentication error: CAS server response invalid - authenticationFailure');
140             }
141             throw new JasigAuthException('Authentication error: '.$failure->textContent);
142         } elseif($success->length > 0) {
143             $success = $success->item(0);
144             if(!($success instanceof DOMElement)) {
145                 throw new JasigException('Authentication error: CAS server response invalid - authenticationSuccess');
146             }
147             
148             $user = $success->getElementsByTagName('user');
149             if($user->length == 0) {
150                 throw new JasigException('Authentication error: CAS server response invalid - user');
151             }
152             
153             $user = trim($user->item(0)->textContent);
154             if(strlen($user)<1) {
155                 throw new JasigException('Authentication error: CAS server response invalid - user value');
156             }
157             
158             $jusr = new JasigUser();
159             $jusr->user = $user;
160             
161             $attrs = $success->getElementsByTagName('attributes');
162             if($attrs->length > 0) {
163                 $attrs = $attrs->item(0);
164                 foreach($attrs->childNodes as $node) {
165                     $jusr->attributes[$node->localName] = $node->textContent;
166                 }
167             }
168             
169             return $jusr;
170         }
171         else
172         {
173             throw new JasigException('Authentication error: CAS server response invalid - required tag not found');
174         }
175     }
176 }