Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an interceptor to support AuthenticationManagerResolver #1034

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/en/server/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,34 @@ GrpcAuthenticationReader authenticationReader() {

See also [Mutual Certificate Authentication](#mutual-certificate-authentication).

#### Using AuthenticationManagerResolver

You can also use the `AuthenticationManagerResolver` to dynamically determine the authentication manager to use for
a particular request. This can be useful for applications that support multiple authentication
mechanisms, such as OAuth and OpenID Connect, or that want to delegate authentication to external services.

To use `AuthenticationManagerResolver`, you first need to create a bean that implements
the `AuthenticationManagerResolver<GrpcServerRequest>` interface instead of `AuthenticationManager`. The `resolve()` method of this bean should
return the AuthenticationManager to use for a particular request.

````java
@Bean
AuthenticationManagerResolver<GrpcServerRequest> grpcAuthenticationManagerResolver() {
return grpcServerRequest -> {
AuthenticationManager authenticationManager = // Check the grpc request and return an authenticationManager
return authenticationManager;
};
}

@Bean
GrpcAuthenticationReader authenticationReader() {
final List<GrpcAuthenticationReader> readers = new ArrayList<>();
// The actual token class is dependent on your spring-security library (OAuth2/JWT/...)
readers.add(new BearerAuthenticationReader(accessToken -> new BearerTokenAuthenticationToken(accessToken)));
return new CompositeGrpcAuthenticationReader(readers);
}
````

### Configure Authorization

This step is very important as it actually secures your application against unwanted access. You can secure your
Expand Down
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2016-2023 The gRPC-Spring Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.devh.boot.grpc.server.autoconfigure;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.core.AuthenticationException;

import net.devh.boot.grpc.server.security.authentication.GrpcAuthenticationReader;
import net.devh.boot.grpc.server.security.check.GrpcSecurityMetadataSource;
import net.devh.boot.grpc.server.security.interceptors.*;

/**
* Auto configuration class with the required beans for the spring-security configuration of the grpc server.
*
* <p>
* To enable security add both an {@link AuthenticationManager} and a {@link GrpcAuthenticationReader} to the
* application context. The authentication reader obtains the credentials from the requests which then will be validated
* by the authentication manager. After that, you can decide how you want to secure your application. Currently these
* options are available:
* </p>
*
* <ul>
* <li>Use Spring Security's annotations. This requires
* {@code @EnableGlobalMethodSecurity(proxyTargetClass = true, ...)}.</li>
* <li>Having both an {@link AccessDecisionManager} and a {@link GrpcSecurityMetadataSource} in the application context.
* </ul>
*
* <p>
* <b>Note:</b> The order of the beans is important! First the exception translating interceptor, then the
* authenticating interceptor and finally the authorization checking interceptor. That is necessary because they are
* executed in the same order as their order.
* </p>
*
* @author Daniel Theuke ([email protected])
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(parameterizedContainer = AuthenticationManagerResolver.class, value = GrpcServerRequest.class)
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class GrpcServerSecurityWithManagerResolverAutoConfiguration {

/**
* The interceptor for handling security related exceptions such as {@link AuthenticationException} and
* {@link AccessDeniedException}.
*
* @return The exceptionTranslatingServerInterceptor bean.
*/
@Bean
@ConditionalOnMissingBean
public ExceptionTranslatingServerInterceptor exceptionTranslatingServerInterceptor() {
return new ExceptionTranslatingServerInterceptor();
}
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved

/**
* The security interceptor that handles the authentication of requests.
*
* @param grpcAuthenticationManagerResolver The authentication manager resolver used to verify the credentials.
* @param authenticationReader The authentication reader used to extract the credentials from the call.
* @return The authenticatingServerInterceptor bean.
*/
@Bean
@ConditionalOnMissingBean(AuthenticatingServerInterceptor.class)
public ManagerResolverAuthenticatingServerInterceptor managerResolverAuthenticatingServerInterceptor(
final AuthenticationManagerResolver<GrpcServerRequest> grpcAuthenticationManagerResolver,
final GrpcAuthenticationReader authenticationReader) {
return new ManagerResolverAuthenticatingServerInterceptor(grpcAuthenticationManagerResolver,
authenticationReader);
}

/**
* The security interceptor that handles the authorization of requests.
*
* @param accessDecisionManager The access decision manager used to check the requesting user.
* @param securityMetadataSource The source for the security metadata (access constraints).
* @return The authorizationCheckingServerInterceptor bean.
*/
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({AccessDecisionManager.class, GrpcSecurityMetadataSource.class})
public AuthorizationCheckingServerInterceptor authorizationCheckingServerInterceptor(
final AccessDecisionManager accessDecisionManager,
final GrpcSecurityMetadataSource securityMetadataSource) {
return new AuthorizationCheckingServerInterceptor(accessDecisionManager, securityMetadataSource);
}

}
Loading