001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.secret;
018
019import java.util.*;
020
021/**
022 * SPI for storing and retrieving a secret by key — the secure, mutable sibling of
023 * {@link org.apache.juneau.commons.settings.PropertySource}.
024 *
025 * <p>
026 * Where a {@code PropertySource} is a read-only source of ordinary configuration values, a {@code SecretStore}
027 * adds <i>write</i>/<i>delete</i> plus <i>sensitivity</i> semantics.  The SPI is deliberately narrow &mdash; it
028 * deals only in a {@link String} key and a {@code char[]} secret, with no dependency on any particular backend.
029 *
030 * <p>
031 * <b>Sensitivity is intrinsic.</b> Secret values are held as {@code char[]} rather than {@link String} so they can
032 * be explicitly zeroed and do not linger in the string pool.  An implementation must never {@code toString()}, log,
033 * or otherwise dump a secret value.  Callers are responsible for zeroing the arrays they pass to {@link #store}
034 * and receive from {@link #find} once done with them.
035 *
036 * <p>
037 * <b>Three-state presence model.</b> The three operations together model a clean present-with-value /
038 * present-without-materializing / absent distinction:
039 * <ul>
040 *    <li>{@link #find(String)} &mdash; returns the secret value when present ({@link Optional} of {@code char[]}),
041 *       or {@link Optional#empty()} when absent.  This is the only method that materializes the value.
042 *    <li>{@link #exists(String)} &mdash; reports whether a secret is stored under the key <i>without</i> retrieving
043 *       (and, for backends that decrypt on read, without decrypting) it.  Prefer this over {@link #find} when only
044 *       presence matters, so the secret is never pulled into memory needlessly.
045 *    <li><i>absent</i> &mdash; {@link #find} returns empty and {@link #exists} returns <jk>false</jk>.
046 * </ul>
047 *
048 * <p>
049 * <b>Backend-unavailable behavior is a consumer decision.</b> The built-in {@link InMemorySecretStore} and
050 * {@link EnvVarSecretStore} never fail on a well-formed call, so they simply throw on a genuine error.  Network- or
051 * OS-backed implementations (for example an OS-keychain-backed store in a separate module) should let the consumer
052 * pick fail-open vs fail-closed via a {@link FailMode} rather than baking a policy into the SPI.
053 *
054 * <h5 class='section'>See Also:</h5><ul>
055 *    <li class='jc'>{@link InMemorySecretStore}
056 *    <li class='jc'>{@link EnvVarSecretStore}
057 *    <li class='jc'>{@link FailMode}
058 *    <li class='jc'>{@link SecretStores}
059 * </ul>
060 *
061 * @since 10.0.0
062 */
063public interface SecretStore {
064
065   /**
066    * Stores a secret under the specified key, replacing any existing value.
067    *
068    * <p>
069    * The caller retains ownership of <jv>secret</jv> and may zero it after this call returns; an implementation
070    * that needs to retain the value must copy it.
071    *
072    * @param key The key under which to store the secret.  Must not be <jk>null</jk>.
073    * @param secret The secret value.  Must not be <jk>null</jk>.
074    * @throws UnsupportedOperationException If this store is read-only.
075    */
076   void store(String key, char[] secret);
077
078   /**
079    * Returns the secret stored under the specified key.
080    *
081    * <p>
082    * The returned array is the caller's to own and zero; it is not a live view of the store's internal state.
083    *
084    * @param key The key to look up.  Must not be <jk>null</jk>.
085    * @return The secret value, or {@link Optional#empty()} if no secret is stored under the key.
086    */
087   Optional<char[]> find(String key);
088
089   /**
090    * Returns whether a secret is stored under the specified key without materializing its value.
091    *
092    * @param key The key to check.  Must not be <jk>null</jk>.
093    * @return <jk>true</jk> if a secret is stored under the key.
094    */
095   boolean exists(String key);
096
097   /**
098    * Deletes the secret stored under the specified key.
099    *
100    * @param key The key to delete.  Must not be <jk>null</jk>.
101    * @return <jk>true</jk> if a secret was present and removed; <jk>false</jk> if the key was already absent.
102    * @throws UnsupportedOperationException If this store is read-only.
103    */
104   boolean delete(String key);
105}