com.amazonaws.encryptionsdk.multi.MultipleProviderFactory Maven / Gradle / Ivy
/*
* Copyright 2016 Amazon.com, Inc. 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. A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.encryptionsdk.multi;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
import com.amazonaws.encryptionsdk.DataKey;
import com.amazonaws.encryptionsdk.EncryptedDataKey;
import com.amazonaws.encryptionsdk.MasterKey;
import com.amazonaws.encryptionsdk.MasterKeyProvider;
import com.amazonaws.encryptionsdk.MasterKeyRequest;
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.exception.NoSuchMasterKeyException;
import com.amazonaws.encryptionsdk.exception.UnsupportedProviderException;
import com.amazonaws.encryptionsdk.internal.Utils;
/**
* Constructs {@link MasterKeyProvider}s which are backed by any number of other
* {@link MasterKeyProvider}s. The returned provider will have the following properties:
*
*
* - {@link MasterKeyProvider#getMasterKeysForEncryption(MasterKeyRequest)} will result in the
* union of all responses from the backing providers. Likewise,
*
- {@link MasterKeyProvider#decryptDataKey(CryptoAlgorithm, Collection, Map)} will succeed if
* and only if at least one backing provider can successfully decrypt the {@link DataKey}s.
*
- {@link MasterKeyProvider#getDefaultProviderId()} is delegated to the first backing provider.
*
- {@link MasterKeyProvider#getMasterKey(String, String)} will attempt to find the appropriate
* backing provider to return a {@link MasterKey}.
*
*
* All methods in this factory return identical results and exist only for different degrees of
* type-safety.
*/
public class MultipleProviderFactory {
private MultipleProviderFactory() {
// Prevent instantiation
}
public static > MasterKeyProvider buildMultiProvider(final Class masterKeyClass,
final List extends MasterKeyProvider extends K>> providers) {
return new MultiProvider(providers);
}
@SafeVarargs
public static , P extends MasterKeyProvider extends K>> MasterKeyProvider buildMultiProvider(
final Class masterKeyClass, final P... providers) {
return buildMultiProvider(masterKeyClass, Arrays.asList(providers));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static MasterKeyProvider> buildMultiProvider(final List extends MasterKeyProvider>> providers) {
return new MultiProvider(providers);
}
@SafeVarargs
public static > MasterKeyProvider> buildMultiProvider(final P... providers) {
return buildMultiProvider(Arrays.asList(providers));
}
private static class MultiProvider> extends MasterKeyProvider {
private final List extends MasterKeyProvider extends K>> providers_;
private MultiProvider(final List extends MasterKeyProvider extends K>> providers) {
Utils.assertNonNull(providers, "providers");
if (providers.isEmpty()) {
throw new IllegalArgumentException("providers must not be empty");
}
providers_ = new ArrayList<>(providers);
}
@Override
public String getDefaultProviderId() {
return providers_.get(0).getDefaultProviderId();
}
@Override
public K getMasterKey(final String keyId) throws UnsupportedProviderException, NoSuchMasterKeyException {
for (final MasterKeyProvider extends K> prov : providers_) {
try {
final K result = prov.getMasterKey(keyId);
if (result != null) {
return result;
}
} catch (final NoSuchMasterKeyException ex) {
// swallow and continue
}
}
throw new NoSuchMasterKeyException();
}
@Override
public K getMasterKey(final String provider, final String keyId) throws UnsupportedProviderException,
NoSuchMasterKeyException {
boolean foundProvider = false;
for (final MasterKeyProvider extends K> prov : providers_) {
if (prov.canProvide(provider)) {
foundProvider = true;
try {
final K result = prov.getMasterKey(provider, keyId);
if (result != null) {
return result;
}
} catch (final NoSuchMasterKeyException ex) {
// swallow and continue
}
}
}
if (foundProvider) {
throw new NoSuchMasterKeyException();
} else {
throw new UnsupportedProviderException(provider);
}
}
@Override
public List getMasterKeysForEncryption(final MasterKeyRequest request) {
final List result = new ArrayList<>();
for (final MasterKeyProvider extends K> prov : providers_) {
result.addAll(prov.getMasterKeysForEncryption(request));
}
return result;
}
@SuppressWarnings("unchecked")
@Override
public DataKey decryptDataKey(final CryptoAlgorithm algorithm,
final Collection extends EncryptedDataKey> encryptedDataKeys,
final Map encryptionContext)
throws UnsupportedProviderException, AwsCryptoException {
final List exceptions = new ArrayList<>();
for (final MasterKeyProvider extends K> prov : providers_) {
try {
final DataKey extends K> result = prov
.decryptDataKey(algorithm, encryptedDataKeys, encryptionContext);
if (result != null) {
return (DataKey) result;
}
} catch (final Exception ex) {
exceptions.add(ex);
}
}
throw buildCannotDecryptDksException(exceptions);
}
}
}