Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-9016

Git creates usernames based on 'name' not the email.

    • Icon: Improvement Improvement
    • Resolution: Unresolved
    • Icon: Major Major
    • git-plugin
    • git plugin 1.1.6
      git plugin 2.0, jenkins 1.540, ubuntu 13.10

      I realize mapping git author/commit users back to Jenkin's users is pain, but perhaps it could be done a little better.

      Some ideas:

      • Try looking up a user's email and comparing that.
      • Using the user portion from the email (e.g. someuser@example.com becomes someuser).
      • Looking up the user's email in LDAP, if LDAP is being used.

      The last would be ideal for us.

      Ciao!

          [JENKINS-9016] Git creates usernames based on 'name' not the email.

          Can't the e-mail address(es) in the commit message be used to find Jenkins security realm users?

          The e-mail address in my commit messages is the same as the e-mail address associated with my Jenkins account.  Why can those not be matched up?

          Brian J Murrell added a comment - Can't the e-mail address(es) in the commit message be used to find Jenkins security realm users? The e-mail address in my commit messages is the same as the e-mail address associated with my Jenkins account.  Why can those not be matched up?

          I agree with everyone else here. We just started converting from old jobs to Pipeline jobs and are now faced with issues surrounding user mapping. I'll admit, it's probably more due to the fact we updated our 3 years old Jenkins instance.

          The unique identifier IS the email address. This is what should be used for mapping with registered Jenkins user. As many others, our company use shorthand names for login in AD, yet in Git all our users configure their full name. This is a common practice in the corporate world at it makes it easy to login everywhere with a shorter name. In my case it's even a lifesaver.
          Imagine if I had to type "Jeremie.Faucher-Goulet" every time I log in somewhere, instead of the much easier "jfaucher" I use against AD in all login forms everywhere.

          Even Fisheye+Crucible from Atlassian is able to do proper mapping between AD and git committer based on emails.

          I feel this is really needed, as I don't like disabling the security check against registered Jenkins users.... We did have in the past a few cases of embarrassing leaked emails from Jenkins because we compile 3rd party applications and committers outside the organization appeared as the culprits in some failed builds. Until Jenkins does proper user mapping based on email we are vulnerable to this issue because we are forced to disable the security feature in the meantime.

          Jérémie Faucher-Goulet added a comment - I agree with everyone else here. We just started converting from old jobs to Pipeline jobs and are now faced with issues surrounding user mapping. I'll admit, it's probably more due to the fact we updated our 3 years old Jenkins instance. The unique identifier IS the email address. This is what should be used for mapping with registered Jenkins user. As many others, our company use shorthand names for login in AD, yet in Git all our users configure their full name. This is a common practice in the corporate world at it makes it easy to login everywhere with a shorter name. In my case it's even a lifesaver. Imagine if I had to type "Jeremie.Faucher-Goulet" every time I log in somewhere, instead of the much easier "jfaucher" I use against AD in all login forms everywhere. Even Fisheye+Crucible from Atlassian is able to do proper mapping between AD and git committer based on emails. I feel this is really needed, as I don't like disabling the security check against registered Jenkins users.... We did have in the past a few cases of embarrassing leaked emails from Jenkins because we compile 3rd party applications and committers outside the organization appeared as the culprits in some failed builds. Until Jenkins does proper user mapping based on email we are vulnerable to this issue because we are forced to disable the security feature in the meantime.

          I was just hit by the same issue. E-mail should be compared against e-mail field, not processed and compared against some different field. Or at least please give an option to choose the behaviour.

          Bartosz Błaszkiewicz added a comment - I was just hit by the same issue. E-mail should be compared against e-mail field, not processed and compared against some different field. Or at least please give an option to choose the behaviour.

          Hopefully this bumps this thread. I am in the exact same spot as jeremfg.
          Since this ticket looks like its stuck in limbo, did anyone find any solution to this?

          Matjaž Matjašec added a comment - Hopefully this bumps this thread. I am in the exact same spot as jeremfg . Since this ticket looks like its stuck in limbo, did anyone find any solution to this?

          Uv Wild added a comment - - edited

          BUMP TOO

          we have 6 companies working on the machine.
          You wont believe what funny names show up in the commiter list of asynchPeople.

          This is ABSOLUTELY not an option for a secure environment.  

          The aysncList we see there is neither injective and can be used to identify, nor is it surjective and I can be sure that my git server will contain the entry as this is the job of the gitserver which might not keep all the user.name 's used by its users over time.

          This is REALLY WRONG!!!

          Uv Wild added a comment - - edited BUMP TOO we have 6 companies working on the machine. You wont believe what funny names show up in the commiter list of asynchPeople. This is ABSOLUTELY not an option for a secure environment.   The aysncList we see there is neither injective and can be used to identify, nor is it surjective and I can be sure that my git server will contain the entry as this is the job of the gitserver which might not keep all the user.name 's used by its users over time. This is REALLY WRONG!!!

          Ben Spoor added a comment -

          🙄 facing the same issues as described above

           

           

           

          Ben Spoor added a comment - 🙄 facing the same issues as described above      

          Ben Spoor added a comment -

          As a workaround I've used the field "Allowed Domains" of the email-ext plugin.

          Ben Spoor added a comment - As a workaround I've used the field "Allowed Domains" of the email-ext plugin.

          R. Fitzner added a comment - - edited

          The first time I run into the issue
          "Not sending mail to unregistered user abc@xyz.com because your SCM claimed this was associated with a user ID `` which your security realm does not recognize; you may need changes in your SCM plugin."
          (see https://docs.cloudbees.com/docs/cloudbees-ci-kb/latest/client-and-managed-masters/not-sending-mail-to-unregistered-user-associated-with-scm)
          was all developers had to change their email address to a new domain.
          Even after telling them to update the email address in their Jenkins account, it did not really fix the issue for all developers.

          After checking the source code https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java
          and doing some tests according to the source code, I came to the following results:

           

          Jenkins always creates new Jenkins user accounts nevertheless if "Create new accounts based on author/committer's email?" is checked:

          https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L468

             user = getUser(csAuthorEmail, true);
          }
          if (user != null && setUserDetails) {
             user.setFullName(csAuthor);
          

          ... or not checked:

          https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L502

          user = getUser(emailParts[0], true);
          

           

          Use case A:

          At the beginning the Jenkins server was running with "Create new accounts based on author/committer's email?" false.
          The result is that some developers have got 2 Jenkins accounts now:

          UserID 1: "firstname.lastname" (auto-created account by GitChangeSet)
          UserID 2: "lastname" ("lastname" is in my company the user name for the Jenkins login and matches the LDAP account and is dependent on your company's policy)

          I guess this happens when a developer logs into Jenkins after pushing his/her first commit.

           

          Use case B:

          Later all developers have updated their email address for UserID 2, but not in UserID 1. Which fixed the issue for some developers,
          but not for all because:

          https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L488

          user = getUser(csAuthor, false);
          

          is looking for the ID or FullName of all Jenkins accounts that matches the extracted "user.name" of the author commit
          (e.g. "Firstname LASTNAME <firstname.lastname@mycompany.com>" -> "user.name" = "Firstname LASTNAME").
          and this comparison is case sensitive!
          One little typo and the account "does not exist" although it exists and then a new account will be created with "firstname.lastname" (as ID and Full Name)!

          You can test it via "Script Console" in Jenkins, e.g. like this:

          def u = User.get('lastname', false, Collections.emptyMap()) // my company LDAP ID
          //def u = User.get('Firstname LASTNAME', false, Collections.emptyMap()) // Full Name of my authorized LDAP Jenkins account (CASE-SENSITIVE!)
          //def u = User.get('firstname.lastname', false, Collections.emptyMap()) // auto-created account from initial pushed commit
          return "id = " + u.getId() + ", FullName = " + u.getFullName() + ", no. of authorities = " + u.getAuthorities()?.size()
          

          Lets assume there is a little typo between Jenkins account FullName and author commit
          (which is a quite common practice in developers life because "git config user.name" is not always set correctly for all dev-tools and environments) then this line will be used:
          https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L499

          String[] emailParts = csAuthorEmail.split("@");
          if (emailParts.length > 0) {
             try {
                user = getUser(emailParts[0], true);
          

          And this is for my company (LDAP policy) always the UN-authorized Jenkins User Account!

           

          Improvement B.1)
          In my opinion to improve here the functionality of enabling/disabling "auto-create user account" should be implemented.
          From a security point of view this ends up in the same situation:
             no account -> no email will be send
             no authorized account -> no email will be send

          Improvement B.2)
          Another improvement could be that

             user = getUser(csAuthor, false);
          

          is looking for matching Full Names but with case-insensitivity.

          Improvement B.3)
          Another improvement could be (if auto-creating is enabled):

             // check 
             user = getUser(emailParts[0], false);
             // if not then create
             user = getUser(emailParts[0], true);
             // and update the user with the extracted user.name and user.email of the author commit:
             user.setFullName(csAuthor);
             setMail(user, csAuthorEmail);
          

          OR in respect of this ticket here instead of creating "firstname.lastname" let's take the extracted author name:

             // check and if not then create
             user = getUser(csAuthor, true);
             // and update the user with the extracted user.email of the author commit:
             setMail(user, csAuthorEmail);
          

          Improvement B.4)
          If
             "Create new accounts based on author/committer's email?" false
             "Use existing account with same email if found?" true
          then before Improvement suggestion B.3 search for accounts with the same email address.
          The code here https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L458 and ff. can be re-used.

           

          Use case C:

          Later my company changed the LDAP policy (1-to-n characters of the firstname plus lastname) and now things got really bad.
          So I changed the Jenkins server setting to:
             "Create new accounts based on author/committer's email?" true
             "Use existing account with same email if found?" true
          because I read it might fix the issue. But in real life for some developers it doesn't work either.

          And the reason is there is a loop in the source code:

          https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L459

          for(User existingUser : User.getAll()) {
             if (csAuthorEmail.equalsIgnoreCase(getMail(existingUser))) {
                 user = existingUser;
                 setUserDetails = false;
                 break; // this line is a real problem
              }
          }
          

          and it stops searching as soon as it got the first UserID with the matching email address.

          In real life some developers have got 3 Jenkins accounts now:

             user.name = "Firstname LASTNAME"
             user.email = "firstname.lastname@mycompany.com"
             author commit = "Firstname LASTNAME <firstname.lastname@mycompany.com>"
             LDAP/AD = "lastname"
             
             UserID 1: "firstname.lastname" (from use case A or use case B)
             UserID 2: "firstname.lastname@mycompany.com" (from use case B)
             UserID 3: "lastname" (authorized by LDAP)

          Well, UserID 1 and 2 are both smaller than UserID 3 ("firstname.lastname" < ""firstname.lastname@mycompany.com"" < "lastname")
          and that's why for some users the UN-authorized UserID 1 or 2 are always taken and not the authorized account UserID 3.

          You can test it via "Script Console" in Jenkins, e.g. like this:

          def u = []
          for (User existingUser : User.getAll()) {
            if ('firstname.lastname@mycompany.com'.equalsIgnoreCase(existingUser.getProperty(hudson.tasks.Mailer.UserProperty.class).getExplicitlyConfiguredAddress())) {
               u += existingUser.getId() + " : " + existingUser.getFullName() + " (" + existingUser.getAuthorities().size() + ")"
               //break // this line is a real problem
             }
          }
          return u
          

           

          Improvement C.1)

          So a quick bug fix (see line 460) could look like this:

          for(User existingUser : User.getAll()) {
             if (csAuthorEmail.equalsIgnoreCase(getMail(existingUser)) && existingUser.getAuthorities().size() > 0) { // line 460
                 user = existingUser;
                 setUserDetails = false;
                 break;
              }
          }
          

           

          Summary:

          As long as the source code is not improved and you don't want to check "Allow sending to unregistered users" then the only workaround is:

          Either my company adapts the LDAP policy to the Jenkins logic:

          firstname.lastname@mycompany.com
          or
          firstname.lastname

          OR

          to disable "Create new accounts based on author/committer's email?" and tell a developers:

          log into Jenkins and make sure that:

          git user.name = jenkins.fullname (CASE-SENSITIVE!)
          git user.email = jenkins.email

          R. Fitzner added a comment - - edited The first time I run into the issue "Not sending mail to unregistered user abc@xyz.com because your SCM claimed this was associated with a user ID `` which your security realm does not recognize; you may need changes in your SCM plugin." (see https://docs.cloudbees.com/docs/cloudbees-ci-kb/latest/client-and-managed-masters/not-sending-mail-to-unregistered-user-associated-with-scm ) was all developers had to change their email address to a new domain. Even after telling them to update the email address in their Jenkins account, it did not really fix the issue for all developers. After checking the source code https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java and doing some tests according to the source code, I came to the following results:   Jenkins always creates new Jenkins user accounts nevertheless if "Create new accounts based on author/committer's email?" is checked: https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L468    user = getUser(csAuthorEmail, true ); } if (user != null && setUserDetails) {    user.setFullName(csAuthor); ... or not checked: https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L502 user = getUser(emailParts[0], true );   Use case A: At the beginning the Jenkins server was running with "Create new accounts based on author/committer's email?" false. The result is that some developers have got 2 Jenkins accounts now: UserID 1: "firstname.lastname" (auto-created account by GitChangeSet) UserID 2: "lastname" ("lastname" is in my company the user name for the Jenkins login and matches the LDAP account and is dependent on your company's policy) I guess this happens when a developer logs into Jenkins after pushing his/her first commit.   Use case B: Later all developers have updated their email address for UserID 2, but not in UserID 1. Which fixed the issue for some developers, but not for all because: https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L488 user = getUser(csAuthor, false ); is looking for the ID or FullName of all Jenkins accounts that matches the extracted "user.name" of the author commit (e.g. "Firstname LASTNAME <firstname.lastname@mycompany.com>" -> "user.name" = "Firstname LASTNAME"). and this comparison is case sensitive! One little typo and the account "does not exist" although it exists and then a new account will be created with "firstname.lastname" (as ID and Full Name)! You can test it via "Script Console" in Jenkins, e.g. like this: def u = User.get( 'lastname' , false , Collections.emptyMap()) // my company LDAP ID //def u = User.get( 'Firstname LASTNAME' , false , Collections.emptyMap()) // Full Name of my authorized LDAP Jenkins account (CASE-SENSITIVE!) //def u = User.get( 'firstname.lastname' , false , Collections.emptyMap()) // auto-created account from initial pushed commit return "id = " + u.getId() + ", FullName = " + u.getFullName() + ", no. of authorities = " + u.getAuthorities()?.size() Lets assume there is a little typo between Jenkins account FullName and author commit (which is a quite common practice in developers life because "git config user.name" is not always set correctly for all dev-tools and environments) then this line will be used: https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L499 String [] emailParts = csAuthorEmail.split( "@" ); if (emailParts.length > 0) {     try {       user = getUser(emailParts[0], true ); And this is for my company (LDAP policy) always the UN-authorized Jenkins User Account!   Improvement B.1) In my opinion to improve here the functionality of enabling/disabling "auto-create user account" should be implemented. From a security point of view this ends up in the same situation:    no account -> no email will be send    no authorized account -> no email will be send Improvement B.2) Another improvement could be that    user = getUser(csAuthor, false ); is looking for matching Full Names but with case-insensitivity. Improvement B.3) Another improvement could be (if auto-creating is enabled):     // check     user = getUser(emailParts[0], false );     // if not then create    user = getUser(emailParts[0], true );     // and update the user with the extracted user.name and user.email of the author commit:    user.setFullName(csAuthor);    setMail(user, csAuthorEmail); OR in respect of this ticket here instead of creating "firstname.lastname" let's take the extracted author name:     // check and if not then create    user = getUser(csAuthor, true );     // and update the user with the extracted user.email of the author commit:    setMail(user, csAuthorEmail); Improvement B.4) If    "Create new accounts based on author/committer's email?" false    "Use existing account with same email if found?" true then before Improvement suggestion B.3 search for accounts with the same email address. The code here https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L458 and ff. can be re-used.   Use case C: Later my company changed the LDAP policy (1-to-n characters of the firstname plus lastname) and now things got really bad. So I changed the Jenkins server setting to:    "Create new accounts based on author/committer's email?" true    "Use existing account with same email if found?" true because I read it might fix the issue. But in real life for some developers it doesn't work either. And the reason is there is a loop in the source code: https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L459 for (User existingUser : User.getAll()) {     if (csAuthorEmail.equalsIgnoreCase(getMail(existingUser))) {       user = existingUser;       setUserDetails = false ;       break ; // this line is a real problem    } } and it stops searching as soon as it got the first UserID with the matching email address. In real life some developers have got 3 Jenkins accounts now:    user.name = "Firstname LASTNAME"    user.email = "firstname.lastname@mycompany.com"    author commit = "Firstname LASTNAME <firstname.lastname@mycompany.com>"    LDAP/AD = "lastname"        UserID 1: "firstname.lastname" (from use case A or use case B)    UserID 2: "firstname.lastname@mycompany.com" (from use case B)    UserID 3: "lastname" (authorized by LDAP) Well, UserID 1 and 2 are both smaller than UserID 3 ("firstname.lastname" < ""firstname.lastname@mycompany.com"" < "lastname") and that's why for some users the UN-authorized UserID 1 or 2 are always taken and not the authorized account UserID 3. You can test it via "Script Console" in Jenkins, e.g. like this: def u = [] for (User existingUser : User.getAll()) {   if ( 'firstname.lastname@mycompany.com' .equalsIgnoreCase(existingUser.getProperty(hudson.tasks.Mailer.UserProperty.class).getExplicitlyConfiguredAddress())) {     u += existingUser.getId() + " : " + existingUser.getFullName() + " (" + existingUser.getAuthorities().size() + ")"     // break // this line is a real problem   } } return u   Improvement C.1) So a quick bug fix (see line 460) could look like this: for (User existingUser : User.getAll()) {     if (csAuthorEmail.equalsIgnoreCase(getMail(existingUser)) && existingUser.getAuthorities().size() > 0) { // line 460       user = existingUser;       setUserDetails = false ;       break ;    } }   Summary: As long as the source code is not improved and you don't want to check "Allow sending to unregistered users" then the only workaround is: Either my company adapts the LDAP policy to the Jenkins logic: firstname.lastname@mycompany.com or firstname.lastname OR to disable "Create new accounts based on author/committer's email?" and tell a developers: log into Jenkins and make sure that: git user.name = jenkins.fullname (CASE-SENSITIVE!) git user.email = jenkins.email

          R. Fitzner added a comment -

          UPDATE:

          My own Improvement suggestion B.3 will also not work and the reason is:

          def u = User.get('Firstname LASTNAME', false, Collections.emptyMap())

          always returns the first UserID if all 2 or 3 Jenkins accounts have the same Full Name 'Firstname LASTNAME':

          UserID 1: "firstname.lastname" (fullName "Firstname LASTNAME", I changed it afterwards as admin just for testing)
          UserID 2: "firstname.lastname@mycompany.com" (fullName "Firstname LASTNAME" extracted user.name and set by auto-create)
          UserID 3: "lastname" (fullName "Firstname LASTNAME" set by developer)

          So auto-creating a new user and extracting the user.name and updating it as FullName
          https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L471

          is also not good if you want to use:

          user = getUser(csAuthor, false);

          later (after disabling "Create new accounts based on author/committer's email").

          So Improvement suggestion B.1 enabling/disabling "auto-create user account" and cleaning-up UN-authorized Jenkins accounts later seems to me the only working solution here, unless deeper Jenkins core and/or LDAP plugin improvements will be provided here by experts.

          R. Fitzner added a comment - UPDATE: My own Improvement suggestion B.3 will also not work and the reason is: def u = User.get( 'Firstname LASTNAME' , false , Collections.emptyMap()) always returns the first UserID if all 2 or 3 Jenkins accounts have the same Full Name 'Firstname LASTNAME': UserID 1: "firstname.lastname" (fullName "Firstname LASTNAME", I changed it afterwards as admin just for testing) UserID 2: "firstname.lastname@mycompany.com" (fullName "Firstname LASTNAME" extracted user.name and set by auto-create) UserID 3: "lastname" (fullName "Firstname LASTNAME" set by developer) So auto-creating a new user and extracting the user.name and updating it as FullName https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitChangeSet.java#L471 is also not good if you want to use: user = getUser(csAuthor, false ); later (after disabling "Create new accounts based on author/committer's email"). So Improvement suggestion B.1 enabling/disabling "auto-create user account" and cleaning-up UN-authorized Jenkins accounts later seems to me the only working solution here, unless deeper Jenkins core and/or LDAP plugin improvements will be provided here by experts.

          We recently tripped over this -  to me, the code should look for a user that is using the email address of the culprit rather than clumsily trying to guess at a username to match with - in our case, we may have some meta data pumped into the Full names by the directory management team.

          I'm curious what would be the knock on effects of having the culprit code use  hudson.tasks.Mailer.UserProperty(csAuthorEmail) and searching for a match among all users.

          Matthew Ludlum added a comment - We recently tripped over this -  to me, the code should look for a user that is using the email address of the culprit rather than clumsily trying to guess at a username to match with - in our case, we may have some meta data pumped into the Full names by the directory management team. I'm curious what would be the knock on effects of having the culprit code use  hudson.tasks.Mailer.UserProperty(csAuthorEmail) and searching for a match among all users.

            Unassigned Unassigned
            docwhat Christian Höltje
            Votes:
            51 Vote for this issue
            Watchers:
            61 Start watching this issue

              Created:
              Updated: