Does anybody know how to create a new jenkins (2.8) credentials (f.e for a git access) via API or POST request in Jenkins? I have tried to use this code (from another stackoverflow topic), but it does nothing:
import json
import requests
def main():
data = {
'credentials': {
'scope': "GLOBAL",
'username': "jenkins",
'privateKeySource': {
'privateKey': "-----BEGIN RSA PRIVATE KEY-----\nX\n-----END RSA PRIVATE KEY-----",
'stapler-class': "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource"
},
'stapler-class': "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
}
}
payload = {
'json': json.dumps(data),
'Submit': "OK",
}
r = requests.post("http://%s:%d/credential-store/domain/_/createCredentials" % (localhost, 8080), data=payload)
if r.status_code != requests.codes.ok:
print r.text
I did it this way:
java -jar /tmp/jenkins-cli.jar -s http://localhost:8080/ \
groovy /tmp/credentials.groovy id username password
credentials.groovy
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.common.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.plugins.credentials.impl.*
domain = Domain.global()
store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
usernameAndPassword = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
args[0],
"",
args[1],
args[2]
)
store.addCredentials(domain, usernameAndPassword)
I ran into the same issue and after a bit of digging/testing it seems you need to change this
/credential-store/domain/_/createCredentials
to this
/credentials/store/system/domain/_/createCredentials
It's doesn't work: /credential-store/domain/_/api/json
You have to use this url: /credentials/store/system/domain/_/api/json
Related
I am using this mssql Ballerina package to connect to my Azure SQL database.
Error:
error: Error in SQL connector configuration: Failed to initialize pool: Connection reset ClientConnectionId:5d5b4f8b-7e6e-43d0-bce3-5fe79e403088 Caused by :Connection reset ClientConnectionId:5d5b4f8b-7e6e-43d0-bce3-5fe79e403088 Caused by :Connection reset
at ballerinax.mssql.1:createClient(Client.bal:173)
ballerinax.mssql.1:init(Client.bal:49)
viggnah.test_apis.0.$anonType$_1:$get$test(testAPI.bal:45)
Code:
import ballerina/sql;
import ballerina/http;
import ballerinax/mssql.driver as _;
import ballerinax/mssql;
configurable int servicePort = 9090;
configurable string user = "admin#my-server";
configurable string host = "my-server.database.windows.net";
configurable string database = "my-db";
configurable int dbPort = 1443;
configurable string password = "***";
service / on new http:Listener(servicePort) {
resource function get test(string id) returns error? {
mssql:Client|sql:Error dbClient = new(host=host, user=user, password=password, database=database, port=dbPort);
if dbClient is error {
return dbClient;
}
}
}
I created azure SQL database with following firewall rules:
Added clint IP to the firewall. I run the below code to connect Azure SQL database with Ballerina.
import ballerina/sql;
import ballerinax/mssql.driver as _;
import ballerinax/mssql;
string clientStorePath = "/path/to/keystore.p12";
string trustStorePath = "/path/to/truststore.p12";
mssql:Options mssqlOptions = {
secureSocket: {
encrypt: true,
-trustServerCertificate: false,
key: {
path: clientStorePath,
password: "password"
},
cert: {
path: trustStorePath,
password: "password"
}
}
};
mssql:Client|sql:Error dbClient = new(host="<serverName>.database.windows.net", user="<username>", password="<password>", database="<dbName>", port=1433);
It connected successfully without any error.
Image for reference:
I try this another way using below code:
import ballerina/sql;
import ballerinax/mssql.driver as _;
import ballerinax/mssql;
mssql:Client|sql:Error dbClient = new(host="<serverName>.database.windows.net", user="<username>", password="<password>", database="<dbName>", port=1433);
By using above also my azure SQL database is connected successfully.
Image for reference:
It worked for me. Once check from your end.
curl -X PATCH -H "vmware-api-session-id: b00db39f948d13ea1e59b4d6fce56389" -H "Content-Type: application/json" -d '{"spec":{"cores_per_socket":0,"count":0,"hot_add_enabled":false,"hot_remove_enabled":false}}' https://{api_host}/rest/vcenter/vm/{vm}/hardware/cpu
I have the code for session id and URL , I need to map the code for -d part where inputs are to be provided like cpu count and all.
This should do it, so long as you're running on Java 11+
import groovy.json.JsonOutput
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
def body = [
spec: [
cores_per_socket : 0,
count : 0,
hot_add_enabled : false,
hot_remove_enabled: false
]
]
def payload = HttpRequest.BodyPublishers.ofString(JsonOutput.toJson(body))
HttpClient httpClient = HttpClient.newHttpClient()
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{api_host}/rest/vcenter/vm/{vm}/hardware/cpu"))
.method("PATCH", payload)
.header("Content-Type", "application/json")
.header("vmware-api-session-id", "b00db39f948d13ea1e59b4d6fce56389")
.build();
HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
println response.body()
I want to implement rbac based auth in airflow with keycloak. Can someone help me with it.
I have creaed the webserver.config file and I am using docker to up the airflow webserver.
from airflow.www_rbac.security import AirflowSecurityManager
from flask_appbuilder.security.manager import AUTH_OAUTH
import os
import json
AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION_ROLE = "Admin"
OAUTH_PROVIDERS = [
{
'name': 'keycloak',
'icon': 'fa-user-circle',
'token_key': 'access_token',
'remote_app': {
'base_url': 'http://localhost:8180/auth/realms/airflow/protocol/openid-connect/',
'request_token_params': {
'scope': 'email profile'
},
'request_token_url': None,
'access_token_url': 'http://localhost:8180/auth/realms/airflow/protocol/openid-connect/token',
'authorize_url': 'http://localhost:8180/auth/realms/airflow/protocol/openid-connect/auth',
'consumer_secret': "98ec2e89-9902-4577-af8c-f607e34aa659"
}
}
]
I have also set the ariflow.cfg
rbac = True
authenticate = True
But still its not redirecting to the keycloak when the airflow is loaded.
I use :
docker build --rm --build-arg AIRFLOW_DEPS="datadog,dask" --build-arg PYTHON_DEPS="flask_oauthlib>=0.9" -t airflow .
and
docker run -d -p 8080:8080 airflow webserver
TO execute it.
I maybe coming late to this one and my answer may not work exactly as I'm using a different auth provider, however it's still OAuth2 and in a previous life I used Keycloak so my solution should also work there.
My answer makes use of authlib (At time of writing newer versions of airflow have switched. I am on 2.1.2)
I've raised a feature request against Flask-AppBuilder which Airflow uses as it's OAuth hander should really take care of things when the scope includes openid (you'd need to add this to your scopes)
From memory keycloak returns id_token along side the access_token and refresh_token and so this code simply decodes what has already been returned.
import os
import logging
import re
import base64
import yaml
from flask import session
from airflow.www.security import AirflowSecurityManager
from flask_appbuilder.security.manager import AUTH_OAUTH
basedir = os.path.abspath(os.path.dirname(__file__))
MY_PROVIDER = 'keycloak'
class customSecurityiManager(AirflowSecurityManager):
def oauth_user_info(self, provider, resp):
if provider == MY_PROVIDER:
log.debug("{0} response received : {1}".format(provider,resp))
id_token = resp["id_token"]
log.debug(str(id_token))
me = self._azure_jwt_token_parse(id_token)
log.debug("Parse JWT token : {0}".format(me))
if not me.get("name"):
firstName = ""
lastName = ""
else:
firstName = me.get("name").split(' ')[0]
lastName = me.get("name").split(' ')[-1]
return {
"username": me.get("email"),
"email": me.get("email"),
"first_name": firstName,
"last_name": lastName,
"role_keys": me.get("groups", ['Guest'])
}
else:
return {}
log = logging.getLogger(__name__)
AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Guest"
AUTH_ROLES_SYNC_AT_LOGIN = True
CSRF_ENABLED = True
AUTH_ROLES_MAPPING = {
"Airflow_Users": ["User"],
"Airflow_Admins": ["Admin"],
}
OAUTH_PROVIDERS = [
{
'name': MY_PROVIDER,
'icon': 'fa-circle-o',
'token_key': 'access_token',
'remote_app': {
'server_metadata_url': WELL_KNOWN_URL,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'client_kwargs': {
'scope': 'openid groups',
'token_endpoint_auth_method': 'client_secret_post'
},
'access_token_method': 'POST',
}
}
]
SECURITY_MANAGER_CLASS = customSecurityManager
Ironically the Azure provider already returns id_token and it's handled so my code makes use of that existing parsing
The code decodes id_token
Note you can turn on debug logging with the environmental variable AIRFLOW__LOGGING__FAB_LOGGING_LEVEL set to DEBUG.
If you switch on debug logs and see an entry like the following (note the id_token) you can probably use the code I've supplied.
DEBUG - OAUTH Authorized resp: {'access_token': '<redacted>', 'expires_in': 3600, 'id_token': '<redacted>', 'refresh_token': '<redacted>, 'scope': 'openid groups', 'token_type': 'Bearer', 'expires_at': <redacted - unix timestamp>}
The id_token is in 3 parts joined by a full stop . The middle part contains the user data and is simply base64 encoded
Here's a example program that generates the error:
import urllib3
import certifi
from google.auth.transport.urllib3 import AuthorizedHttp
from google.oauth2 import service_account
import boto3
from pprint import pprint
import json
# parameters
JSON_SERVICE_ACCOUNT_FILE = "/home/mwilbert/gcp/matt-vm-service-account.json"
SCOPES = [
'https://www.googleapis.com/auth/devstorage.read_write',
'https://www.googleapis.com/auth/compute'
]
TEST_PROJECTID = 'mwilbert-workspace'
TEST_FULLCHAIN_FILE = '/etc/letsencrypt/live/fake.mapgeo.io/fullchain.pem'
TEST_PRIVKEY_FILE = '/etc/letsencrypt/live/fake.mapgeo.io/privkey.pem'
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',ca_certs=certifi.where())
credentials = service_account.Credentials.from_service_account_file(JSON_SERVICE_ACCOUNT_FILE)
scoped_credentials = credentials.with_scopes(SCOPES)
authed_http = AuthorizedHttp(scoped_credentials,http)
requestBody = {
"name":"deleteme",
"description": "fake domain cert",
"certificate": TEST_FULLCHAIN_FILE,
"privateKey": TEST_PRIVKEY_FILE,
}
rb = json.dumps(requestBody)
url = 'https://www.googleapis.com/compute/v1/projects/%s/global/sslCertificates' % TEST_PROJECTID
r = authed_http.urlopen('POST',
url,
headers={'Content-Type': 'application/json'},
body=rb)
response = json.loads(r.data)
pprint(response)
However if I pass the same arguments to gcloud
gcloud compute ssl-certificates create deleteme
--certificate=/etc/letsencrypt/live/fake.mapgeo.io/fullchain.pem
--private-key=/etc/letsencrypt/live/fake.mapgeo.io/privkey.pem
--description="fake domain cert" --project=mwilbert-workspace
from the same terminal session the certificate is created. The certificate is in .PEM format.
Has anyone gotten this call to work? If so, any pointers?
I have a jenkins job and I want to use it's lastSuccessfulBuild number in my Build Flow groovy script.
I can get the last successful build number from Jenkins api at:
http://{JENKINS_DOMAIN}/job/{JOB_NAME}/lastSuccessfulBuild/buildNumber
I tried using groovy's RESTClient in my Build Flow groovy script but when importing the groovyx.net.http.RESTClient library I get syntax error.
Does any one know away of getting around this error or getting the api result in some other way?
maybe this will help you:
import hudson.model.Build;
println(build.getProject().getLastSuccessfulBuild())
for example we have simple build flow groovy script building only one item "JobA". If we want check and print its last successful build we can write such script:
import hudson.model.Build;
def buildA = build("jobA")
println(buildA.getProject().getLastSuccessfulBuild())
Possibly a little overkill, but you can use HttpClient, as all you need is a get request on the url.
Here's one I knocked up from some code I had lying around
Tested it on our own Jenkins instance which has basic auth over ssl.
import org.apache.http.HttpResponse
import org.apache.http.HttpVersion
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.params.ClientPNames
import org.apache.http.conn.ClientConnectionManager
import org.apache.http.conn.scheme.PlainSocketFactory
import org.apache.http.conn.scheme.Scheme
import org.apache.http.conn.scheme.SchemeRegistry
import org.apache.http.conn.ssl.SSLSocketFactory
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.impl.conn.PoolingClientConnectionManager
import org.apache.http.params.BasicHttpParams
import org.apache.http.params.HttpConnectionParams
import org.apache.http.params.HttpParams
import org.apache.http.params.HttpProtocolParams
class LastSuccessfulBuild {
def static main(args) {
println new LastSuccessfulBuild().connect("your.jenkins.com", "443", "/path/to/job/YourJob/lastSuccessfulBuild/buildNumber", "your.user:your-password")
}
def connect(host, port, path, auth) {
def url = new URL("https", host, Integer.parseInt(port), path)
HttpClient client = createClient()
HttpGet get = new HttpGet(url.toURI())
get.setHeader("Authorization", "Basic ${auth.getBytes().encodeBase64().toString()}")
HttpResponse response = client.execute(get)
def status = response.statusLine.statusCode
if (status != 200) {
throw new IOException("Failed to get page, status: $response.statusLine")
}
return response.entity.content.text
}
def createClient() {
HttpParams params = new BasicHttpParams()
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1)
HttpProtocolParams.setContentCharset(params, "UTF-8")
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true)
SchemeRegistry registry = new SchemeRegistry()
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80))
registry.register(new Scheme("https",SSLSocketFactory.getSocketFactory(),443))
ClientConnectionManager ccm = new PoolingClientConnectionManager(registry)
HttpConnectionParams.setConnectionTimeout(params, 8000)
HttpConnectionParams.setSoTimeout(params, 5400000)
HttpClient client = new DefaultHttpClient(ccm, params)
return client
}
}