#154 - Use preemptive authentication for Jira and GitHub.
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user