Gap
Spring Security ships first-non-null converter composition as public API on both stacks: DelegatingAuthenticationConverter and DelegatingServerAuthenticationConverter servlet and reactive, respectively.
Spring gRPC has the same concept/semantics within private inner class CompositeAuthenticationExtractor. So, extractors can only be composed by the builder. An application can't compose a group of extractors and hand the result to something else, wrap the composition to add logging or metrics, or unit-test its own composition without standing up a full GrpcSecurity.
Direction
Extract it to a top-level public final class DelegatingGrpcAuthenticationExtractor in org.springframework.grpc.server.security, mirroring DelegatingAuthenticationConverter:
- list and varargs constructors,
Assert.notEmpty on both
GrpcSecurity.performBuild() uses it internally, so no behaviour change (it already sorts by AnnotationAwareOrderComparator before constructing)
BTW should we also mirror DelegatingServerAuthenticationConverter's continueOnError flag?
Gap
Spring Security ships first-non-null converter composition as public API on both stacks:
DelegatingAuthenticationConverterandDelegatingServerAuthenticationConverterservlet and reactive, respectively.Spring gRPC has the same concept/semantics within private inner class
CompositeAuthenticationExtractor. So, extractors can only be composed by the builder. An application can't compose a group of extractors and hand the result to something else, wrap the composition to add logging or metrics, or unit-test its own composition without standing up a fullGrpcSecurity.Direction
Extract it to a top-level
public final class DelegatingGrpcAuthenticationExtractorinorg.springframework.grpc.server.security, mirroringDelegatingAuthenticationConverter:Assert.notEmptyon bothGrpcSecurity.performBuild()uses it internally, so no behaviour change (it already sorts byAnnotationAwareOrderComparatorbefore constructing)BTW should we also mirror
DelegatingServerAuthenticationConverter'scontinueOnErrorflag?