How to reuse Jenkins credentials without masking the PASSWORD in withCredentials.usernamePassword? - jenkins

Background
I'm using scripted pipelines and Shared Libraries.
All the implementation we have is under the src directory where I reuse the reference in pipelines:
def static myFunction(steps, context) {
steps.withCredentials([steps.usernamePassword(
credentialsId: 'credentialsId',
usernameVariable: 'GITHUB_USERNAME',
passwordVariable: 'GITHUB_PASSWORD')]) {
// use of steps.env.GITHUB_PASSWORD
}
}
I need to make 2 API calls to Github Enterprise with the same Credentials, which is set as the UsernamePassword credentials
Although the first call works as expected, the second call fails because of the env.GITHUB_PASSWORD value is masked
Details
As described in https://wiki.jenkins.io/display/JENKINS/Credentials+Binding+Plugin, the problem might be related to how the Credentials binding is masked when used more than once. That is, once we use ${env.PASSWORD} once, it will mask all the uses of the same value.
Detail
I'm using curl to and I need to generate the URL
def teamMembersApi = sh(curl -H 'Authorization: token ${env.PASSWORD}' ${githubRepoApi}")
The response of this call is another API URL, which I created another URL with the "teamMembersApi". So, making the second call...
def teamMembers = sh("curl -H 'Authorization: token ${env.PASSWORD}' ${teamMembersApi}")
At this point, the value of ${env.PASSWORD} is masked and, as a consequence, the second call fails because of invalid credentials
Questions
As I understand, this is a result of the "masking" of values when accessed via any method that will cause a "toString()" will make it not available for reuse in Strings...
How can I reuse the same credentials, even when they are eligible to be masked?
Verifications
I tried using 2 blocks of steps.withCredentials
I tried using the httpRequest step to not refer to variable
Using httpRequest, I got MalformedURLException with a clearly well-formed URL... I made sure the URL was in String format and has the protocol...
java.net.MalformedURLException: no protocol: https://github.company.com/org/repo

You can use the username/password inside withCredentials block for any times. But
keep in mind, the username/password can only survive inside withCredentials block.
I used the same username/password for twice in following code and it worked well.
node('docker') {
withCredentials([steps.usernamePassword(
credentialsId: 'ba2e4f46-56f1-4467-ae97-17b356d7f854',
usernameVariable: 'JENKINS_USERNAME',
passwordVariable: 'JENKINS_PASSWORD')]) {
def log = sh(
returnStdout: true,
script: "curl -u ${env.JENKINS_USERNAME}:${env.JENKINS_PASSWORD} -k ${env.BUILD_URL}" + 'consoleText').trim()
def pipelineSteps = sh(
returnStdout: true,
script: "curl -u ${env.JENKINS_USERNAME}:${env.JENKINS_PASSWORD} -k ${env.BUILD_URL}" + 'flowGraphTable').trim()
echo '\n## build log ##\n' + log
echo '\n## pipelineSteps ##\n' + pipelineSteps
}
echo "JENKINS_USERNAME: ${env.JENKINS_USERNAME}"
// print JENKINS_USERNAME: null
// because JENKINS_USERNAME's lifecycle is limited inside withCredentials blok.
}
Another issue in your code, if you did not specify option returnStdout: true for step sh, it should return null. Example: def output = sh('command'), output will be null

Related

How to set Jenkins auth2 credential from String?

I'm using the Jenkins parametrised remote trigger plugin to call Jenkins server (A) from our Jenkins server (B). It's been working successfully using the Jenkins credential manager, but I'm now wishing to fetch it at run time and then pass in that fetched credential directly as a string, rather than have it stored in Jenkins.
Essentially I'm trying to get a String into an auth2 object to use in my remote trigger.
Existing code:
triggerRemoteJob job: "${REMOTE_JOB}",
parameters: "REDACTED",
auth: CredentialsAuth(credentials: "cred-id")
What I'm working towards:
def fetchedCred = getFromThirdPartyResource()
triggerRemoteJob job: "${REMOTE_JOB}",
parameters: "REDACTED",
auth: CredFromString(fetchedCred)
The solution really depends on the type of Authentication method you intend to use. Since you are using CredentialsAuth I assume you plan on using Basic Auth. In Basic Auth you will be passing the Authorization header like below
Authorization: Basic username:password (username:password will be base64 encoded)
So in order to get around your issue, you can use TokenAuth instead of CredentialsAuth. If you look at the code here TokenAuth is also generating a Basic Auth header with the provided apiToken and userName. Hence you can use something like the below.
pipeline {
agent any
stages {
stage('Test') {
steps {
script {
def password = new hudson.util.Secret('admin')
def username = 'admin'
triggerRemoteJob job: "http://localhost:8080/job/test", auth: TokenAuth(apiToken: password, userName: username)
}
}
}
}
}

how to load jenkins username and password as env vars in a jenkins file

in the Jenkins credentials I have several types of credentials.
One of them, called my_password is of the type "Secret Text", in which in a Jenkinsfile, I can access like so:
environment {
my_env_var = credentials('my_password')
}
Now I created a credential of type "Username with Password" called user_and_pass in which I can set up both fields in the same credential.
How can I access both params at the same time, and load them into env variables?
I was thinking something like:
environment {
my_user = credentials('user_and_pass').someFunctionThatReturnsUser()
my_pass = credentials('user_and_pass').someFunctionThatReturnsPass()
}
but I don't think it works like that.
When you get back the credentials from a "username and password" secret, you get one string with a username and a password separated by a colon in the format username:password.
Check if using usernamePassword works, as in here.
It is from the Jenkins Credentials Binding Plugin.
withCredentials(
[usernamePassword(credentialsId: 'mycreds',
usernameVariable: 'USERNAME',
passwordVariable: 'PASSWORD')]) {
sh 'cf login some.awesome.url -u $USERNAME -p $PASSWORD'
}
In Jenkins dashboard, Click on Manage Jenkins, Click on Manage Credentials under Security tab, click on system to create Global credentials. This Credential ID (SSH-Centos7 in my case) can be used as below:
stage('Example SSH Username with password') {
environment {
SSH_CREDS = credentials('SSH-Centos7')
}
Recent documentation available at Jenkins official documentation
As far as I know, all we have two methods to extract data from credential type Username and Password:
by the means of Groovy function withCredentials();
by the means of helper credentials().
withCredentials()
Syntax for extracting creds via withCredentials:
withCredentials([usernamePassword(credentialsId: 'your-credentials-id', passwordVariable: 'PASSWORD_VAR', usernameVariable: 'USERNAME')]) {
// your script could access $PASSWORD_VAR and $USERNAME_VAR
// as environment variables
//
// note: PASSWORD_VAR, USERNAME_VAR is just aliases, you may change it to whatever you like
}
If syntax looks too complicated and boring to you, use Pipeline Snippet Generator as follows.
credentials()
Syntax for extracting creds via credentials():
environment {
CREDS = credentials('your-credentials-id')
}
steps {
// your code can access
// username as $CREDS_USR
// and password as $CREDS_PSW
}
Which method to use?
It depends on credential type. For Username and Password you could use any of the methods - as you like.
credentials() helper supports the following types (end of 2022):
secret text;
username and password;
secret file.
For the rest of credentials types you have to use withCredentials().
Check out official docs for more details.

Jenkins: Accessing other plugins from Active Choices Parameter groovy script

I'm quite new to Jenkins, Groovy and all that, so forgive me if this sounds dumb.
I'm using the Active Choices plugin, and from one of the AC Parameters inside the Groovy script I want to use a different plugin - Artifactory, to fetch a file and display each line inside it as an option.
try {
def server = Artifactory.newServer url: 'http://localhost:8081/artifactory/', username: 'user', password: 'pass'
def downloadSpec = """{
"files": [
{
"pattern": "example-repo-local/file.txt",
"target": "example/"
}
]
}"""
server.download(downloadSpec)
String text = readFile("example/file.txt")
return text.tokenize("\n")
} catch (Exception e) {
return [e]
}
However, the Active Choices Parameter doesn't seem to recognize other plugins, and it can't find the Artifactory property:
groovy.lang.MissingPropertyException: No such property: Artifactory for class: Script1
My question is - do I need to import the plugin somehow? If so, how do I determine what to import?
There is an option to also specify an "Additional classpath" near an Active Choice Parameter, but the plugin contains 75 jar files in its WEB-INF/lib directory. (just specifying the artifactory.jar one doesn't seem to change anything)
Just a note - the Pipeline recognizes the Artifactory plugin and it works fine - I can successfully connect and retreive a file and read it.
I can't fine any possibility to run Artifactory plugin in reasonable way. So i thing better option is use curl, and Artifactory API. For example my Active Choices Parameter based on Json file from Artifactory;
import groovy.json.JsonSlurper
def choices = []
def response = ["curl", "-k", "https://artifactory/app/file.json"].execute().text
def list = new JsonSlurper().parseText( response )
list.each { choices.push(it.name) }
return choices

Jenkins Pipeline passing password parameter to downstream job

I want to pass a value, from the Password Parameter plugin, in a Jenkins Pipeline job, to another freestyle job, to be used for login. I don't want to see it in the output or anywhere else. I can do it between two freestyle jobs but it seems that the pipeline is a bit different.
Even if I'm able to send as a string, it would be visible in the Parameters tab or the Environment Variables tab.
Does anyone have any idea how this could be achieved?
I've spent hours trying different solutions for the same problem as you've had and here is the final solution, which worked for me:
In your pipeline script:
stages {
stage("Do something with credentials and pass them to the downstream job") {
steps {
build job: 'your/jobname/path', parameters: [
[$class: 'hudson.model.PasswordParameterValue', name: 'PASSWORD', value: env.PASSWORD],
[$class: 'TextParameterValue', name: 'USERNAME', value: env.USERNAME]
]
}
}
The trick is to use hudson.model.PasswordParameterValue class when passing password parameter to downstream (Freestyle) job, but you must use then the same class for parameter definition in your main pipeline (parent job) in order to make it work.
For example in your pipeline job you would configure password parameter:
configure {
it / 'properties' / 'hudson.model.ParametersDefinitionProperty' / 'parameterDefinitions' << 'hudson.model.PasswordParameterDefinition' {
name('PASSWORD')
description('My password')
}
}
You should make sure that parent and child job both are using password parameters. Then, this parameters tab will mask you password. Making build parameters as password parameter will not mask passwords in environment variables tab, for that you need to enable mask password in child and parent job configuration or use Inject passwords to the build as environment variables and enable mask password.
You should use credentials plugin, which in pipeline you write with withCredentials block. For example:
withCredentials([usernamePassword(credentialsId: 'abcd1234-56ef-494f-a4d9-d5b5e8ac357d',
usernameVariable: 'USERNAME',
passwordVariable: 'PASSWORD')])
{
echo 'username='+USERNAME
echo 'password='+PASSWORD
}
where abcd1234-56ef-494f-a4d9-d5b5e8ac357d is the id of credentials you have in jenkins, and of course, as long as you don't echo the variables (as I did in the example obviously for demonstration purposes), username and password are not visible.
You can trigger you downstream job with the help of below plugin
Parameterized+Trigger+Plugin

Jenkins: trigger a job with buildWithParameters gives white/blank screen

I am using Jenkins version 1.567. I am trying to launch a Jenkins job from a URL by calling the buildWithParameters option.
My URL is set up like:
http://myjenkinsserver:8090/job/pc_test/buildWithParameters?token=PC123&Parm1=1
The job triggers perfectly well, however, I am presented with a blank, white screen. So I do not know if the job has succeeded or not unless I manually logon to Jenkins. This did not used to happen. Previously it would show the project page and I would be able to see the status of my job.
But I am not sure what has changed to make a blank page appear.
Can anyone suggest a solution whereby I can trigger the job via a URL and then see the results of the job?
Thanks.
A suitable workaround is using the build-with-parameters plugin.
Change the URL to:
http://myjenkinsserver:8090/job/pc_test/parambuild?token=PC123&Parm1=1
This will show you a page with the chosen build parameters. You need to confirm by clicking the Build button. Afterwards you are redirected to the project page.
You need to make a POST request to http://myjenkinsserver:8090/job/pc_test/build with json (value must be url encoded) parameter in the request body. The body for your example is (not url encoded yet so it's easy to read):
json={"parameter": {"name": "Parm1", "value": "1"}, "statusCode": "303", "redirectTo": "."}
and here is url encoded version(use this one):
json=%7B%22parameter%22%3A%20%7B%22name%22%3A%20%22Parm1%22%2C%20%22value%22%3A%20%221%22%7D%2C%20%22statusCode%22%3A%20%22303%22%2C%20%22redirectTo%22%3A%20%22.%22%7D
Also make sure that you set Content-Type: application/x-www-form-urlencoded
Full example using curl:
curl --data "json=on=%7B%22parameter%22%3A%20%7B%22name%22%3A%20%22Parm1%22%2C%20%22value%22%3A%20%221%22%7D%2C%20%22statusCode%22%3A%20%22303%22%2C%20%22redirectTo%22%3A%20%22.%22%7D" http://myjenkinsserver:8090/job/pc_test/build --verbose
Once you trigger the job, you can check its status using the Jenkins API.
See http://your-jenkins-host/api/ for more details. Look into the documentations.
I hope this helps.
This is an old question, but there is still fairly sparse information on this.
This is a sample of adding a "Deploy" button to the Build Description on Jenkins 2.89.4:
pipeline {
agent any
stages {
stage('Sample') {
steps {
sh 'echo "Sample"'
}
}
post {
success {
script {
currentBuild.description = "<form method='post' action='/job/sine-deploy/build'><input name='json' type='hidden' value=\"{'parameter': {'name': 'TRIGGERED_FROM_BUILD', 'runId': '${JOB_NAME}#${BUILD_NUMBER}'}, 'statusCode': '303', 'redirectTo': '/job/sine-deploy/'}\" /><input name='Submit' type='submit' value='Deploy' class='submit-button primary' /></form>"
}
}
}
}
}
Safe HTML needs to be turned on for the form to work.

Resources