Skip to content

Anonymous can access gRPC method protected by PreAuthorize annotation #245

@hellozdp

Description

@hellozdp

My application is Native gRPC Server inside a Servlet Container. Security code in my project

Config

  @Bean
  @GlobalServerInterceptor
  AuthenticationProcessInterceptor jwtSecurityFilterChain(GrpcSecurity grpc) throws Exception {
    return grpc.authorizeRequests(requests -> requests.allRequests().permitAll())
        .authenticationManager(authenticationManager)
        .authenticationExtractor(new BearerTokenAuthenticationExtractor())
        .httpBasic(withDefaults())
        .preauth(withDefaults())
        .build();
  }

Annotations

  @Override
  @PreAuthorize("hasAuthority('OperationAdmin')")
  public void createRegion(
      CreateRegionRequest request, StreamObserver<DescribeRegionResponse> responseObserver) {
    //TODO
  }

When some one is logged in our system, another one can access the gRPC method without logging. I do some research for this strange behavior. Here is the default security interceptor: AuthenticationProcessInterceptor, I can not find out any code to clear SecurityContext when call is completed.

public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers,
			ServerCallHandler<ReqT, RespT> next) {
		SecurityContext securityContext = SecurityContextHolder.getContext();
		Authentication user = this.extractor.extract(headers, call.getAttributes());
		if (user != null) {
			user = this.authenticationManager.authenticate(user);
			securityContext.setAuthentication(user);
		}

		if (this.authorizationManager != null) {
			CallContext context = new CallContext(headers, call.getAttributes(), call.getMethodDescriptor());
			if (user == null) {
				// Maybe just throw BadCredentialsException (authentication manager would
				// have to make the anonymous user)?
				user = new AnonymousAuthenticationToken("anonymous", "anonymous",
						AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
			}
			Authentication authentication = user;
			if (!this.authorizationManager.authorize(() -> authentication, context).isGranted()) {
				if (user instanceof AnonymousAuthenticationToken) {
					throw new BadCredentialsException("not authenticated");
				}
				throw new AccessDeniedException("not allowed");
			}
		}
		else if (user == null || !user.isAuthenticated()) {
			throw new BadCredentialsException("not authenticated");
		}

		return next.startCall(call, headers);
	}

And the SecurityContextServerInterceptor is not registered by default. So the SecurityContext is not clear by default, and anonymous can reuse SecurityContext to access the protected gRPC method. Is this a bug or I missed some configuration? In common sense, SecurityContext will be cleared after request is completed or interrupted by default

@ConditionalOnBean(SecurityFilterChain.class)
@Conditional(GrpcServerFactoryAutoConfiguration.OnGrpcServletCondition.class)
@Configuration(proxyBeanMethods = false)
class GrpcServletSecurityConfigurerAutoConfiguration {

	@Bean
	@GlobalServerInterceptor
	public SecurityContextServerInterceptor securityContextInterceptor() {
		return new SecurityContextServerInterceptor();
	}

	@Bean
	public <T extends ServerBuilder<T>> ServerBuilderCustomizer<T> securityContextExecutorCustomizer() {
		return (serverBuilder) -> serverBuilder
			.executor(new DelegatingSecurityContextExecutor(GrpcUtil.SHARED_CHANNEL_EXECUTOR.create()));
	}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions