Skip to content

Commit 4ad4092

Browse files
Mike Kistlergermanattanasio
authored andcommitted
feat(IAM): Add support for IAM Auth and LTv3 (#9)
This PR adds support for Watson services that use IAM authentication. It also replaces the Language Translator V2 service with Language Translator V3. The code in this PR is not yet fully tested, but I wanted to get feedback on these changes before going further.
1 parent 90da5fe commit 4ad4092

13 files changed

+245
-37
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.1.0
2+
current_version = 0.2.0
33
commit = True
44
tag = True
55

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ All you need to do is:
2020
<dependency>
2121
<groupId>com.ibm.watson.developer_cloud</groupId>
2222
<artifactId>watson-spring-boot-starter</artifactId>
23-
<version>0.1.0</version>
23+
<version>0.2.0</version>
2424
</dependency>
2525
```
2626
2727
or in your gradle `build.gradle`, in the dependencies stanza, add
2828
```
29-
compile 'com.ibm.watson.developer_cloud:watson-spring-boot-starter:0.1.0'
29+
compile 'com.ibm.watson.developer_cloud:watson-spring-boot-starter:0.2.0'
3030
```
3131
3232
2. Add your Watson service(s) credentials and version info to your application
@@ -36,7 +36,7 @@ use a different location. The properties to add are:
3636
3737
- `watson.<service>.url`: The base URL for the service. This can be omitted if your
3838
service uses the default service url
39-
- `watson.<service>.username` and `watson.<service>.password` OR `watson.<service>.apiKey`:
39+
- `watson.<service>.username` and `watson.<service>.password` OR `watson.<service>.apiKey` OR `watson.<service>.iamApiKey`:
4040
The credentials for accessing the service.
4141
The credentials can be omitted from the application properties file if they are
4242
supplied through the `VCAP_SERVICES` environment variable.

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
version=0.1.0
1+
version=0.2.0
22
group = com.ibm.watson.developer_cloud
3-
watsonVersion = 4.2.1
3+
watsonVersion = 6.1.0
44
springVersion = 4.3.12.RELEASE
55
springBootVersion = 1.5.9.RELEASE

gradle/wrapper/gradle-wrapper.jar

-293 Bytes
Binary file not shown.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
#Tue Jan 02 10:02:13 CST 2018
21
distributionBase=GRADLE_USER_HOME
32
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright © 2017 IBM Corp. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
14+
15+
package com.ibm.watson.developer_cloud.spring.boot;
16+
17+
import org.springframework.boot.context.properties.ConfigurationProperties;
18+
19+
@ConfigurationProperties(prefix = WatsonAssistantConfigurationProperties.PREFIX)
20+
public class WatsonAssistantConfigurationProperties extends WatsonConfigurationProperties {
21+
22+
public static final String PREFIX = "watson.assistant";
23+
}

src/main/java/com/ibm/watson/developer_cloud/spring/boot/WatsonAutoConfiguration.java

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414

1515
package com.ibm.watson.developer_cloud.spring.boot;
1616

17+
import com.ibm.watson.developer_cloud.assistant.v1.Assistant;
1718
import com.ibm.watson.developer_cloud.conversation.v1.Conversation;
1819
import com.ibm.watson.developer_cloud.discovery.v1.Discovery;
19-
import com.ibm.watson.developer_cloud.language_translator.v2.LanguageTranslator;
20+
import com.ibm.watson.developer_cloud.language_translator.v3.LanguageTranslator;
2021
import com.ibm.watson.developer_cloud.natural_language_classifier.v1.NaturalLanguageClassifier;
2122
import com.ibm.watson.developer_cloud.natural_language_understanding.v1.NaturalLanguageUnderstanding;
2223
import com.ibm.watson.developer_cloud.personality_insights.v3.PersonalityInsights;
2324
import com.ibm.watson.developer_cloud.service.WatsonService;
25+
import com.ibm.watson.developer_cloud.service.security.IamOptions;
2426
import com.ibm.watson.developer_cloud.speech_to_text.v1.SpeechToText;
2527
import com.ibm.watson.developer_cloud.text_to_speech.v1.TextToSpeech;
2628
import com.ibm.watson.developer_cloud.tone_analyzer.v3.ToneAnalyzer;
@@ -34,6 +36,7 @@
3436

3537
@Configuration
3638
@EnableConfigurationProperties({
39+
WatsonAssistantConfigurationProperties.class,
3740
WatsonConversationConfigurationProperties.class,
3841
WatsonDiscoveryConfigurationProperties.class,
3942
WatsonLanguageTranslatorConfigurationProperties.class,
@@ -54,21 +57,41 @@ private void configUrl(WatsonService service, WatsonConfigurationProperties conf
5457
}
5558
}
5659

57-
private void configBasicAuth(WatsonService service, WatsonConfigurationProperties config) {
60+
private void configAuth(WatsonService service, WatsonConfigurationProperties config) {
61+
String iamApiKey = config.getIamApiKey();
62+
if (iamApiKey != null) {
63+
IamOptions options = new IamOptions.Builder().apiKey(iamApiKey).build();
64+
service.setIamCredentials(options);
65+
return;
66+
}
5867
String username = config.getUsername();
5968
String password = config.getPassword();
6069
if (username != null && password != null) {
6170
service.setUsernameAndPassword(username, password);
71+
return;
6272
}
63-
}
64-
65-
private void configApiKey(WatsonService service, WatsonConfigurationProperties config) {
6673
String apiKey = config.getApiKey();
6774
if (apiKey != null) {
6875
service.setApiKey(apiKey);
76+
return;
6977
}
7078
}
7179

80+
// Watson Assistant service
81+
82+
@Autowired
83+
private WatsonAssistantConfigurationProperties assistantConfig;
84+
85+
@Bean
86+
@ConditionalOnMissingBean
87+
@ConditionalOnWatsonServiceProperties(prefix = WatsonAssistantConfigurationProperties.PREFIX)
88+
public Assistant assistant() {
89+
Assistant service = new Assistant(assistantConfig.getVersionDate());
90+
configUrl(service, assistantConfig);
91+
configAuth(service, assistantConfig);
92+
return service;
93+
}
94+
7295
// Watson Conversation service
7396

7497
@Autowired
@@ -80,7 +103,7 @@ private void configApiKey(WatsonService service, WatsonConfigurationProperties c
80103
public Conversation conversation() {
81104
Conversation service = new Conversation(conversationConfig.getVersionDate());
82105
configUrl(service, conversationConfig);
83-
configBasicAuth(service, conversationConfig);
106+
configAuth(service, conversationConfig);
84107
return service;
85108
}
86109

@@ -95,7 +118,7 @@ public Conversation conversation() {
95118
public Discovery discovery() {
96119
Discovery service = new Discovery(discoveryConfig.getVersionDate());
97120
configUrl(service, discoveryConfig);
98-
configBasicAuth(service, discoveryConfig);
121+
configAuth(service, discoveryConfig);
99122
return service;
100123
}
101124

@@ -108,9 +131,9 @@ public Discovery discovery() {
108131
@ConditionalOnMissingBean
109132
@ConditionalOnWatsonServiceProperties(prefix = WatsonLanguageTranslatorConfigurationProperties.PREFIX)
110133
public LanguageTranslator languageTranslator() {
111-
LanguageTranslator service = new LanguageTranslator();
134+
LanguageTranslator service = new LanguageTranslator(ltConfig.getVersionDate());
112135
configUrl(service, ltConfig);
113-
configBasicAuth(service, ltConfig);
136+
configAuth(service, ltConfig);
114137
return service;
115138
}
116139

@@ -125,7 +148,7 @@ public LanguageTranslator languageTranslator() {
125148
public NaturalLanguageClassifier naturalLanguageClassifier() {
126149
NaturalLanguageClassifier service = new NaturalLanguageClassifier();
127150
configUrl(service, nlcConfig);
128-
configBasicAuth(service, nlcConfig);
151+
configAuth(service, nlcConfig);
129152
return service;
130153
}
131154

@@ -140,7 +163,7 @@ public NaturalLanguageClassifier naturalLanguageClassifier() {
140163
public NaturalLanguageUnderstanding naturalLanguageUnderstanding() {
141164
NaturalLanguageUnderstanding service = new NaturalLanguageUnderstanding(nluConfig.getVersionDate());
142165
configUrl(service, nluConfig);
143-
configBasicAuth(service, nluConfig);
166+
configAuth(service, nluConfig);
144167
return service;
145168
}
146169

@@ -155,7 +178,7 @@ public NaturalLanguageUnderstanding naturalLanguageUnderstanding() {
155178
public PersonalityInsights personalityInsights() {
156179
PersonalityInsights service = new PersonalityInsights(piConfig.getVersionDate());
157180
configUrl(service, piConfig);
158-
configBasicAuth(service, piConfig);
181+
configAuth(service, piConfig);
159182
return service;
160183
}
161184

@@ -170,7 +193,7 @@ public PersonalityInsights personalityInsights() {
170193
public SpeechToText speechToText() {
171194
SpeechToText service = new SpeechToText();
172195
configUrl(service, sttConfig);
173-
configBasicAuth(service, sttConfig);
196+
configAuth(service, sttConfig);
174197
return service;
175198
}
176199

@@ -185,7 +208,7 @@ public SpeechToText speechToText() {
185208
public TextToSpeech textToSpeech() {
186209
TextToSpeech service = new TextToSpeech();
187210
configUrl(service, ttsConfig);
188-
configBasicAuth(service, ttsConfig);
211+
configAuth(service, ttsConfig);
189212
return service;
190213
}
191214

@@ -200,7 +223,7 @@ public TextToSpeech textToSpeech() {
200223
public ToneAnalyzer toneAnalyzer() {
201224
ToneAnalyzer service = new ToneAnalyzer(taConfig.getVersionDate());
202225
configUrl(service, taConfig);
203-
configBasicAuth(service, taConfig);
226+
configAuth(service, taConfig);
204227
return service;
205228
}
206229

@@ -215,8 +238,7 @@ public ToneAnalyzer toneAnalyzer() {
215238
public VisualRecognition visualRecognition() {
216239
VisualRecognition service = new VisualRecognition(vrConfig.getVersionDate());
217240
configUrl(service, vrConfig);
218-
configBasicAuth(service, vrConfig);
219-
configApiKey(service, vrConfig);
241+
configAuth(service, vrConfig);
220242
return service;
221243
}
222244

src/main/java/com/ibm/watson/developer_cloud/spring/boot/WatsonConfigurationProperties.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public class WatsonConfigurationProperties {
2828
/** Watson service API key. */
2929
private String apiKey;
3030

31+
/** Watson service IAM API key. */
32+
private String iamApiKey;
33+
3134
/** Watson service versionDate. */
3235
private String versionDate;
3336

@@ -47,6 +50,10 @@ public void setApiKey(String apiKey) {
4750
this.apiKey = apiKey;
4851
}
4952

53+
public void setIamApiKey(String apiKey) {
54+
this.iamApiKey = apiKey;
55+
}
56+
5057
public void setVersionDate(String versionDate) {
5158
this.versionDate = versionDate;
5259
}
@@ -67,6 +74,10 @@ public String getApiKey() {
6774
return apiKey;
6875
}
6976

77+
public String getIamApiKey() {
78+
return iamApiKey;
79+
}
80+
7081
public String getVersionDate() {
7182
return this.versionDate;
7283
}

src/main/java/com/ibm/watson/developer_cloud/spring/boot/WatsonServiceCondition.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata
2323
String url = conditionContext.getEnvironment().getProperty(prefix + ".url");
2424
String username = conditionContext.getEnvironment().getProperty(prefix + ".username");
2525
String password = conditionContext.getEnvironment().getProperty(prefix + ".password");
26+
String apiKey = conditionContext.getEnvironment().getProperty(prefix + ".apiKey");
27+
String iamApiKey = conditionContext.getEnvironment().getProperty(prefix + ".iamApiKey");
2628
String versionDate = conditionContext.getEnvironment().getProperty(prefix + ".versionDate");
27-
if (url != null || username != null || password != null || versionDate != null) {
29+
if (url != null || username != null || password != null || versionDate != null
30+
|| apiKey != null || iamApiKey != null) {
2831
return true;
2932
}
3033

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright © 2017 IBM Corp. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
14+
15+
package com.ibm.watson.developer_cloud.spring.boot.test;
16+
17+
import com.ibm.watson.developer_cloud.assistant.v1.Assistant;
18+
import com.ibm.watson.developer_cloud.service.WatsonService;
19+
import com.ibm.watson.developer_cloud.spring.boot.WatsonAutoConfiguration;
20+
import okhttp3.Credentials;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.ApplicationContext;
25+
import org.springframework.test.context.ContextConfiguration;
26+
import org.springframework.test.context.TestPropertySource;
27+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
28+
import org.springframework.test.context.support.AnnotationConfigContextLoader;
29+
30+
import java.lang.reflect.Field;
31+
32+
import static org.junit.Assert.assertEquals;
33+
import static org.junit.Assert.assertNotNull;
34+
35+
@RunWith(SpringJUnit4ClassRunner.class)
36+
@ContextConfiguration(classes = {WatsonAutoConfiguration.class}, loader = AnnotationConfigContextLoader.class)
37+
@TestPropertySource(properties = {
38+
"watson.assistant.url=" + AssistantAutoConfigTest.url,
39+
"watson.assistant.username=" + AssistantAutoConfigTest.username,
40+
"watson.assistant.password=" + AssistantAutoConfigTest.password,
41+
"watson.assistant.versionDate=" + AssistantAutoConfigTest.versionDate
42+
})
43+
public class AssistantAutoConfigTest {
44+
45+
static final String url = "http://watson.com/assistant";
46+
static final String username = "sam";
47+
static final String password = "secret";
48+
static final String versionDate = "2017-12-15";
49+
50+
@Autowired
51+
private ApplicationContext applicationContext;
52+
53+
@Test
54+
public void assistantBeanConfig() {
55+
Assistant assistant = (Assistant) applicationContext.getBean("assistant");
56+
57+
assertNotNull(assistant);
58+
assertEquals(url, assistant.getEndPoint());
59+
60+
// Verify the credentials and versionDate -- which are stored in private member variables
61+
try {
62+
Field apiKeyField = WatsonService.class.getDeclaredField("apiKey");
63+
apiKeyField.setAccessible(true);
64+
assertEquals(Credentials.basic(username, password), apiKeyField.get(assistant));
65+
66+
Field versionField = Assistant.class.getDeclaredField("versionDate");
67+
versionField.setAccessible(true);
68+
assertEquals(versionDate, versionField.get(assistant));
69+
} catch (NoSuchFieldException | IllegalAccessException ex) {
70+
// This shouldn't happen
71+
assert false;
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)