Skip to content

Commit b1f7088

Browse files
authored
fix: Improve redis configuration for users (#1589)
* WIP fields changed for config Signed-off-by: Carson Cook <carson.cook@ibm.com> * WIP parse sentinel uri Signed-off-by: Carson Cook <carson.cook@ibm.com> * Finish credentials parsing Signed-off-by: Carson Cook <carson.cook@ibm.com> * Cleanup config Signed-off-by: Carson Cook <carson.cook@ibm.com> * Update example config Signed-off-by: Carson Cook <carson.cook@ibm.com> * Fix application.yml back to inMemory by default Signed-off-by: Carson Cook <carson.cook@ibm.com> * Fix unit tests Signed-off-by: Carson Cook <carson.cook@ibm.com> * Cleanup config file Signed-off-by: Carson Cook <carson.cook@ibm.com> * Use new configuration structure in github actions Signed-off-by: Carson Cook <carson.cook@ibm.com> * Cleanup old params in cs application.yml Signed-off-by: Carson Cook <carson.cook@ibm.com> * Set ssl to enabled by default Signed-off-by: Carson Cook <carson.cook@ibm.com> * Update github workflow for ssl defaulting to enabled Signed-off-by: Carson Cook <carson.cook@ibm.com> * Clean redis configuration unit test Signed-off-by: Carson Cook <carson.cook@ibm.com>
1 parent 482a3af commit b1f7088

File tree

6 files changed

+244
-36
lines changed

6 files changed

+244
-36
lines changed

.github/workflows/containers.yml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -452,15 +452,8 @@ jobs:
452452
image: ghcr.io/balhar-jakub/caching-service:${{ github.event.pull_request.number || 'latest' }}
453453
env:
454454
ZWE_CACHING_SERVICE_PERSISTENT: 'redis'
455-
CACHING_STORAGE_REDIS_HOST: 'localhost'
456-
CACHING_STORAGE_REDIS_PORT: 6379
457-
CACHING_STORAGE_REDIS_USERNAME: 'default'
458-
CACHING_STORAGE_REDIS_PASSWORD: 'heslo'
455+
CACHING_STORAGE_REDIS_MASTERNODEURI: 'default:heslo@localhost:6379'
459456
CACHING_STORAGE_REDIS_SSL_ENABLED: true
460-
CACHING_STORAGE_REDIS_SSL_KEYSTORE: keystore/localhost/localhost.keystore.p12
461-
CACHING_STORAGE_REDIS_SSL_KEYSTOREPASSWORD: password
462-
CACHING_STORAGE_REDIS_SSL_TRUSTSTORE: keystore/localhost/localhost.truststore.p12
463-
CACHING_STORAGE_REDIS_SSL_TRUSTSTOREPASSWORD: password
464457
discoverable-client:
465458
image: ghcr.io/balhar-jakub/discoverable-client:${{ github.event.pull_request.number || 'latest' }}
466459
discovery-service:
@@ -545,10 +538,8 @@ jobs:
545538
image: ghcr.io/balhar-jakub/caching-service:${{ github.event.pull_request.number || 'latest' }}
546539
env:
547540
ZWE_CACHING_SERVICE_PERSISTENT: 'redis'
548-
CACHING_STORAGE_REDIS_HOST: 'localhost'
549-
CACHING_STORAGE_REDIS_PORT: 6379
550-
CACHING_STORAGE_REDIS_USERNAME: 'default'
551-
CACHING_STORAGE_REDIS_PASSWORD: 'heslo'
541+
CACHING_STORAGE_REDIS_MASTERNODEURI: 'default:heslo@localhost:6379'
542+
CACHING_STORAGE_REDIS_SSL_ENABLED: false
552543
VERIFY_CERTIFICATES: false
553544
discoverable-client:
554545
image: ghcr.io/balhar-jakub/discoverable-client:${{ github.event.pull_request.number || 'latest' }}

caching-service/src/main/java/org/zowe/apiml/caching/service/redis/config/RedisConfig.java

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,43 @@
1515
import org.springframework.context.annotation.Configuration;
1616
import org.zowe.apiml.caching.config.GeneralConfig;
1717

18+
import javax.annotation.PostConstruct;
1819
import java.util.List;
1920

2021
@Data
2122
@Configuration
2223
@ConfigurationProperties(value = "caching.storage.redis")
2324
@RequiredArgsConstructor
2425
public class RedisConfig {
25-
private final GeneralConfig generalConfig;
26+
private static final int DEFAULT_PORT = 6379;
27+
private static final String DEFAULT_USER = "default";
28+
private static final String DEFAULT_PASSWORD = "";
29+
30+
private static final String AUTHENTICATION_SEPARATOR = "@";
31+
private static final String PORT_SEPARATOR = ":";
32+
private static final String CREDENTIALS_SEPARATOR = ":";
2633

27-
private String host;
28-
private Integer port = 6379;
2934
private Integer timeout = 60;
30-
private String username = "default";
31-
private String password = "";
35+
private String masterNodeUri;
3236

37+
private final GeneralConfig generalConfig;
38+
private String host;
39+
private Integer port = DEFAULT_PORT;
40+
private String username = DEFAULT_USER;
41+
private String password = DEFAULT_PASSWORD;
3342
private Sentinel sentinel;
3443
private SslConfig ssl;
3544

45+
@PostConstruct
46+
public void init() {
47+
NodeUriCredentials credentials = parseCredentialsFromUri(masterNodeUri);
48+
49+
username = credentials.getUsername();
50+
password = credentials.getPassword();
51+
port = parsePortFromUri(masterNodeUri);
52+
host = parseHostFromUri(masterNodeUri);
53+
}
54+
3655
public boolean usesSentinel() {
3756
return sentinel != null;
3857
}
@@ -43,23 +62,99 @@ public boolean usesSsl() {
4362

4463
@Data
4564
public static class Sentinel {
46-
private String master;
65+
private String masterInstance;
4766
private List<SentinelNode> nodes;
4867

4968
@Data
5069
public static class SentinelNode {
5170
private String host;
5271
private Integer port;
5372
private String password;
73+
74+
public SentinelNode(String nodeUri) {
75+
NodeUriCredentials credentials = parseCredentialsFromUri(nodeUri);
76+
password = credentials.getPassword();
77+
78+
host = parseHostFromUri(nodeUri);
79+
port = parsePortFromUri(nodeUri);
80+
}
5481
}
5582
}
5683

5784
@Data
5885
public static class SslConfig {
59-
private Boolean enabled = false;
86+
private Boolean enabled = true;
6087
private String keyStore;
6188
private String keyStorePassword;
6289
private String trustStore;
6390
private String trustStorePassword;
6491
}
92+
93+
private static boolean uriContainsCredentials(String nodeUri) {
94+
return nodeUri.contains(AUTHENTICATION_SEPARATOR);
95+
}
96+
97+
private static boolean uriContainsPort(String nodeUri) {
98+
if (uriContainsCredentials(nodeUri)) {
99+
return nodeUri.substring(nodeUri.indexOf(AUTHENTICATION_SEPARATOR) + 1).contains(PORT_SEPARATOR);
100+
} else {
101+
return nodeUri.contains(PORT_SEPARATOR);
102+
}
103+
}
104+
105+
private static NodeUriCredentials parseCredentialsFromUri(String nodeUri) {
106+
if (!uriContainsCredentials(nodeUri)) {
107+
return new NodeUriCredentials(DEFAULT_USER, DEFAULT_PASSWORD);
108+
}
109+
110+
String credentials = nodeUri.substring(0, nodeUri.indexOf(AUTHENTICATION_SEPARATOR));
111+
112+
if (credentials.contains(CREDENTIALS_SEPARATOR)) {
113+
// password and username provided
114+
String[] splitCredentials = credentials.split(CREDENTIALS_SEPARATOR);
115+
return new NodeUriCredentials(splitCredentials[0], splitCredentials[1]);
116+
} else {
117+
// only password provided
118+
return new NodeUriCredentials(DEFAULT_USER, credentials);
119+
}
120+
}
121+
122+
private static String parseHostFromUri(String nodeUri) {
123+
if (uriContainsCredentials(nodeUri)) {
124+
if (uriContainsPort(nodeUri)) {
125+
String hostAndPort = nodeUri.substring(nodeUri.indexOf(AUTHENTICATION_SEPARATOR) + 1);
126+
return hostAndPort.substring(0, hostAndPort.indexOf(PORT_SEPARATOR));
127+
} else {
128+
return nodeUri.substring(nodeUri.indexOf(AUTHENTICATION_SEPARATOR) + 1);
129+
}
130+
} else if (uriContainsPort(nodeUri)) {
131+
return nodeUri.substring(0, nodeUri.indexOf(PORT_SEPARATOR));
132+
} else {
133+
return nodeUri;
134+
}
135+
}
136+
137+
private static int parsePortFromUri(String nodeUri) {
138+
if (!uriContainsPort(nodeUri)) {
139+
return DEFAULT_PORT;
140+
}
141+
142+
if (uriContainsCredentials(nodeUri)) {
143+
String hostAndPort = nodeUri.substring(nodeUri.indexOf(AUTHENTICATION_SEPARATOR) + 1);
144+
return Integer.parseInt(hostAndPort.substring(hostAndPort.indexOf(PORT_SEPARATOR) + 1));
145+
} else {
146+
return Integer.parseInt(nodeUri.substring(nodeUri.indexOf(PORT_SEPARATOR) + 1));
147+
}
148+
}
149+
150+
@Data
151+
private static class NodeUriCredentials {
152+
private String username;
153+
private String password;
154+
155+
public NodeUriCredentials(String username, String password) {
156+
this.username = username;
157+
this.password = password;
158+
}
159+
}
65160
}

caching-service/src/main/java/org/zowe/apiml/caching/service/redis/config/RedisConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ RedisURI createRedisUri() {
5555

5656
if (redisConfig.usesSentinel()) {
5757
RedisConfig.Sentinel sentinelConfig = redisConfig.getSentinel();
58-
uriBuilder.withSentinelMasterId(sentinelConfig.getMaster());
58+
uriBuilder.withSentinelMasterId(sentinelConfig.getMasterInstance());
5959

6060
for (RedisConfig.Sentinel.SentinelNode sentinelNode : sentinelConfig.getNodes()) {
6161
uriBuilder.withSentinel(sentinelNode.getHost(), sentinelNode.getPort(), sentinelNode.getPassword());

caching-service/src/main/resources/application.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
caching:
2+
storage:
3+
mode: inMemory
4+
redis:
5+
timeout: 60
6+
masterNodeUri: default:heslo@localhost:6379
7+
ssl:
8+
enabled: true
9+
keyStore: ${server.ssl.keyStore}
10+
keyStorePassword: ${server.ssl.keyStorePassword}
11+
trustStore: ${server.ssl.trustStore}
12+
trustStorePassword: ${server.ssl.trustStorePassword}
13+
sentinel:
14+
masterInstance: redismaster
15+
nodes:
16+
- sentinelpassword@localhost:26379
17+
- sentinelpassword@localhost:26380
18+
- sentinelpassword@localhost:26381
19+
120
logging:
221
level:
322
ROOT: WARN

caching-service/src/test/java/org/zowe/apiml/caching/service/redis/config/RedisConfigTest.java

Lines changed: 109 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@
1414
import org.junit.jupiter.api.Test;
1515
import org.zowe.apiml.caching.config.GeneralConfig;
1616

17-
import static org.junit.Assert.assertFalse;
18-
import static org.junit.Assert.assertTrue;
17+
import static org.junit.jupiter.api.Assertions.*;
1918
import static org.mockito.Mockito.mock;
2019

2120
class RedisConfigTest {
21+
private static final int PORT = 1234;
22+
private static final String HOST = "host";
23+
private static final String USER = "user";
24+
private static final String PASSWORD = "pass";
25+
2226
private RedisConfig underTest;
2327

2428
@BeforeEach
@@ -41,6 +45,104 @@ void givenValidSentinel_thenReturnTrue() {
4145
}
4246
}
4347

48+
@Nested
49+
class WhenParseUri {
50+
@Nested
51+
class WhenParseMasterUriCredentials {
52+
@Test
53+
void givenUsernameAndPassword_thenUseBoth() {
54+
String uri = String.format("%s:%s@%s", USER, PASSWORD, HOST);
55+
underTest.setMasterNodeUri(uri);
56+
underTest.init();
57+
58+
assertEquals(USER, underTest.getUsername());
59+
assertEquals(PASSWORD, underTest.getPassword());
60+
}
61+
62+
@Test
63+
void givenOnlyPassword_thenUseGivenPasswordAndDefaultUsername() {
64+
String uri = String.format("%s@%s", PASSWORD, HOST);
65+
underTest.setMasterNodeUri(uri);
66+
underTest.init();
67+
68+
assertEquals("default", underTest.getUsername());
69+
assertEquals(PASSWORD, underTest.getPassword());
70+
}
71+
72+
@Test
73+
void givenNoUsernameOrPassword_thenUseDefaultUsernameAndNoPassword() {
74+
underTest.setMasterNodeUri(HOST);
75+
underTest.init();
76+
77+
assertEquals("default", underTest.getUsername());
78+
assertEquals("", underTest.getPassword());
79+
}
80+
}
81+
82+
@Nested
83+
class WhenParseSentinelUriCredentials {
84+
@Test
85+
void givenPassword_thenSetPassword() {
86+
String uri = String.format("%s@%s", PASSWORD, HOST);
87+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(uri);
88+
assertEquals(PASSWORD, node.getPassword());
89+
}
90+
91+
@Test
92+
void givenNoPassword_thenNoPassword() {
93+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(HOST);
94+
assertEquals("", node.getPassword());
95+
}
96+
}
97+
98+
@Nested
99+
class WhenParsePort {
100+
@Test
101+
void givenPort_thenSetPort() {
102+
String uri = String.format("%s:%d", HOST, PORT);
103+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(uri);
104+
assertEquals(PORT, node.getPort());
105+
}
106+
107+
@Test
108+
void givenNoPort_thenUseDefaultPort() {
109+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(HOST);
110+
assertEquals(6379, node.getPort());
111+
}
112+
}
113+
114+
@Nested
115+
class WhenParseHost_ThenSetHost {
116+
117+
@Test
118+
void givenUsernameAndPasswordAndNoPort() {
119+
String uri = String.format("%s:%s@%s", USER, PASSWORD, HOST);
120+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(uri);
121+
assertEquals(HOST, node.getHost());
122+
}
123+
124+
@Test
125+
void givenUsernameAndPasswordAndPort() {
126+
String uri = String.format("%s:%s@%s:%d", USER, PASSWORD, HOST, PORT);
127+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(uri);
128+
assertEquals(HOST, node.getHost());
129+
}
130+
131+
@Test
132+
void givenNoCredentialsAndPort() {
133+
String uri = String.format("%s:%d", HOST, PORT);
134+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(uri);
135+
assertEquals(HOST, node.getHost());
136+
}
137+
138+
@Test
139+
void givenNoCredentialsAndNoPort() {
140+
RedisConfig.Sentinel.SentinelNode node = new RedisConfig.Sentinel.SentinelNode(HOST);
141+
assertEquals(HOST, node.getHost());
142+
}
143+
}
144+
}
145+
44146
@Nested
45147
class WhenCheckForSsl {
46148
@Test
@@ -50,16 +152,16 @@ void givenNullSslConfig_thenReturnFalse() {
50152

51153
@Test
52154
void givenSslNotEnabled_thenReturnFalse() {
53-
underTest.setSsl(new RedisConfig.SslConfig());
155+
RedisConfig.SslConfig sslConfig = new RedisConfig.SslConfig();
156+
sslConfig.setEnabled(false);
157+
underTest.setSsl(sslConfig);
158+
54159
assertFalse(underTest.usesSsl());
55160
}
56161

57162
@Test
58163
void givenEnabledSsl_thenReturnTrue() {
59-
RedisConfig.SslConfig sslConfig = new RedisConfig.SslConfig();
60-
sslConfig.setEnabled(true);
61-
underTest.setSsl(sslConfig);
62-
164+
underTest.setSsl(new RedisConfig.SslConfig());
63165
assertTrue(underTest.usesSsl());
64166
}
65167
}

caching-service/src/test/java/org/zowe/apiml/caching/service/redis/config/RedisConfigurationTest.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class WhenCreatingUriWithSentinel {
8282
@BeforeEach
8383
void useSentinel() {
8484
sentinelConfig = mock(RedisConfig.Sentinel.class);
85-
when(sentinelConfig.getMaster()).thenReturn(MASTER);
85+
when(sentinelConfig.getMasterInstance()).thenReturn(MASTER);
8686

8787
when(redisConfig.usesSentinel()).thenReturn(true);
8888
when(redisConfig.getSentinel()).thenReturn(sentinelConfig);
@@ -103,14 +103,15 @@ void givenSentinelNodes_thenReturnRedisUri() {
103103
String password1 = "password1";
104104
String password2 = "password2";
105105

106-
RedisConfig.Sentinel.SentinelNode node1 = new RedisConfig.Sentinel.SentinelNode();
107-
node1.setHost(ip1);
108-
node1.setPort(port1);
109-
node1.setPassword(password1);
110-
RedisConfig.Sentinel.SentinelNode node2 = new RedisConfig.Sentinel.SentinelNode();
111-
node2.setHost(ip2);
112-
node2.setPort(port2);
113-
node2.setPassword(password2);
106+
RedisConfig.Sentinel.SentinelNode node1 = mock(RedisConfig.Sentinel.SentinelNode.class);
107+
when(node1.getHost()).thenReturn(ip1);
108+
when(node1.getPort()).thenReturn(port1);
109+
when(node1.getPassword()).thenReturn(password1);
110+
111+
RedisConfig.Sentinel.SentinelNode node2 = mock(RedisConfig.Sentinel.SentinelNode.class);
112+
when(node2.getHost()).thenReturn(ip2);
113+
when(node2.getPort()).thenReturn(port2);
114+
when(node2.getPassword()).thenReturn(password2);
114115

115116
List<RedisConfig.Sentinel.SentinelNode> nodesList = new ArrayList<>();
116117
nodesList.add(node1);

0 commit comments

Comments
 (0)