Skip to content

Commit 3ed8aa8

Browse files
author
vivetiwa
committed
1. JWT token support - #14
2. Optional headers support that could be sent to AEP endpoint - Could be use to support raw ingestion 3. Upgrade gradle wrapper from 5.2.1 to 7.0 - jar could be build without installing java separately 4. Default java build to JDK 11, mark JDK 8 build as deprecated 5. Developer guide to use jwt token for authentication
1 parent 1682709 commit 3ed8aa8

File tree

14 files changed

+169
-46
lines changed

14 files changed

+169
-46
lines changed

DEVELOPER_GUIDE.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ curl -s -X POST \
186186

187187
#### Authentication Enabled
188188

189-
Use the command below to set up an Sink connector to a Authenticated Streaming Connection:
189+
Use the command below to set up a Sink connector to a Authenticated Streaming Connection:
190190

191+
1. Using access_token
191192
```
192193
curl -s -X POST \
193194
-H "Content-Type: application/json" \
@@ -211,6 +212,51 @@ curl -s -X POST \
211212
}' http://localhost:8083/connectors
212213
```
213214

215+
2. Using jwt_token
216+
- Convert private.key from adobe console to PKCS8 private using command
217+
```
218+
openssl pkcs8 -topk8 -inform PEM -outform DER -in private.key -out private-pkcs8.key -nocrypt
219+
```
220+
221+
- Create http connector
222+
```
223+
curl -s -X POST \
224+
-H "Content-Type: application/json" \
225+
--data '{
226+
"name": "aep-auth-sink-connector",
227+
"config": {
228+
"topics": "connect-test",
229+
"tasks.max": 1,
230+
"aep.flush.interval.seconds": 1,
231+
"aep.flush.bytes.kb": 4,
232+
"connector.class": "com.adobe.platform.streaming.sink.impl.AEPSinkConnector",
233+
"key.converter.schemas.enable": "false",
234+
"value.converter.schemas.enable": "false",
235+
"aep.endpoint": "https://dcs.adobedc.net/collection/{DATA_INLET_ID}",
236+
"aep.connection.auth.enabled": true,
237+
"aep.connection.auth.token.type": "jwt_token",
238+
"aep.connection.auth.client.id": "<client_id>",
239+
"aep.connection.auth.imsOrg": "<organization-id>",
240+
"aep.connection.auth.accountKey": "<technical-account-id>",
241+
"aep.connection.auth.filePath": "<path-to-private-pkcs8.key>",
242+
"aep.connection.auth.endpoint": "<ims-url>",
243+
"aep.connection.endpoint.headers": "<optional-header-that-needs-to-be-passed-to-AEP>"
244+
"aep.connection.auth.client.secret": "<client_secret>"
245+
}
246+
}' http://localhost:8083/connectors
247+
```
248+
Note - `aep.connection.endpoint.headers` format should be comma separated.
249+
Example: To send below 2 http header -
250+
1. key: x-adobe-flow-id, value: 341fd4f0-cdec-4912-1ab6-fb54aeb41286
251+
2. key: x-adobe-dataset-id, value: 3096fbfd5978431948af3ba3
252+
253+
Use `aep.connection.endpoint.headers` value -
254+
```
255+
{'x-adobe-flow-id':'341fd4f0-cdec-4912-1ab6-fb54aeb41286','x-adobe-dataset-id': '3096fbfd5978431948af3ba3'}
256+
```
257+
258+
259+
214260
#### Batching
215261

216262
Use the command below to set up an Sink connector to batch up requests and reduce the number of network calls

build.gradle

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
buildscript {
1414
repositories {
1515
jcenter()
16+
mavenCentral()
1617
}
1718

1819
dependencies {
19-
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.3'
20+
classpath 'com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:6.1.0'
2021
}
2122
}
2223

@@ -34,6 +35,7 @@ description 'Adobe Experience Platform Streaming Connect'
3435

3536
repositories {
3637
jcenter()
38+
mavenCentral()
3739
}
3840

3941
subprojects {
@@ -55,8 +57,23 @@ subprojects {
5557
toolVersion '8.10.1'
5658
}
5759

60+
var compileJavaVersion = System.getenv("JAVA_COMPILATION_VERSION") == null ? (JavaVersion.current().getMajorVersion() == "" ? "11" :
61+
JavaVersion.current().getMajorVersion()) : System.getenv("JAVA_COMPILATION_VERSION")
62+
63+
ext {
64+
branchName = System.getenv("BRANCHNAME") ?: grgit.branch.current().getName()
65+
compileVersion = compileJavaVersion + (JavaVersion.toVersion(compileJavaVersion) <= JavaVersion.VERSION_1_8 ? "-deprecated" : "")
66+
}
67+
68+
java {
69+
toolchain {
70+
languageVersion.set(JavaLanguageVersion.of(JavaVersion.toVersion(compileJavaVersion).getMajorVersion()))
71+
}
72+
}
73+
5874
repositories {
5975
jcenter()
76+
mavenCentral()
6077

6178
publishing {
6279
repositories {
@@ -79,12 +96,6 @@ subprojects {
7996
}
8097
}
8198

82-
compileJava {
83-
sourceCompatibility = 1.8
84-
targetCompatibility = 1.8
85-
options.deprecation = true
86-
}
87-
8899
compileTestJava {
89100
options.deprecation = true
90101
}

gradle/wrapper/gradle-wrapper.jar

-556 Bytes
Binary file not shown.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

gradlew

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
#!/usr/bin/env sh
22

3+
#
4+
# Copyright 2015 the original author or authors.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# https://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
319
##############################################################################
420
##
521
## Gradle start up script for UN*X
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
2844
APP_BASE_NAME=`basename "$0"`
2945

3046
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31-
DEFAULT_JVM_OPTS=""
47+
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
3248

3349
# Use the maximum available, or set MAX_FD != -1 to use that value.
3450
MAX_FD="maximum"
@@ -109,8 +125,8 @@ if $darwin; then
109125
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110126
fi
111127

112-
# For Cygwin, switch paths to Windows format before running java
113-
if $cygwin ; then
128+
# For Cygwin or MSYS, switch paths to Windows format before running java
129+
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
114130
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115131
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116132
JAVACMD=`cygpath --unix "$JAVACMD"`

gradlew.bat

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
@rem
2+
@rem Copyright 2015 the original author or authors.
3+
@rem
4+
@rem Licensed under the Apache License, Version 2.0 (the "License");
5+
@rem you may not use this file except in compliance with the License.
6+
@rem You may obtain a copy of the License at
7+
@rem
8+
@rem https://www.apache.org/licenses/LICENSE-2.0
9+
@rem
10+
@rem Unless required by applicable law or agreed to in writing, software
11+
@rem distributed under the License is distributed on an "AS IS" BASIS,
12+
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
@rem See the License for the specific language governing permissions and
14+
@rem limitations under the License.
15+
@rem
16+
117
@if "%DEBUG%" == "" @echo off
218
@rem ##########################################################################
319
@rem
@@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
1430
set APP_HOME=%DIRNAME%
1531

1632
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17-
set DEFAULT_JVM_OPTS=
33+
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
1834

1935
@rem Find java.exe
2036
if defined JAVA_HOME goto findJavaFromJavaHome

settings.gradle

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ pluginManagement {
1818

1919
rootProject.name = 'experience-platform-streaming-connect'
2020

21-
include 'streaming-connect-common'
22-
include 'streaming-connect-sink'
21+
include ':streaming-connect-common'
22+
include ':streaming-connect-sink'
23+
24+
project(':streaming-connect-common').projectDir = file('streaming-connect-common')
25+
project(':streaming-connect-sink').projectDir = file('streaming-connect-sink')

streaming-connect-common/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
apply from: '../dependencies.gradle'
1414

1515
dependencies {
16-
libraries.with {
17-
compile collections4, commonslang, guava, httpClient, jackson, jmockit, junitJupiter, jjwt, orgJson, slf4j, jaxb
18-
testCompile jmockit, junitJupiter
19-
}
16+
implementation libraries.collections4, libraries.commonslang, libraries.guava,
17+
libraries.httpClient, libraries.jackson, libraries.jmockit, libraries.junitJupiter,
18+
libraries.jjwt, libraries.orgJson, libraries.slf4j, libraries.jaxb
19+
testImplementation libraries.jmockit, libraries.junitJupiter
2020
}

streaming-connect-common/src/main/java/com/adobe/platform/streaming/auth/impl/AuthProviderFactory.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,21 @@ private static AuthProvider getIMSAuthProvider(Map<String, String> authPropertie
6161
}
6262

6363
private static AuthProvider getJWTAuthProvider(Map<String, String> authProperties) {
64-
String clientId = authProperties.get(AuthUtils.AUTH_CLIENT_ID);
65-
String imsOrgId = authProperties.get(AuthUtils.AUTH_IMS_ORG_ID);
66-
String technicalAccountKey = authProperties.get(AuthUtils.AUTH_TECHNICAL_ACCOUNT_ID);
67-
String filePath = authProperties.get(AuthUtils.AUTH_PRIVATE_KEY_FILE_PATH);
64+
final String clientId = authProperties.get(AuthUtils.AUTH_CLIENT_ID);
65+
final String clientSecret = authProperties.get(AuthUtils.AUTH_CLIENT_SECRET);
66+
final String imsOrgId = authProperties.get(AuthUtils.AUTH_IMS_ORG_ID);
67+
final String technicalAccountKey = authProperties.get(AuthUtils.AUTH_TECHNICAL_ACCOUNT_ID);
68+
final String filePath = authProperties.get(AuthUtils.AUTH_PRIVATE_KEY_FILE_PATH);
6869

6970
Preconditions.checkNotNull(clientId, "Invalid client Id");
71+
Preconditions.checkNotNull(clientSecret, "Invalid client secret.");
7072
Preconditions.checkNotNull(imsOrgId, "Invalid IMS Org");
7173
Preconditions.checkNotNull(technicalAccountKey, "Invalid technical account Id");
7274

7375
String endpoint = authProperties.get(AuthUtils.AUTH_ENDPOINT);
7476
return StringUtils.isEmpty(endpoint) ?
75-
new JWTTokenProvider(clientId, imsOrgId, technicalAccountKey, filePath) :
76-
new JWTTokenProvider(endpoint, clientId, imsOrgId, technicalAccountKey, filePath);
77+
new JWTTokenProvider(clientId, clientSecret, imsOrgId, technicalAccountKey, filePath) :
78+
new JWTTokenProvider(endpoint, clientId, clientSecret, imsOrgId, technicalAccountKey, filePath);
7779
}
7880

7981
private AuthProviderFactory() {}

streaming-connect-common/src/main/java/com/adobe/platform/streaming/auth/impl/JWTTokenProvider.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,35 +61,37 @@ public class JWTTokenProvider extends AbstractAuthProvider {
6161
private final String imsOrgId;
6262
private final String technicalAccountKey;
6363
private final String clientId;
64+
private final String clientSecret;
6465
private final String keyPath;
6566
private String jwtToken;
6667

67-
JWTTokenProvider(String endpoint, String imsOrgId, String clientId, String technicalAccountKey,
68+
JWTTokenProvider(String endpoint, String clientId, String clientSecret, String imsOrgId, String technicalAccountKey,
6869
String keyPath) {
69-
this(imsOrgId, clientId, technicalAccountKey, keyPath);
70+
this(clientId, clientSecret, imsOrgId, technicalAccountKey, keyPath);
7071
this.endpoint = endpoint;
7172
}
7273

73-
JWTTokenProvider(String imsOrgId, String clientId, String technicalAccountKey, String keyPath) {
74+
JWTTokenProvider(String clientId, String clientSecret, String imsOrgId, String technicalAccountKey, String keyPath) {
7475
this.imsOrgId = imsOrgId;
7576
this.clientId = clientId;
77+
this.clientSecret = clientSecret;
7678
this.technicalAccountKey = technicalAccountKey;
7779
this.keyPath = keyPath;
7880
}
7981

8082
@Override
8183
protected TokenResponse getTokenResponse() throws AuthException {
8284
LOG.debug("refreshing expired jwtToken: {}", clientId);
83-
StringBuffer params = new StringBuffer()
85+
StringBuilder params = new StringBuilder()
8486
.append("&client_id=").append(clientId)
85-
.append("&client_secret=").append(technicalAccountKey)
87+
.append("&client_secret=").append(clientSecret)
8688
.append("&jwt_token=").append(getJWTToken());
8789

8890
try {
8991
return HttpProducer.newBuilder(endpoint).build().post(
9092
IMS_ENDPOINT_PATH,
9193
params.toString().getBytes(),
92-
ContentType.MULTIPART_FORM_DATA.getMimeType(),
94+
ContentType.APPLICATION_FORM_URLENCODED.getMimeType(),
9395
getContentHandler()
9496
);
9597
} catch (HttpException httpException) {
@@ -151,7 +153,7 @@ private boolean isJWTExpired() {
151153
StandardCharsets.UTF_8.name()
152154
);
153155
JSONObject tokenBodyJson = new JSONObject(tokenBody);
154-
Long expiresIn = (Long)tokenBodyJson.get(JWT_EXPIRY_KEY);
156+
long expiresIn = ((Number)tokenBodyJson.get(JWT_EXPIRY_KEY)).longValue();
155157
return System.currentTimeMillis() <= (expiresIn - DEFAULT_JWT_TOKEN_UPDATE_THRESHOLD);
156158
} catch (UnsupportedEncodingException exception) {
157159
LOG.error("Exception while parsing JWT token", exception);

0 commit comments

Comments
 (0)