From 847fb38194393f47c6333bce127e9ba084b214fb Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 15 Jul 2016 08:05:44 +0200 Subject: [PATCH] * NTLM: move ntlm login code from phpgwapi to api to allow NTLM login in 16.1 minimal install --- api/ntlm/README | 41 ++++++++++++++++ api/ntlm/egroupware.conf | 79 ++++++++++++++++++++++++++++++ api/ntlm/index.php | 102 +++++++++++++++++++++++++++++++++++++++ api/src/Egw.php | 2 +- 4 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 api/ntlm/README create mode 100644 api/ntlm/egroupware.conf create mode 100644 api/ntlm/index.php diff --git a/api/ntlm/README b/api/ntlm/README new file mode 100644 index 0000000000..ff3054dc46 --- /dev/null +++ b/api/ntlm/README @@ -0,0 +1,41 @@ +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. + +Firefox (at least 3.6) requires to manually enable NTLM Auth via about:config: +search for ntlm and set "network.automatic-ntlm-auth.trusted-uris" to the domain +your EGroupware install is using. Otherwise you will only get a popup to enter +username (with prepended windows domain eg. DOMAIN\username) and password. + +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/api/ntlm/egroupware.conf b/api/ntlm/egroupware.conf new file mode 100644 index 0000000000..154a766a99 --- /dev/null +++ b/api/ntlm/egroupware.conf @@ -0,0 +1,79 @@ +# +# Apache and PHP configuration for EGroupware using NTLM authentication +# +# This version of EGroupware configuration might not be as up to date as +# the one in /usr/share/doc/rpm-build/apache.conf! +# +# Version: $Id$ +# + +# this makes EGroupware available for all vhosts +Alias /egroupware /usr/share/egroupware + +# Enable ActiveSync protocol support via eSync app +Alias /Microsoft-Server-ActiveSync /usr/share/egroupware/activesync/index.php + +RedirectMatch ^/.well-known/(caldav|carddav)$ /egroupware/groupdav.php/ +# iOS 4.3+ calendar requires that to autodetect accounts +RedirectMatch ^(/principals/users/.*)$ /egroupware/groupdav.php$1 + + + 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 + + # Apache 2.4 + Order allow,deny + Allow from all + + + # Apache 2.4 + Require all granted + + 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 short_open_tag on + php_flag track_vars on + php_flag display_errors off + # E_ALL & ~E_NOTICE & ~E_STRICT = 8191 - 8 - 2048 = 6135 + php_value error_reporting 6135 + php_value max_execution_time 90 + php_admin_value mbstring.func_overload 0 + php_value memory_limit 128M + php_value session.gc_maxlifetime 14400 + php_value include_path . + php_admin_value open_basedir /usr/share/egroupware:/var/lib/egroupware:/tmp:/usr/bin/zip + php_value upload_max_filesize 64M + php_admin_value upload_tmp_dir /tmp + php_value post_max_size 65M + + + # Apache 2.4 + Order allow,deny + Deny from all + + + # Apache 2.4 + Require all denied + + + diff --git a/api/ntlm/index.php b/api/ntlm/index.php new file mode 100644 index 0000000000..1097049b6a --- /dev/null +++ b/api/ntlm/index.php @@ -0,0 +1,102 @@ + + * @copyright (c) 2008-2016 by Ralf Becker + * @version $Id$ + */ + +use EGroupware\Api; + +/** + * Check if given domain is either whitelisted, the current one or the EGroupware one + * + * Used to NOT redirect to arbitrary urls. + * + * @param string $url full url or just path, later is always allowed, as it stays within the domain + * @return boolean + */ +function check_domain($url) +{ + $whitelisted = array( + $_SERVER['HTTP_HOST'], // can contain :port + // add additional domains-names (just full qualified hostnames) here + + ); + if ($GLOBALS['egw_info']['server']['webserver_url'][0] === 'h') + { + $whitelisted[] = parse_url($GLOBALS['egw_info']['server']['webserver_url'], PHP_URL_HOST); + } + $parts = parse_url($url); + $host = $parts['host'].($parts['port'] ? ':'.$parts['port'] : ''); + + return $url[0] == '/' || in_array($host, $whitelisted); +} + +/** + * 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) + { + if (isset($_GET['forward']) && check_domain($_GET['forward'])) + { + header('Location: '.$_GET['forward']); + } + else + { + header('Location: ../../login.php'.(isset($_REQUEST['phpgw_forward']) ? '?phpgw_forward='.urlencode($_REQUEST['phpgw_forward']) : '')); + } + exit; + } + return $sessionid; +} + +$GLOBALS['egw_info']['flags'] = array( + 'noheader' => True, + 'currentapp' => 'api', + '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 (isset($_GET['forward']) && check_domain($_GET['forward'])) +{ + $forward = $_GET['forward']; + Api\Cache::setSession('login', 'referer', $forward); +} +elseif ($_REQUEST['phpgw_forward']) +{ + $forward = '../..'.(isset($_GET['phpgw_forward']) ? urldecode($_GET['phpgw_forward']) : @$_POST['phpgw_forward']); +} +else +{ + $forward = '../../index.php'; +} +// commiting the session, before redirecting might fix racecondition in session creation +$GLOBALS['egw']->session->commit_session(); +header('Location: '.$forward); diff --git a/api/src/Egw.php b/api/src/Egw.php index bfbb4fb689..6c8687c968 100644 --- a/api/src/Egw.php +++ b/api/src/Egw.php @@ -322,7 +322,7 @@ class Egw extends Egw\Base $query = preg_replace('/[&]?sessionid(=|%3D)[^&]+&kp3(=|%3D)[^&]+&domain=.*$/','',$_SERVER['QUERY_STRING']); if ($GLOBALS['egw_info']['server']['http_auth_types']) { - $redirect = '/phpgwapi/ntlm/index.php?'; + $redirect = '/api/ntlm/index.php?'; } else {