View Issue Details

IDProjectCategoryView StatusLast Update
0005595mantisbtldappublic2009-10-07 14:20
Reporterape Assigned Tovboctor  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version0.19.1 
Fixed in Version1.2.0rc2 
Summary0005595: LDAP authentication requires accounts to be manually created first
Description

Currently, users authenticated via LDAP need to already have had an account created for them by an admin in order to use Mantis. It would be great if this needn't be the case.

For example, the option for new users (with valid LDAP logins) to have a basic ('reporter', for instance) account created for them automatically the first time they log in would be hugely valuable, especially for corporate users.

Additional Information

I run Mantis for bug tracking in some software projects I'm involved with at work. At the moment, the development team and (internal) user base is relatively small so creating accounts manually is no big deal.

However, some projects are now being released company-wide (over 50k potential users). I'd rather not have to create 'reporter' accounts for them all by hand!

Tagspatch
Attached Files
get_users_from_ldap (2,042 bytes)
authentication_api.php.patch (877 bytes)   
--- authentication_api_150.php	2005-07-03 07:50:07.815300800 +0100
+++ authentication_api_mine.php	2005-07-03 07:55:16.208748800 +0100
@@ -72,8 +72,8 @@
 		$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 ( BASIC_AUTH == $t_login_method || LDAP == $t_login_method) {
+				# attempt to create the user if using BASIC_AUTH or LDAP
 				$t_cookie_string = user_create( $p_username, $p_password );
 
 				if ( false === $t_cookie_string ) {
@@ -90,6 +90,10 @@
 					# @@@ trigger an error here?
 
 					return false;
+				} elseif ( LDAP == $t_login_method ) {
+					# get the users' email address if using LDAP
+				
+					user_set_email( $t_user_id, ldap_email( $t_user_id ) );
 				}
 			} else {
 				return false;
authentication_api.php.153.patch (849 bytes)   
--- authentication_api.php	10 Aug 2005 16:21:28 -0000	1.53
+++ authentication_api.php	15 Dec 2006 22:55:52 -0000
@@ -72,8 +72,8 @@
 		$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 ( BASIC_AUTH == $t_login_method || LDAP == $t_login_method ) {
+				# attempt to create the user if using BASIC_AUTH or LDAP
 				$t_cookie_string = user_create( $p_username, $p_password );

 				if ( false === $t_cookie_string ) {
@@ -90,6 +90,10 @@
 					# @@@ trigger an error here?

 					return false;
+				} elseif ( LDAP == $t_login_method ) {
+					# get the users' email address if using LDAP
+
+					user_set_email( $t_user_id, ldap_email( $t_user_id ) );
 				}
 			} else {
 				return false;
authentication_api.153.v2.php (17,101 bytes)   
<?php
	# Mantis - a php based bugtracking system
	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
	# Copyright (C) 2002 - 2004  Mantis Team   - mantisbt-dev@lists.sourceforge.net
	# This program is distributed under the terms and conditions of the GPL
	# See the README and LICENSE files for details

	# --------------------------------------------------------
	# $Id: authentication_api.php,v 1.53 2005/08/10 16:21:28 thraxisp Exp $
	# --------------------------------------------------------

	### Authentication API ###

	$g_script_login_cookie = null;
	$g_cache_anonymous_user_cookie_string = null;

	#===================================
	# Boolean queries and ensures
	#===================================

	# --------------------
	# 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
	#  If parameter is given it is used as a URL to redirect to following
	#   successful login.  If none is given, the URL of the current page is used
	function auth_ensure_user_authenticated( $p_return_page = '' ) {
		if ( !php_version_at_least( '4.1.0' ) ) {
			global $_SERVER;
		}

		# if logged in
		if ( auth_is_user_authenticated() ) {
			# check for access enabled
			#  This also makes sure the cookie is valid
			if ( OFF == current_user_get_field( 'enabled' ) ) {
				print_header_redirect( 'logout_page.php' );
			}
		} else { # not logged in
			if ( is_blank( $p_return_page ) ) {
				if (!isset($_SERVER['REQUEST_URI'])) {
					$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
				}
				$p_return_page = $_SERVER['REQUEST_URI'];
			}
			$p_return_page = string_url( $p_return_page );
			print_header_redirect( 'login_page.php?return=' . $p_return_page );
		}
	}

	# --------------------
	# Return true if there is a currently logged in and authenticated user,
	#  false otherwise
	function auth_is_user_authenticated() {
		return ( auth_is_cookie_valid( auth_get_current_user_cookie() ) );
	}


	#===================================
	# Login / Logout
	#===================================

	# --------------------
	# Attempt to login the user with the given password
	#  If the user fails validation, false is returned
	#  If the user passes validation, the cookies are set and
	#   true is returned.  If $p_perm_login is true, the long-term
	#   cookie is created.
	function auth_attempt_login( $p_username, $p_password, $p_perm_login=false ) {
		$t_user_id = user_get_id_by_name( $p_username );

		$t_login_method = config_get( 'login_method' );

		if ( false === $t_user_id ) {
			if ( BASIC_AUTH == $t_login_method || LDAP == $t_login_method ) {

			    # attempt to create the user if using BASIC_AUTH or LDAP
			    if ( BASIC_AUTH == $t_login_method) {
				    $t_cookie_string = user_create( $p_username, $p_password );
				} elseif ( LDAP == $t_login_method ) {
					# get the users' email address as well if using LDAP
					$t_cookie_string = user_create( $p_username, '', ldap_email_from_username( $p_username ) );
				}

				if ( false === $t_cookie_string ) {
					# it didn't work
					return false;
				}

				# ok, we created the user, get the row again
				$t_user_id = user_get_id_by_name( $p_username );

				if ( false === $t_user_id ) {
					# uh oh, something must be really wrong

					# @@@ trigger an error here?

					return false;
				}
			} else {
				return false;
			}
		}

		# check for disabled account
		if ( !user_is_enabled( $t_user_id ) ) {
			return false;
		}

		# max. failed login attempts achieved...
		if( !user_is_login_request_allowed( $t_user_id ) ) {
			return false;
		}

		$t_anon_account = config_get( 'anonymous_account' );
		$t_anon_allowed = config_get( 'allow_anonymous_login' );

		# check for anonymous login
		if ( !( ( ON == $t_anon_allowed ) && ( $t_anon_account == $p_username)  ) ) {
			# anonymous login didn't work, so check the password

			if ( !auth_does_password_match( $t_user_id, $p_password ) ) {
				user_increment_failed_login_count( $t_user_id );
				return false;
			}
		}

		# ok, we're good to login now

		# increment login count
		user_increment_login_count( $t_user_id );

		user_reset_failed_login_count_to_zero( $t_user_id );
		user_reset_lost_password_in_progress_count_to_zero( $t_user_id );

		# set the cookies
		auth_set_cookies( $t_user_id, $p_perm_login );

		return true;
	}

	# --------------------
	# Allows scripts to login using a login name or ( login name + password )
	function auth_attempt_script_login( $p_username, $p_password = null ) {
		global $g_script_login_cookie, $g_cache_current_user_id;

		$t_user_id = user_get_id_by_name( $p_username );

		$t_user = user_get_row( $t_user_id );

		# check for disabled account
		if ( OFF == $t_user['enabled'] ) {
			return false;
		}

		# validate password if supplied
		if ( null !== $p_password ) {
			if ( !auth_does_password_match( $t_user_id, $p_password ) ) {
				return false;
			}
		}

		# ok, we're good to login now

		# increment login count
		user_increment_login_count( $t_user_id );

		# set the cookies
		$g_script_login_cookie = $t_user['cookie_string'];

		# cache user id for future reference
		$g_cache_current_user_id = $t_user_id;

		return true;
	}

	# --------------------
	# Logout the current user and remove any remaining cookies from their browser
	# Returns true on success, false otherwise
	function auth_logout() {
        global $g_cache_current_user_id;

        # clear cached userid
        $g_cache_current_user_id = null;

        # clear cookies, if they were set
        if (auth_clear_cookies()) {
            helper_clear_pref_cookies();
        }
		return true;
	}

	#===================================
	# Password functions
	#===================================

	# --------------------
	# Return true if the password for the user id given matches the given
	#  password (taking into account the global login method)
	function auth_does_password_match( $p_user_id, $p_test_password ) {
		$t_configured_login_method = config_get( 'login_method' );

		if ( LDAP == $t_configured_login_method ) {
			return ldap_authenticate( $p_user_id, $p_test_password );
		}

		$t_password			= user_get_field( $p_user_id, 'password' );
		$t_login_methods	= Array(MD5, CRYPT, PLAIN);
		foreach ( $t_login_methods as $t_login_method ) {

			# pass the stored password in as the salt
			if ( auth_process_plain_password( $p_test_password, $t_password, $t_login_method ) == $t_password ) {
				# Check for migration to another login method and test whether the password was encrypted
				# with our previously insecure implemention of the CRYPT method
				if ( ( $t_login_method != $t_configured_login_method ) ||
					( ( CRYPT == $t_configured_login_method ) && substr( $t_password, 0, 2 ) == substr( $p_test_password, 0, 2 ) ) ) {
					user_set_password( $p_user_id, $p_test_password, true );
				}

				return true;
			}
		}

		return false;
	}

	# --------------------
	# Encrypt and return the plain password given, as appropriate for the current
	#  global login method.
	#
	# When generating a new password, no salt should be passed in.
	# When encrypting a password to compare to a stored password, the stored
	#  password should be passed in as salt.  If the auth method is CRYPT then
	#  crypt() will extract the appropriate portion of the stored password as its salt
	function auth_process_plain_password( $p_password, $p_salt=null, $p_method=null ) {
		$t_login_method = config_get( 'login_method' );
		if ( $p_method !== null ) {
			$t_login_method = $p_method;
		}

		switch ( $t_login_method ) {
			case CRYPT:
				# a null salt is the same as no salt, which causes a salt to be generated
				# otherwise, use the salt given
				$t_processed_password = crypt( $p_password, $p_salt );
				break;
			case MD5:
				$t_processed_password = md5( $p_password );
				break;
			case BASIC_AUTH:
			case PLAIN:
			default:
				$t_processed_password = $p_password;
				break;
		}

		# cut this off to 32 cahracters which the largest possible string in the database
		return substr( $t_processed_password, 0, 32 );
	}

	# --------------------
	# Generate a random 12 character password
	# p_email is unused
	function auth_generate_random_password( $p_email ) {
		$t_val = mt_rand( 0, mt_getrandmax() ) + mt_rand( 0, mt_getrandmax() );
		$t_val = md5( $t_val );

		return substr( $t_val, 0, 12 );
	}

	# --------------------
	# Generate a confirm_hash 12 character to valide the password reset request
	function auth_generate_confirm_hash( $p_user_id ) {
		$t_confirm_hash_generator = config_get( 'password_confirm_hash_magic_string' );
		$t_password = user_get_field( $p_user_id, 'password' );
		$t_last_visit = user_get_field( $p_user_id, 'last_visit' );

		$t_confirm_hash = md5( $t_confirm_hash_generator . $t_password . $t_last_visit );

		return $t_confirm_hash;
	}

	#===================================
	# Cookie functions
	#===================================

	# --------------------
	# Set login cookies for the user
	#  If $p_perm_login is true, a long-term cookie is created
	function auth_set_cookies( $p_user_id, $p_perm_login=false ) {
		$t_cookie_string = user_get_field( $p_user_id, 'cookie_string' );

		$t_cookie_name = config_get( 'string_cookie' );

		if ( $p_perm_login ) {
			# set permanent cookie (1 year)
			gpc_set_cookie( $t_cookie_name, $t_cookie_string, true );
		} else {
			# set temp cookie, cookie dies after browser closes
			gpc_set_cookie( $t_cookie_name, $t_cookie_string, false );
		}
	}

	# --------------------
	# Clear login cookies, return true if they were cleared
	function auth_clear_cookies() {
		global $g_script_login_cookie;

        $t_cookies_cleared = false;

        # clear cookie, if not logged in from script
        if ($g_script_login_cookie == null) {
		    $t_cookie_name =  config_get( 'string_cookie' );
		    $t_cookie_path = config_get( 'cookie_path' );

		    gpc_clear_cookie( $t_cookie_name, $t_cookie_path );
            $t_cookies_cleared = true;
        } else {
            $g_script_login_cookie = null;
        }
        return $t_cookies_cleared;
	}

	# --------------------
	# Generate a string to use as the identifier for the login cookie
	# It is not guaranteed to be unique and should be checked
	# The string returned should be 64 characters in length
	function auth_generate_cookie_string() {
		$t_val = mt_rand( 0, mt_getrandmax() ) + mt_rand( 0, mt_getrandmax() );
		$t_val = md5( $t_val ) . md5( time() );

		return substr( $t_val, 0, 64 );
	}

	# --------------------
	# Generate a UNIQUE string to use as the identifier for the login cookie
	# The string returned should be 64 characters in length
	function auth_generate_unique_cookie_string() {
		do {
			$t_cookie_string = auth_generate_cookie_string();
		} while ( !auth_is_cookie_string_unique( $t_cookie_string ) );

		return $t_cookie_string;
	}

	# --------------------
	# Return true if the cookie login identifier is unique, false otherwise
	function auth_is_cookie_string_unique( $p_cookie_string ) {
		$t_user_table = config_get( 'mantis_user_table' );

		$c_cookie_string = db_prepare_string( $p_cookie_string );

		$query = "SELECT COUNT(*)
				  FROM $t_user_table
				  WHERE cookie_string='$c_cookie_string'";
		$result = db_query( $query );
		$t_count = db_result( $result );

		if ( $t_count > 0 ) {
			return false;
		} else {
			return true;
		}
	}

	# --------------------
	# Return the current user login cookie string,
	# note that the cookie cached by a script login superceeds the cookie provided by
	#  the browser. This shouldn't normally matter, except that the password verification uses
	#  this routine to bypass the normal authentication, and can get confused when a normal user
	#  logs in, then runs the verify script. the act of fetching config variables may get the wrong
	#  userid.
	# if no user is logged in and anonymous login is enabled, returns cookie for anonymous user
	# otherwise returns '' (an empty string)
	function auth_get_current_user_cookie() {
		global $g_script_login_cookie, $g_cache_anonymous_user_cookie_string;

		# if logging in via a script, return that cookie
		if ( $g_script_login_cookie !== null ) {
			return $g_script_login_cookie;
		}

		# fetch user cookie
		$t_cookie_name = config_get( 'string_cookie' );
		$t_cookie = gpc_get_cookie( $t_cookie_name, '' );

		# if cookie not found, and anonymous login enabled, use cookie of anonymous account.
		if ( is_blank( $t_cookie ) ) {
			if ( ON == config_get( 'allow_anonymous_login' ) ) {
				if ( $g_cache_anonymous_user_cookie_string === null ) {
                    if ( function_exists( 'db_is_connected' ) && db_is_connected() ) {
                        # get anonymous information if database is available
                        $query = sprintf('SELECT id, cookie_string FROM %s WHERE username = \'%s\'',
								config_get( 'mantis_user_table' ), config_get( 'anonymous_account' ) );
                        $result = db_query( $query );

                        if ( 1 == db_num_rows( $result ) ) {
                            $row = db_fetch_array( $result );
                            $t_cookie = $row['cookie_string'];

                            $g_cache_anonymous_user_cookie_string = $t_cookie;
                            $g_cache_current_user_id = $row['id'];
                        }
                    }
                } else {
					$t_cookie = $g_cache_anonymous_user_cookie_string;
				}
			}
		}

		return $t_cookie;
	}


	#===================================
	# Data Access
	#===================================

	#########################################
	# is cookie valid?

	function auth_is_cookie_valid( $p_cookie_string ) {
		global $g_cache_current_user_id;

	    # fail if DB isn't accessible
	    if ( !db_is_connected() ) {
			return false;
		}

	    # fail if cookie is blank
	    if ( '' === $p_cookie_string ) {
			return false;
		}

        # succeeed if user has already been authenticated
		if ( null !== $g_cache_current_user_id ) {
			return true;
		}

		# look up cookie in the database to see if it is valid
		$t_user_table = config_get( 'mantis_user_table' );

		$c_cookie_string = db_prepare_string( $p_cookie_string );

		$query = "SELECT id
				  FROM $t_user_table
				  WHERE cookie_string='$c_cookie_string'";
		$result = db_query( $query );

		# return true if a matching cookie was found
		return ( 1 == db_num_rows( $result ) );
	}

	#########################################
	# SECURITY NOTE: cache globals are initialized here to prevent them
	#   being spoofed if register_globals is turned on
	#
	$g_cache_current_user_id = null;

	function auth_get_current_user_id() {
		global $g_cache_current_user_id;

		if ( null !== $g_cache_current_user_id ) {
			return $g_cache_current_user_id;
		}

		$t_user_table = config_get( 'mantis_user_table' );

		$t_cookie_string = auth_get_current_user_cookie();

		# @@@ error with an error saying they aren't logged in?
		#     Or redirect to the login page maybe?

		$c_cookie_string = db_prepare_string( $t_cookie_string );

		$query = "SELECT id
				  FROM $t_user_table
				  WHERE cookie_string='$c_cookie_string'";
		$result = db_query( $query );

		# The cookie was invalid. Clear the cookie (to allow people to log in again)
		# and give them an Access Denied message.
		if ( db_num_rows( $result ) < 1 ) {
			auth_clear_cookies();
		    access_denied(); # never returns
			return false;
		}

		$t_user_id = (int)db_result( $result );
		$g_cache_current_user_id = $t_user_id;

		return $t_user_id;
	}


	#===================================
	# HTTP Auth
	#===================================

	function auth_http_prompt() {
		header( "HTTP/1.0 401 Authorization Required" );
		header( "WWW-Authenticate: Basic realm=\"" . lang_get( 'http_auth_realm' ) . "\"" );
		header( 'status: 401 Unauthorized' );

		echo '<center>';
		echo '<p>'.error_string(ERROR_ACCESS_DENIED).'</p>';
		print_bracket_link( 'main_page.php', lang_get( 'proceed' ) );
		echo '</center>';

		exit;
	}

	function auth_http_set_logout_pending( $p_pending ) {
		$t_cookie_name = config_get( 'logout_cookie' );

		if ( $p_pending ) {
			gpc_set_cookie( $t_cookie_name, "1", false );
		} else {
			$t_cookie_path = config_get( 'cookie_path' );
			gpc_clear_cookie( $t_cookie_name, $t_cookie_path );
		}
	}

	function auth_http_is_logout_pending() {
		$t_cookie_name = config_get( 'logout_cookie' );
		$t_cookie = gpc_get_cookie( $t_cookie_name, '' );

		return( $t_cookie > '' );
	}
?>
authentication_api.153.v2.php (17,101 bytes)   
authentication_api.php.153.v2.patch (3,954 bytes)   
Index: authentication_api.php
===================================================================
RCS file: /cvsroot/mantisbt/mantisbt/core/authentication_api.php,v
retrieving revision 1.53
diff -u -r1.53 authentication_api.php
--- authentication_api.php	10 Aug 2005 16:21:28 -0000	1.53
+++ authentication_api.php	17 Jan 2007 00:16:21 -0000
@@ -72,9 +72,15 @@
 		$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
-				$t_cookie_string = user_create( $p_username, $p_password );
+			if ( BASIC_AUTH == $t_login_method || LDAP == $t_login_method ) {
+
+			    # attempt to create the user if using BASIC_AUTH or LDAP
+			    if ( BASIC_AUTH == $t_login_method) {
+				    $t_cookie_string = user_create( $p_username, $p_password );
+				} elseif ( LDAP == $t_login_method ) {
+					# get the users' email address as well if using LDAP
+					$t_cookie_string = user_create( $p_username, '', ldap_email_from_username( $p_username ) );
+				}
 
 				if ( false === $t_cookie_string ) {
 					# it didn't work
@@ -161,7 +167,7 @@
 
 		# set the cookies
 		$g_script_login_cookie = $t_user['cookie_string'];
-		
+
 		# cache user id for future reference
 		$g_cache_current_user_id = $t_user_id;
 
@@ -173,11 +179,11 @@
 	# Returns true on success, false otherwise
 	function auth_logout() {
         global $g_cache_current_user_id;
-        
+
         # clear cached userid
         $g_cache_current_user_id = null;
-        
-        # clear cookies, if they were set  
+
+        # clear cookies, if they were set
         if (auth_clear_cookies()) {
             helper_clear_pref_cookies();
         }
@@ -301,7 +307,7 @@
 		global $g_script_login_cookie;
 
         $t_cookies_cleared = false;
-        
+
         # clear cookie, if not logged in from script
         if ($g_script_login_cookie == null) {
 		    $t_cookie_name =  config_get( 'string_cookie' );
@@ -373,8 +379,8 @@
 		if ( $g_script_login_cookie !== null ) {
 			return $g_script_login_cookie;
 		}
-			
-		# fetch user cookie 
+
+		# fetch user cookie
 		$t_cookie_name = config_get( 'string_cookie' );
 		$t_cookie = gpc_get_cookie( $t_cookie_name, '' );
 
@@ -382,12 +388,12 @@
 		if ( is_blank( $t_cookie ) ) {
 			if ( ON == config_get( 'allow_anonymous_login' ) ) {
 				if ( $g_cache_anonymous_user_cookie_string === null ) {
-                    if ( function_exists( 'db_is_connected' ) && db_is_connected() ) { 
+                    if ( function_exists( 'db_is_connected' ) && db_is_connected() ) {
                         # get anonymous information if database is available
                         $query = sprintf('SELECT id, cookie_string FROM %s WHERE username = \'%s\'',
 								config_get( 'mantis_user_table' ), config_get( 'anonymous_account' ) );
                         $result = db_query( $query );
-                        
+
                         if ( 1 == db_num_rows( $result ) ) {
                             $row = db_fetch_array( $result );
                             $t_cookie = $row['cookie_string'];
@@ -415,7 +421,7 @@
 
 	function auth_is_cookie_valid( $p_cookie_string ) {
 		global $g_cache_current_user_id;
-	
+
 	    # fail if DB isn't accessible
 	    if ( !db_is_connected() ) {
 			return false;
@@ -430,7 +436,7 @@
 		if ( null !== $g_cache_current_user_id ) {
 			return true;
 		}
-		
+
 		# look up cookie in the database to see if it is valid
 		$t_user_table = config_get( 'mantis_user_table' );
 
@@ -444,7 +450,7 @@
 		# return true if a matching cookie was found
 		return ( 1 == db_num_rows( $result ) );
 	}
-	
+
 	#########################################
 	# SECURITY NOTE: cache globals are initialized here to prevent them
 	#   being spoofed if register_globals is turned on
authentication_api.php.rev5021.patch (1,021 bytes)   
Index: authentication_api.php
===================================================================
--- authentication_api.php	(revision 5021)
+++ authentication_api.php	(working copy)
@@ -82,10 +82,16 @@
 		$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
-				$t_cookie_string = user_create( $p_username, $p_password );
+			if ( BASIC_AUTH == $t_login_method || LDAP == $t_login_method ) {
 
+			    # attempt to create the user if using BASIC_AUTH or LDAP
+			    if ( BASIC_AUTH == $t_login_method) {
+				    $t_cookie_string = user_create( $p_username, $p_password );
+				} elseif ( LDAP == $t_login_method ) {
+					# get the users' email address as well if using LDAP
+					$t_cookie_string = user_create( $p_username, '', ldap_email_from_username( $p_username ) );
+				}
+
 				if ( false === $t_cookie_string ) {
 					# it didn't work
 					return false;
authentication_api.rev5021+.php (20,783 bytes)   
<?php
# Mantis - a php based bugtracking system

# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
# Copyright (C) 2002 - 2007  Mantis Team   - mantisbt-dev@lists.sourceforge.net

# Mantis is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Mantis is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mantis.  If not, see <http://www.gnu.org/licenses/>.

	# --------------------------------------------------------
	# $Id: authentication_api.php,v 1.60.2.3 2007-10-19 06:54:58 vboctor Exp $
	# --------------------------------------------------------

	require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'gpc_api.php' );

	### Authentication API ###

	$g_script_login_cookie = null;
	$g_cache_anonymous_user_cookie_string = null;

	#===================================
	# Boolean queries and ensures
	#===================================

	# --------------------
	# 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
	#  If parameter is given it is used as a URL to redirect to following
	#   successful login.  If none is given, the URL of the current page is used
	function auth_ensure_user_authenticated( $p_return_page = '' ) {
		# if logged in
		if ( auth_is_user_authenticated() ) {
			# check for access enabled
			#  This also makes sure the cookie is valid
			if ( OFF == current_user_get_field( 'enabled' ) ) {
				print_header_redirect( 'logout_page.php' );
			}
		} else { # not logged in
			if ( is_blank( $p_return_page ) ) {
				if (!isset($_SERVER['REQUEST_URI'])) {
					$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
				}
				$p_return_page = $_SERVER['REQUEST_URI'];
			}
			$p_return_page = string_url( $p_return_page );
			print_header_redirect( 'login_page.php?return=' . $p_return_page );
		}
	}

	# --------------------
	# Return true if there is a currently logged in and authenticated user,
	#  false otherwise
	function auth_is_user_authenticated() {
		return ( auth_is_cookie_valid( auth_get_current_user_cookie() ) );
	}


	#===================================
	# Login / Logout
	#===================================

	# --------------------
	# Attempt to login the user with the given password
	#  If the user fails validation, false is returned
	#  If the user passes validation, the cookies are set and
	#   true is returned.  If $p_perm_login is true, the long-term
	#   cookie is created.
	function auth_attempt_login( $p_username, $p_password, $p_perm_login=false ) {
		$t_user_id = user_get_id_by_name( $p_username );

		$t_login_method = config_get( 'login_method' );

		if ( false === $t_user_id ) {
			if ( BASIC_AUTH == $t_login_method || LDAP == $t_login_method ) {

			    # attempt to create the user if using BASIC_AUTH or LDAP
			    if ( BASIC_AUTH == $t_login_method) {
				    $t_cookie_string = user_create( $p_username, $p_password );
				} elseif ( LDAP == $t_login_method ) {
					# get the users' email address as well if using LDAP
					$t_cookie_string = user_create( $p_username, '', ldap_email_from_username( $p_username ) );
				}

				if ( false === $t_cookie_string ) {
					# it didn't work
					return false;
				}

				# ok, we created the user, get the row again
				$t_user_id = user_get_id_by_name( $p_username );

				if ( false === $t_user_id ) {
					# uh oh, something must be really wrong

					# @@@ trigger an error here?

					return false;
				}
			} else {
				return false;
			}
		}

		# check for disabled account
		if ( !user_is_enabled( $t_user_id ) ) {
			return false;
		}

		# max. failed login attempts achieved...
		if( !user_is_login_request_allowed( $t_user_id ) ) {
			return false;
		}

		$t_anon_account = config_get( 'anonymous_account' );
		$t_anon_allowed = config_get( 'allow_anonymous_login' );

		# check for anonymous login
		if ( !( ( ON == $t_anon_allowed ) && ( $t_anon_account == $p_username)  ) ) {
			# anonymous login didn't work, so check the password

			if ( !auth_does_password_match( $t_user_id, $p_password ) ) {
				user_increment_failed_login_count( $t_user_id );
				return false;
			}
		}

		# ok, we're good to login now

		# increment login count
		user_increment_login_count( $t_user_id );

		user_reset_failed_login_count_to_zero( $t_user_id );
		user_reset_lost_password_in_progress_count_to_zero( $t_user_id );

		# set the cookies
		auth_set_cookies( $t_user_id, $p_perm_login );
		auth_set_tokens( $t_user_id );

		return true;
	}

	# --------------------
	# Allows scripts to login using a login name or ( login name + password )
	function auth_attempt_script_login( $p_username, $p_password = null ) {
		global $g_script_login_cookie, $g_cache_current_user_id;

		$t_user_id = user_get_id_by_name( $p_username );

		$t_user = user_get_row( $t_user_id );

		# check for disabled account
		if ( OFF == $t_user['enabled'] ) {
			return false;
		}

		# validate password if supplied
		if ( null !== $p_password ) {
			if ( !auth_does_password_match( $t_user_id, $p_password ) ) {
				return false;
			}
		}

		# ok, we're good to login now

		# With cases like RSS feeds and MantisConnect there is a login per operation, hence, there is no
		# real significance of incrementing login count.
		# increment login count
		# user_increment_login_count( $t_user_id );

		# set the cookies
		$g_script_login_cookie = $t_user['cookie_string'];

		# cache user id for future reference
		$g_cache_current_user_id = $t_user_id;

		return true;
	}

	# --------------------
	# Logout the current user and remove any remaining cookies from their browser
	# Returns true on success, false otherwise
	function auth_logout() {
        global $g_cache_current_user_id;
        
        # clear cached userid
        $g_cache_current_user_id = null;
        
        # clear cookies, if they were set  
        if (auth_clear_cookies()) {
            helper_clear_pref_cookies();
        }
		return true;
	}

	#===================================
	# Password functions
	#===================================

	# --------------------
	# Return true if the password for the user id given matches the given
	#  password (taking into account the global login method)
	function auth_does_password_match( $p_user_id, $p_test_password ) {
		$t_configured_login_method = config_get( 'login_method' );

		if ( LDAP == $t_configured_login_method ) {
			return ldap_authenticate( $p_user_id, $p_test_password );
		}

		$t_password			= user_get_field( $p_user_id, 'password' );
		$t_login_methods	= Array(MD5, CRYPT, PLAIN);
		foreach ( $t_login_methods as $t_login_method ) {

			# pass the stored password in as the salt
			if ( auth_process_plain_password( $p_test_password, $t_password, $t_login_method ) == $t_password ) {
				# Do not support migration to PLAIN, since this would be a crazy thing to do.
				# Also if we do, then a user will be able to login by providing the MD5 value
				# that is copied from the database.  See #8467 for more details.
				if ( $t_configured_login_method != PLAIN && $t_login_method == PLAIN ) {
					continue;
				}

				# Check for migration to another login method and test whether the password was encrypted
				# with our previously insecure implemention of the CRYPT method
				if ( ( $t_login_method != $t_configured_login_method ) ||
					( ( CRYPT == $t_configured_login_method ) && substr( $t_password, 0, 2 ) == substr( $p_test_password, 0, 2 ) ) ) {
					user_set_password( $p_user_id, $p_test_password, true );
				}

				return true;
			}
		}

		return false;
	}

	# --------------------
	# Encrypt and return the plain password given, as appropriate for the current
	#  global login method.
	#
	# When generating a new password, no salt should be passed in.
	# When encrypting a password to compare to a stored password, the stored
	#  password should be passed in as salt.  If the auth method is CRYPT then
	#  crypt() will extract the appropriate portion of the stored password as its salt
	function auth_process_plain_password( $p_password, $p_salt=null, $p_method=null ) {
		$t_login_method = config_get( 'login_method' );
		if ( $p_method !== null ) {
			$t_login_method = $p_method;
		}

		switch ( $t_login_method ) {
			case CRYPT:
				# a null salt is the same as no salt, which causes a salt to be generated
				# otherwise, use the salt given
				$t_processed_password = crypt( $p_password, $p_salt );
				break;
			case MD5:
				$t_processed_password = md5( $p_password );
				break;
			case BASIC_AUTH:
			case PLAIN:
			default:
				$t_processed_password = $p_password;
				break;
		}

		# cut this off to 32 cahracters which the largest possible string in the database
		return substr( $t_processed_password, 0, 32 );
	}

	# --------------------
	# Generate a random 12 character password
	# p_email is unused
	function auth_generate_random_password( $p_email ) {
		$t_val = mt_rand( 0, mt_getrandmax() ) + mt_rand( 0, mt_getrandmax() );
		$t_val = md5( $t_val );

		return substr( $t_val, 0, 12 );
	}

	# --------------------
	# Generate a confirm_hash 12 character to valide the password reset request
	function auth_generate_confirm_hash( $p_user_id ) {
		$t_confirm_hash_generator = config_get( 'password_confirm_hash_magic_string' );
		$t_password = user_get_field( $p_user_id, 'password' );
		$t_last_visit = user_get_field( $p_user_id, 'last_visit' );

		$t_confirm_hash = md5( $t_confirm_hash_generator . $t_password . $t_last_visit );

		return $t_confirm_hash;
	}

	#===================================
	# Cookie functions
	#===================================

	# --------------------
	# Set login cookies for the user
	#  If $p_perm_login is true, a long-term cookie is created
	function auth_set_cookies( $p_user_id, $p_perm_login=false ) {
		$t_cookie_string = user_get_field( $p_user_id, 'cookie_string' );

		$t_cookie_name = config_get( 'string_cookie' );

		if ( $p_perm_login ) {
			# set permanent cookie (1 year)
			gpc_set_cookie( $t_cookie_name, $t_cookie_string, true );
		} else {
			# set temp cookie, cookie dies after browser closes
			gpc_set_cookie( $t_cookie_name, $t_cookie_string, false );
		}
	}

	# --------------------
	# Clear login cookies, return true if they were cleared
	function auth_clear_cookies() {
		global $g_script_login_cookie;

        $t_cookies_cleared = false;
        
        # clear cookie, if not logged in from script
        if ($g_script_login_cookie == null) {
		    $t_cookie_name =  config_get( 'string_cookie' );
		    $t_cookie_path = config_get( 'cookie_path' );

		    gpc_clear_cookie( $t_cookie_name, $t_cookie_path );
            $t_cookies_cleared = true;
        } else {
            $g_script_login_cookie = null;
        }
        return $t_cookies_cleared;
	}

	# --------------------
	# Generate a string to use as the identifier for the login cookie
	# It is not guaranteed to be unique and should be checked
	# The string returned should be 64 characters in length
	function auth_generate_cookie_string() {
		$t_val = mt_rand( 0, mt_getrandmax() ) + mt_rand( 0, mt_getrandmax() );
		$t_val = md5( $t_val ) . md5( time() );

		return substr( $t_val, 0, 64 );
	}

	# --------------------
	# Generate a UNIQUE string to use as the identifier for the login cookie
	# The string returned should be 64 characters in length
	function auth_generate_unique_cookie_string() {
		do {
			$t_cookie_string = auth_generate_cookie_string();
		} while ( !auth_is_cookie_string_unique( $t_cookie_string ) );

		return $t_cookie_string;
	}

	# --------------------
	# Return true if the cookie login identifier is unique, false otherwise
	function auth_is_cookie_string_unique( $p_cookie_string ) {
		$t_user_table = config_get( 'mantis_user_table' );

		$c_cookie_string = db_prepare_string( $p_cookie_string );

		$query = "SELECT COUNT(*)
				  FROM $t_user_table
				  WHERE cookie_string='$c_cookie_string'";
		$result = db_query( $query );
		$t_count = db_result( $result );

		if ( $t_count > 0 ) {
			return false;
		} else {
			return true;
		}
	}

	# --------------------
	# Return the current user login cookie string,
	# note that the cookie cached by a script login superceeds the cookie provided by
	#  the browser. This shouldn't normally matter, except that the password verification uses
	#  this routine to bypass the normal authentication, and can get confused when a normal user
	#  logs in, then runs the verify script. the act of fetching config variables may get the wrong
	#  userid.
	# if no user is logged in and anonymous login is enabled, returns cookie for anonymous user
	# otherwise returns '' (an empty string)
	function auth_get_current_user_cookie() {
		global $g_script_login_cookie, $g_cache_anonymous_user_cookie_string;
 
		# if logging in via a script, return that cookie
		if ( $g_script_login_cookie !== null ) {
			return $g_script_login_cookie;
		}
			
		# fetch user cookie 
		$t_cookie_name = config_get( 'string_cookie' );
		$t_cookie = gpc_get_cookie( $t_cookie_name, '' );

		# if cookie not found, and anonymous login enabled, use cookie of anonymous account.
		if ( is_blank( $t_cookie ) ) {
			if ( ON == config_get( 'allow_anonymous_login' ) ) {
				if ( $g_cache_anonymous_user_cookie_string === null ) {
                    if ( function_exists( 'db_is_connected' ) && db_is_connected() ) { 
                        # get anonymous information if database is available
                        $query = sprintf('SELECT id, cookie_string FROM %s WHERE username = \'%s\'',
								config_get( 'mantis_user_table' ), config_get( 'anonymous_account' ) );
                        $result = db_query( $query );
                        
                        if ( 1 == db_num_rows( $result ) ) {
                            $row = db_fetch_array( $result );
                            $t_cookie = $row['cookie_string'];

                            $g_cache_anonymous_user_cookie_string = $t_cookie;
                            $g_cache_current_user_id = $row['id'];
                        }
                    }
                } else {
					$t_cookie = $g_cache_anonymous_user_cookie_string;
				}
			}
		}

		return $t_cookie;
	}

	#===================================
	# Re-Authentication Tokens
	#===================================

	/**
	 * Set authentication tokens for secure session.
	 * @param integer User ID
	 */
	function auth_set_tokens( $p_user_id ) {
		$t_auth_token = token_get( TOKEN_AUTHENTICATED, $p_user_id );
		if ( null == $t_auth_token ) {
			token_set( TOKEN_AUTHENTICATED, true, TOKEN_EXPIRY_AUTHENTICATED, $p_user_id );
		} else {
			token_touch( $t_auth_token['id'], TOKEN_EXPIRY_AUTHENTICATED );
		}
	}

	/**
	 * Check for authentication tokens, and display re-authentication page if needed.
	 * Currently, if using BASIC or HTTP authentication methods, or if logged in anonymously, 
	 * this function will always "authenticate" the user (do nothing).
	 */
	function auth_reauthenticate() {
		if ( BASIC_AUTH == config_get( 'login_method' ) ||
				HTTP_AUTH == config_get( 'login_method' ) ) {
			return true;
		}

		$t_auth_token = token_get( TOKEN_AUTHENTICATED );
		if ( null != $t_auth_token ) {
			token_touch( $t_auth_token['id'], TOKEN_EXPIRY_AUTHENTICATED );
			return true;
		} else {
			$t_anon_account = config_get( 'anonymous_account' );
			$t_anon_allowed = config_get( 'allow_anonymous_login' );

			$t_user_id = auth_get_current_user_id();
			$t_username = user_get_field( $t_user_id, 'username' );

			# check for anonymous login
			if ( ON == $t_anon_allowed && $t_anon_account == $t_username ) {
				return true;
			}
	
			return auth_reauthenticate_page( $t_user_id, $t_username );
		}
	}

	/**
	 * Generate the intermediate authentication page.
	 * @param integer User ID
	 * @param string Username
	 */
	function auth_reauthenticate_page( $p_user_id, $p_username ) {
		$t_error = false;

		if ( true == gpc_get_bool( '_authenticate' ) ) {
			$f_password     = gpc_get_string( 'password', '' );
					    
			if ( auth_attempt_login( $p_username, $f_password ) ) {
				auth_set_tokens( $p_user_id );
				return true;
			} else {
				$t_error = true;
			}
		}

		html_page_top1();
		html_page_top2();

?>
<div align="center">
<p>
<?php 
		echo lang_get( 'reauthenticate_message' ); 
		if ( $t_error != false ) {
			echo '<br/><font color="red">',lang_get( 'login_error' ),'</font>';
		}
?>
</p>
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">

<?php
		print_hidden_inputs( gpc_strip_slashes( $_POST ) );
		print_hidden_inputs( gpc_strip_slashes( $_GET ) );
?>

<input type="hidden" name="_authenticate" value="1" />

<table class="width50 center">
<tr>
	<td class="form-title"><?php echo lang_get( 'reauthenticate_title' ); ?></td>
</tr>

<tr class="row-1">
	<td class="category"><?php echo lang_get( 'username' ); ?></td>
	<td><input type="text" disabled="disabled" size="32" maxlength="32" value="<?php echo $p_username; ?>" /></td>
</tr>

<tr class="row-2">
	<td class="category"><?php echo lang_get( 'password' ); ?></td>
	<td><input type="password" name="password" size="16" maxlength="32" /></td>
</tr>

<tr>
	<td class="center" colspan="2"><input type="submit" class="button" value="<?php echo lang_get( 'login_button' ); ?>" /></td>
</tr>
</table>

</form>
</div>

		<?php
		html_page_bottom1();

		exit;
	}

	#===================================
	# Data Access
	#===================================

	#########################################
	# is cookie valid?

	function auth_is_cookie_valid( $p_cookie_string ) {
		global $g_cache_current_user_id;
		
		# fail if DB isn't accessible
		if ( !db_is_connected() ) {
			return false;
		}

		# fail if cookie is blank
		if ( '' === $p_cookie_string ) {
			return false;
		}

		# succeeed if user has already been authenticated
		if ( null !== $g_cache_current_user_id ) {
			return true;
		}
		
		# look up cookie in the database to see if it is valid
		$t_user_table = config_get( 'mantis_user_table' );

		$c_cookie_string = db_prepare_string( $p_cookie_string );

		$query = "SELECT id
				  FROM $t_user_table
				  WHERE cookie_string='$c_cookie_string'";
		$result = db_query( $query );

		# return true if a matching cookie was found
 		return ( 1 == db_num_rows( $result ) );
	}

	#########################################
	# SECURITY NOTE: cache globals are initialized here to prevent them
	#   being spoofed if register_globals is turned on
	#
	$g_cache_current_user_id = null;

	function auth_get_current_user_id() {
		global $g_cache_current_user_id;

		if ( null !== $g_cache_current_user_id ) {
			return $g_cache_current_user_id;
		}

		$t_user_table = config_get( 'mantis_user_table' );

		$t_cookie_string = auth_get_current_user_cookie();

		# @@@ error with an error saying they aren't logged in?
		#     Or redirect to the login page maybe?

		$c_cookie_string = db_prepare_string( $t_cookie_string );

		$query = "SELECT id
				  FROM $t_user_table
				  WHERE cookie_string='$c_cookie_string'";
		$result = db_query( $query );

		# The cookie was invalid. Clear the cookie (to allow people to log in again)
		# and give them an Access Denied message.
		if ( db_num_rows( $result ) < 1 ) {
			auth_clear_cookies();
		    access_denied(); # never returns
			return false;
		}

		$t_user_id = (int)db_result( $result );
		$g_cache_current_user_id = $t_user_id;

		return $t_user_id;
	}

	#===================================
	# HTTP Auth
	#===================================

	function auth_http_prompt() {
		header( "HTTP/1.0 401 Authorization Required" );
		header( "WWW-Authenticate: Basic realm=\"" . lang_get( 'http_auth_realm' ) . "\"" );
		header( 'status: 401 Unauthorized' );

		echo '<center>';
		echo '<p>'.error_string(ERROR_ACCESS_DENIED).'</p>';
		print_bracket_link( 'main_page.php', lang_get( 'proceed' ) );
		echo '</center>';

		exit;
	}

	function auth_http_set_logout_pending( $p_pending ) {
		$t_cookie_name = config_get( 'logout_cookie' );

		if ( $p_pending ) {
			gpc_set_cookie( $t_cookie_name, "1", false );
		} else {
			$t_cookie_path = config_get( 'cookie_path' );
			gpc_clear_cookie( $t_cookie_name, $t_cookie_path );
		}
	}

	function auth_http_is_logout_pending() {
		$t_cookie_name = config_get( 'logout_cookie' );
		$t_cookie = gpc_get_cookie( $t_cookie_name, '' );

		return( $t_cookie > '' );
	}
?>
authentication_api.rev5021+.php (20,783 bytes)   

Relationships

related to 0004906 closeddregad new user email incorrect when using LDAP backend 

Activities

RJelinek

RJelinek

2005-05-23 07:47

reporter   ~0010193

I also have this situation. I solved it by a little cron-script (I will add to this bug) running every evening.

ape

ape

2005-07-03 03:16

reporter   ~0010659

Last edited: 2005-07-05 08:22

Thanks for the script, RJelinek.

I've been doing a bit of work on a more integrated solution. It saves a) running the script every evening and b) creating thousands of accounts for users who might never use the system.

The patch for authentication_api.php (attached) simply tries to create a new user account, if ones doesn't already exist, when logging in using LDAP. It pulls the new user's email address from LDAP too and adds it to their record.

ape

ape

2005-07-03 03:19

reporter   ~0010660

I think this behaviour should probabably be controlled by a preference. Another preference could be added to set the default access level for users created this way. If people agree, I'll add these features too.

ape

ape

2005-10-25 11:32

reporter   ~0011531

Anyone got any further thoughts or comments on this patch? I'd welcome the feedback. If there's more work to be done just let me know and I'll take a look at it again.

If not, vwegert, could we get this folded into the tree? I can patch against a more recent authentication_api.php if that helps.

Mikael Nyborg

Mikael Nyborg

2005-10-27 05:02

reporter   ~0011551

I dont't have any comments about the patch but we have solved the problem by running a sync-script from our LDAP-server every night so we have exact the same info in Mantis as we have in our LDAP-server.

ericb

ericb

2006-03-19 23:24

reporter   ~0012370

Can anyone confirm that this patch works on version 1.0.1? It looks to me like a valid email address is required by the mantis code to create a user and this patch looks for an email address based on a mantis user ID, kind of a chicken and egg problem?

To get this to work I had to comment out line 346 of user_api.php
#email_ensure_valid( $p_email );

ape

ape

2006-05-14 12:42

reporter   ~0012829

Ok, just upgraded our installation to Mantis 1.0.3. This patch works fine for me against that.

Didn't have to change any other files. ericb, do you have 'validate_email' or something like that turned on in your config file?

ericb

ericb

2006-05-14 21:21

reporter   ~0012830

Yes, validate email is on. I believe it is the default.

config_defaults_inc.php: $g_validate_email = ON;

Eric

ape

ape

2006-05-15 04:03

reporter   ~0012832

Eric, I'm on a Windows server so have it switched off.

This may be the problem you're seeing as it looks to me that user_create() calls email_ensure_valid() which automatically returns TRUE if validate_email is OFF. If it's ON, email_ensure_valid() fails as the LDAP user is initially created with a blank email.

If this is indeed the problem, maybe it's better trying to create a LDAP user with their LDAP email address in one call to user_create(), rather than using the 'create then add email' approach in the current patch?

I'll have another look at this when I get a moment.

sithgunner

sithgunner

2007-01-13 02:52

reporter   ~0013916

I've tried the patch posted here on recent version of Mantis (1.1.0a1) and it didn't work saying 'Invalid email address'.

Now I checked a bit of source and altering a bit and it worked fine.
The fix was that you have to set the email address on the user creation code and not after that.

Sorry for not putting the actual patch, but this is what I altered from the patch posted here.

1) Add ", ldap_email_from_username( $p_username )" on the "user_create" function.
2) Delete the "user_set_email" block that patch is trying to add. (From "} elseif ( LDAP...)" to "user_set_email(...)")

So, frankly put, only a few lines of modification from the original source make this to work, though I never extensively checked the whole source to make sure this integeration is harmless. But hopefully this feature goes in the official tree by the official devs.

sithgunner

sithgunner

2007-01-13 03:09

reporter   ~0013917

Last edited: 2007-01-13 03:12

I found another issue, which doesn't look too good.

When I went to look for SQL data with the user information on mantis_user_table, the passwords were stored as plain text opposed to md5 when attempting to auto create user via this patch. Though, somehow even passwords were stored as plain text, I could still log in to the system with the right password on LDAP accounts.

I just edited again to fix the problem. Just near the same "user_create" context, use this instead. Altering "$p_password" itself caused problem, so I made a new variable.

$t_pass = LDAP == $t_login_method ? md5($p_password) : $p_password;
$t_cookie_string = user_create( $p_username, $t_pass, ldap_email_from_username( $p_username ));

[Edit]
Yes, auth works as it's trying to look in LDAP instead of the SQL table, so, there is probably no point in storing a password on the mantis SQL table. Maybe better to keep it just empty instead?

ape

ape

2007-01-16 19:51

reporter   ~0013929

Firstly, thanks to sithgunner for the work on a better fix for this and for noticing the gaping security flaw! I can confirm that issue here.

Regarding the error you got, I think you and ericb both were seeing the results of the same problem with the original patch. So...

I've attached a second attempt at a fix both as a patch and a modified version of the original file (rev 1.53 from Mantis 1.0.6) You should be able to drop in the file with no damage to later versions too.

I started by implemented your fix, sithgunner, but made separate cases for BASIC_AUTH and LDAP authentication. I also fixed the security hole by simply passing a null password to user_create() for new LDAP users. As you suggested, there's no need to store a password for LDAP authenticated users.

ericb, maybe you'd care to try this new patch/file and see if it works for you now (without you needing to change your user_api.php)?

ape

ape

2007-01-16 20:54

reporter   ~0013932

<can content="worms">

Actually, on reflection, this stored password issue raises some other points:

Consider the situation where someone changed login_method to PLAIN, for example, on an installation previously using LDAP. If no passwords were stored, wouldn't the system would be wide open to anyone with a user_id (simply logging in with no password)?

Some alternative ideas (not all of them good):

  1. Store hashed LDAP passwords. If someone changed the login_method, at least the system would still be secure and users could still log in using their old LDAP credentials. (Problems: in this scenario, the stored LDAP passwords would need to be updated on every login in case a user changed their LDAP password. But what if a user changed their LDAP password, and didn't log into Mantis again before login_method was changed?)

  2. Warn if Mantis notices that login_method is changed to something else having previously been LDAP. (bit complicated, previous value of login_method needs to be 'remembered')

  3. When creating LDAP users, continue to set a blank password, but add a condition to the non-LDAP authentication mechanism to notice a login against a blank password and to being the password reset/email/confirm process in such a situation. (Hmmm is this the best solution?)

Or am I making a meal out of a contrived situation which is highly unlikely to happen? Would a warning in the config file next to $g_login_method suffice?

</can>

sithgunner

sithgunner

2007-01-19 20:14

reporter   ~0013934

Hmm, I thought I posted my comment... but here goes again.

Anyway, in summary, I said,
As for how to manage password sync, the server should, on changing the auth method to local user from ldap, sync password from ldap on existing user to store them in SQL, so, when users use next time, they have newest ldap password and can manage their password on local mantis db from then on. Don't think even with a few thousand users, it would be too much of a concern on server to update all passwords.

But I think that feature is beyond that of this php file, so I guess developers should merge the idea on the mantis source.

ape

ape

2007-01-29 10:37

reporter   ~0013971

I agree with sithgunner on this one: I think the 'changing from LDAP auth to something else' issue is somewhat contrived and would anyway be admin issue not a user one.

If we can get this fix checked in, then we can file another bug and consider the 'changing auth methods' problem separately. I think it's well beyond the scope of this bug.

mlowrie

mlowrie

2007-10-30 22:01

reporter   ~0016034

Last edited: 2007-11-05 02:05

I just tried installing Mantis 1.1.0rc2 only to find that this is STILL an issue. Why use an LDAP backend if it requires manual intervention for users to use Mantis? It kinda defeats the purpose of using LDAP... same old story... I know.

Anyway, does anyone have patches for 1.10rc2 or will I be stuck using an older version? I really don't have the time to figure out what has changed since 1.53 and how to change the patch to get this working.

(My apologies if this has been fixed and it's just my inept configuration abilities)

[edit]
Someone has generated diffs for this release candidate:
http://www.mantisbt.org/bugs/view.php?id=7731

ape

ape

2008-03-10 11:00

reporter   ~0017306

Attaching updated patch (authentication_api.php.rev5021.patch) and drop-in replacement (authentication_api.rev5021+.php) for authentication_api.php for Mantis 1.1.1.

Tested and working fine here.

Might this make it in to 1.1.2? Or at least 1.2.0?

dpdev

dpdev

2008-08-05 09:26

reporter   ~0019038

Last edited: 2008-08-05 09:26

The patch 'authentication_api.php.rev5021.patch' work fine on 1.1.2.

brissou

brissou

2009-03-24 11:48

reporter   ~0021179

Last edited: 2009-03-24 12:00

[Resolved]

Hy everybody,
I'm really interested in using this 'authentication_api.php' patch.
Unfortunately I don't know a lot about SOAP API.
I've paste the authentication_api.rev5021+.php in the mantis api folder...

Is there something else to change? I suppose i need to add a line to tell mantis => 'please take the authentication.api' during the login process..
But i don't know where i have to do this...

Thank you by advance

Brissou

I'm using mantis 1.1.1

=> ok I answer to my question:
you need to replace the authentication_api.php in /core

eevul

eevul

2009-03-25 18:16

reporter   ~0021190

I was able to replace the authentication_api.php in /core with MantisBT 1.1.6 and it seems to be working fine. It does not seem to be working in MantisBT 1.20a3. I am getting the following error in my Browser:

Fatal error: Call to undefined function auth_automatic_logon_bypass_form() in /var/www/html/login_page.php on line 40

I am using Debian Lenny with PHP Version 5.2.6-1+lenny2 and mySQL5.

Related Changesets

MantisBT: master-1.2.x 639629e9

2009-07-15 00:20

vboctor


Details Diff
Fixes 0005595: LDAP authentication requires accounts to be manually created first. Affected Issues
0005595
mod - core/ldap_api.php Diff File
mod - signup_page.php Diff File
mod - core/print_api.php Diff File
mod - lost_pwd_page.php Diff File
mod - core/authentication_api.php Diff File

MantisBT: master ac370f40

2009-07-15 00:20

vboctor


Details Diff
Fixes 0005595: LDAP authentication requires accounts to be manually created first. Affected Issues
0005595
mod - core/ldap_api.php Diff File
mod - signup_page.php Diff File
mod - core/print_api.php Diff File
mod - lost_pwd_page.php Diff File
mod - core/authentication_api.php Diff File