/* * JBoss, Home of Professional Open Source * Copyright 2015 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.wildfly.security.credential.store; import static org.wildfly.security._private.ElytronMessages.log; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.Security; import java.security.spec.AlgorithmParameterSpec; import java.util.Map; import java.util.Set; import org.wildfly.common.Assert; import org.wildfly.security.credential.Credential; import org.wildfly.security.credential.source.CredentialSource; /** * This class represents credential store functionality. * Type of the credential store is determined by instance type and is loaded from {@link java.security.Provider}. * * @author <a href="mailto:pskopek@redhat.com">Peter Skopek</a>. */ public class CredentialStore { /** * JCA service type for a credential store. */ public static final String CREDENTIAL_STORE_TYPE = "CredentialStore"; private final Provider provider; private final String type; private final CredentialStoreSpi spi; /** * Get a {@code CredentialStore} instance. The returned CredentialStore object will implement the given algorithm. * * @param algorithm the name of the algorithm * @return a {@code CredentialStore} instance * @throws NoSuchAlgorithmException if the given algorithm has no available implementations */ public static CredentialStore getInstance(String algorithm) throws NoSuchAlgorithmException { for (Provider provider : Security.getProviders()) { final Provider.Service service = provider.getService(CREDENTIAL_STORE_TYPE, algorithm); if (service != null) { return new CredentialStore(provider, (CredentialStoreSpi) service.newInstance(null), algorithm); } } throw new NoSuchAlgorithmException(); } /** * Get a {@code CredentialStore} instance. The returned CredentialStore object will implement the given algorithm. * * @param algorithm the name of the algorithm * @param providerName the name of the provider to use * @return a {@code CredentialStore} instance * @throws NoSuchAlgorithmException if the given algorithm has no available implementations * @throws NoSuchProviderException if given provider name cannot match any registered {@link Provider} */ public static CredentialStore getInstance(String algorithm, String providerName) throws NoSuchAlgorithmException, NoSuchProviderException { final Provider provider = Security.getProvider(providerName); if (provider == null) throw new NoSuchProviderException(providerName); return getInstance(algorithm, provider); } /** * Get a {@code CredentialStore} instance. The returned CredentialStore object will implement the given algorithm. * * @param algorithm the name of the algorithm * @param provider the provider to use * @return a {@code CredentialStore} instance * @throws NoSuchAlgorithmException if the given algorithm has no available implementations */ public static CredentialStore getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { final Provider.Service service = provider.getService(CREDENTIAL_STORE_TYPE, algorithm); if (service == null) throw new NoSuchAlgorithmException(algorithm); return new CredentialStore(provider, (CredentialStoreSpi) service.newInstance(null), algorithm); } /** * Constructor to create CredentialStore instance * @param provider {@link Provider} of {@link CredentialStoreSpi} instance * @param spi {@link CredentialStoreSpi} instance * @param type JCA type of CredentialStore */ protected CredentialStore(Provider provider, CredentialStoreSpi spi, String type) { this.provider = provider; this.spi = spi; this.type = type; } /** * Initialize Credential Store service with given attributes. * This procedure should set {@link CredentialStoreSpi#initialized} after successful initialization. * * @param attributes attributes to used to pass information to Credential Store service * @param protectionParameter the protection parameter to use when accessing the store * @param providers providers to be injected into SPI implementation to get custom object instances of various type from * @throws CredentialStoreException if initialization fails due to any reason */ public void initialize(Map<String, String> attributes, ProtectionParameter protectionParameter, Provider[] providers) throws CredentialStoreException { spi.initialize(attributes, protectionParameter, providers); } /** * Initialize Credential Store service with given attributes. * This procedure should set {@link CredentialStoreSpi#initialized} after successful initialization. * * @param attributes attributes to used to pass information to Credential Store service * @param protectionParameter the protection parameter to use when accessing the store * @throws CredentialStoreException if initialization fails due to any reason */ public void initialize(Map<String, String> attributes, ProtectionParameter protectionParameter) throws CredentialStoreException { initialize(attributes, protectionParameter, null); } /** * Initialize Credential Store service with given attributes. * This procedure should set {@link CredentialStoreSpi#initialized} after successful initialization. * * @param attributes attributes to used to pass information to Credential Store service * @throws CredentialStoreException if initialization fails due to any reason */ public void initialize(Map<String, String> attributes) throws CredentialStoreException { initialize(attributes, null); } /** * Checks whether underlying credential store is initialized. * @return {@code true} in case of initialization passed successfully, {@code false} otherwise. */ public boolean isInitialized() { return spi.isInitialized(); } /** * Check if credential store supports modification of actual store * @return true in case of modification of store is supported */ public boolean isModifiable() { return spi.isModifiable(); } /** * Check whether credential store has an entry associated with the given credential alias of specified credential type. * @param credentialAlias alias to check existence * @param credentialType to check existence in the credential store * @param <C> the class of type to which should be credential casted * @return true in case key exist in store * @throws CredentialStoreException when there is a problem with credential store * @throws UnsupportedCredentialTypeException when the credentialType is not supported */ public <C extends Credential> boolean exists(String credentialAlias, Class<C> credentialType) throws CredentialStoreException, UnsupportedCredentialTypeException { return spi.exists(credentialAlias, credentialType); } /** * Store credential to the store under the given alias. If given alias already contains specific credential type type the credential * replaces older one. <em>Note:</em> {@link CredentialStoreSpi} supports storing of multiple entries (credential types) per alias. * Each must be of different credential type. * @param credentialAlias to store the credential to the store * @param credential instance of {@link Credential} to store * @param <C> the class of type to which should be credential casted * @throws CredentialStoreException when the credential cannot be stored * @throws UnsupportedCredentialTypeException when the credentialType is not supported */ public <C extends Credential> void store(String credentialAlias, C credential) throws CredentialStoreException, UnsupportedCredentialTypeException { store(credentialAlias, credential, null); } /** * Store credential to the store under the given alias. If given alias already contains specific credential type type the credential * replaces older one. <em>Note:</em> {@link CredentialStoreSpi} supports storing of multiple entries (credential types) per alias. * Each must be of different credential type. * @param credentialAlias to store the credential to the store * @param credential instance of {@link Credential} to store * @param protectionParameter the protection parameter to use, or {@code null} for none * @param <C> the class of type to which should be credential casted * @throws CredentialStoreException when the credential cannot be stored * @throws UnsupportedCredentialTypeException when the credentialType is not supported */ public <C extends Credential> void store(String credentialAlias, C credential, ProtectionParameter protectionParameter) throws CredentialStoreException, UnsupportedCredentialTypeException { if (isModifiable()) { spi.store(credentialAlias, credential, protectionParameter); } else { throw log.nonModifiableCredentialStore("store"); } } /** * Retrieve credential stored in the store under the key and of the credential type * @param credentialAlias to find the credential in the store * @param credentialType - credential type to retrieve from under the credentialAlias from the store * @param <C> the class of type to which should be credential casted * @return instance of {@link Credential} stored in the store * @throws CredentialStoreException - if credentialAlias credentialType combination doesn't exist or credentialAlias cannot be retrieved * @throws UnsupportedCredentialTypeException when the credentialType is not supported */ public <C extends Credential> C retrieve(String credentialAlias, Class<C> credentialType) throws CredentialStoreException, UnsupportedCredentialTypeException { return retrieve(credentialAlias, credentialType, null, null, null); } /** * Retrieve credential stored in the store under the key and of the credential type. * * @param credentialAlias to find the credential in the store * @param credentialType credential type to retrieve from under the credentialAlias from the store * @param credentialAlgorithm the credential algorithm to match, or {@code null} to match any * @param <C> the class of type to which should be credential casted * @return instance of {@link Credential} stored in the store * @throws CredentialStoreException if credentialAlias credentialType combination doesn't exist or credentialAlias cannot be retrieved */ public <C extends Credential> C retrieve(String credentialAlias, Class<C> credentialType, String credentialAlgorithm) throws CredentialStoreException { return retrieve(credentialAlias, credentialType, credentialAlgorithm, null, null); } /** * Retrieve credential stored in the store under the key and of the credential type. * * @param credentialAlias to find the credential in the store * @param credentialType credential type to retrieve from under the credentialAlias from the store * @param credentialAlgorithm the credential algorithm to match, or {@code null} to match any * @param parameterSpec the parameter specification to match, or {@code null} to match any * @param <C> the class of type to which should be credential casted * @return instance of {@link Credential} stored in the store * @throws CredentialStoreException if credentialAlias credentialType combination doesn't exist or credentialAlias cannot be retrieved */ public <C extends Credential> C retrieve(String credentialAlias, Class<C> credentialType, String credentialAlgorithm, AlgorithmParameterSpec parameterSpec) throws CredentialStoreException { return retrieve(credentialAlias, credentialType, credentialAlgorithm, parameterSpec, null); } /** * Retrieve credential stored in the store under the key and of the credential type. * * @param credentialAlias to find the credential in the store * @param credentialType credential type to retrieve from under the credentialAlias from the store * @param credentialAlgorithm the credential algorithm to match, or {@code null} to match any * @param parameterSpec the parameter specification to match, or {@code null} to match any * @param protectionParameter the protection parameter to use, or {@code null} to use none * @param <C> the class of type to which should be credential casted * @return instance of {@link Credential} stored in the store * @throws CredentialStoreException if credentialAlias credentialType combination doesn't exist or credentialAlias cannot be retrieved */ public <C extends Credential> C retrieve(String credentialAlias, Class<C> credentialType, String credentialAlgorithm, AlgorithmParameterSpec parameterSpec, ProtectionParameter protectionParameter) throws CredentialStoreException { return spi.retrieve(credentialAlias, credentialType, credentialAlgorithm, parameterSpec, protectionParameter); } /** * Remove the credentialType with from given alias matching the given criteria from the store. * * @param credentialAlias alias to remove credential(s) from * @param credentialType credential type to match (must not be {@code null}) * @throws CredentialStoreException if credential removal fails */ public void remove(String credentialAlias, Class<? extends Credential> credentialType) throws CredentialStoreException { remove(credentialAlias, credentialType, null, null); } /** * Remove the credentialType with from given alias matching the given criteria from the store. * * @param credentialAlias alias to remove credential(s) from * @param credentialType credential type to match (must not be {@code null}) * @param credentialAlgorithm the algorithm name to match, or {@code null} to match any * @throws CredentialStoreException if credential removal fails */ public void remove(String credentialAlias, Class<? extends Credential> credentialType, String credentialAlgorithm) throws CredentialStoreException { remove(credentialAlias, credentialType, credentialAlgorithm, null); } /** * Remove the credentialType with from given alias matching the given criteria from the store. * * @param credentialAlias alias to remove credential(s) from * @param credentialType credential type to match (must not be {@code null}) * @param credentialAlgorithm the algorithm name to match, or {@code null} to match any * @param parameterSpec the parameters to match, or {@code null} to match any * @throws CredentialStoreException if credential removal fails */ public void remove(String credentialAlias, Class<? extends Credential> credentialType, String credentialAlgorithm, AlgorithmParameterSpec parameterSpec) throws CredentialStoreException { if (isModifiable()) { spi.remove(credentialAlias, credentialType, credentialAlgorithm, parameterSpec); } else { throw log.nonModifiableCredentialStore("remove"); } } /** * Returns {@code Set<String>} stored in this store. * * @return {@code Set<String>} of all keys stored in this store * @throws UnsupportedOperationException when this method is not supported by the underlying credential store * @throws CredentialStoreException if there is any problem with internal store */ public Set<String> getAliases() throws UnsupportedOperationException, CredentialStoreException { return spi.getAliases(); } /** * Flush the contents of this credential store to storage. This method may be a no-op on credential stores * without backing storage or which do not buffer changes. * * @throws CredentialStoreException if flushing the store fails for some reason */ public void flush() throws CredentialStoreException { if (isModifiable()) { spi.flush(); } else { throw log.nonModifiableCredentialStore("flush"); } } /** * Returns {@link Provider} which provides {@link CredentialStoreSpi} for this instance. * @return {@link Provider} of this {@link CredentialStoreSpi} */ public Provider getProvider() { return provider; } /** * Returns JCA service type of {@link CredentialStoreSpi} for this instance. * @return type of service of this {@link CredentialStoreSpi} */ public String getType() { return type; } /** * The protection parameter to use when accessing a credential store or entry. */ public interface ProtectionParameter { } /** * A protection parameter which uses a credential source to acquire a credential to use. */ public static final class CredentialSourceProtectionParameter implements ProtectionParameter { private final CredentialSource credentialSource; /** * Construct a new instance. * * @param credentialSource the credential source to use (must not be {@code null}) */ public CredentialSourceProtectionParameter(final CredentialSource credentialSource) { Assert.checkNotNullParam("credentialSource", credentialSource); this.credentialSource = credentialSource; } /** * Get the credential source. * * @return the credential source (not {@code null}) */ public CredentialSource getCredentialSource() { return credentialSource; } } }