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

io.helidon.security.provider.httpsign.OutboundTargetDefinition Maven / Gradle / Ivy

There is a newer version: 0.10.6
Show newest version
/*
 * Copyright (c) 2018 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.provider.httpsign;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

import io.helidon.common.pki.KeyConfig;
import io.helidon.config.Config;

/**
 * Configuration of outbound target to sign outgoing requests.
 */
public class OutboundTargetDefinition {
    private final String keyId;
    private final String algorithm;
    private final KeyConfig keyConfig;
    private final HttpSignHeader header;
    private final byte[] hmacSharedSecret;
    private final SignedHeadersConfig signedHeadersConfig;

    private OutboundTargetDefinition(Builder builder) {
        this.keyId = builder.keyId;
        this.algorithm = builder.algorithm;
        this.keyConfig = builder.keyConfig;
        this.header = builder.header;
        this.hmacSharedSecret = builder.hmacSharedSecret;
        this.signedHeadersConfig = builder.signedHeadersConfig;

        Objects.requireNonNull(algorithm, "Signature algorithm must not be null");
        Objects.requireNonNull(keyId, "Key id must not be null");
        Objects.requireNonNull(header, "Header to use must not be null");
        Objects.requireNonNull(signedHeadersConfig, "Configuration of how to sign headers must not be null");

        if (HttpSignProvider.ALGORITHM_HMAC.equals(algorithm)) {
            Objects.requireNonNull(hmacSharedSecret, "HMAC shared secret must not be null");
        } else if (HttpSignProvider.ALGORITHM_RSA.equals(algorithm)) {
            Objects.requireNonNull(keyConfig, "RSA Keys configuration must not be null");
        }
    }

    /**
     * Get a new builder .
     *
     * @param keyId keyId to send with signature
     * @return builder instance
     */
    public static Builder builder(String keyId) {
        return new Builder().keyId(keyId);
    }

    /**
     * Create a builder from configuration.
     *
     * @param config configuration located at this target, expects "key-id" to be a child
     * @return builder instance
     */
    public static Builder builder(Config config) {
        return new Builder().fromConfig(config);
    }

    /**
     * Create an instance from configuration.
     *
     * @param config configuration located at this outbound key, expects "key-id" to be a child
     * @return new instance configured from config
     */
    public static OutboundTargetDefinition fromConfig(Config config) {
        return builder(config).build();
    }

    /**
     * Key id of this service (will be mapped by target service to validate signature).
     *
     * @return key id string (may be an API key, key fingerprint, service name etc.)
     */
    public String getKeyId() {
        return keyId;
    }

    /**
     * Algorithm used by this signature.
     *
     * @return algorithm
     */
    public String getAlgorithm() {
        return algorithm;
    }

    /**
     * Private key configuration for RSA based algorithms.
     *
     * @return private key location and configuration or empty optional if not configured
     */
    public Optional getKeyConfig() {
        return Optional.ofNullable(keyConfig);
    }

    /**
     * Shared secret for HMAC based algorithms.
     *
     * @return shared secret or empty optional if not configured
     */
    public Optional getHmacSharedSecret() {
        return Optional.ofNullable(hmacSharedSecret);
    }

    /**
     * Header to store signature in.
     *
     * @return header type
     */
    public HttpSignHeader getHeader() {
        return header;
    }

    /**
     * Configuration of method to headers to define headers to be signed.
     * 

* The following headers have special handling: *

    *
  • date - if not present and required, will be added to request
  • *
  • host - if not present and required, will be added to request from target URI
  • *
  • (request-target) - as per spec, calculated from method and path
  • *
  • authorization - if {@link #getHeader()} returns {@link HttpSignHeader#AUTHORIZATION} it is ignored
  • *
* * @return configuration of headers to be signed */ public SignedHeadersConfig getSignedHeadersConfig() { return signedHeadersConfig; } /** * Fluent API builder to build {@link OutboundTargetDefinition} instances. * Call {@link #build()} to create a new instance. */ public static class Builder implements io.helidon.common.Builder { private String keyId; private String algorithm; private KeyConfig keyConfig; private HttpSignHeader header = HttpSignHeader.SIGNATURE; private byte[] hmacSharedSecret; private SignedHeadersConfig signedHeadersConfig = HttpSignProvider.DEFAULT_REQUIRED_HEADERS; private Builder() { } /** * Key id of this service (will be mapped by target service to validate signature). * * @param keyId key id mapped by target service * @return updated builder instance */ public Builder keyId(String keyId) { this.keyId = keyId; return this; } /** * Header to store signature in. * * @param header header type * @return updated builder instance */ public Builder header(HttpSignHeader header) { this.header = header; return this; } /** * Algorithm used by this signature. * Set automatically on call to methods {@link #privateKeyConfig(KeyConfig)} and {@link #hmacSecret(byte[])}. * * @param algorithm algorithm to use for outbound signatures * @return updated builder instance */ public Builder algorithm(String algorithm) { this.algorithm = algorithm; return this; } /** * Private key configuration for RSA based algorithms. * If called sets the algorithm to "rsa-sha256". Expects either explicit private key, or keystore and private key * alias. * * @param keyConfig private key configuration for outbound signatures * @return updated builder instance */ public Builder privateKeyConfig(KeyConfig keyConfig) { if (null == algorithm) { algorithm = HttpSignProvider.ALGORITHM_RSA; } // make sure this is a private key (signature of outbound requests) keyConfig.getPrivateKey() .orElseThrow(() -> new HttpSignatureException("Configuration must contain a private key")); this.keyConfig = keyConfig; return this; } /** * Configuration of required and "if-present" headers to be signed for this target. * Defaults to the same as {@link HttpSignProvider.Builder#inboundRequiredHeaders(SignedHeadersConfig)}. * * @param config configuration of outbound headers to be signed for each method. * @return updated builder instance */ public Builder signedHeaders(SignedHeadersConfig config) { this.signedHeadersConfig = config; return this; } /** * Shared secret for HMAC based algorithms. * Also sets the algorithm to "hmac-sha256" * * @param secret secret to sign outgoing requests (symmetric) * @return updated builder instance */ public Builder hmacSecret(byte[] secret) { if (null == algorithm) { algorithm = HttpSignProvider.ALGORITHM_HMAC; } this.hmacSharedSecret = Arrays.copyOf(secret, secret.length); return this; } /** * Shared secret for HMAC based algorithms. * Calls {@link #hmacSecret(byte[])} getting bytes of the secret string with UTF-8. * * @param secret shared secret to sign outgoing requests * @return updated builder instance */ public Builder hmacSecret(String secret) { return hmacSecret(secret.getBytes(StandardCharsets.UTF_8)); } @Override public OutboundTargetDefinition build() { return new OutboundTargetDefinition(this); } /** * Update this builder instance from configuration. * * @param config config instance * @return updated builder instance */ public Builder fromConfig(Config config) { Builder builder = new Builder(); // mandatory builder.keyId(config.get("key-id").asString()); config.get("header").asOptional(HttpSignHeader.class).ifPresent(builder::header); config.get("sign-headers").asOptional(SignedHeadersConfig.class).ifPresent(builder::signedHeaders); config.get("private-key").asOptional(KeyConfig.class).ifPresent(builder::privateKeyConfig); config.get("hmac.secret").value().ifPresent(builder::hmacSecret); // last, as we configure defaults based on configuration config.get("algorithm").value().ifPresent(builder::algorithm); return builder; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy