io.helidon.integrations.oci.sdk.cdi.AdpStrategyDescriptors Maven / Gradle / Ivy
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* 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.integrations.oci.sdk.cdi;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Pattern;
import static java.util.function.Predicate.not;
/**
* A utility class providing convenience methods and fields for working with OCI authentication strategy
* descriptors.
*
* In this documentation, "OCI" is an abbreviation of "Oracle Cloud Infrastructure". "ADP" and "Adp" are
* abbreviations of "{@linkplain com.oracle.bmc.auth.BasicAuthenticationDetailsProvider authentication details
* provider}".
*
* An OCI authentication strategy descriptor—a simple {@link String} with no additional semantics—can
* serve as a kind of shorthand identifier for {@linkplain AdpSupplierSelector#select(Object) selecting} a particular
* {@link AdpSupplier} that can ultimately supply a particular {@link
* com.oracle.bmc.auth.BasicAuthenticationDetailsProvider BasicAuthenticationDetailsProvider} implementation.
*
* While fundamentally OCI authentication strategy descriptors are simply {@link String}s with no particular
* semantics, they are particularly useful when combined with the usage of an {@link AdpSupplierSelector}. See the
* {@link AdpSupplierSelector#select(Object)} method for more details.
*
* @see #strategyDescriptors(ConfigAccessor)
*
* @see #DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS
*
* @see AdpSupplier
*
* @see AdpSupplierSelector#select(Object)
*
* @see CascadingAdpSupplier
*/
final class AdpStrategyDescriptors {
/**
* A convenience field containing an ordered {@link List} of OCI authentication strategy descriptors, each
* element of which normally serves as an identifier for selecting a particular {@link AdpSupplier} that can
* ultimately supply a particular {@link com.oracle.bmc.auth.BasicAuthenticationDetailsProvider
* BasicAuthenticationDetailsProvider} implementation.
*
* The order of the list describes a common-sense approach to authentication that should work adequately in all
* environments and situations, ranging from local development to Kubernetes deployments.
*
* The {@link List} contains the following {@link String}s, in the following order:
*
*
* - {@code config}
* - {@code config-file}
* - {@code session-token-config-file}
* - {@code session-token-builder}
* - {@code instance-principals}
* - {@code resource-principal}
* - {@code oke-workload-identity}
*
*
* It is strongly recommended, but strictly speaking not required, that any {@link AdpSupplierSelector}
* implementation that uses {@link String}s as keys map these OCI authentication strategy descriptors to {@link
* AdpSupplier} instances as follows:
*
*
*
* - {@code config} should {@linkplain AdpSupplierSelector#select(Object) select} a
* {@link SimpleAdpSupplier} instance
*
* - {@code config-file} should {@linkplain AdpSupplierSelector#select(Object) select} a
* {@link ConfigFileAdpSupplier} instance
*
* - {@code session-token-config-file} should {@linkplain AdpSupplierSelector#select(Object)
* select} a {@link SessionTokenAdpSupplier} instance {@linkplain
* SessionTokenAdpSupplier#ofConfigFileSupplier(java.util.function.Supplier) originating from a
*
ConfigFile
}
*
* - {@code session-token-builder} should {@linkplain AdpSupplierSelector#select(Object) select}
* a {@link SessionTokenAdpSupplier} instance {@linkplain
* SessionTokenAdpSupplier#ofBuilderSupplier(Supplier) built by a
*
SessionTokenAuthenticationDetailsProviderBuilder
}
*
* - {@code instance-principals} should {@linkplain AdpSupplierSelector#select(Object) select} an
* {@link InstancePrincipalsAdpSupplier} instance
* - {@code resource-principal} should {@linkplain AdpSupplierSelector#select(Object) select} a
* {@link ResourcePrincipalAdpSupplier} instance
*
* - {@code oke-workload-identity} should {@linkplain AdpSupplierSelector#select(Object) select}
* an {@link OkeWorkloadIdentityAdpSupplier} instance
*
*
*
* @see strategyDescriptors(ConfigAccessor)
*
* @see AdpSupplier
*
* @see AdpSupplierSelector#select(Object)
*
* @see CascadingAdpSupplier
*/
public static final List DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS =
List.of("config",
"config-file",
"session-token-config-file",
"session-token-builder",
"instance-principals",
"resource-principal",
"oke-workload-identity");
private static final Pattern WHITESPACE_COMMA_WHITESPACE_PATTERN = Pattern.compile("\\s*,\\s*");
private AdpStrategyDescriptors() {
super();
}
/**
* A convenience method that returns a {@link List} of OCI authentication strategy descriptors, each
* element of which can serve as a kind of shorthand identifier for a particular {@link AdpSupplier} that can
* ultimately supply a {@link com.oracle.bmc.auth.BasicAuthenticationDetailsProvider
* BasicAuthenticationDetailsProvider} implementation.
*
* The behavior of this method is as follows:
*
*
*
* - The supplied {@link ConfigAccessor} is {@linkplain ConfigAccessor#get(String) queried for} a {@link
* String}-typed configuration value corresponding to the configuration name "{@code oci.auth-strategies}".
*
*
*
* - If that results in an {@linkplain java.util.Optional#isEmpty() empty
Optional
}, the {@link
* ConfigAccessor} is then {@linkplain ConfigAccessor#get(String) queried for} a {@link String}-typed configuration
* value corresponding to the configuration name "{@code oci.auth-strategy}". (This property exists for backwards
* compatibility only and its usage is discouraged.)
*
*
*
* - If this still results in an {@linkplain java.util.Optional#isEmpty() empty
Optional
}, then the
* value of the {@link #DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS} field is returned.
*
*
*
*
*
* - The resulting {@link String} value is {@linkplain String#strip() stripped}.
*
*
*
* - If the resulting {@link String} is {@linkplain String#isEmpty() empty}, then the value of the {@link
* #DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS} field is returned.
*
*
*
* - The resulting {@link String} value is now {@linkplain Pattern#split(CharSequence) split} as if by code
* similar to {@link Pattern Pattern}{@code .}{@link Pattern#compile(String) compile}{@code ("\\s*,\\s*").}{@link
* Pattern#split(CharSequence) split}{@code (value)}, and the resulting array is converted to an immutable {@link
* List} via the {@link List#of(Object...)} method, and the resulting {@link List} is returned.
*
*
*
* This method does not necessarily return a determinate value.
*
* This method never returns {@code null}.
*
* @param ca a {@link ConfigAccessor}; must not be {@code null}
*
* @return an unodifiable, unchanging {@link List} of names; never {@code null}
*
* @exception NullPointerException if {@code ca} is {@code null}
*
* @see #DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS
*
* @see AdpSupplierSelector
*
* @see AdpSupplier
*/
public static List strategyDescriptors(ConfigAccessor ca) {
return ca.get("oci.auth-strategies")
.or(() -> ca.get("oci.auth-strategy"))
.map(String::strip)
.filter(not(String::isEmpty))
.map(WHITESPACE_COMMA_WHITESPACE_PATTERN::split)
.map(List::of)
.orElse(DEFAULT_ORDERED_ADP_STRATEGY_DESCRIPTORS);
}
/**
* A convenience method that replaces occurrences of an element returned from an {@link
* java.util.Iterator Iterator} with {@link Collection}s of replacement elements and returns an unmodifiable and
* unchanging {@link List} representing the result.
*
* This method is often used in combination with the return value of the {@link
* #strategyDescriptors(ConfigAccessor)} method and an {@link AdpSupplierSelector}'s {@link
* AdpSupplierSelector#select(Iterable)} method, but it is general-purpose.
*
* @param the element type
*
* @param i an {@link Iterable}; must not be {@code null}
*
* @param f a {@link Function} that receives an element from the supplied {@link Iterable} and returns a {@link
* Collection} of replacement elements in its place (the {@link Collection} may be {@linkplain Collection#isEmpty()
* empty}); a {@link Function} that wishes to keep the element could, for example, return the equivalent of {@link
* List#of(Object) List.of(element)} or similar; must not return {@code null}; need not be safe for concurrent use
* by multiple threads
*
* @return an unmodifiable, unchanging {@link List} of elements that results from the replacement operation
*
* @exception NullPointerException if any argument is {@code null}
*/
public static List replaceElements(Iterable extends T> i, Function super T, ? extends Collection extends T>> f) {
ArrayList list = new ArrayList<>(9); // 9 == arbitrary, small
i.forEach(e -> list.addAll(f.apply(e)));
list.trimToSize();
return Collections.unmodifiableList(list);
}
}