Skip to content

Commit 4c49f60

Browse files
fix: reimplement http authentification (#1098)
* fix: reimplement http authentification * fix: typo * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent 70408e2 commit 4c49f60

11 files changed

+677
-221
lines changed

src/main/java/io/jenkins/plugins/opentelemetry/backend/elastic/ElasticLogsBackendWithJenkinsVisualization.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@
1313
import java.util.logging.Logger;
1414

1515
import org.apache.commons.lang.StringUtils;
16-
import org.apache.hc.client5.http.auth.Credentials;
1716
import org.kohsuke.stapler.DataBoundConstructor;
1817
import org.kohsuke.stapler.DataBoundSetter;
1918
import org.kohsuke.stapler.QueryParameter;
19+
import org.kohsuke.stapler.interceptor.RequirePOST;
2020

2121
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
2222
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
2323
import com.google.errorprone.annotations.MustBeClosed;
2424

2525
import edu.umd.cs.findbugs.annotations.CheckForNull;
26-
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2726
import groovy.text.Template;
2827
import hudson.Extension;
2928
import hudson.Util;
@@ -34,7 +33,7 @@
3433
import io.jenkins.plugins.opentelemetry.TemplateBindingsProvider;
3534
import io.jenkins.plugins.opentelemetry.backend.ObservabilityBackend;
3635
import io.jenkins.plugins.opentelemetry.jenkins.CredentialsNotFoundException;
37-
import io.jenkins.plugins.opentelemetry.jenkins.JenkinsCredentialsToApacheHttpCredentialsAdapter;
36+
import io.jenkins.plugins.opentelemetry.jenkins.HttpAuthHeaderFactory;
3837
import io.jenkins.plugins.opentelemetry.job.log.LogStorageRetriever;
3938
import jenkins.model.Jenkins;
4039

@@ -60,9 +59,8 @@ public LogStorageRetriever newLogStorageRetriever(TemplateBindingsProvider templ
6059
logger.warning(MSG_ELASTICSEARCH_URL_IS_BLANK);
6160
throw new IllegalStateException(MSG_ELASTICSEARCH_URL_IS_BLANK);
6261
} else {
63-
Credentials credentials = new JenkinsCredentialsToApacheHttpCredentialsAdapter(elasticsearchCredentialsId);
6462
return new ElasticsearchLogStorageRetriever(
65-
this.elasticsearchUrl, disableSslVerifications, credentials,
63+
this.elasticsearchUrl, disableSslVerifications, elasticsearchCredentialsId,
6664
buildLogsVisualizationUrlTemplate, templateBindingsProvider);
6765
}
6866
}
@@ -129,6 +127,7 @@ public String getDisplayName() {
129127
return "Store pipeline logs In Elastic and visualize logs both in Elastic and through Jenkins";
130128
}
131129

130+
@RequirePOST
132131
public FormValidation doCheckElasticsearchUrl(@QueryParameter("elasticsearchUrl") String url) {
133132
if (StringUtils.isEmpty(url)) {
134133
return FormValidation.ok();
@@ -141,6 +140,7 @@ public FormValidation doCheckElasticsearchUrl(@QueryParameter("elasticsearchUrl"
141140
return FormValidation.ok();
142141
}
143142

143+
@RequirePOST
144144
public ListBoxModel doFillElasticsearchCredentialsIdItems(Item context,
145145
@QueryParameter String elasticsearchCredentialsId) {
146146
if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER)
@@ -153,8 +153,7 @@ public ListBoxModel doFillElasticsearchCredentialsIdItems(Item context,
153153
.includeCurrentValue(elasticsearchCredentialsId);
154154
}
155155

156-
@SuppressFBWarnings(value="RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT",
157-
justification="We don't care about the return value, we just want to check that the credentials are valid")
156+
@RequirePOST
158157
public FormValidation doCheckElasticsearchCredentialsId(Item context,
159158
@QueryParameter String elasticsearchCredentialsId) {
160159
if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER)
@@ -166,25 +165,24 @@ public FormValidation doCheckElasticsearchCredentialsId(Item context,
166165
return FormValidation.error("Elasticsearch credentials are missing");
167166
}
168167
try {
169-
new JenkinsCredentialsToApacheHttpCredentialsAdapter(elasticsearchCredentialsId)
170-
.getUserPrincipal().getName();
168+
new HttpAuthHeaderFactory(elasticsearchCredentialsId).createAuthHeader();
171169
} catch (CredentialsNotFoundException e) {
172170
return FormValidation.error("Elasticsearch credentials are not valid");
173171
}
174172
return FormValidation.ok();
175173
}
176174

175+
@RequirePOST
177176
public FormValidation doValidate(@QueryParameter String elasticsearchUrl,
178177
@QueryParameter boolean disableSslVerifications, @QueryParameter String elasticsearchCredentialsId) {
179178
FormValidation elasticsearchUrlValidation = doCheckElasticsearchUrl(elasticsearchUrl);
180179
if (elasticsearchUrlValidation.kind != FormValidation.Kind.OK) {
181180
return elasticsearchUrlValidation;
182181
}
183-
Credentials credentials = new JenkinsCredentialsToApacheHttpCredentialsAdapter(elasticsearchCredentialsId);
184182
try (ElasticsearchLogStorageRetriever elasticsearchLogStorageRetriever = new ElasticsearchLogStorageRetriever(
185183
elasticsearchUrl,
186184
disableSslVerifications,
187-
credentials,
185+
elasticsearchCredentialsId,
188186
ObservabilityBackend.ERROR_TEMPLATE,
189187
TemplateBindingsProvider.empty())) {
190188

src/main/java/io/jenkins/plugins/opentelemetry/backend/elastic/ElasticsearchLogStorageRetriever.java

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
4444
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
4545
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
46+
import org.apache.hc.core5.http.Header;
4647
import org.apache.hc.core5.http.HttpHost;
4748
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
4849
import org.apache.hc.core5.reactor.IOReactorConfig;
@@ -74,6 +75,7 @@
7475
import io.jenkins.plugins.opentelemetry.backend.ElasticBackend;
7576
import io.jenkins.plugins.opentelemetry.backend.ObservabilityBackend;
7677
import io.jenkins.plugins.opentelemetry.jenkins.CredentialsNotFoundException;
78+
import io.jenkins.plugins.opentelemetry.jenkins.HttpAuthHeaderFactory;
7779
import io.jenkins.plugins.opentelemetry.job.log.LogStorageRetriever;
7880
import io.jenkins.plugins.opentelemetry.job.log.LogsQueryResult;
7981
import io.jenkins.plugins.opentelemetry.job.log.LogsViewHeader;
@@ -109,7 +111,7 @@ public class ElasticsearchLogStorageRetriever implements LogStorageRetriever, Cl
109111
private final TemplateBindingsProvider templateBindingsProvider;
110112

111113
@NonNull
112-
final Credentials elasticsearchCredentials;
114+
final String elasticsearchCredentialsId;
113115
@NonNull
114116
final String elasticsearchUrl;
115117
@NonNull
@@ -127,24 +129,21 @@ public class ElasticsearchLogStorageRetriever implements LogStorageRetriever, Cl
127129
@MustBeClosed
128130
public ElasticsearchLogStorageRetriever(
129131
@NonNull String elasticsearchUrl, boolean disableSslVerifications,
130-
@NonNull Credentials elasticsearchCredentials,
132+
@NonNull String elasticsearchCredentialsId,
131133
@NonNull Template buildLogsVisualizationUrlTemplate, @NonNull TemplateBindingsProvider templateBindingsProvider) {
132134

133135
if (StringUtils.isBlank(elasticsearchUrl)) {
134136
throw new IllegalArgumentException("Elasticsearch url cannot be blank");
135137
}
136138

137139
this.elasticsearchUrl = elasticsearchUrl;
138-
this.elasticsearchCredentials = elasticsearchCredentials;
139-
BasicCredentialsProvider credentialsProvider = getCredentialsProvider(elasticsearchUrl,
140-
elasticsearchCredentials);
140+
this.elasticsearchCredentialsId = elasticsearchCredentialsId;
141141

142142
RequestConfig requestConfig = RequestConfig.custom()
143143
.setConnectionKeepAlive(TimeValue.ofMilliseconds(KEEPALIVE_INTERVAL))
144144
.build();
145145
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
146146
.setDefaultRequestConfig(requestConfig)
147-
.setDefaultCredentialsProvider(credentialsProvider)
148147
.build();
149148

150149
if (disableSslVerifications) {
@@ -165,12 +164,14 @@ public ElasticsearchLogStorageRetriever(
165164
httpclient = HttpAsyncClients.custom()
166165
.setDefaultRequestConfig(requestConfig)
167166
.setConnectionManager(cm)
168-
.setDefaultCredentialsProvider(credentialsProvider)
169167
.build();
170168
}
171169

170+
HttpAuthHeaderFactory httpAuthHeaderFactory = new HttpAuthHeaderFactory(elasticsearchCredentialsId);
171+
Header[] headers = {httpAuthHeaderFactory.createAuthHeader()};
172172
this.restClient = Rest5Client.builder(URI.create(elasticsearchUrl))
173173
.setHttpClient(httpclient)
174+
.setDefaultHeaders(headers)
174175
.build();
175176

176177
this.elasticsearchTransport = new Rest5ClientTransport(restClient, new JacksonJsonpMapper());
@@ -180,23 +181,6 @@ public ElasticsearchLogStorageRetriever(
180181
this.templateBindingsProvider = templateBindingsProvider;
181182
}
182183

183-
/**
184-
* Get the credentials provider for the Elasticsearch client.
185-
* @param elasticsearchUrl
186-
* @param elasticsearchCredentials
187-
* @return
188-
*/
189-
private BasicCredentialsProvider getCredentialsProvider(String elasticsearchUrl,
190-
Credentials elasticsearchCredentials) {
191-
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
192-
try{
193-
credentialsProvider.setCredentials(new AuthScope(HttpHost.create(elasticsearchUrl)), elasticsearchCredentials);
194-
} catch(URISyntaxException e) {
195-
throw new IllegalArgumentException(e);
196-
}
197-
return credentialsProvider;
198-
}
199-
200184
@NonNull
201185
@Override
202186
public LogsQueryResult overallLog(
@@ -287,14 +271,6 @@ public LogsQueryResult stepLog(@NonNull String jobFullName, int runNumber, @NonN
287271
public List<FormValidation> checkElasticsearchSetup() {
288272
List<FormValidation> validations = new ArrayList<>();
289273
ElasticsearchIndicesClient indicesClient = this.esClient.indices();
290-
String elasticsearchUsername;
291-
try {
292-
elasticsearchUsername = Optional.ofNullable(elasticsearchCredentials.getUserPrincipal()).map(Principal::getName).orElse("No username for credentials type " + elasticsearchCredentials.getClass().getSimpleName());
293-
} catch (CredentialsNotFoundException e) {
294-
validations.add(FormValidation.error("No credentials defined"));
295-
return validations;
296-
}
297-
298274
try {
299275
final GetIndexResponse response = indicesClient.get(b -> b.index(ElasticsearchFields.INDEX_TEMPLATE_PATTERNS));
300276
if (response == null || response.indices() == null || response.indices().isEmpty()) {
@@ -304,14 +280,14 @@ public List<FormValidation> checkElasticsearchSetup() {
304280
}
305281
} catch (ElasticsearchException e) {
306282
logger.fine(e.getLocalizedMessage());
307-
validations.addAll(findEsErrorCause(elasticsearchUsername, e));
283+
validations.addAll(findEsErrorCause(e));
308284
return validations;
309285
} catch (IOException e) {
310286
logger.fine(e.getLocalizedMessage());
311-
validations.add(FormValidation.warning("Exception accessing Elasticsearch " + elasticsearchUrl + " with user '" + elasticsearchUsername + "'.", e));
287+
validations.add(FormValidation.warning("Exception accessing Elasticsearch " + elasticsearchUrl + " with credentials '" + elasticsearchCredentialsId + "'.", e));
312288
return validations;
313289
}
314-
validations.add(FormValidation.ok("Connected to Elasticsearch " + elasticsearchUrl + " with user '" + elasticsearchUsername + "'."));
290+
validations.add(FormValidation.ok("Connected to Elasticsearch " + elasticsearchUrl + " with credentials '" + elasticsearchCredentialsId + "'."));
315291
return validations;
316292
}
317293

@@ -322,25 +298,25 @@ public List<FormValidation> checkElasticsearchSetup() {
322298
* @return a list of FormValidation objects representing the error cause
323299
*/
324300
@NonNull
325-
private List<FormValidation> findEsErrorCause(@NonNull String elasticsearchUsername, @NonNull ElasticsearchException e) {
301+
private List<FormValidation> findEsErrorCause(@NonNull ElasticsearchException e) {
326302
List<FormValidation> validations = new ArrayList<>();
327303
ErrorCause errorCause = e.error();
328304
int status = e.status();
329305
if (ElasticsearchFields.ERROR_CAUSE_TYPE_SECURITY_EXCEPTION.equals(errorCause.type())) {
330306
if (status == HttpURLConnection.HTTP_UNAUTHORIZED) {
331-
validations.add(FormValidation.error("Authentication failure " + "/" + status + " accessing Elasticsearch " + elasticsearchUrl + " with user '" + elasticsearchUsername + "'.", e));
307+
validations.add(FormValidation.error("Authentication failure " + "/" + status + " accessing Elasticsearch " + elasticsearchUrl + " with user '" + elasticsearchCredentialsId + "'.", e));
332308
} else if (status == HttpURLConnection.HTTP_FORBIDDEN) {
333-
validations.add(FormValidation.ok("Connected to Elasticsearch " + elasticsearchUrl + " with user '" + elasticsearchUsername + "'."));
309+
validations.add(FormValidation.ok("Connected to Elasticsearch " + elasticsearchUrl + " with credentials '" + elasticsearchCredentialsId + "'."));
334310
validations.add(FormValidation.warning(errorCause.type() + "/" + status + " accessing index template '" + ElasticsearchFields.INDEX_TEMPLATE_PATTERNS + "' on '" + elasticsearchUrl + "'. " +
335-
"Elasticsearch user '" + elasticsearchUsername + "' doesn't have read permission to the index template metadata - " + errorCause.reason() + "."));
311+
"Elasticsearch credentials '" + elasticsearchCredentialsId + "' doesn't have read permission to the index template metadata - " + errorCause.reason() + "."));
336312
} else {
337-
validations.add(FormValidation.ok("Connected to Elasticsearch " + elasticsearchUrl + " with user '" + elasticsearchUsername + "'."));
313+
validations.add(FormValidation.ok("Connected to Elasticsearch " + elasticsearchUrl + " with credentials '" + elasticsearchCredentialsId + "'."));
338314
validations.add(FormValidation.warning(errorCause.type() + "/" + status + " accessing index template '" + ElasticsearchFields.INDEX_TEMPLATE_PATTERNS + "' on '" + elasticsearchUrl + "' with " +
339-
"Elasticsearch user '" + elasticsearchUsername + "' - " + errorCause.reason() + "."));
315+
"Elasticsearch credentials '" + elasticsearchCredentialsId + "' - " + errorCause.reason() + "."));
340316
}
341317
} else {
342318
validations.add(FormValidation.warning(errorCause.type() + "/" + status + " accessing index template '" + ElasticsearchFields.INDEX_TEMPLATE_PATTERNS + "' on '" + elasticsearchUrl + "' with " +
343-
"Elasticsearch user '" + elasticsearchUsername + "' - " + errorCause.reason() + "."));
319+
"Elasticsearch credentials '" + elasticsearchCredentialsId + "' - " + errorCause.reason() + "."));
344320
}
345321
return validations;
346322
}

0 commit comments

Comments
 (0)