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

Session-ID missing alongside CSRF tokens

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Not A Defect
    • Component/s: swarm-plugin
    • Labels:
      None
    • Environment:
      Jenkins LTS 2.176.3
    • Similar Issues:

      Description

      Jenkins LTS 2.176.3 incorporated commit ace596, which factors the Session ID into the computation of CSRF crumbs; since a new Session ID is generated if none is provided, previously issued crumbs are rendered useless in the absence of a reusable Session ID. This currently prevents Swarm clients from connecting to Jenkins masters secured with the DefaultCrumbIssuer, since the generated crumb is immediately rendered useless.

      I think a fix would involve the Swarm plugin using a persistent session ID on the client-side. I labeled this issue as "minor", because an easy workaround exists (setting hudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID to true on the Jenkins master). It should be noted, however, that this reduces the efficacy of the fixes to SECURITY-626 and SECURITY-1491.

        Attachments

          Issue Links

            Activity

            Hide
            basil Basil Crow added a comment -

            Daniel Katz Hiroki OHZAKI Can you provide me with a list of steps to reproduce the issue? Bonus points if you can submit a PR with a failing unit test. I tried updated the unit tests to use Jenkins 2.176.3 and DefaultCrumbIssuer, but the tests still passed:

            diff --git a/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java b/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java
            index b4d1f12..426e01c 100644
            --- a/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java
            +++ b/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java
            @@ -12,6 +12,7 @@ import hudson.model.FreeStyleProject;
             import hudson.model.Node;
             import hudson.plugins.swarm.test.ProcessDestroyer;
             import hudson.plugins.swarm.test.TestUtils;
            +import hudson.security.csrf.DefaultCrumbIssuer;
             import hudson.tasks.BatchFile;
             import hudson.tasks.CommandInterpreter;
             import hudson.tasks.Shell;
            @@ -28,6 +29,7 @@ import org.apache.commons.lang.RandomStringUtils;
             import org.apache.commons.lang.math.NumberUtils;
             import org.junit.After;
             import org.junit.Assume;
            +import org.junit.Before;
             import org.junit.ClassRule;
             import org.junit.Rule;
             import org.junit.Test;
            @@ -51,6 +53,11 @@ public class SwarmClientIntegrationTest {
             
                 private final ProcessDestroyer processDestroyer = new ProcessDestroyer();
             
            +    @Before
            +    public void setIssuer() {
            +        j.jenkins.setCrumbIssuer(new DefaultCrumbIssuer(false));
            +    }
            +
                 /** Executes a shell script build on a Swarm Client agent. */
                 @Test
                 public void buildShellScript() throws Exception {
            diff --git a/pom.xml b/pom.xml
            index cdaf0ed..3c7d7c2 100644
            --- a/pom.xml
            +++ b/pom.xml
            @@ -24,7 +24,7 @@
                 <version>3.18-SNAPSHOT</version>
             
                 <properties>
            -        <jenkins.version>2.60.3</jenkins.version>
            +        <jenkins.version>2.176.3</jenkins.version>
                     <java.level>8</java.level>
                 </properties>
             
            
            Show
            basil Basil Crow added a comment - Daniel Katz Hiroki OHZAKI Can you provide me with a list of steps to reproduce the issue? Bonus points if you can submit a PR with a failing unit test. I tried updated the unit tests to use Jenkins 2.176.3 and DefaultCrumbIssuer , but the tests still passed: diff --git a/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java b/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java index b4d1f12..426e01c 100644 --- a/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java +++ b/plugin/src/test/java/hudson/plugins/swarm/SwarmClientIntegrationTest.java @@ -12,6 +12,7 @@ import hudson.model.FreeStyleProject; import hudson.model.Node; import hudson.plugins.swarm.test.ProcessDestroyer; import hudson.plugins.swarm.test.TestUtils; +import hudson.security.csrf.DefaultCrumbIssuer; import hudson.tasks.BatchFile; import hudson.tasks.CommandInterpreter; import hudson.tasks.Shell; @@ -28,6 +29,7 @@ import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.math.NumberUtils; import org.junit.After; import org.junit.Assume; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -51,6 +53,11 @@ public class SwarmClientIntegrationTest { private final ProcessDestroyer processDestroyer = new ProcessDestroyer(); + @Before + public void setIssuer() { + j.jenkins.setCrumbIssuer(new DefaultCrumbIssuer(false)); + } + /** Executes a shell script build on a Swarm Client agent. */ @Test public void buildShellScript() throws Exception { diff --git a/pom.xml b/pom.xml index cdaf0ed..3c7d7c2 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ <version>3.18-SNAPSHOT</version> <properties> - <jenkins.version>2.60.3</jenkins.version> + <jenkins.version>2.176.3</jenkins.version> <java.level>8</java.level> </properties>
            Hide
            basil Basil Crow added a comment -

            For what it's worth, I also tried a manual test of installing Jenkins 2.190.1, ensuring that "Prevent Cross Site Request Forgery exploits" was checked with "Default Crumb Issuer" as the crumb algorithm, and then running this command:

            java -jar swarm-client-3.17.jar -master <url> -username <username> -password <password> -name <name> -disableClientsUniqueId  -deleteExistingClients
            

            This worked fine as well. Without being able to reproduce the error, I won't be able to make progress fixing this I'm afraid.

            Show
            basil Basil Crow added a comment - For what it's worth, I also tried a manual test of installing Jenkins 2.190.1, ensuring that "Prevent Cross Site Request Forgery exploits" was checked with "Default Crumb Issuer" as the crumb algorithm, and then running this command: java -jar swarm-client-3.17.jar -master <url> -username <username> -password <password> -name <name> -disableClientsUniqueId -deleteExistingClients This worked fine as well. Without being able to reproduce the error, I won't be able to make progress fixing this I'm afraid.
            Hide
            bruce Dirk Kuypers added a comment -

            I am not sure if this is related. I am hit by 403 after a restart of the master. Node was connected via swarm, master restart due to (Windows) updates, swarm client refuses to connect with 403. Client restart does not help. After 24 hours something seems to expire and clients can connect again. I have installed the new Crumb Issuer Plugin and I have unticked the Session ID.

            Environment is Windows 2016 server for the master, Windows 10 for the clients, Active Directory and Role-Based Access (which can be found when googling for swarm and 403 quite often:-/)

            Show
            bruce Dirk Kuypers added a comment - I am not sure if this is related. I am hit by 403 after a restart of the master. Node was connected via swarm, master restart due to (Windows) updates, swarm client refuses to connect with 403. Client restart does not help. After 24 hours something seems to expire and clients can connect again. I have installed the new Crumb Issuer Plugin and I have unticked the Session ID. Environment is Windows 2016 server for the master, Windows 10 for the clients, Active Directory and Role-Based Access (which can be found when googling for swarm and 403 quite often:-/)
            Hide
            basil Basil Crow added a comment -

            Thanks for the information Dirk Kuypers. Unfortunately this still doesn't get me any closer to reproducing the problem or resolving it. The unit tests I mentioned above do restart Jenkins (see PipelineJobTest), although not on Windows. If someone can provide me with steps to reproduce this problem from scratch I would be very grateful.

            Show
            basil Basil Crow added a comment - Thanks for the information Dirk Kuypers . Unfortunately this still doesn't get me any closer to reproducing the problem or resolving it. The unit tests I mentioned above do restart Jenkins (see PipelineJobTest ), although not on Windows. If someone can provide me with steps to reproduce this problem from scratch I would be very grateful.
            Hide
            basil Basil Crow added a comment - - edited

            Hey Daniel Katz, Hiroki OHZAKI, and Dirk Kuypers, I think I have figured this out. This doesn't have anything to do with the CSRF configuration but rather the Authorization Strategy configuration. Your Swarm user needs the Overall/Read permission in order to obtain a CSRF token. I just recently documented the recommended configuration for Swarm with examples and screenshots for matrix-based security, project-based Matrix Authorization Strategy, and Role-Based Strategy. Please ensure that you have configured your permissions appropriately following the above documentation.

            Show
            basil Basil Crow added a comment - - edited Hey Daniel Katz , Hiroki OHZAKI , and Dirk Kuypers , I think I have figured this out. This doesn't have anything to do with the CSRF configuration but rather the Authorization Strategy configuration. Your Swarm user needs the Overall/Read permission in order to obtain a CSRF token. I just recently documented the recommended configuration for Swarm with examples and screenshots for matrix-based security, project-based Matrix Authorization Strategy, and Role-Based Strategy. Please ensure that you have configured your permissions appropriately following the above documentation.
            Hide
            katzdm Daniel Katz added a comment -

            Hey Basil - Thanks so much for following up on this, and for not giving up on the issue (despite your frustrations trying to reproduce it). I've unfortunately not had time to revisit this myself, but after your recent comment, the least I could do was to try your recommended solution.

            Although you were correct in guessing that my Swarm user (i.e. worker_node) did not previously have permission Overall/Read, granting this permission unfortunately did not solve the problem. The permissions currently granted to worker_node are: [{{Overall/Read}}, {{Credentials/UseItem}}, {{Agent/Build}}, {{Agent/Configure}}, {{Agent/Connect}} (through another permission), {{Agent/Create}}, {{Agent/Delete}}, {{Agent/Disconnect}}, {{Job/Build}}].

            I'll try to revisit this in the next week or so - Thanks again for your continued attention to it!

            Show
            katzdm Daniel Katz added a comment - Hey Basil - Thanks so much for following up on this, and for not giving up on the issue (despite your frustrations trying to reproduce it). I've unfortunately not had time to revisit this myself, but after your recent comment, the least I could do was to try your recommended solution. Although you were correct in guessing that my Swarm user (i.e. worker_node ) did not previously have permission Overall/Read , granting this permission unfortunately did not solve the problem. The permissions currently granted to worker_node are: [{{Overall/Read}}, {{Credentials/UseItem}}, {{Agent/Build}}, {{Agent/Configure}}, {{Agent/Connect}} (through another permission), {{Agent/Create}}, {{Agent/Delete}}, {{Agent/Disconnect}}, {{Job/Build}}] . I'll try to revisit this in the next week or so - Thanks again for your continued attention to it!
            Hide
            basil Basil Crow added a comment -

            Thanks for the reply, Daniel Katz. Can you provide more information about your Authorization Strategy? Are you using matrix-based security, project-based Matrix Authorization Strategy, or Role-Based Strategy? Are you using a Jenkins API token or a password? Also please verify you are using the latest release of the Swarm plugin and Swarm client, as it contains some security related fixes relating to authorization. If you have some time and don't mind writing some Java code, see if you can reproduce the problem with some variant of your configuration programmatically in AuthorizationStrategyTest. Otherwise please tell me as much as you can about your authorization setup, obviously without revealing any sensitive information.

            Show
            basil Basil Crow added a comment - Thanks for the reply, Daniel Katz . Can you provide more information about your Authorization Strategy? Are you using matrix-based security, project-based Matrix Authorization Strategy, or Role-Based Strategy? Are you using a Jenkins API token or a password? Also please verify you are using the latest release of the Swarm plugin and Swarm client, as it contains some security related fixes relating to authorization. If you have some time and don't mind writing some Java code, see if you can reproduce the problem with some variant of your configuration programmatically in AuthorizationStrategyTest . Otherwise please tell me as much as you can about your authorization setup, obviously without revealing any sensitive information.
            Hide
            katzdm Daniel Katz added a comment -

            We're using a project-based Matrix Authorization Strategy, and I don't believe we're using an API token/password (AFAIK). We're currently on version 1.21 of the plugin, but version 1.18 of the client - Have there been relevant fixes since then? If so, I'll get the client upgraded and we can try again.

            I'll try to dig into the Java, when I've exhausted every other idea  Which won't be long now.

            Show
            katzdm Daniel Katz added a comment - We're using a project-based Matrix Authorization Strategy, and I don't believe we're using an API token/password (AFAIK). We're currently on version 1.21 of the plugin, but version 1.18 of the client - Have there been relevant fixes since then? If so, I'll get the client upgraded and we can try again. I'll try to dig into the Java, when I've exhausted every other idea  Which won't be long now.
            Hide
            basil Basil Crow added a comment -

            Yes, please ensure you are running the latest version of both the plugin and the client, as both contain multiple fixes regarding CSRF and authorization.

            Show
            basil Basil Crow added a comment - Yes, please ensure you are running the latest version of both the plugin and the client, as both contain multiple fixes regarding CSRF and authorization.
            Hide
            katzdm Daniel Katz added a comment -

            Hey Basil - Tried today with the latest versions of both the plugin and client; no dice - still seeing the issue, when I disable EXCLUDE_SESSION_ID.

            I'll try to dig more and look into implementing an integration test, but I still think this makes some sense: The commit I cited in the original bug incorporates the "Session ID" (which as far as I can tell derives from the JSESSIONID cookie) into the crumb-generation logic. If we don't pass back the JSESSIONID (which we don't appear to), then our crumb will be invalidated. Example of the Set-Cookie header from the Jenkins master:

            'Set-Cookie': 'ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE=; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly,JSESSIONID.f443e328=node01s03czg5u9gagotkcld9tm98225.node0; Path=/; Secure; HttpOnly'

            Note the JESSIONID.xyz component, which we don't seem to return to the master in subsequent requests.

            Anyway, as I said - I'll try to dig more on my side.

            Show
            katzdm Daniel Katz added a comment - Hey Basil - Tried today with the latest versions of both the plugin and client; no dice - still seeing the issue, when I disable EXCLUDE_SESSION_ID . I'll try to dig more and look into implementing an integration test, but I still think this makes some sense: The commit I cited in the original bug incorporates the "Session ID" (which as far as I can tell derives from the JSESSIONID cookie) into the crumb-generation logic. If we don't pass back the JSESSIONID  (which we don't appear to), then our crumb will be invalidated. Example of the Set-Cookie header from the Jenkins master: 'Set-Cookie': 'ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE=; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly,JSESSIONID.f443e328=node01s03czg5u9gagotkcld9tm98225.node0; Path=/; Secure; HttpOnly' Note the JESSIONID.xyz component, which we don't seem to return to the master in subsequent requests. Anyway, as I said - I'll try to dig more on my side.
            Hide
            basil Basil Crow added a comment -

            Thanks for following up with the latest versions. I stepped through the code in the Java debugger against my production Jenkins instance, and as far as I can tell I am correctly returning the JSESSIONID in Swarm. Here is a walkthrough of the code:

            1. First, hudson.plugins.swarm.SwarmClient#createSwarmSlave creates an instance of HttpClientContext.
            2. Next, hudson.plugins.swarm.SwarmClient#getCsrfCrumb calls the crumbIssuer API, successfully obtaining a crumb request field and a crumb. Note that this requires Overall/Read permission for the user. The server's response sets a JSESSIONID cookie, which is visible in the HttpClientContext's BasicCookieStore (e.g., JSESSIONID.472fe218).
            3. Next, hudson.plugins.swarm.SwarmClient#createSwarmSlave adds the CSRF header returned by hudson.plugins.swarm.SwarmClient#getCsrfCrumb to the POST request.
            4. Next, hudson.plugins.swarm.SwarmClient#getCsrfCrumb executes the POST request. During this process, org.apache.http.client.protocol.RequestAddCookies examines the HttpClientContext's BasicCookieStore, finds the JSESSIONID cookie, and adds it to the set of headers before making the HTTP POST request.

            The key invariants for all this to work are that the HTTP GET in SwarmClient#getCsrfCrumb must always be called immediately before making any POST request, the HttpClientContext (and therefore the BasicCookieStore) must always be shared between the CSRF crumb retrieval GET and the subsequent POST, and the POST must contain both a CSRF header (obtained from the previous CSRF crumb retrieval GET) and a JSESSIONID header (which must be the same JSESSIONID from the previous CSRF crumb retrieval GET). As far as I can tell all of these invariants are met in the code.

            To see where things are going off the rails you might want to start by turning up logging to a higher level as described here. Then see if there are any errors logged by SwarmClient#getCsrfCrumb or related methods. If you can, sanitize the log and post it here.

            If you can, try to step through the above process in an IDE's debugger and see where things are going off the rails, or write a test in AuthorizationStrategyTest that reproduces the problem. If I could attach a debugger to an instance that is exhibiting this problem I'm sure I could figure it out quickly, but it is difficult to guess at the cause from far away.

            Show
            basil Basil Crow added a comment - Thanks for following up with the latest versions. I stepped through the code in the Java debugger against my production Jenkins instance, and as far as I can tell I am correctly returning the JSESSIONID in Swarm. Here is a walkthrough of the code: First, hudson.plugins.swarm.SwarmClient#createSwarmSlave creates an instance of HttpClientContext . Next, hudson.plugins.swarm.SwarmClient#getCsrfCrumb calls the crumbIssuer API, successfully obtaining a crumb request field and a crumb. Note that this requires Overall/Read permission for the user. The server's response sets a JSESSIONID cookie, which is visible in the HttpClientContext 's BasicCookieStore (e.g., JSESSIONID.472fe218 ). Next, hudson.plugins.swarm.SwarmClient#createSwarmSlave adds the CSRF header returned by hudson.plugins.swarm.SwarmClient#getCsrfCrumb to the POST request. Next, hudson.plugins.swarm.SwarmClient#getCsrfCrumb executes the POST request. During this process, org.apache.http.client.protocol.RequestAddCookies examines the HttpClientContext 's BasicCookieStore , finds the JSESSIONID cookie, and adds it to the set of headers before making the HTTP POST request. The key invariants for all this to work are that the HTTP GET in SwarmClient#getCsrfCrumb must always be called immediately before making any POST request, the HttpClientContext (and therefore the BasicCookieStore ) must always be shared between the CSRF crumb retrieval GET and the subsequent POST, and the POST must contain both a CSRF header (obtained from the previous CSRF crumb retrieval GET) and a JSESSIONID header (which must be the same JSESSIONID from the previous CSRF crumb retrieval GET). As far as I can tell all of these invariants are met in the code. To see where things are going off the rails you might want to start by turning up logging to a higher level as described here . Then see if there are any errors logged by SwarmClient#getCsrfCrumb or related methods. If you can, sanitize the log and post it here. If you can, try to step through the above process in an IDE's debugger and see where things are going off the rails, or write a test in AuthorizationStrategyTest that reproduces the problem. If I could attach a debugger to an instance that is exhibiting this problem I'm sure I could figure it out quickly, but it is difficult to guess at the cause from far away.
            Hide
            katzdm Daniel Katz added a comment -

            Hey Basil - Increasing logging verbosity turned out to be the key here - And my apologies! As you suspected, this was on my end.

            Turns out that our Swarm workers reach the Jenkins master through a minimal and very poorly built proxy served from localhost (this was implemented well before my time working on our stack, and I only discovered the existence of the proxy yesterday). The only purpose of the proxy is to append an "X-Forwarded-User: worker_node" header to identify itself to the Jenkins master; this header is typically appended to human-users' requests by our OAuth2 reverse-proxy, but Swarm agents access the master directly.

            Turns out that the Jenkins master sends JSESSIONID cookies with the Secure attribute, which (correctly) forces the Swarm client to omit the cookie from http://localhost-bound requests. That solves that mystery.

            If I could poke you with one more question, I am now left with the issue of, "How to move forward" - I would still like to remove that EXCLUDE_SESSION_ID override from our configuration, after all. Is there an easier way for me to inject an X-Forwarded-User header into Swarm-issued requests? If not, would you entertain adding a command-line option (--include-header or something?) to support such a use case (or maybe something to that effect already exists within the underlying Apache machinery)? Or perhaps we're going about this wrong, and you would recommend a different setup configuration altogether.

            Thanks again for your time, and thanks in advance for any guidance you could give on best practices here!
            ---Dan

            Show
            katzdm Daniel Katz added a comment - Hey Basil - Increasing logging verbosity turned out to be the key here - And my apologies! As you suspected, this was on my end. Turns out that our Swarm workers reach the Jenkins master through a minimal and  very poorly built proxy served from localhost  (this was implemented well before my time working on our stack, and I only discovered the existence of the proxy yesterday). The only purpose of the proxy is to append an " X-Forwarded-User: worker_node " header to identify itself to the Jenkins master; this header is typically appended to human-users' requests by our OAuth2 reverse-proxy, but Swarm agents access the master directly. Turns out that the Jenkins master sends JSESSIONID cookies with the Secure attribute, which (correctly) forces the Swarm client to omit the cookie from http://localhost -bound requests. That solves that mystery. If I could poke you with one more question, I am now left with the issue of, "How to move forward" - I would still like to remove that EXCLUDE_SESSION_ID override from our configuration, after all. Is there an easier way for me to inject an X-Forwarded-User header into Swarm-issued requests? If not, would you entertain adding a command-line option ( --include-header  or something?) to support such a use case (or maybe something to that effect already exists within the underlying Apache machinery)? Or perhaps we're going about this wrong, and you would recommend a different setup configuration altogether. Thanks again for your time, and thanks in advance for any guidance you could give on best practices here! ---Dan
            Hide
            basil Basil Crow added a comment -

            Great, I'm glad you were able to figure this out! There is some documentation for using Swarm with proxies here. I'm not very familiar with proxies or cookies with the Secure attribute, but from a quick Google search I gather that

            A cookie with the Secure attribute is sent to the server only with an encrypted request over the HTTPS protocol, never with unsecured HTTP, and therefore can't easily be accessed by a man-in-the-middle attacker.

            I am reticent to add support for arbitrary headers. It seems fairly outside the scope of what the Swarm client is meant to do. It is not meant to be a general purpose utility like curl(1) but rather just a wrapper around the Remoting JAR, and its proxy support matches that of Remoting. I would be willing to reconsider this position if other users express an interest and can demonstrate a common use case that requires this. As far as your specific issue is concerned, a proxy seems like the right approach to add custom headers, but it seems like your particular proxy configuration isn't compatible with how Jenkins sets the JSESSIONID cookie. So in my opinion the most appropriate solution would be to make your proxy configuration compatible by enabling TLS on your proxy server and setting -Dhttps.proxyHost and -Dhttps.proxyPort (note the "s") per the Swarm proxy documentation. Please let me know if I've misunderstood any of this.

            Show
            basil Basil Crow added a comment - Great, I'm glad you were able to figure this out! There is some documentation for using Swarm with proxies here . I'm not very familiar with proxies or cookies with the Secure attribute, but from a quick Google search I gather that A cookie with the Secure attribute is sent to the server only with an encrypted request over the HTTPS protocol, never with unsecured HTTP, and therefore can't easily be accessed by a man-in-the-middle attacker. I am reticent to add support for arbitrary headers. It seems fairly outside the scope of what the Swarm client is meant to do. It is not meant to be a general purpose utility like curl(1) but rather just a wrapper around the Remoting JAR, and its proxy support matches that of Remoting. I would be willing to reconsider this position if other users express an interest and can demonstrate a common use case that requires this. As far as your specific issue is concerned, a proxy seems like the right approach to add custom headers, but it seems like your particular proxy configuration isn't compatible with how Jenkins sets the JSESSIONID cookie. So in my opinion the most appropriate solution would be to make your proxy configuration compatible by enabling TLS on your proxy server and setting -Dhttps.proxyHost and -Dhttps.proxyPort (note the "s") per the Swarm proxy documentation. Please let me know if I've misunderstood any of this.
            Hide
            katzdm Daniel Katz added a comment -

            Hey Basil - After reading up on Jenkins API tokens, I was able to make this work for our use case! I think we can safely close this - Thanks for your help with debugging!

            Show
            katzdm Daniel Katz added a comment - Hey Basil - After reading up on Jenkins API tokens, I was able to make this work for our use case! I think we can safely close this - Thanks for your help with debugging!

              People

              Assignee:
              basil Basil Crow
              Reporter:
              katzdm Daniel Katz
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: