getEnabledProviders(); } public static function isCacheableClass() { return true; } public function __sleep() { return array_merge( parent::__sleep(), [ 'mEnabledProviders' ] ); } /** * Returns: * - false: Authentication Failed * - true: Authentication was connected to pUser * - INT: users_users.user_id of auth'ed profile * - Object: Hybrid_User_Profile of validated profile, but no local user_id was found to match the profile **/ public function authenticate( $pProvider, &$pUser ) { $ret = false; if( $this->isProviderEnabled( $pProvider ) ) { $hybridAuth = $this->getHybridAuth(); $authedProvider = $hybridAuth->authenticate( $pProvider ); if( $authProfile = $authedProvider->getUserProfile() ) { $ret = $authProfile; $this->cacheUserProfile( $pProvider, $authProfile ); if( ($userId = $this->mDb->getOne( "SELECT `user_id` FROM `".BIT_DB_PREFIX."users_auth_map` uam WHERE uam.`provider`=? AND uam.`provider_identifier`=?", [ $pProvider, $authProfile->identifier ] )) > ROOT_USER_ID ) { } elseif( $authProfile->emailVerified && ($userId = $this->mDb->getOne( "SELECT uu.`user_id` FROM `".BIT_DB_PREFIX."users_users` uu WHERE uu.`email`=?", [ $authProfile->emailVerified ] )) > ROOT_USER_ID ) { } else { $ret = $authProfile; } if( !empty( $userId ) ) { $pUser->mUserId = $userId; if( $pUser->load() ) { $pUser->loadPermissions( true ); $pUser->setUserSession(); $pUser->clearFromCache(); $ret = $userId; } } if( $pUser->isRegistered() ) { $this->storeUserProfile( $pUser->mUserId, $pProvider, $authProfile->identifier, $authProfile ); } } } return $ret; } public function expungeUserProfile( $pUserId, $pProvider ) { global $gBitSystem; if( $authData = $this->getAuthData( $pProvider, $pUserId ) ) { if( $gBitSystem::isCacheActive() ) { $cacheKey = $this->getProfileCacheKey( $pProvider, $authData['profile_hash']['identifier'] ); apc_delete( $cacheKey ); } $query = "DELETE FROM `".BIT_DB_PREFIX."users_auth_map` WHERE `user_id`=? AND `provider`=?"; $result = $this->mDb->query( $query, [ $pUserId, $pProvider ] ); } } public function storeUserProfile( $pUserId, $pProvider, $pIdentifier, $pAuthProfile ) { if( \Bitweaver\BitBase::verifyId( $pUserId ) && !empty( $pProvider ) && !empty( $pIdentifier ) ) { $this->StartTrans(); $query = "DELETE FROM `".BIT_DB_PREFIX."users_auth_map` WHERE `user_id`=? AND `provider`=?"; $result = $this->mDb->query( $query, [ $pUserId, $pProvider ] ); if( !is_null( $pIdentifier ) ) { $profileHash = get_object_vars( $pAuthProfile ); ksort( $profileHash ); $query = "INSERT INTO `".BIT_DB_PREFIX."users_auth_map` (`user_id`,`provider`,`provider_identifier`,`last_login`,`profile_json`) VALUES(?, ?, ?, ?, ?)"; $result = $this->mDb->query( $query, [ $pUserId, $pProvider, $pIdentifier, time(), json_encode( $profileHash ) ] ); } $this->CompleteTrans(); } } private function getProfileCacheKey( $pProvider, $pId ) { return 'users_ha_'.strtolower( $pProvider ).'_'.$pId; } private function cacheUserProfile( $pProvider, $pProfile ) { $ret = false; global $gBitSystem; if( $gBitSystem::isCacheActive() ) { $cacheKey = $this->getProfileCacheKey( $pProvider, $pProfile->identifier ); apc_store( $cacheKey, $pProfile ); } return $ret; } public function getAuthData( $pProvider, $pUserId=null ) { $ret = []; try { if( empty( $pUserId ) ) { global $gBitUser; $pUserId = $gBitUser->mUserId; } if( $ret = $this->mDb->getRow( "SELECT * FROM `".BIT_DB_PREFIX."users_auth_map` WHERE `user_id`=? AND `provider`=?", [ $pUserId, $pProvider ] ) ) { $ret['profile_hash'] = json_decode( $ret['profile_json'], true ); } } catch( \Exception $e ) { \Bitweaver\bit_error_log( $e->GetMessage() ); } return $ret; } public function getHybridAuth() { $config = [ // "base_url" the url that point to HybridAuth Endpoint (where the index.php and config.php are found) "base_url" => USERS_PKG_URI.'hauth/', "debug_mode" => true, "debug_file" => sys_get_temp_dir().'/hybridauth_log', ]; foreach( $this->mEnabledProviders as $providerKey => $providerHash ) { $config['providers'][$providerHash['provider']] = [ "enabled" => true ]; foreach( array_keys( $providerHash['keys'] ) as $configKey ) { $config['providers'][$providerHash['provider']]['keys'][$configKey] = $this->getProviderConfig( $providerKey, $configKey ); } if( !empty( $providerHash['options'] ) ) { foreach( array_keys( $providerHash['options'] ) as $optionKey ) { $config['providers'][$providerHash['provider']][$optionKey] = $this->getProviderConfig( $providerKey, $optionKey ); } } } return new \Hybrid_Auth( $config ); } public function isProviderEnabled( $pProvider ) { return isset( $this->mEnabledProviders[strtolower( $pProvider )] ); } public function getConnectUri( $pProvider ) { if( $this->isProviderEnabled( $pProvider ) ) { return USERS_PKG_URI.'validate?provider='.$pProvider; } } public function getProviderConfig( $pProviderKey, $pConfigKey ) { return $this->getConfig( $this->getConfigName( $pProviderKey, $pConfigKey ) ); } public function getConfigName( $pProviderKey, $pConfigKey ) { return 'users_ha_'.strtolower( $pProviderKey ).'_'.$pConfigKey; } private function getProviderPath() { return USERS_PKG_PATH.'hauth/Hybrid/Providers/'; } private function getProviderClass( $pProvider ) { return 'Hybrid_Providers_'.$pProvider; } private function getProviderFile( $pProvider ) { return $this->getProviderPath().'/'.$pProvider.'.php'; } private function getProviderIcon( $pProvider ) { $ret = 'icon-user'; $allProviders = $this->getAllProviders(); if( !empty( $allProviders[$pProvider]['icon'] ) ) { $ret = $allProviders[$pProvider]['icon']; } return $ret; } public function getEnabledConfigKey( $pProvider ) { return strtolower( 'users_ha_'.$pProvider.'_enabled' ); } public function getEnabledProviders() { if( empty( $this->mEnabledProviders ) ) { $allProviders = $this->getAllProviders(); foreach( $allProviders as $providerKey=>$providerHash ) { if( $this->getConfig( $this->getEnabledConfigKey( $providerHash['provider'] ) ) ) { $active = true; foreach( array_keys( $providerHash['keys'] ) as $providerConfig ) { $configValue = $this->getProviderConfig( $providerKey, $providerConfig ); $active &= !empty( $configValue ); } if( $active ) { $this->mEnabledProviders[$providerKey] = $providerHash; } } } } return $this->mEnabledProviders; } public function scanProviders() { $ret = []; if( $providerFiles = array_diff(scandir( $this->getProviderPath() ), ['..', '.']) ) { foreach( $providerFiles as $providerFile ) { require_once $this->getProviderFile( $provider ); } } } public function getAllProviders() { return [ 'google' => [ 'provider' => 'Google', 'icon' => 'icon-google-plus-sign', 'image' => USERS_PKG_URL.'hauth/images/google.png', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'amazon' => [ 'provider' => 'Amazon', 'icon' => 'icon-user', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'aol' => [ 'provider' => 'AOL', 'icon' => 'icon-user', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'facebook' => [ 'provider' => 'Facebook', 'icon' => 'icon-facebook-sign', 'keys' => [ 'id'=>'', 'secret'=> '' ], 'options' => [ 'scope'=>'Comma separated list of requested permissions. Default are: email, user_about_me, user_birthday, user_hometown, user_location, user_website, publish_actions, read_custom_friendlists' ] ], 'foursquare' => [ 'provider' => 'Foursquare', 'icon' => 'icon-foursquare', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'instagram' => [ 'provider' => 'Instagram', 'icon' => 'icon-instagram', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'linkedin' => [ 'provider' => 'LinkedIn', 'icon' => 'icon-linkedin', 'keys' => [ 'key'=>'', 'secret'=> '' ] ], 'live' => [ 'provider' => 'Live', 'icon' => 'icon-windows', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'openid' => [ 'provider' => 'OpenID', 'icon' => 'icon-user', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'paypal' => [ 'provider' => 'Paypal', 'icon' => 'icon-user', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], 'twitter' => [ 'provider' => 'Twitter', 'icon' => 'icon-twitter', 'keys' => [ 'key'=>'', 'secret'=> '' ] ], 'yahoo' => [ 'provider' => 'Yahoo', 'icon' => 'icon-user', 'keys' => [ 'id'=>'', 'secret'=> '' ] ], ]; } }