Skip to content

Commit d925402

Browse files
committed
Added ServiceRolesProcessor
1 parent a6f361d commit d925402

File tree

4 files changed

+192
-33
lines changed

4 files changed

+192
-33
lines changed

services-api/src/main/java/io/scalecube/services/Reflect.java

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.scalecube.services.annotations.ServiceMethod;
1313
import io.scalecube.services.annotations.Tag;
1414
import io.scalecube.services.api.ServiceMessage;
15+
import io.scalecube.services.auth.AllowedRole;
1516
import io.scalecube.services.auth.AllowedRoles;
1617
import io.scalecube.services.auth.Secured;
1718
import io.scalecube.services.methods.MethodInfo;
@@ -401,41 +402,39 @@ public static boolean isSecured(Method method) {
401402
* @return {@link ServiceRoleDefinition} objects
402403
*/
403404
public static Collection<ServiceRoleDefinition> serviceRoles(Method method) {
405+
AllowedRole[] allowedRoles = null;
406+
404407
if (method.isAnnotationPresent(AllowedRoles.class)) {
405-
final var allowedRolesAnnotation = method.getAnnotation(AllowedRoles.class);
406-
final var allowedRoles = allowedRolesAnnotation.value();
407-
return Arrays.stream(allowedRoles)
408-
.map(
409-
allowedRole ->
410-
new ServiceRoleDefinition(
411-
allowedRole.name(), new HashSet<>(Arrays.asList(allowedRole.permissions()))))
412-
.collect(Collectors.toSet());
408+
allowedRoles = method.getAnnotation(AllowedRoles.class).value();
409+
} else if (method.isAnnotationPresent(AllowedRole.class)) {
410+
allowedRoles = method.getAnnotationsByType(AllowedRole.class);
413411
}
414412

415-
// If @AllowedRoles/@AllowedRole annotations is not present on service method, then find it on
416-
// service class
417-
418-
Class<?> clazz = method.getDeclaringClass();
413+
// If @AllowedRoles/@AllowedRole annotations are not present on service method, then find them
414+
// on service class
419415

420-
AllowedRoles allowedRolesAnnotation = null;
421-
for (; clazz != null; clazz = clazz.getSuperclass()) {
422-
allowedRolesAnnotation = clazz.getAnnotation(AllowedRoles.class);
423-
if (allowedRolesAnnotation != null) {
424-
break;
416+
if (allowedRoles == null) {
417+
for (var clazz = method.getDeclaringClass(); clazz != null; clazz = clazz.getSuperclass()) {
418+
if (clazz.isAnnotationPresent(AllowedRoles.class)) {
419+
allowedRoles = clazz.getAnnotation(AllowedRoles.class).value();
420+
break;
421+
}
422+
if (clazz.isAnnotationPresent(AllowedRole.class)) {
423+
allowedRoles = clazz.getAnnotationsByType(AllowedRole.class);
424+
break;
425+
}
425426
}
426427
}
427428

428-
if (allowedRolesAnnotation != null) {
429-
final var allowedRoles = allowedRolesAnnotation.value();
430-
return Arrays.stream(allowedRoles)
431-
.map(
432-
allowedRole ->
433-
new ServiceRoleDefinition(
434-
allowedRole.name(), new HashSet<>(Arrays.asList(allowedRole.permissions()))))
435-
.collect(Collectors.toSet());
436-
}
437-
438-
return Set.of();
429+
return allowedRoles != null
430+
? Arrays.stream(allowedRoles)
431+
.map(
432+
allowedRole ->
433+
new ServiceRoleDefinition(
434+
allowedRole.name(),
435+
new HashSet<>(Arrays.asList(allowedRole.permissions()))))
436+
.collect(Collectors.toSet())
437+
: Set.of();
439438
}
440439

441440
/**
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.scalecube.services.auth;
2+
3+
import io.scalecube.services.methods.ServiceRoleDefinition;
4+
import java.util.Collection;
5+
6+
public interface ServiceRolesProcessor {
7+
8+
void process(Collection<ServiceRoleDefinition> serviceRoles);
9+
}

services/src/main/java/io/scalecube/services/Microservices.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static reactor.core.publisher.Sinks.EmitFailureHandler.busyLooping;
44

55
import io.scalecube.services.auth.Authenticator;
6+
import io.scalecube.services.auth.ServiceRolesProcessor;
67
import io.scalecube.services.discovery.api.ServiceDiscovery;
78
import io.scalecube.services.discovery.api.ServiceDiscoveryEvent;
89
import io.scalecube.services.discovery.api.ServiceDiscoveryFactory;
@@ -262,8 +263,10 @@ private void doInject() {
262263
}
263264

264265
private void processServiceRoles() {
265-
final var serviceRoles = ServiceScanner.collectServiceRoles(serviceInstances);
266-
// TODO: take abstract "service roles processor" from context, and invoke "processing"
266+
final var serviceRolesProcessor = context.serviceRolesProcessor;
267+
if (serviceRolesProcessor != null) {
268+
serviceRolesProcessor.process(ServiceScanner.collectServiceRoles(serviceInstances));
269+
}
267270
}
268271

269272
private void startListen() {
@@ -512,8 +515,8 @@ public static final class Context {
512515
private ServiceDiscoveryFactory discoveryFactory;
513516
private Supplier<ServiceTransport> transportSupplier;
514517
private final List<Supplier<Gateway>> gatewaySuppliers = new ArrayList<>();
515-
private final Map<String, Supplier<Scheduler>> schedulerSuppliers = new HashMap<>();
516518
private final Map<String, Scheduler> schedulers = new ConcurrentHashMap<>();
519+
private ServiceRolesProcessor serviceRolesProcessor;
517520

518521
public Context() {}
519522

@@ -715,7 +718,18 @@ public Context defaultLogger(Logger logger) {
715718
* @return this
716719
*/
717720
public Context scheduler(String name, Supplier<Scheduler> supplier) {
718-
schedulerSuppliers.put(name, supplier);
721+
schedulers.put(name, supplier.get());
722+
return this;
723+
}
724+
725+
/**
726+
* Setter for {@link ServiceRolesProcessor}.
727+
*
728+
* @param serviceRolesProcessor serviceRolesProcessor
729+
* @return this
730+
*/
731+
public Context serviceRolesProcessor(ServiceRolesProcessor serviceRolesProcessor) {
732+
this.serviceRolesProcessor = serviceRolesProcessor;
719733
return this;
720734
}
721735

@@ -746,7 +760,6 @@ private Context conclude() {
746760
schedulers.put("single", Schedulers.single());
747761
schedulers.put("boundedElastic", Schedulers.boundedElastic());
748762
schedulers.put("immediate", Schedulers.immediate());
749-
schedulerSuppliers.forEach((s, supplier) -> schedulers.put(s, supplier.get()));
750763

751764
return this;
752765
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package io.scalecube.services.auth;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.hasItem;
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
import static org.junit.jupiter.api.Assertions.assertNotNull;
7+
import static org.mockito.Mockito.mock;
8+
import static org.mockito.Mockito.verify;
9+
10+
import io.scalecube.services.Microservices;
11+
import io.scalecube.services.Microservices.Context;
12+
import io.scalecube.services.annotations.Service;
13+
import io.scalecube.services.annotations.ServiceMethod;
14+
import io.scalecube.services.methods.ServiceRoleDefinition;
15+
import java.util.List;
16+
import java.util.Set;
17+
import org.junit.jupiter.api.Test;
18+
import org.mockito.ArgumentMatchers;
19+
import reactor.core.publisher.Mono;
20+
21+
public class ServiceRolesProcessorTest {
22+
23+
@Test
24+
void processSuccessfully() {
25+
final var serviceRolesProcessor = mock(ServiceRolesProcessor.class);
26+
27+
final var expectedServiceRoles =
28+
List.of(
29+
new ServiceRoleDefinition("admin", Set.of("*")),
30+
new ServiceRoleDefinition("user", Set.of("read")),
31+
new ServiceRoleDefinition("foo", Set.of("read", "write", "delete")));
32+
33+
//noinspection unused
34+
try (final var microservices =
35+
Microservices.start(
36+
new Context()
37+
.serviceRolesProcessor(serviceRolesProcessor)
38+
.services(new Service1Impl(), new Service2Impl(), new Service3Impl()))) {
39+
verify(serviceRolesProcessor)
40+
.process(
41+
ArgumentMatchers.argThat(
42+
serviceRoles -> {
43+
assertNotNull(serviceRoles, "serviceRoles");
44+
assertEquals(
45+
expectedServiceRoles.size(), serviceRoles.size(), "serviceRoles.size");
46+
for (var role : expectedServiceRoles) {
47+
assertThat(serviceRoles, hasItem(role));
48+
}
49+
return true;
50+
}));
51+
}
52+
}
53+
54+
@Service
55+
private interface Service1 {
56+
57+
@ServiceMethod
58+
Mono<Void> hello();
59+
}
60+
61+
@AllowedRole(
62+
name = "admin",
63+
permissions = {"*"})
64+
public static class Service1Impl implements Service1 {
65+
66+
@Override
67+
public Mono<Void> hello() {
68+
return null;
69+
}
70+
}
71+
72+
@Service
73+
private interface Service2 {
74+
75+
@ServiceMethod
76+
Mono<Void> hello();
77+
}
78+
79+
@Service
80+
public static class Service2Impl implements Service2 {
81+
82+
@AllowedRole(
83+
name = "user",
84+
permissions = {"read"})
85+
@Override
86+
public Mono<Void> hello() {
87+
return null;
88+
}
89+
}
90+
91+
@Service
92+
private interface Service3 {
93+
94+
@ServiceMethod
95+
Mono<Void> hello1();
96+
97+
@ServiceMethod
98+
Mono<Void> hello2();
99+
100+
@ServiceMethod
101+
Mono<Void> hello3();
102+
103+
@ServiceMethod
104+
Mono<Void> hello4();
105+
}
106+
107+
@AllowedRole(
108+
name = "foo",
109+
permissions = {"read"})
110+
public static class Service3Impl implements Service3 {
111+
112+
@Override
113+
public Mono<Void> hello1() {
114+
return null;
115+
}
116+
117+
@Override
118+
public Mono<Void> hello2() {
119+
return null;
120+
}
121+
122+
@AllowedRole(
123+
name = "foo",
124+
permissions = {"write"})
125+
@Override
126+
public Mono<Void> hello3() {
127+
return null;
128+
}
129+
130+
@AllowedRole(
131+
name = "foo",
132+
permissions = {"delete"})
133+
@Override
134+
public Mono<Void> hello4() {
135+
return null;
136+
}
137+
}
138+
}

0 commit comments

Comments
 (0)