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

this.me NullPointerException in GithubAuthenticationToken.java oauth

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: Minor Minor
    • github-oauth-plugin
    • None

      With github-oauth-0.31 as well as github-oauth-0.32 (to which I upgraded by manually placing it into the plugins directory in an attempt to fix the issue), since today my Jenkins refuses to work at all because I can't log in with Github, with the following exception:

      java.lang.NullPointerException
      	at org.jenkinsci.plugins.GithubAuthenticationToken.<init>(GithubAuthenticationToken.java:205)
      	at org.jenkinsci.plugins.GithubSecurityRealm$1.authenticate(GithubSecurityRealm.java:538)
      	at jenkins.security.BasicHeaderRealPasswordAuthenticator.authenticate(BasicHeaderRealPasswordAuthenticator.java:56)
      	at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:79)
      	at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      	at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
      	at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:67)
      	at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
      	at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:90)
      	at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171)
      	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
      	at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:49)
      	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
      	at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82)
      	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
      	at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
      	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
      	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
      	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
      	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
      	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
      	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
      	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
      	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
      	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
      	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242)
      	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
      	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
      	at org.eclipse.jetty.server.Server.handle(Server.java:503)
      	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
      	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
      	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
      	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
      	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
      	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
      	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
      	at java.lang.Thread.run(Thread.java:748)
      

      That's this code:

      https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubAuthenticationToken.java#L205

      This suggests that this.me is null.

      Happens to me for both Jenkins 2.150.1 and 2.164.2.

      It occurred after I temporarily added HTTP basic auth on the nginx that reverse-proxies this Jenkins, and then disabled it again. Not sure if it's related or coincidence.

          [JENKINS-56997] this.me NullPointerException in GithubAuthenticationToken.java oauth

          For others also trying to use HTTP Basic Auth in front of Jenkins, an important trick is that after doing the HudsonPrivateSecurityRealm reset, one cannot login at all if the basic auth is enabled in nginx; that has to be turned off first.

          Otherwise it keeps asking for a HTTP basic auth password in the browser and accepts none, not even the one it had accepted before.

          Niklas Hambuechen added a comment - For others also trying to use HTTP Basic Auth in front of Jenkins, an important trick is that after doing the HudsonPrivateSecurityRealm reset, one cannot login at all if the basic auth is enabled in nginx; that has to be turned off first. Otherwise it keeps asking for a HTTP basic auth password in the browser and accepts none, not even the one it had accepted before.

          OK, I compiled the plugin from source and added some logs.

          This assertion

          https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubAuthenticationToken.java#L201

          has no effect, it is just continued past. This is most likely because assertions are off by default on the JVM unless you enable them with java -ea (which is short for -enableassertions).

          Should this really be an assertion, or should this be a proper check with if and throwing an exception?

          Niklas Hambuechen added a comment - OK, I compiled the plugin from source and added some logs. This assertion https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubAuthenticationToken.java#L201 has no effect, it is just continued past. This is most likely because assertions are off by default on the JVM unless you enable them with java -ea (which is short for -enableassertions ). Should this really be an assertion, or should this be a proper check with if and throwing an exception?

          OK, with more logging I found a couple more things that are wrong here.

          This code is triggered:

          https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubAuthenticationToken.java#L494

                  } catch (IOException e) {
                      LOGGER.log(Level.FINEST, e.getMessage(), e);
                      me = UNKNOWN_TOKEN;
          usersByTokenCache.put(token, UNKNOWN_TOKEN);
          

          but because it uses FINEST logging, the error message never appears anywhere. The exeception e is:

          org.kohsuke.github.GHFileNotFoundException: {"message":"Bad credentials","documentation_url":"https://developer.github.com/v3"}
          

          Why does the code catch the much more general IOException instead of GHFileNotFoundException or some general Github-specific error?

          The code then also does me = UNKNOWN_TOKEN; where UNKNOWN_TOKEN = new GithubMyself(null);, so that's where the null comes from. In the face of this, the use of assert mentioned above looks quite certainly wrong, as Github complaining about bad credentials is a normal code path that can be taken, and should thus be always checked.

          It seems right now there's no code path that clearly tells the user what Github's error message is ("Bad credentials"), which is bad.

          Niklas Hambuechen added a comment - OK, with more logging I found a couple more things that are wrong here. This code is triggered: https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubAuthenticationToken.java#L494 } catch (IOException e) { LOGGER.log(Level.FINEST, e.getMessage(), e); me = UNKNOWN_TOKEN; usersByTokenCache.put(token, UNKNOWN_TOKEN); but because it uses FINEST logging, the error message never appears anywhere. The exeception e is: org.kohsuke.github.GHFileNotFoundException: { "message" : "Bad credentials" , "documentation_url" : "https: //developer.github.com/v3" } Why does the code catch the much more general IOException instead of GHFileNotFoundException or some general Github-specific error? The code then also does me = UNKNOWN_TOKEN; where UNKNOWN_TOKEN = new GithubMyself(null); , so that's where the null comes from. In the face of this, the use of assert mentioned above looks quite certainly wrong, as Github complaining about bad credentials is a normal code path that can be taken, and should thus be always checked. It seems right now there's no code path that clearly tells the user what Github's error message is ("Bad credentials"), which is bad.

          Niklas Hambuechen added a comment - - edited

          OK, I think I found a key underlying problem for why the NullPointerException comes back to me repeatedly, and also why it only appeared the first time after I shortly turned on Basic Auth in nginx.

          If I try to fix the problem by switching back to HudsonPrivateSecurityRealm, logging in as some local user, say admin, Jenkins prompts me with HTTP Basic Auth, into which I have to put my user admin. If I then then enable Github login, then I'll also get the NullPointerException, because in this code

          https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubSecurityRealm.java#L531

          the authentication printed shows as

          org.acegisecurity.providers.UsernamePasswordAuthenticationToken@8cffbcaa: Username: admin; Password: [PROTECTED]
          

          Se how there's admin in here. That's because I haven't had a chance to log out of HTTP Basic Auth. I can see the Authorization: Basic ... header being set in the dev tools, and in fact, browsers like Firefox have no method to display visually that it's still being sent, or even to clear HTTP basic auth for just a single site (see https://bugzilla.mozilla.org/show_bug.cgi?id=540516#c2), but Firefox's Clear History... -> [x] Active Logins does the trick (wiping all sites' Basic Auth). And Jenkins / the Github plugin seems to pick up this Basic Auth header, and thus try to authenticate me to Github as admin (which can't work) instead of doing a normal Github OAuth.

          Then when that happens, the above-found problems with lack of error reporting that the auth failed kick in, and the NullPointerException is thrown.

          Niklas Hambuechen added a comment - - edited OK, I think I found a key underlying problem for why the NullPointerException comes back to me repeatedly, and also why it only appeared the first time after I shortly turned on Basic Auth in nginx. If I try to fix the problem by switching back to HudsonPrivateSecurityRealm , logging in as some local user, say admin , Jenkins prompts me with HTTP Basic Auth, into which I have to put my user admin . If I then then enable Github login, then I'll also get the NullPointerException , because in this code https://github.com/jenkinsci/github-oauth-plugin/blob/6165ab2acc4e9e39cbc67d231187e859f3524ff3/src/main/java/org/jenkinsci/plugins/GithubSecurityRealm.java#L531 the authentication printed shows as org.acegisecurity.providers.UsernamePasswordAuthenticationToken@8cffbcaa: Username: admin; Password: [PROTECTED] Se how there's admin in here. That's because I haven't had a chance to log out of HTTP Basic Auth. I can see the Authorization: Basic ... header being set in the dev tools, and in fact, browsers like Firefox have no method to display visually that it's still being sent, or even to clear HTTP basic auth for just a single site (see https://bugzilla.mozilla.org/show_bug.cgi?id=540516#c2 ), but Firefox's Clear History... -> [x] Active Logins does the trick (wiping all sites' Basic Auth). And Jenkins / the Github plugin seems to pick up this Basic Auth header, and thus try to authenticate me to Github as admin (which can't work) instead of doing a normal Github OAuth. Then when that happens, the above-found problems with lack of error reporting that the auth failed kick in, and the NullPointerException is thrown.

          Finally, let's get back to Basic Auth in the nginx reverse proxy in front of Jenkins.

          When I have cleared the Basic Auth as described and everything is working, and I then enable Basic Auth in nginx, I get a password prompt (into which I put my nginx-configured credentials, let's say username niklas), and everything continues working fine (I'm still logged in in Jenkins and can browse around). But as soon as I click Logout in Jenkins, everything breaks, and I cannot get logged back in with Github.

          That is because we now have the same problem as before: The plugin picks up nginx's Basic Auth and uses that user to Github:

          org.acegisecurity.providers.UsernamePasswordAuthenticationToken@dc12364c: Username: niklas; Password: [PROTECTED]
          

          Which is wrong, because it should use the normal OAuth and ignore nginx's Basic Auth.

          That means right now, you can't run Jenkins behind nginx with Basic Auth while also using the github-oauth-plugin.

          So it seems there should be a way to disable the second branch in

                          if (authentication instanceof GithubAuthenticationToken)
                              return authentication;
                          if (authentication instanceof UsernamePasswordAuthenticationToken)
                              try {
          

          being taken, and forcing Github auth no matter the HTTP auth.

          Niklas Hambuechen added a comment - Finally, let's get back to Basic Auth in the nginx reverse proxy in front of Jenkins. When I have cleared the Basic Auth as described and everything is working, and I then enable Basic Auth in nginx, I get a password prompt (into which I put my nginx-configured credentials, let's say username niklas ), and everything continues working fine (I'm still logged in in Jenkins and can browse around). But as soon as I click Logout in Jenkins, everything breaks, and I cannot get logged back in with Github. That is because we now have the same problem as before: The plugin picks up nginx's Basic Auth and uses that user to Github: org.acegisecurity.providers.UsernamePasswordAuthenticationToken@dc12364c: Username: niklas; Password: [PROTECTED] Which is wrong, because it should use the normal OAuth and ignore nginx's Basic Auth. That means right now, you can't run Jenkins behind nginx with Basic Auth while also using the github-oauth-plugin . So it seems there should be a way to disable the second branch in if (authentication instanceof GithubAuthenticationToken) return authentication; if (authentication instanceof UsernamePasswordAuthenticationToken) try { being taken, and forcing Github auth no matter the HTTP auth.

          I found a workaround for the above to use with nginx:

          proxy_set_header Authorization "";
          

          This makes sure nginx does not pass through any HTTP Basic Auth (or other authorization) header to Jenkins.

          So the remaining tasks for this ticket should probably be:

          • Better error messages (don't swallow Bad credentials from Github, don't use assert here)
          • Make it somehow possible to disable the plugin picking up Basic Auth and passing it to Github, especially after just switching from another Jenkins auth method to Github auth

          Niklas Hambuechen added a comment - I found a workaround for the above to use with nginx: proxy_set_header Authorization ""; This makes sure nginx does not pass through any HTTP Basic Auth (or other authorization) header to Jenkins. So the remaining tasks for this ticket should probably be: Better error messages (don't swallow Bad credentials from Github, don't use assert here) Make it somehow possible to disable the plugin picking up Basic Auth and passing it to Github, especially after just switching from another Jenkins auth method to Github auth

          Hello developers,

          is there any approach on this issue ?

          We are using github-oauth-plugin within our Jenkins (based in rhel 7) in AWS and have still this problem with version 0.32.

          Version 0.29 works but has security issues.

          Thanks for your help.

          Best regards,

             Sascha Vujevic

          Sascha Vujevic added a comment - Hello developers, is there any approach on this issue ? We are using github-oauth-plugin within our Jenkins (based in rhel 7) in AWS and have still this problem with version 0.32. Version 0.29 works but has security issues. Thanks for your help. Best regards,    Sascha Vujevic

          Hello developers,

          seems to work. I think it was part of caching and wrong configuration of

          <oauthScopes>read:org,user:email,repo</oauthScopes>
          

          and wrong githubApiUri.

          Thanks.

           

          Sascha Vujevic added a comment - Hello developers, seems to work. I think it was part of caching and wrong configuration of <oauthScopes>read:org,user:email,repo</oauthScopes> and wrong githubApiUri. Thanks.  

          Marcin Losek added a comment - - edited

          I have also encountered this problem while upgrading jobs and Jenkins from an old version for core and plugin to latest ones (0.32). The same error and issues appeared for old jobs which should be migrated. But when I create a new job with same settings for GitHub multibranch it worked properly. When tried to copy old, broken to a new one (create new base on old one) error persist. When I downgraded plugin version to 0.31 old jobs which were migrated also started to work, so for my case, problems seems to be in the latest version of plugin (0.32) and old jobs. I also have basic auth in front of Jenkins but it's optional when accessing instance from trusted IPs and I've found that header Authorization was missing in requests, but error persisted.

          So I think it's not only related with nginx reverse proxy behind Jenkins. Also I've encounted this problem while Scanning GitHub repository in jobs I could login to Jenkins which uses OAuth apps without problems.

          Kind regards,
          Marcin

          Marcin Losek added a comment - - edited I have also encountered this problem while upgrading jobs and Jenkins from an old version for core and plugin to latest ones (0.32). The same error and issues appeared for old jobs which should be migrated. But when I create a new job with same settings for GitHub multibranch it worked properly. When tried to copy old, broken to a new one (create new base on old one) error persist. When I downgraded plugin version to 0.31 old jobs which were migrated also started to work, so for my case, problems seems to be in the latest version of plugin (0.32) and old jobs. I also have basic auth in front of Jenkins but it's optional when accessing instance from trusted IPs and I've found that header Authorization was missing in requests, but error persisted. So I think it's not only related with nginx reverse proxy behind Jenkins. Also I've encounted this problem while Scanning GitHub repository in jobs I could login to Jenkins which uses OAuth apps without problems. Kind regards, Marcin

          Sam Gleske added a comment -

          I didn't realize the other issue was a dupe of this one. In any case, I'll close this as a dupe instead.

          Fix released as https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/github-oauth/0.33/github-oauth-0.33.hpi

          Sam Gleske added a comment - I didn't realize the other issue was a dupe of this one. In any case, I'll close this as a dupe instead. Fix released as https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/github-oauth/0.33/github-oauth-0.33.hpi

            sag47 Sam Gleske
            nh2 Niklas Hambuechen
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: