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 java.util.List;
22 import java.util.Map;
23 import java.util.concurrent.TimeUnit;
24 import java.util.regex.Pattern;
25 import javax.security.auth.login.AppConfigurationEntry;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.curator.framework.CuratorFramework;
28 import org.apache.curator.framework.CuratorFrameworkFactory;
29 import org.apache.curator.framework.api.ACLProvider;
30 import org.apache.curator.retry.ExponentialBackoffRetry;
31 import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
32 import org.apache.syncope.common.keymaster.client.api.DomainOps;
33 import org.apache.syncope.common.keymaster.client.api.KeymasterProperties;
34 import org.apache.syncope.common.keymaster.client.api.ServiceOps;
35 import org.apache.zookeeper.ZooDefs;
36 import org.apache.zookeeper.data.ACL;
37 import org.apache.zookeeper.server.auth.DigestLoginModule;
38 import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
39 import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
40 import org.springframework.boot.context.properties.EnableConfigurationProperties;
41 import org.springframework.context.annotation.Bean;
42 import org.springframework.context.annotation.ConditionContext;
43 import org.springframework.context.annotation.Conditional;
44 import org.springframework.context.annotation.Configuration;
45 import org.springframework.core.type.AnnotatedTypeMetadata;
46
47 @EnableConfigurationProperties(KeymasterProperties.class)
48 @Configuration(proxyBeanMethods = false)
49 public class ZookeeperKeymasterClientContext {
50
51 private static final Pattern IPV4 = Pattern.compile(
52 "^((\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})|[a-z\\.]+):[0-9]+$");
53
54 static class ZookeeperCondition extends SpringBootCondition {
55
56 @Override
57 public ConditionOutcome getMatchOutcome(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
58 String keymasterAddress = context.getEnvironment().getProperty("keymaster.address");
59 return new ConditionOutcome(
60 keymasterAddress != null && IPV4.matcher(keymasterAddress).matches(),
61 "Keymaster address not set for Zookeeper: " + keymasterAddress);
62 }
63 }
64
65 @Conditional(ZookeeperCondition.class)
66 @Bean
67 public CuratorFramework curatorFramework(final KeymasterProperties props) throws InterruptedException {
68 if (StringUtils.isNotBlank(props.getUsername()) && StringUtils.isNotBlank(props.getPassword())) {
69 javax.security.auth.login.Configuration.setConfiguration(new javax.security.auth.login.Configuration() {
70
71 private final AppConfigurationEntry[] entries = {
72 new AppConfigurationEntry(
73 DigestLoginModule.class.getName(),
74 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
75 Map.of(
76 "username", props.getUsername(),
77 "password", props.getPassword()
78 ))
79 };
80
81 @Override
82 public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {
83 return entries;
84 }
85 });
86 }
87
88 CuratorFrameworkFactory.Builder clientBuilder = CuratorFrameworkFactory.builder().
89 connectString(props.getAddress()).
90 retryPolicy(new ExponentialBackoffRetry(props.getBaseSleepTimeMs(), props.getMaxRetries()));
91 if (StringUtils.isNotBlank(props.getUsername())) {
92 clientBuilder.authorization("digest", props.getUsername().getBytes()).aclProvider(new ACLProvider() {
93
94 @Override
95 public List<ACL> getDefaultAcl() {
96 return ZooDefs.Ids.CREATOR_ALL_ACL;
97 }
98
99 @Override
100 public List<ACL> getAclForPath(final String path) {
101 return ZooDefs.Ids.CREATOR_ALL_ACL;
102 }
103 });
104 }
105 CuratorFramework client = clientBuilder.build();
106 client.start();
107 client.blockUntilConnected(3, TimeUnit.SECONDS);
108
109 return client;
110 }
111
112 @Conditional(ZookeeperCondition.class)
113 @Bean
114 public ConfParamOps selfConfParamOps(final CuratorFramework client) {
115 return new ZookeeperConfParamOps(client);
116 }
117
118 @Conditional(ZookeeperCondition.class)
119 @Bean
120 public ServiceOps serviceOps() {
121 return new ZookeeperServiceDiscoveryOps();
122
123 }
124
125 @Conditional(ZookeeperCondition.class)
126 @Bean
127 public DomainOps domainOps() {
128 return new ZookeeperDomainOps();
129 }
130 }