1<?php 2 3namespace OAuth\Plugin; 4 5use OAuth\Common\Consumer\Credentials; 6use OAuth\Common\Http\Exception\TokenResponseException; 7use OAuth\Common\Storage\Exception\TokenNotFoundException; 8use OAuth\ServiceFactory; 9use OAuth\OAuth2\Token\StdOAuth2Token; 10 11/** 12 * Class AbstractAdapter 13 * 14 * For each service that shall be used for logging into DokuWiki a subclass of this abstract 15 * class has to be created. It defines how to talk to the Service's API to retrieve user 16 * information 17 * 18 * @package OAuth\Plugin 19 */ 20abstract class AbstractAdapter { 21 22 /** @var \OAuth\Common\Service\AbstractService|\OAuth\OAuth2\Service\AbstractService|\OAuth\OAuth2\Service\AbstractService */ 23 public $oAuth = null; 24 /** @var \helper_plugin_evesso */ 25 protected $hlp = null; 26 /** @var \OAuth\Plugin\oAuthStorage */ 27 protected $storage = null; 28 29 /** 30 * Constructor 31 * 32 * @param $url 33 */ 34 public function __construct() { 35 $this->hlp = plugin_load('helper', 'evesso'); 36 37 $credentials = new Credentials( 38 $this->hlp->getKey(), 39 $this->hlp->getSecret(), 40 $this->hlp->getRedirectURI() 41 ); 42 43 $this->storage = new oAuthStorage(); 44 45 $serviceFactory = new ServiceFactory(); 46 $serviceFactory->setHttpClient(new oAuthHTTPClient()); 47 $this->oAuth = $serviceFactory->createService( 48 $this->getServiceName(), 49 $credentials, 50 $this->storage, 51 $this->getScope() 52 ); 53 } 54 55 /** 56 * Check if the initialization worked 57 * 58 * @return bool 59 */ 60 public function isInitialized() { 61 if(is_null($this->oAuth)) { 62 return false; 63 } 64 return true; 65 } 66 67 /** 68 * Redirects to the service for requesting access 69 * 70 * This is the first step of oAuth authentication 71 * 72 * This implementation tries to abstract away differences between oAuth1 and oAuth2, 73 * but might need to be overwritten for specific services 74 */ 75 public function login() { 76 if(is_a($this->oAuth, 'OAuth\OAuth2\Service\AbstractService')) { /* oAuth2 handling */ 77 78 $url = $this->oAuth->getAuthorizationUri(); 79 } else { /* oAuth1 handling */ 80 81 // extra request needed for oauth1 to request a request token :-) 82 $token = $this->oAuth->requestRequestToken(); 83 84 $url = $this->oAuth->getAuthorizationUri(array('oauth_token' => $token->getRequestToken())); 85 } 86 87 send_redirect($url); 88 } 89 90 /** 91 * Clear storage token for user 92 * 93 */ 94 public function logout() { 95 if ($this->isInitialized()) { 96 $this->oAuth->getStorage()->clearToken($this->oAuth->service()); 97 $this->oAuth->getStorage()->clearAuthorizationState($this->oAuth->service()); 98 } 99 } 100 101 /** 102 * Check access_token 103 * 104 * Update as needed 105 * 106 * @return bool true if access_token is valid. false otherwise 107 */ 108 public function checkToken() { 109 global $INPUT; 110 111 if ($INPUT->get->has('code')) { 112 if (!$this->requestAccessToken()) { //Request access token (Second step of oAuth authentication) 113 return false; 114 } 115 } else { 116 //Check if access token is still valid, if not, refresh the access_token 117 if (!$this->checkAccessToken() && !$this->refreshAccessToken()) { 118 return false; 119 } 120 } 121 return true; 122 } 123 124 /** 125 * Request access token 126 * 127 * Second step of oAuth authentication 128 * 129 * @global type $INPUT 130 * @global \OAuth\Plugin\type $conf 131 * @return boolean true if successful. false otherwise 132 */ 133 private function requestAccessToken() { 134 global $INPUT, $conf; 135 136 try { 137 $this->oAuth->requestAccessToken($INPUT->get->str('code'), $INPUT->get->str('state', null)); 138 return true; 139 } catch (TokenResponseException $e) { 140 msg($e->getMessage(), -1); 141 if ($conf['allowdebug']) { 142 msg('<pre>' . hsc($e->getTraceAsString()) . '</pre>', -1); 143 } 144 return false; 145 } finally { 146 $this->oAuth->getStorage()->clearAuthorizationState($this->oAuth->service()); 147 } 148 } 149 150 /** 151 * Check if access token is still valid 152 * 153 * @global type $conf 154 * @return boolean true if access_token is vaild. false otherwise 155 */ 156 private function checkAccessToken() { 157 global $conf; 158 try { 159 if ($this->oAuth->getStorage()->hasAccessToken($this->oAuth->service()) && $this->oAuth->getStorage()->retrieveAccessToken($this->oAuth->service())->getEndOfLife() - 90 > time()) { 160 return true; // access_token is still vaild - already validated 161 } 162 } catch (TokenNotFoundException $e) { 163 msg($e->getMessage(), -1); 164 if ($conf['allowdebug']) { 165 msg('<pre>' . hsc($e->getTraceAsString()) . '</pre>', -1); 166 } 167 } 168 return false; // oAuth storage have no token 169 } 170 171 /** 172 * Refresh access_token (from refresh_token) 173 * 174 * @global \OAuth\Plugin\type $conf 175 * @return boolean true if successful. false otherwise 176 */ 177 private function refreshAccessToken() { 178 global $conf; 179 try { 180 if ($this->oAuth->getStorage()->hasAccessToken($this->oAuth->service())) { 181 $this->oAuth->refreshAccessToken($this->oAuth->getStorage()->retrieveAccessToken($this->oAuth->service())); 182 return true; 183 } 184 } catch (TokenNotFoundException | TokenResponseException $e) { 185 msg($e->getMessage(), -1); 186 if ($conf['allowdebug']) { 187 msg('<pre>' . hsc($e->getTraceAsString()) . '</pre>', -1); 188 } 189 } 190 return false; 191 } 192 193 /** 194 * Return the name of the oAuth service class to use 195 * 196 * This should match with one of the files in 197 * phpoauth/src/oAuth/oAuth[12]/Service/* 198 * 199 * By default extracts the name from the class name 200 * 201 * @return string 202 */ 203 public function getServiceName() { 204 return $this->getAdapterName(); 205 } 206 207 /** 208 * Return the name of this Adapter 209 * 210 * It specifies which configuration setting should be used 211 * 212 * @return string 213 */ 214 public function getAdapterName() { 215 $name = preg_replace('/Adapter$/', '', get_called_class()); 216 $name = str_replace('OAuth\\Plugin\\', '', $name); 217 return $name; 218 } 219 220 /** 221 * Return the scope to request 222 * 223 * This should return the minimal scope needed for accessing the user's data 224 * 225 * @return array 226 */ 227 public function getScope() { 228 return array(); 229 } 230 231 /** 232 * Retrieve the user's data 233 * 234 * The array needs to contain at least 'email', 'name', 'user', 'grps' 235 * 236 * @return array 237 */ 238 abstract public function getUser(); 239} 240