v. 0.6.3 from http://dev.piwik.org/trac/ticket/598
[piwik-CASLogin.git] / Auth.php
1 <?php
2 /**
3  * Piwik - Open source web analytics
4  * 
5  * @link http://piwik.org
6  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
7  * @version $Id:$
8  * 
9  * @package Piwik_CASLogin
10  */
11
12 /**
13  * Class that implements an authentication mechanism via CAS (Central Authentication Services)
14  *
15  * @package Piwik_CASLogin
16  */
17 class Piwik_CASLogin_Auth implements Piwik_Auth
18 {
19         protected $login = null;
20         protected $token_auth = null;
21
22         public function getName()
23         {
24                 return 'CASLogin';
25         }
26
27         public function authenticate()
28         {
29                 $user = '';
30                 $rootLogin = Zend_Registry::get('config')->superuser->login;
31
32                 $additionalSuperUsers = array();
33                 $oAdditionalSuperUsers = Zend_Registry::get('config')->caslogin->additionalsuperusers;
34                 if(is_object($oAdditionalSuperUsers)) {
35                         $additionalSuperUsers = $oAdditionalSuperUsers->toArray();
36                 }
37
38                 require_once PIWIK_INCLUDE_PATH . '/plugins/CASLogin/CAS/CAS.php';
39
40                 // initialize phpCAS
41
42                 // What happens here: in some piwik functionality, some additional API-style calls are
43                 // made from a controller action, where the authenticate() method will be called *again*.
44                 // This happens for instance when an admin changes some permissions in Settings->Users.
45                 // The first authenticate() is from the page, and the second is due to an API call.
46                 // This checks if there was already a phpcas instance already initialized, otherwize
47                 // phpCAS::client() would fail.
48                 global $PHPCAS_CLIENT;
49                 if(!is_object($PHPCAS_CLIENT)) {
50                         phpCAS::client(
51                                 constant( Zend_Registry::get('config')->caslogin->protocol ),
52                                 Zend_Registry::get('config')->caslogin->host,
53                                 (integer) Zend_Registry::get('config')->caslogin->port,
54                 '',
55                 false
56                         );
57                 }
58
59                 // no SSL validation for the CAS server
60                 phpCAS::setNoCasServerValidation();
61
62                 // Handle single signout requests from CAS server
63                 phpCAS::handleLogoutRequests();
64
65                 // force CAS authentication only if it has been requested by action argument
66                 $action = Piwik::getAction();
67                 
68                 $auth = phpCAS::checkAuthentication();
69                 if(!$auth) {
70                         if($action == 'redirectToCAS') {
71                                 phpCAS::forceAuthentication();
72                         }
73
74                         if($action != 'login' && Piwik::getModule() != 'CoreUpdater') {
75                                 Piwik::redirectToModule('CASLogin', 'login');
76                                 return;
77                         } elseif($action == 'redirectToCAS') {
78                                 phpCAS::forceAuthentication();
79                         } else {
80                                 return new Piwik_Auth_Result( Piwik_Auth_Result::FAILURE, $user, NULL );
81                         }
82                 }
83
84                 // Additional Attributes
85                 // For future retrieval of attributes; they _might_ be of some use, but are highly
86                 // dependable on a specific installation. CAS|piwik hackers can do some magic
87                 // here with SAML attributes etc.
88                 /*
89                 foreach (phpCAS::getAttributes() as $key => $value) {
90                         // syslog(LOG_DEBUG, "attribute: $key - ". print_r($value, true));
91                 }
92                  */
93
94                 if (isset($_SESSION['phpCAS']) && isset($_SESSION['phpCAS']['user'])) {
95                         $user = $_SESSION['phpCAS']['user'];
96                 }
97
98                 if($user) {
99                         if($user == $rootLogin || in_array($user, $additionalSuperUsers)) {
100                                 // Root / Admin login
101                                 return new Piwik_Auth_Result(Piwik_Auth_Result::SUCCESS_SUPERUSER_AUTH_CODE, $user, NULL );
102                         }
103
104                         $login = Zend_Registry::get('db')->fetchOne(
105                                         'SELECT login FROM '.Piwik_Common::prefixTable('user').' WHERE login = ?',
106                                         array($user)
107                         );
108                         if($login === false) {
109                                 // ***User Autocreate***
110                                 // We can either add the authenticated but not-yet-authorized user to the piwik users
111                                 // database, or ignore that.
112                                 // TODO: make this a config option
113                                 // $this->_populateDb($user);
114                                 $login = $user;
115                         }
116
117                         if($login == $user)
118                         {
119                                 return new Piwik_Auth_Result(Piwik_Auth_Result::SUCCESS, $login, NULL );
120                         }
121                 }
122
123                 return new Piwik_Auth_Result( Piwik_Auth_Result::FAILURE, $user, NULL );
124         }
125
126         public function setLogin($login)
127         {
128                 $this->login = $login;
129         }
130         
131     public function setTokenAuth($token_auth)
132         {
133                 $this->token_auth = $token_auth;
134         }
135
136         /**
137          * This method is used to inject user into Piwik's tables.
138          * @todo Alias could be the 'cn' returned from CAS attributes.
139          */
140         private function _populateDb($user)
141         {
142                 $result = null;
143                 $dummy = md5('abcd1234');
144                 if ($this->_helper_userExists($user)) {
145                         $this->_helper_updateUser($user, $dummy, '', 'alias');
146                 } else {
147                         $this->_helper_addUser($user, $dummy, '', 'alias');
148                 }
149         }
150
151
152         ///// The following methods are taken from Piwik's UserManager, but in order to inject data into piwik's user and access tables, we need
153         ///// to make sure we don't wreck things. The UserManager API uses authenticate() to check if we're eligable to look this up,
154         ///// soi we can't use it - we need superuser permissions anyway.
155         //
156         ///// Warning - these methods are of course under Piwik's license.
157         private function _helper_userExists($name)
158         {
159                 $count = Zend_Registry::get('db')->fetchOne("SELECT count(*)
160                                                                         FROM ".Piwik_Common::prefixTable("user"). "
161                                                                         WHERE login = ?", $name);
162                 return $count > 0;
163         }
164
165         private function _helper_updateUser( $userLogin, $password = false, $email = false, $alias = false ) 
166         {
167                 $token_auth = Piwik_UsersManager_API::getTokenAuth($userLogin, $password);
168
169                 $db = Zend_Registry::get('db');
170
171                 $db->update( Piwik_Common::prefixTable("user"),
172                                         array(
173                                                 'password' => $password,
174                                                 'alias' => $alias,
175                                                 'email' => $email,
176                                                 'token_auth' => $token_auth,
177                                                 ),
178                                         "login = '$userLogin'"
179                         );
180         }
181
182         private function _helper_addUser( $userLogin, $password, $email, $alias = false )
183         {               
184                 $token_auth = Piwik_UsersManager_API::getTokenAuth($userLogin, $password);
185
186                 $db = Zend_Registry::get('db');
187
188                 $db->insert( Piwik_Common::prefixTable("user"), array(
189                                                                         'login' => $userLogin,
190                                                                         'password' => $password,
191                                                                         'alias' => $alias,
192                                                                         'email' => $email,
193                                                                         'token_auth' => $token_auth,
194                                                                         )
195                 );
196         }
197     
198 }
199