How to generate an API Token when Jenkins is configured with SAML authentication

Hi,

We are running the Jenkins with the SAML authentication. Now, we are trying to extract build user info from Jenkins buildURL xmi path by authenticating with the jenkins server. I created api token using my user and now using it for every build to communicate with buildURL job.

Is there any way, we can create a common api credential to authenticate with Jenkins. Or any another method to authenticate with the jenkins api instead of using personal api token.

Thanks

not really, each auth plugin creates and manages users on their own, and afaik saml doesn’t provide a way to create a local user. Some have had luck switching to local auth, creating a user, then switching back

You could make a custom plugin (there are a few plugins already that extract some of the build cause info into env variables) or a shared library function that calls User (Jenkins core 2.433 API). and returns whatever info you need.

Thanks @halkeye for your reply.
Yeah, I thought about the switching but didn’t find any admin user. So, I’m not sure how to login if SAML is not there and don’t want to test the luck on it. :slight_smile:

I tried some available plugin like “build user vars” but the plugin not able to capture the user email address when build is trigger by SCM webhook. So, still need to get build user info from the Jenkins buildurl api.

I will have a look around further if able to do some work around.

those seem mutually exclusive. if its triggered by scm, then the “user” is scm. if its triggered by a user, then its a user.

Do you mean you want the email of the last scm commit? you can do something like script { email = sh(script: "git show -s --format='%ae' HEAD", returnStdout: true).trim() }

Yes right, I’m using this plugin “https://plugins.jenkins.io/build-user-vars-plugin/” which is using the calls Class User which you mentioned but when the user is SCM, it’s not able to get the details as trigger by SCM instead of Jenkins User.

Currently, I’m using the api token to get the xml data from Jenkins buildURL path and trim to extract the user info (name & email) to send some like vuln/failed when build is trigger by SCM. Each commit is trigger the build and get the details from the commitID which is available in Jenkins buildURL xml/json path .

Not sure, is there any better way to extract the SCM details rather than hitting the jenkins api.

If I am understanding this correctly, you are trying to read cause data for builds from outside Jenkins. This is exactly what API tokens are designed to do, however an alternative is to PUSH the data into some sort of a database and then query it there

To expand on the answer given by @halkeye.

Some have had luck switching to local auth, creating a user, then switching back

We do a 2 stage Jenkins build in Kubernetes using Helm and Helm YAML Templates.

Jenkins install stages:

  1. helm upgrade --install ... using Helm values files that use JCASC configure Jenkins security realm to local and creates users and configures roles for a local admin and a local limited user account. Documentation for this can be found in the JCASC docs.

    • The Helm install uses JCASC Groovy scripts that run on Jenkins during startup to generate tokens for the created local users and store them as kubernetes secrets.

      ---
      controller:
        JCasC:
          configScripts:
            jenkins-groovy-user-tokens: |
              groovy:
                - script: |
                    import hudson.model.*;
                    import jenkins.model.*;
                    import jenkins.security.*;
                    import jenkins.security.apitoken.*;        
                    import groovy.json.JsonSlurper;
                    import groovy.json.JsonOutput;
                    import java.io.*;
                    import java.net.*;
      
                    def env = System.getenv();
                    def userName = env.JENKINS_SERVICE_ACCOUNT;
                    def tokenName = 'service-token';
                    jlc = JenkinsLocationConfiguration.get();
      
                    def user = User.get(userName, false);
                    if ( user != null ) {
                      def apiTokenProperty = user.getProperty(ApiTokenProperty.class);
                      ApiTokenProperty apiToken = user.getProperty(jenkins.security.ApiTokenProperty.class);
                      if ( !apiTokenProperty.getTokenList().name.contains(tokenName) ) {
                        def result = apiTokenProperty.tokenStore.generateNewToken(tokenName);
                        user.save();
      
                        def json = JsonOutput.toJson([action: 'config', instance: env.JENKINS_NAME, url: jlc.getUrl(), key: result.plainValue]);
                        File file = new File("/var/jenkins_home/jobs/token.json");
                        file.write(json);
                      }
                    }
      
    • The Helm install also creates an init container that runs a Bash script that reads /var/jenkins_home/jobs/token.json from the Jenkins container after it is created and creates a kubernetes secret.

      TOKEN=$(kubectl exec $target -c=jenkins -n $K8S_NAMESPACE'] -- bash -c "cat /var/jenkins_home/jobs/token.json" | jq -r '.key')
      [[ -n "$TOKEN" ]] && [[ "$TOKEN" != null ]] && kubectl create secret generic jenkins-user-token -n $K8S_NAMESPACE --from-literal="token=$TOKEN" --save-config --dry-run=client -o yaml | kubectl apply -f -
      
  2. helm upgrade --install ... using Helm values files that use JCASC configure Jenkins security realm to saml and configures role based authorization roles for specified groups that exist in the external SAML DB. Documentation for this can be found in the JCASC docs.

To use the local user and api token from a remote server you need to either know the token or have access to it via Kubernetes.

  1. Authenticate to Jenkins and get a crumb using bash and curl:

    CRUMB=$(curl --location --insecure \
      --user user_jenkins:$(kubectl get secrets jenkins-user-token -o json | jq -r '.data.token' | base64 -d) \
      --url 'https://jenkins.company.com/jenkins/crumbIssuer/api/json' | jq -r '.crumb')
    
  2. Use the crumb and the token to do something like running an existing job using bash and curl:

    curl -X POST -L -H $CRUMB \
      --user user_jenkins:$(kubectl get secrets jenkins-user-token -o json | jq -r '.data.token' | base64 -d) \
      https://jenkins.company.com/jenkins/job/nodejs/job/main/buildWithParameters
    

This is not ALL the code but it is the important parts.