init
This commit is contained in:
185
modules/Users/authentication/AuthenticationController.php
Executable file
185
modules/Users/authentication/AuthenticationController.php
Executable file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
class AuthenticationController {
|
||||
var $loggedIn = false; //if a user has attempted to login
|
||||
var $authenticated = false;
|
||||
var $loginSuccess = false;// if a user has successfully logged in
|
||||
|
||||
/**
|
||||
* Creates an instance of the authentication controller and loads it
|
||||
*
|
||||
* @param STRING $type - the authentication Controller - default to SugarAuthenticate
|
||||
* @return AuthenticationController -
|
||||
*/
|
||||
function AuthenticationController($type = 'SugarAuthenticate') {
|
||||
if(!file_exists('modules/Users/authentication/'.$type.'/' . $type . '.php'))$type = 'SugarAuthenticate';
|
||||
|
||||
|
||||
if($type == 'SugarAuthenticate' && !empty($GLOBALS['system_config']->settings['system_ldap_enabled']) && empty($_SESSION['sugar_user'])){
|
||||
$type = 'LDAPAuthenticate';
|
||||
}
|
||||
|
||||
|
||||
|
||||
require_once ('modules/Users/authentication/'.$type.'/' . $type . '.php');
|
||||
$this->authController = new $type();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an instance of the authentication controller
|
||||
*
|
||||
* @param STRING $type this is the type of authetnication you want to use default is SugarAuthenticate
|
||||
* @return an instance of the authetnciation controller
|
||||
*/
|
||||
function &getInstance($type='SugarAuthenticate'){
|
||||
static $authcontroller;
|
||||
if(empty($authcontroller)){
|
||||
$authcontroller = new AuthenticationController($type);
|
||||
}
|
||||
return $authcontroller;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when a user initially tries to login.
|
||||
* It will return true if the user successfully logs in or false otherwise.
|
||||
*
|
||||
* @param STRING $username
|
||||
* @param STRING $password
|
||||
* @param ARRAY $PARAMS
|
||||
* @return boolean
|
||||
*/
|
||||
function login($username, $password, $PARAMS = array ()) {
|
||||
//kbrill bug #13225
|
||||
$_SESSION['loginAttempts'] = (isset($_fSESSION['loginAttempts']))? $_SESSION['loginAttempts'] + 1: 1;
|
||||
unset($GLOBALS['login_error']);
|
||||
|
||||
if($this->loggedIn)return $this->loginSuccess;
|
||||
|
||||
$this->loginSuccess = $this->authController->loginAuthenticate($username, $password, false, $PARAMS);
|
||||
$this->loggedIn = true;
|
||||
|
||||
if($this->loginSuccess){
|
||||
//Ensure the user is authorized
|
||||
checkAuthUserStatus();
|
||||
|
||||
loginLicense();
|
||||
if(!empty($GLOBALS['login_error'])){
|
||||
unset($_SESSION['authenticated_user_id']);
|
||||
$GLOBALS['log']->fatal('FAILED LOGIN: potential hack attempt');
|
||||
$this->loginSuccess = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for running Admin Wizard
|
||||
$config = new Administration();
|
||||
$config->retrieveSettings();
|
||||
if ( is_admin($GLOBALS['current_user']) && $_REQUEST['action'] != 'AdminWizard' && empty($config->settings['system_adminwizard']) ) {
|
||||
$GLOBALS['module'] = 'Configurator';
|
||||
$GLOBALS['action'] = 'AdminWizard';
|
||||
ob_clean();
|
||||
header("Location: index.php?module=Configurator&action=AdminWizard");
|
||||
sugar_cleanup(true);
|
||||
}
|
||||
|
||||
$ut = $GLOBALS['current_user']->getPreference('ut');
|
||||
$checkTimeZone = true;
|
||||
if (is_array($PARAMS) && !empty($PARAMS) && isset($PARAMS['passwordEncrypted'])) {
|
||||
$checkTimeZone = false;
|
||||
} // if
|
||||
if(empty($ut) && $_REQUEST['action'] != 'SetTimezone' && $_REQUEST['action'] != 'SaveTimezone' && $checkTimeZone) {
|
||||
$GLOBALS['module'] = 'Users';
|
||||
$GLOBALS['action'] = 'Wizard';
|
||||
ob_clean();
|
||||
header("Location: index.php?module=Users&action=Wizard");
|
||||
sugar_cleanup(true);
|
||||
}
|
||||
|
||||
|
||||
//call business logic hook
|
||||
if(isset($GLOBALS['current_user']))
|
||||
$GLOBALS['current_user']->call_custom_logic('after_login');
|
||||
}else{
|
||||
//kbrill bug #13225
|
||||
LogicHook::initialize();
|
||||
$GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
|
||||
$GLOBALS['log']->fatal('FAILED LOGIN:attempts[' .$_SESSION['loginAttempts'] .'] - '. $username);
|
||||
}
|
||||
// if password has expired, set a session variable
|
||||
|
||||
return $this->loginSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called on every page hit.
|
||||
* It returns true if the current session is authenticated or false otherwise
|
||||
* @return booelan
|
||||
*/
|
||||
function sessionAuthenticate() {
|
||||
|
||||
if(!$this->authenticated){
|
||||
$this->authenticated = $this->authController->sessionAuthenticate();
|
||||
}
|
||||
if($this->authenticated){
|
||||
if(!isset($_SESSION['userStats']['pages'])){
|
||||
$_SESSION['userStats']['loginTime'] = time();
|
||||
$_SESSION['userStats']['pages'] = 0;
|
||||
}
|
||||
$_SESSION['userStats']['lastTime'] = time();
|
||||
$_SESSION['userStats']['pages']++;
|
||||
|
||||
}
|
||||
return $this->authenticated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user requests to logout. Should invalidate the session and redirect
|
||||
* to the login page.
|
||||
*
|
||||
*/
|
||||
function logout(){
|
||||
$GLOBALS['current_user']->call_custom_logic('before_logout');
|
||||
$this->authController->logout();
|
||||
LogicHook::initialize();
|
||||
$GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
61
modules/Users/authentication/EmailAuthenticate/EmailAuthenticate.php
Executable file
61
modules/Users/authentication/EmailAuthenticate/EmailAuthenticate.php
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This file is used to control the authentication process.
|
||||
* It will call on the user authenticate and controll redirection
|
||||
* based on the users validation
|
||||
*
|
||||
*/
|
||||
require_once('modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php');
|
||||
class EmailAuthenticate extends SugarAuthenticate {
|
||||
var $userAuthenticateClass = 'EmailAuthenticateUser';
|
||||
var $authenticationDir = 'EmailAuthenticate';
|
||||
/**
|
||||
* Constructs EmailAuthenticate
|
||||
* This will load the user authentication class
|
||||
*
|
||||
* @return EmailAuthenticate
|
||||
*/
|
||||
function EmailAuthenticate(){
|
||||
|
||||
parent::SugarAuthenticate();
|
||||
}
|
||||
|
||||
}
|
||||
164
modules/Users/authentication/EmailAuthenticate/EmailAuthenticateUser.php
Executable file
164
modules/Users/authentication/EmailAuthenticate/EmailAuthenticateUser.php
Executable file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This file is where the user authentication occurs. No redirection should happen in this file.
|
||||
*
|
||||
*/
|
||||
require_once('modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php');
|
||||
class EmailAuthenticateUser extends SugarAuthenticateUser {
|
||||
var $passwordLength = 4;
|
||||
|
||||
|
||||
/**
|
||||
* this is called when a user logs in
|
||||
*
|
||||
* @param STRING $name
|
||||
* @param STRING $password
|
||||
* @return boolean
|
||||
*/
|
||||
function loadUserOnLogin($name, $password) {
|
||||
|
||||
global $login_error;
|
||||
|
||||
$GLOBALS['log']->debug("Starting user load for ". $name);
|
||||
if(empty($name) || empty($password)) return false;
|
||||
|
||||
if(empty($_SESSION['lastUserId'])){
|
||||
$user_hash = SugarAuthenticate::encodePassword($password);
|
||||
$user_id = $this->authenticateUser($name, $user_hash);
|
||||
if(empty($user_id)) {
|
||||
$GLOBALS['log']->fatal('SECURITY: User authentication for '.$name.' failed');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($_SESSION['emailAuthToken'])){
|
||||
$_SESSION['lastUserId'] = $user_id;
|
||||
$_SESSION['lastUserName'] = $name;
|
||||
$_SESSION['emailAuthToken'] = '';
|
||||
for($i = 0; $i < $this->passwordLength; $i++){
|
||||
$_SESSION['emailAuthToken'] .= chr(mt_rand(48,90));
|
||||
}
|
||||
$_SESSION['emailAuthToken'] = str_replace(array('<', '>'), array('#', '@'), $_SESSION['emailAuthToken']);
|
||||
$_SESSION['login_error'] = 'Please Enter Your User Name and Emailed Session Token';
|
||||
$this->sendEmailPassword($user_id, $_SESSION['emailAuthToken']);
|
||||
return false;
|
||||
}else{
|
||||
if(strcmp($name, $_SESSION['lastUserName']) == 0 && strcmp($password, $_SESSION['emailAuthToken']) == 0){
|
||||
$this->loadUserOnSession($_SESSION['lastUserId']);
|
||||
unset($_SESSION['lastUserId']);
|
||||
unset($_SESSION['lastUserName']);
|
||||
unset($_SESSION['emailAuthToken']);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$_SESSION['login_error'] = 'Please Enter Your User Name and Emailed Session Token';
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends the users password to the email address or sends
|
||||
*
|
||||
* @param unknown_type $user_id
|
||||
* @param unknown_type $password
|
||||
*/
|
||||
function sendEmailPassword($user_id, $password){
|
||||
|
||||
$result = $GLOBALS['db']->query("SELECT email1, email2, first_name, last_name FROM users WHERE id='$user_id'");
|
||||
$row = $GLOBALS['db']->fetchByAssoc($result);
|
||||
|
||||
global $sugar_config;
|
||||
if(empty($row['email1']) && empty($row['email2'])){
|
||||
|
||||
$_SESSION['login_error'] = 'Please contact an administrator to setup up your email address associated to this account';
|
||||
return;
|
||||
}
|
||||
|
||||
require_once("include/SugarPHPMailer.php");
|
||||
global $locale;
|
||||
$OBCharset = $locale->getPrecedentPreference('default_email_charset');
|
||||
$notify_mail = new SugarPHPMailer();
|
||||
$notify_mail->CharSet = $sugar_config['default_charset'];
|
||||
$notify_mail->AddAddress(((!empty($row['email1']))?$row['email1']: $row['email2']),$locale->translateCharsetMIME(trim($row['first_name'] . ' ' . $row['last_name']), 'UTF-8', $OBCharset));
|
||||
|
||||
if (empty($_SESSION['authenticated_user_language'])) {
|
||||
$current_language = $sugar_config['default_language'];
|
||||
}
|
||||
else {
|
||||
$current_language = $_SESSION['authenticated_user_language'];
|
||||
}
|
||||
$mail_settings = new Administration();
|
||||
$mail_settings->retrieveSettings('mail');
|
||||
|
||||
|
||||
$notify_mail->Subject = 'Sugar Token';
|
||||
$notify_mail->Body = 'Your sugar session authentication token is: ' . $password;
|
||||
if ($mail_settings->settings['mail_sendtype'] == "SMTP") {
|
||||
$notify_mail->Mailer = "smtp";
|
||||
$notify_mail->Host = $mail_settings->settings['mail_smtpserver'];
|
||||
$notify_mail->Port = $mail_settings->settings['mail_smtpport'];
|
||||
if ($mail_settings->settings['mail_smtpauth_req']) {
|
||||
$notify_mail->SMTPAuth = TRUE;
|
||||
$notify_mail->Username = $mail_settings->settings['mail_smtpuser'];
|
||||
$notify_mail->Password = $mail_settings->settings['mail_smtppass'];
|
||||
}
|
||||
}
|
||||
|
||||
$notify_mail->From = 'no-reply@sugarcrm.com';
|
||||
$notify_mail->FromName = 'Sugar Authentication';
|
||||
|
||||
if(!$notify_mail->Send()) {
|
||||
$GLOBALS['log']->warn("Notifications: error sending e-mail (method: {$notify_mail->Mailer}), (error: {$notify_mail->ErrorInfo})");
|
||||
}
|
||||
else {
|
||||
$GLOBALS['log']->info("Notifications: e-mail successfully sent");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
60
modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticate.php
Executable file
60
modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticate.php
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This file is used to control the authentication process.
|
||||
* It will call on the user authenticate and controll redirection
|
||||
* based on the users validation
|
||||
*
|
||||
*/
|
||||
require_once('modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php');
|
||||
class LDAPAuthenticate extends SugarAuthenticate {
|
||||
var $userAuthenticateClass = 'LDAPAuthenticateUser';
|
||||
var $authenticationDir = 'LDAPAuthenticate';
|
||||
/**
|
||||
* Constructs LDAPAuthenticate
|
||||
* This will load the user authentication class
|
||||
*
|
||||
* @return LDAPAuthenticate
|
||||
*/
|
||||
function LDAPAuthenticate(){
|
||||
parent::SugarAuthenticate();
|
||||
}
|
||||
|
||||
}
|
||||
400
modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticateUser.php
Executable file
400
modules/Users/authentication/LDAPAuthenticate/LDAPAuthenticateUser.php
Executable file
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This file is where the user authentication occurs. No redirection should happen in this file.
|
||||
*
|
||||
*/
|
||||
require_once('modules/Users/authentication/LDAPAuthenticate/LDAPConfigs/default.php');
|
||||
require_once('modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php');
|
||||
|
||||
define('DEFAULT_PORT', 389);
|
||||
class LDAPAuthenticateUser extends SugarAuthenticateUser{
|
||||
|
||||
/**
|
||||
* Does the actual authentication of the user and returns an id that will be used
|
||||
* to load the current user (loadUserOnSession)
|
||||
*
|
||||
* @param STRING $name
|
||||
* @param STRING $password
|
||||
* @return STRING id - used for loading the user
|
||||
*
|
||||
* Contributions by Erik Mitchell erikm@logicpd.com
|
||||
*/
|
||||
function authenticateUser($name, $password) {
|
||||
|
||||
$server = $GLOBALS['ldap_config']->settings['ldap_hostname'];
|
||||
$port = $GLOBALS['ldap_config']->settings['ldap_port'];
|
||||
if(!$port)
|
||||
$port = DEFAULT_PORT;
|
||||
$GLOBALS['log']->debug("ldapauth: Connecting to LDAP server: $server");
|
||||
$ldapconn = ldap_connect($server, $port);
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
return '';
|
||||
}
|
||||
@ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
@ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0); // required for AD
|
||||
|
||||
|
||||
|
||||
$bind_user = $this->ldap_rdn_lookup($name, $password);
|
||||
$GLOBALS['log']->debug("ldapauth.ldap_authenticate_user: ldap_rdn_lookup returned bind_user=" . $bind_user);
|
||||
if (!$bind_user) {
|
||||
$GLOBALS['log']->fatal("SECURITY: ldapauth: failed LDAP bind (login) by " .
|
||||
$name . ", could not construct bind_user");
|
||||
return '';
|
||||
}
|
||||
|
||||
// MRF - Bug #18578 - punctuation was being passed as HTML entities, i.e. &
|
||||
$bind_password = html_entity_decode($password,ENT_QUOTES);
|
||||
$GLOBALS['log']->info("ldapauth: Binding user " . $bind_user);
|
||||
|
||||
$bind = ldap_bind($ldapconn, $bind_user, $bind_password);
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
$GLOBALS['log']->fatal('[LDAP] ATTEMPTING BIND USING BASE DN PARAMS');
|
||||
$bind = ldap_bind($ldapconn, $GLOBALS['ldap_config']->settings['ldap_bind_attr'] . "=" . $bind_user . "," . $GLOBALS['ldap_config']->settings['ldap_base_dn'], $bind_password);
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['log']->info("ldapauth: Bind attempt complete.");
|
||||
|
||||
if ($bind) {
|
||||
// Authentication succeeded, get info from LDAP directory
|
||||
$attrs = array_keys($GLOBALS['ldapConfig']['users']['fields']);
|
||||
$base_dn = $GLOBALS['ldap_config']->settings['ldap_base_dn'];
|
||||
$name_filter = $this->getUserNameFilter($name);
|
||||
|
||||
//add the group user attribute that we will compare to the group attribute for membership validation if group membership is turned on
|
||||
if(!empty($GLOBALS['ldap_config']->settings['ldap_group']) && !empty($GLOBALS['ldap_config']->settings['ldap_group_user_attr']) && !empty($GLOBALS['ldap_config']->settings['ldap_group_attr'])){
|
||||
if(!in_array($attrs, $GLOBALS['ldap_config']->settings['ldap_group_user_attr'])){
|
||||
$attrs[] = $GLOBALS['ldap_config']->settings['ldap_group_user_attr'];
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['log']->debug("ldapauth: Fetching user info from Directory.");
|
||||
$result = @ldap_search($ldapconn, $base_dn, $name_filter, $attrs);
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
return '';
|
||||
}
|
||||
$GLOBALS['log']->debug("ldapauth: ldap_search complete.");
|
||||
|
||||
$info = @ldap_get_entries($ldapconn, $result);
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$GLOBALS['log']->debug("ldapauth: User info from Directory fetched.");
|
||||
|
||||
// some of these don't seem to work
|
||||
$this->ldapUserInfo = array();
|
||||
foreach($GLOBALS['ldapConfig']['users']['fields'] as $key=>$value){
|
||||
//MRF - BUG:19765
|
||||
$key = strtolower($key);
|
||||
if(isset($info[0]) && isset($info[0][$key]) && isset($info[0][$key][0])){
|
||||
$this->ldapUserInfo[$value] = $info[0][$key][0];
|
||||
}
|
||||
}
|
||||
|
||||
//we should check that a user is a member of a specific group
|
||||
if(!empty($GLOBALS['ldap_config']->settings['ldap_group'])){
|
||||
$GLOBALS['log']->debug("LDAPAuth: scanning group for user membership");
|
||||
$group_user_attr = $GLOBALS['ldap_config']->settings['ldap_group_user_attr'];
|
||||
$group_attr = $GLOBALS['ldap_config']->settings['ldap_group_attr'];
|
||||
if(!isset($info[0][$group_user_attr])){
|
||||
$GLOBALS['log']->fatal("ldapauth: $group_user_attr not found for user $name cannot authenticate against an LDAP group");
|
||||
ldap_close($ldapconn);
|
||||
return '';
|
||||
}else{
|
||||
$user_uid = $info[0][$group_user_attr];
|
||||
}
|
||||
//user is not a member of the group if the count is zero get the logs and return no id so it fails login
|
||||
if(!isset($user_uid[0]) || ldap_count_entries($ldapconn, ldap_search($ldapconn,$GLOBALS['ldap_config']->settings['ldap_group_name'] . ",". $GLOBALS['ldap_config']->settings['ldap_group_dn'] ,"($group_attr=" . $user_uid[0] . ")")) == 0){
|
||||
$GLOBALS['log']->fatal("ldapauth: User ($name) is not a member of the LDAP group");
|
||||
$user_id = var_export($user_uid, true);
|
||||
$GLOBALS['log']->debug("ldapauth: Group DN:{$GLOBALS['ldap_config']->settings['ldap_group_dn']} Group Name: " . $GLOBALS['ldap_config']->settings['ldap_group_name'] . " Group Attribute: $group_attr User Attribute: $group_user_attr :(" . $user_uid[0] . ")");
|
||||
ldap_close($ldapconn);
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
ldap_close($ldapconn);
|
||||
$dbresult = $GLOBALS['db']->query("SELECT id, status FROM users WHERE user_name='" . $name . "' AND deleted = 0");
|
||||
|
||||
//user already exists use this one
|
||||
if($row = $GLOBALS['db']->fetchByAssoc($dbresult)){
|
||||
if($row['status'] != 'Inactive')
|
||||
return $row['id'];
|
||||
else
|
||||
return '';
|
||||
}
|
||||
|
||||
//create a new user and return the user
|
||||
if($GLOBALS['ldap_config']->settings['ldap_auto_create_users']){
|
||||
return $this->createUser($name);
|
||||
|
||||
}
|
||||
return '';
|
||||
|
||||
} else {
|
||||
$GLOBALS['log']->fatal("SECURITY: failed LDAP bind (login) by $this->user_name using bind_user=$bind_user");
|
||||
$GLOBALS['log']->fatal("ldapauth: failed LDAP bind (login) by $this->user_name using bind_user=$bind_user");
|
||||
ldap_close($ldapconn);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* takes in a name and creates the appropriate search filter for that user name including any additional filters specified in the system settings page
|
||||
* @param $name
|
||||
* @return String
|
||||
*/
|
||||
function getUserNameFilter($name){
|
||||
$name_filter = "(" . $GLOBALS['ldap_config']->settings['ldap_login_attr']. "=" . $name . ")";
|
||||
//add the additional user filter if it is specified
|
||||
if(!empty($GLOBALS['ldap_config']->settings['ldap_login_filter'])){
|
||||
$add_filter = $GLOBALS['ldap_config']->settings['ldap_login_filter'];
|
||||
if(substr($add_filter, 0, 1) !== "("){
|
||||
$add_filter = "(" . $add_filter . ")";
|
||||
}
|
||||
$name_filter = "(&" . $name_filter . $add_filter . ")";
|
||||
}
|
||||
return $name_filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a user with the given User Name and returns the id of that new user
|
||||
* populates the user with what was set in ldapUserInfo
|
||||
*
|
||||
* @param STRING $name
|
||||
* @return STRING $id
|
||||
*/
|
||||
function createUser($name){
|
||||
|
||||
$user = new User();
|
||||
$user->user_name = $name;
|
||||
foreach($this->ldapUserInfo as $key=>$value){
|
||||
$user->$key = $value;
|
||||
}
|
||||
$user->employee_status = 'Active';
|
||||
$user->status = 'Active';
|
||||
$user->is_admin = 0;
|
||||
$user->external_auth_only = 1;
|
||||
$user->save();
|
||||
return $user->id;
|
||||
|
||||
}
|
||||
/**
|
||||
* this is called when a user logs in
|
||||
*
|
||||
* @param STRING $name
|
||||
* @param STRING $password
|
||||
* @return boolean
|
||||
*/
|
||||
function loadUserOnLogin($name, $password) {
|
||||
|
||||
global $mod_strings;
|
||||
|
||||
// Check if the LDAP extensions are loaded
|
||||
if(!function_exists('ldap_connect')) {
|
||||
$error = $mod_strings['LBL_LDAP_EXTENSION_ERROR'];
|
||||
$GLOBALS['log']->fatal($error);
|
||||
$_SESSION['login_error'] = $error;
|
||||
return false;
|
||||
}
|
||||
|
||||
global $login_error;
|
||||
$GLOBALS['ldap_config'] = new Administration();
|
||||
$GLOBALS['ldap_config']->retrieveSettings('ldap');
|
||||
$GLOBALS['log']->debug("Starting user load for ". $name);
|
||||
if(empty($name) || empty($password)) return false;
|
||||
checkAuthUserStatus();
|
||||
|
||||
$user_id = $this->authenticateUser($name, $password);
|
||||
if(empty($user_id)) {
|
||||
//check if the user can login as a normal sugar user
|
||||
$GLOBALS['log']->fatal('SECURITY: User authentication for '.$name.' failed');
|
||||
return false;
|
||||
}
|
||||
$this->loadUserOnSession($user_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called with the error number of the last call if the error number is 0
|
||||
* there was no error otherwise it converts the error to a string and logs it as fatal
|
||||
*
|
||||
* @param INT $error
|
||||
* @return boolean
|
||||
*/
|
||||
function loginError($error){
|
||||
if(empty($error)) return false;
|
||||
$errorstr = ldap_err2str($error);
|
||||
// BEGIN SUGAR INT
|
||||
$_SESSION['login_error'] = $errorstr;
|
||||
/*
|
||||
// END SUGAR INT
|
||||
$_SESSION['login_error'] = translate('ERR_INVALID_PASSWORD', 'Users');
|
||||
// BEGIN SUGAR INT
|
||||
*/
|
||||
// END SUGAR INT
|
||||
$GLOBALS['log']->fatal('[LDAP ERROR]['. $error . ']'.$errorstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string appropriate value for username when binding to directory server.
|
||||
* @param string $user_name the value provided in login form
|
||||
* @desc Take the login username and return either said username for AD or lookup
|
||||
* distinguished name using anonymous credentials for OpenLDAP.
|
||||
* Contributions by Erik Mitchell erikm@logicpd.com
|
||||
*/
|
||||
function ldap_rdn_lookup($user_name, $password) {
|
||||
|
||||
// MFH BUG# 14547 - Added htmlspecialchars_decode()
|
||||
$server = $GLOBALS['ldap_config']->settings['ldap_hostname'];
|
||||
$base_dn = htmlspecialchars_decode($GLOBALS['ldap_config']->settings['ldap_base_dn']);
|
||||
if(!empty($GLOBALS['ldap_config']->settings['ldap_authentication'])){
|
||||
$admin_user = htmlspecialchars_decode($GLOBALS['ldap_config']->settings['ldap_admin_user']);
|
||||
$admin_password = htmlspecialchars_decode($GLOBALS['ldap_config']->settings['ldap_admin_password']);
|
||||
}else{
|
||||
$admin_user = '';
|
||||
$admin_password = '';
|
||||
}
|
||||
$user_attr = $GLOBALS['ldap_config']->settings['ldap_login_attr'];
|
||||
$bind_attr = $GLOBALS['ldap_config']->settings['ldap_bind_attr'];
|
||||
$port = $GLOBALS['ldap_config']->settings['ldap_port'];
|
||||
if(!$port)
|
||||
$port = DEFAULT_PORT;
|
||||
$ldapconn = ldap_connect($server, $port);
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
return false;
|
||||
}
|
||||
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0); // required for AD
|
||||
//if we are going to connect anonymously lets atleast try to connect with the user connecting
|
||||
if(empty($admin_user)){
|
||||
$bind = @ldap_bind($ldapconn, $user_name, $password);
|
||||
$error = ldap_errno($ldapconn);
|
||||
}
|
||||
if(empty($bind)){
|
||||
$bind = @ldap_bind($ldapconn, $admin_user, $admin_password);
|
||||
$error = ldap_errno($ldapconn);
|
||||
}
|
||||
|
||||
if($this->loginError($error)){
|
||||
return false;
|
||||
}
|
||||
if (!$bind) {
|
||||
$GLOBALS['log']->warn("ldapauth.ldap_rdn_lookup: Could not bind with admin user, trying to bind anonymously");
|
||||
$bind = @ldap_bind($ldapconn);
|
||||
$error = ldap_errno($ldapconn);
|
||||
|
||||
if($this->loginError($error)){
|
||||
return false;
|
||||
}
|
||||
if (!$bind) {
|
||||
$GLOBALS['log']->warn("ldapauth.ldap_rdn_lookup: Could not bind anonymously, returning username");
|
||||
return $user_name;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here we were able to bind somehow
|
||||
$search_filter = $this->getUserNameFilter($user_name);
|
||||
|
||||
$GLOBALS['log']->info("ldapauth.ldap_rdn_lookup: Bind succeeded, searching for $user_attr=$user_name");
|
||||
$GLOBALS['log']->debug("ldapauth.ldap_rdn_lookup: base_dn:$base_dn , search_filter:$search_filter");
|
||||
|
||||
$result = @ldap_search($ldapconn, $base_dn , $search_filter, array("dn", $bind_attr));
|
||||
$error = ldap_errno($ldapconn);
|
||||
if($this->loginError($error)){
|
||||
return false;
|
||||
}
|
||||
$info = ldap_get_entries($ldapconn, $result);
|
||||
if($info['count'] == 0){
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
ldap_unbind($ldapconn);
|
||||
|
||||
$GLOBALS['log']->info("ldapauth.ldap_rdn_lookup: Search result:\nldapauth.ldap_rdn_lookup: " . count($info));
|
||||
|
||||
if ($bind_attr == "dn") {
|
||||
$found_bind_user = $info[0]['dn'];
|
||||
} else {
|
||||
$found_bind_user = $info[0][strtolower($bind_attr)][0];
|
||||
}
|
||||
|
||||
$GLOBALS['log']->info("ldapauth.ldap_rdn_lookup: found_bind_user=" . $found_bind_user);
|
||||
|
||||
if (!empty($found_bind_user)) {
|
||||
return $found_bind_user;
|
||||
} elseif ($user_attr == $bind_attr) {
|
||||
return $user_name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
69
modules/Users/authentication/LDAPAuthenticate/LDAPConfigs/default.php
Executable file
69
modules/Users/authentication/LDAPAuthenticate/LDAPConfigs/default.php
Executable file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
$GLOBALS['ldapConfig'] = array(
|
||||
'users'=>
|
||||
array(
|
||||
'fields'=>
|
||||
array(
|
||||
"givenName"=>'first_name',
|
||||
"sn"=>'last_name',
|
||||
"mail"=>'email1',
|
||||
"telephoneNumber"=>'phone_work',
|
||||
"facsimileTelephoneNumber"=>'phone_fax',
|
||||
"mobile"=>'phone_mobile',
|
||||
"street"=>'address_street',
|
||||
"l"=>'address_city',
|
||||
"st"=>'address_state',
|
||||
"postalCode"=>'address_postalcode',
|
||||
"c"=>'address_country'
|
||||
|
||||
|
||||
|
||||
)
|
||||
),
|
||||
'system'=>
|
||||
array('overwriteSugarUserInfo'=>true,),
|
||||
|
||||
|
||||
|
||||
);
|
||||
|
||||
|
||||
?>
|
||||
345
modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php
Executable file
345
modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php
Executable file
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This file is used to control the authentication process.
|
||||
* It will call on the user authenticate and controll redirection
|
||||
* based on the users validation
|
||||
*
|
||||
*/
|
||||
class SugarAuthenticate{
|
||||
var $userAuthenticateClass = 'SugarAuthenticateUser';
|
||||
var $authenticationDir = 'SugarAuthenticate';
|
||||
/**
|
||||
* Constructs SugarAuthenticate
|
||||
* This will load the user authentication class
|
||||
*
|
||||
* @return SugarAuthenticate
|
||||
*/
|
||||
function SugarAuthenticate(){
|
||||
require_once('modules/Users/authentication/'. $this->authenticationDir . '/'. $this->userAuthenticateClass . '.php');
|
||||
$this->userAuthenticate = new $this->userAuthenticateClass();
|
||||
|
||||
}
|
||||
/**
|
||||
* Authenticates a user based on the username and password
|
||||
* returns true if the user was authenticated false otherwise
|
||||
* it also will load the user into current user if he was authenticated
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean
|
||||
*/
|
||||
function loginAuthenticate($username, $password, $fallback=false, $PARAMS = array ()){
|
||||
global $mod_strings;
|
||||
unset($_SESSION['login_error']);
|
||||
$usr= new user();
|
||||
$usr_id=$usr->retrieve_user_id($username);
|
||||
$usr->retrieve($usr_id);
|
||||
$_SESSION['login_error']='';
|
||||
$_SESSION['waiting_error']='';
|
||||
$_SESSION['hasExpiredPassword']='0';
|
||||
if ($this->userAuthenticate->loadUserOnLogin($username, $password, $fallback, $PARAMS)) {
|
||||
require_once('modules/Users/password_utils.php');
|
||||
if(hasPasswordExpired($username)) {
|
||||
$_SESSION['hasExpiredPassword'] = '1';
|
||||
}
|
||||
return $this->postLoginAuthenticate();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!empty($usr_id) && $res['lockoutexpiration'] > 0){
|
||||
if (($logout=$usr->getPreference('loginfailed'))=='')
|
||||
$usr->setPreference('loginfailed','1');
|
||||
else
|
||||
$usr->setPreference('loginfailed',$logout+1);
|
||||
$usr->savePreferencesToDB();
|
||||
}
|
||||
}
|
||||
if(strtolower(get_class($this)) != 'sugarauthenticate'){
|
||||
$sa = new SugarAuthenticate();
|
||||
$error = (!empty($_SESSION['login_error']))?$_SESSION['login_error']:'';
|
||||
if($sa->loginAuthenticate($username, $password, true, $PARAMS)){
|
||||
return true;
|
||||
}
|
||||
$_SESSION['login_error'] = $error;
|
||||
}
|
||||
|
||||
|
||||
$_SESSION['login_user_name'] = $username;
|
||||
$_SESSION['login_password'] = $password;
|
||||
if(empty($_SESSION['login_error'])){
|
||||
$_SESSION['login_error'] = translate('ERR_INVALID_PASSWORD', 'Users');
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Once a user is authenticated on login this function will be called. Populate the session with what is needed and log anything that needs to be logged
|
||||
*
|
||||
*/
|
||||
function postLoginAuthenticate(){
|
||||
|
||||
global $reset_theme_on_default_user, $reset_language_on_default_user, $sugar_config;
|
||||
//THIS SECTION IS TO ENSURE VERSIONS ARE UPTODATE
|
||||
|
||||
require_once ('modules/Versions/CheckVersions.php');
|
||||
$invalid_versions = get_invalid_versions();
|
||||
if (!empty ($invalid_versions)) {
|
||||
if (isset ($invalid_versions['Rebuild Relationships'])) {
|
||||
unset ($invalid_versions['Rebuild Relationships']);
|
||||
|
||||
// flag for pickup in DisplayWarnings.php
|
||||
$_SESSION['rebuild_relationships'] = true;
|
||||
}
|
||||
|
||||
if (isset ($invalid_versions['Rebuild Extensions'])) {
|
||||
unset ($invalid_versions['Rebuild Extensions']);
|
||||
|
||||
// flag for pickup in DisplayWarnings.php
|
||||
$_SESSION['rebuild_extensions'] = true;
|
||||
}
|
||||
|
||||
$_SESSION['invalid_versions'] = $invalid_versions;
|
||||
}
|
||||
|
||||
|
||||
//just do a little house cleaning here
|
||||
unset($_SESSION['login_password']);
|
||||
unset($_SESSION['login_error']);
|
||||
unset($_SESSION['login_user_name']);
|
||||
unset($_SESSION['ACL']);
|
||||
|
||||
//set the server unique key
|
||||
if (isset ($sugar_config['unique_key']))$_SESSION['unique_key'] = $sugar_config['unique_key'];
|
||||
|
||||
//set user language
|
||||
if (isset ($reset_language_on_default_user) && $reset_language_on_default_user && $$GLOBALS['current_user']->user_name == $sugar_config['default_user_name']) {
|
||||
$authenticated_user_language = $sugar_config['default_language'];
|
||||
} else {
|
||||
$authenticated_user_language = isset($_REQUEST['login_language']) ? $_REQUEST['login_language'] : (isset ($_REQUEST['ck_login_language_20']) ? $_REQUEST['ck_login_language_20'] : $sugar_config['default_language']);
|
||||
}
|
||||
|
||||
$_SESSION['authenticated_user_language'] = $authenticated_user_language;
|
||||
|
||||
$GLOBALS['log']->debug("authenticated_user_language is $authenticated_user_language");
|
||||
|
||||
// Clear all uploaded import files for this user if it exists
|
||||
|
||||
$tmp_file_name = $sugar_config['import_dir']."IMPORT_".$GLOBALS['current_user']->id;
|
||||
|
||||
if (file_exists($tmp_file_name)) {
|
||||
unlink($tmp_file_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* On every page hit this will be called to ensure a user is authenticated
|
||||
* @return boolean
|
||||
*/
|
||||
function sessionAuthenticate(){
|
||||
|
||||
global $module, $action, $allowed_actions;
|
||||
$authenticated = false;
|
||||
$allowed_actions = array ("Authenticate", "Login"); // these are actions where the user/server keys aren't compared
|
||||
if (isset ($_SESSION['authenticated_user_id'])) {
|
||||
|
||||
$GLOBALS['log']->debug("We have an authenticated user id: ".$_SESSION["authenticated_user_id"]);
|
||||
|
||||
$authenticated = $this->postSessionAuthenticate();
|
||||
|
||||
} else
|
||||
if (isset ($action) && isset ($module) && $action == "Authenticate" && $module == "Users") {
|
||||
$GLOBALS['log']->debug("We are authenticating user now");
|
||||
} else {
|
||||
$GLOBALS['log']->debug("The current user does not have a session. Going to the login page");
|
||||
$action = "Login";
|
||||
$module = "Users";
|
||||
$_REQUEST['action'] = $action;
|
||||
$_REQUEST['module'] = $module;
|
||||
}
|
||||
if (empty ($GLOBALS['current_user']->id) && !in_array($action, $allowed_actions)) {
|
||||
|
||||
$GLOBALS['log']->debug("The current user is not logged in going to login page");
|
||||
$action = "Login";
|
||||
$module = "Users";
|
||||
$_REQUEST['action'] = $action;
|
||||
$_REQUEST['module'] = $module;
|
||||
|
||||
}
|
||||
|
||||
if($authenticated && ((empty($_REQUEST['module']) || empty($_REQUEST['action'])) || ($_REQUEST['module'] != 'Users' || $_REQUEST['action'] != 'Logout'))){
|
||||
$this->validateIP();
|
||||
}
|
||||
return $authenticated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Called after a session is authenticated - if this returns false the sessionAuthenticate will return false and destroy the session
|
||||
* and it will load the current user
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
function postSessionAuthenticate(){
|
||||
|
||||
global $action, $allowed_actions, $sugar_config;
|
||||
$_SESSION['userTime']['last'] = time();
|
||||
$user_unique_key = (isset ($_SESSION['unique_key'])) ? $_SESSION['unique_key'] : '';
|
||||
$server_unique_key = (isset ($sugar_config['unique_key'])) ? $sugar_config['unique_key'] : '';
|
||||
|
||||
//CHECK IF USER IS CROSSING SITES
|
||||
if (($user_unique_key != $server_unique_key) && (!in_array($action, $allowed_actions)) && (!isset ($_SESSION['login_error']))) {
|
||||
|
||||
session_destroy();
|
||||
$post_login_nav = '';
|
||||
if (!empty ($record) && !empty ($action) && !empty ($module)) {
|
||||
$post_login_nav = "&login_module=".$module."&login_action=".$action."&login_record=".$record;
|
||||
}
|
||||
$GLOBALS['log']->debug('Destroying Session User has crossed Sites');
|
||||
header("Location: index.php?action=Login&module=Users".$post_login_nav);
|
||||
sugar_cleanup(true);
|
||||
}
|
||||
if (!$this->userAuthenticate->loadUserOnSession($_SESSION['authenticated_user_id'])) {
|
||||
session_destroy();
|
||||
header("Location: index.php?action=Login&module=Users");
|
||||
$GLOBALS['log']->debug('Current user session does not exist redirecting to login');
|
||||
sugar_cleanup(true);
|
||||
}
|
||||
$GLOBALS['log']->debug('Current user is: '.$GLOBALS['current_user']->user_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure a user isn't stealing sessions so check the ip to ensure that the ip address hasn't dramatically changed
|
||||
*
|
||||
*/
|
||||
function validateIP() {
|
||||
global $sugar_config;
|
||||
// grab client ip address
|
||||
$clientIP = query_client_ip();
|
||||
$classCheck = 0;
|
||||
// check to see if config entry is present, if not, verify client ip
|
||||
if (!isset ($sugar_config['verify_client_ip']) || $sugar_config['verify_client_ip'] == true) {
|
||||
// check to see if we've got a current ip address in $_SESSION
|
||||
// and check to see if the session has been hijacked by a foreign ip
|
||||
if (isset ($_SESSION["ipaddress"])) {
|
||||
$session_parts = explode(".", $_SESSION["ipaddress"]);
|
||||
$client_parts = explode(".", $clientIP);
|
||||
if(count($session_parts) < 4) {
|
||||
$classCheck = 0;
|
||||
}
|
||||
else {
|
||||
// match class C IP addresses
|
||||
for ($i = 0; $i < 3; $i ++) {
|
||||
if ($session_parts[$i] == $client_parts[$i]) {
|
||||
$classCheck = 1;
|
||||
continue;
|
||||
} else {
|
||||
$classCheck = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we have a different IP address
|
||||
if ($_SESSION["ipaddress"] != $clientIP && empty ($classCheck)) {
|
||||
$GLOBALS['log']->fatal("IP Address mismatch: SESSION IP: {$_SESSION['ipaddress']} CLIENT IP: {$clientIP}");
|
||||
session_destroy();
|
||||
die("Your session was terminated due to a significant change in your IP address. <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
|
||||
}
|
||||
} else {
|
||||
$_SESSION["ipaddress"] = $clientIP;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Called when a user requests to logout
|
||||
*
|
||||
*/
|
||||
function logout(){
|
||||
session_destroy();
|
||||
ob_clean();
|
||||
header('Location: index.php?module=Users&action=Login');
|
||||
sugar_cleanup(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a users password. This is a static function and can be called at any time.
|
||||
*
|
||||
* @param STRING $password
|
||||
* @return STRING $encoded_password
|
||||
*/
|
||||
function encodePassword($password){
|
||||
return strtolower(md5($password));
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user may change there password through the Sugar UI
|
||||
*
|
||||
*/
|
||||
function canChangePassword(){
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* If a user may change there user name through the Sugar UI
|
||||
*
|
||||
*/
|
||||
function canChangeUserName(){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
142
modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php
Executable file
142
modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php
Executable file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
|
||||
/*********************************************************************************
|
||||
* SugarCRM is a customer relationship management program developed by
|
||||
* SugarCRM, Inc. Copyright (C) 2004-2010 SugarCRM Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along with
|
||||
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||
* SugarCRM" logo. If the display of the logo is not reasonably feasible for
|
||||
* technical reasons, the Appropriate Legal Notices must display the words
|
||||
* "Powered by SugarCRM".
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This file is where the user authentication occurs. No redirection should happen in this file.
|
||||
*
|
||||
*/
|
||||
class SugarAuthenticateUser{
|
||||
|
||||
/**
|
||||
* Does the actual authentication of the user and returns an id that will be used
|
||||
* to load the current user (loadUserOnSession)
|
||||
*
|
||||
* @param STRING $name
|
||||
* @param STRING $password
|
||||
* @param STRING $fallback - is this authentication a fallback from a failed authentication
|
||||
* @return STRING id - used for loading the user
|
||||
*/
|
||||
function authenticateUser($name, $password, $fallback=false) {
|
||||
$name = $GLOBALS['db']->quote($name);
|
||||
$password = $GLOBALS['db']->quote($password);
|
||||
$query = "SELECT * from users where user_name='$name' AND user_hash='$password' AND (portal_only IS NULL OR portal_only !='1') AND (is_group IS NULL OR is_group !='1') AND status !='Inactive'";
|
||||
$result =$GLOBALS['db']->limitQuery($query,0,1,false);
|
||||
$row = $GLOBALS['db']->fetchByAssoc($result);
|
||||
|
||||
// set the ID in the seed user. This can be used for retrieving the full user record later
|
||||
//if it's falling back on Sugar Authentication after the login failed on an external authentication return empty if the user has external_auth_disabled for them
|
||||
if (empty ($row) || ($fallback && !empty($row['external_auth_only']))) {
|
||||
return '';
|
||||
} else {
|
||||
return $row['id'];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if a user is a sugarLogin user
|
||||
* which implies they should use the sugar authentication to login
|
||||
*
|
||||
* @param STRING $name
|
||||
* @param STRIUNG $password
|
||||
* @return boolean
|
||||
*/
|
||||
function isSugarLogin($name, $password){
|
||||
$password = SugarAuthenticate::encodePassword($password);
|
||||
$name = $GLOBALS['db']->quote($name);
|
||||
$password = $GLOBALS['db']->quote($password);
|
||||
$query = "SELECT * from users where user_name='$name' AND user_hash='$password' AND (portal_only IS NULL OR portal_only !='1') AND (is_group IS NULL OR is_group !='1') AND status !='Inactive' AND sugar_login=1";
|
||||
$result =$GLOBALS['db']->limitQuery($query,0,1,false);
|
||||
$row = $GLOBALS['db']->fetchByAssoc($result);
|
||||
if($row)return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* this is called when a user logs in
|
||||
*
|
||||
* @param STRING $name
|
||||
* @param STRING $password
|
||||
* @param STRING $fallback - is this authentication a fallback from a failed authentication
|
||||
* @return boolean
|
||||
*/
|
||||
function loadUserOnLogin($name, $password, $fallback = false, $PARAMS = array()) {
|
||||
global $login_error;
|
||||
|
||||
$GLOBALS['log']->debug("Starting user load for ". $name);
|
||||
if(empty($name) || empty($password)) return false;
|
||||
$user_hash = $password;
|
||||
$passwordEncrypted = false;
|
||||
if (!empty($PARAMS) && isset($PARAMS['passwordEncrypted']) && $PARAMS['passwordEncrypted']) {
|
||||
$passwordEncrypted = true;
|
||||
}// if
|
||||
if (!$passwordEncrypted) {
|
||||
$user_hash = SugarAuthenticate::encodePassword($password);
|
||||
} // if
|
||||
$user_id = $this->authenticateUser($name, $user_hash, $fallback);
|
||||
if(empty($user_id)) {
|
||||
$GLOBALS['log']->fatal('SECURITY: User authentication for '.$name.' failed');
|
||||
return false;
|
||||
}
|
||||
$this->loadUserOnSession($user_id);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Loads the current user bassed on the given user_id
|
||||
*
|
||||
* @param STRING $user_id
|
||||
* @return boolean
|
||||
*/
|
||||
function loadUserOnSession($user_id=''){
|
||||
if(!empty($user_id)){
|
||||
$_SESSION['authenticated_user_id'] = $user_id;
|
||||
}
|
||||
|
||||
if(!empty($_SESSION['authenticated_user_id']) || !empty($user_id)){
|
||||
$GLOBALS['current_user'] = new User();
|
||||
if($GLOBALS['current_user']->retrieve($_SESSION['authenticated_user_id'])){
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user