#154 - Use preemptive authentication for Jira and GitHub.

This commit is contained in:
Mark Paluch
2020-10-28 11:15:13 +01:00
parent de54dd4b10
commit a1090896a2
4 changed files with 68 additions and 39 deletions

View File

@@ -17,6 +17,18 @@ package org.springframework.data.release.issues;
import java.util.List;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cache.CacheManager;
@@ -24,7 +36,11 @@ import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.release.issues.github.GitHubProperties;
import org.springframework.data.release.issues.jira.JiraProperties;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.utils.HttpBasicCredentials;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.plugin.core.OrderAwarePluginRegistry;
@@ -66,15 +82,38 @@ class IssueTrackerConfiguration {
return mapper;
}
@Bean
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory(JiraProperties jiraProperties,
GitHubProperties gitHubProperties) {
// Preemptive auth
CredentialsProvider credsProvider = new BasicCredentialsProvider();
AuthCache authCache = new BasicAuthCache();
addPreemptiveAuth(credsProvider, authCache, jiraProperties.getApiUrl(), jiraProperties.getCredentials());
addPreemptiveAuth(credsProvider, authCache, gitHubProperties.getApiUrl(), gitHubProperties.getHttpCredentials());
CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultCredentialsProvider(credsProvider).build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setHttpContextFactory((httpMethod, uri) -> {
HttpClientContext context = HttpClientContext.create();
context.setAuthCache(authCache);
return context;
});
return factory;
}
@Bean
@Qualifier("tracker")
RestTemplateBuilder restTemplate() {
RestTemplateBuilder restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(jacksonObjectMapper());
return new RestTemplateBuilder().messageConverters(converter)
.requestFactory(HttpComponentsClientHttpRequestFactory.class);
.requestFactory(() -> clientHttpRequestFactory);
}
@Bean
@@ -82,6 +121,16 @@ class IssueTrackerConfiguration {
return OrderAwarePluginRegistry.of(plugins);
}
private static void addPreemptiveAuth(CredentialsProvider credsProvider, AuthCache authCache, String requestUrl,
HttpBasicCredentials credentials) {
HttpHost jiraHost = HttpHost.create(requestUrl);
credsProvider.setCredentials(new AuthScope(jiraHost),
new UsernamePasswordCredentials(credentials.getUsername(), credentials.getPassword().toString()));
authCache.put(jiraHost, new BasicScheme());
}
/**
* @author Oliver Gierke
*/

View File

@@ -131,7 +131,7 @@ class GitHub implements IssueTracker {
try {
GitHubIssue gitHubIssue = operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.GET,
new HttpEntity<>(newUserScopedHttpHeaders()), ISSUE_TYPE, parameters).getBody();
new HttpEntity<>(new HttpHeaders()), ISSUE_TYPE, parameters).getBody();
tickets.add(toTicket(gitHubIssue));
@@ -219,7 +219,7 @@ class GitHub implements IssueTracker {
GithubMilestone githubMilestone = new GithubMilestone(moduleIteration);
logger.log(moduleIteration, "Creating GitHub milestone %s", githubMilestone);
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("repoName", repositoryName);
@@ -265,7 +265,7 @@ class GitHub implements IssueTracker {
}
private Ticket doCreateTicket(ModuleIteration moduleIteration, String text) {
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
Milestone milestone = getMilestone(moduleIteration, repositoryName);
@@ -313,7 +313,7 @@ class GitHub implements IssueTracker {
GitHubIssue edit = GitHubIssue.assignedTo(properties.getUsername());
GitHubIssue response = operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.PATCH,
new HttpEntity<>(edit, newUserScopedHttpHeaders()), ISSUE_TYPE, parameters).getBody();
new HttpEntity<>(edit, new HttpHeaders()), ISSUE_TYPE, parameters).getBody();
return toTicket(response);
}
@@ -347,7 +347,7 @@ class GitHub implements IssueTracker {
GitHubIssue edit = GitHubIssue.assignedTo(properties.getUsername()).close();
GitHubIssue response = operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.PATCH,
new HttpEntity<>(edit, newUserScopedHttpHeaders()), ISSUE_TYPE, parameters).getBody();
new HttpEntity<>(edit, new HttpHeaders()), ISSUE_TYPE, parameters).getBody();
return toTicket(response);
}
@@ -356,14 +356,6 @@ class GitHub implements IssueTracker {
return ticket.getId().startsWith("#") ? ticket.getId().substring(1) : ticket.getId();
}
private HttpHeaders newUserScopedHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", properties.getHttpCredentials().toString());
return headers;
}
private Map<String, Object> newUrlTemplateVariables() {
Map<String, Object> parameters = new HashMap<>();
@@ -382,7 +374,7 @@ class GitHub implements IssueTracker {
logger.log(moduleIteration, "Looking up milestone…");
doWithPaging(MILESTONE_URI, HttpMethod.GET, parameters, new HttpEntity<>(newUserScopedHttpHeaders()),
doWithPaging(MILESTONE_URI, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()),
MILESTONES_TYPE, milestones -> {
Optional<GitHubIssue.Milestone> milestone = milestones.stream(). //
@@ -477,7 +469,7 @@ class GitHub implements IssueTracker {
// - mark version as released
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
GitProject project = GitProject.of(module.getProject());
@@ -530,7 +522,7 @@ class GitHub implements IssueTracker {
private Stream<GitHubIssue> getForIssues(String template, Map<String, Object> parameters) {
List<GitHubIssue> issues = new ArrayList<>();
doWithPaging(template, HttpMethod.GET, parameters, new HttpEntity<>(newUserScopedHttpHeaders()), ISSUES_TYPE,
doWithPaging(template, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()), ISSUES_TYPE,
tickets -> {
issues.addAll(tickets);
return true;

View File

@@ -173,7 +173,7 @@ class Jira implements JiraConnector {
JqlQuery query = JqlQuery
.from(trainIteration.stream().filter(moduleIteration -> supports(moduleIteration.getProject())));
HttpHeaders headers = newUserScopedHttpHeaders();
HttpHeaders headers = new HttpHeaders();
List<Ticket> tickets = new ArrayList<>();
@@ -227,7 +227,7 @@ class Jira implements JiraConnector {
Assert.notNull(moduleIteration, "ModuleIteration must not be null.");
Map<String, Object> parameters = newUrlTemplateVariables();
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
Optional<JiraReleaseVersion> versionsForModuleIteration = findJiraReleaseVersion(moduleIteration);
@@ -257,7 +257,7 @@ class Jira implements JiraConnector {
Assert.notNull(module, "ModuleIteration must not be null.");
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
findJiraReleaseVersion(module) //
.filter(JiraReleaseVersion::isActive) //
@@ -327,7 +327,7 @@ class Jira implements JiraConnector {
private Ticket doCreateTicket(ModuleIteration moduleIteration, String text) {
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> parameters = newUrlTemplateVariables();
findJiraReleaseVersion(moduleIteration).orElseThrow(
@@ -354,7 +354,7 @@ class Jira implements JiraConnector {
Assert.notNull(ticket, "Ticket must not be null.");
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("ticketId", ticket.getId());
@@ -408,7 +408,7 @@ class Jira implements JiraConnector {
Assert.notNull(ticket, "Ticket must not be null.");
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("ticketId", ticket.getId());
@@ -437,7 +437,7 @@ class Jira implements JiraConnector {
Assert.notNull(ticket, "Ticket must not be null.");
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("ticketId", ticket.getId());
@@ -521,7 +521,7 @@ class Jira implements JiraConnector {
// - mark version as releases
HttpHeaders httpHeaders = newUserScopedHttpHeaders();
HttpHeaders httpHeaders = new HttpHeaders();
findJiraReleaseVersion(module) //
.filter(JiraReleaseVersion::isOpen) //
@@ -709,18 +709,6 @@ class Jira implements JiraConnector {
String.format("%s/browse/%s", jiraProperties.getApiUrl(), issue.getKey()), jiraTicketStatus);
}
/**
* Returns new {@link HttpHeaders} with authentication headers.
*
* @return
*/
private HttpHeaders newUserScopedHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", jiraProperties.getCredentials().toString());
return headers;
}
private Map<String, Object> newUrlTemplateVariables() {
Map<String, Object> parameters = new HashMap<>();
return parameters;

View File

@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
@Data
@Component
@ConfigurationProperties(prefix = "jira")
class JiraProperties {
public class JiraProperties {
private @Getter(AccessLevel.PRIVATE) Password password;
private String username, apiUrl;