diff options
-rw-r--r-- | classes/ElggOpenIDConsumer.php | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/classes/ElggOpenIDConsumer.php b/classes/ElggOpenIDConsumer.php new file mode 100644 index 000000000..6e6828e1c --- /dev/null +++ b/classes/ElggOpenIDConsumer.php @@ -0,0 +1,248 @@ +<?php +/** + * Consumer for OpenID + */ + +class ElggOpenIDConsumer { + + protected $provider; + protected $returnURL; + + protected $store; + protected $consumer; + protected $request; + + /** + * Constructor + * + * @param Auth_OpenID_OpenIDStore $store Optional persistence store + */ + public function __construct(Auth_OpenID_OpenIDStore $store = null) { + if ($store) { + $this->store = $store; + } else { + // use the default store + $this->store = new OpenID_ElggStore(); + } + } + + /** + * Set the name of the OpenID provider + * + * @param string $provider + */ + public function setProvider($provider) { + $this->provider = $provider; + } + + /** + * Set the return URL + * + * @param string $url The URL the OpenID provider returns the user to + */ + public function setReturnURL($url) { + $this->returnURL = $url; + } + + /** + * Send a request to the provider for authentication + * + * @return mixed HTMl form on success and false for failure + */ + public function requestAuthentication() { + + if (!$this->store) { + return false; + } + + $this->consumer = new Auth_OpenID_Consumer($this->store); + if (!$this->consumer) { + return false; + } + + $url = $this->getProviderURL(); + if (!$url) { + return false; + } + + // discovers the identity server + $this->request = $this->consumer->begin($url); + if (!$this->request) { + return false; + } + + // request user information + if (!$this->addAttributeRequests()) { + return false; + } + + // send browser for authentication + return $this->getForm(); + } + + /** + * Complete the OpenID authentication by parsing the response + * + * This returns an array of key value pairs about the user. + * + * @return array + */ + public function completeAuthentication() { + + if (!$this->store) { + return false; + } + + $this->consumer = new Auth_OpenID_Consumer($this->store); + if (!$this->consumer) { + return false; + } + + $response = $this->consumer->complete($this->returnURL); + switch ($response->status) { + case Auth_OpenID_SUCCESS: + $data = $this->getUserData($response); + break; + case Auth_OpenID_FAILURE: + case Auth_OpenID_CANCEL: + $data = array(); + break; + } + + return $data; + } + + /** + * Get the OpenID provider URL based on name + * + * @return string + */ + protected function getProviderURL() { + $url = null; + switch ($this->provider) { + case 'google': + $url = 'https://www.google.com/accounts/o8/id'; + break; + default: + break; + } + + return $url; + } + + /** + * Add attribute requests to the OpenID authentication request + * + * @return bool + */ + protected function addAttributeRequests() { + + // Simple Registration + $required = array(); + $optional = array('email', 'nickname', 'fullname', 'language'); + $sregRequest = Auth_OpenID_SRegRequest::build($required, $optional); + if (!$sregRequest) { + return false; + } + $this->request->addExtension($sregRequest); + + // Attribute Exchange + $axRequest = new Auth_OpenID_AX_FetchRequest(); + $attributes[] = Auth_OpenID_AX_AttrInfo::make('http://axschema.org/contact/email', 1, true, 'email'); + $attributes[] = Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/first', 1, true, 'firstname'); + $attributes[] = Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson/last', 1, true, 'lastname'); + foreach ($attributes as $attribute) { + $axRequest->add($attribute); + } + $this->request->addExtension($axRequest); + + return true; + } + + /** + * Gets the form to send the user to the provider to authenticate + * + * This implements OpenID 2.0 by submitting a form through JavaScript against + * the provider. If JavaScript is not enabled, a plain html form with a + * continue button is displayed. + * + * @return mixed + */ + protected function getForm() { + if (!$this->request->shouldSendRedirect()) { + // OpenID 2.0 + $html = $this->request->htmlMarkup(elgg_get_site_url(), $this->returnURL, false); + return $html; + } else { + // OpenID 1.x + return false; + } + } + + /** + * Get user data from the OpenID response + * + * @param Auth_OpenID_ConsumerResponse $response + * @return array + */ + protected function getUserData($response) { + if (!$response) { + return array(); + } + + $sregResponse = Auth_OpenID_SRegResponse::fromSuccessResponse($response); + $sreg = $sregResponse->contents(); + + $axResponse = Auth_OpenID_AX_FetchResponse::fromSuccessResponse($response); + $ax = $axResponse->data; + + $data = $this->extractUserData($sreg, $ax); + $data['openid_identifier'] = $response->getDisplayIdentifier(); + + return data; + } + + /** + * Extract user data from the extensions in the response + * + * @param array $sreg Simple Registration data + * @param array $ax Attribute Exchange data + * @return array + */ + protected function extractUserData($sreg, $ax) { + $data = array(); + + // email + if (isset($sreg['email'])) { + $data['email'] = $sreg['email']; + } + if (isset($ax['http://axschema.org/contact/email'])) { + $data['email'] = $ax['http://axschema.org/contact/email']; + } + + // display name + if (isset($sreg['fullname'])) { + $data['name'] = $sreg['fullname']; + } + if (isset($ax['http://axschema.org/namePerson/first'])) { + $data['name'] = $ax['http://axschema.org/namePerson/first']; + } + if (isset($ax['http://axschema.org/namePerson/last'])) { + $data['name'] .= ' ' . $ax['http://axschema.org/namePerson/last']; + $data['name'] = trim($data['name']); + } + + // username + if (isset($sreg['nickname'])) { + $data['username'] = $sreg['nickname']; + } + + // language + if (isset($sreg['language'])) { + $languages = get_installed_translations(); + // @todo - find out format + } + + return $data; + } +} |