All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.security.integration.grpc.GrpcClientSecurity Maven / Gradle / Ivy

There is a newer version: 4.0.0-ALPHA6
Show newest version
/*
 * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * 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 io.helidon.security.integration.grpc;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

import io.helidon.common.HelidonFeatures;
import io.helidon.security.EndpointConfig;
import io.helidon.security.OutboundSecurityClientBuilder;
import io.helidon.security.OutboundSecurityResponse;
import io.helidon.security.SecurityContext;
import io.helidon.security.SecurityEnvironment;
import io.helidon.security.SecurityResponse;
import io.helidon.security.integration.common.OutboundTracing;
import io.helidon.security.integration.common.SecurityTracing;
import io.helidon.webserver.ServerRequest;

import io.grpc.CallCredentials;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;

import static io.helidon.security.integration.grpc.GrpcSecurity.ABAC_ATTRIBUTE_METHOD;

/**
 * A gRPC {@link CallCredentials} implementation.
 * 

* Only works as part of integration with the Helidon Security component. */ public final class GrpcClientSecurity extends CallCredentials { /** * Property name for outbound security provider name. Set this with * {@link GrpcClientSecurity.Builder#property(String, Object)}. */ public static final String PROPERTY_PROVIDER = "io.helidon.security.integration.grpc.GrpcClientSecurity.explicitProvider"; static { HelidonFeatures.register("Security", "Integration", "gRPC Client"); } private final SecurityContext context; private final Map properties; private GrpcClientSecurity(SecurityContext context, Map properties) { this.context = context; this.properties = properties; } @Override public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) { OutboundTracing tracing = SecurityTracing.get().outboundTracing(); String explicitProvider = (String) properties.get(PROPERTY_PROVIDER); try { MethodDescriptor methodDescriptor = requestInfo.getMethodDescriptor(); String methodName = methodDescriptor.getFullMethodName(); SecurityEnvironment.Builder outboundEnv = context.env().derive(); outboundEnv.path(methodName) .method(methodName) .addAttribute(ABAC_ATTRIBUTE_METHOD, methodDescriptor) .transport("grpc") .build(); EndpointConfig.Builder outboundEp = context.endpointConfig().derive(); properties.forEach(outboundEp::addAtribute); OutboundSecurityClientBuilder clientBuilder = context.outboundClientBuilder() .outboundEnvironment(outboundEnv) .tracingSpan(tracing.findParent().orElse(null)) .tracingSpan(tracing.findParentSpan().orElse(null)) .outboundEndpointConfig(outboundEp) .explicitProvider(explicitProvider); OutboundSecurityResponse providerResponse = clientBuilder.buildAndGet(); SecurityResponse.SecurityStatus status = providerResponse.status(); tracing.logStatus(status); switch (status) { case FAILURE: case FAILURE_FINISH: providerResponse.throwable() .ifPresentOrElse(tracing::error, () -> tracing.error(providerResponse.description().orElse("Failed"))); break; case ABSTAIN: case SUCCESS: case SUCCESS_FINISH: default: break; } Map> newHeaders = providerResponse.requestHeaders(); Metadata metadata = new Metadata(); for (Map.Entry> entry : newHeaders.entrySet()) { Metadata.Key key = Metadata.Key.of(entry.getKey(), Metadata.ASCII_STRING_MARSHALLER); for (String value : entry.getValue()) { metadata.put(key, value); } } applier.apply(metadata); tracing.finish(); } catch (SecurityException e) { tracing.error(e); applier.fail(Status.UNAUTHENTICATED.withDescription("Security principal propagation error").withCause(e)); } catch (Exception e) { tracing.error(e); applier.fail(Status.UNAUTHENTICATED.withDescription("Unknown error").withCause(e)); } } @Override public void thisUsesUnstableApi() { } /** * Create a {@link GrpcClientSecurity} instance. * * @param securityContext the {@link SecurityContext} to use * * @return a {@link GrpcClientSecurity} builder. */ public static GrpcClientSecurity create(SecurityContext securityContext) { return builder(securityContext).build(); } /** * Create a {@link GrpcClientSecurity} instance. * * @param req the http {@link ServerRequest} to use to obtain the {@link SecurityContext} * * @return a {@link GrpcClientSecurity} builder. */ public static GrpcClientSecurity create(ServerRequest req) { return builder(req).build(); } /** * Obtain a {@link GrpcClientSecurity} builder. * * @param securityContext the {@link SecurityContext} to use * * @return a {@link GrpcClientSecurity} builder. */ public static Builder builder(SecurityContext securityContext) { return new Builder(securityContext); } /** * Obtain a {@link GrpcClientSecurity} builder. * * @param req the http {@link ServerRequest} to use to obtain the {@link SecurityContext} * * @return a {@link GrpcClientSecurity} builder. */ public static Builder builder(ServerRequest req) { return builder(getContext(req)); } private static SecurityContext getContext(ServerRequest req) { return req.context().get(SecurityContext.class) .orElseThrow(() -> new RuntimeException("Failed to get security context from request, security not configured")); } /** * A builder of {@link GrpcClientSecurity} instances. */ public static final class Builder implements io.helidon.common.Builder { private final SecurityContext securityContext; private final Map properties; private Builder(SecurityContext securityContext) { this.securityContext = securityContext; this.properties = new HashMap<>(); } /** * Set a new property that may be used by {@link io.helidon.security.spi.SecurityProvider}s * when creating the credentials to apply to the call. * * @param name property name. * @param value (new) property value. {@code null} value removes the property * with the given name. * * @return the updated builder. */ public Builder property(String name, Object value) { if (value == null) { properties.remove(name); } else { properties.put(name, value); } return this; } @Override public GrpcClientSecurity build() { return new GrpcClientSecurity(securityContext, properties); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy