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 — 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)} — 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)} — 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> — {@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}