1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.encrypt.rule;
19
20 import com.google.common.base.Preconditions;
21 import org.apache.shardingsphere.encrypt.api.config.EncryptRuleConfiguration;
22 import org.apache.shardingsphere.encrypt.api.config.rule.EncryptColumnRuleConfiguration;
23 import org.apache.shardingsphere.encrypt.api.config.rule.EncryptTableRuleConfiguration;
24 import org.apache.shardingsphere.encrypt.exception.metadata.EncryptTableNotFoundException;
25 import org.apache.shardingsphere.encrypt.exception.metadata.MismatchedEncryptAlgorithmTypeException;
26 import org.apache.shardingsphere.encrypt.rule.attribute.EncryptTableMapperRuleAttribute;
27 import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
28 import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
29 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
30 import org.apache.shardingsphere.infra.rule.PartialRuleUpdateSupported;
31 import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
32 import org.apache.shardingsphere.infra.rule.scope.DatabaseRule;
33 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
34
35 import java.util.Collection;
36 import java.util.HashSet;
37 import java.util.Map.Entry;
38 import java.util.Optional;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.atomic.AtomicReference;
41 import java.util.stream.Collectors;
42
43
44
45
46 public final class EncryptRule implements DatabaseRule, PartialRuleUpdateSupported<EncryptRuleConfiguration> {
47
48 private final String databaseName;
49
50 private final AtomicReference<EncryptRuleConfiguration> ruleConfig = new AtomicReference<>();
51
52 private final ConcurrentHashMap<String, EncryptAlgorithm> encryptors;
53
54 private final ConcurrentHashMap<String, EncryptTable> tables = new ConcurrentHashMap<>();
55
56 private final AtomicReference<RuleAttributes> attributes = new AtomicReference<>();
57
58 public EncryptRule(final String databaseName, final EncryptRuleConfiguration ruleConfig) {
59 this.databaseName = databaseName;
60 this.ruleConfig.set(ruleConfig);
61 encryptors = createEncryptors(ruleConfig);
62 for (EncryptTableRuleConfiguration each : ruleConfig.getTables()) {
63 each.getColumns().forEach(this::checkEncryptorType);
64 tables.put(each.getName().toLowerCase(), new EncryptTable(each, encryptors));
65 }
66 attributes.set(new RuleAttributes(new EncryptTableMapperRuleAttribute(tables.keySet())));
67 }
68
69 private ConcurrentHashMap<String, EncryptAlgorithm> createEncryptors(final EncryptRuleConfiguration ruleConfig) {
70 ConcurrentHashMap<String, EncryptAlgorithm> result = new ConcurrentHashMap<>(ruleConfig.getEncryptors().size(), 1F);
71 for (Entry<String, AlgorithmConfiguration> entry : ruleConfig.getEncryptors().entrySet()) {
72 result.put(entry.getKey(), TypedSPILoader.getService(EncryptAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps()));
73 }
74 return result;
75 }
76
77
78 private void checkEncryptorType(final EncryptColumnRuleConfiguration columnRuleConfig) {
79 ShardingSpherePreconditions.checkState(encryptors.containsKey(columnRuleConfig.getCipher().getEncryptorName())
80 && encryptors.get(columnRuleConfig.getCipher().getEncryptorName()).getMetaData().isSupportDecrypt(),
81 () -> new MismatchedEncryptAlgorithmTypeException(databaseName, "Cipher", columnRuleConfig.getCipher().getEncryptorName(), "decrypt"));
82 columnRuleConfig.getAssistedQuery().ifPresent(optional -> ShardingSpherePreconditions.checkState(encryptors.containsKey(optional.getEncryptorName())
83 && encryptors.get(optional.getEncryptorName()).getMetaData().isSupportEquivalentFilter(),
84 () -> new MismatchedEncryptAlgorithmTypeException(databaseName, "Assisted query", columnRuleConfig.getCipher().getEncryptorName(), "equivalent filter")));
85 columnRuleConfig.getLikeQuery().ifPresent(optional -> ShardingSpherePreconditions.checkState(encryptors.containsKey(optional.getEncryptorName())
86 && encryptors.get(optional.getEncryptorName()).getMetaData().isSupportLike(),
87 () -> new MismatchedEncryptAlgorithmTypeException(databaseName, "Like query", columnRuleConfig.getCipher().getEncryptorName(), "like")));
88 }
89
90
91
92
93
94
95 public Collection<String> getAllTableNames() {
96 return tables.keySet();
97 }
98
99
100
101
102
103
104
105 public Optional<EncryptTable> findEncryptTable(final String tableName) {
106 return Optional.ofNullable(tables.get(tableName.toLowerCase()));
107 }
108
109
110
111
112
113
114
115 public EncryptTable getEncryptTable(final String tableName) {
116 Optional<EncryptTable> encryptTable = findEncryptTable(tableName);
117 ShardingSpherePreconditions.checkState(encryptTable.isPresent(), () -> new EncryptTableNotFoundException(tableName));
118 return encryptTable.get();
119 }
120
121 @Override
122 public RuleAttributes getAttributes() {
123 return attributes.get();
124 }
125
126 @Override
127 public EncryptRuleConfiguration getConfiguration() {
128 return ruleConfig.get();
129 }
130
131 @Override
132 public void updateConfiguration(final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
133 ruleConfig.set(toBeUpdatedRuleConfig);
134 }
135
136 @Override
137 public boolean partialUpdate(final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
138 Collection<String> toBeAddedTableNames = toBeUpdatedRuleConfig.getTables().stream().map(EncryptTableRuleConfiguration::getName).filter(each -> !tables.containsKey(each.toLowerCase()))
139 .collect(Collectors.toList());
140 if (!toBeAddedTableNames.isEmpty()) {
141 toBeAddedTableNames.forEach(each -> addTableRule(each, toBeUpdatedRuleConfig));
142 attributes.set(new RuleAttributes(new EncryptTableMapperRuleAttribute(tables.keySet())));
143 return true;
144 }
145 Collection<String> toBeRemovedTableNames = new HashSet<>(tables.keySet());
146 toBeRemovedTableNames.removeAll(toBeUpdatedRuleConfig.getTables().stream().map(EncryptTableRuleConfiguration::getName).collect(Collectors.toList()));
147 if (!toBeRemovedTableNames.isEmpty()) {
148 toBeRemovedTableNames.stream().map(String::toLowerCase).forEach(tables::remove);
149 attributes.set(new RuleAttributes(new EncryptTableMapperRuleAttribute(tables.keySet())));
150
151 return true;
152 }
153
154
155 return false;
156 }
157
158 private void addTableRule(final String tableName, final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
159 EncryptTableRuleConfiguration tableRuleConfig = getTableRuleConfiguration(tableName, toBeUpdatedRuleConfig);
160 for (Entry<String, AlgorithmConfiguration> entry : toBeUpdatedRuleConfig.getEncryptors().entrySet()) {
161 encryptors.computeIfAbsent(entry.getKey(), key -> TypedSPILoader.getService(EncryptAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps()));
162 }
163 tableRuleConfig.getColumns().forEach(this::checkEncryptorType);
164 tables.put(tableName.toLowerCase(), new EncryptTable(tableRuleConfig, encryptors));
165 }
166
167 private EncryptTableRuleConfiguration getTableRuleConfiguration(final String tableName, final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
168 Optional<EncryptTableRuleConfiguration> result = toBeUpdatedRuleConfig.getTables().stream().filter(table -> table.getName().equals(tableName)).findFirst();
169 Preconditions.checkState(result.isPresent());
170 return result.get();
171 }
172 }