All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.autoconfigure.bootstrap.AppEncryptionBootstrapConfiguration Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version

package org.zodiac.autoconfigure.bootstrap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
import org.springframework.security.rsa.crypto.RsaSecretEncryptor;
import org.springframework.util.StringUtils;
import org.zodiac.autoconfigure.bootstrap.KeyProperties.KeyStore;
import org.zodiac.commons.constants.SystemPropertiesConstants;
import org.zodiac.core.bootstrap.encrypt.AppEnvironmentDecryptApplicationInitializer;
import org.zodiac.core.context.encrypt.EncryptorFactory;

@SpringBootConfiguration
@EnableConfigurationProperties(value = {KeyProperties.class})
@ConditionalOnClass({org.springframework.security.crypto.encrypt.TextEncryptor.class})
public class AppEncryptionBootstrapConfiguration {

    @Autowired(required = false)
    private org.springframework.security.crypto.encrypt.TextEncryptor encryptor;

    @Autowired
    private KeyProperties key;

    @Bean
    protected AppEnvironmentDecryptApplicationInitializer environmentDecryptApplicationListener() {
        if (this.encryptor == null) {
            this.encryptor = new FailsafeTextEncryptor();
        }
        AppEnvironmentDecryptApplicationInitializer listener =
            new AppEnvironmentDecryptApplicationInitializer(this.encryptor);
        listener.setFailOnError(this.key.isFailOnError());
        return listener;
    }

    @SpringBootConfiguration
    @Conditional(KeyCondition.class)
    @ConditionalOnClass(RsaSecretEncryptor.class)
    @EnableConfigurationProperties({RsaProperties.class})
    protected static class RsaEncryptionConfiguration {

        @Autowired
        private KeyProperties key;

        @Autowired
        private RsaProperties rsaProperties;

        @Bean
        @ConditionalOnMissingBean(org.springframework.security.crypto.encrypt.TextEncryptor.class)
        protected org.springframework.security.crypto.encrypt.TextEncryptor textEncryptor() {
            KeyStore keyStore = this.key.getKeyStore();
            if (keyStore.getLocation() != null) {
                if (keyStore.getLocation().exists()) {
                    return new RsaSecretEncryptor(
                        new KeyStoreKeyFactory(keyStore.getLocation(), keyStore.getPassword().toCharArray())
                            .getKeyPair(keyStore.getAlias(), keyStore.getSecret().toCharArray()),
                        this.rsaProperties.getAlgorithm(), this.rsaProperties.getSalt(), this.rsaProperties.isStrong());
                }

                throw new IllegalStateException("Invalid keystore location");
            }

            return new EncryptorFactory(this.key.getSalt()).create(this.key.getKey());
        }

    }

    @SpringBootConfiguration
    @Conditional(KeyCondition.class)
    @ConditionalOnMissingClass("org.springframework.security.rsa.crypto.RsaSecretEncryptor")
    protected static class VanillaEncryptionConfiguration {

        @Autowired
        private KeyProperties key;

        @Bean
        @ConditionalOnMissingBean(org.springframework.security.crypto.encrypt.TextEncryptor.class)
        protected org.springframework.security.crypto.encrypt.TextEncryptor textEncryptor() {
            return new EncryptorFactory(this.key.getSalt()).create(this.key.getKey());
        }

    }

    /**
     * A Spring Boot condition for key encryption.
     */
    public static class KeyCondition extends SpringBootCondition {

        @Override
        public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment environment = context.getEnvironment();
            if (hasProperty(environment, SystemPropertiesConstants.Zodiac.SPRING_BOOTSTRAP_ENCRYPT_KEY_STORE_LOC)) {
                if (hasProperty(environment, SystemPropertiesConstants.Zodiac.SPRING_BOOTSTRAP_ENCRYPT_KEY_STORE_PWD)) {
                    return ConditionOutcome.match("Keystore found in Environment");
                }
                return ConditionOutcome.noMatch("Keystore found but no password in Environment");
            } else if (hasProperty(environment, SystemPropertiesConstants.Zodiac.SPRING_BOOTSTRAP_ENCRYPT_KEY)) {
                return ConditionOutcome.match("Key found in Environment");
            }
            return ConditionOutcome.noMatch("Keystore nor key found in Environment");
        }

        private boolean hasProperty(Environment environment, String key) {
            String value = environment.getProperty(key);
            if (value == null) {
                return false;
            }
            return StringUtils.hasText(environment.resolvePlaceholders(value));
        }

    }

    /**
     * TextEncryptor that just fails, so that users don't get a false sense of security adding ciphers to config files
     * and not getting them decrypted.
     *
     *
     */
    protected static class FailsafeTextEncryptor implements org.springframework.security.crypto.encrypt.TextEncryptor {

        @Override
        public String encrypt(String text) {
            throw new UnsupportedOperationException(
                "No encryption for FailsafeTextEncryptor. Did you configure the keystore correctly?");
        }

        @Override
        public String decrypt(String encryptedText) {
            throw new UnsupportedOperationException(
                "No decryption for FailsafeTextEncryptor. Did you configure the keystore correctly?");
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy