11package org .lognet .springboot .grpc .security ;
22
3- import io .grpc .BindableService ;
4- import io .grpc .MethodDescriptor ;
5- import io .grpc .ServerInterceptor ;
6- import io .grpc .ServerMethodDefinition ;
7- import io .grpc .ServerServiceDefinition ;
8- import io .grpc .ServiceDescriptor ;
3+ import io .grpc .*;
94import org .lognet .springboot .grpc .GRpcServicesRegistry ;
5+ import org .springframework .beans .factory .BeanCreationException ;
106import org .springframework .core .annotation .AnnotationUtils ;
117import org .springframework .security .access .ConfigAttribute ;
128import org .springframework .security .access .SecurityConfig ;
1511import org .springframework .util .LinkedMultiValueMap ;
1612import org .springframework .util .MultiValueMap ;
1713
18- import java .util .Arrays ;
19- import java .util .Collection ;
20- import java .util .Collections ;
21- import java .util .List ;
22- import java .util .Optional ;
14+ import java .util .*;
2315import java .util .function .Predicate ;
2416import java .util .stream .Collectors ;
2517import java .util .stream .Stream ;
@@ -40,7 +32,7 @@ public Registry getRegistry() {
4032 @ Override
4133 public void configure (GrpcSecurity builder ) throws Exception {
4234 registry .processSecuredAnnotation ();
43- builder .setSharedObject (GrpcSecurityMetadataSource .class , new GrpcSecurityMetadataSource (registry .servicesRegistry ,registry .securedMethods ));
35+ builder .setSharedObject (GrpcSecurityMetadataSource .class , new GrpcSecurityMetadataSource (registry .servicesRegistry , registry .securedMethods ));
4436 }
4537
4638
@@ -99,18 +91,18 @@ public GrpcSecurity withoutSecuredAnnotation() {
9991 }
10092
10193 public AuthorizedMethod anyMethod () {
102- return anyMethodExcluding (s -> false );
94+ return anyMethodExcluding (s -> false );
10395 }
10496
10597 public AuthorizedMethod anyMethodExcluding (MethodDescriptor <?, ?>... methodDescriptor ) {
106- List <MethodDescriptor <?,?>> excludedMethods = Arrays .asList (methodDescriptor );
98+ List <MethodDescriptor <?, ?>> excludedMethods = Arrays .asList (methodDescriptor );
10799 return anyMethodExcluding (excludedMethods ::contains );
108100
109101 }
110102
111103
112104 public AuthorizedMethod anyMethodExcluding (Predicate <MethodDescriptor <?, ?>> excludePredicate ) {
113- MethodDescriptor <?,?>[] allMethods = servicesRegistry .getBeanNameToServiceBeanMap ()
105+ MethodDescriptor <?, ?>[] allMethods = servicesRegistry .getBeanNameToServiceBeanMap ()
114106 .values ()
115107 .stream ()
116108 .map (BindableService ::bindService )
@@ -124,12 +116,14 @@ public AuthorizedMethod anyMethodExcluding(Predicate<MethodDescriptor<?, ?>> exc
124116
125117
126118 public AuthorizedMethod anyService () {
127- return anyServiceExcluding (s -> false );
119+ return anyServiceExcluding (s -> false );
128120 }
121+
129122 public AuthorizedMethod anyServiceExcluding (ServiceDescriptor ... serviceDescriptor ) {
130123 List <ServiceDescriptor > excludedServices = Arrays .asList (serviceDescriptor );
131124 return anyServiceExcluding (excludedServices ::contains );
132125 }
126+
133127 public AuthorizedMethod anyServiceExcluding (Predicate <ServiceDescriptor > excludePredicate ) {
134128
135129 ServiceDescriptor [] allServices = servicesRegistry .getBeanNameToServiceBeanMap ()
@@ -144,11 +138,13 @@ public AuthorizedMethod anyServiceExcluding(Predicate<ServiceDescriptor> exclude
144138
145139 /**
146140 * Same as {@code withSecuredAnnotation(true)}
141+ *
147142 * @return GrpcSecurity configuration
148143 */
149144 public GrpcSecurity withSecuredAnnotation () {
150145 return withSecuredAnnotation (true );
151146 }
147+
152148 public GrpcSecurity withSecuredAnnotation (boolean withSecuredAnnotation ) {
153149 this .withSecuredAnnotation = withSecuredAnnotation ;
154150 return and ();
@@ -163,29 +159,43 @@ private void processSecuredAnnotation() {
163159 // service level security
164160 {
165161 Optional .ofNullable (AnnotationUtils .findAnnotation (service .getClass (), Secured .class ))
166- .ifPresent (secured -> {
167- if (secured .value ().length == 0 ) {
168- new AuthorizedMethod (serverServiceDefinition .getServiceDescriptor ()).authenticated ();
169- } else {
170- new AuthorizedMethod (serverServiceDefinition .getServiceDescriptor ()).hasAnyAuthority (secured .value ());
171- }
172- });
173-
174- }
175- // method level security
176- for (ServerMethodDefinition <?, ?> methodDefinition : serverServiceDefinition .getMethods ()) {
177- Stream .of (service .getClass ().getMethods ()) // get method from methodDefinition
178- .filter (m -> m .getName ().equalsIgnoreCase (methodDefinition .getMethodDescriptor ().getBareMethodName ()))
179- .findFirst ()
180- .flatMap (m -> Optional .ofNullable (AnnotationUtils .findAnnotation (m , Secured .class )))
181162 .ifPresent (secured -> {
182163 if (secured .value ().length == 0 ) {
183- new AuthorizedMethod (methodDefinition . getMethodDescriptor ()).authenticated ();
164+ new AuthorizedMethod (serverServiceDefinition . getServiceDescriptor ()).authenticated ();
184165 } else {
185- new AuthorizedMethod (methodDefinition . getMethodDescriptor ()).hasAnyAuthority (secured .value ());
166+ new AuthorizedMethod (serverServiceDefinition . getServiceDescriptor ()).hasAnyAuthority (secured .value ());
186167 }
187168 });
188169
170+ }
171+ // method level security
172+ for (ServerMethodDefinition <?, ?> methodDefinition : serverServiceDefinition .getMethods ()) {
173+
174+ List <Secured > secureds = Stream .of (service .getClass ().getMethods ()) // get method from methodDefinition
175+ .filter (m -> m .getName ().equalsIgnoreCase (methodDefinition .getMethodDescriptor ().getBareMethodName ()))
176+ .map (m -> AnnotationUtils .findAnnotation (m , Secured .class ))
177+ .filter (Objects ::nonNull )
178+ .toList ();
179+ if (secureds .isEmpty ()) {
180+ continue ;
181+ }
182+ if (1 == secureds .size ()) {
183+ Secured secured = secureds .get (0 );
184+ if (secured .value ().length == 0 ) {
185+ new AuthorizedMethod (methodDefinition .getMethodDescriptor ()).authenticated ();
186+ } else {
187+ new AuthorizedMethod (methodDefinition .getMethodDescriptor ()).hasAnyAuthority (secured .value ());
188+ }
189+ } else {
190+ String errorMessage = String .format ("Ambiguous 'Secured' method '%s' in service '%s'." +
191+ "When securing reactive method, the @Secured annotation should be added to the method getting 'Mono<Request>' and not with pure 'Request' argument." ,
192+ methodDefinition .getMethodDescriptor ().getBareMethodName (),
193+ service .getClass ().getName ()
194+ );
195+ throw new BeanCreationException (errorMessage );
196+ }
197+
198+
189199 }
190200 }
191201 }
0 commit comments