View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0007568 | mantisbt | authentication | public | 2006-11-06 20:48 | 2020-10-20 18:22 |
Reporter | joshua_chan | Assigned To | |||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | new | Resolution | open | ||
Product Version | 1.0.5 | ||||
Summary | 0007568: 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. | ||||
Tags | patch | ||||
Attached Files | 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.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 ) { 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.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); 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 ); 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 ); 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.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); | ||||
Files affected: core/authentication_api.php |
|
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); |
|
This patch work against Mantis 1.1.0rc2. |
|
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. |
|
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 |
|
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. |
|
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". |
|
WARNING: this patch opens mantisconnect full access without authentication. mantisconnect calls "auth_attempt_script_login" that ends calling api/soap/mc_api.php: function mci_check_login( $p_username, $p_password ) { core/authentication_api.php: function auth_attempt_script_login( $p_username, $p_password = null ) { function auth_does_password_match( $p_user_id, $p_test_password ) { CAS already took care of password verification for us
[...] |
|
Could you clarify which patch you're referring to? Is it mantis-1.2.0a3_cas.patch? |
|
yes, mantis 1.2.0rc2 with mantis-1.2.0a3_cas.patch |
|
Attached is patch for MantisBT 1.2.1. Note that I did not change anything related to the comment posted by agarcia. |
|
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? |
|
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. |
|
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. |
|
Is there a patch for Mantis-1.2.4 ? Thanks |
|
The patch works on 1.2.4? |
|
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. |
|
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? :-) |
|
Why are there so many file changes in the last diff for 1.2.5? |
|
I have corrected the patch (falsely deleted files by a dev, etc.). |
|
@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. |
|
Anyone test this with 1.2.7? |
|
I translated the patch for 1.2.8, it is now uploaded. |
|
Updated the patch for 1.2.9. |
|
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. |
|
I've manually integrated patch for 1.2.9 on 1.2.17 & found one problem with email validation. |
|
Updated patch for 2.24.3. mantisbt-2.24.3.patch (12,445 bytes)
--- mantisbt-2.24.3/config_defaults_inc.php +++ ../mantisbt/config_defaults_inc.php @@ -2006,6 +2006,108 @@ */ $g_wrap_in_preformatted_text = ON; +/*********************** + * 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 Authentication and LDAP Settings # ############################################# --- mantisbt-2.24.3/core/authentication_api.php +++ ../mantisbt/core/authentication_api.php @@ -75,6 +75,182 @@ $g_cache_current_user_id = NO_USER; /** + * 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_global( 'cas_debug' ) ); + + ## These should be set in config_inc.php + $t_server_version = config_get_global( 'cas_version' ); + $t_server_cas_server = config_get_global( 'cas_server' ); + $t_server_port = config_get_global( 'cas_port' ); + $t_server_uri = config_get_global( '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); + phpCAS::setCasServerCACert('/usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt'); + + $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 ); + } + 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_global( 'ldap_organization' ); + $t_ldap_root_dn = config_get_global( 'ldap_root_dn' ); + + # Required fields in LDAP for CAS + $t_ldap_language_field = config_get_global( 'ldap_language_field', '' ); + $t_ldap_uid_field = config_get_global( 'ldap_uid_field', 'uid' ) ; + $t_ldap_mantis_uid = config_get_global( '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_global( '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_global( '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_global( '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_global( 'ldap_language_keys', ''); + $t_language_values = config_get_global( '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_global('path'); + + auth_cas_init(); + if (method_Exists('phpCAS', 'logoutWithRedirectService')) { + phpCAS::logoutWithRedirectService($t_path); + } else { + phpCAS::logout($t_path); + } +} + + +/** * Gets set of flags for authentication for the specified user. * @param int|null|bool $p_user_id The user id or null for logged in user or NO_USER/false for user that doesn't exist * in the system, that may be auto-provisioned. @@ -671,6 +847,10 @@ if( HTTP_AUTH == config_get_global( 'login_method' ) ) { auth_http_set_logout_pending( true ); } + elseif ( CAS_AUTH == config_get_global( 'login_method' ) ) { + # Redirect to CAS page to logout + auth_cas_logout(); + } session_clean(); } @@ -681,7 +861,7 @@ * @access public */ function auth_automatic_logon_bypass_form() { - return config_get_global( 'login_method' ) == HTTP_AUTH; + return (config_get_global( 'login_method' ) == HTTP_AUTH || config_get_global( 'login_method' ) == CAS_AUTH); } /** @@ -718,6 +898,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; + } if( !auth_can_use_standard_login( $p_user_id ) ) { return false; @@ -992,7 +1176,7 @@ * @access public */ function auth_reauthenticate() { - if( !auth_reauthentication_enabled() || BASIC_AUTH == config_get_global( 'login_method' ) || HTTP_AUTH == config_get_global( 'login_method' ) ) { + if( !auth_reauthentication_enabled() || BASIC_AUTH == config_get_global( 'login_method' ) || HTTP_AUTH == config_get_global( 'login_method' ) || CAS_AUTH == config_get_global( 'login_method' ) ) { return true; } --- mantisbt-2.24.3/core/constant_inc.php +++ ../mantisbt/core/constant_inc.php @@ -149,6 +149,7 @@ define( 'LDAP', 4 ); define( 'BASIC_AUTH', 5 ); define( 'HTTP_AUTH', 6 ); +define( 'CAS_AUTH', 7 ); # file upload methods define( 'DISK', 1 ); --- mantisbt-2.24.3/login.php +++ ../mantisbt/login.php @@ -54,6 +54,13 @@ $t_return = 'admin/install.php'; } +if ( CAS_AUTH == config_get_global( '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 ); |
|