HTTP-запрос от конвейера Jenkins с аутентификацией прокси и сертификатом клиента - PullRequest
0 голосов
/ 08 февраля 2019

Мне нужно сделать HTTP-вызов из моего конвейера Jenkins на внешний ресурс HTTPS, для которого требуется сертификат клиента.Кроме того, Дженкинс находится за корпоративным прокси-сервером, который требует аутентификации.

После довольно долгой борьбы мне удалось заставить работать автономный код, используя Apache HTTP-клиент.Проблема заключается в том, что клиентские HTTP-классы Apache не могут быть сериализованы, и в результате код не работает в Jenkins.Вот мой отличный код (упрощенно):

KeyStore keyStore = KeyStore.getInstance("PKCS12")
keyStore.load(new ByteArrayInputStream(clientPfxBytes), "".toCharArray())
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
keyManagerFactory.init(keyStore, "".toCharArray())
SSLContext context = SSLContext.getInstance("TLS")
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom())
connection.setSSLSocketFactory(context.getSSLSocketFactory())

HttpHost proxy = new HttpHost(proxyHost, proxyPort, proxyProtocol)
HttpClientBuilder builder = HttpClientBuilder.create().setProxy(proxy).setSSLSocketFactory(new SSLConnectionSocketFactory(context))

CredentialsProvider credProvider = new BasicCredentialsProvider()
credProvider.setCredentials(
        new AuthScope(proxyHost, proxyPort),
        new UsernamePasswordCredentials(proxyUser, proxyPass)
)

CloseableHttpClient client = builder.build()

def url = "https://my.target.url/with/path"
URIBuilder builder = new URIBuilder(url)
builder.setParameter("name", "value")
HttpPost request = new HttpPost(builder.build())
request.addHeader("x-customer-header", "custom-value")
request.addHeader("Content-Type", "application/xml")
request.setEntity(new StringEntity(inputXml))

HttpResponse response = client.execute(request)
int result = response.statusLine.statusCode

Как я указал, он работает правильно автономно, работает как консольное приложение, однако, когда я пытаюсь выполнить его из конвейера Jenkins, я получаю NotSerializableException:

an exception which occurred:
    in field groovy.lang.Reference.value
    in object groovy.lang.Reference@16eeaf
    in field WorkflowScript$_getHttpClient_closure1.builder
    in object WorkflowScript$_getHttpClient_closure1@3739c8
    in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.closures
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@4c1866
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@4c1866
Caused: java.io.NotSerializableException: org.apache.http.impl.client.HttpClientBuilder
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:926)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
    at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
    at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
    at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
    at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at java.util.HashMap.internalWriteEntries(Unknown Source)
    at java.util.HashMap.writeObject(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor177.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.jboss.marshalling.reflect.JDKSpecific$SerMethods.callWriteObject(JDKSpecific.java:156)
    at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:191)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1028)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1082)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1040)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:920)
    at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58)
    at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)
    at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverWriter.lambda$writeObject$0(RiverWriter.java:144)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:121)
    at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverWriter.writeObject(RiverWriter.java:143)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:482)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:458)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgramIfPossible(CpsThreadGroup.java:445)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:372)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Итак, вопрос в том, как я могу сделать этот звонок?Либо что-то изменить в моем конвейере Jenkins, либо использовать совершенно другой подход.У меня есть полный контроль над установкой Jenkins, и я могу вносить в нее любые необходимые изменения.

Если больше ничего не работает, мне придется написать плагин для этой связи, но я бы предпочел избежатьидти по этому пути.

1 Ответ

0 голосов
/ 13 марта 2019

Потратив на это много времени, я до сих пор не нашел ответа.Я закончил тем, что написал свой собственный плагин Jenkins Steps для выполнения этой HTTP-коммуникации.Для тех, кто заинтересован, вот ссылка на соответствующую документацию о том, как написать такие плагины: https://github.com/jenkinsci/workflow-step-api-plugin

...