View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0009967 | mantisbt | ldap | public | 2008-12-12 14:55 | 2021-01-16 05:01 |
Reporter | rgomes1997 | Assigned To | dregad | ||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | closed | Resolution | won't fix | ||
Product Version | git trunk | ||||
Summary | 0009967: Added capability to create accounts on OpenLDAP | ||||
Description | Hi, I've added basic support for creating userDN on OpenLDAP and potentially Micro$oft AD to. ---Overview ---
---Issues---
| ||||
Additional Information | See attached files:
| ||||
Tags | patch | ||||
Attached Files | mantisbt-20081208.patch (17,916 bytes)
Only in mantisbt-20081208.new: config_inc.php diff -urp mantisbt-20081208.old/core/ldap_api.php mantisbt-20081208.new/core/ldap_api.php --- mantisbt-20081208.old/core/ldap_api.php 2008-12-09 14:40:45.000000000 +0000 +++ mantisbt-20081208.new/core/ldap_api.php 2008-12-12 19:14:39.000000000 +0000 @@ -73,12 +73,12 @@ function ldap_email_from_username( $p_us $t_ldap_organization = config_get( 'ldap_organization' ); $t_ldap_root_dn = config_get( 'ldap_root_dn' ); - $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ); - $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$p_username))"; + $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); + $t_search_filter = "(&$t_ldap_organization($t_ldap_username_field=$p_username))"; $t_search_attrs = array( - $t_ldap_uid_field, + $t_ldap_username_field, 'mail', - 'dn', + 'dn' ); $t_ds = ldap_connect_bind(); @@ -97,12 +97,12 @@ function ldap_has_group( $p_user_id, $p_ $t_ldap_root_dn = config_get( 'ldap_root_dn' ); $t_username = user_get_field( $p_user_id, 'username' ); - $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ); - $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$t_username)(assignedgroup=$p_group))"; + $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); + $t_search_filter = "(&$t_ldap_organization($t_ldap_username_field=$t_username)(assignedgroup=$p_group))"; $t_search_attrs = array( - $t_ldap_uid_field, + $t_ldap_username_field, 'dn', - 'assignedgroup', + 'assignedgroup' ); $t_ds = ldap_connect_bind(); @@ -133,11 +133,11 @@ function ldap_authenticate( $p_user_id, $t_ldap_root_dn = config_get( 'ldap_root_dn' ); $t_username = user_get_field( $p_user_id, 'username' ); - $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ); - $t_search_filter = "(&$t_ldap_organization($t_ldap_uid_field=$t_username))"; + $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); + $t_search_filter = "(&$t_ldap_organization($t_ldap_username_field=$t_username))"; $t_search_attrs = array( - $t_ldap_uid_field, - 'dn', + $t_ldap_username_field, + 'dn' ); $t_ds = ldap_connect_bind(); @@ -169,6 +169,394 @@ function ldap_authenticate( $p_user_id, return $t_authenticated; } + +##### Richard Gomes: started to add code from here ##### + + +/** + * This method is responsible for finding an user given its username, the rootDN + * and parameters used to build a search filter. A bind using the given username + * and password is tried for every candidate match in order to properly identify + * which userDN entry we are interested on. + * + * A typical scenario would be when we would like to find an inetOrgPerson class + * which contains a certain cn attribute. Another scenario would be when we are + * interested on a posixAccount class which contatin a certain uid. Doing so, we + * can find an user by various search strategies + * + * This approach is useful when a certain user has a typical unix id for + * FTP and SSH access for instance, but has also another identification for + * wiki systems and eventually other identifications. + * + * Below we can see an use case: + * ----------------------------------------------------------- + * dn: uid=jsmith,ou=people,dc=example,dc=com + * objectClass: krb5Principal + * objectClass: krb5KDCEntry + * objectClass: simpleSecurityObject + * objectClass: inetOrgPerson + * objectClass: person + * objectClass: top + * uid: jsmith + * cn: JohnSmith + * cn: John Smith + * sn: Smith + * description: John Paul Smith + * givenName: John + * displayName: Smith, John + * mail: john.smith@example.com + * userPassword: {K5KEY} + * krb5PrincipalName: jsmith@EXAMPLE.COM + * krb5KeyVersionNumber: 0 + * krb5KDCFlags: 126 + * krb5MaxLife: 86400 + * krb5MaxRenew: 604800 + * krb5Key: + * ----------------------------------------------------------- + * + * Observe that "cn=JohnSmith" is intended to be used by wiki systems. + * + * Notes: + * 1. This method <i>always<i> performs a search. It never tries to access + * the user entry directly by its supposed dn. + * 2. Mantis is not responsible for creating all possible objectClass(es) + * needed by other purposes like FTP, SSH, Kerberos, but it's desirable to + * smoothly integrate Mantis with previously created user entries, providing + * means of recognizing the same user by various means. + * + * Parameters + * $p_username is user we would like to find. Example: 'jsmith' + * $p_password is the password for binding such user. A bind is performed in + * order to make sure the correct userDN was found. + * $p_ldap_people_dn is the rootDN where userDNs are located into. + * Example: 'ou=people,dc=example,dc=com' + * $p_ldap_organization is used to build a search filter. + * Example: '(objectClass=inetOrgPerson)' + * + * Returns: + * a DN relative to the successfully authenticated user entry. + */ +function ldap_find_userdn( $p_username, $p_password, $p_ldap_people_dn = '', $p_ldap_organization = '' ) { +//trigger_error( "Entering ldap_find_userdn", WARNING ); + // assertions + if ( '' == $p_username ) return NULL; + if ( '' == $p_ldap_people_dn ) { + $p_ldap_people_dn = config_get( 'ldap_people_dn', "ou=people,".config_get( 'ldap_base_dn' ) ); + } + if ( '' == $p_ldap_organization ) { + $p_ldap_organization = config_get( 'ldap_organization' , '' ); + } + + // find userDN, if any + $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); +//trigger_error( "p_ldap_people_dn"."=".$p_ldap_people_dn, WARNING ); +//trigger_error( "p_ldap_organization"."=".$p_ldap_organization, WARNING ); +//trigger_error( "t_ldap_username_field"."=".$t_ldap_username_field, WARNING ); + $t_user_dn = ldap_find_userdn_by_attribute( $p_username, $p_password, $p_ldap_people_dn, $p_ldap_organization, $t_ldap_username_field ); +//trigger_error( "t_user_dn"."=".$t_user_dn, WARNING ); + return $t_user_dn; +} + + +/** + * This method is intended to be called by ldap_find_userdn. + * Some consistency checks are not done here! You were warned! + */ +function ldap_find_userdn_by_attribute( $p_username = '', + $p_password = '', + $p_ldap_people_dn = '', + $p_ldap_organization ='', + $p_ldap_attribute ='') { +//trigger_error( "Entering ldap_find_userdn_by_attribute", WARNING ); + // assertions + if ( '' == $p_ldap_attribute ) return NULL; + + // connect using an admin bind username/password + $t_ldap_bind_dn = config_get( 'ldap_bind_dn' ); + $t_ldap_bind_passwd = config_get( 'ldap_bind_passwd' ); + $t_ds = ldap_connect_bind( $t_ldap_bind_dn, $t_ldap_bind_password ); + + // build search filter and attributes we are interested on + if ( '' == $p_ldap_organization ) { + $t_search_filter = "($p_ldap_attribute=$p_username)"; + } else { + $t_search_filter = "(&$p_ldap_organization($p_ldap_attribute=$p_username))"; + } + $t_search_attrs = array($p_ldap_attribute, 'dn'); + // perform search +//trigger_error( "p_ldap_root_dn"."=".$p_ldap_root_dn, WARNING ); +//trigger_error( "t_search_filter"."=".$t_search_filter, WARNING ); + $t_sr = ldap_search( $t_ds, $p_ldap_root_dn, $t_search_filter, $t_search_attrs ); + $t_info = ldap_get_entries( $t_ds, $t_sr ); + + $t_result_dn = NULL; + + if ( $t_info ) { + for ( $i = 0; $i < $t_info['count']; $i++ ) { + $t_dn = $t_info[$i]['dn']; + # Attempt to connect again but using the obtained DN + $t_test_ds = ldap_connect_bind( $t_dn, $p_password ); + if ( $t_test_ds ) { + $t_result_dn = $t_dn; + ldap_unbind( $t_test_ds ); + break; + } + } + } + + ldap_free_result( $t_sr ); + ldap_unbind( $t_ds ); + + return $t_result_dn; +} + + +function ldap_default_kerberos_domain( $p_ldap_base_dn = '' ) { + if ( '' == $p_ldap_base_dn ) { + $p_ldap_base_dn = config_get( 'ldap_base_dn' ); + } + return strtoupper( str_replace ( array('dc=',','), array('','.'), $p_ldap_base_dn ) ); +} + + +/** + * Returns a password that is created via the configured hash settings. + * + * @param string $password + * @return string + */ +function ldap_get_password_hash( $password ) { + $t_passwd_method = strtolower( config_get( 'passwd_method', 'sha' ) ); + + switch ( $t_passwd_method ) { + case 'clear': + $pass = $password; + break; + case 'crypt': + $pass = '{CRYPT}' . crypt( $password ); + break; + case 'md5': + $tmp = base64_encode( pack( 'H*', md5( $password ) ) ); + $pass = "{MD5}".$tmp; + break; + default: + $tmp = base64_encode( pack( 'H*', sha1( $password ) ) ); + $pass = "{SHA}".$tmp; + break; + } + + return $pass; +} + + +/** + * This is a typical record being produced by this method: + * ----------------------------------------------------------- + * dn: uid=jsmith,ou=people,dc=example,dc=com + * objectClass: krb5Principal + * objectClass: krb5KDCEntry + * objectClass: simpleSecurityObject + * objectClass: inetOrgPerson + * objectClass: person + * objectClass: top + * uid: jsmith + * cn: JohnSmith + * cn: John Smith + * sn: Smith + * description: John Paul Smith + * givenName: John + * displayName: Smith, John + * mail: john.smith@example.com + * userPassword: {K5KEY} + * krb5PrincipalName: jsmith@EXAMPLE.COM + * krb5KeyVersionNumber: 0 + * krb5KDCFlags: 126 + * krb5MaxLife: 86400 + * krb5MaxRenew: 604800 + * krb5Key: + * ----------------------------------------------------------- + */ +function ldap_prepare_entry( $p_username, $p_realname, $p_email ) { + + // Ensure username is lowecase + $p_username = strtolower( $p_username ); + + // split realname and test results + if ( '' == $p_realname ) { + trigger_error( "Realname cannot be empty", ERROR ); + return NULL; + } + $names = split(' ', $p_realname); + if ( sizeof( $names ) < 2 ) { + trigger_error( "Realname must have at least first and last names", ERROR ); + return NULL; + } + + // obtain name and surname + $first = $names[0]; + $last = $names[sizeof($names)-1]; + + // obtain Kerberos preferences + $t_krb_vendor = strtolower( config_get( 'krb_vendor', 'none' ) ); + + // set up basic objectClass(es) + $classes = 0; + if ( 'heimdal' == $t_krb_vendor ) { + $entry['objectClass'][$classes++] = 'krb5Principal'; + $entry['objectClass'][$classes++] = 'krb5KDCEntry'; + } + $entry['objectClass'][$classes++] = 'simpleSecurityObject'; + $entry['objectClass'][$classes++] = 'inetOrgPerson'; + $entry['objectClass'][$classes++] = 'person'; + $entry['objectClass'][$classes++] = 'top'; + + // attributes uid and cn are mandatory in objectClass=account + $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ); + $t_ldap_cn_field = config_get( 'ldap_cn_field', 'cn' ); + $entry[$t_ldap_uid_field] = $p_username; + $entry[$t_ldap_cn_field][0] = $first; + $entry[$t_ldap_cn_field][1] = $first.$last; + $entry[$t_ldap_cn_field][2] = $first.' '.$last; + + // attribute sn is mandatory in objectClass=inetOrgPerson + $entry['sn'] = $last; + + // attribute mail is optional in objectClass=inetOrgPerson + // but highly useful + $entry['mail'] = $p_email; + + // attributes givenName, displayName and description are optional in + // objectClass=inetOrgPerson but highly useful + $entry['givenName'] = $first; + $entry['displayName'] = $last.", ".$first; + $middle = ""; + for ( $i = 1; $i < sizeof($names)-1; $i++ ) { + $middle = $middle.' '.$names[$i]; + } + $entry['description'] = $first.$middle.' '.$last; + + if ( 'heimdal' == $t_krb_vendor ) { + // attribute krb5PrincipalName is mandatory in objectClass=krb5Principal + $t_krb_domain = config_get( 'krb_domain', ldap_default_kerberos_domain( ) ); + $entry['krb5PrincipalName'] = $p_username.'@'.$t_krb_domain; + + // attribute krb5VersionNumber is mandatory in objectClass=krb5KDCEntry + $entry['krb5KeyVersionNumber'] = 0; + + // optional attributes in objectClass=krb5KDCEntry + $entry['krb5KDCFlags'] = 126; + $entry['krb5MaxLife'] = 86400; + $entry['krb5MaxRenew'] = 604800; + + // optional krb5Key is the initial password in objectClass=krb5KDCEntry + $entry['krb5Key'] = 'cleartext'; + + // attribute userPassword is mandatory in objectClass=simpleSecurityObject + $entry['userPassword'] = '{K5KEY}'; + } else { + // attribute userPassword is mandatory in objectClass=simpleSecurityObject + $entry['userPassword'] = 'cleartext'; + } + + return $entry; +} + + # Create a new user account in the LDAP Directory. +function ldap_create_user( $p_username, $p_password, $p_realname, $p_email ) { +//trigger_error( "Entering ldap_create_user", WARNING ); + + // find userDN, if any + $t_user_dn = ldap_find_userdn( $p_username, $p_password ); + $create = ( NULL == $t_user_dn ); + if ( $create ) { + $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); + $t_ldap_people_dn = config_get( 'ldap_people_dn' ); + $t_user_dn = $t_ldap_username_field.'='.$p_username.','.$t_ldap_people_dn; + } + + // prepare an entry for being added or modify an existing one + $entry = ldap_prepare_entry( $p_username, $p_realname, $p_email ); + if ( NULL == $entry ) return false; + + // if an existing userDN was found, simply consolidate its contents + if ( ! $create ) return ldap_modify_userdn( $t_user_dn, $entry ); + + // bind as privileged user + $t_ldap_writer_dn = config_get( 'ldap_writer_dn', config_get( 'ldap_bind_dn' ) ); + $t_ldap_writer_passwd = config_get( 'ldap_writer_passwd', config_get( 'ldap_bind_passwd' ) ); + $t_ds = ldap_connect_bind( $t_ldap_writer_dn , $t_ldap_writer_passwd ); + + // try to add a new userDN + $t_added = ldap_add( $t_ds, $t_user_dn, $entry ); + if ( !$t_added ) { + trigger_error( "Failed to add user $t_user_dn", ERROR ); + } + + // now change password :: ldap_get_password_hash( $p_password ); + + ldap_unbind($t_ds); + return $t_added; +} + # Update the user's account in the LDAP Directory + +function ldap_modify_user( $p_username, $p_password, $p_realname, $p_email ) { +trigger_error( "ldap_modify_user(username, password, realname, email) is not implemented", WARNING ); + return false; +} + +function ldap_modify_userdn( $p_user_dn, $p_entry ) { +trigger_error( "ldap_modify_userdn(p_user_dn, p_entry) is not implemented", WARNING ); + return true; +} + + # Change the user's password in the LDAP Directory + +/** + * This method binds to an existing userDN and requests a password change. + * + * See: + * ldap_passwd_userdn + */ +function ldap_passwd( $p_username, $p_password, $p_new_password) { +//trigger_error( "Entering ldap_passwd", WARNING ); + $t_user_dn = ldap_find_userdn( $p_username, $p_password ); + return ldap_passwd_userdn( $t_userdn, $p_new_password ); +} + + +/** + * This method changes the password of a given userDN without binding to it. + * This strategy allows a priviledged account to change user's password without + * knowing its previous password. + * + * See: + * ldap_passwd + */ +function ldap_passwd_userdn( $p_user_dn, $p_new_password ) { +trigger_error( "ldap_passwd_userdn(p_user_dn, p_new_password) is not implemented", ERROR ); + // not allowed yet + return FALSE; + + // THIS CODE WAS NEVER TESTED ! You were warned!! :( + + // assertions + if ( (NULL == $p_userdn) || ( '' == $p_user_dn ) ) return false; + + // bind as privileged user + $t_ldap_writer_dn = config_get( 'ldap_writer_dn', config_get( 'ldap_bind_dn' ) ); + $t_ldap_writer_passwd = config_get( 'ldap_writer_passwd', config_get( 'ldap_bind_passwd' ) ); + $t_ds = ldap_connect_bind( $t_ldap_writer_dn, $t_ldap_writer_passwd ); + + $entry['userPassword'] = $p_password; + + // try to add a new userDN + $t_modified = ldap_modify( $t_ds, $p_user_dn, $entry ); + if ( !$t_modified ) { + trigger_error( "Failed to change password for $t_user_dn", ERROR ); + } + + return $t_modified; +} diff -urp mantisbt-20081208.old/core/user_api.php mantisbt-20081208.new/core/user_api.php --- mantisbt-20081208.old/core/user_api.php 2008-12-09 14:40:45.000000000 +0000 +++ mantisbt-20081208.new/core/user_api.php 2008-12-11 12:43:36.000000000 +0000 @@ -446,6 +446,13 @@ function user_create( $p_username, $p_pa user_ensure_realname_unique( $p_username, $p_realname ); email_ensure_valid( $p_email ); + $t_login_method = config_get( 'login_method' ); + if ( $t_login_method == LDAP) { + if ( !ldap_create_user( $p_username, $p_password, $p_realname, $p_email ) ) { + return ''; + } + } + $t_seed = $p_email . $p_username; $t_cookie_string = auth_generate_unique_cookie_string( $t_seed ); $t_user_table = db_get_table( 'mantis_user_table' ); @@ -1253,6 +1260,13 @@ function user_set_password( $p_user_id, $c_password = auth_process_plain_password( $p_password ); $c_user_table = db_get_table( 'mantis_user_table' ); + $t_login_method = config_get( 'login_method' ); + if ( $t_login_method == LDAP) { + if ( !ldap_passwd( $p_username, $p_password ) ) { + return false; + } + } + $query = "UPDATE $c_user_table SET password=" . db_param() . ", cookie_string=" . db_param() . " config_inc.php (4,678 bytes)
<?php // // FILE: config_inc.php // // // Regarding LDAP authentication // // Mantis does not fully support LDAP authentication. // // For the time being, LDAP accounts must be created elsewhere whilst // Mantis administrator is responsible for creating these accounts by // hand in Mantis. This is because Mantis keeps user information in its // internal SQL database. Only authentication is done againt LDAP database. // // The account creation in Mantis consists of picking up a convenient // username for a previously created account in LDAP. The current // implementation allows you to choose which LDAP attribute must be used. // For instance: The following userDN could be selected by its "uid=jsmith" // or "cn=JohnSmith" or "cn=John Smith", etc. // ----------------------------------------------------------- // dn: uid=jsmith,ou=people,dc=example,dc=com // objectClass: simpleSecurityObject // objectClass: inetOrgPerson // objectClass: person // objectClass: top // uid: jsmith // cn: JohnSmith // cn: John Smith // sn: Smith // description: John Paul Smith // givenName: John // displayName: Smith, John // mail: john.smith@example.com // userPassword: secret // ----------------------------------------------------------- // // Once the administrator choose which field must be used, it must be // referenced by g_ldap_username_field, like this: // // $g_ldap_uid_field = 'uid'; // M$ AD uses 'sAMAccountName' // $g_ldap_cn_field = 'cn'; // $g_ldap_username_field = &$g_ldap_cn_field; // // Other aspects to consider is that only the Mantis administrator is // allowed to create accounts. For this reason, signups are not allowed // and the password reset feature must be disallowed because it's not // fully implemented. // // $g_send_reset_password = OFF; // $g_allow_signup = OFF; // $g_send_reset_password = OFF; // This will display password input while creating new account for admin login. $g_allow_signup = OFF; // Sign up feature is disabled $g_login_method = LDAP; $g_passwd_method = 'clear'; // one of: 'clear', 'crypt', 'md5', 'sha'. default: 'sha' $g_ldap_protocol_version = 3; $g_ldap_server = 'ldap://localhost'; $g_ldap_port = '389'; $g_ldap_base_dn = 'dc=jquantlib,dc=org'; // bind for read-only opeations $g_ldap_bind_dn = 'cn=admin,dc=jquantlib,dc=org'; $g_ldap_bind_passwd = 'secret'; // bind for privileged operations $g_ldap_writer_dn = 'cn=admin,dc=jquantlib,dc=org'; // default: $g_ldap_bind_dn $g_ldap_writer_passwd = 'secret'; // default: $g_ldap_bind_passwd // DEPRECATED: // The name "rootDN" is a generic concept which can be applied to different operations. // We should have several "rootDNs" for several different operations instead. $g_ldap_root_dn = "ou=People,dc=jquantlib,dc=org"; // DEPRECATED: for backward compatibility only // peopleDN and groupDN are better replacements for rootDN $g_ldap_people_dn = "ou=People,dc=jquantlib,dc=org"; // default: "ou=people,".$ldap_base_dn $g_ldap_group_dn = "ou=Group,dc=jquantlib,dc=org"; // default: "ou=group,".$ldap_base_dn $g_ldap_uid_field = 'uid'; // default: 'uid' $g_ldap_cn_field = 'cn'; // default: 'cn' // attribute to be used for userDN lookups $g_ldap_username_field = &$g_ldap_uid_field; // We should have a more specific name here, for instance: $g_people_filter $g_ldap_organization = '(objectClass=inetOrgPerson)'; // default: '' $g_use_ldap_email = ON; // // The following setting are Kerberos related and indirectly related to LDAP // // MIT Kerberos and Heimdal Kerberos are able to store username/password information in LDAP backends. // By specifying the Kerberos implementation, additional objectClass(es) need to be added in the userDN // At the moment, only Heimdal Kerberos is supported $g_krb_vendor = 'heimdal'; // values: 'mit', 'heimdal', 'none'. Default: 'none' $g_krb_domain = 'JQUANTLIB.ORG'; // default: strtoupper(str_replace(array('dc=',','), array('','.'), $p_ldap_base_dn)) // ***** Add your other configurations here ***** ?> ldap_api.php (19,141 bytes)
<?php # Mantis - a php based bugtracking system # 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/>. /** * LDAP API * @package CoreAPI * @subpackage LDAPAPI * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org * @copyright Copyright (C) 2002 - 2009 Mantis Team - mantisbt-dev@lists.sourceforge.net * @link http://www.mantisbt.org */ # Connect and bind to the LDAP directory function ldap_connect_bind( $p_binddn = '', $p_password = '' ) { $t_ldap_server = config_get( 'ldap_server' ); if( !extension_loaded( 'ldap' ) ) { trigger_error( ERROR_LDAP_EXTENSION_NOT_LOADED, ERROR ); } $t_ds = @ldap_connect( $t_ldap_server ); if( $t_ds > 0 ) { $t_protocol_version = config_get( 'ldap_protocol_version' ); if( $t_protocol_version > 0 ) { ldap_set_option( $t_ds, LDAP_OPT_PROTOCOL_VERSION, $t_protocol_version ); } # If no Bind DN and Password is set, attempt to login as the configured # Bind DN. if( is_blank( $p_binddn ) && is_blank( $p_password ) ) { $p_binddn = config_get( 'ldap_bind_dn', '' ); $p_password = config_get( 'ldap_bind_passwd', '' ); } if( !is_blank( $p_binddn ) && !is_blank( $p_password ) ) { $t_br = @ldap_bind( $t_ds, $p_binddn, $p_password ); } else { # Either the Bind DN or the Password are empty, so attempt an anonymous bind. $t_br = @ldap_bind( $t_ds ); } if( !$t_br ) { trigger_error( ERROR_LDAP_AUTH_FAILED, ERROR ); } } else { trigger_error( ERROR_LDAP_SERVER_CONNECT_FAILED, ERROR ); } return $t_ds; } # Return an email address from LDAP, given a userid function ldap_email( $p_user_id ) { $t_username = user_get_field( $p_user_id, 'username' ); return ldap_email_from_username( $t_username ); } # Return an email address from LDAP, given a username function ldap_email_from_username( $p_username ) { $t_ldap_organization = config_get( 'ldap_organization' ); $t_ldap_root_dn = config_get( 'ldap_root_dn' ); $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); $t_search_filter = "(&$t_ldap_organization($t_ldap_username_field=$p_username))"; $t_search_attrs = array( $t_ldap_username_field, 'mail', 'dn' ); $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 ); ldap_free_result( $t_sr ); ldap_unbind( $t_ds ); return $t_info[0]['mail'][0]; } # Return true if the $uid has an assigngroup=$p_group tag, false otherwise function ldap_has_group( $p_user_id, $p_group ) { $t_ldap_organization = config_get( 'ldap_organization' ); $t_ldap_root_dn = config_get( 'ldap_root_dn' ); $t_username = user_get_field( $p_user_id, 'username' ); $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); $t_search_filter = "(&$t_ldap_organization($t_ldap_username_field=$t_username)(assignedgroup=$p_group))"; $t_search_attrs = array( $t_ldap_username_field, 'dn', 'assignedgroup' ); $t_ds = ldap_connect_bind(); $t_sr = ldap_search( $t_ds, $t_ldap_root_dn, $t_search_filter, $t_search_attrs ); $t_entries = ldap_count_entries( $t_ds, $t_sr ); ldap_free_result( $t_sr ); ldap_unbind( $t_ds ); if( $t_entries > 0 ) { return true; } else { return false; } } # Attempt to authenticate the user against the LDAP directory # return true on successful authentication, false otherwise function ldap_authenticate( $p_user_id, $p_password ) { # if password is empty and ldap allows anonymous login, then # the user will be able to login, hence, we need to check # for this special case. if( is_blank( $p_password ) ) { return false; } $t_ldap_organization = config_get( 'ldap_organization' ); $t_ldap_root_dn = config_get( 'ldap_root_dn' ); $t_username = user_get_field( $p_user_id, 'username' ); $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); $t_search_filter = "(&$t_ldap_organization($t_ldap_username_field=$t_username))"; $t_search_attrs = array( $t_ldap_username_field, 'dn' ); $t_ds = ldap_connect_bind(); # Search for the user id $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 ); $t_authenticated = false; if( $t_info ) { # Try to authenticate to each until we get a match for( $i = 0;$i < $t_info['count'];$i++ ) { $t_dn = $t_info[$i]['dn']; # Attempt to bind with the DN and password if( @ldap_bind( $t_ds, $t_dn, $p_password ) ) { $t_authenticated = true; break; # Don't need to go any further } } } ldap_free_result( $t_sr ); ldap_unbind( $t_ds ); return $t_authenticated; } ##### Richard Gomes: started to add code from here ##### /** * This method is responsible for finding an user given its username, the rootDN * and parameters used to build a search filter. A bind using the given username * and password is tried for every candidate match in order to properly identify * which userDN entry we are interested on. * * A typical scenario would be when we would like to find an inetOrgPerson class * which contains a certain cn attribute. Another scenario would be when we are * interested on a posixAccount class which contatin a certain uid. Doing so, we * can find an user by various search strategies * * This approach is useful when a certain user has a typical unix id for * FTP and SSH access for instance, but has also another identification for * wiki systems and eventually other identifications. * * Below we can see an use case: * ----------------------------------------------------------- * dn: uid=jsmith,ou=people,dc=example,dc=com * objectClass: krb5Principal * objectClass: krb5KDCEntry * objectClass: simpleSecurityObject * objectClass: inetOrgPerson * objectClass: person * objectClass: top * uid: jsmith * cn: JohnSmith * cn: John Smith * sn: Smith * description: John Paul Smith * givenName: John * displayName: Smith, John * mail: john.smith@example.com * userPassword: {K5KEY} * krb5PrincipalName: jsmith@EXAMPLE.COM * krb5KeyVersionNumber: 0 * krb5KDCFlags: 126 * krb5MaxLife: 86400 * krb5MaxRenew: 604800 * krb5Key: * ----------------------------------------------------------- * * Observe that "cn=JohnSmith" is intended to be used by wiki systems. * * Notes: * 1. This method <i>always<i> performs a search. It never tries to access * the user entry directly by its supposed dn. * 2. Mantis is not responsible for creating all possible objectClass(es) * needed by other purposes like FTP, SSH, Kerberos, but it's desirable to * smoothly integrate Mantis with previously created user entries, providing * means of recognizing the same user by various means. * * Parameters * $p_username is user we would like to find. Example: 'jsmith' * $p_password is the password for binding such user. A bind is performed in * order to make sure the correct userDN was found. * $p_ldap_people_dn is the rootDN where userDNs are located into. * Example: 'ou=people,dc=example,dc=com' * $p_ldap_organization is used to build a search filter. * Example: '(objectClass=inetOrgPerson)' * * Returns: * a DN relative to the successfully authenticated user entry. */ function ldap_find_userdn( $p_username, $p_password, $p_ldap_people_dn = '', $p_ldap_organization = '' ) { //trigger_error( "Entering ldap_find_userdn", WARNING ); // assertions if ( '' == $p_username ) return NULL; if ( '' == $p_ldap_people_dn ) { $p_ldap_people_dn = config_get( 'ldap_people_dn', "ou=people,".config_get( 'ldap_base_dn' ) ); } if ( '' == $p_ldap_organization ) { $p_ldap_organization = config_get( 'ldap_organization' , '' ); } // find userDN, if any $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); //trigger_error( "p_ldap_people_dn"."=".$p_ldap_people_dn, WARNING ); //trigger_error( "p_ldap_organization"."=".$p_ldap_organization, WARNING ); //trigger_error( "t_ldap_username_field"."=".$t_ldap_username_field, WARNING ); $t_user_dn = ldap_find_userdn_by_attribute( $p_username, $p_password, $p_ldap_people_dn, $p_ldap_organization, $t_ldap_username_field ); //trigger_error( "t_user_dn"."=".$t_user_dn, WARNING ); return $t_user_dn; } /** * This method is intended to be called by ldap_find_userdn. * Some consistency checks are not done here! You were warned! */ function ldap_find_userdn_by_attribute( $p_username = '', $p_password = '', $p_ldap_people_dn = '', $p_ldap_organization ='', $p_ldap_attribute ='') { //trigger_error( "Entering ldap_find_userdn_by_attribute", WARNING ); // assertions if ( '' == $p_ldap_attribute ) return NULL; // connect using an admin bind username/password $t_ldap_bind_dn = config_get( 'ldap_bind_dn' ); $t_ldap_bind_passwd = config_get( 'ldap_bind_passwd' ); $t_ds = ldap_connect_bind( $t_ldap_bind_dn, $t_ldap_bind_password ); // build search filter and attributes we are interested on if ( '' == $p_ldap_organization ) { $t_search_filter = "($p_ldap_attribute=$p_username)"; } else { $t_search_filter = "(&$p_ldap_organization($p_ldap_attribute=$p_username))"; } $t_search_attrs = array($p_ldap_attribute, 'dn'); // perform search //trigger_error( "p_ldap_root_dn"."=".$p_ldap_root_dn, WARNING ); //trigger_error( "t_search_filter"."=".$t_search_filter, WARNING ); $t_sr = ldap_search( $t_ds, $p_ldap_root_dn, $t_search_filter, $t_search_attrs ); $t_info = ldap_get_entries( $t_ds, $t_sr ); $t_result_dn = NULL; if ( $t_info ) { for ( $i = 0; $i < $t_info['count']; $i++ ) { $t_dn = $t_info[$i]['dn']; # Attempt to connect again but using the obtained DN $t_test_ds = ldap_connect_bind( $t_dn, $p_password ); if ( $t_test_ds ) { $t_result_dn = $t_dn; ldap_unbind( $t_test_ds ); break; } } } ldap_free_result( $t_sr ); ldap_unbind( $t_ds ); return $t_result_dn; } function ldap_default_kerberos_domain( $p_ldap_base_dn = '' ) { if ( '' == $p_ldap_base_dn ) { $p_ldap_base_dn = config_get( 'ldap_base_dn' ); } return strtoupper( str_replace ( array('dc=',','), array('','.'), $p_ldap_base_dn ) ); } /** * Returns a password that is created via the configured hash settings. * * @param string $password * @return string */ function ldap_get_password_hash( $password ) { $t_passwd_method = strtolower( config_get( 'passwd_method', 'sha' ) ); switch ( $t_passwd_method ) { case 'clear': $pass = $password; break; case 'crypt': $pass = '{CRYPT}' . crypt( $password ); break; case 'md5': $tmp = base64_encode( pack( 'H*', md5( $password ) ) ); $pass = "{MD5}".$tmp; break; default: $tmp = base64_encode( pack( 'H*', sha1( $password ) ) ); $pass = "{SHA}".$tmp; break; } return $pass; } /** * This is a typical record being produced by this method: * ----------------------------------------------------------- * dn: uid=jsmith,ou=people,dc=example,dc=com * objectClass: krb5Principal * objectClass: krb5KDCEntry * objectClass: simpleSecurityObject * objectClass: inetOrgPerson * objectClass: person * objectClass: top * uid: jsmith * cn: JohnSmith * cn: John Smith * sn: Smith * description: John Paul Smith * givenName: John * displayName: Smith, John * mail: john.smith@example.com * userPassword: {K5KEY} * krb5PrincipalName: jsmith@EXAMPLE.COM * krb5KeyVersionNumber: 0 * krb5KDCFlags: 126 * krb5MaxLife: 86400 * krb5MaxRenew: 604800 * krb5Key: * ----------------------------------------------------------- */ function ldap_prepare_entry( $p_username, $p_realname, $p_email ) { // Ensure username is lowecase $p_username = strtolower( $p_username ); // split realname and test results if ( '' == $p_realname ) { trigger_error( "Realname cannot be empty", ERROR ); return NULL; } $names = split(' ', $p_realname); if ( sizeof( $names ) < 2 ) { trigger_error( "Realname must have at least first and last names", ERROR ); return NULL; } // obtain name and surname $first = $names[0]; $last = $names[sizeof($names)-1]; // obtain Kerberos preferences $t_krb_vendor = strtolower( config_get( 'krb_vendor', 'none' ) ); // set up basic objectClass(es) $classes = 0; if ( 'heimdal' == $t_krb_vendor ) { $entry['objectClass'][$classes++] = 'krb5Principal'; $entry['objectClass'][$classes++] = 'krb5KDCEntry'; } $entry['objectClass'][$classes++] = 'simpleSecurityObject'; $entry['objectClass'][$classes++] = 'inetOrgPerson'; $entry['objectClass'][$classes++] = 'person'; $entry['objectClass'][$classes++] = 'top'; // attributes uid and cn are mandatory in objectClass=account $t_ldap_uid_field = config_get( 'ldap_uid_field', 'uid' ); $t_ldap_cn_field = config_get( 'ldap_cn_field', 'cn' ); $entry[$t_ldap_uid_field] = $p_username; $entry[$t_ldap_cn_field][0] = $first; $entry[$t_ldap_cn_field][1] = $first.$last; $entry[$t_ldap_cn_field][2] = $first.' '.$last; // attribute sn is mandatory in objectClass=inetOrgPerson $entry['sn'] = $last; // attribute mail is optional in objectClass=inetOrgPerson // but highly useful $entry['mail'] = $p_email; // attributes givenName, displayName and description are optional in // objectClass=inetOrgPerson but highly useful $entry['givenName'] = $first; $entry['displayName'] = $last.", ".$first; $middle = ""; for ( $i = 1; $i < sizeof($names)-1; $i++ ) { $middle = $middle.' '.$names[$i]; } $entry['description'] = $first.$middle.' '.$last; if ( 'heimdal' == $t_krb_vendor ) { // attribute krb5PrincipalName is mandatory in objectClass=krb5Principal $t_krb_domain = config_get( 'krb_domain', ldap_default_kerberos_domain( ) ); $entry['krb5PrincipalName'] = $p_username.'@'.$t_krb_domain; // attribute krb5VersionNumber is mandatory in objectClass=krb5KDCEntry $entry['krb5KeyVersionNumber'] = 0; // optional attributes in objectClass=krb5KDCEntry $entry['krb5KDCFlags'] = 126; $entry['krb5MaxLife'] = 86400; $entry['krb5MaxRenew'] = 604800; // optional krb5Key is the initial password in objectClass=krb5KDCEntry $entry['krb5Key'] = 'cleartext'; // attribute userPassword is mandatory in objectClass=simpleSecurityObject $entry['userPassword'] = '{K5KEY}'; } else { // attribute userPassword is mandatory in objectClass=simpleSecurityObject $entry['userPassword'] = 'cleartext'; } return $entry; } # Create a new user account in the LDAP Directory. function ldap_create_user( $p_username, $p_password, $p_realname, $p_email ) { //trigger_error( "Entering ldap_create_user", WARNING ); // find userDN, if any $t_user_dn = ldap_find_userdn( $p_username, $p_password ); $create = ( NULL == $t_user_dn ); if ( $create ) { $t_ldap_username_field = config_get( 'ldap_username_field', 'uid' ); $t_ldap_people_dn = config_get( 'ldap_people_dn' ); $t_user_dn = $t_ldap_username_field.'='.$p_username.','.$t_ldap_people_dn; } // prepare an entry for being added or modify an existing one $entry = ldap_prepare_entry( $p_username, $p_realname, $p_email ); if ( NULL == $entry ) return false; // if an existing userDN was found, simply consolidate its contents if ( ! $create ) return ldap_modify_userdn( $t_user_dn, $entry ); // bind as privileged user $t_ldap_writer_dn = config_get( 'ldap_writer_dn', config_get( 'ldap_bind_dn' ) ); $t_ldap_writer_passwd = config_get( 'ldap_writer_passwd', config_get( 'ldap_bind_passwd' ) ); $t_ds = ldap_connect_bind( $t_ldap_writer_dn , $t_ldap_writer_passwd ); // try to add a new userDN $t_added = ldap_add( $t_ds, $t_user_dn, $entry ); if ( !$t_added ) { trigger_error( "Failed to add user $t_user_dn", ERROR ); } // now change password :: ldap_get_password_hash( $p_password ); ldap_unbind($t_ds); return $t_added; } # Update the user's account in the LDAP Directory function ldap_modify_user( $p_username, $p_password, $p_realname, $p_email ) { trigger_error( "ldap_modify_user(username, password, realname, email) is not implemented", WARNING ); return false; } function ldap_modify_userdn( $p_user_dn, $p_entry ) { trigger_error( "ldap_modify_userdn(p_user_dn, p_entry) is not implemented", WARNING ); return true; } # Change the user's password in the LDAP Directory /** * This method binds to an existing userDN and requests a password change. * * See: * ldap_passwd_userdn */ function ldap_passwd( $p_username, $p_password, $p_new_password) { //trigger_error( "Entering ldap_passwd", WARNING ); $t_user_dn = ldap_find_userdn( $p_username, $p_password ); return ldap_passwd_userdn( $t_userdn, $p_new_password ); } /** * This method changes the password of a given userDN without binding to it. * This strategy allows a priviledged account to change user's password without * knowing its previous password. * * See: * ldap_passwd */ function ldap_passwd_userdn( $p_user_dn, $p_new_password ) { trigger_error( "ldap_passwd_userdn(p_user_dn, p_new_password) is not implemented", ERROR ); // not allowed yet return FALSE; // THIS CODE WAS NEVER TESTED ! You were warned!! :( // assertions if ( (NULL == $p_userdn) || ( '' == $p_user_dn ) ) return false; // bind as privileged user $t_ldap_writer_dn = config_get( 'ldap_writer_dn', config_get( 'ldap_bind_dn' ) ); $t_ldap_writer_passwd = config_get( 'ldap_writer_passwd', config_get( 'ldap_bind_passwd' ) ); $t_ds = ldap_connect_bind( $t_ldap_writer_dn, $t_ldap_writer_passwd ); $entry['userPassword'] = $p_password; // try to add a new userDN $t_modified = ldap_modify( $t_ds, $p_user_dn, $entry ); if ( !$t_modified ) { trigger_error( "Failed to change password for $t_user_dn", ERROR ); } return $t_modified; } user_api.php (40,762 bytes)
<?php # Mantis - a php based bugtracking system # Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org # Copyright (C) 2002 - 2009 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$ # -------------------------------------------------------- /** * @package CoreAPI * @subpackage UserAPI */ $t_core_dir = dirname( __FILE__ ) . DIRECTORY_SEPARATOR; require_once( $t_core_dir . 'email_api.php' ); require_once( $t_core_dir . 'ldap_api.php' ); # =================================== # Caching # =================================== # ######################################## # SECURITY NOTE: cache globals are initialized here to prevent them # being spoofed if register_globals is turned on $g_cache_user = array(); # -------------------- # Cache a user row if necessary and return the cached copy # If the second parameter is true (default), trigger an error # if the user can't be found. If the second parameter is # false, return false if the user can't be found. function user_cache_row( $p_user_id, $p_trigger_errors = true ) { global $g_cache_user; if( isset( $g_cache_user[$p_user_id] ) ) { return $g_cache_user[$p_user_id]; } $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT * FROM $t_user_table WHERE id=" . db_param(); $result = db_query_bound( $query, Array( $p_user_id ) ); if( 0 == db_num_rows( $result ) ) { $g_cache_user[$p_user_id] = false; if( $p_trigger_errors ) { error_parameters( (integer)$p_user_id ); trigger_error( ERROR_USER_BY_ID_NOT_FOUND, ERROR ); } return false; } $row = db_fetch_array( $result ); $g_cache_user[$p_user_id] = $row; return $row; } function user_cache_array_rows( $p_user_id_array ) { global $g_cache_user; $c_user_id_array = array(); foreach( $p_user_id_array as $t_user_id ) { if( !isset( $g_cache_user[(int) $t_user_id] ) ) { $c_user_id_array[] = (int) $t_user_id; } } if( empty( $c_user_id_array ) ) { return; } $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT * FROM $t_user_table WHERE id IN (" . implode( ',', $c_user_id_array ) . ')'; $result = db_query_bound( $query ); while( $row = db_fetch_array( $result ) ) { $g_cache_user[(int) $row['id']] = $row; } return; } # -------------------- # Cache an object as a bug. function user_cache_database_result( $p_user_database_result ) { global $g_cache_user; if( isset( $g_cache_user[$p_user_database_result['id']] ) ) { return $g_cache_user[$p_user_database_result['id']]; } $g_cache_user[$p_user_database_result['id']] = $p_user_database_result; } # -------------------- # Clear the user cache (or just the given id if specified) function user_clear_cache( $p_user_id = null ) { global $g_cache_user; if( null === $p_user_id ) { $g_cache_user = array(); } else { unset( $g_cache_user[$p_user_id] ); } return true; } function user_update_cache( $p_user_id, $p_field, $p_value ) { global $g_cache_user; if( isset( $g_cache_user[$p_user_id] ) && isset( $g_cache_user[$p_user_id][$p_field] ) ) { $g_cache_user[$p_user_id][$p_field] = $p_value; } else { user_clear_cache( $p_user_id ); } } function user_search_cache( $p_field, $p_value ) { global $g_cache_user; if( isset( $g_cache_user ) ) { foreach( $g_cache_user as $t_user ) { if( $t_user[$p_field] == $p_value ) { return $t_user; } } } return false; } # =================================== # Boolean queries and ensures # =================================== # -------------------- # check to see if user exists by id # return true if it does, false otherwise # # Use user_cache_row() to benefit from caching if called multiple times # and because if the user does exist the data may well be wanted function user_exists( $p_user_id ) { $row = user_cache_row( $p_user_id, false ); if( false === $row ) { return false; } else { return true; } } # -------------------- # check to see if project exists by id # if it doesn't exist then error # otherwise let execution continue undisturbed function user_ensure_exists( $p_user_id ) { $c_user_id = (integer)$p_user_id; if ( !user_exists( $c_user_id ) ) { error_parameters( $c_user_id ); trigger_error( ERROR_USER_BY_ID_NOT_FOUND, ERROR ); } } # -------------------- # return true if the username is unique, false if there is already a user # with that username function user_is_name_unique( $p_username ) { $c_username = db_prepare_string( $p_username ); $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT username FROM $t_user_table WHERE username=" . db_param(); $result = db_query_bound( $query, Array( $c_username ), 1 ); if( db_num_rows( $result ) > 0 ) { return false; } else { return true; } } # -------------------- # Check if the username is unique and trigger an ERROR if it isn't function user_ensure_name_unique( $p_username ) { if( !user_is_name_unique( $p_username ) ) { trigger_error( ERROR_USER_NAME_NOT_UNIQUE, ERROR ); } } # -------------------- # Check if the realname is a valid username (does not account for uniqueness) # Return 0 if it is invalid, The number of matches + 1 function user_is_realname_unique( $p_username, $p_realname ) { if( is_blank( $p_realname ) ) { # don't bother checking if realname is blank return 1; } $c_realname = db_prepare_string( $p_realname ); # allow realname to match username $t_count = 0; if( $p_realname <> $p_username ) { # check realname does not match an existing username if( user_get_id_by_name( $p_realname ) ) { return 0; } # check to see if the realname is unique $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT id FROM $t_user_table WHERE realname=" . db_param(); $result = db_query_bound( $query, Array( $c_realname ) ); $t_count = db_num_rows( $result ); if( $t_count > 0 ) { # set flags for non-unique realnames if( config_get( 'differentiate_duplicates' ) ) { for( $i = 0;$i < $t_count;$i++ ) { $t_user_id = db_result( $result, $i ); user_set_field( $t_user_id, 'duplicate_realname', ON ); } } } } return $t_count + 1; } # -------------------- # Check if the realname is a unique # Trigger an error if the username is not valid function user_ensure_realname_unique( $p_username, $p_realname ) { if( 1 > user_is_realname_unique( $p_username, $p_realname ) ) { trigger_error( ERROR_USER_REAL_MATCH_USER, ERROR ); } } # -------------------- # Check if the realname is a valid (does not account for uniqueness) # true: valid, false: not valid function user_is_realname_valid( $p_realname ) { return( !string_contains_scripting_chars( $p_realname ) ); } # -------------------- # Check if the realname is a valid (does not account for uniqueness), if not, trigger an error function user_ensure_realname_valid( $p_realname ) { if( !user_is_realname_valid( $p_realname ) ) { trigger_error( ERROR_USER_REAL_NAME_INVALID, ERROR ); } } # -------------------- # Check if the username is a valid username (does not account for uniqueness) # realname can match # Return true if it is, false otherwise function user_is_name_valid( $p_username ) { # The DB field is hard-coded. USERLEN should not be modified. if( strlen( $p_username ) > USERLEN ) { return false; } # username must consist of at least one character if( is_blank( $p_username ) ) { return false; } # Only allow a basic set of characters if( 0 == preg_match( config_get( 'user_login_valid_regex' ), $p_username ) ) { return false; } # We have a valid username return true; } # -------------------- # Check if the username is a valid username (does not account for uniqueness) # Trigger an error if the username is not valid function user_ensure_name_valid( $p_username ) { if( !user_is_name_valid( $p_username ) ) { trigger_error( ERROR_USER_NAME_INVALID, ERROR ); } } # -------------------- # return whether user is monitoring bug for the user id and bug id function user_is_monitoring_bug( $p_user_id, $p_bug_id ) { $c_user_id = db_prepare_int( $p_user_id ); $c_bug_id = db_prepare_int( $p_bug_id ); $t_bug_monitor_table = db_get_table( 'mantis_bug_monitor_table' ); $query = "SELECT COUNT(*) FROM $t_bug_monitor_table WHERE user_id=" . db_param() . " AND bug_id=" . db_param(); $result = db_query_bound( $query, Array( $c_user_id, $c_bug_id ) ); if( 0 == db_result( $result ) ) { return false; } else { return true; } } # -------------------- # return true if the user has access of ADMINISTRATOR or higher, false otherwise function user_is_administrator( $p_user_id ) { $t_access_level = user_get_field( $p_user_id, 'access_level' ); if( $t_access_level >= ADMINISTRATOR ) { return true; } else { return false; } } # -------------------- # return true is the user account is protected, false otherwise function user_is_protected( $p_user_id ) { if( ON == user_get_field( $p_user_id, 'protected' ) ) { return true; } else { return false; } } # -------------------- # Trigger an ERROR if the user account is protected function user_ensure_unprotected( $p_user_id ) { if( user_is_protected( $p_user_id ) ) { trigger_error( ERROR_PROTECTED_ACCOUNT, ERROR ); } } # -------------------- # return true is the user account is enabled, false otherwise function user_is_enabled( $p_user_id ) { if( ON == user_get_field( $p_user_id, 'enabled' ) ) { return true; } else { return false; } } # -------------------- # count the number of users at or greater than a specific level function user_count_level( $p_level = ANYBODY ) { $t_level = db_prepare_int( $p_level ); $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT COUNT(id) FROM $t_user_table WHERE access_level>=" . db_param(); $result = db_query_bound( $query, Array( $t_level ) ); # Get the list of connected users $t_users = db_result( $result ); return $t_users; } # -------------------- # Return an array of user ids that are logged in. # A user is considered logged in if the last visit timestamp is within the # specified session duration. # If the session duration is 0, then no users will be returned. function user_get_logged_in_user_ids( $p_session_duration_in_minutes ) { $t_session_duration_in_minutes = (integer) $p_session_duration_in_minutes; # if session duration is 0, then there is no logged in users. if( $t_session_duration_in_minutes == 0 ) { return array(); } # Generate timestamp # @@@ The following code may not be portable accross DBMS. $t_last_timestamp_threshold = mktime( date( "H" ), date( "i" ) - 1 * $t_session_duration_in_minutes, date( "s" ), date( "m" ), date( "d" ), date( "Y" ) ); $c_last_timestamp_threshold = date( "Y-m-d H:i:s", $t_last_timestamp_threshold ); $t_user_table = db_get_table( 'mantis_user_table' ); # Execute query $query = "SELECT id FROM $t_user_table WHERE last_visit > '$c_last_timestamp_threshold'"; $result = db_query( $query, 1 ); # Get the list of connected users $t_users_connected = array(); while( $row = db_fetch_array( $result ) ) { $t_users_connected[] = $row['id']; } return $t_users_connected; } # =================================== # Creation / Deletion / Updating # =================================== # -------------------- # Create a user. # returns false if error, the generated cookie string if ok function user_create( $p_username, $p_password, $p_email = '', $p_access_level = null, $p_protected = false, $p_enabled = true, $p_realname = '' ) { if( null === $p_access_level ) { $p_access_level = config_get( 'default_new_account_access_level' ); } $t_password = auth_process_plain_password( $p_password ); $c_username = db_prepare_string( $p_username ); $c_realname = db_prepare_string( $p_realname ); $c_password = db_prepare_string( $t_password ); $c_email = db_prepare_string( $p_email ); $c_access_level = db_prepare_int( $p_access_level ); $c_protected = db_prepare_bool( $p_protected ); $c_enabled = db_prepare_bool( $p_enabled ); user_ensure_name_valid( $p_username ); user_ensure_name_unique( $p_username ); user_ensure_realname_valid( $p_realname ); user_ensure_realname_unique( $p_username, $p_realname ); email_ensure_valid( $p_email ); $t_login_method = config_get( 'login_method' ); if ( $t_login_method == LDAP) { if ( !ldap_create_user( $p_username, $p_password, $p_realname, $p_email ) ) { return ''; } } $t_seed = $p_email . $p_username; $t_cookie_string = auth_generate_unique_cookie_string( $t_seed ); $t_user_table = db_get_table( 'mantis_user_table' ); $query = "INSERT INTO $t_user_table ( username, email, password, date_created, last_visit, enabled, access_level, login_count, cookie_string, realname ) VALUES ( " . db_param() . ", " . db_param() . ", " . db_param() . ", " . db_param() . ", " . db_param() . ", " . db_param() . "," . db_param() . "," . db_param() . "," . db_param() . ", " . db_param() . ")"; db_query_bound( $query, Array( $c_username, $c_email, $c_password, db_now(), db_now(), $c_enabled, $c_access_level, 0, $t_cookie_string, $c_realname ) ); # Create preferences for the user $t_user_id = db_insert_id( $t_user_table ); user_pref_set_default( $t_user_id ); # Users are added with protected set to FALSE in order to be able to update # preferences. Now set the real value of protected. if( $c_protected ) { user_set_field( $t_user_id, 'protected', 1 ); } # Send notification email if( !is_blank( $p_email ) ) { $t_confirm_hash = auth_generate_confirm_hash( $t_user_id ); email_signup( $t_user_id, $p_password, $t_confirm_hash ); } return $t_cookie_string; } # -------------------- # Signup a user. # If the use_ldap_email config option is on then tries to find email using # ldap. $p_email may be empty, but the user wont get any emails. # returns false if error, the generated cookie string if ok function user_signup( $p_username, $p_email = null ) { if( null === $p_email ) { $p_email = ''; # @@@ I think the ldap_email stuff is a bit borked # Where is it being set? When is it being used? # Shouldn't we override an email that is passed in here? # If the user doesn't exist in ldap, is the account created? # If so, there password won't get set anywhere... (etc) # RJF: I was going to check for the existence of an LDAP email. # however, since we can't create an LDAP account at the moment, # and we don't know the user password in advance, we may not be able # to retrieve it anyway. # I'll re-enable this once a plan has been properly formulated for LDAP # account management and creation. /* $t_email = ''; if ( ON == config_get( 'use_ldap_email' ) ) { $t_email = ldap_email_from_username( $p_username ); } if ( !is_blank( $t_email ) ) { $p_email = $t_email; } */ } $p_email = trim( $p_email ); $t_seed = $p_email . $p_username; # Create random password $t_password = auth_generate_random_password( $t_seed ); return user_create( $p_username, $t_password, $p_email ); } # -------------------- # delete project-specific user access levels. # returns true when successfully deleted function user_delete_project_specific_access_levels( $p_user_id ) { $c_user_id = db_prepare_int( $p_user_id ); user_ensure_unprotected( $p_user_id ); $t_project_user_list_table = db_get_table( 'mantis_project_user_list_table' ); $query = "DELETE FROM $t_project_user_list_table WHERE user_id=" . db_param(); db_query_bound( $query, Array( $c_user_id ) ); user_clear_cache( $p_user_id ); return true; } # -------------------- # delete profiles for the specified user # returns true when successfully deleted function user_delete_profiles( $p_user_id ) { $c_user_id = db_prepare_int( $p_user_id ); user_ensure_unprotected( $p_user_id ); $t_user_profile_table = db_get_table( 'mantis_user_profile_table' ); # Remove associated profiles $query = "DELETE FROM $t_user_profile_table WHERE user_id=" . db_param(); db_query_bound( $query, Array( $c_user_id ) ); user_clear_cache( $p_user_id ); return true; } # -------------------- # delete a user account (account, profiles, preferences, project-specific access levels) # returns true when the account was successfully deleted function user_delete( $p_user_id ) { $c_user_id = db_prepare_int( $p_user_id ); $t_user_table = db_get_table( 'mantis_user_table' ); user_ensure_unprotected( $p_user_id ); # Remove associated profiles user_delete_profiles( $p_user_id ); # Remove associated preferences user_pref_delete_all( $p_user_id ); # Remove project specific access levels user_delete_project_specific_access_levels( $p_user_id ); # unset non-unique realname flags if necessary if( config_get( 'differentiate_duplicates' ) ) { $c_realname = db_prepare_string( user_get_field( $p_user_id, 'realname' ) ); $query = "SELECT id FROM $t_user_table WHERE realname=" . db_param(); $result = db_query_bound( $query, Array( $c_realname ) ); $t_count = db_num_rows( $result ); if( $t_count == 2 ) { # unset flags if there are now only 2 unique names for( $i = 0;$i < $t_count;$i++ ) { $t_user_id = db_result( $result, $i ); user_set_field( $t_user_id, 'duplicate_realname', OFF ); } } } user_clear_cache( $p_user_id ); # Remove account $query = "DELETE FROM $t_user_table WHERE id=" . db_param(); db_query_bound( $query, Array( $c_user_id ) ); return true; } # =================================== # Data Access # =================================== # -------------------- # get a user id from a username # return false if the username does not exist function user_get_id_by_name( $p_username ) { global $g_cache_user; if( $t_user = user_search_cache( 'username', $p_username ) ) { return $t_user['id']; } $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT * FROM $t_user_table WHERE username=" . db_param(); $result = db_query_bound( $query, Array( $p_username ) ); if( 0 == db_num_rows( $result ) ) { return false; } else { $row = db_fetch_array( $result ); user_cache_database_result( $row ); return $row['id']; } } # Get a user id from an email address function user_get_id_by_email( $p_email ) { global $g_cache_user; if( $t_user = user_search_cache( 'email', $p_email ) ) { return $t_user['id']; } $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT * FROM $t_user_table WHERE email=" . db_param(); $result = db_query_bound( $query, Array( $p_email ) ); if( 0 == db_num_rows( $result ) ) { return false; } else { $row = db_fetch_array( $result ); user_cache_database_result( $row ); return $row['id']; } } # Get a user id from their real name function user_get_id_by_realname( $p_realname ) { global $g_cache_user; if( $t_user = user_search_cache( 'realname', $p_realname ) ) { return $t_user['id']; } $t_user_table = db_get_table( 'mantis_user_table' ); $query = "SELECT * FROM $t_user_table WHERE realname=" . db_param(); $result = db_query_bound( $query, Array( $p_realname ) ); if( 0 == db_num_rows( $result ) ) { return false; } else { $row = db_fetch_array( $result ); user_cache_database_result( $row ); return $row['id']; } } # -------------------- # return all data associated with a particular user name # return false if the username does not exist function user_get_row_by_name( $p_username ) { $t_user_id = user_get_id_by_name( $p_username ); if( false === $t_user_id ) { return false; } $row = user_get_row( $t_user_id ); return $row; } # -------------------- # return a user row function user_get_row( $p_user_id ) { return user_cache_row( $p_user_id ); } # -------------------- # return the specified user field for the user id function user_get_field( $p_user_id, $p_field_name ) { if( NO_USER == $p_user_id ) { trigger_error( 'user_get_field() for NO_USER', WARNING ); return "@null@"; } $row = user_get_row( $p_user_id ); if( isset( $row[$p_field_name] ) ) { return $row[$p_field_name]; } else { error_parameters( $p_field_name ); trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING ); return ''; } } # -------------------- # lookup the user's email in LDAP or the db as appropriate function user_get_email( $p_user_id ) { $t_email = ''; if( ON == config_get( 'use_ldap_email' ) ) { $t_email = ldap_email( $p_user_id ); } if( is_blank( $t_email ) ) { $t_email = user_get_field( $p_user_id, 'email' ); } return $t_email; } # -------------------- # lookup the user's realname function user_get_realname( $p_user_id ) { $t_realname = user_get_field( $p_user_id, 'realname' ); return $t_realname; } # -------------------- # return the username or a string "user<id>" if the user does not exist # if show_realname is set, replace the name with a realname (if set) function user_get_name( $p_user_id ) { $row = user_cache_row( $p_user_id, false ); if( false == $row ) { return lang_get( 'prefix_for_deleted_users' ) . (int) $p_user_id; } else { if( ON == config_get( 'show_realname' ) ) { if( is_blank( $row['realname'] ) ) { return $row['username']; } else { if( isset( $row['duplicate_realname'] ) && ( ON == $row['duplicate_realname'] ) ) { return $row['realname'] . ' (' . $row['username'] . ')'; } else { return $row['realname']; } } } else { return $row['username']; } } } /** * Return the user avatar image URL * in this first implementation, only gravatar.com avatars are supported * @return array|bool an array( URL, width, height ) or false when the given user has no avatar */ function user_get_avatar( $p_user_id, $p_size = 80 ) { $t_email = strtolower( user_get_email( $p_user_id ) ); if( is_blank( $t_email ) ) { $t_result = false; } else { $t_default_image = config_get( 'default_avatar' ); $t_size = $p_size; $t_use_ssl = false; if( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) != 'off' ) ) { $t_use_ssl = true; } if( !$t_use_ssl ) { $t_gravatar_domain = 'http://www.gravatar.com/'; } else { $t_gravatar_domain = 'https://secure.gravatar.com/'; } $t_avatar_url = $t_gravatar_domain . 'avatar.php?gravatar_id=' . md5( $t_email ) . '&default=' . urlencode( $t_default_image ) . '&size=' . $t_size . '&rating=G'; $t_result = array( $t_avatar_url, $t_size, $t_size, ); } return $t_result; } # -------------------- # return the user's access level # account for private project and the project user lists function user_get_access_level( $p_user_id, $p_project_id = ALL_PROJECTS ) { $t_access_level = user_get_field( $p_user_id, 'access_level' ); if( $t_access_level >= ADMINISTRATOR ) { return $t_access_level; } $t_project_access_level = project_get_local_user_access_level( $p_project_id, $p_user_id ); if( false === $t_project_access_level ) { return $t_access_level; } else { return $t_project_access_level; } } $g_user_accessible_projects_cache = null; # -------------------- # retun an array of project IDs to which the user has access function user_get_accessible_projects( $p_user_id, $p_show_disabled = false ) { global $g_user_accessible_projects_cache; if( null !== $g_user_accessible_projects_cache && auth_get_current_user_id() == $p_user_id && false == $p_show_disabled ) { return $g_user_accessible_projects_cache; } if( access_has_global_level( config_get( 'private_project_threshold' ), $p_user_id ) ) { $t_projects = project_hierarchy_get_subprojects( ALL_PROJECTS, $p_show_disabled ); } else { $t_project_table = db_get_table( 'mantis_project_table' ); $t_project_user_list_table = db_get_table( 'mantis_project_user_list_table' ); $t_project_hierarchy_table = db_get_table( 'mantis_project_hierarchy_table' ); $t_public = VS_PUBLIC; $t_private = VS_PRIVATE; $result = null; if( $p_show_disabled ) { $query = "SELECT p.id, p.name, ph.parent_id FROM $t_project_table p LEFT JOIN $t_project_user_list_table u ON p.id=u.project_id AND u.user_id=" . db_param() . " LEFT JOIN $t_project_hierarchy_table ph ON ph.child_id = p.id WHERE ( p.view_state=" . db_param() . " OR (p.view_state=" . db_param() . " AND u.user_id=" . db_param() . " ) ) ORDER BY p.name"; $result = db_query_bound( $query, Array( $p_user_id, $t_public, $t_private, $p_user_id ) ); } else { $query = "SELECT p.id, p.name, ph.parent_id FROM $t_project_table p LEFT JOIN $t_project_user_list_table u ON p.id=u.project_id AND u.user_id=" . db_param() . " LEFT JOIN $t_project_hierarchy_table ph ON ph.child_id = p.id WHERE p.enabled = " . db_param() . " AND ( p.view_state=" . db_param() . " OR (p.view_state=" . db_param() . " AND u.user_id=" . db_param() . " ) ) ORDER BY p.name"; $result = db_query_bound( $query, Array( $p_user_id, true, $t_public, $t_private, $p_user_id ) ); } $row_count = db_num_rows( $result ); $t_projects = array(); for( $i = 0;$i < $row_count;$i++ ) { $row = db_fetch_array( $result ); $t_projects[$row['id']] = ( $row['parent_id'] === NULL ) ? 0 : $row['parent_id']; } # prune out children where the parents are already listed. Make the list # first, then prune to avoid pruning a parent before the child is found. $t_prune = array(); foreach( $t_projects as $t_id => $t_parent ) { if(( $t_parent !== 0 ) && isset( $t_projects[$t_parent] ) ) { $t_prune[] = $t_id; } } foreach( $t_prune as $t_id ) { unset( $t_projects[$t_id] ); } $t_projects = array_keys( $t_projects ); } if( auth_get_current_user_id() == $p_user_id ) { $g_user_accessible_projects_cache = $t_projects; } return $t_projects; } $g_user_accessible_subprojects_cache = null; # -------------------- # retun an array of subproject IDs of a certain project to which the user has access function user_get_accessible_subprojects( $p_user_id, $p_project_id, $p_show_disabled = false ) { global $g_user_accessible_subprojects_cache; if( null !== $g_user_accessible_subprojects_cache && auth_get_current_user_id() == $p_user_id && false == $p_show_disabled ) { if( isset( $g_user_accessible_subprojects_cache[$p_project_id] ) ) { return $g_user_accessible_subprojects_cache[$p_project_id]; } else { return Array(); } } $t_project_table = db_get_table( 'mantis_project_table' ); $t_project_user_list_table = db_get_table( 'mantis_project_user_list_table' ); $t_project_hierarchy_table = db_get_table( 'mantis_project_hierarchy_table' ); $t_public = VS_PUBLIC; $t_private = VS_PRIVATE; if( access_has_global_level( config_get( 'private_project_threshold' ), $p_user_id ) ) { $t_enabled_clause = $p_show_disabled ? '' : 'p.enabled = ' . db_param() . ' AND'; $query = "SELECT DISTINCT p.id, p.name, ph.parent_id FROM $t_project_table p LEFT JOIN $t_project_hierarchy_table ph ON ph.child_id = p.id WHERE $t_enabled_clause ph.parent_id IS NOT NULL ORDER BY p.name"; $result = db_query_bound( $query, ( $p_show_disabled ? null : Array( true ) ) ); } else { $p = 0; $query = "SELECT DISTINCT p.id, p.name, ph.parent_id FROM $t_project_table p LEFT JOIN $t_project_user_list_table u ON p.id = u.project_id AND u.user_id=" . db_param( $p++ ) . " LEFT JOIN $t_project_hierarchy_table ph ON ph.child_id = p.id WHERE " . ( $p_show_disabled ? '' : ( 'p.enabled = ' . db_param( $p++ ) . ' AND ' ) ) . ' ph.parent_id IS NOT NULL AND ( p.view_state=' . db_param( $p++ ) . ' OR (p.view_state=' . db_param( $p++ ) . ' AND u.user_id=' . db_param( $p++ ) . ' ) ) ORDER BY p.name'; $result = db_query_bound( $query, ( $p_show_disabled ? Array( $p_user_id, $t_public, $t_private, $p_user_id ) : Array( $p_user_id, 1, $t_public, $t_private, $p_user_id ) ) ); } $row_count = db_num_rows( $result ); $t_projects = array(); for( $i = 0;$i < $row_count;$i++ ) { $row = db_fetch_array( $result ); if( !isset( $t_projects[$row['parent_id']] ) ) { $t_projects[$row['parent_id']] = array(); } array_push( $t_projects[$row['parent_id']], $row['id'] ); } if( auth_get_current_user_id() == $p_user_id ) { $g_user_accessible_subprojects_cache = $t_projects; } if( !isset( $t_projects[$p_project_id] ) ) { $t_projects[$p_project_id] = array(); } return $t_projects[$p_project_id]; } # -------------------- function user_get_all_accessible_subprojects( $p_user_id, $p_project_id ) { # @@@ (thraxisp) Should all top level projects be a sub-project of ALL_PROJECTS implicitly? # affects how news and some summaries are generated $t_todo = user_get_accessible_subprojects( $p_user_id, $p_project_id ); $t_subprojects = Array(); while( $t_todo ) { $t_elem = array_shift( $t_todo ); if( !in_array( $t_elem, $t_subprojects ) ) { array_push( $t_subprojects, $t_elem ); $t_todo = array_merge( $t_todo, user_get_accessible_subprojects( $p_user_id, $t_elem ) ); } } return $t_subprojects; } # -------------------- # return the number of open assigned bugs to a user in a project function user_get_assigned_open_bug_count( $p_user_id, $p_project_id = ALL_PROJECTS ) { $t_bug_table = db_get_table( 'mantis_bug_table' ); $t_where_prj = helper_project_specific_where( $p_project_id, $p_user_id ) . " AND"; $t_resolved = config_get( 'bug_resolved_status_threshold' ); $query = "SELECT COUNT(*) FROM $t_bug_table WHERE $t_where_prj status<'$t_resolved' AND handler_id=" . db_param(); $result = db_query_bound( $query, Array( $p_user_id ) ); return db_result( $result ); } # -------------------- # return the number of open reported bugs by a user in a project function user_get_reported_open_bug_count( $p_user_id, $p_project_id = ALL_PROJECTS ) { $t_bug_table = db_get_table( 'mantis_bug_table' ); $t_where_prj = helper_project_specific_where( $p_project_id, $p_user_id ) . " AND"; $t_resolved = config_get( 'bug_resolved_status_threshold' ); $query = "SELECT COUNT(*) FROM $t_bug_table WHERE $t_where_prj status<'$t_resolved' AND reporter_id=" . db_param(); $result = db_query_bound( $query, Array( $p_user_id ) ); return db_result( $result ); } # -------------------- # return a profile row function user_get_profile_row( $p_user_id, $p_profile_id ) { $c_user_id = db_prepare_int( $p_user_id ); $c_profile_id = db_prepare_int( $p_profile_id ); $t_user_profile_table = db_get_table( 'mantis_user_profile_table' ); $query = "SELECT * FROM $t_user_profile_table WHERE id=" . db_param() . " AND user_id=" . db_param(); $result = db_query_bound( $query, Array( $c_profile_id, $c_user_id ) ); if( 0 == db_num_rows( $result ) ) { trigger_error( ERROR_USER_PROFILE_NOT_FOUND, ERROR ); } $row = db_fetch_array( $result ); return $row; } # -------------------- # Get failed login attempts function user_is_login_request_allowed( $p_user_id ) { $t_max_failed_login_count = config_get( 'max_failed_login_count' ); $t_failed_login_count = user_get_field( $p_user_id, 'failed_login_count' ); return( $t_failed_login_count < $t_max_failed_login_count || OFF == $t_max_failed_login_count ); } # -------------------- # Get 'lost password' in progress attempts function user_is_lost_password_request_allowed( $p_user_id ) { if( OFF == config_get( 'lost_password_feature' ) ) { return false; } $t_max_lost_password_in_progress_count = config_get( 'max_lost_password_in_progress_count' ); $t_lost_password_in_progress_count = user_get_field( $p_user_id, 'lost_password_request_count' ); return( $t_lost_password_in_progress_count < $t_max_lost_password_in_progress_count || OFF == $t_max_lost_password_in_progress_count ); } # -------------------- # return the bug filter parameters for the specified user function user_get_bug_filter( $p_user_id, $p_project_id = null ) { if( null === $p_project_id ) { $t_project_id = helper_get_current_project(); } else { $t_project_id = $p_project_id; } $t_view_all_cookie_id = filter_db_get_project_current( $t_project_id, $p_user_id ); $t_view_all_cookie = filter_db_get_filter( $t_view_all_cookie_id, $p_user_id ); $t_cookie_detail = explode( '#', $t_view_all_cookie, 2 ); if( !isset( $t_cookie_detail[1] ) ) { return false; } $t_filter = unserialize( $t_cookie_detail[1] ); $t_filter = filter_ensure_valid_filter( $t_filter ); return $t_filter; } # =================================== # Data Modification # =================================== # -------------------- # Update the last_visited field to be now function user_update_last_visit( $p_user_id ) { $c_user_id = db_prepare_int( $p_user_id ); $c_value = db_now(); $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET last_visit= " . db_param() . " WHERE id=" . db_param(); db_query_bound( $query, Array( $c_value, $c_user_id ) ); user_update_cache( $p_user_id, 'last_visit', $c_value ); # db_query errors on failure so: return true; } # -------------------- # Increment the number of times the user has logegd in # This function is only called from the login.php script function user_increment_login_count( $p_user_id ) { $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET login_count=login_count+1 WHERE id=" . db_param(); db_query_bound( $query, Array( $p_user_id ) ); user_clear_cache( $p_user_id ); # db_query errors on failure so: return true; } # -------------------- # Reset to zero the failed login attempts function user_reset_failed_login_count_to_zero( $p_user_id ) { $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET failed_login_count=0 WHERE id=" . db_param(); db_query_bound( $query, Array( $p_user_id ) ); user_clear_cache( $p_user_id ); return true; } # -------------------- # Increment the failed login count by 1 function user_increment_failed_login_count( $p_user_id ) { $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET failed_login_count=failed_login_count+1 WHERE id=" . db_param(); db_query_bound( $query, Array( $p_user_id ) ); user_clear_cache( $p_user_id ); return true; } # -------------------- # Reset to zero the 'lost password' in progress attempts function user_reset_lost_password_in_progress_count_to_zero( $p_user_id ) { $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET lost_password_request_count=0 WHERE id=" . db_param(); db_query_bound( $query, Array( $p_user_id ) ); user_clear_cache( $p_user_id ); return true; } # -------------------- # Increment the failed login count by 1 function user_increment_lost_password_in_progress_count( $p_user_id ) { $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET lost_password_request_count=lost_password_request_count+1 WHERE id=" . db_param(); db_query_bound( $query, Array( $p_user_id ) ); user_clear_cache( $p_user_id ); return true; } # -------------------- # Set a user field function user_set_field( $p_user_id, $p_field_name, $p_field_value ) { $c_user_id = db_prepare_int( $p_user_id ); $c_field_name = db_prepare_string( $p_field_name ); $c_field_value = db_prepare_string( $p_field_value ); if( $p_field_name != "protected" ) { user_ensure_unprotected( $p_user_id ); } $t_user_table = db_get_table( 'mantis_user_table' ); $query = "UPDATE $t_user_table SET $c_field_name=" . db_param() . " WHERE id=" . db_param(); db_query_bound( $query, Array( $c_field_value, $c_user_id ) ); user_clear_cache( $p_user_id ); # db_query errors on failure so: return true; } # -------------------- # Set the user's default project function user_set_default_project( $p_user_id, $p_project_id ) { return user_pref_set_pref( $p_user_id, 'default_project', (int) $p_project_id ); } # -------------------- # Set the user's password to the given string, encoded as appropriate function user_set_password( $p_user_id, $p_password, $p_allow_protected = false ) { if( !$p_allow_protected ) { user_ensure_unprotected( $p_user_id ); } $t_email = user_get_field( $p_user_id, 'email' ); $t_username = user_get_field( $p_user_id, 'username' ); # When the password is changed, invalidate the cookie to expire sessions that # may be active on all browsers. $t_seed = $t_email . $t_username; $c_cookie_string = auth_generate_unique_cookie_string( $t_seed ); $c_user_id = db_prepare_int( $p_user_id ); $c_password = auth_process_plain_password( $p_password ); $c_user_table = db_get_table( 'mantis_user_table' ); $t_login_method = config_get( 'login_method' ); if ( $t_login_method == LDAP) { if ( !ldap_passwd( $p_username, $p_password ) ) { return false; } } $query = "UPDATE $c_user_table SET password=" . db_param() . ", cookie_string=" . db_param() . " WHERE id=" . db_param(); db_query_bound( $query, Array( $c_password, $c_cookie_string, $c_user_id ) ); # db_query errors on failure so: return true; } # -------------------- # Set the user's email to the given string after checking that it is a valid email function user_set_email( $p_user_id, $p_email ) { email_ensure_valid( $p_email ); return user_set_field( $p_user_id, 'email', $p_email ); } # -------------------- # Set the user's realname to the given string after checking validity function user_set_realname( $p_user_id, $p_realname ) { # @@@ TODO: ensure_realname_valid( $p_realname ); return user_set_field( $p_user_id, 'realname', $p_realname ); } # -------------------- # Set the user's username to the given string after checking that it is valid function user_set_name( $p_user_id, $p_username ) { user_ensure_name_valid( $p_username ); user_ensure_name_unique( $p_username ); return user_set_field( $p_user_id, 'username', $p_username ); } # -------------------- # Reset the user's password # Take into account the 'send_reset_password' setting # - if it is ON, generate a random password and send an email # (unless the second parameter is false) # - if it is OFF, set the password to blank # Return false if the user is protected, true if the password was # successfully reset function user_reset_password( $p_user_id, $p_send_email = true ) { $t_protected = user_get_field( $p_user_id, 'protected' ); # Go with random password and email it to the user if( ON == $t_protected ) { return false; } # @@@ do we want to force blank password instead of random if # email notifications are turned off? # How would we indicate that we had done this with a return value? # Should we just have two functions? (user_reset_password_random() # and user_reset_password() )? if(( ON == config_get( 'send_reset_password' ) ) && ( ON == config_get( 'enable_email_notification' ) ) ) { # Create random password $t_email = user_get_field( $p_user_id, 'email' ); $t_password = auth_generate_random_password( $t_email ); $t_password2 = auth_process_plain_password( $t_password ); user_set_field( $p_user_id, 'password', $t_password2 ); # Send notification email if( $p_send_email ) { $t_confirm_hash = auth_generate_confirm_hash( $p_user_id ); email_send_confirm_hash_url( $p_user_id, $t_confirm_hash ); } } else { # use blank password, no emailing $t_password = auth_process_plain_password( '' ); user_set_field( $p_user_id, 'password', $t_password ); # reset the failed login count because in this mode there is no emailing user_reset_failed_login_count_to_zero( $p_user_id ); } return true; } | ||||
Files attached: mantisbt-20081208.patch |
|
rgomes, i'll take a look at this tomorrow morning. |
|
When I rolled out to Mantis 1.2.4 I've decided to centralize user maintenance on a separate web application. Now Mantis only consumes data from LDAP and performs authentication. No need anymore to create users in the backing store. See module 'selfregister', part of simpleSAMLphp Thanks |
|
What is the status of this? I suspect it predates the LDAP/AD support that's already in Mantis at this point? |
|
I don't think this belongs in MantisBT core. If such functionality is needed, it should be implemented as an authentication plugin. |
|