Skip to content

Commit 129a8fb

Browse files
authored
Fix oauth test failures causing build to fail (#6030)
1 parent 2ee79f2 commit 129a8fb

File tree

2 files changed

+40
-28
lines changed

2 files changed

+40
-28
lines changed

airbyte-oauth/src/main/java/io/airbyte/oauth/google/GoogleOAuthFlow.java

+23-20
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,17 @@
3939
import io.airbyte.validation.json.JsonValidationException;
4040
import java.io.IOException;
4141
import java.net.URI;
42+
import java.net.URISyntaxException;
4243
import java.net.URLEncoder;
4344
import java.net.http.HttpClient;
4445
import java.net.http.HttpClient.Version;
4546
import java.net.http.HttpRequest;
4647
import java.net.http.HttpResponse;
4748
import java.nio.charset.StandardCharsets;
48-
import java.util.List;
4949
import java.util.Map;
5050
import java.util.Optional;
5151
import java.util.UUID;
52+
import org.apache.http.client.utils.URIBuilder;
5253

5354
/**
5455
* Following docs from https://developers.google.com/identity/protocols/oauth2/web-server
@@ -61,7 +62,7 @@ public class GoogleOAuthFlow implements OAuthFlowImplementation {
6162
private final static String ACCESS_TOKEN_URL = "https://oauth2.googleapis.com/token";
6263

6364
private final String scope;
64-
private final List<String> googleQueryParameters;
65+
private final Map<String, String> defaultQueryParams;
6566

6667
private final ConfigRepository configRepository;
6768

@@ -73,13 +74,15 @@ public GoogleOAuthFlow(ConfigRepository configRepository, String scope) {
7374
GoogleOAuthFlow(ConfigRepository configRepository, String scope, HttpClient httpClient) {
7475
this.configRepository = configRepository;
7576
this.httpClient = httpClient;
76-
this.scope = UrlEncode(scope);
77-
this.googleQueryParameters = List.of(
78-
String.format("scope=%s", this.scope),
79-
"access_type=offline",
80-
"include_granted_scopes=true",
81-
"response_type=code",
82-
"prompt=consent");
77+
this.scope = scope;
78+
this.defaultQueryParams = ImmutableMap.<String, String>builder()
79+
.put("scope", this.scope)
80+
.put("access_type", "offline")
81+
.put("include_granted_scopes", "true")
82+
.put("response_type", "code")
83+
.put("prompt", "consent")
84+
.build();
85+
8386
}
8487

8588
@Override
@@ -96,18 +99,18 @@ public String getDestinationConsentUrl(UUID workspaceId, UUID destinationDefinit
9699
}
97100

98101
private String getConsentUrl(UUID definitionId, String clientId, String redirectUrl) {
99-
final StringBuilder result = new StringBuilder(CONSENT_URL)
100-
.append("?");
101-
for (String queryParameter : googleQueryParameters) {
102-
result.append(queryParameter).append("&");
102+
try {
103+
URIBuilder uriBuilder = new URIBuilder(CONSENT_URL)
104+
.addParameter("state", definitionId.toString())
105+
.addParameter("client_id", clientId)
106+
.addParameter("redirect_uri", redirectUrl);
107+
for (Map.Entry<String, String> queryParameter : defaultQueryParams.entrySet()) {
108+
uriBuilder.addParameter(queryParameter.getKey(), queryParameter.getValue());
109+
}
110+
return uriBuilder.toString();
111+
} catch (URISyntaxException e) {
112+
throw new IllegalArgumentException(e);
103113
}
104-
return result
105-
// TODO state should be randomly generated, and the 2nd step of oauth should verify its value
106-
// matches the initially generated state value
107-
.append("state=").append(definitionId.toString()).append("&")
108-
.append("client_id=").append(clientId).append("&")
109-
.append("redirect_uri=").append(redirectUrl)
110-
.toString();
111114
}
112115

113116
@Override

airbyte-oauth/src/test/java/io/airbyte/oauth/google/GoogleOAuthFlowTest.java

+17-8
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
import io.airbyte.config.persistence.ConfigRepository;
4040
import io.airbyte.validation.json.JsonValidationException;
4141
import java.io.IOException;
42+
import java.net.URLEncoder;
4243
import java.net.http.HttpClient;
4344
import java.net.http.HttpResponse;
45+
import java.nio.charset.StandardCharsets;
4446
import java.nio.file.Files;
4547
import java.nio.file.Path;
4648
import java.util.List;
@@ -55,8 +57,8 @@ public class GoogleOAuthFlowTest {
5557

5658
private static final Logger LOGGER = LoggerFactory.getLogger(GoogleOAuthFlowTest.class);
5759
private static final Path CREDENTIALS_PATH = Path.of("secrets/credentials.json");
58-
private static final String REDIRECT_URL = "https%3A//airbyte.io";
59-
private static final String SCOPE = "https%3A//www.googleapis.com/auth/analytics.readonly";
60+
private static final String REDIRECT_URL = "https://airbyte.io";
61+
private static final String SCOPE = "https://www.googleapis.com/auth/analytics.readonly";
6062

6163
private HttpClient httpClient;
6264
private ConfigRepository configRepository;
@@ -108,11 +110,11 @@ public void testGetSourceConsentUrl() throws IOException, ConfigNotFoundExceptio
108110
.build()))));
109111
final String actualSourceUrl = googleOAuthFlow.getSourceConsentUrl(workspaceId, definitionId, REDIRECT_URL);
110112
final String expectedSourceUrl = String.format(
111-
"https://accounts.google.com/o/oauth2/v2/auth?scope=%s&access_type=offline&include_granted_scopes=true&response_type=code&prompt=consent&state=%s&client_id=%s&redirect_uri=%s",
112-
SCOPE,
113+
"https://accounts.google.com/o/oauth2/v2/auth?state=%s&client_id=%s&redirect_uri=%s&scope=%s&access_type=offline&include_granted_scopes=true&response_type=code&prompt=consent",
113114
definitionId,
114115
getClientId(),
115-
REDIRECT_URL);
116+
urlEncode(REDIRECT_URL),
117+
urlEncode(SCOPE));
116118
LOGGER.info(expectedSourceUrl);
117119
assertEquals(expectedSourceUrl, actualSourceUrl);
118120
}
@@ -126,13 +128,16 @@ public void testGetDestinationConsentUrl() throws IOException, ConfigNotFoundExc
126128
.withConfiguration(Jsons.jsonNode(ImmutableMap.builder()
127129
.put("client_id", getClientId())
128130
.build()))));
131+
// It would be better to make this comparison agnostic of the order of query params but the URI
132+
// class' equals() method
133+
// considers URLs with different qparam orders different URIs..
129134
final String actualDestinationUrl = googleOAuthFlow.getDestinationConsentUrl(workspaceId, definitionId, REDIRECT_URL);
130135
final String expectedDestinationUrl = String.format(
131-
"https://accounts.google.com/o/oauth2/v2/auth?scope=%s&access_type=offline&include_granted_scopes=true&response_type=code&prompt=consent&state=%s&client_id=%s&redirect_uri=%s",
132-
SCOPE,
136+
"https://accounts.google.com/o/oauth2/v2/auth?state=%s&client_id=%s&redirect_uri=%s&scope=%s&access_type=offline&include_granted_scopes=true&response_type=code&prompt=consent",
133137
definitionId,
134138
getClientId(),
135-
REDIRECT_URL);
139+
urlEncode(REDIRECT_URL),
140+
urlEncode(SCOPE));
136141
LOGGER.info(expectedDestinationUrl);
137142
assertEquals(expectedDestinationUrl, actualDestinationUrl);
138143
}
@@ -201,4 +206,8 @@ private String getClientId() throws IOException {
201206
}
202207
}
203208

209+
private String urlEncode(String s) {
210+
return URLEncoder.encode(s, StandardCharsets.UTF_8);
211+
}
212+
204213
}

0 commit comments

Comments
 (0)