Skip to content

Commit cf95403

Browse files
Add list app users in the BDK
1 parent 0986508 commit cf95403

17 files changed

Lines changed: 481 additions & 14 deletions

buildSrc/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ repositories {
77
}
88

99
dependencies {
10-
implementation 'org.openapitools:openapi-generator-gradle-plugin:5.4.0'
10+
implementation 'org.openapitools:openapi-generator-gradle-plugin:6.6.0'
1111
implementation 'de.undercouch:gradle-download-task:5.0.2'
1212
implementation 'com.github.ben-manes:gradle-versions-plugin:0.42.0'
1313
}

symphony-bdk-core/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ dependencies {
7676
}
7777

7878
// OpenAPI code generation
79-
def apiBaseUrl = "https://raw.githubusercontent.com/finos/symphony-api-spec/fc80c3204d8a92a0b82d3c951eab7f5cb78a7c53"
79+
def apiBaseUrl = "https://raw.githubusercontent.com/aidenM-symphony/symphony-api-spec/6ff7cc838ff20a57535f0ff16833047b08587072/"
8080
def generatedFolder = "$buildDir/generated/openapi"
8181
def apisToGenerate = [
8282
Agent: 'agent/agent-api-public-deprecated.yaml',
8383
Pod : 'pod/pod-api-public-deprecated.yaml',
8484
Auth : 'authenticator/authenticator-api-public-deprecated.yaml',
8585
Login: 'login/login-api-public.yaml',
86+
Users: 'users/users-api-public.yaml'
8687
]
8788

8889
sourceSets.main.java.srcDirs += "$generatedFolder/src/main/java"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.symphony.bdk.core;
2+
3+
import com.symphony.bdk.core.auth.ExtAppAuthSession;
4+
import com.symphony.bdk.core.retry.RetryWithRecoveryBuilder;
5+
import com.symphony.bdk.core.service.apps.AppService;
6+
7+
import com.symphony.bdk.gen.api.AppsApi;
8+
import com.symphony.bdk.http.api.ApiClient;
9+
10+
import org.apiguardian.api.API;
11+
12+
@API(status = API.Status.EXPERIMENTAL)
13+
public class ExtAppServices {
14+
AppService appService;
15+
16+
public ExtAppServices(ApiClient apiClient, ExtAppAuthSession authSession, RetryWithRecoveryBuilder<?> retryBuilder) {
17+
AppsApi appsApi = new AppsApi(apiClient);
18+
this.appService = new AppService(appsApi, authSession, retryBuilder);
19+
}
20+
21+
public AppService app() {
22+
return this.appService;
23+
};
24+
}

symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class SymphonyBdk {
4646

4747
private final OboAuthenticator oboAuthenticator;
4848
private final ExtensionAppAuthenticator extensionAppAuthenticator;
49+
private final ExtAppAuthenticator extAppAuthenticator;
4950

5051
private final AuthSession botSession;
5152
private final UserV2 botInfo;
@@ -63,6 +64,8 @@ public class SymphonyBdk {
6364
private final SessionService sessionService;
6465
private final HealthService healthService;
6566
private final ExtensionService extensionService;
67+
private final ExtAppServices extAppServices;
68+
6669

6770
/**
6871
* Returns a new {@link SymphonyBdkBuilder} for fluent initialization.
@@ -107,6 +110,7 @@ protected SymphonyBdk(
107110
this.oboAuthenticator = config.isOboConfigured() ? authenticatorFactory.getOboAuthenticator() : null;
108111
this.extensionAppAuthenticator =
109112
config.isOboConfigured() ? authenticatorFactory.getExtensionAppAuthenticator() : null;
113+
this.extAppAuthenticator = config.isOboConfigured() ? authenticatorFactory.getExtAppAuthenticator() : null;
110114

111115
ServiceFactory serviceFactory = null;
112116
if (config.isBotConfigured()) {
@@ -128,6 +132,14 @@ protected SymphonyBdk(
128132
this.messageService = serviceFactory != null ? serviceFactory.getMessageService() : null;
129133
this.disclaimerService = serviceFactory != null ? serviceFactory.getDisclaimerService() : null;
130134

135+
if (serviceFactory != null && extAppAuthenticator != null) {
136+
this.extAppServices = new ExtAppServices(apiClientFactory.getPodClient(),
137+
extAppAuthenticator.authenticateExtApp(),
138+
new RetryWithRecoveryBuilder<>().retryConfig(this.config.getRetry()));
139+
} else {
140+
this.extAppServices = null;
141+
}
142+
131143
// retrieve bot session info
132144
this.botInfo = sessionService != null ? sessionService.getSession() : null;
133145

@@ -304,6 +316,10 @@ public OboServices obo(AuthSession oboSession) {
304316
return new OboServices(config, oboSession);
305317
}
306318

319+
public ExtAppServices apps() {
320+
return this.extAppServices;
321+
}
322+
307323
/**
308324
* Returns the {@link ExtensionAppAuthenticator}.
309325
*
@@ -313,6 +329,15 @@ public ExtensionAppAuthenticator appAuthenticator() {
313329
return this.getExtensionAppAuthenticator();
314330
}
315331

332+
/**
333+
* Returns the {@link ExtAppAuthenticator}.
334+
*
335+
* @return the {@link ExtAppAuthenticator}
336+
*/
337+
public ExtAppAuthenticator extAppAuthenticator() {
338+
return this.getExtAppAuthenticator();
339+
}
340+
316341
/**
317342
* Returns the Bot session.
318343
*
@@ -360,4 +385,9 @@ protected OboAuthenticator getOboAuthenticator() {
360385
return Optional.ofNullable(this.oboAuthenticator)
361386
.orElseThrow(() -> new IllegalStateException("OBO is not configured."));
362387
}
388+
389+
protected ExtAppAuthenticator getExtAppAuthenticator() {
390+
return Optional.ofNullable(this.extAppAuthenticator)
391+
.orElseThrow(() -> new IllegalStateException("Ext app is not configured."));
392+
}
363393
}

symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/AuthenticatorFactory.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,13 @@ public interface AuthenticatorFactory {
4343
*/
4444
@Nonnull
4545
ExtensionAppAuthenticator getExtensionAppAuthenticator() throws AuthInitializationException;
46+
47+
/**
48+
* Creates a new instance of a {@link ExtAppAuthenticator}.
49+
*
50+
* @return a new {@link ExtAppAuthenticator} instance.
51+
* @throws AuthInitializationException if the authenticator cannot be instantiated.
52+
*/
53+
@Nonnull
54+
ExtAppAuthenticator getExtAppAuthenticator() throws AuthInitializationException;
4655
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.symphony.bdk.core.auth;
2+
3+
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
4+
5+
import org.apiguardian.api.API;
6+
7+
import javax.annotation.Nullable;
8+
9+
/**
10+
* Extension App Authentication session handle. The {@link ExtAppAuthSession#refresh()} will trigger a re-auth against the API endpoints.
11+
*/
12+
@API(status = API.Status.STABLE)
13+
public interface ExtAppAuthSession {
14+
/**
15+
* Extension app session token.
16+
*
17+
* @return extension app session token
18+
*/
19+
@Nullable
20+
String getAppSession();
21+
22+
/**
23+
* Trigger re-authentication to refresh session token.
24+
*/
25+
void refresh() throws AuthUnauthorizedException;
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.symphony.bdk.core.auth;
2+
3+
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
4+
import org.apiguardian.api.API;
5+
6+
import javax.annotation.Nonnull;
7+
8+
/**
9+
* Extension App authenticator service.
10+
*/
11+
@API(status = API.Status.STABLE)
12+
public interface ExtAppAuthenticator {
13+
14+
/**
15+
* Authenticates an extension app.
16+
*
17+
* @return the authentication session.
18+
*/
19+
@Nonnull ExtAppAuthSession authenticateExtApp() throws AuthUnauthorizedException;
20+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.symphony.bdk.core.auth.impl;
2+
3+
import com.symphony.bdk.core.auth.ExtAppAuthenticator;
4+
import com.symphony.bdk.core.auth.OboAuthenticator;
5+
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
6+
import com.symphony.bdk.core.config.model.BdkRetryConfig;
7+
import com.symphony.bdk.http.api.ApiException;
8+
9+
import lombok.extern.slf4j.Slf4j;
10+
import org.apiguardian.api.API;
11+
12+
/**
13+
* Abstract class to factorize the {@link OboAuthenticator} logic between RSA and certificate,
14+
* especially the retry logic on top of HTTP calls.
15+
*/
16+
@Slf4j
17+
@API(status = API.Status.INTERNAL)
18+
public abstract class AbstractExtAppAuthenticator implements ExtAppAuthenticator {
19+
20+
protected final String appId;
21+
private final AuthenticationRetry<String> authenticationRetry;
22+
23+
protected AbstractExtAppAuthenticator(BdkRetryConfig retryConfig, String appId) {
24+
this.appId = appId;
25+
this.authenticationRetry = new AuthenticationRetry<>(retryConfig);
26+
}
27+
28+
protected String retrieveAppSessionToken() throws AuthUnauthorizedException {
29+
log.debug("Start authenticating app with id : {} ...", appId);
30+
31+
final String unauthorizedErrorMessage = "Unable to authenticate app with ID : " + appId + ". "
32+
+ "It usually happens when the app has not been configured or is not activated.";
33+
34+
return authenticationRetry.executeAndRetry("AbstractExtAppAuthenticator.retrieveAppSessionToken", getBasePath(),
35+
this::authenticateAndRetrieveAppSessionToken, unauthorizedErrorMessage);
36+
}
37+
38+
protected abstract String authenticateAndRetrieveAppSessionToken() throws ApiException;
39+
40+
protected abstract String getBasePath();
41+
}

symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthenticatorFactoryImpl.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,38 @@ ExtensionAppAuthenticator getExtensionAppAuthenticator() throws AuthInitializati
179179
throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
180180
}
181181

182+
@Nonnull
183+
@Override
184+
public ExtAppAuthenticator getExtAppAuthenticator() throws AuthInitializationException {
185+
if (this.config.getApp().isBothCertificateAndRsaConfigured()) {
186+
throw new AuthInitializationException(
187+
"Both of certificate and rsa authentication are configured. Only one of them should be provided.");
188+
}
189+
if (this.config.getApp().isCertificateAuthenticationConfigured()) {
190+
if (!this.config.getApp().isCertificateConfigurationValid()) {
191+
throw new AuthInitializationException(
192+
"Only one of certificate path or content should be configured for app authentication.");
193+
}
194+
return new ExtAppAuthenticatorCertImpl(
195+
this.config.getRetry(),
196+
this.config.getApp().getAppId(),
197+
this.apiClientFactory.getExtAppSessionAuthClient());
198+
}
199+
if (this.config.getApp().isRsaAuthenticationConfigured()) {
200+
if (!this.config.getApp().isRsaConfigurationValid()) {
201+
throw new AuthInitializationException(
202+
"Only one of private key path or content should be configured for app authentication.");
203+
}
204+
return new ExtAppAuthenticatorRsaImpl(
205+
this.config.getRetry(),
206+
this.config.getApp().getAppId(),
207+
this.loadPrivateKeyFromAuthenticationConfig(this.config.getApp()),
208+
this.apiClientFactory.getLoginClient()
209+
);
210+
}
211+
throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
212+
}
213+
182214
private PrivateKey loadPrivateKeyFromAuthenticationConfig(BdkAuthenticationConfig config)
183215
throws AuthInitializationException {
184216
String privateKeyPath = "";
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.symphony.bdk.core.auth.impl;
2+
3+
import com.symphony.bdk.core.auth.ExtAppAuthSession;
4+
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
5+
6+
import org.apiguardian.api.API;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
@API(status = API.Status.INTERNAL)
10+
public class ExtAppAuthSessionCertImpl implements ExtAppAuthSession {
11+
12+
String appSession;
13+
ExtAppAuthenticatorCertImpl authenticator;
14+
15+
public ExtAppAuthSessionCertImpl(ExtAppAuthenticatorCertImpl authenticator) {
16+
this.authenticator = authenticator;
17+
}
18+
19+
@Nullable
20+
@Override
21+
public String getAppSession() {
22+
return appSession;
23+
}
24+
25+
@Override
26+
public void refresh() throws AuthUnauthorizedException {
27+
this.appSession = this.authenticator.retrieveAppSessionToken();
28+
}
29+
}

0 commit comments

Comments
 (0)