Skip to content

Commit 89c209f

Browse files
committed
Changed signature of CredentialsSupplier, added more responsibility to ServiceTokenCredentialsSupplier
1 parent 9dc2658 commit 89c209f

File tree

6 files changed

+54
-28
lines changed

6 files changed

+54
-28
lines changed

services-api/src/main/java/io/scalecube/services/auth/CredentialsSupplier.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.scalecube.services.auth;
22

3+
import java.util.List;
34
import reactor.core.publisher.Mono;
45

56
/**
@@ -12,8 +13,9 @@ public interface CredentialsSupplier {
1213
/**
1314
* Obtains credentials for the given service role.
1415
*
15-
* @param serviceRole serviceRole
16+
* @param serviceName logical service name
17+
* @param serviceRoles allowed roles on the service (optional)
1618
* @return credentials
1719
*/
18-
Mono<byte[]> credentials(String serviceRole);
20+
Mono<byte[]> credentials(String serviceName, List<String> serviceRoles);
1921
}

services-gateway/src/test/java/io/scalecube/services/gateway/files/FileDownloadTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static org.junit.jupiter.api.Assertions.assertTrue;
99
import static org.junit.jupiter.api.Assertions.fail;
1010
import static org.mockito.ArgumentMatchers.any;
11+
import static org.mockito.ArgumentMatchers.anyList;
1112
import static org.mockito.Mockito.mock;
1213
import static org.mockito.Mockito.when;
1314

@@ -58,7 +59,7 @@ public class FileDownloadTest {
5859
@BeforeAll
5960
static void beforeAll() {
6061
credentialsSupplier = mock(CredentialsSupplier.class);
61-
when(credentialsSupplier.credentials(any(String.class))).thenReturn(Mono.never());
62+
when(credentialsSupplier.credentials(any(String.class), anyList())).thenReturn(Mono.never());
6263

6364
gateway =
6465
Microservices.start(

services-security/src/main/java/io/scalecube/services/security/ServiceTokenCredentialsSupplier.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import io.scalecube.security.vault.VaultServiceTokenSupplier;
44
import io.scalecube.services.auth.CredentialsSupplier;
5+
import io.scalecube.services.exceptions.ForbiddenException;
6+
import java.util.Collection;
57
import java.util.Collections;
8+
import java.util.List;
69
import java.util.Objects;
710
import java.util.concurrent.CompletableFuture;
811
import java.util.function.Supplier;
@@ -13,37 +16,58 @@ public class ServiceTokenCredentialsSupplier implements CredentialsSupplier {
1316
private final String environment;
1417
private final String vaultAddress;
1518
private final Supplier<CompletableFuture<String>> vaultTokenSupplier;
19+
private final Collection<String> allowedRoles;
1620

1721
/**
1822
* Constructor.
1923
*
2024
* @param environment logical environment name
2125
* @param vaultAddress vaultAddress
2226
* @param vaultTokenSupplier vaultTokenSupplier
27+
* @param allowedRoles allowedRoles (optional)
2328
*/
2429
public ServiceTokenCredentialsSupplier(
2530
String environment,
2631
String vaultAddress,
27-
Supplier<CompletableFuture<String>> vaultTokenSupplier) {
32+
Supplier<CompletableFuture<String>> vaultTokenSupplier,
33+
Collection<String> allowedRoles) {
2834
this.environment = Objects.requireNonNull(environment, "environment");
2935
this.vaultAddress = Objects.requireNonNull(vaultAddress, "vaultAddress");
3036
this.vaultTokenSupplier = Objects.requireNonNull(vaultTokenSupplier, "vaultTokenSupplier");
37+
this.allowedRoles = allowedRoles;
3138
}
3239

3340
@Override
34-
public Mono<byte[]> credentials(String serviceRole) {
41+
public Mono<byte[]> credentials(String serviceName, List<String> serviceRoles) {
3542
return Mono.defer(
3643
() -> {
37-
if (serviceRole == null) {
44+
if (serviceRoles == null || serviceRoles.isEmpty()) {
3845
return Mono.just(new byte[0]);
3946
}
4047

48+
String serviceRole = null;
49+
50+
if (allowedRoles == null || allowedRoles.isEmpty()) {
51+
serviceRole = serviceRoles.get(0);
52+
} else {
53+
for (var allowedRole : allowedRoles) {
54+
if (serviceRoles.contains(allowedRole)) {
55+
serviceRole = allowedRole;
56+
}
57+
}
58+
}
59+
60+
if (serviceRole == null) {
61+
throw new ForbiddenException("Insufficient permissions");
62+
}
63+
4164
return Mono.fromFuture(
4265
VaultServiceTokenSupplier.builder()
4366
.vaultAddress(vaultAddress)
4467
.serviceRole(serviceRole)
4568
.vaultTokenSupplier(vaultTokenSupplier)
46-
.serviceTokenNameBuilder((role, tags) -> environment + "." + role)
69+
.serviceTokenNameBuilder(
70+
(role, tags) -> String.join(".", environment, serviceName, role))
4771
.build()
4872
.getToken(Collections.emptyMap()))
4973
.map(String::getBytes);

services-security/src/test/java/io/scalecube/services/security/ServiceTokenTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void shouldAuthenticateSuccessfully(SuccessArgs args, VaultEnvironment vaultEnvi
3434
() -> CompletableFuture.completedFuture(vaultEnvironment.login());
3535

3636
final var credentialsSupplier =
37-
new ServiceTokenCredentialsSupplier(args.environment, vaultAddr, vaultTokenSupplier);
37+
new ServiceTokenCredentialsSupplier(args.environment, vaultAddr, vaultTokenSupplier, null);
3838

3939
final var authenticator =
4040
new ServiceTokenAuthenticator(
@@ -49,7 +49,7 @@ void shouldAuthenticateSuccessfully(SuccessArgs args, VaultEnvironment vaultEnvi
4949
// Get service token
5050

5151
final var credentials =
52-
credentialsSupplier.credentials(args.service + "." + args.serviceRole).block();
52+
credentialsSupplier.credentials(args.service, List.of(args.serviceRole)).block();
5353

5454
// Authenticate
5555

services-transport-parent/services-transport-rsocket/src/main/java/io/scalecube/services/transport/rsocket/RSocketClientTransport.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ public ClientChannel create(ServiceReference serviceReference) {
6666
final var mono =
6767
monoMap.computeIfAbsent(
6868
new Destination(address, serviceRole),
69-
key ->
70-
connect(key, serviceReference, monoMap)
69+
destination ->
70+
connect(destination, serviceReference, monoMap)
7171
.cacheInvalidateIf(RSocket::isDisposed)
72-
.doOnError(ex -> monoMap.remove(key)));
72+
.doOnError(ex -> monoMap.remove(destination)));
7373

7474
return new RSocketClientChannel(mono, new ServiceMessageCodec(headersCodec, dataCodecs));
7575
}
@@ -99,7 +99,7 @@ private Mono<RSocket> connect(
9999
ServiceReference serviceReference,
100100
Map<Destination, Mono<RSocket>> monoMap) {
101101
return RSocketConnector.create()
102-
.setupPayload(Mono.defer(() -> getCredentials(serviceReference, destination.role())))
102+
.setupPayload(Mono.defer(() -> getCredentials(serviceReference)))
103103
.connect(() -> clientTransportFactory.clientTransport(destination.address()))
104104
.doOnSuccess(
105105
rsocket -> {
@@ -122,13 +122,13 @@ private Mono<RSocket> connect(
122122
ex -> LOGGER.warn("Failed to connect ({}), cause: {}", destination, ex.toString()));
123123
}
124124

125-
private Mono<Payload> getCredentials(ServiceReference serviceReference, String serviceRole) {
126-
if (credentialsSupplier == null || !serviceReference.isSecured() || serviceRole == null) {
125+
private Mono<Payload> getCredentials(ServiceReference serviceReference) {
126+
if (credentialsSupplier == null || !serviceReference.isSecured()) {
127127
return Mono.just(EmptyPayload.INSTANCE);
128128
}
129129

130130
return credentialsSupplier
131-
.credentials(serviceReference.endpointName() + "." + serviceRole)
131+
.credentials(serviceReference.endpointName(), serviceReference.allowedRoles())
132132
.map(data -> data.length != 0 ? DefaultPayload.create(data) : EmptyPayload.INSTANCE)
133133
.onErrorMap(
134134
th -> {

services/src/test/java/io/scalecube/services/AuthTest.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ class SecuredTests {
104104
void authenticateSuccessfully(String test, SuccessArgs args) {
105105
serviceCall =
106106
serviceCall(
107-
serviceRole -> credentials(args.tokenSupplier.apply(stripService(serviceRole))),
108-
args.serviceRole,
109-
args.allowedRoles);
107+
(serviceName, roles) ->
108+
credentials(args.tokenSupplier.apply(stripService(args.serviceRole))),
109+
args.serviceRole);
110110

111111
StepVerifier.create(serviceCall.api(SecuredService.class).invokeWithRoleOrPermissions())
112112
.verifyComplete();
@@ -138,9 +138,9 @@ private static Stream<Arguments> authenticateSuccessfullyMethodSource() {
138138
void failedAuthentication(String test, FailedArgs args) {
139139
serviceCall =
140140
serviceCall(
141-
serviceRole -> credentials(args.tokenSupplier.apply(stripService(serviceRole))),
142-
args.serviceRole,
143-
args.allowedRoles);
141+
(serviceName, roles) ->
142+
credentials(args.tokenSupplier.apply(stripService(args.serviceRole))),
143+
args.serviceRole);
144144

145145
StepVerifier.create(serviceCall.api(SecuredService.class).invokeWithRoleOrPermissions())
146146
.verifyErrorSatisfies(
@@ -206,7 +206,7 @@ void authenticateSuccessfully() {
206206
credentials.put("user", "alice");
207207
credentials.put("permissions", "helloComposite");
208208

209-
serviceCall = serviceCall((r) -> credentials(tokenCredentials), role, null);
209+
serviceCall = serviceCall((serviceName, roles) -> credentials(tokenCredentials), role);
210210

211211
StepVerifier.create(
212212
serviceCall
@@ -222,7 +222,7 @@ void failedAuthentication(String test, FailedArgs args) {
222222
final var role = "invoker";
223223
final var tokenCredentials = new TokenCredentials(VALID_TOKEN, role, null);
224224

225-
serviceCall = serviceCall((r) -> credentials(tokenCredentials), role, null);
225+
serviceCall = serviceCall((serviceName, roles) -> credentials(tokenCredentials), role);
226226

227227
StepVerifier.create(
228228
serviceCall
@@ -268,7 +268,7 @@ void authenticateSuccessfully() {
268268
final var tokenCredentials =
269269
new TokenCredentials(VALID_TOKEN, role, List.of("read", "write", "delete", "*"));
270270

271-
serviceCall = serviceCall((r) -> credentials(tokenCredentials), role, null);
271+
serviceCall = serviceCall((serviceName, roles) -> credentials(tokenCredentials), role);
272272

273273
StepVerifier.create(serviceCall.api(SecuredService.class).readWithAllowedRoleAnnotation())
274274
.verifyComplete();
@@ -329,8 +329,7 @@ private static Mono<Principal> mapPrincipal(RequestContext requestContext) {
329329
});
330330
}
331331

332-
private ServiceCall serviceCall(
333-
CredentialsSupplier credentialsSupplier, String serviceRole, List<String> allowedRoles) {
332+
private ServiceCall serviceCall(CredentialsSupplier credentialsSupplier, String serviceRole) {
334333
//noinspection resource
335334
return new ServiceCall()
336335
.transport(
@@ -339,7 +338,7 @@ private ServiceCall serviceCall(
339338
DataCodec.getAllInstances(),
340339
RSocketClientTransportFactory.websocket().apply(LOOP_RESOURCE),
341340
credentialsSupplier,
342-
allowedRoles))
341+
serviceRole != null ? List.of(serviceRole) : null))
343342
.router(
344343
StaticAddressRouter.forService(service.serviceAddress(), "app-service")
345344
.secured(credentialsSupplier != null)

0 commit comments

Comments
 (0)