Skip to content

Commit

Permalink
Add custom enhanced auth support on symphony agent apis
Browse files Browse the repository at this point in the history
  • Loading branch information
yinan-symphony committed Feb 5, 2024
1 parent 5e4eab3 commit 402fbbb
Show file tree
Hide file tree
Showing 25 changed files with 271 additions and 225 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ jobs:
java-version: '17'

- name: Build with Gradle
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v2.4.2
with:
arguments: build jacocoTestReport jacocoTestCoverageVerification
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id "org.owasp.dependencycheck" version "9.0.9"
}

ext.projectVersion = '3.0.0.RC6'
ext.projectVersion = '3.0.0.RC7'
ext.isReleaseVersion = !ext.projectVersion.endsWith('SNAPSHOT')

ext.mavenRepoUrl = project.properties['mavenRepoUrl'] ?: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public String getFormattedContext() {
if (!localContext.equals("") && localContext.charAt(0) != '/') {
return "/" + localContext;
}
if (!localContext.equals("") && localContext.endsWith("/")) {
if (localContext.endsWith("/")) {
return localContext.substring(0, localContext.length() - 1);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ public ServiceFactory(ApiClientFactory apiClientFactory, BotAuthSession authSess
throw new UnsupportedOperationException(
"Common JWT feature is enabled, it use 'Authorization' header too, there is a conflict with the enhanced authentication.");
}
this.podClient.getAuthentications()
.put(enhancedAuthConfig.getId(), new CustomEnhancedAuthAuthentication(enhancedAuthConfig.getHeaderName(),
enhancedAuthSession::getEnhancedAuthToken));
this.podClient.addEnforcedAuthenticationScheme(enhancedAuthConfig.getId());
this.retryBuilder.recoveryStrategy((e) -> e.isUnauthorized() && enhancedAuthSession.isSessionExpired(e),
enhancedAuthSession::refresh);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

import java.util.Map;

/**
*
*/
@RequiredArgsConstructor
@API(status = Status.EXPERIMENTAL)
public class CustomEnhancedAuthAuthentication implements Authentication {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.symphony.bdk.core.client;

import com.symphony.bdk.core.config.model.BdkAgentConfig;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.config.model.BdkCustomEnhancedAuthConfig;
import com.symphony.bdk.http.api.ApiClient;
import com.symphony.bdk.http.api.auth.Authentication;

import lombok.extern.slf4j.Slf4j;
import org.apiguardian.api.API;

import jakarta.annotation.Nonnull;

@Slf4j
@API(status = API.Status.EXPERIMENTAL)
public class EnhancedAuthApiClientFactory extends ApiClientFactory {

private final Authentication enhancedAuthentication;
private final BdkCustomEnhancedAuthConfig enhancedAuthConfig;

public EnhancedAuthApiClientFactory(@Nonnull BdkConfig config, @Nonnull Authentication enhancedAuthentication) {
super(config);
this.enhancedAuthentication = enhancedAuthentication;
this.enhancedAuthConfig = config.getEnhancedAuth();
}

@Override
protected ApiClient buildAgentClient(String basePath, BdkAgentConfig agentConfig) {
return addAuthScheme(super.getApiClientBuilder(basePath, agentConfig).build());
}

private ApiClient addAuthScheme(ApiClient apiClient) {
apiClient.addEnforcedAuthenticationScheme(enhancedAuthConfig.getId());
apiClient.getAuthentications().put(enhancedAuthConfig.getId(), enhancedAuthentication);
return apiClient;
}}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.symphony.bdk.core.service.datafeed.impl;

import com.symphony.bdk.core.auth.BotAuthSession;
import com.symphony.bdk.core.auth.CustomEnhancedAuthSession;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.gen.api.DatafeedApi;
import com.symphony.bdk.gen.api.model.UserV2;
Expand Down Expand Up @@ -33,6 +34,11 @@ public abstract class AbstractAckIdEventLoop extends AbstractDatafeedLoop {
@Getter(AccessLevel.PROTECTED)
protected String ackId;

public AbstractAckIdEventLoop(DatafeedApi datafeedApi, BotAuthSession authSession, CustomEnhancedAuthSession enhancedAuthSession, BdkConfig config, UserV2 botInfo) {
super(datafeedApi, authSession, enhancedAuthSession, config, botInfo);
this.ackId = INITIAL_ACK_ID;
}

public AbstractAckIdEventLoop(DatafeedApi datafeedApi, BotAuthSession authSession, BdkConfig config, UserV2 botInfo) {
super(datafeedApi, authSession, config, botInfo);
this.ackId = INITIAL_ACK_ID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.symphony.bdk.core.retry.RetryWithRecovery.networkIssueMessageError;

import com.symphony.bdk.core.auth.BotAuthSession;
import com.symphony.bdk.core.auth.CustomEnhancedAuthSession;
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.service.datafeed.DatafeedLoop;
Expand Down Expand Up @@ -35,6 +36,7 @@
abstract class AbstractDatafeedLoop implements DatafeedLoop {

protected final BotAuthSession authSession;
protected final CustomEnhancedAuthSession enhancedAuthSession;
protected final BdkConfig bdkConfig;
protected final UserV2 botInfo;
protected final AtomicBoolean started = new AtomicBoolean();
Expand All @@ -44,10 +46,20 @@ abstract class AbstractDatafeedLoop implements DatafeedLoop {
// access needs to be thread safe (DF loop is usually running on its own thread)
private final List<RealTimeEventListener> listeners;

public AbstractDatafeedLoop(DatafeedApi datafeedApi, BotAuthSession authSession, CustomEnhancedAuthSession enhancedAuthSession, BdkConfig config, UserV2 botInfo) {
this.datafeedApi = datafeedApi;
this.listeners = new ArrayList<>();
this.authSession = authSession;
this.enhancedAuthSession = enhancedAuthSession;
this.bdkConfig = config;
this.botInfo = botInfo;
}

public AbstractDatafeedLoop(DatafeedApi datafeedApi, BotAuthSession authSession, BdkConfig config, UserV2 botInfo) {
this.datafeedApi = datafeedApi;
this.listeners = new ArrayList<>();
this.authSession = authSession;
this.enhancedAuthSession = null;
this.bdkConfig = config;
this.botInfo = botInfo;
}
Expand Down Expand Up @@ -161,6 +173,9 @@ protected void handleV4EventList(@Nullable List<V4Event> events) throws RequeueE
protected void refresh() throws AuthUnauthorizedException {
log.info("Re-authenticate and try again");
this.authSession.refresh();
if (this.enhancedAuthSession != null) {
this.enhancedAuthSession.refresh();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.symphony.bdk.core.service.datafeed.impl;

import com.symphony.bdk.core.auth.BotAuthSession;
import com.symphony.bdk.core.auth.CustomEnhancedAuthSession;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.retry.RetryWithRecovery;
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
Expand Down Expand Up @@ -56,6 +57,41 @@ public class DatafeedLoopV2 extends AbstractAckIdEventLoop {

private V5Datafeed datafeed;

public DatafeedLoopV2(DatafeedApi datafeedApi, BotAuthSession authSession, CustomEnhancedAuthSession enhancedAuthSession, BdkConfig config, UserV2 botInfo) {
super(datafeedApi, authSession, enhancedAuthSession, config, botInfo);

this.retryWithRecoveryBuilder = new RetryWithRecoveryBuilder<>()
.basePath(datafeedApi.getApiClient().getBasePath())
.retryConfig(config.getDatafeedRetryConfig())
.recoveryStrategy((e) -> e.isUnauthorized() && enhancedAuthSession.isSessionExpired(e),
enhancedAuthSession::refresh)
.recoveryStrategy(ApiException::isUnauthorized, this::refresh);

this.readDatafeed = RetryWithRecoveryBuilder.<Void>from(retryWithRecoveryBuilder)
.name("Read Datafeed V2")
.supplier(this::readAndHandleEvents)
.retryOnException(RetryWithRecoveryBuilder::isNetworkIssueOrMinorErrorOrClientError)
.recoveryStrategy(ApiException::isClientError, this::recreateDatafeed)
.build();

this.retrieveDatafeed = RetryWithRecoveryBuilder.<V5Datafeed>from(retryWithRecoveryBuilder)
.name("Retrieve Datafeed V2")
.supplier(this::doRetrieveDatafeed)
.build();

this.createDatafeed = RetryWithRecoveryBuilder.<V5Datafeed>from(retryWithRecoveryBuilder)
.name("Create Datafeed V2")
.supplier(this::doCreateDatafeed)
.retryOnException(RetryWithRecoveryBuilder::isNetworkIssueOrMinorErrorOrClientError)
.build();

this.deleteDatafeed = RetryWithRecoveryBuilder.<Void>from(retryWithRecoveryBuilder)
.name("Delete Datafeed V2")
.supplier(this::doDeleteDatafeed)
.ignoreException(ApiException::isClientError)
.build();
}

public DatafeedLoopV2(DatafeedApi datafeedApi, BotAuthSession authSession, BdkConfig config, UserV2 botInfo) {
super(datafeedApi, authSession, config, botInfo);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.symphony.bdk.core.service.datafeed.impl;

import com.symphony.bdk.core.auth.BotAuthSession;
import com.symphony.bdk.core.auth.CustomEnhancedAuthSession;
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.core.retry.RetryWithRecovery;
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
Expand Down Expand Up @@ -30,6 +31,29 @@ public class DatahoseLoopImpl extends AbstractAckIdEventLoop implements Datahose
private final List<String> filters;
private final RetryWithRecovery<Object> readEvents;

public DatahoseLoopImpl(DatafeedApi datafeedApi, BotAuthSession authSession, CustomEnhancedAuthSession enhancedAuthSession, BdkConfig config, UserV2 botInfo) {
super(datafeedApi, authSession, config, botInfo);

String untruncatedTag = config.getDatahose().getTag();
if (StringUtils.isEmpty(untruncatedTag)) {
untruncatedTag = DATAHOSE + "-" + botInfo.getUsername();
}
this.tag = StringUtils.truncate(untruncatedTag, DATAHOSE_TAG_MAX_LENGTH);

this.filters = config.getDatahose().getEventTypes();

this.readEvents = new RetryWithRecoveryBuilder<>()
.basePath(datafeedApi.getApiClient().getBasePath())
.retryConfig(config.getDatahose().getRetry())
.name("readEvents")
.supplier(this::readAndHandleEvents)
.retryOnException(RetryWithRecoveryBuilder::isNetworkIssueOrMinorError)
.recoveryStrategy((e) -> e.isUnauthorized() && enhancedAuthSession.isSessionExpired(e),
enhancedAuthSession::refresh)
.recoveryStrategy(ApiException::isUnauthorized, this::refresh)
.build();
}

public DatahoseLoopImpl(DatafeedApi datafeedApi, BotAuthSession authSession, BdkConfig config, UserV2 botInfo) {
super(datafeedApi, authSession, config, botInfo);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import com.symphony.bdk.core.config.model.BdkConfig;
import com.symphony.bdk.http.api.ApiException;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import jakarta.annotation.Nonnull;

import java.util.List;

@Component
@ConditionalOnProperty(value = "bdk.enhanced-auth.enabled", havingValue = "true")
public class ApigeeCustomAuthenticator extends AbstractCustomAuthenticator {

public ApigeeCustomAuthenticator(BdkConfig bdkConfig) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ bdk:
username: wdkbot
privateKey:
path: /Users/yinan.liu/Projects/certs/privatekey.pem
agent:
host: 34.49.130.230.nip.io

enhanced-auth:
id: apigee
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import com.symphony.bdk.core.auth.AuthSession;
import com.symphony.bdk.core.auth.BotAuthSession;
import com.symphony.bdk.core.client.ApiClientFactory;
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
import com.symphony.bdk.ext.group.auth.OAuthSession;
Expand Down Expand Up @@ -39,7 +39,7 @@ void testGroupServiceInitialization() throws ApiException {

SymphonyGroupBdkExtension groupExtension = new SymphonyGroupBdkExtension();
groupExtension.setApiClientFactory(clientFactory);
groupExtension.setAuthSession(mock(AuthSession.class));
groupExtension.setAuthSession(mock(BotAuthSession.class));
groupExtension.setRetryBuilder(new RetryWithRecoveryBuilder<>());

final SymphonyGroupService service = groupExtension.getService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.symphony.bdk.core.auth.AuthSession;
import com.symphony.bdk.core.auth.BotAuthSession;
import com.symphony.bdk.core.client.ApiClientFactory;
import com.symphony.bdk.core.config.model.BdkRetryConfig;
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
Expand Down Expand Up @@ -52,7 +52,7 @@ class SymphonyGroupServiceTest {
private ApiClientFactory clientFactory;
private ApiClient loginClient;
private ApiClient profileManagerClient;
private AuthSession authSession;
private BotAuthSession authSession;
private SymphonyGroupService groupService;

@BeforeEach
Expand All @@ -72,7 +72,7 @@ void setUp() throws ApiException {
when(clientFactory.getLoginClient()).thenReturn(loginClient);
when(clientFactory.getPodClient(eq("/profile-manager"))).thenReturn(profileManagerClient);

authSession = mock(AuthSession.class);
authSession = mock(BotAuthSession.class);

groupService = new SymphonyGroupService(ofMinimalInterval(2), clientFactory, authSession);
}
Expand Down
3 changes: 3 additions & 0 deletions symphony-bdk-http/symphony-bdk-http-jersey2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ dependencies {

api project(':symphony-bdk-http:symphony-bdk-http-api')

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

implementation 'org.slf4j:slf4j-api'
implementation 'org.apiguardian:apiguardian-api'
implementation 'io.jsonwebtoken:jjwt'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.NoHttpResponseException;
import org.apache.http.conn.ConnectTimeoutException;
import org.apiguardian.api.API;
Expand Down Expand Up @@ -54,6 +56,7 @@
* Jersey2 implementation for the {@link ApiClient} interface called by generated code.
*/
@API(status = API.Status.STABLE)
@Slf4j
public class ApiClientJersey2 implements ApiClient {

protected Client httpClient;
Expand Down Expand Up @@ -121,6 +124,10 @@ public <T> ApiResponse<T> invokeAPI(
String value = entry.getValue();
if (value != null) {
invocationBuilder = invocationBuilder.header(entry.getKey(), value);
log.debug("request={}", target.getUri());
log.debug("method={}", method);
log.debug("header={}", entry.getKey());
log.debug("value={}", value);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.symphony.bdk.spring;

import com.symphony.bdk.spring.config.BdkAuthEnhancedServiceConfig;
import com.symphony.bdk.spring.config.BdkActivityConfig;
import com.symphony.bdk.spring.config.BdkApiClientsConfig;
import com.symphony.bdk.spring.config.BdkCommonFeedConfig;
import com.symphony.bdk.spring.config.BdkCoreConfig;
import com.symphony.bdk.spring.config.BdkDatafeedConfig;
import com.symphony.bdk.spring.config.BdkDatahoseConfig;
import com.symphony.bdk.spring.config.BdkEnhancedAuthConfig;
import com.symphony.bdk.spring.config.BdkExtensionConfig;
import com.symphony.bdk.spring.config.BdkOboServiceConfig;
import com.symphony.bdk.spring.config.BdkRetryConfig;
Expand All @@ -20,12 +20,12 @@
*/
@Import({
BdkCoreConfig.class,
BdkEnhancedAuthConfig.class,
BdkRetryConfig.class,
BdkApiClientsConfig.class,
BdkCommonFeedConfig.class,
BdkDatafeedConfig.class,
BdkDatahoseConfig.class,
BdkAuthEnhancedServiceConfig.class,
BdkServiceConfig.class,
BdkOboServiceConfig.class,
BdkActivityConfig.class,
Expand Down
Loading

0 comments on commit 402fbbb

Please sign in to comment.