1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.common.keymaster.client.zookeeper;
20
21 import com.fasterxml.jackson.databind.json.JsonMapper;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Objects;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.curator.framework.CuratorFramework;
28 import org.apache.curator.framework.recipes.cache.CuratorCache;
29 import org.apache.syncope.common.keymaster.client.api.DomainOps;
30 import org.apache.syncope.common.keymaster.client.api.DomainWatcher;
31 import org.apache.syncope.common.keymaster.client.api.KeymasterException;
32 import org.apache.syncope.common.keymaster.client.api.model.Domain;
33 import org.apache.syncope.common.lib.SyncopeConstants;
34 import org.apache.syncope.common.lib.types.CipherAlgorithm;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.springframework.beans.factory.InitializingBean;
38 import org.springframework.beans.factory.annotation.Autowired;
39
40
41
42
43 public class ZookeeperDomainOps implements DomainOps, InitializingBean {
44
45 protected static final Logger LOG = LoggerFactory.getLogger(DomainOps.class);
46
47 protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build();
48
49 protected static final String DOMAIN_PATH = "/domains";
50
51 protected static String buildDomainPath(final String... parts) {
52 String prefix = DOMAIN_PATH;
53 String suffix = StringUtils.EMPTY;
54 if (parts != null && parts.length > 0) {
55 suffix = '/' + String.join("/", parts);
56 }
57 return prefix + suffix;
58 }
59
60 @Autowired
61 protected CuratorFramework client;
62
63 @Autowired(required = false)
64 protected DomainWatcher watcher;
65
66 @Override
67 public void afterPropertiesSet() throws Exception {
68 if (watcher != null) {
69 if (client.checkExists().forPath(buildDomainPath()) == null) {
70 client.create().creatingParentContainersIfNeeded().forPath(buildDomainPath());
71 }
72
73 CuratorCache cache = CuratorCache.build(client, buildDomainPath());
74 cache.listenable().addListener((type, oldData, newData) -> {
75 switch (type) {
76 case NODE_CREATED:
77 LOG.debug("Domain {} added", newData.getPath());
78 try {
79 Domain domain = MAPPER.readValue(newData.getData(), Domain.class);
80
81 LOG.info("Domain {} created", domain.getKey());
82 watcher.added(domain);
83 } catch (IOException e) {
84 LOG.debug("Could not parse {}", new String(newData.getData()), e);
85 }
86 break;
87
88 case NODE_CHANGED:
89 LOG.debug("Domain {} updated", newData.getPath());
90 break;
91
92 case NODE_DELETED:
93 LOG.debug("Domain {} removed", newData.getPath());
94 watcher.removed(StringUtils.substringAfter(newData.getPath(), DOMAIN_PATH + '/'));
95 break;
96
97 default:
98 LOG.debug("Event {} received with data {}", type, newData);
99 }
100 });
101 cache.start();
102 }
103 }
104
105 @Override
106 public List<Domain> list() {
107 try {
108 if (client.checkExists().forPath(buildDomainPath()) == null) {
109 client.create().creatingParentContainersIfNeeded().forPath(buildDomainPath());
110 }
111
112 List<Domain> list = new ArrayList<>();
113 for (String child : client.getChildren().forPath(buildDomainPath())) {
114 list.add(MAPPER.readValue(client.getData().forPath(buildDomainPath(child)), Domain.class));
115 }
116
117 return list;
118 } catch (Exception e) {
119 throw new KeymasterException(e);
120 }
121 }
122
123 @Override
124 public Domain read(final String key) {
125 try {
126 return MAPPER.readValue(client.getData().forPath(buildDomainPath(key)), Domain.class);
127 } catch (Exception e) {
128 throw new KeymasterException(e);
129 }
130 }
131
132 @Override
133 public void create(final Domain domain) {
134 if (Objects.equals(domain.getKey(), SyncopeConstants.MASTER_DOMAIN)) {
135 throw new KeymasterException("Cannot create domain " + SyncopeConstants.MASTER_DOMAIN);
136 }
137
138 try {
139 if (client.checkExists().forPath(buildDomainPath(domain.getKey())) != null) {
140 throw new KeymasterException("Domain " + domain.getKey() + " existing");
141 }
142
143 client.create().creatingParentContainersIfNeeded().
144 forPath(buildDomainPath(domain.getKey()), MAPPER.writeValueAsBytes(domain));
145 } catch (KeymasterException e) {
146 throw e;
147 } catch (Exception e) {
148 throw new KeymasterException(e);
149 }
150 }
151
152 @Override
153 public void changeAdminPassword(
154 final String key, final String password, final CipherAlgorithm cipherAlgorithm) {
155
156 try {
157 Domain domain = read(key);
158
159 domain.setAdminPassword(password);
160 domain.setAdminCipherAlgorithm(cipherAlgorithm);
161 client.setData().forPath(buildDomainPath(key), MAPPER.writeValueAsBytes(domain));
162 } catch (KeymasterException e) {
163 throw e;
164 } catch (Exception e) {
165 throw new KeymasterException(e);
166 }
167 }
168
169 @Override
170 public void adjustPoolSize(final String key, final int poolMaxActive, final int poolMinIdle) {
171 try {
172 Domain domain = read(key);
173
174 domain.setPoolMaxActive(poolMaxActive);
175 domain.setPoolMinIdle(poolMinIdle);
176 client.setData().forPath(buildDomainPath(key), MAPPER.writeValueAsBytes(domain));
177 } catch (KeymasterException e) {
178 throw e;
179 } catch (Exception e) {
180 throw new KeymasterException(e);
181 }
182 }
183
184 @Override
185 public void delete(final String key) {
186 try {
187 client.delete().forPath(buildDomainPath(key));
188 } catch (Exception e) {
189 throw new KeymasterException(e);
190 }
191 }
192 }