
com.spotify.helios.servicescommon.RuleBasedZooKeeperAclProvider Maven / Gradle / Ivy
/*
* Copyright (c) 2016 Spotify AB.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.spotify.helios.servicescommon;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.curator.framework.api.ACLProvider;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* A ZooKeeper ACLProvider that uses regular expression-based rules to determine what ACLs govern
* created nodes.
*
* The permissions for all rules that match a path apply. For example if there
* are two rules:
*
* - "/foo.*", DELETE, usr1
* - "/foo/bar", CREATE, user1
*
* Then ACLs will be set so that user1 can create and delete nodes on the /foo/bar node, but he can
* not delete nodes under the /foo node.
*/
public class RuleBasedZooKeeperAclProvider implements ACLProvider {
private final ImmutableList defaultAcl;
private final ImmutableList rules;
public static Builder builder() {
return new Builder();
}
private RuleBasedZooKeeperAclProvider(final ImmutableList rules,
final ImmutableList defaultAcl) {
this.rules = rules;
this.defaultAcl = defaultAcl;
}
@Override
public List getDefaultAcl() {
return defaultAcl;
}
@Override
public List getAclForPath(final String path) {
// id -> permissions
final Map matching = Maps.newHashMap();
for (final Rule rule : rules) {
if (rule.matches(path)) {
final int existingPerms = matching.containsKey(rule.id) ? matching.get(rule.id) : 0;
matching.put(rule.id, rule.perms | existingPerms);
}
}
if (matching.isEmpty()) {
return null;
}
final List acls = Lists.newArrayList();
for (final Map.Entry e : matching.entrySet()) {
acls.add(new ACL(e.getValue(), e.getKey()));
}
return acls;
}
private static class Rule {
private final Pattern pattern;
private final Id id;
private final int perms;
Rule(final String regex, final int perms, final Id id) {
this.pattern = Pattern.compile(regex);
this.perms = perms;
this.id = id;
}
boolean matches(final String path) {
return pattern.matcher(path).matches();
}
}
public static class Builder {
private final List rules = Lists.newArrayList();
private ImmutableList defaultAcl = ImmutableList.copyOf(ZooDefs.Ids.READ_ACL_UNSAFE);
Builder defaultAcl(final ACL... acls) {
return defaultAcl(Arrays.asList(acls));
}
Builder defaultAcl(final List defaultAcl) {
this.defaultAcl = ImmutableList.copyOf(defaultAcl);
return this;
}
Builder rule(final String pathRegex, final int permissions, final Id id) {
rules.add(new Rule(pathRegex, permissions, id));
return this;
}
RuleBasedZooKeeperAclProvider build() {
return new RuleBasedZooKeeperAclProvider(ImmutableList.copyOf(rules), defaultAcl);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy