View Issue Details

IDProjectCategoryView StatusLast Update
0007568mantisbtauthenticationpublic2014-11-07 16:10
Reporterjoshua_chan Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status newResolutionopen 
Product Version1.0.5 
Target VersionFixed in Version 
Summary0007568: CAS Authentication with phpCAS
Description

I have added support for phpCAS authentication. The affected files will be included here.

Steps To Reproduce

phpCAS must be installed on the server.
http://esup-phpcas.sourceforge.net/

Tagspatch

Relationships

has duplicate 0004234 closedvboctor CAS authentication 

Activities

2006-11-06 20:58

 

mantis-1.0.5-phpCAS_changes.tar.gz (31,477 bytes)
joshua_chan

joshua_chan

2006-11-06 20:59

reporter   ~0013686

Files affected:

core/authentication_api.php
core/ldap_api.php
core/constant_inc.php
login_page.php
login.php
config_defaults_inc.php

TOTOleHero

TOTOleHero

2006-11-09 05:51

reporter   ~0013705

We have pb with CAS and direct issue access.

I have add some features to phpCAS to use direct access and CAS.

You must apply patch to phpCAS : (phpCAS_service_url_encode.diff) http://sourceforge.net/tracker/download.php?group_id=88445&atid=586709&file_id=202061&aid=1593269

and add in file : core\authentication_api.php

Just after this line : phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);

Add : phpCAS::setEncodingUrl(true);

2007-11-28 09:23

 

mantis-1.1.0rc2_cas.patch (12,555 bytes)
diff -rbup mantis/config_defaults_inc.php mantis-cas/config_defaults_inc.php
--- mantis/config_defaults_inc.php	2007-10-24 07:35:38.000000000 +0200
+++ mantis-cas/config_defaults_inc.php	2007-11-28 15:05:05.000000000 +0100
@@ -873,6 +873,22 @@
 	$g_hr_width				= 50;
 
 	#############################
+	# Mantis CAS Settings
+	#############################
+
+	# --- using phpCAS -------------
+	$g_cas_server = 'example.com.au';
+	$g_cas_port = 443;
+	$g_cas_uri = '';             # e.g. '/cas'
+	$g_cas_version = '2.0';
+	# --- CAS + LDAP -------------
+	$g_cas_use_ldap     = OFF;   # translate CAS username through LDAP
+	$g_ldap_mantis_uid  = 'uid'; # The LDAP field matching the Mantis username
+	$g_cas_ldap_update  = OFF;   # Should we update user details from LDAP?
+	$g_cas_ldap_update_fields = ''; # e.g. 'cn,userpassword'
+	$g_cas_ldap_update_map    = ''; # e.g. 'realname,password'
+
+	#############################
 	# Mantis LDAP Settings
 	#############################
 
@@ -1147,7 +1163,7 @@
 	$g_set_status_threshold = array();
 
 	# --- login method ----------------
-	# CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	# CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH or CAS_AUTH
 	# You can simply change this at will. Mantis will try to figure out how the passwords were encrypted.
 	$g_login_method				= MD5;
 
diff -rbup mantis/core/authentication_api.php mantis-cas/core/authentication_api.php
--- mantis/core/authentication_api.php	2007-11-21 16:19:41.000000000 +0100
+++ mantis-cas/core/authentication_api.php	2007-11-28 15:15:03.000000000 +0100
@@ -23,6 +23,171 @@
 
 	require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'gpc_api.php' );
 
+	# --------------------
+	# PHP4 hack
+	# --------------------
+	if(!function_exists('array_combine')) {
+		function array_combine($keys, $values) {
+			if(count($keys) < 1 || count($keys) != count($values) || !is_array($keys) || !is_array($values)) {
+				return false;
+			}
+
+			$keys = array_values($keys);
+			$values = array_values($values);
+			for($x=0; $x < count($keys); $x++) {
+				$return_array[$keys[$x]] = $values[$x];
+			}
+
+			return $return_array;
+		}
+	}
+
+    ## CAS functions and settings
+    
+    # --------------------
+    # Initializes phpCAS
+    #
+    function auth_cas_init() {
+        # phpCAS must be installed
+        require_once('CAS/CAS.php');
+    
+        static $s_initialized=false;
+        
+        if (! $s_initialized ) {
+            phpCAS::setDebug();
+            ## These should be set in config_inc.php
+            ## $g_login_method = CAS_AUTH;
+            $t_server_version = config_get( 'cas_version' );
+            $t_server_cas_server = config_get( 'cas_server' );
+            $t_server_port = config_get( 'cas_port' );
+            $t_server_uri = config_get( 'cas_uri' );
+            $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+            
+            phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+            
+            $s_initialized = true;
+        }
+    
+    }
+
+
+    # --------------------
+    # Fetches the user's CAS name, authenticating if needed
+    # Can translate name through LDAP
+    #
+    function auth_cas_get_name()
+    {
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        phpCAS::forceAuthentication();
+        $t_cas_id =  phpCAS::getUser();
+
+        # If needed, translate the CAS username through LDAP        
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+            $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }        
+        return $t_username;
+    }
+
+
+    # --------------------
+    # Takes an ID string, and looks up the LDAP directory to find
+    # the matching username for Mantis.
+    #
+    # Optionally, also update the user information in the Mantis user
+    # table.
+    #
+    # @param $p_cas_id [STRING] Typically, the username given by phpCAS
+    # @param $p_update_user [BOOLEAN] Whether or not to update user details from LDAP
+    #
+    function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+    {
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+        
+	$t_ldap_organization = config_get( 'ldap_organization' );
+	$t_ldap_root_dn	= config_get( 'ldap_root_dn' );
+		
+        # Required fields in LDAP for CAS
+	$t_ldap_uid_field = config_get( 'cas_ldap_uid_field', 'uid' ) ;
+	$t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+	# User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+	$t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+	$t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);  # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+	$t_sr = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+	$t_info	= ldap_get_entries( $t_ds, $t_sr );
+	# Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+            # Get Mantis username
+            $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+            
+            # @@@ The fact that we got here means the user is authenticated
+            # @@@ by CAS, and has an LDAP entry.
+            # @@@ We might as well update other user details since we are here.
+
+            # If no argument given, check settings
+            if ( '' == $p_update_user ) {
+                $p_update_user = config_get( 'cas_ldap_update', FALSE );
+            }
+            # If there's a user record, then update it
+            if ( $p_update_user ) {
+                # Only proceed if the field map arrays are the same length
+                $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                if ($t_field_map) {
+                    # If user is new, then we must create their account before updating it
+                    # @@@ ( make sure $g_allow_blank_email == ON )
+                    $t_userid = user_get_id_by_name($t_username);
+                    if ( false == $t_userid ) {
+                        user_create( $t_username, '' );
+                        # @@@ Wow, this is pretty lame
+                        $t_userid = user_get_id_by_name($t_username);                        
+                    }
+                    # @@@ maybe we can optimize this to write all fields at once?
+                    foreach ( $t_field_map as $key=>$t_userfield ) {
+                        if (isset($t_info[0][$key][0])) {
+                            user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                        }
+                    }
+                }
+            }
+            
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+        
+        return $t_username;
+    }
+
+    
+    # --------------------
+    # Logs out of CAS, redirecting to Mantis on re-login
+    # User should already be logged out of Mantis by the time this is called
+    # (see auth_logout)
+    #
+    function auth_cas_logout()
+    {
+        $t_path = config_get('path');
+        
+        auth_cas_init();
+        phpCAS::logout($t_path);
+    }
+
+
+
+
 	### Authentication API ###
 
 	$g_script_login_cookie = null;
@@ -81,9 +246,11 @@
 
 		$t_login_method = config_get( 'login_method' );
 
+        # @@@ added by Joshua: CAS_AUTH
 		if ( false === $t_user_id ) {
-			if ( BASIC_AUTH == $t_login_method ) {
-				# attempt to create the user if using BASIC_AUTH
+			if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+				# attempt to create the user if using BASIC_AUTH or CAS_AUTH
+                # ( make sure $g_allow_blank_email == ON )
 				$t_cookie_string = user_create( $p_username, $p_password );
 
 				if ( false === $t_cookie_string ) {
@@ -194,6 +361,13 @@
         if (auth_clear_cookies()) {
             helper_clear_pref_cookies();
         }
+
+    	# @@@ added by Joshua
+    	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+            # Redirect to CAS page to logout
+            auth_cas_logout();
+    	}
+
 		return true;
 	}
 
@@ -207,11 +381,24 @@
 	function auth_does_password_match( $p_user_id, $p_test_password ) {
 		$t_configured_login_method = config_get( 'login_method' );
 
+        # @@@ added by Joshua
+        if ( CAS_AUTH == $t_configured_login_method ) {
+            # CAS takes care of password verification for us
+            return true;
+        }
+
 		if ( LDAP == $t_configured_login_method ) {
 			return ldap_authenticate( $p_user_id, $p_test_password );
 		}
 
 		$t_password			= user_get_field( $p_user_id, 'password' );
+		# @@@ added by Joshua
+		# Allow for packed MD5 passwords
+        if (substr($t_password, 0, 5) == '{MD5}') {
+            # Unpack the stored password into MD5 for comparison
+            $temp = unpack('H*', base64_decode( substr( $t_password, 5 ) ));
+            $t_password = $temp[1];
+        }
 		$t_login_methods	= Array(MD5, CRYPT, PLAIN);
 		foreach ( $t_login_methods as $t_login_method ) {
 
diff -rbup mantis/core/constant_inc.php mantis-cas/core/constant_inc.php
--- mantis/core/constant_inc.php	2007-10-14 00:35:18.000000000 +0200
+++ mantis-cas/core/constant_inc.php	2007-11-27 16:45:49.000000000 +0100
@@ -116,6 +116,7 @@
 	define( 'LDAP',				4 );
 	define( 'BASIC_AUTH',		5 );
 	define( 'HTTP_AUTH',		6 );
+	define( 'CAS_AUTH',         7 );
 
 	# file upload methods
 	define( 'DISK',			1 );
diff -rbup mantis/core/ldap_api.php mantis-cas/core/ldap_api.php
--- mantis/core/ldap_api.php	2007-11-21 16:08:26.000000000 +0100
+++ mantis-cas/core/ldap_api.php	2007-11-27 16:51:30.000000000 +0100
@@ -28,8 +28,10 @@
  	# --------------------
 	# Connect and bind to the LDAP directory
 	function ldap_connect_bind( $p_binddn = '', $p_password = '' ) {
+		# @@@ added by Joshua: ldap_ver
 		$t_ldap_server	= config_get( 'ldap_server' );
 		$t_ldap_port	= config_get( 'ldap_port' );
+		$t_ldap_ver	= config_get( 'ldap_ver', 3 );
 
 		if (!extension_loaded('ldap')) {
 			trigger_error(ERROR_LDAP_EXTENSION_NOT_LOADED,ERROR);
@@ -37,6 +39,7 @@
 		
 		$t_ds = @ldap_connect ( $t_ldap_server, $t_ldap_port );
 		if ( $t_ds > 0 ) {
+			ldap_set_option($t_ds, LDAP_OPT_PROTOCOL_VERSION, $t_ldap_ver);
 			$t_protocol_version = config_get( 'ldap_protocol_version' );
 
 			if ( $t_protocol_version > 0 ) {
diff -rbup mantis/login_page.php mantis-cas/login_page.php
--- mantis/login_page.php	2007-11-21 16:21:09.000000000 +0100
+++ mantis-cas/login_page.php	2007-11-27 16:45:49.000000000 +0100
@@ -35,8 +35,9 @@
 	$f_return		= gpc_get_string( 'return', '' );
 
 	# Check for HTTP_AUTH. HTTP_AUTH is handled in login.php
-
-	if ( HTTP_AUTH == config_get( 'login_method' ) ) {
+	# And now CAS_AUTH too -- Joshua
+	if ( in_array(config_get( 'login_method' ), array( HTTP_AUTH, CAS_AUTH )) )
+	{
 		$t_uri = "login.php";
 
 		if ( !$f_return && ON == config_get( 'allow_anonymous_login' ) ) {
diff -rbup mantis/login.php mantis-cas/login.php
--- mantis/login.php	2007-10-14 00:33:18.000000000 +0200
+++ mantis-cas/login.php	2007-11-27 16:45:49.000000000 +0100
@@ -33,12 +33,19 @@
 	$f_return		= gpc_get_string( 'return', config_get( 'default_home_page' ) );
 	$f_from			= gpc_get_string( 'from', '' );
 
-	if ( BASIC_AUTH == config_get( 'login_method' ) ) {
+    // Added by Joshua (17 October 2006)
+    if ( CAS_AUTH == config_get( 'login_method' ) ) {
+        // This will detour to the CAS login page if needed
+        $f_username = auth_cas_get_name();
+        $f_password = '';
+    }
+
+	else if ( BASIC_AUTH == config_get( 'login_method' ) ) {
 		$f_username = $_SERVER['REMOTE_USER'];
 		$f_password = $_SERVER['PHP_AUTH_PW'];
  	}
 
-	if ( HTTP_AUTH == config_get( 'login_method' ) ) {
+	else if ( HTTP_AUTH == config_get( 'login_method' ) ) {
 		if ( !auth_http_is_logout_pending() )
 		{
 			if ( isset( $_SERVER['PHP_AUTH_USER'] ) )
mantis-1.1.0rc2_cas.patch (12,555 bytes)
lmeunier

lmeunier

2007-11-28 09:24

reporter   ~0016320

This patch work against Mantis 1.1.0rc2.

foo

foo

2008-01-17 17:10

reporter   ~0016707

Any big changes between 1.1.0 rc2 and GA? I'd love to try this, as we use CAS for most of our core web apps.

Also, any chance this could be targeted for a real release? That would be sweet.

wdouglascampbell

wdouglascampbell

2008-07-15 04:03

reporter   ~0018535

The patch by TOTOleHero should not be used for more recent version of phpCAS (0.6.0 in particular) as it is already fixed and the patch then causes things to break.

The rest of the changes appear to work find with Mantis 1.1.2

2008-10-21 11:59

 

mantis-1.1.4+phpcas-1.0.1.patch (13,018 bytes)
diff -ru mantis/config_defaults_inc.php mantis+cas/config_defaults_inc.php
--- mantis/config_defaults_inc.php	Tue Oct 14 18:24:01 2008
+++ mantis+cas/config_defaults_inc.php	Tue Oct 21 11:33:02 2008
@@ -306,7 +306,7 @@
 	# note if you allow users to create their own accounts, they
 	#  must specify an email at that point, no matter what the value
 	#  of this option is.  Otherwise they wouldn't get their passwords.
-	$g_allow_blank_email	= OFF;
+	$g_allow_blank_email	= ON;
 
 	# Only allow and send email to addresses in the given domain
 	# For example:
@@ -892,6 +892,22 @@
 	$g_hr_width				= 50;
 
 	#############################
+	# Mantis CAS Settings
+	#############################
+
+	# --- using phpCAS -------------
+	$g_cas_server = 'example.com.au';
+	$g_cas_port = 443;
+	$g_cas_uri = '';             # e.g. '/cas'
+	$g_cas_version = '2.0';
+	# --- CAS + LDAP -------------
+	$g_cas_use_ldap     = OFF;   # translate CAS username through LDAP
+	$g_ldap_mantis_uid  = 'uid'; # The LDAP field matching the Mantis username
+	$g_cas_ldap_update  = OFF;   # Should we update user details from LDAP?
+	$g_cas_ldap_update_fields = ''; # e.g. 'cn,userpassword'
+	$g_cas_ldap_update_map    = ''; # e.g. 'realname,password'
+
+	#############################
 	# Mantis LDAP Settings
 	#############################
 
@@ -1166,9 +1182,9 @@
 	$g_set_status_threshold = array();
 
 	# --- login method ----------------
-	# CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	# CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH or CAS_AUTH
 	# You can simply change this at will. Mantis will try to figure out how the passwords were encrypted.
-	$g_login_method				= MD5;
+	$g_login_method				= CAS_AUTH;
 
 	# --- limit reporters -------------
 	# Set to ON if you wish to limit reporters to only viewing bugs that they report.
diff -ru mantis/login.php mantis+cas/login.php
--- mantis/login.php	Sat Oct 13 18:36:41 2007
+++ mantis+cas/login.php	Tue Oct 21 11:33:02 2008
@@ -33,12 +33,19 @@
 	$f_return		= gpc_get_string( 'return', config_get( 'default_home_page' ) );
 	$f_from			= gpc_get_string( 'from', '' );
 
-	if ( BASIC_AUTH == config_get( 'login_method' ) ) {
+    // Added by Joshua (17 October 2006)
+    if ( CAS_AUTH == config_get( 'login_method' ) ) {
+        // This will detour to the CAS login page if needed
+        $f_username = auth_cas_get_name();
+        $f_password = '';
+    }
+
+	else if ( BASIC_AUTH == config_get( 'login_method' ) ) {
 		$f_username = $_SERVER['REMOTE_USER'];
 		$f_password = $_SERVER['PHP_AUTH_PW'];
  	}
 
-	if ( HTTP_AUTH == config_get( 'login_method' ) ) {
+	else if ( HTTP_AUTH == config_get( 'login_method' ) ) {
 		if ( !auth_http_is_logout_pending() )
 		{
 			if ( isset( $_SERVER['PHP_AUTH_USER'] ) )
diff -ru mantis/login_page.php mantis+cas/login_page.php
--- mantis/login_page.php	Sat Oct 13 18:36:41 2007
+++ mantis+cas/login_page.php	Tue Oct 21 11:33:02 2008
@@ -35,8 +35,9 @@
 	$f_return		= gpc_get_string( 'return', '' );
 
 	# Check for HTTP_AUTH. HTTP_AUTH is handled in login.php
-
-	if ( HTTP_AUTH == config_get( 'login_method' ) ) {
+	# And now CAS_AUTH too -- Joshua
+	if ( in_array(config_get( 'login_method' ), array( HTTP_AUTH, CAS_AUTH )) )
+	{
 		$t_uri = "login.php";
 
 		if ( !$f_return && ON == config_get( 'allow_anonymous_login' ) ) {
diff -ru mantis/core/authentication_api.php mantis+cas/core/authentication_api.php
--- mantis/core/authentication_api.php	Sat Sep 27 10:28:01 2008
+++ mantis+cas/core/authentication_api.php	Tue Oct 21 11:34:39 2008
@@ -23,6 +23,173 @@
 
 	require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'gpc_api.php' );
 
+	# --------------------
+	# PHP4 hack
+	# --------------------
+	if(!function_exists('array_combine')) {
+		function array_combine($keys, $values) {
+			if(count($keys) < 1 || count($keys) != count($values) || !is_array($keys) || !is_array($values)) {
+				return false;
+			}
+
+			$keys = array_values($keys);
+			$values = array_values($values);
+			for($x=0; $x < count($keys); $x++) {
+				$return_array[$keys[$x]] = $values[$x];
+			}
+
+			return $return_array;
+		}
+	}
+
+    ## CAS functions and settings
+    
+    # --------------------
+    # Initializes phpCAS
+    #
+    function auth_cas_init() {
+        # phpCAS must be installed
+        require_once('CAS/CAS.php');
+    
+        static $s_initialized=false;
+        
+        if (! $s_initialized ) {
+            phpCAS::setDebug();
+            ## These should be set in config_inc.php
+            ## $g_login_method = CAS_AUTH;
+            $t_server_version = config_get( 'cas_version' );
+            $t_server_cas_server = config_get( 'cas_server' );
+            $t_server_port = config_get( 'cas_port' );
+            $t_server_uri = config_get( 'cas_uri' );
+            $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+            
+            phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+            
+            $s_initialized = true;
+        }
+    
+    }
+
+
+    # --------------------
+    # Fetches the user's CAS name, authenticating if needed
+    # Can translate name through LDAP
+    #
+    function auth_cas_get_name()
+    {
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        // no SSL validation for the CAS server
+        phpCAS::setNoCasServerValidation();
+        phpCAS::forceAuthentication();
+        $t_cas_id =  phpCAS::getUser();
+
+        # If needed, translate the CAS username through LDAP        
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+            $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }        
+        return $t_username;
+    }
+
+
+    # --------------------
+    # Takes an ID string, and looks up the LDAP directory to find
+    # the matching username for Mantis.
+    #
+    # Optionally, also update the user information in the Mantis user
+    # table.
+    #
+    # @param $p_cas_id [STRING] Typically, the username given by phpCAS
+    # @param $p_update_user [BOOLEAN] Whether or not to update user details from LDAP
+    #
+    function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+    {
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+        
+	$t_ldap_organization = config_get( 'ldap_organization' );
+	$t_ldap_root_dn	= config_get( 'ldap_root_dn' );
+		
+        # Required fields in LDAP for CAS
+	$t_ldap_uid_field = config_get( 'cas_ldap_uid_field', 'uid' ) ;
+	$t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+	# User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+	$t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+	$t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);  # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+	$t_sr = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+	$t_info	= ldap_get_entries( $t_ds, $t_sr );
+	# Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+            # Get Mantis username
+            $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+            
+            # @@@ The fact that we got here means the user is authenticated
+            # @@@ by CAS, and has an LDAP entry.
+            # @@@ We might as well update other user details since we are here.
+
+            # If no argument given, check settings
+            if ( '' == $p_update_user ) {
+                $p_update_user = config_get( 'cas_ldap_update', FALSE );
+            }
+            # If there's a user record, then update it
+            if ( $p_update_user ) {
+                # Only proceed if the field map arrays are the same length
+                $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                if ($t_field_map) {
+                    # If user is new, then we must create their account before updating it
+                    # @@@ ( make sure $g_allow_blank_email == ON )
+                    $t_userid = user_get_id_by_name($t_username);
+                    if ( false == $t_userid ) {
+                        user_create( $t_username, '' );
+                        # @@@ Wow, this is pretty lame
+                        $t_userid = user_get_id_by_name($t_username);                        
+                    }
+                    # @@@ maybe we can optimize this to write all fields at once?
+                    foreach ( $t_field_map as $key=>$t_userfield ) {
+                        if (isset($t_info[0][$key][0])) {
+                            user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                        }
+                    }
+                }
+            }
+            
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+        
+        return $t_username;
+    }
+
+    
+    # --------------------
+    # Logs out of CAS, redirecting to Mantis on re-login
+    # User should already be logged out of Mantis by the time this is called
+    # (see auth_logout)
+    #
+    function auth_cas_logout()
+    {
+        $t_path = config_get('path');
+        
+        auth_cas_init();
+        phpCAS::logoutWithUrl($t_path);
+    }
+
+
+
+
 	### Authentication API ###
 
 	$g_script_login_cookie = null;
@@ -81,9 +248,11 @@
 
 		$t_login_method = config_get( 'login_method' );
 
+        # @@@ added by Joshua: CAS_AUTH
 		if ( false === $t_user_id ) {
-			if ( BASIC_AUTH == $t_login_method ) {
-				# attempt to create the user if using BASIC_AUTH
+			if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+				# attempt to create the user if using BASIC_AUTH or CAS_AUTH
+                # ( make sure $g_allow_blank_email == ON )
 				$t_cookie_string = user_create( $p_username, $p_password );
 
 				if ( false === $t_cookie_string ) {
@@ -195,6 +364,12 @@
             helper_clear_pref_cookies();
         }
 
+        # @@@ added by Joshua
+        if ( CAS_AUTH == config_get( 'login_method' ) ) {
+             # Redirect to CAS page to logout
+             auth_cas_logout();
+        }
+
 		session_clean();
 
 		return true;
@@ -210,11 +385,24 @@
 	function auth_does_password_match( $p_user_id, $p_test_password ) {
 		$t_configured_login_method = config_get( 'login_method' );
 
+        # @@@ added by Joshua
+        if ( CAS_AUTH == $t_configured_login_method ) {
+            # CAS takes care of password verification for us
+            return true;
+        }
+
 		if ( LDAP == $t_configured_login_method ) {
 			return ldap_authenticate( $p_user_id, $p_test_password );
 		}
 
 		$t_password			= user_get_field( $p_user_id, 'password' );
+		# @@@ added by Joshua
+		# Allow for packed MD5 passwords
+        if (substr($t_password, 0, 5) == '{MD5}') {
+            # Unpack the stored password into MD5 for comparison
+            $temp = unpack('H*', base64_decode( substr( $t_password, 5 ) ));
+            $t_password = $temp[1];
+        }
 		$t_login_methods	= Array(MD5, CRYPT, PLAIN);
 		foreach ( $t_login_methods as $t_login_method ) {
 
diff -ru mantis/core/constant_inc.php mantis+cas/core/constant_inc.php
--- mantis/core/constant_inc.php	Thu Oct 16 16:30:13 2008
+++ mantis+cas/core/constant_inc.php	Tue Oct 21 11:33:02 2008
@@ -116,6 +116,7 @@
 	define( 'LDAP',				4 );
 	define( 'BASIC_AUTH',		5 );
 	define( 'HTTP_AUTH',		6 );
+	define( 'CAS_AUTH',         7 );
 
 	# file upload methods
 	define( 'DISK',			1 );
diff -ru mantis/core/ldap_api.php mantis+cas/core/ldap_api.php
--- mantis/core/ldap_api.php	Sat Oct 13 18:36:41 2007
+++ mantis+cas/core/ldap_api.php	Tue Oct 21 11:33:02 2008
@@ -28,8 +28,10 @@
  	# --------------------
 	# Connect and bind to the LDAP directory
 	function ldap_connect_bind( $p_binddn = '', $p_password = '' ) {
+		# @@@ added by Joshua: ldap_ver
 		$t_ldap_server	= config_get( 'ldap_server' );
 		$t_ldap_port	= config_get( 'ldap_port' );
+		$t_ldap_ver	= config_get( 'ldap_ver', 3 );
 
 		if (!extension_loaded('ldap')) {
 			trigger_error(ERROR_LDAP_EXTENSION_NOT_LOADED,ERROR);
@@ -37,6 +39,7 @@
 		
 		$t_ds = @ldap_connect ( $t_ldap_server, $t_ldap_port );
 		if ( $t_ds > 0 ) {
+			ldap_set_option($t_ds, LDAP_OPT_PROTOCOL_VERSION, $t_ldap_ver);
 			$t_protocol_version = config_get( 'ldap_protocol_version' );
 
 			if ( $t_protocol_version > 0 ) {
mstrumyla

mstrumyla

2008-10-21 12:01

reporter   ~0019620

I updated the patch using mantis 1.1.4 and phpCAS 1.0.1. It changes the original patch to use CAS authentication instead of MD5.

2009-02-19 14:46

 

mantis-1.2.0a3_cas.patch (11,268 bytes)
diff -ru mantis-1.2.0a3/config_defaults_inc.php mantis-1.2.0a3.CAS/config_defaults_inc.php
--- mantis-1.2.0a3/config_defaults_inc.php	2009-01-16 00:04:59.000000000 +0800
+++ mantis-1.2.0a3.CAS/config_defaults_inc.php	2009-02-20 02:06:55.000000000 +0800
@@ -464,7 +464,7 @@
 	 * of this option is.  Otherwise they wouldn't get their passwords.
 	 * @global int $g_allow_blank_email
 	 */	
-	$g_allow_blank_email	= OFF;
+	$g_allow_blank_email	= ON;
 
 	/**
 	 * Only allow and send email to addresses in the given domain
@@ -1625,6 +1625,65 @@
 	 */	
 	$g_hr_width				= 50;
 
+
+	/***********************
+	 * Mantis CAS Settings *
+	 ***********************/
+
+	# --- using phpCAS -------------
+	/**
+	 * @global string $g_cas_server
+	 */
+	$g_cas_server = 'example.com.au';
+
+	/**
+	 * @global int $g_cas_port
+	 */
+	$g_cas_port = 443;
+
+	/**
+	 * The CAS path on the server. E.g. '/cas'
+	 * @global int $g_cas_uri
+	 */
+	$g_cas_uri = '';
+
+	/**
+	 * @global $g_cas_version string
+	 */
+	$g_cas_version = '2.0';
+
+	# --- CAS + LDAP -------------
+	/**
+	 * Translate CAS username through LDAP.
+	 * @global $g_cas_use_ldap int
+	 */
+	$g_cas_use_ldap     = OFF;
+
+	/**
+	 * The LDAP field matching the Mantis username.
+	 * @global $g_ldap_mantis_udi string
+	 */
+	$g_ldap_mantis_uid  = 'uid';
+
+	/**
+	 * Should Mantis update user details from LDAP while authenticating with CAS?
+	 * @global $g_cas_ldap_update int
+	 */
+	$g_cas_ldap_update  = OFF;
+
+	/**
+	 * E.g. 'cn,userpassword'.
+	 * @global $g_cas_ldap_update_fields string
+	 */
+	$g_cas_ldap_update_fields = '';
+
+	/**
+	 * E.g. 'realname,password'.
+	 * @global $g_cas_ldap_update_map string
+	 */
+	$g_cas_ldap_update_map    = '';
+
+
 	/**************************
 	 * MantisBT LDAP Settings *
 	 **************************/
@@ -2149,11 +2208,11 @@
 
 	/**
 	 * login method
-	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH or CAS_AUTH
 	 * You can simply change this at will. MantisBT will try to figure out how the passwords were encrypted.
 	 * @global int $g_login_method
 	 */	
-	$g_login_method				= MD5;
+	$g_login_method				= CAS_AUTH;
 
 	/**
 	 * limit reporters
Only in mantis-1.2.0a3: config_inc.php
diff -ru mantis-1.2.0a3/core/authentication_api.php mantis-1.2.0a3.CAS/core/authentication_api.php
--- mantis-1.2.0a3/core/authentication_api.php	2009-01-16 00:04:59.000000000 +0800
+++ mantis-1.2.0a3.CAS/core/authentication_api.php	2009-02-20 03:36:04.000000000 +0800
@@ -52,6 +52,178 @@
  */
 $g_cache_current_user_id = null;
 
+
+/*************
+ * PHP4 hack *
+ *************/
+if(!function_exists('array_combine')) {
+	function array_combine($keys, $values) {
+		if(count($keys) < 1 || count($keys) != count($values) || !is_array($keys) || !is_array($values)) {
+			return false;
+		}
+
+		$keys = array_values($keys);
+		$values = array_values($values);
+		for($x=0; $x < count($keys); $x++) {
+			$return_array[$keys[$x]] = $values[$x];
+		}
+
+		return $return_array;
+	}
+}
+
+/**
+ * Initialize phpCAS.
+ */
+function auth_cas_init() {
+	# phpCAS must be installed in the include path
+	# or in the Mantis directory.
+	require_once('CAS/CAS.php');
+
+	static $s_initialized=false;
+
+	if (! $s_initialized ) {
+		phpCAS::setDebug();
+        ## These should be set in config_inc.php
+		$t_server_version = config_get( 'cas_version' );
+		$t_server_cas_server = config_get( 'cas_server' );
+		$t_server_port = config_get( 'cas_port' );
+		$t_server_uri = config_get( 'cas_uri' );
+		$t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+
+		phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+		if (method_exists('phpCAS', 'setNoCasServerValidation')) {
+			// no SSL validation for the CAS server
+			phpCAS::setNoCasServerValidation();
+		}
+
+		$s_initialized = true;
+	}
+
+}
+
+
+/**
+ * Fetches the user's CAS name, authenticating if needed.
+ * Can translate CAS login name to Mantis username through LDAP.
+ */
+function auth_cas_get_name()
+{
+	# Get CAS username from phpCAS
+	auth_cas_init();
+	phpCAS::forceAuthentication();
+	$t_cas_id = phpCAS::getUser();
+
+	# If needed, translate the CAS username through LDAP
+	$t_username = $t_cas_id;
+	if (config_get( 'cas_use_ldap', false )) {
+		$t_username = auth_cas_ldap_translate( $t_cas_id );
+	}
+	return $t_username;
+}
+
+
+/**
+ * Takes an ID string, and looks up the LDAP directory to find
+ * the matching username for Mantis.
+ *
+ * Optionally, also update the user information in the Mantis user
+ * table.
+ *
+ * @param $p_cas_id string Typically, the username given by phpCAS.
+ * @param $p_update_user bool Whether or not to update user details from LDAP.
+ */
+function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+{
+
+	# Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+
+	$t_ldap_organization	= config_get( 'ldap_organization' );
+	$t_ldap_root_dn			= config_get( 'ldap_root_dn' );
+
+	# Required fields in LDAP for CAS
+	$t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ) ;
+	$t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+	$t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+	$t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+	# User-defined fields to fetch from LDAP...
+	$t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+	$t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+	# ...which are mapped to Mantis user fields
+	$t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+	$t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+	# Build LDAP search filter, attribute list from CAS ID
+	$t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+	$t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);	# array union
+	
+	# Use Mantis ldap_api to connect to LDAP
+	$t_ds = ldap_connect_bind();
+	$t_sr   = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+	$t_info = ldap_get_entries( $t_ds, $t_sr );
+	# Parse the LDAP entry to find the Mantis username
+	if ( $t_info ) {
+		# Get Mantis username
+		$t_username = $t_info[0][$t_ldap_mantis_uid][0];
+
+		# @@@ The fact that we got here means the user is authenticated
+		# @@@ by CAS, and has an LDAP entry.
+		# @@@ We might as well update other user details since we are here.
+
+		# If no argument given, check settings
+		if ( '' == $p_update_user ) {
+			$p_update_user = config_get( 'cas_ldap_update', FALSE );
+		}
+		# If there's a user record, then update it
+		if ( $p_update_user ) {
+			# Only proceed if the field map arrays are the same length
+			$t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+			if ($t_field_map) {
+				# If user is new, then we must create their account before updating it
+				# @@@ ( make sure $g_allow_blank_email == ON )
+				$t_userid = user_get_id_by_name($t_username);
+				if ( false == $t_userid ) {
+					user_create( $t_username, '' );
+					# @@@ Wow, this is pretty lame
+					$t_userid = user_get_id_by_name($t_username);
+				}
+				# @@@ maybe we can optimize this to write all fields at once?
+				foreach ( $t_field_map as $key=>$t_userfield ) {
+					if (isset($t_info[0][$key][0])) {
+						user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+					}
+				}
+			}
+		}
+
+	}
+	ldap_free_result( $t_sr );
+	ldap_unbind( $t_ds );
+
+	return $t_username;
+}
+
+
+/**
+ * Logs out of CAS, redirecting to Mantis on re-login.
+ * User should already be logged out of Mantis by the time this is called.
+ * @see auth_logout()
+ */
+function auth_cas_logout()
+{
+	$t_path = config_get('path');
+
+	auth_cas_init();
+	if (method_Exists('phpCAS', 'logoutWithUrl')) {
+		phpCAS::logoutWithUrl($t_path);
+	} else {
+		phpCAS::logout($t_path);
+	}
+}
+
+
+
 /**
  * Check that there is a user logged-in and authenticated
  * If the user's account is disabled they will be logged out
@@ -180,9 +352,10 @@
 
 	$t_login_method = config_get( 'login_method' );
 
-	if( false === $t_user_id ) {
-		if( BASIC_AUTH == $t_login_method ) {
-			# attempt to create the user if using BASIC_AUTH
+	if ( false === $t_user_id ) {
+		if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+			# attempt to create the user if using BASIC_AUTH or CAS_AUTH
+			# ( note: CAS_AUTH must have $g_allow_blank_email == ON )
 			$t_cookie_string = user_create( $p_username, $p_password );
 
 			if( false === $t_cookie_string ) {
@@ -193,7 +366,7 @@
 			# ok, we created the user, get the row again
 			$t_user_id = user_get_id_by_name( $p_username );
 
-			if( false === $t_user_id ) {
+			if ( false === $t_user_id ) {
 				# uh oh, something must be really wrong
 				# @@@ trigger an error here?
 				return false;
@@ -204,7 +377,7 @@
 	}
 
 	# check for disabled account
-	if( !user_is_enabled( $t_user_id ) ) {
+	if ( !user_is_enabled( $t_user_id ) ) {
 		return false;
 	}
 
@@ -305,6 +478,10 @@
 	if( HTTP_AUTH == config_get( 'login_method' ) ) {
 		auth_http_set_logout_pending( true );
 	}
+	elseif ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# Redirect to CAS page to logout
+		auth_cas_logout();
+	}
 
 	session_clean();
 }
@@ -318,6 +495,8 @@
 	switch( config_get( 'login_method' ) ) {
 		case HTTP_AUTH:
 			return true;
+		case CAS_AUTH:
+			return true;
 	}
 	return false;
 }
@@ -336,6 +515,10 @@
 	if( LDAP == $t_configured_login_method ) {
 		return ldap_authenticate( $p_user_id, $p_test_password );
 	}
+	elseif ( CAS_AUTH == $t_configured_login_method ) {
+		# CAS already took care of password verification for us
+		return true;
+	}
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
@@ -611,7 +794,7 @@
  * @access public
  */
 function auth_reauthenticate() {
-	if( config_get_global( 'reauthentication' ) == OFF || BASIC_AUTH == config_get( 'login_method' ) || HTTP_AUTH == config_get( 'login_method' ) ) {
+	if( config_get_global( 'reauthentication' ) == OFF || in_array(config_get('login_method'), array(BASIC_AUTH, HTTP_AUTH, CAS_AUTH)) ) {
 		return true;
 	}
 
diff -ru mantis-1.2.0a3/core/constant_inc.php mantis-1.2.0a3.CAS/core/constant_inc.php
--- mantis-1.2.0a3/core/constant_inc.php	2009-01-16 00:53:27.000000000 +0800
+++ mantis-1.2.0a3.CAS/core/constant_inc.php	2009-02-19 16:30:54.000000000 +0800
@@ -115,6 +115,7 @@
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'CAS_AUTH', 7);
 
 # file upload methods
 define( 'DISK', 1 );
diff -ru mantis-1.2.0a3/login.php mantis-1.2.0a3.CAS/login.php
--- mantis-1.2.0a3/login.php	2009-01-16 00:04:53.000000000 +0800
+++ mantis-1.2.0a3.CAS/login.php	2009-02-20 03:37:28.000000000 +0800
@@ -32,6 +32,13 @@
 	$f_return		= gpc_get_string( 'return', config_get( 'default_home_page' ) );
 	$f_from			= gpc_get_string( 'from', '' );
 	
+	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+	    # This will detour to the CAS login page if needed
+	    $f_password = '';
+	    $f_username = auth_cas_get_name();
+	    # User is always authenticated by this point
+	}
+
 	$f_username = auth_prepare_username($f_username);
 	$f_password = auth_prepare_password($f_password);
 
mantis-1.2.0a3_cas.patch (11,268 bytes)
joshua_chan

joshua_chan

2009-02-19 14:53

reporter   ~0020900

Here is an updated patch for Mantis-1.2.0a3.

I fixed a bug (my own!) that may have caused problems if you used the "Translate CAS username through LDAP" feature with a non-default $g_ldap_uid_field.

See "mantis-1.2.0a3_cas.patch".

agarcia

agarcia

2010-01-29 06:47

reporter   ~0024268

WARNING: this patch opens mantisconnect full access without authentication.

mantisconnect calls "auth_attempt_script_login" that ends calling
"auth_does_password_match" that allways returns true for CAS_AUTH login method.

api/soap/mc_api.php:

function mci_check_login( $p_username, $p_password ) {
[...]
if( false === auth_attempt_script_login( $p_username, $p_password ) ) {
return false;
}
[...]

core/authentication_api.php:

function auth_attempt_script_login( $p_username, $p_password = null ) {
[...]
if( !auth_does_password_match( $t_user_id, $p_password ) ) {
return false;
}
[...]
}

function auth_does_password_match( $p_user_id, $p_test_password ) {
[...]
elseif ( CAS_AUTH == $t_configured_login_method ) {

CAS already took care of password verification for us

            return true;
    }

[...]
}

mstrumyla

mstrumyla

2010-01-29 10:24

reporter   ~0024269

Could you clarify which patch you're referring to? Is it mantis-1.2.0a3_cas.patch?

agarcia

agarcia

2010-01-29 10:46

reporter   ~0024270

yes, mantis 1.2.0rc2 with mantis-1.2.0a3_cas.patch

wdouglascampbell

wdouglascampbell

2010-04-24 11:29

reporter   ~0025245

Attached is patch for MantisBT 1.2.1.

Note that I did not change anything related to the comment posted by agarcia.

wdouglascampbell

wdouglascampbell

2010-04-24 11:30

reporter  

mantis-1.2.1_cas.patch (13,022 bytes)
diff -ru mantisbt-1.2.1/config_defaults_inc.php mantisbt-1.2.1.CAS/config_defaults_inc.php
--- mantisbt-1.2.1/config_defaults_inc.php	2010-04-24 02:28:34.000000000 +0800
+++ mantisbt-1.2.1.CAS/config_defaults_inc.php	2010-04-24 16:03:46.000000000 +0800
@@ -1629,6 +1629,83 @@
 	 */
 	$g_hr_width				= 50;
 
+
+	/***********************
+	 * Mantis CAS Settings *
+	 ***********************/
+
+	# --- using phpCAS -------------
+	/**
+	 * @global string $g_cas_server
+	 */
+	$g_cas_server = 'example.com.au';
+
+	/**
+	 * @global int $g_cas_port
+	 */
+	$g_cas_port = 443;
+
+	/**
+	 * The CAS path on the server. E.g. '/cas'
+	 * @global int $g_cas_uri
+	 */
+	$g_cas_uri = '';
+
+	/**
+	 * @global $g_cas_version string
+	 */
+	$g_cas_version = '2.0';
+
+	# --- CAS + LDAP -------------
+	/**
+	 * Translate CAS username through LDAP.
+	 * @global $g_cas_use_ldap int
+	 */
+	$g_cas_use_ldap     = OFF;
+
+	/**
+	 * The LDAP field matching the Mantis username.
+	 * @global $g_ldap_mantis_udi string
+	 */
+	$g_ldap_mantis_uid  = 'uid';
+
+	/**
+	 * Should Mantis update user details from LDAP while authenticating with CAS?
+	 * @global $g_cas_ldap_update int
+	 */
+	$g_cas_ldap_update  = OFF;
+
+	/**
+	 * E.g. 'cn,userpassword'.
+	 * @global $g_cas_ldap_update_fields string
+	 */
+	$g_cas_ldap_update_fields = '';
+
+	/**
+	 * E.g. 'realname,password'.
+	 * @global $g_cas_ldap_update_map string
+	 */
+	$g_cas_ldap_update_map    = '';
+
+	/**
+	 * This is the field in LDAP to use to set the user's language preference.
+	 * @global $g_ldap_language_field string
+	 */
+	$g_ldap_language_field = '';
+
+	/**
+	 * E.g. 'en,zh_hans,ko'.
+	 * @global $g_ldap_language_keys string
+	 */
+	$g_ldap_language_keys = '';
+
+	/**
+	 * E.g. 'english,chinese_simplified,korean'.
+	 * @global $g_ldap_language_values string
+	 */
+	$g_cas_ldap_update_values    = '';
+
+
 	/**************************
 	 * MantisBT LDAP Settings *
 	 **************************/
@@ -2478,7 +2555,7 @@
 
 	/**
 	 * login method
-	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH or CAS_AUTH
 	 * You can simply change this at will. MantisBT will try to figure out how the passwords were encrypted.
 	 * @global int $g_login_method
 	 */
Only in mantisbt-1.2.1.CAS: config_inc.php
diff -ru mantisbt-1.2.1/core/authentication_api.php mantisbt-1.2.1.CAS/core/authentication_api.php
--- mantisbt-1.2.1/core/authentication_api.php	2010-04-24 02:28:34.000000000 +0800
+++ mantisbt-1.2.1.CAS/core/authentication_api.php	2010-04-24 16:43:34.000000000 +0800
@@ -53,6 +53,177 @@
 $g_cache_current_user_id = null;
 
 /**
+ * Initialize phpCAS.
+ */
+function auth_cas_init() {
+        # phpCAS must be installed in the include path
+        # or in the Mantis directory.
+        require_once('CAS/CAS.php');
+
+        static $s_initialized=false;
+
+        if (! $s_initialized ) {
+                phpCAS::setDebug();
+        ## These should be set in config_inc.php
+                $t_server_version = config_get( 'cas_version' );
+                $t_server_cas_server = config_get( 'cas_server' );
+                $t_server_port = config_get( 'cas_port' );
+                $t_server_uri = config_get( 'cas_uri' );
+                $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+
+                phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+                if (method_exists('phpCAS', 'setNoCasServerValidation')) {
+                        // no SSL validation for the CAS server
+                        phpCAS::setNoCasServerValidation();
+                }
+
+                $s_initialized = true;
+        }
+
+}
+
+
+/**
+ * Fetches the user's CAS name, authenticating if needed.
+ * Can translate CAS login name to Mantis username through LDAP.
+ */
+function auth_cas_get_name()
+{
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        phpCAS::forceAuthentication();
+        $t_cas_id = phpCAS::getUser();
+
+        # If needed, translate the CAS username through LDAP
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+                $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }
+        return $t_username;
+}
+
+
+/**
+ * Takes an ID string, and looks up the LDAP directory to find
+ * the matching username for Mantis.
+ *
+ * Optionally, also update the user information in the Mantis user
+ * table.
+ *
+ * @param $p_cas_id string Typically, the username given by phpCAS.
+ * @param $p_update_user bool Whether or not to update user details from LDAP.
+ */
+function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+{
+
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+
+        $t_ldap_organization    = config_get( 'ldap_organization' );
+        $t_ldap_root_dn                 = config_get( 'ldap_root_dn' );
+
+        # Required fields in LDAP for CAS
+        $t_ldap_language_field = config_get( 'ldap_language_field', '' );
+        $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ) ;
+        $t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        if ($t_ldap_language_field) {
+                // Add language field to attributes list only if it is configured.
+                $t_ldap_required[] = $t_ldap_language_field;
+        }
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+        # User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+        $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+        $t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);      # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+        $t_sr   = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+        $t_info = ldap_get_entries( $t_ds, $t_sr );
+        # Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+                # Get Mantis username
+                $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+
+                # @@@ The fact that we got here means the user is authenticated
+                # @@@ by CAS, and has an LDAP entry.
+                # @@@ We might as well update other user details since we are here.
+
+                # If no argument given, check settings
+                if ( '' == $p_update_user ) {
+                        $p_update_user = config_get( 'cas_ldap_update', FALSE );
+                }
+                # If there's a user record, then update it
+                if ( $p_update_user ) {
+                        # Only proceed if the field map arrays are the same length
+                        $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                        if ($t_field_map) {
+                                # If user is new, then we must create their account before updating it
+                                # @@@ ( make sure $g_allow_blank_email == ON )
+                                $t_userid = user_get_id_by_name($t_username);
+                                if ( false == $t_userid ) {
+                                        user_create( $t_username, '' );
+                                        # @@@ Wow, this is pretty lame
+                                        $t_userid = user_get_id_by_name($t_username);
+                                }
+                                # @@@ maybe we can optimize this to write all fields at once?
+                                foreach ( $t_field_map as $key=>$t_userfield ) {
+                                        if (isset($t_info[0][$key][0])) {
+                                                user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                                        }
+                                }
+                        }
+
+                        // Update user's overall language preference
+                        if ($t_ldap_language_field) {
+                                $t_language = $t_info[0][$t_ldap_language_field][0];
+                                // Map the LDAP language field to Mantis' language field if needed
+                                $t_language_keys = config_get( 'ldap_language_keys', '');
+                                $t_language_values = config_get( 'ldap_language_values', '');
+                                $t_language_map = array_combine(
+                                        explode(',', $t_language_keys),
+                                        explode(',', $t_language_values)
+                                );
+                                if (isset($t_language_map[$t_language])) {
+                                        $t_language = $t_language_map[$t_language];
+                                }
+                                user_pref_set_pref($t_userid, 'language', $t_language);
+                        }
+                }
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+
+        return $t_username;
+}
+
+
+/**
+ * Logs out of CAS, redirecting to Mantis on re-login.
+ * User should already be logged out of Mantis by the time this is called.
+ * @see auth_logout()
+ */
+function auth_cas_logout()
+{
+        $t_path = config_get('path');
+
+        auth_cas_init();
+        if (method_Exists('phpCAS', 'logoutWithUrl')) {
+                phpCAS::logoutWithUrl($t_path);
+        } else {
+                phpCAS::logout($t_path);
+        }
+}
+
+
+/**
  * Check that there is a user logged-in and authenticated
  * If the user's account is disabled they will be logged out
  * If there is no user logged in, redirect to the login page
@@ -182,7 +353,9 @@
 	$t_login_method = config_get( 'login_method' );
 
 	if ( false === $t_user_id ) {
-		if ( BASIC_AUTH == $t_login_method ) {
+		if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+			# attempt to create the user if using BASIC_AUTH or CAS_AUTH
+			# ( note: CAS_AUTH must have $g_allow_blank_email == ON )
 			$t_auto_create = true;
 		} else if ( LDAP == $t_login_method && ldap_authenticate_by_username( $p_username, $p_password ) ) {
 			$t_auto_create = true;
@@ -311,6 +484,10 @@
 	if( HTTP_AUTH == config_get( 'login_method' ) ) {
 		auth_http_set_logout_pending( true );
 	}
+	elseif ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# Redirect to CAS page to logout
+		auth_cas_logout();
+	}
 
 	session_clean();
 }
@@ -324,6 +501,8 @@
 	switch( config_get( 'login_method' ) ) {
 		case HTTP_AUTH:
 			return true;
+		case CAS_AUTH:
+			return true;
 	}
 	return false;
 }
@@ -342,6 +521,10 @@
 	if( LDAP == $t_configured_login_method ) {
 		return ldap_authenticate( $p_user_id, $p_test_password );
 	}
+	elseif ( CAS_AUTH == $t_configured_login_method ) {
+		# CAS already took care of password verification for us
+		return true;
+	}
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
@@ -617,7 +800,7 @@
  * @access public
  */
 function auth_reauthenticate() {
-	if( config_get_global( 'reauthentication' ) == OFF || BASIC_AUTH == config_get( 'login_method' ) || HTTP_AUTH == config_get( 'login_method' ) ) {
+	if( config_get_global( 'reauthentication' ) == OFF || in_array(config_get('login_method'), array(BASIC_AUTH, HTTP_AUTH, CAS_AUTH)) ) {
 		return true;
 	}
 
diff -ru mantisbt-1.2.1/core/constant_inc.php mantisbt-1.2.1.CAS/core/constant_inc.php
--- mantisbt-1.2.1/core/constant_inc.php	2010-04-24 02:28:34.000000000 +0800
+++ mantisbt-1.2.1.CAS/core/constant_inc.php	2010-04-24 16:23:23.000000000 +0800
@@ -134,6 +134,7 @@
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'CAS_AUTH', 7);
 
 # file upload methods
 define( 'DISK', 1 );
diff -ru mantisbt-1.2.1/login.php mantisbt-1.2.1.CAS/login.php
--- mantisbt-1.2.1/login.php	2010-04-24 02:28:34.000000000 +0800
+++ mantisbt-1.2.1.CAS/login.php	2010-04-24 16:26:17.000000000 +0800
@@ -33,6 +33,13 @@
 	$f_from			= gpc_get_string( 'from', '' );
 	$f_secure_session = gpc_get_bool( 'secure_session', false );
 
+	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# This will detour to the CAS login page if needed
+		$f_password = '';
+		$f_username = auth_cas_get_name();
+		# User is always authenticated by this point
+	}
+
 	$f_username = auth_prepare_username($f_username);
 	$f_password = auth_prepare_password($f_password);
 
mantis-1.2.1_cas.patch (13,022 bytes)
SchoutenCC

SchoutenCC

2010-07-19 04:00

reporter   ~0026096

Maybe not the best place to post this (if so, @mods please move) but is it possible that after applying wdouglascampbell's mantis-1.2.1_cas.patch mantis may react very slow?
I've successfully applied the patch and configured config_inc.php to allow cas authentication, but response became quite slow (>10sec to load a bug view page). Leaving the patch in but commenting out all settings in config_inc makes mantis remain slow, commenting out the patch (and restoring the original lines that were changed) returned speed for me. Ergo, the patch is definitely the problem for me. Any thoughts most appreciated.

wdouglascampbell

wdouglascampbell

2010-07-20 21:31

reporter   ~0026108

SchoutenCC, I haven't experienced a slow down. That is not to say there isn't a problem in the patch but it should be noted that the problem would have existed for other version releases too since I really didn't change anything from earlier patches.

SchoutenCC

SchoutenCC

2010-07-21 02:29

reporter   ~0026109

Hi wdouglascampbell, thanks for checking. I've narrowed the issue down to the in_array calls. Rewriting those two statements to an extra OR concatenated to the original statement restored speed for me. Why, I don't know, but such was the case for me. So, should anybody experience similar problems, one could try this.

rgomes1997

rgomes1997

2011-01-02 23:11

reporter   ~0027773

Is there a patch for Mantis-1.2.4 ? Thanks

fwestanqueiro

fwestanqueiro

2011-03-24 12:43

reporter   ~0028466

The patch works on 1.2.4?

mdevilz

mdevilz

2011-05-31 18:49

reporter  

phpcas-mantisbt-1.2.5.patch (322,254 bytes)
mdevilz

mdevilz

2011-05-31 18:51

reporter   ~0028880

Added a patch for 1.2.5 that seems to be working for me. Other than not knowing how to pull the users email address from CAS attributes. I am using phpcas-1.1.3.

foo

foo

2011-06-16 11:04

reporter   ~0029024

So, what exactly is the deal with CAS support? People have been re-rolling patches for 5 years, and it still hasn't made it into the core?

I'm all for the generic authentication API discussion going on over at issue 0004235, but seriously, 5 years?

Who do I need to buy a beer around here to get something committed? :-)

pzYsTorM

pzYsTorM

2011-06-17 05:08

reporter   ~0029030

Why are there so many file changes in the last diff for 1.2.5?
The patch file is 322kb ... and files like
admin/upgrade_unattended.php
admin/test_langs.php
are added or replaced. Why?

pzYsTorM

pzYsTorM

2011-06-17 12:21

reporter  

phpcas-mantisbt-1.2.5-corr.patch (15,795 bytes)
diff -ur mantisbt-1.2.5/config_defaults_inc.php mantisbt-1.2.5-CAS/config_defaults_inc.php
--- mantisbt-1.2.5/config_defaults_inc.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/config_defaults_inc.php	Fri Jun 17 18:06:59 2011
@@ -1645,6 +1645,110 @@
 	 */
 	$g_hr_width				= 50;
 
+
+	/***********************
+	 * Mantis CAS Settings *
+	 ***********************/
+
+	# --- using phpCAS -------------
+	/**
+	 * @global string $g_cas_server
+	 */
+	$g_cas_server = 'example.com.au';
+
+	/**
+	 * @global int $g_cas_port
+	 */
+	$g_cas_port = 443;
+
+	/**
+	 * The CAS path on the server. E.g. '/cas'
+	 * @global string $g_cas_uri
+	 */
+	$g_cas_uri = '';
+	
+	/**
+	 * The CAS validation URL to the server
+	 * @global string $g_cas_validation
+	 */
+	$g_cas_validation = '';
+
+	/**
+	 * Protocol version 2.0 (to use CAS) or S1 (to use SAML)
+	 * @global string $g_cas_version
+	 */
+	$g_cas_version = '2.0';
+	
+	/**
+	 * Full path incl filename to the cas debug log file
+	 * @global string $g_cas_debug
+	 */
+	$g_cas_debug = '';
+	
+	/**
+	 * When using SAML the CAS can provide user attributes
+	 * @global boolean $g_cas_saml_attributes
+	 */
+	$g_cas_saml_attributes = OFF;
+	
+	/**
+	 * Array with two entries: name => ..., mail => ...
+	 * Look in your WEB-INF/deployerConfigContext.xml at the CAS server
+	 * @global array $g_cas_saml_map
+	 */
+	$g_cas_saml_map = array( 'name' => '', 'mail' => '' );
+	
+
+	# --- CAS + LDAP -------------
+	/**
+	 * Translate CAS username through LDAP.
+	 * @global $g_cas_use_ldap int
+	 */
+	$g_cas_use_ldap     = OFF;
+
+	/**
+	 * The LDAP field matching the Mantis username.
+	 * @global $g_ldap_mantis_udi string
+	 */
+	$g_ldap_mantis_uid  = 'uid';
+
+	/**
+	 * Should Mantis update user details from LDAP while authenticating with CAS?
+	 * @global $g_cas_ldap_update int
+	 */
+	$g_cas_ldap_update  = OFF;
+
+	/**
+	 * E.g. 'cn,userpassword'.
+	 * @global $g_cas_ldap_update_fields string
+	 */
+	$g_cas_ldap_update_fields = '';
+
+	/**
+	 * E.g. 'realname,password'.
+	 * @global $g_cas_ldap_update_map string
+	 */
+	$g_cas_ldap_update_map    = '';
+
+	/**
+	 * This is the field in LDAP to use to set the user's language preference.
+	 * @global $g_ldap_language_field string
+	 */
+	$g_ldap_language_field = '';
+
+	/**
+	 * E.g. 'en,zh_hans,ko'.
+	 * @global $g_ldap_language_keys string
+	 */
+	$g_ldap_language_keys = '';
+
+	/**
+	 * E.g. 'english,chinese_simplified,korean'.
+	 * @global $g_ldap_language_values string
+	 */
+	$g_cas_ldap_update_values    = '';
+
+
 	/**************************
 	 * MantisBT LDAP Settings *
 	 **************************/
@@ -2501,7 +2605,7 @@
 
 	/**
 	 * login method
-	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH or CAS_AUTH
 	 * You can simply change this at will. MantisBT will try to figure out how the passwords were encrypted.
 	 * @global int $g_login_method
 	 */
diff -ur mantisbt-1.2.5/login.php mantisbt-1.2.5-CAS/login.php
--- mantisbt-1.2.5/login.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/login.php	Fri Jun 17 16:49:29 2011
@@ -28,11 +28,18 @@
 
 	$f_username		= gpc_get_string( 'username', '' );
 	$f_password		= gpc_get_string( 'password', '' );
-	$f_perm_login	= gpc_get_bool( 'perm_login' );
+	$f_perm_login		= gpc_get_bool( 'perm_login' );
 	$t_return		= string_url( string_sanitize_url( gpc_get_string( 'return', config_get( 'default_home_page' ) ) ) );
 	$f_from			= gpc_get_string( 'from', '' );
-	$f_secure_session = gpc_get_bool( 'secure_session', false );
+	$f_secure_session	= gpc_get_bool( 'secure_session', false );
 
+	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# This will detour to the CAS login page if needed
+		$f_password = '';
+		$f_username = auth_cas_get_name();
+		# User is always authenticated by this point
+	}
+
 	$f_username = auth_prepare_username($f_username);
 	$f_password = auth_prepare_password($f_password);
 
@@ -56,3 +63,5 @@
 	}
 
 	print_header_redirect( $t_redirect_url );
+
+?>
diff -ur mantisbt-1.2.5/login_page.php mantisbt-1.2.5-CAS/login_page.php
--- mantisbt-1.2.5/login_page.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/login_page.php	Fri Jun 17 16:51:49 2011
@@ -33,11 +33,11 @@
 	}
 
 	$f_error		= gpc_get_bool( 'error' );
-	$f_cookie_error	= gpc_get_bool( 'cookie_error' );
+	$f_cookie_error		= gpc_get_bool( 'cookie_error' );
 	$f_return		= string_sanitize_url( gpc_get_string( 'return', '' ) );
-	$f_username     = gpc_get_string( 'username', '' );
-	$f_perm_login	= gpc_get_bool( 'perm_login', false );
-	$f_secure_session = gpc_get_bool( 'secure_session', false );
+	$f_username		= gpc_get_string( 'username', '' );
+	$f_perm_login		= gpc_get_bool( 'perm_login', false );
+	$f_secure_session	= gpc_get_bool( 'secure_session', false );
 	$f_secure_session_cookie = gpc_get_cookie( config_get_global( 'cookie_prefix' ) . '_secure_session', null );
 
 	$t_session_validation = ( ON == config_get_global( 'session_validation' ) );
diff -ur mantisbt-1.2.5/core/authentication_api.php mantisbt-1.2.5-CAS/core/authentication_api.php
--- mantisbt-1.2.5/core/authentication_api.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/core/authentication_api.php	Fri Jun 17 18:08:26 2011
@@ -53,6 +53,190 @@
 $g_cache_current_user_id = null;
 
 /**
+ * Initialize phpCAS.
+ */
+function auth_cas_init() {
+        # phpCAS must be installed in the include path
+        # or in the Mantis directory.
+        require_once('CAS.php');
+
+        static $s_initialized=false;
+
+        if (! $s_initialized ) {
+                phpCAS::setDebug( config_get( 'cas_debug' ) );
+        ## These should be set in config_inc.php
+                $t_server_version = config_get( 'cas_version' );
+                $t_server_cas_server = config_get( 'cas_server' );
+                $t_server_port = config_get( 'cas_port' );
+                $t_server_uri = config_get( 'cas_uri' );
+                $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+
+                phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+                if ($t_server_version == "S1")
+                        phpCAS::setServerSamlValidateURL( config_get( 'cas_validate' ) );
+                else
+                        phpCAS::setServerProxyValidateURL( config_get( 'cas_validate' ) );
+                if (method_exists('phpCAS', 'setNoCasServerValidation')) {
+                        // no SSL validation for the CAS server
+                        phpCAS::setNoCasServerValidation();
+                }
+
+                $s_initialized = true;
+        }
+
+}
+
+
+/**
+ * Fetches the user's CAS name, authenticating if needed.
+ * Can translate CAS login name to Mantis username through LDAP.
+ */
+function auth_cas_get_name()
+{
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        phpCAS::forceAuthentication();
+        $t_cas_id = phpCAS::getUser();
+        $t_cas_attribs = phpCAS::getAttributes();
+
+        # If needed, translate the CAS username through LDAP
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+                $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }
+        elseif (config_get( 'cas_saml_attributes', false )) {
+                $t_cas_attribmap = config_get( 'cas_saml_map', array() );
+                $t_cas_attrib_name = $t_cas_attribs[$t_cas_attribmap['name']];
+                $t_cas_attrib_mail = $t_cas_attribs[$t_cas_attribmap['mail']];
+                if ( user_get_id_by_name($t_cas_id) == false ) {
+                        user_create( $t_cas_id, '', $t_cas_attrib_mail, null, false, true, $t_cas_attrib_name );
+	         }
+        }
+                                
+        return $t_username;
+}
+
+/**
+ * Takes an ID string, and looks up the LDAP directory to find
+ * the matching username for Mantis.
+ *
+ * Optionally, also update the user information in the Mantis user
+ * table.
+ *
+ * @param $p_cas_id string Typically, the username given by phpCAS.
+ * @param $p_update_user bool Whether or not to update user details from LDAP.
+ */
+function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+{
+
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+
+        $t_ldap_organization    = config_get( 'ldap_organization' );
+        $t_ldap_root_dn         = config_get( 'ldap_root_dn' );
+
+        # Required fields in LDAP for CAS
+        $t_ldap_language_field = config_get( 'ldap_language_field', '' );
+        $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ) ;
+        $t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        if ($t_ldap_language_field) {
+                // Add language field to attributes list only if it is configured.
+                $t_ldap_required[] = $t_ldap_language_field;
+        }
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+        # User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+        $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+        $t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);      # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+        $t_sr   = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+        $t_info = ldap_get_entries( $t_ds, $t_sr );
+        # Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+                # Get Mantis username
+                $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+
+                # @@@ The fact that we got here means the user is authenticated
+                # @@@ by CAS, and has an LDAP entry.
+                # @@@ We might as well update other user details since we are here.
+
+                # If no argument given, check settings
+                if ( '' == $p_update_user ) {
+                        $p_update_user = config_get( 'cas_ldap_update', FALSE );
+                }
+                # If there's a user record, then update it
+                if ( $p_update_user ) {
+                        # Only proceed if the field map arrays are the same length
+                        $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                        if ($t_field_map) {
+                                # If user is new, then we must create their account before updating it
+                                # @@@ ( make sure $g_allow_blank_email == ON )
+                                $t_userid = user_get_id_by_name($t_username);
+                                if ( false == $t_userid ) {
+                                        user_create( $t_username, '' );
+                                        # @@@ Wow, this is pretty lame
+                                        $t_userid = user_get_id_by_name($t_username);
+                                }
+                                # @@@ maybe we can optimize this to write all fields at once?
+                                foreach ( $t_field_map as $key=>$t_userfield ) {
+                                        if (isset($t_info[0][$key][0])) {
+                                                user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                                        }
+                                }
+                        }
+
+                        // Update user's overall language preference
+                        if ($t_ldap_language_field) {
+                                $t_language = $t_info[0][$t_ldap_language_field][0];
+                                // Map the LDAP language field to Mantis' language field if needed
+                                $t_language_keys = config_get( 'ldap_language_keys', '');
+                                $t_language_values = config_get( 'ldap_language_values', '');
+                                $t_language_map = array_combine(
+                                        explode(',', $t_language_keys),
+                                        explode(',', $t_language_values)
+                                );
+                                if (isset($t_language_map[$t_language])) {
+                                        $t_language = $t_language_map[$t_language];
+                                }
+                                user_pref_set_pref($t_userid, 'language', $t_language);
+                        }
+                }
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+
+        return $t_username;
+}
+
+
+/**
+ * Logs out of CAS, redirecting to Mantis on re-login.
+ * User should already be logged out of Mantis by the time this is called.
+ * @see auth_logout()
+ */
+function auth_cas_logout()
+{
+        $t_path = config_get('path');
+
+        auth_cas_init();
+        if (method_Exists('phpCAS', 'logoutWithUrl')) {
+                phpCAS::logoutWithUrl($t_path);
+        } else {
+                phpCAS::logout($t_path);
+        }
+}
+
+
+/**
  * Check that there is a user logged-in and authenticated
  * If the user's account is disabled they will be logged out
  * If there is no user logged in, redirect to the login page
@@ -182,7 +366,8 @@
 	$t_login_method = config_get( 'login_method' );
 
 	if ( false === $t_user_id ) {
-		if ( BASIC_AUTH == $t_login_method ) {
+		if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+			# attempt to create the user if using BASIC_AUTH or CAS_AUTH
 			$t_auto_create = true;
 		} else if ( LDAP == $t_login_method && ldap_authenticate_by_username( $p_username, $p_password ) ) {
 			$t_auto_create = true;
@@ -311,6 +496,10 @@
 	if( HTTP_AUTH == config_get( 'login_method' ) ) {
 		auth_http_set_logout_pending( true );
 	}
+	elseif ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# Redirect to CAS page to logout
+		auth_cas_logout();
+	}
 
 	session_clean();
 }
@@ -324,6 +513,8 @@
 	switch( config_get( 'login_method' ) ) {
 		case HTTP_AUTH:
 			return true;
+		case CAS_AUTH:
+			return true;
 	}
 	return false;
 }
@@ -342,6 +533,10 @@
 	if( LDAP == $t_configured_login_method ) {
 		return ldap_authenticate( $p_user_id, $p_test_password );
 	}
+	elseif ( CAS_AUTH == $t_configured_login_method ) {
+		# CAS already took care of password verification for us
+		return true;
+	}
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
@@ -617,7 +812,7 @@
  * @access public
  */
 function auth_reauthenticate() {
-	if( config_get_global( 'reauthentication' ) == OFF || BASIC_AUTH == config_get( 'login_method' ) || HTTP_AUTH == config_get( 'login_method' ) ) {
+	if( config_get_global( 'reauthentication' ) == OFF || in_array(config_get('login_method'), array(BASIC_AUTH, HTTP_AUTH, CAS_AUTH)) ) {
 		return true;
 	}
 
diff -ur mantisbt-1.2.5/core/constant_inc.php mantisbt-1.2.5-CAS/core/constant_inc.php
--- mantisbt-1.2.5/core/constant_inc.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/core/constant_inc.php	Fri Jun 17 14:00:53 2011
@@ -134,6 +134,7 @@
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'CAS_AUTH', 7);
 
 # file upload methods
 define( 'DISK', 1 );
pzYsTorM

pzYsTorM

2011-06-17 12:25

reporter   ~0029035

I have corrected the patch (falsely deleted files by a dev, etc.).
And I have implemented the support of the SAML protocol (especially user attributes via SAML). There are some new config options. All of them are documented in the config_defaults_inc.php
Now there is no need to set $g_allow_blank_email == ON, if the mail adress is provided via SAML. It is read (the user's full name, too) and written to the database.

foo

foo

2011-06-17 16:43

reporter   ~0029037

@pzYsTorM: Thanks for the updated patch! It has one problem, though; the $g_cas_validation setting should be renamed $g_cas_validate, because that's what authentication_api.php expects. Once I fixed that, CAS auth worked great! I'll attached a patched patch.

foo

foo

2011-06-17 16:45

reporter  

phpcas-mantisbt-1.2.5-corr-validate.patch (15,793 bytes)
diff -ur mantisbt-1.2.5/config_defaults_inc.php mantisbt-1.2.5-CAS/config_defaults_inc.php
--- mantisbt-1.2.5/config_defaults_inc.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/config_defaults_inc.php	Fri Jun 17 18:06:59 2011
@@ -1645,6 +1645,110 @@
 	 */
 	$g_hr_width				= 50;
 
+
+	/***********************
+	 * Mantis CAS Settings *
+	 ***********************/
+
+	# --- using phpCAS -------------
+	/**
+	 * @global string $g_cas_server
+	 */
+	$g_cas_server = 'example.com.au';
+
+	/**
+	 * @global int $g_cas_port
+	 */
+	$g_cas_port = 443;
+
+	/**
+	 * The CAS path on the server. E.g. '/cas'
+	 * @global string $g_cas_uri
+	 */
+	$g_cas_uri = '';
+	
+	/**
+	 * The CAS validation URL to the server
+	 * @global string $g_cas_validation
+	 */
+	$g_cas_validate = '';
+
+	/**
+	 * Protocol version 2.0 (to use CAS) or S1 (to use SAML)
+	 * @global string $g_cas_version
+	 */
+	$g_cas_version = '2.0';
+	
+	/**
+	 * Full path incl filename to the cas debug log file
+	 * @global string $g_cas_debug
+	 */
+	$g_cas_debug = '';
+	
+	/**
+	 * When using SAML the CAS can provide user attributes
+	 * @global boolean $g_cas_saml_attributes
+	 */
+	$g_cas_saml_attributes = OFF;
+	
+	/**
+	 * Array with two entries: name => ..., mail => ...
+	 * Look in your WEB-INF/deployerConfigContext.xml at the CAS server
+	 * @global array $g_cas_saml_map
+	 */
+	$g_cas_saml_map = array( 'name' => '', 'mail' => '' );
+	
+
+	# --- CAS + LDAP -------------
+	/**
+	 * Translate CAS username through LDAP.
+	 * @global $g_cas_use_ldap int
+	 */
+	$g_cas_use_ldap     = OFF;
+
+	/**
+	 * The LDAP field matching the Mantis username.
+	 * @global $g_ldap_mantis_udi string
+	 */
+	$g_ldap_mantis_uid  = 'uid';
+
+	/**
+	 * Should Mantis update user details from LDAP while authenticating with CAS?
+	 * @global $g_cas_ldap_update int
+	 */
+	$g_cas_ldap_update  = OFF;
+
+	/**
+	 * E.g. 'cn,userpassword'.
+	 * @global $g_cas_ldap_update_fields string
+	 */
+	$g_cas_ldap_update_fields = '';
+
+	/**
+	 * E.g. 'realname,password'.
+	 * @global $g_cas_ldap_update_map string
+	 */
+	$g_cas_ldap_update_map    = '';
+
+	/**
+	 * This is the field in LDAP to use to set the user's language preference.
+	 * @global $g_ldap_language_field string
+	 */
+	$g_ldap_language_field = '';
+
+	/**
+	 * E.g. 'en,zh_hans,ko'.
+	 * @global $g_ldap_language_keys string
+	 */
+	$g_ldap_language_keys = '';
+
+	/**
+	 * E.g. 'english,chinese_simplified,korean'.
+	 * @global $g_ldap_language_values string
+	 */
+	$g_cas_ldap_update_values    = '';
+
+
 	/**************************
 	 * MantisBT LDAP Settings *
 	 **************************/
@@ -2501,7 +2605,7 @@
 
 	/**
 	 * login method
-	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH
+	 * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH or CAS_AUTH
 	 * You can simply change this at will. MantisBT will try to figure out how the passwords were encrypted.
 	 * @global int $g_login_method
 	 */
diff -ur mantisbt-1.2.5/login.php mantisbt-1.2.5-CAS/login.php
--- mantisbt-1.2.5/login.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/login.php	Fri Jun 17 16:49:29 2011
@@ -28,11 +28,18 @@
 
 	$f_username		= gpc_get_string( 'username', '' );
 	$f_password		= gpc_get_string( 'password', '' );
-	$f_perm_login	= gpc_get_bool( 'perm_login' );
+	$f_perm_login		= gpc_get_bool( 'perm_login' );
 	$t_return		= string_url( string_sanitize_url( gpc_get_string( 'return', config_get( 'default_home_page' ) ) ) );
 	$f_from			= gpc_get_string( 'from', '' );
-	$f_secure_session = gpc_get_bool( 'secure_session', false );
+	$f_secure_session	= gpc_get_bool( 'secure_session', false );
 
+	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# This will detour to the CAS login page if needed
+		$f_password = '';
+		$f_username = auth_cas_get_name();
+		# User is always authenticated by this point
+	}
+
 	$f_username = auth_prepare_username($f_username);
 	$f_password = auth_prepare_password($f_password);
 
@@ -56,3 +63,5 @@
 	}
 
 	print_header_redirect( $t_redirect_url );
+
+?>
diff -ur mantisbt-1.2.5/login_page.php mantisbt-1.2.5-CAS/login_page.php
--- mantisbt-1.2.5/login_page.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/login_page.php	Fri Jun 17 16:51:49 2011
@@ -33,11 +33,11 @@
 	}
 
 	$f_error		= gpc_get_bool( 'error' );
-	$f_cookie_error	= gpc_get_bool( 'cookie_error' );
+	$f_cookie_error		= gpc_get_bool( 'cookie_error' );
 	$f_return		= string_sanitize_url( gpc_get_string( 'return', '' ) );
-	$f_username     = gpc_get_string( 'username', '' );
-	$f_perm_login	= gpc_get_bool( 'perm_login', false );
-	$f_secure_session = gpc_get_bool( 'secure_session', false );
+	$f_username		= gpc_get_string( 'username', '' );
+	$f_perm_login		= gpc_get_bool( 'perm_login', false );
+	$f_secure_session	= gpc_get_bool( 'secure_session', false );
 	$f_secure_session_cookie = gpc_get_cookie( config_get_global( 'cookie_prefix' ) . '_secure_session', null );
 
 	$t_session_validation = ( ON == config_get_global( 'session_validation' ) );
diff -ur mantisbt-1.2.5/core/authentication_api.php mantisbt-1.2.5-CAS/core/authentication_api.php
--- mantisbt-1.2.5/core/authentication_api.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/core/authentication_api.php	Fri Jun 17 18:08:26 2011
@@ -53,6 +53,190 @@
 $g_cache_current_user_id = null;
 
 /**
+ * Initialize phpCAS.
+ */
+function auth_cas_init() {
+        # phpCAS must be installed in the include path
+        # or in the Mantis directory.
+        require_once('CAS.php');
+
+        static $s_initialized=false;
+
+        if (! $s_initialized ) {
+                phpCAS::setDebug( config_get( 'cas_debug' ) );
+        ## These should be set in config_inc.php
+                $t_server_version = config_get( 'cas_version' );
+                $t_server_cas_server = config_get( 'cas_server' );
+                $t_server_port = config_get( 'cas_port' );
+                $t_server_uri = config_get( 'cas_uri' );
+                $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+
+                phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+                if ($t_server_version == "S1")
+                        phpCAS::setServerSamlValidateURL( config_get( 'cas_validate' ) );
+                else
+                        phpCAS::setServerProxyValidateURL( config_get( 'cas_validate' ) );
+                if (method_exists('phpCAS', 'setNoCasServerValidation')) {
+                        // no SSL validation for the CAS server
+                        phpCAS::setNoCasServerValidation();
+                }
+
+                $s_initialized = true;
+        }
+
+}
+
+
+/**
+ * Fetches the user's CAS name, authenticating if needed.
+ * Can translate CAS login name to Mantis username through LDAP.
+ */
+function auth_cas_get_name()
+{
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        phpCAS::forceAuthentication();
+        $t_cas_id = phpCAS::getUser();
+        $t_cas_attribs = phpCAS::getAttributes();
+
+        # If needed, translate the CAS username through LDAP
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+                $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }
+        elseif (config_get( 'cas_saml_attributes', false )) {
+                $t_cas_attribmap = config_get( 'cas_saml_map', array() );
+                $t_cas_attrib_name = $t_cas_attribs[$t_cas_attribmap['name']];
+                $t_cas_attrib_mail = $t_cas_attribs[$t_cas_attribmap['mail']];
+                if ( user_get_id_by_name($t_cas_id) == false ) {
+                        user_create( $t_cas_id, '', $t_cas_attrib_mail, null, false, true, $t_cas_attrib_name );
+	         }
+        }
+                                
+        return $t_username;
+}
+
+/**
+ * Takes an ID string, and looks up the LDAP directory to find
+ * the matching username for Mantis.
+ *
+ * Optionally, also update the user information in the Mantis user
+ * table.
+ *
+ * @param $p_cas_id string Typically, the username given by phpCAS.
+ * @param $p_update_user bool Whether or not to update user details from LDAP.
+ */
+function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+{
+
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+
+        $t_ldap_organization    = config_get( 'ldap_organization' );
+        $t_ldap_root_dn         = config_get( 'ldap_root_dn' );
+
+        # Required fields in LDAP for CAS
+        $t_ldap_language_field = config_get( 'ldap_language_field', '' );
+        $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ) ;
+        $t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        if ($t_ldap_language_field) {
+                // Add language field to attributes list only if it is configured.
+                $t_ldap_required[] = $t_ldap_language_field;
+        }
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+        # User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+        $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+        $t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);      # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+        $t_sr   = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+        $t_info = ldap_get_entries( $t_ds, $t_sr );
+        # Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+                # Get Mantis username
+                $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+
+                # @@@ The fact that we got here means the user is authenticated
+                # @@@ by CAS, and has an LDAP entry.
+                # @@@ We might as well update other user details since we are here.
+
+                # If no argument given, check settings
+                if ( '' == $p_update_user ) {
+                        $p_update_user = config_get( 'cas_ldap_update', FALSE );
+                }
+                # If there's a user record, then update it
+                if ( $p_update_user ) {
+                        # Only proceed if the field map arrays are the same length
+                        $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                        if ($t_field_map) {
+                                # If user is new, then we must create their account before updating it
+                                # @@@ ( make sure $g_allow_blank_email == ON )
+                                $t_userid = user_get_id_by_name($t_username);
+                                if ( false == $t_userid ) {
+                                        user_create( $t_username, '' );
+                                        # @@@ Wow, this is pretty lame
+                                        $t_userid = user_get_id_by_name($t_username);
+                                }
+                                # @@@ maybe we can optimize this to write all fields at once?
+                                foreach ( $t_field_map as $key=>$t_userfield ) {
+                                        if (isset($t_info[0][$key][0])) {
+                                                user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                                        }
+                                }
+                        }
+
+                        // Update user's overall language preference
+                        if ($t_ldap_language_field) {
+                                $t_language = $t_info[0][$t_ldap_language_field][0];
+                                // Map the LDAP language field to Mantis' language field if needed
+                                $t_language_keys = config_get( 'ldap_language_keys', '');
+                                $t_language_values = config_get( 'ldap_language_values', '');
+                                $t_language_map = array_combine(
+                                        explode(',', $t_language_keys),
+                                        explode(',', $t_language_values)
+                                );
+                                if (isset($t_language_map[$t_language])) {
+                                        $t_language = $t_language_map[$t_language];
+                                }
+                                user_pref_set_pref($t_userid, 'language', $t_language);
+                        }
+                }
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+
+        return $t_username;
+}
+
+
+/**
+ * Logs out of CAS, redirecting to Mantis on re-login.
+ * User should already be logged out of Mantis by the time this is called.
+ * @see auth_logout()
+ */
+function auth_cas_logout()
+{
+        $t_path = config_get('path');
+
+        auth_cas_init();
+        if (method_Exists('phpCAS', 'logoutWithUrl')) {
+                phpCAS::logoutWithUrl($t_path);
+        } else {
+                phpCAS::logout($t_path);
+        }
+}
+
+
+/**
  * Check that there is a user logged-in and authenticated
  * If the user's account is disabled they will be logged out
  * If there is no user logged in, redirect to the login page
@@ -182,7 +366,8 @@
 	$t_login_method = config_get( 'login_method' );
 
 	if ( false === $t_user_id ) {
-		if ( BASIC_AUTH == $t_login_method ) {
+		if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+			# attempt to create the user if using BASIC_AUTH or CAS_AUTH
 			$t_auto_create = true;
 		} else if ( LDAP == $t_login_method && ldap_authenticate_by_username( $p_username, $p_password ) ) {
 			$t_auto_create = true;
@@ -311,6 +496,10 @@
 	if( HTTP_AUTH == config_get( 'login_method' ) ) {
 		auth_http_set_logout_pending( true );
 	}
+	elseif ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# Redirect to CAS page to logout
+		auth_cas_logout();
+	}
 
 	session_clean();
 }
@@ -324,6 +513,8 @@
 	switch( config_get( 'login_method' ) ) {
 		case HTTP_AUTH:
 			return true;
+		case CAS_AUTH:
+			return true;
 	}
 	return false;
 }
@@ -342,6 +533,10 @@
 	if( LDAP == $t_configured_login_method ) {
 		return ldap_authenticate( $p_user_id, $p_test_password );
 	}
+	elseif ( CAS_AUTH == $t_configured_login_method ) {
+		# CAS already took care of password verification for us
+		return true;
+	}
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
@@ -617,7 +812,7 @@
  * @access public
  */
 function auth_reauthenticate() {
-	if( config_get_global( 'reauthentication' ) == OFF || BASIC_AUTH == config_get( 'login_method' ) || HTTP_AUTH == config_get( 'login_method' ) ) {
+	if( config_get_global( 'reauthentication' ) == OFF || in_array(config_get('login_method'), array(BASIC_AUTH, HTTP_AUTH, CAS_AUTH)) ) {
 		return true;
 	}
 
diff -ur mantisbt-1.2.5/core/constant_inc.php mantisbt-1.2.5-CAS/core/constant_inc.php
--- mantisbt-1.2.5/core/constant_inc.php	Tue Apr  5 20:24:17 2011
+++ mantisbt-1.2.5-CAS/core/constant_inc.php	Fri Jun 17 14:00:53 2011
@@ -134,6 +134,7 @@
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'CAS_AUTH', 7);
 
 # file upload methods
 define( 'DISK', 1 );
mdevilz

mdevilz

2011-09-01 23:14

reporter   ~0029618

Last edited: 2011-09-01 23:14

View 2 revisions

Anyone test this with 1.2.7?

zdevex

zdevex

2012-01-24 21:15

reporter  

mantisbt-1.2.8-CAS.patch (16,154 bytes)
diff -ur mantisbt-1.2.8/config_defaults_inc.php mantisbt-1.2.8-CAS//config_defaults_inc.php
--- mantisbt-1.2.8/config_defaults_inc.php	2011-09-06 08:23:10.000000000 -0600
+++ mantisbt-1.2.8-CAS//config_defaults_inc.php	2012-01-24 18:57:36.257115000 -0700
@@ -1651,6 +1651,110 @@
 	 */
 	$g_hr_width				= 50;
 
+
+	/***********************
+	 * Mantis CAS Settings *
+	 ***********************/
+
+	# --- using phpCAS -------------
+	/**
+	 * @global string $g_cas_server
+	 */
+	$g_cas_server = 'example.com.au';
+
+	/**
+	 * @global int $g_cas_port
+	 */
+	$g_cas_port = 443;
+
+	/**
+	 * The CAS path on the server. E.g. '/cas'
+	 * @global string $g_cas_uri
+	 */
+	$g_cas_uri = '';
+	
+	/**
+	 * The CAS validation URL to the server
+	 * @global string $g_cas_validation
+	 */
+	$g_cas_validate = '';
+
+	/**
+	 * Protocol version 2.0 (to use CAS) or S1 (to use SAML)
+	 * @global string $g_cas_version
+	 */
+	$g_cas_version = '2.0';
+	
+	/**
+	 * Full path incl filename to the cas debug log file
+	 * @global string $g_cas_debug
+	 */
+	$g_cas_debug = '';
+	
+	/**
+	 * When using SAML the CAS can provide user attributes
+	 * @global boolean $g_cas_saml_attributes
+	 */
+	$g_cas_saml_attributes = OFF;
+	
+	/**
+	 * Array with two entries: name => ..., mail => ...
+	 * Look in your WEB-INF/deployerConfigContext.xml at the CAS server
+	 * @global array $g_cas_saml_map
+	 */
+	$g_cas_saml_map = array( 'name' => '', 'mail' => '' );
+	
+
+	# --- CAS + LDAP -------------
+	/**
+	 * Translate CAS username through LDAP.
+	 * @global $g_cas_use_ldap int
+	 */
+	$g_cas_use_ldap     = OFF;
+
+	/**
+	 * The LDAP field matching the Mantis username.
+	 * @global $g_ldap_mantis_udi string
+	 */
+	$g_ldap_mantis_uid  = 'uid';
+
+	/**
+	 * Should Mantis update user details from LDAP while authenticating with CAS?
+	 * @global $g_cas_ldap_update int
+	 */
+	$g_cas_ldap_update  = OFF;
+
+	/**
+	 * E.g. 'cn,userpassword'.
+	 * @global $g_cas_ldap_update_fields string
+	 */
+	$g_cas_ldap_update_fields = '';
+
+	/**
+	 * E.g. 'realname,password'.
+	 * @global $g_cas_ldap_update_map string
+	 */
+	$g_cas_ldap_update_map    = '';
+
+	/**
+	 * This is the field in LDAP to use to set the user's language preference.
+	 * @global $g_ldap_language_field string
+	 */
+	$g_ldap_language_field = '';
+
+	/**
+	 * E.g. 'en,zh_hans,ko'.
+	 * @global $g_ldap_language_keys string
+	 */
+	$g_ldap_language_keys = '';
+
+	/**
+	 * E.g. 'english,chinese_simplified,korean'.
+	 * @global $g_ldap_language_values string
+	 */
+	$g_cas_ldap_update_values    = '';
+
+
 	/**************************
 	 * MantisBT LDAP Settings *
 	 **************************/
@@ -2506,7 +2610,7 @@
 
 	/**
 	 * login method
-	 * MD5, LDAP, BASIC_AUTH or HTTP_AUTH.
+	 * MD5, LDAP, BASIC_AUTH, HTTP_AUTH, or CAS_AUTH.
 	 * Note: you may not be able to easily switch encryption methods, so this
 	 * should be carefully chosen at install time. However, MantisBT will attempt
 	 * to "fall back" to older methods if possible.
diff -ur mantisbt-1.2.8/core/authentication_api.php mantisbt-1.2.8-CAS//core/authentication_api.php
--- mantisbt-1.2.8/core/authentication_api.php	2011-09-06 08:23:10.000000000 -0600
+++ mantisbt-1.2.8-CAS//core/authentication_api.php	2012-01-24 18:57:36.257115000 -0700
@@ -53,6 +53,191 @@
 $g_cache_current_user_id = null;
 
 /**
+ * Initialize phpCAS.
+ */
+function auth_cas_init() {
+        # phpCAS must be installed in the include path
+        # or in the Mantis directory.
+        require_once('CAS.php');
+
+        static $s_initialized=false;
+
+        if (! $s_initialized ) {
+                phpCAS::setDebug( config_get( 'cas_debug' ) );
+        ## These should be set in config_inc.php
+                $t_server_version = config_get( 'cas_version' );
+                $t_server_cas_server = config_get( 'cas_server' );
+                $t_server_port = config_get( 'cas_port' );
+                $t_server_uri = config_get( 'cas_uri' );
+                $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+
+                phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+                if ($t_server_version == "S1")
+                        phpCAS::setServerSamlValidateURL( config_get( 'cas_validate' ) );
+                else
+                        phpCAS::setServerProxyValidateURL( config_get( 'cas_validate' ) );
+                if (method_exists('phpCAS', 'setNoCasServerValidation')) {
+                        // no SSL validation for the CAS server
+                        phpCAS::setNoCasServerValidation();
+                }
+
+                $s_initialized = true;
+        }
+
+}
+
+
+/**
+ * Fetches the user's CAS name, authenticating if needed.
+ * Can translate CAS login name to Mantis username through LDAP.
+ */
+function auth_cas_get_name()
+{
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        phpCAS::forceAuthentication();
+        $t_cas_id = phpCAS::getUser();
+        $t_cas_attribs = phpCAS::getAttributes();
+
+        # If needed, translate the CAS username through LDAP
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+                $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }
+        elseif (config_get( 'cas_saml_attributes', false )) {
+                $t_cas_attribmap = config_get( 'cas_saml_map', array() );
+                $t_cas_attrib_name = $t_cas_attribs[$t_cas_attribmap['name']];
+                $t_cas_attrib_mail = $t_cas_attribs[$t_cas_attribmap['mail']];
+                if ( user_get_id_by_name($t_cas_id) == false ) {
+                        user_create( $t_cas_id, '', $t_cas_attrib_mail, null, false, true, $t_cas_attrib_name );
+	         }
+        }
+                                
+        return $t_username;
+}
+
+/**
+ * Takes an ID string, and looks up the LDAP directory to find
+ * the matching username for Mantis.
+ *
+ * Optionally, also update the user information in the Mantis user
+ * table.
+ *
+ * @param $p_cas_id string Typically, the username given by phpCAS.
+ * @param $p_update_user bool Whether or not to update user details from LDAP.
+ */
+function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+{
+
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+
+        $t_ldap_organization    = config_get( 'ldap_organization' );
+        $t_ldap_root_dn         = config_get( 'ldap_root_dn' );
+
+        # Required fields in LDAP for CAS
+        $t_ldap_language_field = config_get( 'ldap_language_field', '' );
+        $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ) ;
+        $t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        if ($t_ldap_language_field) {
+                // Add language field to attributes list only if it is configured.
+                $t_ldap_required[] = $t_ldap_language_field;
+        }
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+        # User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+        $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+        $t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);      # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+        $t_sr   = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+        $t_info = ldap_get_entries( $t_ds, $t_sr );
+        # Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+                # Get Mantis username
+                $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+
+                # @@@ The fact that we got here means the user is authenticated
+                # @@@ by CAS, and has an LDAP entry.
+                # @@@ We might as well update other user details since we are here.
+
+                # If no argument given, check settings
+                if ( '' == $p_update_user ) {
+                        $p_update_user = config_get( 'cas_ldap_update', FALSE );
+                }
+                # If there's a user record, then update it
+                if ( $p_update_user ) {
+                        # Only proceed if the field map arrays are the same length
+                        $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                        if ($t_field_map) {
+                                # If user is new, then we must create their account before updating it
+                                # @@@ ( make sure $g_allow_blank_email == ON )
+                                $t_userid = user_get_id_by_name($t_username);
+                                if ( false == $t_userid ) {
+                                        user_create( $t_username, '' );
+                                        # @@@ Wow, this is pretty lame
+                                        $t_userid = user_get_id_by_name($t_username);
+                                }
+                                # @@@ maybe we can optimize this to write all fields at once?
+                                foreach ( $t_field_map as $key=>$t_userfield ) {
+                                        if (isset($t_info[0][$key][0])) {
+                                                user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                                        }
+                                }
+                        }
+
+                        // Update user's overall language preference
+                        if ($t_ldap_language_field) {
+                                $t_language = $t_info[0][$t_ldap_language_field][0];
+                                // Map the LDAP language field to Mantis' language field if needed
+                                $t_language_keys = config_get( 'ldap_language_keys', '');
+                                $t_language_values = config_get( 'ldap_language_values', '');
+                                $t_language_map = array_combine(
+                                        explode(',', $t_language_keys),
+                                        explode(',', $t_language_values)
+                                );
+                                if (isset($t_language_map[$t_language])) {
+                                        $t_language = $t_language_map[$t_language];
+                                }
+                                user_pref_set_pref($t_userid, 'language', $t_language);
+                        }
+                }
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+
+        return $t_username;
+}
+
+
+/**
+ * Logs out of CAS, redirecting to Mantis on re-login.
+ * User should already be logged out of Mantis by the time this is called.
+ * @see auth_logout()
+ */
+function auth_cas_logout()
+{
+        $t_path = config_get('path');
+
+        auth_cas_init();
+        if (method_Exists('phpCAS', 'logoutWithUrl')) {
+                phpCAS::logoutWithUrl($t_path);
+        } else {
+                phpCAS::logout($t_path);
+        }
+}
+
+
+
+/**
  * Check that there is a user logged-in and authenticated
  * If the user's account is disabled they will be logged out
  * If there is no user logged in, redirect to the login page
@@ -182,7 +367,8 @@
 	$t_login_method = config_get( 'login_method' );
 
 	if ( false === $t_user_id ) {
-		if ( BASIC_AUTH == $t_login_method ) {
+		if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+			# attempt to create the user if using BASIC_AUTH or CAS_AUTH
 			$t_auto_create = true;
 		} else if ( LDAP == $t_login_method && ldap_authenticate_by_username( $p_username, $p_password ) ) {
 			$t_auto_create = true;
@@ -312,6 +498,11 @@
 		auth_http_set_logout_pending( true );
 	}
 
+	elseif ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# Redirect to CAS page to logout
+		auth_cas_logout();
+	}
+
 	session_clean();
 }
 
@@ -324,6 +515,8 @@
 	switch( config_get( 'login_method' ) ) {
 		case HTTP_AUTH:
 			return true;
+		case CAS_AUTH:
+			return true;
 	}
 	return false;
 }
@@ -362,6 +555,11 @@
 	if( LDAP == $t_configured_login_method ) {
 		return ldap_authenticate( $p_user_id, $p_test_password );
 	}
+	elseif ( CAS_AUTH == $t_configured_login_method ) {
+		# CAS already took care of password verification for us
+		# WARNING: this statement may open mantisconnect to full access without authentication.  This issue should be looked into and considered when using this patch.  For more info see thread at "http://www.mantisbt.org/bugs/view.php?id=7568"
+		return true;
+	}
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
@@ -637,7 +835,7 @@
  * @access public
  */
 function auth_reauthenticate() {
-	if( config_get_global( 'reauthentication' ) == OFF || BASIC_AUTH == config_get( 'login_method' ) || HTTP_AUTH == config_get( 'login_method' ) ) {
+	if( config_get_global( 'reauthentication' ) == OFF || in_array(config_get('login_method'), array(BASIC_AUTH, HTTP_AUTH, CAS_AUTH)) ) {
 		return true;
 	}
 
diff -ur mantisbt-1.2.8/core/constant_inc.php mantisbt-1.2.8-CAS//core/constant_inc.php
--- mantisbt-1.2.8/core/constant_inc.php	2011-09-06 08:23:10.000000000 -0600
+++ mantisbt-1.2.8-CAS//core/constant_inc.php	2012-01-24 18:57:36.257115000 -0700
@@ -134,6 +134,7 @@
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'CAS_AUTH', 7);
 
 # file upload methods
 define( 'DISK', 1 );
diff -ur mantisbt-1.2.8/login_page.php mantisbt-1.2.8-CAS//login_page.php
--- mantisbt-1.2.8/login_page.php	2011-09-06 08:23:11.000000000 -0600
+++ mantisbt-1.2.8-CAS//login_page.php	2012-01-24 18:57:36.257115000 -0700
@@ -33,11 +33,11 @@
 	}
 
 	$f_error		= gpc_get_bool( 'error' );
-	$f_cookie_error	= gpc_get_bool( 'cookie_error' );
+	$f_cookie_error		= gpc_get_bool( 'cookie_error' );
 	$f_return		= string_sanitize_url( gpc_get_string( 'return', '' ) );
-	$f_username     = gpc_get_string( 'username', '' );
-	$f_perm_login	= gpc_get_bool( 'perm_login', false );
-	$f_secure_session = gpc_get_bool( 'secure_session', false );
+	$f_username     	= gpc_get_string( 'username', '' );
+	$f_perm_login		= gpc_get_bool( 'perm_login', false );
+	$f_secure_session 	= gpc_get_bool( 'secure_session', false );
 	$f_secure_session_cookie = gpc_get_cookie( config_get_global( 'cookie_prefix' ) . '_secure_session', null );
 
 	$t_session_validation = ( ON == config_get_global( 'session_validation' ) );
diff -ur mantisbt-1.2.8/login.php mantisbt-1.2.8-CAS//login.php
--- mantisbt-1.2.8/login.php	2011-09-06 08:23:11.000000000 -0600
+++ mantisbt-1.2.8-CAS//login.php	2012-01-24 18:57:36.257115000 -0700
@@ -28,10 +28,17 @@
 
 	$f_username		= gpc_get_string( 'username', '' );
 	$f_password		= gpc_get_string( 'password', '' );
-	$f_perm_login	= gpc_get_bool( 'perm_login' );
+	$f_perm_login		= gpc_get_bool( 'perm_login' );
 	$t_return		= string_url( string_sanitize_url( gpc_get_string( 'return', config_get( 'default_home_page' ) ) ) );
 	$f_from			= gpc_get_string( 'from', '' );
-	$f_secure_session = gpc_get_bool( 'secure_session', false );
+	$f_secure_session 	= gpc_get_bool( 'secure_session', false );
+
+	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# This will detour to the CAS login page if needed
+		$f_password = '';
+		$f_username = auth_cas_get_name();
+		# User is always authenticated by this point
+	}
 
 	$f_username = auth_prepare_username($f_username);
 	$f_password = auth_prepare_password($f_password);
@@ -56,3 +63,5 @@
 	}
 
 	print_header_redirect( $t_redirect_url );
+
+?>
mantisbt-1.2.8-CAS.patch (16,154 bytes)
zdevex

zdevex

2012-01-24 21:16

reporter   ~0031021

I translated the patch for 1.2.8, it is now uploaded.

zdevex

zdevex

2012-03-30 17:15

reporter  

mantisbt-1.2.9-CAS.patch (14,699 bytes)
diff -ur mantisbt-1.2.9/config_defaults_inc.php mantisbt-1.2.9-CAS//config_defaults_inc.php
--- mantisbt-1.2.9/config_defaults_inc.php	2012-03-03 19:32:43.000000000 -0700
+++ mantisbt-1.2.9-CAS//config_defaults_inc.php	2012-03-20 20:54:36.831013000 -0600
@@ -1661,6 +1661,108 @@
 	 */
 	$g_hr_width				= 50;
 
+	/***********************
+	 * Mantis CAS Settings *
+	 ***********************/
+
+	# --- using phpCAS -------------
+	/**
+	 * @global string $g_cas_server
+	 */
+	$g_cas_server = 'example.com.au';
+
+	/**
+	 * @global int $g_cas_port
+	 */
+	$g_cas_port = 443;
+
+	/**
+	 * The CAS path on the server. E.g. '/cas'
+	 * @global string $g_cas_uri
+	 */
+	$g_cas_uri = '';
+	
+	/**
+	 * The CAS validation URL to the server
+	 * @global string $g_cas_validation
+	 */
+	$g_cas_validate = '';
+
+	/**
+	 * Protocol version 2.0 (to use CAS) or S1 (to use SAML)
+	 * @global string $g_cas_version
+	 */
+	$g_cas_version = '2.0';
+	
+	/**
+	 * Full path incl filename to the cas debug log file
+	 * @global string $g_cas_debug
+	 */
+	$g_cas_debug = '';
+	
+	/**
+	 * When using SAML the CAS can provide user attributes
+	 * @global boolean $g_cas_saml_attributes
+	 */
+	$g_cas_saml_attributes = OFF;
+	
+	/**
+	 * Array with two entries: name => ..., mail => ...
+	 * Look in your WEB-INF/deployerConfigContext.xml at the CAS server
+	 * @global array $g_cas_saml_map
+	 */
+	$g_cas_saml_map = array( 'name' => '', 'mail' => '' );
+	
+
+	# --- CAS + LDAP -------------
+	/**
+	 * Translate CAS username through LDAP.
+	 * @global $g_cas_use_ldap int
+	 */
+	$g_cas_use_ldap     = OFF;
+
+	/**
+	 * The LDAP field matching the Mantis username.
+	 * @global $g_ldap_mantis_udi string
+	 */
+	$g_ldap_mantis_uid  = 'uid';
+
+	/**
+	 * Should Mantis update user details from LDAP while authenticating with CAS?
+	 * @global $g_cas_ldap_update int
+	 */
+	$g_cas_ldap_update  = OFF;
+
+	/**
+	 * E.g. 'cn,userpassword'.
+	 * @global $g_cas_ldap_update_fields string
+	 */
+	$g_cas_ldap_update_fields = '';
+
+	/**
+	 * E.g. 'realname,password'.
+	 * @global $g_cas_ldap_update_map string
+	 */
+	$g_cas_ldap_update_map    = '';
+
+	/**
+	 * This is the field in LDAP to use to set the user's language preference.
+	 * @global $g_ldap_language_field string
+	 */
+	$g_ldap_language_field = '';
+
+	/**
+	 * E.g. 'en,zh_hans,ko'.
+	 * @global $g_ldap_language_keys string
+	 */
+	$g_ldap_language_keys = '';
+
+	/**
+	 * E.g. 'english,chinese_simplified,korean'.
+	 * @global $g_ldap_language_values string
+	 */
+	$g_cas_ldap_update_values    = '';
+
 	/**************************
 	 * MantisBT LDAP Settings *
 	 **************************/
@@ -2504,7 +2606,7 @@
 
 	/**
 	 * login method
-	 * MD5, LDAP, BASIC_AUTH or HTTP_AUTH.
+	 * MD5, LDAP, BASIC_AUTH, HTTP_AUTH, or CAS_AUTH.
 	 * Note: you may not be able to easily switch encryption methods, so this
 	 * should be carefully chosen at install time. However, MantisBT will attempt
 	 * to "fall back" to older methods if possible.
diff -ur mantisbt-1.2.9/core/authentication_api.php mantisbt-1.2.9-CAS//core/authentication_api.php
--- mantisbt-1.2.9/core/authentication_api.php	2012-03-03 19:32:43.000000000 -0700
+++ mantisbt-1.2.9-CAS//core/authentication_api.php	2012-03-20 20:54:36.831013000 -0600
@@ -53,6 +53,190 @@
 $g_cache_current_user_id = null;
 
 /**
+ * Initialize phpCAS.
+ */
+function auth_cas_init() {
+        # phpCAS must be installed in the include path
+        # or in the Mantis directory.
+        require_once('CAS.php');
+
+        static $s_initialized=false;
+
+        if (! $s_initialized ) {
+                phpCAS::setDebug( config_get( 'cas_debug' ) );
+        ## These should be set in config_inc.php
+                $t_server_version = config_get( 'cas_version' );
+                $t_server_cas_server = config_get( 'cas_server' );
+                $t_server_port = config_get( 'cas_port' );
+                $t_server_uri = config_get( 'cas_uri' );
+                $t_start_session = (boolean)FALSE; # Mantis takes care of its own session
+
+                phpCAS::client($t_server_version, $t_server_cas_server, $t_server_port, $t_server_uri, $t_start_session);
+                if ($t_server_version == "S1")
+                        phpCAS::setServerSamlValidateURL( config_get( 'cas_validate' ) );
+                else
+                        phpCAS::setServerProxyValidateURL( config_get( 'cas_validate' ) );
+                if (method_exists('phpCAS', 'setNoCasServerValidation')) {
+                        // no SSL validation for the CAS server
+                        phpCAS::setNoCasServerValidation();
+                }
+
+                $s_initialized = true;
+        }
+
+}
+
+
+/**
+ * Fetches the user's CAS name, authenticating if needed.
+ * Can translate CAS login name to Mantis username through LDAP.
+ */
+function auth_cas_get_name()
+{
+        # Get CAS username from phpCAS
+        auth_cas_init();
+        phpCAS::forceAuthentication();
+        $t_cas_id = phpCAS::getUser();
+        $t_cas_attribs = phpCAS::getAttributes();
+
+        # If needed, translate the CAS username through LDAP
+        $t_username = $t_cas_id;
+        if (config_get( 'cas_use_ldap', false )) {
+                $t_username = auth_cas_ldap_translate( $t_cas_id );
+        }
+        elseif (config_get( 'cas_saml_attributes', false )) {
+                $t_cas_attribmap = config_get( 'cas_saml_map', array() );
+                $t_cas_attrib_name = $t_cas_attribs[$t_cas_attribmap['name']];
+                $t_cas_attrib_mail = $t_cas_attribs[$t_cas_attribmap['mail']];
+                if ( user_get_id_by_name($t_cas_id) == false ) {
+                        user_create( $t_cas_id, '', $t_cas_attrib_mail, null, false, true, $t_cas_attrib_name );
+	         }
+        }
+                                
+        return $t_username;
+}
+
+/**
+ * Takes an ID string, and looks up the LDAP directory to find
+ * the matching username for Mantis.
+ *
+ * Optionally, also update the user information in the Mantis user
+ * table.
+ *
+ * @param $p_cas_id string Typically, the username given by phpCAS.
+ * @param $p_update_user bool Whether or not to update user details from LDAP.
+ */
+function auth_cas_ldap_translate( $p_cas_id, $p_update_user='' )
+{
+
+        # Please make sure the Mantis CAS and LDAP settings are set in config_inc.php
+
+        $t_ldap_organization    = config_get( 'ldap_organization' );
+        $t_ldap_root_dn         = config_get( 'ldap_root_dn' );
+
+        # Required fields in LDAP for CAS
+        $t_ldap_language_field = config_get( 'ldap_language_field', '' );
+        $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ) ;
+        $t_ldap_mantis_uid = config_get( 'ldap_mantis_uid', 'uid' );
+        $t_ldap_required = array( $t_ldap_uid_field, $t_ldap_mantis_uid, 'dn' );
+        if ($t_ldap_language_field) {
+                // Add language field to attributes list only if it is configured.
+                $t_ldap_required[] = $t_ldap_language_field;
+        }
+        $t_ldap_required = array_combine( $t_ldap_required, $t_ldap_required );
+
+        # User-defined fields to fetch from LDAP...
+        $t_ldap_fields = explode( ',', config_get( 'cas_ldap_update_fields' ) );
+        $t_ldap_fields = array_combine( $t_ldap_fields, $t_ldap_fields );
+        # ...which are mapped to Mantis user fields
+        $t_ldap_map = explode( ',', config_get( 'cas_ldap_update_map' ) );
+        $t_ldap_map = array_combine( $t_ldap_map, $t_ldap_map );
+
+        # Build LDAP search filter, attribute list from CAS ID
+        $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_cas_id))";
+        $t_search_attrs = array_values($t_ldap_required + $t_ldap_fields);      # array union
+
+        # Use Mantis ldap_api to connect to LDAP
+        $t_ds = ldap_connect_bind();
+        $t_sr   = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs );
+        $t_info = ldap_get_entries( $t_ds, $t_sr );
+        # Parse the LDAP entry to find the Mantis username
+        if ( $t_info ) {
+                # Get Mantis username
+                $t_username = $t_info[0][$t_ldap_mantis_uid][0];
+
+                # @@@ The fact that we got here means the user is authenticated
+                # @@@ by CAS, and has an LDAP entry.
+                # @@@ We might as well update other user details since we are here.
+
+                # If no argument given, check settings
+                if ( '' == $p_update_user ) {
+                        $p_update_user = config_get( 'cas_ldap_update', FALSE );
+                }
+                # If there's a user record, then update it
+                if ( $p_update_user ) {
+                        # Only proceed if the field map arrays are the same length
+                        $t_field_map = array_combine( $t_ldap_fields, $t_ldap_map );
+                        if ($t_field_map) {
+                                # If user is new, then we must create their account before updating it
+                                # @@@ ( make sure $g_allow_blank_email == ON )
+                                $t_userid = user_get_id_by_name($t_username);
+                                if ( false == $t_userid ) {
+                                        user_create( $t_username, '' );
+                                        # @@@ Wow, this is pretty lame
+                                        $t_userid = user_get_id_by_name($t_username);
+                                }
+                                # @@@ maybe we can optimize this to write all fields at once?
+                                foreach ( $t_field_map as $key=>$t_userfield ) {
+                                        if (isset($t_info[0][$key][0])) {
+                                                user_set_field( $t_userid, $t_userfield, $t_info[0][$key][0] );
+                                        }
+                                }
+                        }
+
+                        // Update user's overall language preference
+                        if ($t_ldap_language_field) {
+                                $t_language = $t_info[0][$t_ldap_language_field][0];
+                                // Map the LDAP language field to Mantis' language field if needed
+                                $t_language_keys = config_get( 'ldap_language_keys', '');
+                                $t_language_values = config_get( 'ldap_language_values', '');
+                                $t_language_map = array_combine(
+                                        explode(',', $t_language_keys),
+                                        explode(',', $t_language_values)
+                                );
+                                if (isset($t_language_map[$t_language])) {
+                                        $t_language = $t_language_map[$t_language];
+                                }
+                                user_pref_set_pref($t_userid, 'language', $t_language);
+                        }
+                }
+        }
+        ldap_free_result( $t_sr );
+        ldap_unbind( $t_ds );
+
+        return $t_username;
+}
+
+
+/**
+ * Logs out of CAS, redirecting to Mantis on re-login.
+ * User should already be logged out of Mantis by the time this is called.
+ * @see auth_logout()
+ */
+function auth_cas_logout()
+{
+        $t_path = config_get('path');
+
+        auth_cas_init();
+        if (method_Exists('phpCAS', 'logoutWithUrl')) {
+                phpCAS::logoutWithUrl($t_path);
+        } else {
+                phpCAS::logout($t_path);
+        }
+}
+
+
+/**
  * Check that there is a user logged-in and authenticated
  * If the user's account is disabled they will be logged out
  * If there is no user logged in, redirect to the login page
@@ -182,7 +366,8 @@
 	$t_login_method = config_get( 'login_method' );
 
 	if ( false === $t_user_id ) {
-		if ( BASIC_AUTH == $t_login_method ) {
+		if ( in_array( $t_login_method, array( BASIC_AUTH, CAS_AUTH ) ) ) {
+			# attempt to create the user if using BASIC_AUTH or CAS_AUTH
 			$t_auto_create = true;
 		} else if ( LDAP == $t_login_method && ldap_authenticate_by_username( $p_username, $p_password ) ) {
 			$t_auto_create = true;
@@ -312,6 +497,12 @@
 		auth_http_set_logout_pending( true );
 	}
 
+
+	elseif ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# Redirect to CAS page to logout
+		auth_cas_logout();
+	}
+
 	session_clean();
 }
 
@@ -324,6 +515,8 @@
 	switch( config_get( 'login_method' ) ) {
 		case HTTP_AUTH:
 			return true;
+		case CAS_AUTH:
+			return true;
 	}
 	return false;
 }
@@ -362,6 +555,11 @@
 	if( LDAP == $t_configured_login_method ) {
 		return ldap_authenticate( $p_user_id, $p_test_password );
 	}
+	elseif ( CAS_AUTH == $t_configured_login_method ) {
+		# CAS already took care of password verification for us
+		# WARNING: this statement may open mantisconnect to full access without authentication.  This issue should be looked into and considered when using this patch.  For more info see thread at "http://www.mantisbt.org/bugs/view.php?id=7568"
+		return true;
+	}
 
 	$t_password = user_get_field( $p_user_id, 'password' );
 	$t_login_methods = Array(
@@ -637,7 +835,7 @@
  * @access public
  */
 function auth_reauthenticate() {
-	if( config_get_global( 'reauthentication' ) == OFF || BASIC_AUTH == config_get( 'login_method' ) || HTTP_AUTH == config_get( 'login_method' ) ) {
+	if( config_get_global( 'reauthentication' ) == OFF || in_array(config_get('login_method'), array(BASIC_AUTH, HTTP_AUTH, CAS_AUTH)) ) {
 		return true;
 	}
 
diff -ur mantisbt-1.2.9/core/constant_inc.php mantisbt-1.2.9-CAS//core/constant_inc.php
--- mantisbt-1.2.9/core/constant_inc.php	2012-03-03 19:32:43.000000000 -0700
+++ mantisbt-1.2.9-CAS//core/constant_inc.php	2012-03-26 16:48:41.531293000 -0600
@@ -134,6 +134,7 @@
 define( 'LDAP', 4 );
 define( 'BASIC_AUTH', 5 );
 define( 'HTTP_AUTH', 6 );
+define( 'CAS_AUTH', 7);
 
 # file upload methods
 define( 'DISK', 1 );
diff -ur mantisbt-1.2.9/login.php mantisbt-1.2.9-CAS//login.php
--- mantisbt-1.2.9/login.php	2012-03-03 19:32:43.000000000 -0700
+++ mantisbt-1.2.9-CAS//login.php	2012-03-26 16:48:41.531293000 -0600
@@ -33,6 +33,13 @@
 	$f_from			= gpc_get_string( 'from', '' );
 	$f_secure_session = gpc_get_bool( 'secure_session', false );
 
+	if ( CAS_AUTH == config_get( 'login_method' ) ) {
+		# This will detour to the CAS login page if needed
+		$f_password = '';
+		$f_username = auth_cas_get_name();
+		# User is always authenticated by this point
+	}
+
 	$f_username = auth_prepare_username($f_username);
 	$f_password = auth_prepare_password($f_password);
 
mantisbt-1.2.9-CAS.patch (14,699 bytes)
zdevex

zdevex

2012-03-30 17:15

reporter   ~0031576

Updated the patch for 1.2.9.

herringm

herringm

2013-11-07 15:22

reporter   ~0038499

Any chance this can get targeted against v1.3.x and released with 1.3.0? We use Mantis with CAS making it a pain to upgrade.

alexket

alexket

2014-07-07 05:44

reporter   ~0040883

I've manually integrated patch for 1.2.9 on 1.2.17 & found one problem with email validation.
In function email_is_valid, the login method is tested against LDAP only. In my cas I use CAS & LDAP synchronization, so I had to update the test on the login as folllowing:
( (LDAP == config_get( 'login_method' )) || (CAS_AUTH == config_get('login_method' )) ) && ...

Issue History

Date Modified Username Field Change
2006-11-06 20:48 joshua_chan New Issue
2006-11-06 20:58 joshua_chan File Added: mantis-1.0.5-phpCAS_changes.tar.gz
2006-11-06 20:59 joshua_chan Note Added: 0013686
2006-11-07 02:07 vboctor Relationship added related to 0004234
2006-11-09 05:51 TOTOleHero Note Added: 0013705
2007-07-06 10:30 vboctor Category feature => authentication
2007-11-28 09:23 lmeunier File Added: mantis-1.1.0rc2_cas.patch
2007-11-28 09:24 lmeunier Note Added: 0016320
2008-01-17 17:10 foo Note Added: 0016707
2008-07-15 04:03 wdouglascampbell Note Added: 0018535
2008-07-15 04:06 vboctor Tag Attached: patch
2008-07-15 04:08 vboctor Relationship replaced has duplicate 0004234
2008-07-15 14:05 grangeway Status new => assigned
2008-07-15 14:05 grangeway Assigned To => grangeway
2008-10-21 11:59 mstrumyla File Added: mantis-1.1.4+phpcas-1.0.1.patch
2008-10-21 12:01 mstrumyla Note Added: 0019620
2009-02-19 14:46 joshua_chan File Added: mantis-1.2.0a3_cas.patch
2009-02-19 14:53 joshua_chan Note Added: 0020900
2010-01-29 06:47 agarcia Note Added: 0024268
2010-01-29 10:24 mstrumyla Note Added: 0024269
2010-01-29 10:46 agarcia Note Added: 0024270
2010-04-24 11:29 wdouglascampbell Note Added: 0025245
2010-04-24 11:30 wdouglascampbell File Added: mantis-1.2.1_cas.patch
2010-07-19 04:00 SchoutenCC Note Added: 0026096
2010-07-20 21:31 wdouglascampbell Note Added: 0026108
2010-07-21 02:29 SchoutenCC Note Added: 0026109
2011-01-02 23:11 rgomes1997 Note Added: 0027773
2011-03-24 12:43 fwestanqueiro Note Added: 0028466
2011-05-31 18:49 mdevilz File Added: phpcas-mantisbt-1.2.5.patch
2011-05-31 18:51 mdevilz Note Added: 0028880
2011-06-16 11:04 foo Note Added: 0029024
2011-06-17 05:08 pzYsTorM Note Added: 0029030
2011-06-17 12:21 pzYsTorM File Added: phpcas-mantisbt-1.2.5-corr.patch
2011-06-17 12:25 pzYsTorM Note Added: 0029035
2011-06-17 16:43 foo Note Added: 0029037
2011-06-17 16:45 foo File Added: phpcas-mantisbt-1.2.5-corr-validate.patch
2011-09-01 23:14 mdevilz Note Added: 0029618
2011-09-01 23:14 mdevilz Note Edited: 0029618 View Revisions
2012-01-24 21:15 zdevex File Added: mantisbt-1.2.8-CAS.patch
2012-01-24 21:16 zdevex Note Added: 0031021
2012-03-30 17:15 zdevex File Added: mantisbt-1.2.9-CAS.patch
2012-03-30 17:15 zdevex Note Added: 0031576
2013-11-07 15:22 herringm Note Added: 0038499
2014-07-07 05:44 alexket Note Added: 0040883
2014-11-07 16:10 atrol Assigned To grangeway =>
2014-11-07 16:10 atrol Status assigned => new