OpenID works
authorCălin-Andrei Burloiu <calin.burloiu@gmail.com>
Wed, 19 Oct 2011 11:56:08 +0000 (14:56 +0300)
committerCălin-Andrei Burloiu <calin.burloiu@gmail.com>
Wed, 19 Oct 2011 11:56:08 +0000 (14:56 +0300)
application/controllers/catalog.php
application/controllers/user.php
application/language/english/openid_lang.php
application/libraries/Openid.php
application/models/users_model.php

index 28063ee..da3548a 100644 (file)
@@ -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)
index 2e4b4ee..397699b 100644 (file)
@@ -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 '<br />';
-                       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()
index ac2658e..20a1def 100644 (file)
@@ -14,6 +14,7 @@ $lang['openid_auth_age'] = "<p>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.';
index 7fd12fd..bf20e85 100644 (file)
@@ -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)
                {
index 02a520f..427b07e 100644 (file)
@@ -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:
-        * <ul>
-        *   <li>'internal' or 'ldap': a DB row</li>
-        *   <li>'ldap_first_time': LDAP user information</li>
-        * </ul>
+        * @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)
        {