001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.enc;
017
018import java.util.List;
019
020import org.jasypt.util.text.TextEncryptor;
021import org.kuali.common.util.Assert;
022import org.kuali.common.util.PropertyUtils;
023import org.kuali.common.util.Str;
024import org.kuali.common.util.spring.SpringUtils;
025import org.kuali.common.util.spring.env.BasicEnvironmentService;
026import org.kuali.common.util.spring.env.EnvUtils;
027import org.kuali.common.util.spring.env.EnvironmentService;
028
029import com.google.common.base.Optional;
030import com.google.common.collect.ImmutableList;
031
032/**
033 * @deprecated Use EncContext instead
034 */
035@Deprecated
036public final class EncContext {
037
038        private final Optional<TextEncryptor> textEncryptor;
039        private final EncStrength strength;
040
041        private EncContext(Builder builder) {
042                this.strength = builder.strength;
043                this.textEncryptor = builder.textEncryptor;
044        }
045
046        public Optional<TextEncryptor> getTextEncryptor() {
047                return textEncryptor;
048        }
049
050        public EncStrength getStrength() {
051                return strength;
052        }
053
054        public static Builder builder(String password) {
055                return new Builder(password);
056        }
057
058        public static Builder builder(EnvironmentService env) {
059                return new Builder(env);
060        }
061
062        public static class Builder {
063
064                // Required (but optional)
065                private final Optional<String> password;
066                private final Optional<EnvironmentService> env;
067
068                // Optional
069                private Optional<TextEncryptor> textEncryptor = Optional.absent();
070                private EncStrength strength = EncStrength.BASIC;
071                private boolean required = false;
072                private boolean removeSystemProperties = false;
073
074                private static final List<String> PASSWORD_KEYS = ImmutableList.of("enc.password", "properties.enc.password");
075                private static final List<String> STRENGTH_KEYS = ImmutableList.of("enc.strength", "properties.enc.strength");
076                private static final List<String> PASSWORD_REQUIRED_KEYS = ImmutableList.of("enc.password.required", "properties.decrypt");
077                private static final String PASSWORD_REMOVE_KEY = "enc.password.removeSystemProperty";
078
079                /**
080                 * Setup encryption using <code>password</code>
081                 */
082                public Builder(String password) {
083                        this(EnvUtils.ABSENT, Optional.of(password));
084                }
085
086                /**
087                 * Use the password they gave us, unless it is overridden by a password in the environment
088                 */
089                public Builder(EnvironmentService env, String password) {
090                        this(Optional.of(env), Optional.of(password));
091                }
092
093                /**
094                 * Use system properties / environment variables to locate the encryption password
095                 */
096                public Builder() {
097                        this(new BasicEnvironmentService());
098                }
099
100                /**
101                 * Locate the encryption password in the environment
102                 */
103                public Builder(EnvironmentService env) {
104                        this(Optional.of(env), Optional.<String> absent());
105                }
106
107                private Builder(Optional<EnvironmentService> env, Optional<String> password) {
108                        if (env.isPresent()) {
109                                this.password = SpringUtils.getString(env, PASSWORD_KEYS, password);
110                        } else {
111                                this.password = password;
112                        }
113                        this.env = env;
114                }
115
116                public Builder removeSystemProperties(boolean removeSystemProperties) {
117                        this.removeSystemProperties = removeSystemProperties;
118                        return this;
119                }
120
121                public Builder required(boolean required) {
122                        this.required = required;
123                        return this;
124                }
125
126                public Builder strength(EncStrength strength) {
127                        this.strength = strength;
128                        return this;
129                }
130
131                private void override() {
132                        if (env.isPresent()) {
133                                strength(SpringUtils.getProperty(env, STRENGTH_KEYS, EncStrength.class, strength));
134                                required(SpringUtils.getProperty(env, PASSWORD_REQUIRED_KEYS, Boolean.class, required));
135                                removeSystemProperties(env.get().getBoolean(PASSWORD_REMOVE_KEY, removeSystemProperties));
136                        }
137                }
138
139                private void validate(EncContext ctx, boolean required, Optional<String> password) {
140                        Assert.notNull(ctx.getTextEncryptor(), "'textEncryptor' cannot be null");
141                        Assert.notNull(ctx.getStrength(), "'strength' cannot be null");
142                        if (required) {
143                                Assert.isTrue(ctx.getTextEncryptor().isPresent());
144                        }
145                        if (password.isPresent()) {
146                                Assert.noBlanks(password.get());
147                                Assert.notEncrypted(password.get());
148                                Assert.notConcealed(password.get());
149                        }
150                }
151
152                private void finish() {
153                        override();
154                        if (password.isPresent()) {
155                                String revealed = Str.reveal(password.get());
156                                TextEncryptor enc = EncUtils.getTextEncryptor(revealed, strength);
157                                this.textEncryptor = Optional.of(enc);
158                        }
159                }
160
161                public EncContext build() {
162                        // Finish setting up the builder
163                        finish();
164
165                        // Get local references to builder instance variables
166                        boolean required = this.required;
167                        boolean removeSystemProperties = this.removeSystemProperties;
168                        Optional<String> password = Optional.fromNullable(this.password.orNull());
169
170                        // Construct the encryption context
171                        EncContext ctx = new EncContext(this);
172
173                        // Validate that it's in good shape
174                        validate(ctx, required, password);
175
176                        // Now that we've successfully created and validated the instance, it's safe to remove the system properties
177                        if (removeSystemProperties) {
178                                PropertyUtils.removeSystemProperties(PASSWORD_KEYS);
179                        }
180
181                        // Return the context
182                        return ctx;
183                }
184
185        }
186
187}