diff --git a/index.php b/index.php index f7e479c53e..03b8075b5c 100755 --- a/index.php +++ b/index.php @@ -17,15 +17,6 @@ exit; } - $GLOBALS['sessionid'] = isset($_GET['sessionid']) ? $_GET['sessionid'] : @$_COOKIE['sessionid']; - if(!$GLOBALS['sessionid']) - { - Header('Location: login.php'. - (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING']) ? - '?phpgw_forward='.urlencode('/index.php?'.$_SERVER['QUERY_STRING']):'')); - exit; - } - if(isset($_GET['hasupdates']) && $_GET['hasupdates'] == 'yes') { $hasupdates = True; diff --git a/phpgwapi/inc/class.auth.inc.php b/phpgwapi/inc/class.auth.inc.php index b68d05f60a..03e62a2ff1 100644 --- a/phpgwapi/inc/class.auth.inc.php +++ b/phpgwapi/inc/class.auth.inc.php @@ -11,10 +11,17 @@ * @version $Id$ */ +// allow to set an application depending authentication type (eg. for syncml, groupdav, ...) +if (isset($GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]) && + $GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]) +{ + $GLOBALS['egw_info']['server']['auth_type'] = $GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]; +} if(empty($GLOBALS['egw_info']['server']['auth_type'])) { $GLOBALS['egw_info']['server']['auth_type'] = 'sql'; } +//error_log('using auth_type='.$GLOBALS['egw_info']['server']['auth_type'].', currentapp='.$GLOBALS['egw_info']['flags']['currentapp']); include(EGW_API_INC.'/class.auth_'.$GLOBALS['egw_info']['server']['auth_type'].'.inc.php'); /** diff --git a/phpgwapi/inc/class.egw.inc.php b/phpgwapi/inc/class.egw.inc.php index 42d0dd7119..a4b5fc0976 100644 --- a/phpgwapi/inc/class.egw.inc.php +++ b/phpgwapi/inc/class.egw.inc.php @@ -131,7 +131,6 @@ class egw extends egw_minimal // setup the other subclasses $this->translation = new translation(); $this->common = new common(); - $this->auth = new auth(); $this->accounts = accounts::getInstance(); $this->acl = new acl(); /* Do not create the session object if called by the sessions class. This way @@ -277,7 +276,9 @@ class egw extends egw_minimal } // this removes the sessiondata if its saved in the URL $query = preg_replace('/[&]?sessionid(=|%3D)[^&]+&kp3(=|%3D)[^&]+&domain=.*$/','',$_SERVER['QUERY_STRING']); - Header('Location: '.$GLOBALS['egw_info']['server']['webserver_url'].'/login.php?cd=10&phpgw_forward='.urlencode($relpath.(!empty($query) ? '?'.$query : ''))); + $redirect = '/login.php?cd=10&'; + if ($GLOBALS['egw_info']['server']['http_auth_types']) $redirect = '/phpgwapi/ntlm/index.php?'; + Header('Location: '.$GLOBALS['egw_info']['server']['webserver_url'].$redirect.'phpgw_forward='.urlencode($relpath.(!empty($query) ? '?'.$query : ''))); exit; } } diff --git a/phpgwapi/inc/class.sessions.inc.php b/phpgwapi/inc/class.sessions.inc.php index 54cd1bfa93..053cf04d0a 100644 --- a/phpgwapi/inc/class.sessions.inc.php +++ b/phpgwapi/inc/class.sessions.inc.php @@ -560,9 +560,10 @@ * @param string $passwd user password * @param string $passwd_type type of password being used, ie plaintext, md5, sha1 * @param boolean $no_session_needed=false dont create a real session, eg. for GroupDAV clients using only basic auth, no cookie support + * @param boolean $auth_check=true if false, the user is loged in without checking his password (eg. for single sign on), default = true * @return string session id */ - function create($login,$passwd = '',$passwd_type = '',$no_session=false) + function create($login,$passwd = '',$passwd_type = '',$no_session=false,$auth_check=true) { if (is_array($login)) { @@ -577,6 +578,7 @@ $this->passwd = $passwd; $this->passwd_type = $passwd_type; } + //error_log(__METHOD__."($this->login,$this->passwd,$this->passwd_type,$no_session,$auth_check)"); $this->clean_sessions(); $this->split_login_domain($login,$this->account_lid,$this->account_domain); @@ -618,7 +620,7 @@ if (($blocked = $this->login_blocked($login,$user_ip)) || // too many unsuccessful attempts $GLOBALS['egw_info']['server']['global_denied_users'][$this->account_lid] || - !$GLOBALS['egw']->auth->authenticate($this->account_lid, $this->passwd, $this->passwd_type) || + $auth_check && !$GLOBALS['egw']->auth->authenticate($this->account_lid, $this->passwd, $this->passwd_type) || $this->account_id && $GLOBALS['egw']->accounts->get_type($this->account_id) == 'g') { $this->reason = $blocked ? 'blocked, too many attempts' : 'bad login or password'; diff --git a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php index 63c50bf5d0..8ddeedb1fd 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php @@ -244,51 +244,57 @@ class EGW_SyncML_State extends Horde_SyncML_State } - function isAuthorized() - { - if (!$this->_isAuthorized) { - - if(!isset($this->_locName) && !isset($this->_password)) + function isAuthorized() + { + if (!$this->_isAuthorized) { - Horde::logMessage('SyncML: Authentication not yet possible currently. Username and password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG); - return FALSE; - } - - if(!isset($this->_password)) - { - Horde::logMessage('SyncML: Authentication not yet possible currently. Password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG); - return FALSE; - } - - if(strpos($this->_locName,'@') === False) - { - $this->_locName .= '@'.$GLOBALS['egw_info']['server']['default_domain']; - } - - #Horde::logMessage('SyncML: authenticate with username: ' . $this->_locName . ' and password: ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG); - - if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text')) - { - $this->_isAuthorized = true; - Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + if(!isset($this->_locName) && !isset($this->_password)) + { + Horde::logMessage('SyncML: Authentication not yet possible currently. Username and password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + return FALSE; + } + + if(!isset($this->_password)) + { + Horde::logMessage('SyncML: Authentication not yet possible currently. Password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + return FALSE; + } + + if(strpos($this->_locName,'@') === False) + { + $this->_locName .= '@'.$GLOBALS['egw_info']['server']['default_domain']; + } + + #Horde::logMessage('SyncML: authenticate with username: ' . $this->_locName . ' and password: ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text')) + { + $this->_isAuthorized = true; + Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + } + else + { + $this->_isAuthorized = false; + Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_INFO); + } } + /* + * RalfBecker 2008-07-16: commented out, as return value is NOT used anyway + * It is not a security problem, as without a valid SyncML session + * one is created anyway. The horde SyncML codes handles that on it's own. + * Leaving it in gives problems with NTLM auth, as verify redirects there. + * else { - $this->_isAuthorized = false; - Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_INFO); - } - } - else - { - // store sessionID in a variable, because ->verify maybe resets that value - $sessionID = session_id(); - if(!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) { - Horde::logMessage('SyncML_EGW: egw session(' .$sessionID. ') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG); - } - } + // store sessionID in a variable, because ->verify maybe resets that value + $sessionID = session_id(); + if(!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) { + Horde::logMessage('SyncML_EGW: egw session(' .$sessionID. ') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + } + }*/ - return $this->_isAuthorized; - } + return $this->_isAuthorized; + } /** * Removes all locid<->guid mappings for the given type. diff --git a/phpgwapi/ntlm/README b/phpgwapi/ntlm/README new file mode 100644 index 0000000000..4e304f04e9 --- /dev/null +++ b/phpgwapi/ntlm/README @@ -0,0 +1,40 @@ +Steps to set up NTLM Single Sign On for eGroupWare 1.6 +====================================================== +(Version: $Id$) + +NTLM SSO removes Windows users on a PC, which is a member of a Windows domain +and who are logged into that domain, from the need to explicitly log into eGW. +They simply point IE to the eGW URL (eg. http://domain.com/egroupware/) and +start working. They can of cause explicitly log out and log in as an other user. + +As far as I tested, Firefox 3 only allows to enter user (including domain(!), eg. DOMAIN\user) +and password in a popup, which then get's checked from apache via winbind. +It does NOT automatically log you in, if you're logged into the domain on your PC! + +Here's in short what you need: +----------------------------- +1. eGW 1.6 running on Apache +2. a fully working and configured winbind configuration (not described here) +3. mod_ntlm_winbind (eg. for openSUSE from their package apache2-mod_auth_ntml_winbind) +4. an Apache configuration with the egroupware.conf in this directory (expecting eGW + to be installed in it's default location /usr/share/egroupware) or port the necessary + settings to your Apache configuration. + --> You NEED to change the domain from "TEST" to your used domain name! +5. Make the following changes in eGW's setup >> configuraition: + - HTTP auth types (comma-separated) to use without login-page, eg. "NTLM": NTLM + - Select which type of authentication you are using: ADS + This is not needed for NTLM authentication, but allows the users to use their windows + user and password to log into eGW, if they log in using an other browser or location. + - Host/IP Domain controler: ... <-- NEED to be filled out + - Domain name: ... <-- NEED to be filled out, same domain name as above +6. If you use EMail, you have to explicitly specify user/pw to use for contacting the IMAP + (and SMTP) server, it's no longer available to eGW! + +Please note the DC has to be started before you start winbind! + +The eGW code should work with every Apache authentication, which sets REMOTE_USER and AUTH_TYPE. +With slight modifications (different var names) it should work eg. with SSL client certificates. + +This feature was sponsored by Sponsored by Carl Knauber Holding GmbH und Co. KG. + +Ralf Becker \ No newline at end of file diff --git a/phpgwapi/ntlm/egroupware.conf b/phpgwapi/ntlm/egroupware.conf new file mode 100644 index 0000000000..f9d3a20444 --- /dev/null +++ b/phpgwapi/ntlm/egroupware.conf @@ -0,0 +1,58 @@ +# +# Apache and PHP configuration for eGroupWare using NTLM authentication +# +# Version: $Id$ +# + +Alias /egroupware /usr/share/egroupware + + + AuthName "NTLM eGroupWare Authentication" + NTLMAuth on + NegotiateAuth off + NTLMBasicRealm TEST + NTLMBasicAuth on + NTLMAuthHelper "/usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp" + NegotiateAuthHelper "/usr/bin/ntlm_auth --helper-protocol=gss-spnego" + PlaintextAuthHelper "/usr/bin/ntlm_auth --domain=TEST.LOCAL --helper-protocol=squid-2.5-basic" + NTLMBasicAuthoritative on + AuthType NTLM + require valid-user + + + + Options FollowSymLinks ExecCGI + AllowOverride None + Order allow,deny + Allow from all + DirectoryIndex index.html index.php + AddHandler cgi-script .cgi + AddDefaultCharset Off + php_flag file_uploads on + php_flag log_errors on + php_flag magic_quotes_gpc off + php_flag magic_quotes_runtime off + php_flag register_globals off + php_flag track_vars on + php_value error_reporting E_ALL + php_value max_execution_time 90 + php_value mbstring.func_overload 7 + php_value memory_limit 48M + php_value session.gc_maxlifetime 14400 + php_value open_basedir /usr/share/egroupware:/var/lib/egroupware:/tmp:/var/lib/php5 + php_value upload_max_filesize 16M + + Order allow,deny + Deny from all + + + + + php_value open_basedir / + + + + php_value mbstring.func_overload 0 + Order allow,deny + Allow from all + diff --git a/phpgwapi/ntlm/index.php b/phpgwapi/ntlm/index.php new file mode 100644 index 0000000000..27370a4aa6 --- /dev/null +++ b/phpgwapi/ntlm/index.php @@ -0,0 +1,61 @@ + + * @copyright (c) 2008 by Ralf Becker + * @version $Id$ + */ + +/** + * check if the given user has access + * + * Create a session or if the user has no account return authenticate header and 401 Unauthorized + * + * @param array &$account + * @return int session-id + */ +function check_access(&$account) +{ + //error_log("AUTH_TYPE={$_SERVER['AUTH_TYPE']}, REMOTE_USER={$_SERVER['REMOTE_USER']}, HTTP_USER_AGENT={$_SERVER['HTTP_USER_AGENT']}, http_auth_types={$GLOBALS['egw_info']['server']['http_auth_types']}"); + + if (isset($_SERVER['REMOTE_USER']) && $_SERVER['REMOTE_USER'] && isset($_SERVER['AUTH_TYPE']) && + isset($GLOBALS['egw_info']['server']['http_auth_types']) && $GLOBALS['egw_info']['server']['http_auth_types'] && + in_array(strtoupper($_SERVER['AUTH_TYPE']),explode(',',strtoupper($GLOBALS['egw_info']['server']['http_auth_types'])))) + { + if (strpos($account=$_SERVER['REMOTE_USER'],'\\') !== false) + { + list(,$account) = explode('\\',$account,2); + } + $sessionid = $GLOBALS['egw']->session->create($account,null,'ntlm',false,false); // false=no auth check + //error_log("create('$account',null,'ntlm',false,false)=$sessionid ({$GLOBALS['egw']->session->reason})"); + } + if (!$sessionid) + { + header('Location: ../../login.php'.(isset($_REQUEST['phpgw_forward']) ? '?'.$_REQUEST['phpgw_forward'] : '')); + exit; + } + return $sessionid; +} + +$GLOBALS['egw_info']['flags'] = array( + 'noheader' => True, + 'currentapp' => 'home', + 'autocreate_session_callback' => 'check_access', +); +// if you move this file somewhere else, you need to adapt the path to the header! +include(dirname(__FILE__).'/../../header.inc.php'); + +if ($_REQUEST['phpgw_forward']) +{ + $forward = '../../'.(isset($_GET['phpgw_forward']) ? urldecode($_GET['phpgw_forward']) : @$_POST['phpgw_forward']); +} +else +{ + $forward = '../../index.php'; +} +header('Location: '.$forward); \ No newline at end of file diff --git a/rpc.php b/rpc.php index 52ec9a5181..39ebf340dd 100644 --- a/rpc.php +++ b/rpc.php @@ -24,6 +24,9 @@ $GLOBALS['egw_info'] = array( ); include('./header.inc.php'); +// allow to use an authentication specific for SyncML +$GLOBALS['egw_info']['flags']['currentapp'] = 'syncml'; + $errors = array(); // SyncML works currently only with PHP sessions diff --git a/setup/templates/default/config.tpl b/setup/templates/default/config.tpl index 70c86c28d9..fc113af715 100644 --- a/setup/templates/default/config.tpl +++ b/setup/templates/default/config.tpl @@ -175,7 +175,7 @@ {lang_Authentication_/_Accounts} - + {lang_Select_which_type_of_authentication_you_are_using}: + + + + + + + + + + + + + + + {lang_Authentication_type_for_application}: GroupDAV/CalDAV/CardDAV + + + + + + + {lang_HTTP_auth_types_(comma-separated)_to_use_without_login-page, eg. "NTLM"}: + + + + {lang_Select_where_you_want_to_store/retrieve_user_accounts}: