Skip to content

Commit aee6208

Browse files
Support Two-legged OAuth flow (#874)
1 parent 8e0f089 commit aee6208

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ dependencies {
7171
compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '2.10.0'
7272
compile group: 'io.grpc', name: 'grpc-testing', version: '1.54.2'
7373
compile group: 'com.google.protobuf', name: 'protobuf-java-util', version: '3.21.9'
74+
compile group: 'com.google.oauth-client', name: 'google-oauth-client', version: '1.35.0'
75+
compile group: 'com.google.http-client', name: 'google-http-client-gson', version: '1.19.0'
7476

7577
implementation 'io.grpc:grpc-netty-shaded:1.54.2'
7678
implementation 'io.grpc:grpc-protobuf:1.54.2'

src/main/java/com/uber/cadence/internal/compatibility/proto/serviceclient/GrpcServiceStubs.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.uber.cadence.internal.Version;
3535
import com.uber.cadence.internal.tracing.TracingPropagator;
3636
import com.uber.cadence.serviceclient.ClientOptions;
37+
import com.uber.cadence.serviceclient.auth.IAuthorizationProvider;
3738
import io.grpc.CallOptions;
3839
import io.grpc.Channel;
3940
import io.grpc.ClientCall;
@@ -53,6 +54,7 @@
5354
import io.opentelemetry.context.propagation.TextMapSetter;
5455
import io.opentracing.Span;
5556
import io.opentracing.Tracer;
57+
import java.nio.charset.StandardCharsets;
5658
import java.util.HashMap;
5759
import java.util.Map;
5860
import java.util.Objects;
@@ -79,6 +81,9 @@ final class GrpcServiceStubs implements IGrpcServiceStubs {
7981
private static final Metadata.Key<String> RPC_ENCODING_HEADER_KEY =
8082
Metadata.Key.of("rpc-encoding", Metadata.ASCII_STRING_MARSHALLER);
8183

84+
private static final Metadata.Key<String> AUTHORIZATION_HEADER_KEY =
85+
Metadata.Key.of("cadence-authorization", Metadata.ASCII_STRING_MARSHALLER);
86+
8287
private static final String CLIENT_IMPL_HEADER_VALUE = "uber-java";
8388

8489
private final ClientOptions options;
@@ -121,6 +126,7 @@ final class GrpcServiceStubs implements IGrpcServiceStubs {
121126
if (!Strings.isNullOrEmpty(options.getIsolationGroup())) {
122127
headers.put(ISOLATION_GROUP_HEADER_KEY, options.getIsolationGroup());
123128
}
129+
124130
Channel interceptedChannel =
125131
ClientInterceptors.intercept(
126132
channel,
@@ -131,6 +137,11 @@ final class GrpcServiceStubs implements IGrpcServiceStubs {
131137
if (log.isTraceEnabled()) {
132138
interceptedChannel = ClientInterceptors.intercept(interceptedChannel, tracingInterceptor);
133139
}
140+
if (options.getAuthProvider() != null) {
141+
interceptedChannel =
142+
ClientInterceptors.intercept(
143+
interceptedChannel, newAuthorizationInterceptor(options.getAuthProvider()));
144+
}
134145
this.domainBlockingStub = DomainAPIGrpc.newBlockingStub(interceptedChannel);
135146
this.domainFutureStub = DomainAPIGrpc.newFutureStub(interceptedChannel);
136147
this.visibilityBlockingStub = VisibilityAPIGrpc.newBlockingStub(interceptedChannel);
@@ -143,6 +154,36 @@ final class GrpcServiceStubs implements IGrpcServiceStubs {
143154
this.metaFutureStub = MetaAPIGrpc.newFutureStub(interceptedChannel);
144155
}
145156

157+
private ClientInterceptor newAuthorizationInterceptor(IAuthorizationProvider provider) {
158+
return new ClientInterceptor() {
159+
@Override
160+
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
161+
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
162+
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
163+
next.newCall(method, callOptions)) {
164+
165+
@Override
166+
public void start(Listener<RespT> responseListener, Metadata headers) {
167+
headers.put(
168+
AUTHORIZATION_HEADER_KEY,
169+
new String(provider.getAuthToken(), StandardCharsets.UTF_8));
170+
171+
Listener<RespT> listener =
172+
new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(
173+
responseListener) {
174+
175+
@Override
176+
public void onHeaders(Metadata headers) {
177+
super.onHeaders(headers);
178+
}
179+
};
180+
super.start(listener, headers);
181+
}
182+
};
183+
}
184+
};
185+
}
186+
146187
private ClientInterceptor newOpenTelemetryInterceptor() {
147188
return new ClientInterceptor() {
148189
@Override
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* <p>Modifications copyright (C) 2017 Uber Technologies, Inc.
5+
*
6+
* <p>Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
7+
* except in compliance with the License. A copy of the License is located at
8+
*
9+
* <p>http://aws.amazon.com/apache2.0
10+
*
11+
* <p>or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
13+
* specific language governing permissions and limitations under the License.
14+
*/
15+
package com.uber.cadence.serviceclient.auth;
16+
17+
import com.google.api.client.auth.oauth2.ClientCredentialsTokenRequest;
18+
import com.google.api.client.auth.oauth2.ClientParametersAuthentication;
19+
import com.google.api.client.auth.oauth2.TokenResponse;
20+
import com.google.api.client.http.GenericUrl;
21+
import com.google.api.client.http.HttpTransport;
22+
import com.google.api.client.http.javanet.NetHttpTransport;
23+
import com.google.api.client.json.JsonFactory;
24+
import com.google.api.client.json.gson.GsonFactory;
25+
import java.io.IOException;
26+
import java.nio.charset.StandardCharsets;
27+
import java.time.Instant;
28+
import java.util.List;
29+
30+
public class OAuthAuthorizationProvider implements IAuthorizationProvider {
31+
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
32+
33+
private Instant nextRefresh;
34+
35+
private final ClientCredentialsTokenRequest tokenRequest;
36+
37+
private TokenResponse token;
38+
39+
static final JsonFactory JSON_FACTORY = new GsonFactory();
40+
41+
public OAuthAuthorizationProvider(
42+
String clientId, String clientSecret, String url, List<String> scopes) {
43+
this.tokenRequest =
44+
new ClientCredentialsTokenRequest(HTTP_TRANSPORT, JSON_FACTORY, new GenericUrl(url))
45+
.setClientAuthentication(new ClientParametersAuthentication(clientId, clientSecret))
46+
.setScopes(scopes);
47+
}
48+
49+
@Override
50+
public byte[] getAuthToken() {
51+
return fetchToken().getBytes(StandardCharsets.UTF_8);
52+
}
53+
54+
private synchronized String fetchToken() {
55+
if (this.nextRefresh == null || Instant.now().isAfter(this.nextRefresh)) {
56+
try {
57+
this.token = this.tokenRequest.execute();
58+
this.nextRefresh = Instant.now().plusSeconds(this.token.getExpiresInSeconds());
59+
} catch (IOException e) {
60+
return "";
61+
}
62+
}
63+
return this.token.getAccessToken();
64+
}
65+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.uber.cadence.serviceclient.auth;
2+
3+
import static org.junit.Assert.*;
4+
5+
import org.junit.Assert;
6+
import org.junit.Test;
7+
8+
public class OAuthAuthorizationProviderTest {
9+
@Test
10+
public void testConstructorWillThrowException() {
11+
try {
12+
final OAuthAuthorizationProvider provider =
13+
new OAuthAuthorizationProvider("a", "b", "c", null);
14+
} catch (IllegalArgumentException e) {
15+
Assert.assertEquals(IllegalArgumentException.class, e.getClass());
16+
}
17+
}
18+
19+
@Test
20+
public void testClientWillReturnEmptyOnWrongServer() {
21+
22+
final OAuthAuthorizationProvider provider =
23+
new OAuthAuthorizationProvider("a", "b", "https://test", null);
24+
25+
byte[] token = provider.getAuthToken();
26+
27+
assertEquals(0, token.length);
28+
}
29+
}

0 commit comments

Comments
 (0)