ccmenu / ccmenu2

CCMenu is a Mac app that shows the status of builds on CI/CD servers in the menu bar.
https://ccmenu.org/
Apache License 2.0
29 stars 6 forks source link

Jenkins access via basic auth not working any more #13

Closed oli99sc closed 1 month ago

oli99sc commented 2 months ago

Since the update via app store (to v 25.0) I get unauthorized errors in pipeline overview for all pipelines using basic auth access for jenkins based builds.

CCMenu is able to poll the list of projects from Jenkins on the "Add project from CCTray feed" dialog when I use basic auth with my credentials and add recursive cc.xml URL

Screenshot 2024-08-12 at 09 51 42

However when I select a pipeline and apply my changes, the related pipeline is shown as unauthorized. Screenshot 2024-08-12 at 09 49 37

I checked that CCMenu has access to the related keystore password entries according to the settings in the credentials.

sodul commented 1 month ago

I can confirm the same issue. The GH integration seems to work well, but all of my jenkins pipelines are now broken and I can't get it to work again. As @oli99sc reported we know the credentials work since we can see the list of projects in the configuration view, but the pipelines are all being reported as 'unauthorized'.

The older version works fine: https://github.com/ccmenu/ccmenu/releases/tag/v15.0

erikdoe commented 1 month ago

It's curious that the pipelines in the window report "unauthorised" and not "no matching password in Keychain", but there's definitely a bug now when adding basic auth protected CCTray projects. Looking into it.

Can you confirm: do the pipelines show "unauthorised" directly after upgrading from CCMenu 15 to 25? And do they show the same error when you try to re-add them?

oli99sc commented 1 month ago

I can confirm all pipelines were in unauthorized state after the update. I removed all configured pipelines and added one which immediately also went to unauthorized.

erikdoe commented 1 month ago

Still can't reproduce the "unauthorized" state, but I have fixed a bug that prevented the password for new pipelines to be stored.

Is it maybe possible that the password in your keychain is outdated? If that were the case, then CCMenu would try to use the outdated password, and get an "unauthorized". Adding a new pipeline would result in the same outcome, because v25.0 has this bug where it doesn't store the password in the keychain, which means CCMenu would add the pipeline but would continue to try to use the old password from the keychain.

Can you have a look at CCMenu 25.1 and let me know whether this allows you to add new pipelines successfully?

sodul commented 1 month ago

I tried to re-add a pipeline and re-paste a token, which allowed to get the list of jobs, but then the status would always be unauthorized. We know the credentials work, since we can get the list of jobs from the config UI, the problem is only on getting the individual statuses somehow. Is it possible that the individual statuses change the http url which would lead to the unauthorized error?

Again, rolling back to v15 fixes the issue without me having to muck with the settings so the token in Keychain is correct.

I tried v25.1 with the same issue: existing pipelines, freshly configured pipelines are not able to report status. Note that we use API tokens, we use 2FA, so normal passwords are not possible to use.

erikdoe commented 1 month ago

@sodul Can you confirm what you mean by "normal passwords are not possible to use"? My understanding is that you get an API token from Jenkins and put that into the password field in CCMenu, right?

erikdoe commented 1 month ago

Just to make sure: when you look at the URL in the pipeline window, it has the correct user name, right? In the example below it's "dev".

Screenshot 2024-08-16 at 11 10 41

And then, when you open the Keychain Access app, you have an entry for that URL with the correct password / token, right?

Screenshot 2024-08-16 at 11 11 13 Screenshot 2024-08-16 at 11 11 44
erikdoe commented 1 month ago

To help diagnose this issue I have created a developer release with additional logging.

Can you please run the Console app, apply a process filter for CCMenu, and "start streaming". Then, launch CCMenu. Theoretically you should see messages like the ones below. This is what I see with the fake server I use for development. But with your Jenkins installs something must be different. Just what?

Screenshot 2024-08-16 at 15 54 57

sodul commented 1 month ago

@sodul Can you confirm what you mean by "normal passwords are not possible to use"? My understanding is that you get an API token from Jenkins and put that into the password field in CCMenu, right?

Yes, Jenkins has many ways to authenticate. Our instances use SSO with a third party provider and we create API tokens from the Jenkins UI in order to use the Jenkins CLI, API, or CCMenu.

With the Dev release I see:

default 13:49:20.019026-0700    CCMenu  Retrieving password for https://stephane%40******@jenkins.********/job/ci/cc.xml/ from keychain
....
default 13:49:20.148454-0700    CCMenu  Got password (length = 34)
default 13:49:20.149549-0700    CCMenu  Making request for url https://stephane%40*****@jenkins.*********/job/ci/cc.xml/ with authorization ***** ****************************************************************************
default 13:49:20.154947-0700    CCMenu  Connection 1: enabling TLS
default 13:49:20.154958-0700    CCMenu  Connection 1: starting, TC(0x0)
default 13:49:20.154992-0700    CCMenu  [C1 24A8CFD7-8F5F-4B66-AFA1-DF43B02AF70F Hostname#fa44b5fa:443 quic-connection, url hash: fdd42b49, definite, attribution: developer, context: com.apple.CFNetwork.NSURLSession.{41B13D2C-405A-48A0-B2B8-63B06F1BA674}{(null)}{Y}{2}{0x0} (private), proc: BF2FE5E4-5302-3618-9164-DAEA18A4C53E] start
default 13:49:20.155019-0700    CCMenu  [C1 Hostname#fa44b5fa:443 initial parent-flow ((null))] event: path:start @0.000s
default 13:49:20.155167-0700    CCMenu  [C1 Hostname#fa44b5fa:443 waiting parent-flow (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: path:satisfied @0.000s, uuid: DB2C8CD0-C096-459C-AFFA-AAD8A144EE7E
default 13:49:20.155265-0700    CCMenu  [C1 Hostname#fa44b5fa:443 in_progress parent-flow (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: flow:start_connect @0.000s
default 13:49:20.155273-0700    CCMenu  nw_connection_report_state_with_handler_on_nw_queue [C1] reporting state preparing
default 13:49:20.155358-0700    CCMenu  [C1 Hostname#fa44b5fa:443 in_progress parent-flow (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: flow:start_child @0.000s
default 13:49:20.155417-0700    CCMenu  [C1.1 Hostname#fa44b5fa:443 initial path ((null))] event: path:start @0.000s
default 13:49:20.155531-0700    CCMenu  [C1.1 Hostname#fa44b5fa:443 waiting path (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: path:satisfied @0.000s, uuid: DB2C8CD0-C096-459C-AFFA-AAD8A144EE7E
default 13:49:20.155617-0700    CCMenu  [C1.1 Hostname#fa44b5fa:443 in_progress transform (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: transform:start @0.000s
default 13:49:20.155754-0700    CCMenu  [C1.1.1 Hostname#fa44b5fa:443 initial path ((null))] event: path:start @0.000s
default 13:49:20.155872-0700    CCMenu  [C1.1.1 Hostname#fa44b5fa:443 waiting path (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: path:satisfied @0.000s, uuid: 24A43546-0E87-406D-AE7C-B67BD4629AB0
default 13:49:20.155997-0700    CCMenu  [C1.1.1 Hostname#fa44b5fa:443 in_progress resolver (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi)] event: resolver:start_dns @0.000s
default 13:49:20.156130-0700    CCMenu  Task <5C3D77E1-F76B-45B7-89AC-0F90F3EB5DB8>.<1> setting up Connection 1
default 13:49:20.156086-0700    CCMenu  [0x600002f51860] activating connection: mach=true listener=false peer=false name=com.apple.dnssd.service

Something to note, we have a 'test' instance which we have not hooked to SSO and it uses regular password auth. I tried to add a connection to it with password, and everything works fine. I tried with a toke it works fine as well.

In our SSO enabled instances the usernames are user@example.com, on our test instance it is just user. I tried to create test user with an email address as the username but Jenkins does not allow that for internally managed users.

I suspect that the issue is the @ in our usernames that get transformed to %40. Somehow the request done to get the list of statuses in the configuration UI is able to authenticate, but then for the call to get the actual statuses it behaves differently.

erikdoe commented 1 month ago

Thank you for your investigation. It was the @ in the user name that caused the problem. In the dialogue where you add pipelines the user name is kept as a string and passed directly to the request builder. It's only in the feed reader that the user name is taken from the URL.

In addition, I had moved away from a deprecated API on the URL class to a new API, which introduced an optional boolean flag to specify whether you want the user name as is or percent encoded. And for some reason someone at Apple thought it was a good idea to make percent encoded the default...

sodul commented 1 month ago

I can confirm that v26.0 is now working as expected.

There is a slight regression where some of my urls no longer work if they do not end with a trailing /: /cc.xml/ works, but /cc.xml no longer works. I assume the old version would try to append a trailing / if missing.

Since there is no ui to update the urls, I have to export the json, fix it, import the fixed json, and delete the old entry. This is a one time thing so not too bad.

Thanks for fixing the issue promptly.