From 497b76b61faee6e2e8d72ce6d9ed8eacd45107d2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?C=C4=83lin-Andrei=20Burloiu?= Date: Wed, 19 Oct 2011 14:56:08 +0300 Subject: [PATCH] OpenID works --- application/controllers/catalog.php | 14 +- application/controllers/user.php | 84 ++---- application/language/english/openid_lang.php | 1 + application/libraries/Openid.php | 48 ++-- application/models/users_model.php | 255 +++++++++++++++++-- 5 files changed, 297 insertions(+), 105 deletions(-) diff --git a/application/controllers/catalog.php b/application/controllers/catalog.php index 28063ee..da3548a 100644 --- a/application/controllers/catalog.php +++ b/application/controllers/catalog.php @@ -71,13 +71,13 @@ class Catalog extends CI_Controller { public function test() { - $q = $this->input->get('q'); - $q = ($q ? $q : 'nimic'); - - $w = $this->input->get('w'); - $w = ($w ? $w : 'nimic'); - - echo "$q / $w"; + $data['email'] = 'CA-LăIN$*(_3@GMAIL.COM'; + $data['email'] = strtolower($data['email']); + $data['username'] = substr($data['email'], + 0, strpos($data['email'], '@')); + $data['username'] = preg_replace(array('/[^a-z0-9\._]*/'), + array(''), $data['username']); + echo $data['username']; } public function category($category_name, $ordering = 'hottest', $offset = 0) diff --git a/application/controllers/user.php b/application/controllers/user.php index 2e4b4ee..397699b 100644 --- a/application/controllers/user.php +++ b/application/controllers/user.php @@ -26,7 +26,7 @@ class User extends CI_Controller { public function test($user_id = 1) { - + echo ($this->users_model->get_userdata('calin.burloiu') ? 'd' : 'n'); } /** @@ -82,24 +82,8 @@ class User extends CI_Controller { { if ($b_openid) { - $this->lang->load('openid'); - $this->load->library('openid'); - $this->config->load('openid'); - $request_to = site_url('user/check_openid_login'); - $req = $this->config->item('openid_required'); - $opt = $this->config->item('openid_optional'); - $policy = site_url('user/openid_policy'); - $pape_policy_uris = $this->config->item('openid_papa_policies'); - - $this->openid->set_request_to($request_to); - $this->openid->set_trust_root(base_url()); - $this->openid->set_args(null); - $this->openid->set_sreg(true, $req, $opt, $policy); - if (!empty($pape_policy_uris)) - $this->openid->set_pape(true, $pape_policy_uris); - - // Redirection to OP site will follow. - $this->openid->authenticate($this->input->post('openid')); + $this->users_model->openid_begin_login( + $this->input->post('openid')); return; } @@ -124,48 +108,34 @@ class User extends CI_Controller { public function check_openid_login() { - $this->lang->load('openid'); - $this->load->library('openid'); - $this->config->load('openid'); - $request_to = site_url('user/check_openid_login'); - - $this->openid->set_request_to($request_to); - $response = $this->openid->get_response(); - - switch ($response->status) + $user = $this->users_model->openid_complete_login(); + + // Authentication failed. + if ($user == Auth_OpenID_CANCEL) { - case Auth_OpenID_CANCEL: $this->load->helper('message'); - show_info_msg_page($this, $this->lang->line('openid_cancel')); - break; - case Auth_OpenID_FAILURE: + show_error_msg_page($this, $this->lang->line('openid_cancel')); + return; + } + else if ($user == Auth_OpenID_FAILURE) + { $this->load->helper('message'); - show_error_msg_page($this, - $this->_format_message('openid_failure', - $response->message)); - break; - case Auth_OpenID_SUCCESS: - $openid = $response->getDisplayIdentifier(); - $esc_identity = htmlspecialchars($openid, ENT_QUOTES); - - $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response); - $sreg = $sreg_resp->contents(); - - // Get registration informations - $ax = new Auth_OpenID_AX_FetchResponse(); - $obj = $ax->fromSuccessResponse($response); - - //echo 'nickname('. $sreg_resp->get('nickname'). ')'; - echo var_dump($obj->data); - echo '
'; - echo var_dump($sreg); -// foreach ($sreg as $key => $value) -// { -// $data['success'] .= $this->_set_message('openid_content', array($key, $value), array('%s', '%t')); -// } - - break; + show_error_msg_page($this, $this->lang->line('openid_failure')); + return; } + + // Authentication successful: set session with user data. + $this->session->set_userdata(array( + 'user_id'=> $user['id'], + 'username'=> $user['username'], + 'auth_src'=> $user['auth_src'], + 'time_zone'=> $user['time_zone'] + )); + + if ($user['import']) + header('Location: '. site_url('user/account')); + else + header('Location: '. site_url()); } public function openid_policy() diff --git a/application/language/english/openid_lang.php b/application/language/english/openid_lang.php index ac2658e..20a1def 100644 --- a/application/language/english/openid_lang.php +++ b/application/language/english/openid_lang.php @@ -14,6 +14,7 @@ $lang['openid_auth_age'] = "

The authentication age returned by the server is: $lang['openid_auth_error'] = 'Authentication error; not a valid OpenID.'; $lang['openid_sreg_failed'] = 'SREG failed.'; +$lang['openid_sreg_failed'] = 'AX failed.'; $lang['openid_pape_failed'] = 'PAPE failed.'; $lang['openid_redirect_failed'] = 'Could not redirect to server: %s'; $lang['openid_storepath_failed'] = 'Could not create the FileStore directory %s. Please check the effective permissions.'; diff --git a/application/libraries/Openid.php b/application/libraries/Openid.php index 7fd12fd..bf20e85 100644 --- a/application/libraries/Openid.php +++ b/application/libraries/Openid.php @@ -14,10 +14,13 @@ if (!defined('BASEPATH')) class Openid { var $storePath = 'tmp'; + var $sreg_enable = FALSE; var $sreg_required = NULL; var $sreg_optional = NULL; var $sreg_policy = NULL; + var $ax_enable = FALSE; + var $ax_attributes = NULL; var $pape_enable = FALSE; var $pape_policy_uris = NULL; var $ext_args = NULL; @@ -54,6 +57,12 @@ class Openid { $this->sreg_optional = $optional; $this->sreg_policy = $policy; } + + function set_ax($enable, $ax_attributes = NULL) + { + $this->ax_enable = $enable; + $this->ax_attributes = $ax_attributes; + } function set_pape($enable, $policy_uris = NULL) { @@ -115,32 +124,21 @@ class Openid { } } - - - // *** TODO *** - - // Create attribute request object - // See http://code.google.com/apis/accounts/docs/OpenID.html#Parameters for parameters - // Usage: make($type_uri, $count=1, $required=false, $alias=null) - $attribute[] = Auth_OpenID_AX_AttrInfo::make( - 'http://axschema.org/contact/email', 1, TRUE); - $attribute[] = Auth_OpenID_AX_AttrInfo::make( - 'http://axschema.org/namePerson/first', 1, TRUE); - $attribute[] = Auth_OpenID_AX_AttrInfo::make( - 'http://axschema.org/namePerson/last', 1, TRUE); - - // Create AX fetch request - $ax = new Auth_OpenID_AX_FetchRequest; - - // Add attributes to AX fetch request - foreach($attribute as $attr){ - $ax->add($attr); + if ($this->ax_enable) + { + $ax_request = new Auth_OpenID_AX_FetchRequest(); + + if ($ax_request) + { + foreach ($this->ax_attributes as $attr) + $ax_request->add($attr); + $authRequest->addExtension($ax_request); + } + else + { + $this->_set_message(TRUE, 'openid_ax_failed'); + } } - - // Add AX fetch request to authentication request - $authRequest->addExtension($ax); - - if ($this->pape_enable) { diff --git a/application/models/users_model.php b/application/models/users_model.php index 02a520f..427b07e 100644 --- a/application/models/users_model.php +++ b/application/models/users_model.php @@ -26,16 +26,8 @@ class Users_model extends CI_Model { * * @param string $username * @param string $password - * @return mixed can return FALSE if authentication failed, a DB row as an - * associative array if authentication was succesful or an associative - * array with LDAP user information if authentication with LDAP was - * successful but the user logged in for the first time and it does not - * have an entry in `users` table yet. The key 'auth_src' distinguishes - * which associative array was returned: - *

+ * @return mixed can return FALSE if authentication failed, a `users`DB row + * as an associative array if authentication was successful */ public function login($username, $password) { @@ -49,7 +41,6 @@ class Users_model extends CI_Model { $enc_password = sha1($password); - // TODO select only required fields. $query = $this->db->query("SELECT u.*, a.activation_code FROM `users` u LEFT JOIN `users_unactivated` a ON (u.id = a.user_id) WHERE $cond_user @@ -78,8 +69,9 @@ class Users_model extends CI_Model { && ! $this->ldap_login($username, $password)) return FALSE; - if (empty($user['email']) || empty($user['first_name']) - || empty($user['last_name'])) + if (empty($user['username']) || empty($user['email']) + || empty($user['first_name']) || empty($user['last_name']) + || empty($user['country'])) $user['import'] = TRUE; // Update last login time. @@ -91,6 +83,205 @@ class Users_model extends CI_Model { return $user; } + /** + * Begin the OpenID login by redirecting user to the OP to authenticate. + * + * @param string $openid + */ + public function openid_begin_login($openid) + { + $this->lang->load('openid'); + $this->load->library('openid'); + + $request_to = site_url('user/check_openid_login'); + + $req = array('nickname'); + $opt = array('fullname', 'email', 'dob', 'country'); + $policy = site_url('user/openid_policy'); + + $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make( + 'http://axschema.org/contact/email', 1, TRUE); + $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make( + 'http://axschema.org/namePerson/first', 1, TRUE); + $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make( + 'http://axschema.org/namePerson/last', 1, TRUE); + $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make( + 'http://axschema.org/contact/country', 1, TRUE); + + $this->openid->set_request_to($request_to); + $this->openid->set_trust_root(base_url()); + $this->openid->set_sreg(TRUE, $req, $opt, $policy); + $this->openid->set_ax(TRUE, $ax_attributes); + + // Redirection to OP site will follow. + $this->openid->authenticate($openid); + } + + /** + * Finalize the OpenID login. Register user if is here for the first time. + * + * @return mixed returns a `users` DB row as an associative array if + * authentication was successful or Auth_OpenID_CANCEL/_FAILURE if it was + * unsuccessful. + */ + public function openid_complete_login() + { + $this->lang->load('openid'); + $this->load->library('openid'); + + $request_to = site_url('user/check_openid_login'); + $this->openid->set_request_to($request_to); + + $response = $this->openid->get_response(); + + if ($response->status === Auth_OpenID_CANCEL + || $response->status === Auth_OpenID_FAILURE) + return $response->status; + + // Auth_OpenID_SUCCESS + $openid = $response->getDisplayIdentifier(); + //$esc_openid = htmlspecialchars($openid, ENT_QUOTES); + + // Get user_id to see if it's the first time the user logs in with + // OpenID. + $query = $this->db->query("SELECT * from `users_openid` + WHERE openid_url = '$openid'"); + $import = FALSE; + + // First time with OpenID => register user + if ($query->num_rows() === 0) + { + $user_id = $this->openid_register($response); + $import = TRUE; + } + // Not first time with OpenID. + else + $user_id = $query->row()->user_id; + + // Login + $query = $this->db->query("SELECT * FROM `users` + WHERE id = $user_id"); + $userdata = $query->row_array(); + $userdata['import'] = $import; + + if (empty($userdata['username']) || empty($userdata['email']) + || empty($userdata['first_name']) + || empty($userdata['last_name']) + || empty($userdata['country'])) + $userdata['import'] = TRUE; + + // Update last login time. + $this->db->query("UPDATE `users` + SET last_login = UTC_TIMESTAMP() + WHERE id = $user_id"); + + return $userdata; + } + + /** + * Register an user that logged in with OpenID for the first time. + * + * @param object $op_response object returned by Janrain + * Consumer::complete method. + * @return mixed the user_id inserted or FALSE on error + */ + public function openid_register($op_response) + { + $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($op_response); + $ax_resp = Auth_OpenID_AX_FetchResponse::fromSuccessResponse($op_response); + + // E-mail + $email = $ax_resp->get('http://axschema.org/contact/email'); + if (empty($email) || is_a($email, 'Auth_OpenID_AX_Error')) + $data['email'] = $sreg_resp->get('email', ''); + else + $data['email'] = $email[0]; + + // First Name + $first_name = $ax_resp->get('http://axschema.org/namePerson/first'); + if (empty($first_name) || is_a($first_name, 'Auth_OpenID_AX_Error')) + $data['first_name'] = ''; + else + $data['first_name'] = $first_name[0]; + + // Sur Name + $last_name = $ax_resp->get('http://axschema.org/namePerson/last'); + if (empty($last_name) || is_a($last_name, 'Auth_OpenID_AX_Error')) + $data['last_name'] = ''; + else + $data['last_name'] = $last_name[0]; + + // First Name and Last Name + if (empty($data['first_name']) || empty($data['last_name'])) + { + $fullname = $sreg_resp->get('fullname'); + + if ($fullname) + { + if (empty($data['first_name'])) + $data['first_name'] = substr( + $fullname, 0, strrpos($fullname, ' ')); + if (empty($data['last_name'])) + $data['last_name'] = substr( + $fullname, strrpos($fullname, ' ') + 1); + } + } + + // Username + $data['username'] = $sreg_resp->get('nickname'); + if (!$data['username']) + { + if (!empty($data['email'])) + { + $data['email'] = strtolower($data['email']); + $data['username'] = substr($data['email'], + 0, strpos($data['email'], '@')); + $data['username'] = preg_replace(array('/[^a-z0-9\._]*/'), + array(''), $data['username']); + } + else if(!empty($data['first_name']) || !empty($data['last_name'])) + { + $data['username'] = $data['first_name'] . '_' + . $data['last_name']; + $data['username'] = substr($data['username'], 0, 32); + } + else + $data['username'] = $this->gen_username(); + } + if ($this->get_userdata($data['username'])) + { + $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; + $len_chars = strlen($chars); + $data['username'] .= '_'; + do + { + $data['username'] .= $chars[ mt_rand(0, $len_chars - 1) ]; + } while($this->get_userdata($data['username'])); + } + + // Country + $country = $ax_resp->get('http://axschema.org/contact/country'); + if (empty($country) || is_a($country, 'Auth_OpenID_AX_Error')) + $data['country'] = $sreg_resp->get('country', ''); + else + $data['country'] = $country[0]; + + // Birth Date + $data['birth_date'] = $sreg_resp->get('dob', NULL); + + // OpenID + $data['auth_src'] = 'openid'; + +// print_r($data); + + if (!$this->register($data, $op_response->getDisplayIdentifier())) + return FALSE; + + $query = $this->db->query("SELECT id from `users` + WHERE username = '{$data['username']}'"); + return $query->row()->id; + } + /** * Converts an array returned by LDAP login to an array which contains * user data ready to be used in `users` DB. @@ -191,10 +382,12 @@ class Users_model extends CI_Model { * Adds a new user to DB. * Do not add join_date and last_login column, they will be automatically * added. + * Provide an 'openid' with the OpenID as value in order to register users + * logging in this way. * * @param array $data corresponds to DB columns */ - public function register($data) + public function register($data, $openid = NULL) { $this->load->helper('array'); @@ -203,7 +396,6 @@ class Users_model extends CI_Model { // Process data. if (isset($data['password'])) $data['password'] = sha1($data['password']); - // TODO picture data: save, convert, make it thumbnail if (empty($data['birth_date'])) $data['birth_date'] = NULL; @@ -234,6 +426,24 @@ class Users_model extends CI_Model { if ($query === FALSE) return FALSE; + // If registered with OpenID insert a row in `users_openid`. + if ($openid) + { + // Find user_id. + $query = $this->db->query("SELECT id from `users` + WHERE username = '{$data['username']}'"); + if ($query->num_rows() === 0) + return FALSE; + $user_id = $query->row()->id; + + // Insert row in `users_openid`. + $query = $this->db->query("INSERT INTO `users_openid` + (openid_url, user_id) + VALUES ('$openid', $user_id)"); + if (!$query) + return FALSE; + } + // If registered with internal authentication it needs to activate // the account. if ($data['auth_src'] == 'internal') @@ -464,7 +674,20 @@ class Users_model extends CI_Model { } return $password; - } + } + + public static function gen_username() + { + $chars = 'abcdefghijklmnopqrstuvwxyz0123456789._'; + $len_chars = strlen($chars); + $len = 8; + $username = ''; + + for ($i = 0; $i < $len; $i++) + $username .= $chars[ mt_rand(0, $len_chars - 1) ]; + + return $username; + } public static function roles_to_string($roles) { -- 2.20.1