Skip to content

Commit 86cadf7

Browse files
authored
Merge pull request cloudant#443 from cloudant/support-legacy-creds-with-iam
Added support for IAM API key in bluemix method
2 parents 981be62 + a2ee717 commit 86cadf7

File tree

8 files changed

+377
-146
lines changed

8 files changed

+377
-146
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [NEW] Add `ComplexKey.addHighSentinel()` to allow matching of all values as part of a complex key
88
range.
99
- [NEW] Support IAM authentication in replication documents.
10+
- [IMPROVED] Added support for IAM API key in the client builder `bluemix` method.
1011
- [IMPROVED] When making view requests (including `_all_docs`), set `keys` in the `POST` body rather
1112
than in `GET` query parameters. This is because a large number of keys could previously exceed the
1213
maximum URL length, causing errors.

Jenkinsfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ def runTests(testEnv, isServiceTests) {
2727

2828
//Set up the environment and run the tests
2929
withEnv(testEnv) {
30-
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: env.CREDS_ID, usernameVariable: 'DB_USER', passwordVariable: 'DB_PASSWORD']]) {
30+
withCredentials([usernamePassword(credentialsId: 'clientlibs-test', usernameVariable: 'DB_USER', passwordVariable: 'DB_PASSWORD'),
31+
string(credentialsId: 'clientlibs-test-iam', variable: 'DB_IAM_API_KEY')]) {
3132
try {
32-
sh './gradlew -Dtest.couch.username=$DB_USER -Dtest.couch.password=$DB_PASSWORD -Dtest.couch.host=$DB_HOST -Dtest.couch.port=$DB_PORT -Dtest.couch.http=$DB_HTTP $GRADLE_TARGET'
33+
sh './gradlew -Dtest.couch.username=$DB_USER -Dtest.couch.password=$DB_PASSWORD -Dtest.couch.host=$DB_HOST -Dtest.couch.port=$DB_PORT -Dtest.couch.http=$DB_HTTP -Dtest.couch.iam.api.key=$DB_IAM_API_KEY $GRADLE_TARGET'
3334
} finally {
3435
junit '**/build/test-results/**/*.xml'
3536
}

cloudant-client/src/main/java/com/cloudant/client/api/ClientBuilder.java

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright © 2015, 2017 IBM Corp. All rights reserved.
2+
* Copyright © 2015, 2018 IBM Corp. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
55
* except in compliance with the License. You may obtain a copy of the License at
@@ -180,12 +180,8 @@ public class ClientBuilder {
180180
*/
181181
public static ClientBuilder account(String account) {
182182
logger.config("Account: " + account);
183-
try {
184-
URL url = new URL(String.format("https://%s.cloudant.com", account));
185-
return ClientBuilder.url(url);
186-
} catch (MalformedURLException e) {
187-
throw new IllegalArgumentException("Could not generate url from account name.", e);
188-
}
183+
return ClientBuilder.url(
184+
convertStringToURL(String.format("https://%s.cloudant.com", account)));
189185
}
190186

191187
/**
@@ -229,17 +225,13 @@ private ClientBuilder(URL url) {
229225
String urlPath = url.getPath().trim();
230226
urlPath = urlPath.endsWith("/") ? urlPath.substring(0, urlPath.length() - 1) : urlPath;
231227

232-
try {
233-
// Reconstruct URL without user credentials
234-
this.url = new URL(urlProtocol
235-
+ "://"
236-
+ urlHost
237-
+ ":"
238-
+ urlPort
239-
+ urlPath);
240-
} catch (MalformedURLException e) {
241-
throw new RuntimeException(e);
242-
}
228+
// Reconstruct URL without user credentials
229+
this.url = convertStringToURL(urlProtocol
230+
+ "://"
231+
+ urlHost
232+
+ ":"
233+
+ urlPort
234+
+ urlPath);
243235
}
244236

245237

@@ -748,11 +740,7 @@ public static ClientBuilder bluemix(String vcapServices, String serviceName, Str
748740
if (instanceName == null) {
749741
if (cloudantServices.size() == 1) {
750742
CloudFoundryService cloudantService = cloudantServices.get(0);
751-
if (cloudantService.credentials == null || cloudantService.credentials.url == null) {
752-
throw new IllegalArgumentException(
753-
"The Cloudant service instance information was invalid.");
754-
}
755-
return ClientBuilder.url(cloudantService.credentials.url);
743+
return vcapClientBuilder(cloudantService);
756744
} else {
757745
throw new IllegalArgumentException("Multiple Cloudant service instances present. " +
758746
"A service instance name must be specified.");
@@ -761,11 +749,7 @@ public static ClientBuilder bluemix(String vcapServices, String serviceName, Str
761749

762750
for (CloudFoundryService cloudantService : cloudantServices) {
763751
if (instanceName.equals(cloudantService.name)) {
764-
if (cloudantService.credentials == null || cloudantService.credentials.url == null) {
765-
throw new IllegalArgumentException(
766-
"The Cloudant service instance information was invalid.");
767-
}
768-
return ClientBuilder.url(cloudantService.credentials.url);
752+
return vcapClientBuilder(cloudantService);
769753
}
770754
}
771755

@@ -774,6 +758,30 @@ public static ClientBuilder bluemix(String vcapServices, String serviceName, Str
774758
);
775759
}
776760

761+
private static ClientBuilder vcapClientBuilder(CloudFoundryService cloudantService) {
762+
// Create client with IAM if the API key exists
763+
if (cloudantService.credentials != null
764+
&& cloudantService.credentials.host != null) {
765+
URL vcapUrl = convertStringToURL(
766+
String.format("https://%s", cloudantService.credentials.host));
767+
ClientBuilder clientBuilder = ClientBuilder.url(vcapUrl);
768+
if (cloudantService.credentials.apikey != null) {
769+
return clientBuilder.iamApiKey(cloudantService.credentials.apikey);
770+
} else if (cloudantService.credentials.username != null
771+
&& cloudantService.credentials.password != null) {
772+
return clientBuilder.username(cloudantService.credentials.username)
773+
.password(cloudantService.credentials.password);
774+
} else {
775+
throw new IllegalArgumentException(
776+
"The Cloudant service instance is missing the IAM API key, " +
777+
"or both the username and password credential properties.");
778+
}
779+
} else {
780+
throw new IllegalArgumentException(
781+
"The Cloudant service instance information was invalid.");
782+
}
783+
}
784+
777785
/**
778786
* Sets the
779787
* <a href="https://console.bluemix.net/docs/services/Cloudant/guides/iam.html#ibm-cloud-identity-and-access-management"
@@ -787,4 +795,11 @@ public ClientBuilder iamApiKey(String iamApiKey) {
787795
return this;
788796
}
789797

798+
private static URL convertStringToURL(String urlAsString) {
799+
try {
800+
return new URL(urlAsString);
801+
} catch (MalformedURLException e) {
802+
throw new RuntimeException(e);
803+
}
804+
}
790805
}

cloudant-client/src/main/java/com/cloudant/client/internal/util/CloudFoundryService.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright © 2016 IBM Corp. All rights reserved.
2+
* Copyright © 2016, 2018 IBM Corp. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
55
* except in compliance with the License. You may obtain a copy of the License at
@@ -14,6 +14,8 @@
1414

1515
package com.cloudant.client.internal.util;
1616

17+
import com.google.gson.annotations.SerializedName;
18+
1719
import java.net.URL;
1820

1921

@@ -24,6 +26,13 @@ public class CloudFoundryService {
2426

2527
public static class CloudFoundryServiceCredentials {
2628

27-
public URL url;
29+
@SerializedName("apikey")
30+
public String apikey;
31+
@SerializedName("host")
32+
public String host;
33+
@SerializedName("username")
34+
public String username;
35+
@SerializedName("password")
36+
public String password;
2837
}
2938
}

0 commit comments

Comments
 (0)