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);