Skip to content

Commit f257f0f

Browse files
Add Confluence Data Center support with allow_local_address and bearer token auth
Make address validation configurable via allow_local_address (default false) so Confluence Data Center on internal networks is supported. Add bearer token authentication for Personal Access Tokens used by Data Center deployments. Resolves #6496 Signed-off-by: Srikanth Padakanti <srikanth_padakanti@apple.com>
1 parent 74aa3cf commit f257f0f

17 files changed

Lines changed: 338 additions & 9 deletions

File tree

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/main/java/org/opensearch/dataprepper/plugins/source/atlassian/AtlassianSourceConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public abstract class AtlassianSourceConfig implements CrawlerSourceConfig {
4141
@JsonProperty("acknowledgments")
4242
private boolean acknowledgments = false;
4343

44+
@JsonProperty("allow_local_address")
45+
private boolean allowLocalAddress = false;
46+
4447
public String getAccountUrl() {
4548
return this.getHosts().get(0);
4649
}

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/main/java/org/opensearch/dataprepper/plugins/source/atlassian/configuration/AuthenticationConfig.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import lombok.Getter;
1717

1818
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.BASIC;
19+
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.BEARER_TOKEN;
1920
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.OAUTH2;
2021

2122

@@ -29,16 +30,23 @@ public class AuthenticationConfig {
2930
@Valid
3031
private Oauth2Config oauth2Config;
3132

32-
@AssertTrue(message = "Authentication config should have either basic or oauth2")
33+
@JsonProperty("bearer_token")
34+
private String bearerToken;
35+
36+
@AssertTrue(message = "Authentication config should have exactly one of basic, oauth2, or bearer_token")
3337
private boolean isValidAuthenticationConfig() {
3438
boolean hasBasic = basicConfig != null;
3539
boolean hasOauth = oauth2Config != null;
36-
return hasBasic ^ hasOauth;
40+
boolean hasBearer = bearerToken != null && !bearerToken.isBlank();
41+
int count = (hasBasic ? 1 : 0) + (hasOauth ? 1 : 0) + (hasBearer ? 1 : 0);
42+
return count == 1;
3743
}
3844

3945
public String getAuthType() {
4046
if (basicConfig != null) {
4147
return BASIC;
48+
} else if (bearerToken != null && !bearerToken.isBlank()) {
49+
return BEARER_TOKEN;
4250
} else {
4351
return OAUTH2;
4452
}

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/main/java/org/opensearch/dataprepper/plugins/source/atlassian/rest/AtlassianRestClient.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,24 @@ public class AtlassianRestClient {
3939
final Counter authFailures;
4040
private final RestTemplate restTemplate;
4141
private final AtlassianAuthConfig authConfig;
42+
private final boolean allowLocalAddress;
4243

4344
public AtlassianRestClient(RestTemplate restTemplate, AtlassianAuthConfig authConfig,
4445
PluginMetrics pluginMetrics) {
46+
this(restTemplate, authConfig, pluginMetrics, false);
47+
}
48+
49+
public AtlassianRestClient(RestTemplate restTemplate, AtlassianAuthConfig authConfig,
50+
PluginMetrics pluginMetrics, boolean allowLocalAddress) {
4551
this.restTemplate = restTemplate;
4652
this.authConfig = authConfig;
4753
this.authFailures = pluginMetrics.counter(AUTH_FAILURES_COUNTER);
54+
this.allowLocalAddress = allowLocalAddress;
4855
}
4956

5057

5158
protected <T> ResponseEntity<T> invokeRestApi(URI uri, Class<T> responseType) throws BadRequestException {
52-
AddressValidation.validateInetAddress(AddressValidation.getInetAddress(uri.toString()));
59+
AddressValidation.validateInetAddress(AddressValidation.getInetAddress(uri.toString()), allowLocalAddress);
5360
int retryCount = 0;
5461
while (retryCount < MAX_RETRIES) {
5562
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*
9+
*/
10+
11+
package org.opensearch.dataprepper.plugins.source.atlassian.rest;
12+
13+
import org.opensearch.dataprepper.plugins.source.atlassian.rest.auth.AtlassianBearerTokenAuthConfig;
14+
import org.springframework.http.HttpRequest;
15+
import org.springframework.http.client.ClientHttpRequestExecution;
16+
import org.springframework.http.client.ClientHttpRequestInterceptor;
17+
import org.springframework.http.client.ClientHttpResponse;
18+
19+
import java.io.IOException;
20+
21+
public class BearerTokenInterceptor implements ClientHttpRequestInterceptor {
22+
23+
private final AtlassianBearerTokenAuthConfig authConfig;
24+
25+
public BearerTokenInterceptor(AtlassianBearerTokenAuthConfig authConfig) {
26+
this.authConfig = authConfig;
27+
}
28+
29+
@Override
30+
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
31+
request.getHeaders().setBearerAuth(authConfig.getBearerToken());
32+
return execution.execute(request, body);
33+
}
34+
}

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/main/java/org/opensearch/dataprepper/plugins/source/atlassian/rest/CustomRestTemplateConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313

1414
import org.opensearch.dataprepper.plugins.source.atlassian.AtlassianSourceConfig;
1515
import org.opensearch.dataprepper.plugins.source.atlassian.rest.auth.AtlassianAuthConfig;
16+
import org.opensearch.dataprepper.plugins.source.atlassian.rest.auth.AtlassianBearerTokenAuthConfig;
1617
import org.springframework.context.annotation.Bean;
1718
import org.springframework.context.annotation.Configuration;
1819
import org.springframework.http.client.ClientHttpRequestInterceptor;
1920
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
2021
import org.springframework.web.client.RestTemplate;
2122

23+
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.BEARER_TOKEN;
2224
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.OAUTH2;
2325

2426
@Configuration
@@ -31,6 +33,8 @@ public RestTemplate basicAuthRestTemplate(AtlassianSourceConfig config, Atlassia
3133
ClientHttpRequestInterceptor httpInterceptor;
3234
if (OAUTH2.equals(config.getAuthType())) {
3335
httpInterceptor = new OAuth2RequestInterceptor(authConfig);
36+
} else if (BEARER_TOKEN.equals(config.getAuthType())) {
37+
httpInterceptor = new BearerTokenInterceptor((AtlassianBearerTokenAuthConfig) authConfig);
3438
} else {
3539
httpInterceptor = new BasicAuthInterceptor(config);
3640
}

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/main/java/org/opensearch/dataprepper/plugins/source/atlassian/rest/auth/AtlassianAuthFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.springframework.beans.factory.FactoryBean;
1515
import org.springframework.context.annotation.Configuration;
1616

17+
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.BEARER_TOKEN;
1718
import static org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants.OAUTH2;
1819

1920
@Configuration
@@ -31,6 +32,9 @@ public AtlassianAuthConfig getObject() {
3132
if (OAUTH2.equals(authType)) {
3233
return new AtlassianOauthConfig(sourceConfig);
3334
}
35+
if (BEARER_TOKEN.equals(authType)) {
36+
return new AtlassianBearerTokenAuthConfig(sourceConfig);
37+
}
3438
return new AtlassianBasicAuthConfig(sourceConfig);
3539
}
3640

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*
9+
*/
10+
11+
package org.opensearch.dataprepper.plugins.source.atlassian.rest.auth;
12+
13+
import org.opensearch.dataprepper.plugins.source.atlassian.AtlassianSourceConfig;
14+
15+
public class AtlassianBearerTokenAuthConfig implements AtlassianAuthConfig {
16+
17+
private String accountUrl;
18+
private final String bearerToken;
19+
20+
public AtlassianBearerTokenAuthConfig(AtlassianSourceConfig sourceConfig) {
21+
this.bearerToken = sourceConfig.getAuthenticationConfig().getBearerToken();
22+
accountUrl = sourceConfig.getAccountUrl();
23+
if (!accountUrl.endsWith("/")) {
24+
accountUrl += "/";
25+
}
26+
}
27+
28+
@Override
29+
public String getUrl() {
30+
return accountUrl;
31+
}
32+
33+
public String getBearerToken() {
34+
return bearerToken;
35+
}
36+
37+
@Override
38+
public void renewCredentials() {
39+
// static token, no renewal needed
40+
}
41+
}

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/main/java/org/opensearch/dataprepper/plugins/source/atlassian/utils/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ public class Constants {
1919

2020
public static final String OAUTH2 = "OAuth2";
2121
public static final String BASIC = "Basic";
22+
public static final String BEARER_TOKEN = "BearerToken";
2223
public static final String SLASH = "/";
2324
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* The OpenSearch Contributors require contributions made to
6+
* this file be licensed under the Apache-2.0 license or a
7+
* compatible open source license.
8+
*
9+
*/
10+
11+
package org.opensearch.dataprepper.plugins.source.atlassian.rest;
12+
13+
import org.junit.jupiter.api.Test;
14+
import org.junit.jupiter.api.extension.ExtendWith;
15+
import org.mockito.Mock;
16+
import org.mockito.junit.jupiter.MockitoExtension;
17+
import org.opensearch.dataprepper.plugins.source.atlassian.rest.auth.AtlassianBearerTokenAuthConfig;
18+
import org.springframework.http.HttpHeaders;
19+
import org.springframework.http.HttpRequest;
20+
import org.springframework.http.client.ClientHttpRequestExecution;
21+
import org.springframework.http.client.ClientHttpResponse;
22+
23+
import java.io.IOException;
24+
25+
import static org.hamcrest.MatcherAssert.assertThat;
26+
import static org.hamcrest.Matchers.equalTo;
27+
import static org.mockito.Mockito.verify;
28+
import static org.mockito.Mockito.when;
29+
30+
@ExtendWith(MockitoExtension.class)
31+
class BearerTokenInterceptorTest {
32+
33+
@Mock
34+
private AtlassianBearerTokenAuthConfig authConfig;
35+
36+
@Mock
37+
private HttpRequest request;
38+
39+
@Mock
40+
private ClientHttpRequestExecution execution;
41+
42+
@Mock
43+
private ClientHttpResponse response;
44+
45+
@Test
46+
void testInterceptSetsBearerAuthHeader() throws IOException {
47+
when(authConfig.getBearerToken()).thenReturn("my-token");
48+
HttpHeaders headers = new HttpHeaders();
49+
when(request.getHeaders()).thenReturn(headers);
50+
when(execution.execute(request, new byte[0])).thenReturn(response);
51+
52+
BearerTokenInterceptor interceptor = new BearerTokenInterceptor(authConfig);
53+
interceptor.intercept(request, new byte[0], execution);
54+
55+
verify(execution).execute(request, new byte[0]);
56+
assertThat(headers.getFirst(HttpHeaders.AUTHORIZATION), equalTo("Bearer my-token"));
57+
}
58+
}

data-prepper-plugins/saas-source-plugins/atlassian-commons/src/test/java/org/opensearch/dataprepper/plugins/source/atlassian/rest/CustomRestTemplateConfigTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.opensearch.dataprepper.plugins.source.atlassian.configuration.BasicConfig;
2424
import org.opensearch.dataprepper.plugins.source.atlassian.configuration.Oauth2Config;
2525
import org.opensearch.dataprepper.plugins.source.atlassian.rest.auth.AtlassianAuthConfig;
26+
import org.opensearch.dataprepper.plugins.source.atlassian.rest.auth.AtlassianBearerTokenAuthConfig;
2627
import org.opensearch.dataprepper.plugins.source.atlassian.utils.Constants;
2728
import org.springframework.http.client.ClientHttpRequestInterceptor;
2829
import org.springframework.http.client.InterceptingClientHttpRequestFactory;
@@ -48,6 +49,9 @@ class CustomRestTemplateConfigTest {
4849
@Mock
4950
private AtlassianAuthConfig mockAuthConfig;
5051

52+
@Mock
53+
private AtlassianBearerTokenAuthConfig mockBearerAuthConfig;
54+
5155
@Mock
5256
private BasicConfig mockBasicConfig;
5357

@@ -67,6 +71,7 @@ private static Stream<Arguments> provideAuthTypeAndExpectedInterceptorType() {
6771
return Stream.of(
6872
Arguments.of(Constants.OAUTH2, OAuth2RequestInterceptor.class),
6973
Arguments.of(Constants.BASIC, BasicAuthInterceptor.class),
74+
Arguments.of(Constants.BEARER_TOKEN, BearerTokenInterceptor.class),
7075
Arguments.of("Default", BasicAuthInterceptor.class),
7176
Arguments.of(null, BasicAuthInterceptor.class)
7277
);
@@ -92,7 +97,8 @@ void testBasicAuthRestTemplateWithOAuth2(String authType, Class interceptorClass
9297
lenient().when(mockBasicConfig.getUsername()).thenReturn("username");
9398
lenient().when(mockBasicConfig.getPassword()).thenReturn("password");
9499

95-
RestTemplate restTemplate = config.basicAuthRestTemplate(mockSourceConfig, mockAuthConfig);
100+
AtlassianAuthConfig authConfigToUse = Constants.BEARER_TOKEN.equals(authType) ? mockBearerAuthConfig : mockAuthConfig;
101+
RestTemplate restTemplate = config.basicAuthRestTemplate(mockSourceConfig, authConfigToUse);
96102
assertNotNull(restTemplate);
97103
assertInstanceOf(InterceptingClientHttpRequestFactory.class, restTemplate.getRequestFactory());
98104
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();

0 commit comments

Comments
 (0)