Java tutorial
/******************************************************************************* * Copyright 2008(c) The OBiBa Consortium. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.obiba.opal.core.service.security; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.annotation.PostConstruct; import javax.validation.constraints.NotNull; import org.obiba.opal.core.domain.HasUniqueProperties; import org.obiba.opal.core.domain.security.SubjectAcl; import org.obiba.opal.core.service.OrientDbService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.orientechnologies.orient.core.metadata.schema.OType; import static com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE; import static org.obiba.opal.core.domain.security.SubjectAcl.Subject; import static org.obiba.opal.core.domain.security.SubjectAcl.SubjectType; @Component public class DefaultSubjectAclService implements SubjectAclService { private static final Logger log = LoggerFactory.getLogger(DefaultSubjectAclService.class); private final Set<SubjectAclChangeCallback> callbacks = Sets.newHashSet(); @Autowired private OrientDbService orientDbService; @Override @PostConstruct public void start() { orientDbService.createUniqueIndex(SubjectAcl.class); orientDbService.createIndex(SubjectAcl.class, INDEX_TYPE.NOTUNIQUE, OType.STRING, "domain"); orientDbService.createIndex(SubjectAcl.class, INDEX_TYPE.NOTUNIQUE, OType.STRING, "node"); orientDbService.createIndex(SubjectAcl.class, INDEX_TYPE.NOTUNIQUE, OType.STRING, "principal"); orientDbService.createIndex(SubjectAcl.class, INDEX_TYPE.NOTUNIQUE, OType.STRING, "type"); } @Override public void stop() { } @Override public void addListener(SubjectAclChangeCallback callback) { if (callback != null) callbacks.add(callback); } @Override public void deleteNodePermissions(String node) { Iterable<SubjectAcl> subjectAcls = orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where node = ? or node like ?", node, node + "/%"); Set<Subject> subjects = Sets.newTreeSet(); for (SubjectAcl acl : subjectAcls) { subjects.add(acl.getSubject()); delete(acl); } notifyListeners(subjects); } private void delete(SubjectAcl acl) { orientDbService.delete(acl); } @Override public void deleteNodePermissions(String domain, String node) { Set<Subject> subjects = Sets.newTreeSet(); for (SubjectAcl acl : find(domain, node)) { subjects.add(acl.getSubject()); delete(acl); } notifyListeners(subjects); } @Override public void deleteNodeHierarchyPermissions(String domain, String node) { deleteNodePermissions(domain, node); Set<Subject> subjects = Sets.newTreeSet(); for (SubjectAcl acl : Iterables.concat(find(domain, node), findLike(domain, node + "/"))) { subjects.add(acl.getSubject()); delete(acl); } notifyListeners(subjects); } @Override public void deleteSubjectPermissions(Subject subject) { for (SubjectAcl acl : find(subject)) { delete(acl); } notifyListeners(subject); } @Override public void deleteSubjectPermissions(String domain, String node, Subject subject) { for (SubjectAcl acl : find(domain, node, subject)) { delete(acl); } notifyListeners(subject); } @Override public void deleteSubjectPermissions(String domain, String node, Subject subject, String permission) { SubjectAcl acl = find(domain, node, subject, permission); if (acl != null) { delete(acl); notifyListeners(subject); } } @Override public void addSubjectPermissions(String domain, String node, Subject subject, Iterable<String> permissions) { for (String permission : permissions) { addSubjectPermission(domain, node, subject, permission); } } @Override public void addSubjectPermission(String domain, String node, @NotNull Subject subject, @NotNull String permission) { Assert.notNull(subject, "subject cannot be null"); Assert.notNull(permission, "permission cannot be null"); HasUniqueProperties acl = new SubjectAcl(domain, node, subject, permission); orientDbService.save(acl, acl); notifyListeners(subject); } @Override public Permissions getSubjectNodePermissions(@NotNull final String domain, @NotNull final String node, @NotNull final Subject subject) { Assert.notNull(node, "node cannot be null"); Assert.notNull(subject, "subject cannot be null"); return new Permissions() { @Override public String getDomain() { return domain; } @Override public String getNode() { return node; } @Override public Subject getSubject() { return subject; } @Override public Iterable<String> getPermissions() { return Iterables.transform(find(domain, node, subject), new Function<SubjectAcl, String>() { @Override public String apply(SubjectAcl from) { return from.getPermission(); } }); } }; } @Override public Iterable<Permissions> getSubjectNodeHierarchyPermissions(@NotNull String domain, @NotNull String node, @NotNull Subject subject) { Map<String, Permissions> entries = Maps.newHashMap(); for (SubjectAcl acl : Iterables.concat(find(domain, node, subject), findLike(domain, node + "/", subject))) { String key = acl.getSubject() + ":" + acl.getNode(); PermissionsImpl perms = (PermissionsImpl) entries.get(key); if (perms == null) { perms = new PermissionsImpl(domain, acl.getNode(), acl.getSubject()); entries.put(key, perms); } perms.addPermission(acl.getPermission()); } return entries.values(); } private Iterable<SubjectAcl> find(Subject subject) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where principal = ? and type = ?", subject.getPrincipal(), subject.getType()); } private Iterable<SubjectAcl> find(String domain, String node, SubjectType type) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and node = ? and type = ?", domain, node, type); } private Iterable<SubjectAcl> findLike(String domain, String node, SubjectType type) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and node like ? and type = ?", domain, node + "%", type); } private Iterable<SubjectAcl> find(String domain, SubjectType type) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and type = ?", domain, type); } private Iterable<SubjectAcl> find(@NotNull String domain, @NotNull String node, @NotNull Subject subject) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and node = ? and principal = ? and type = ?", domain, node, subject.getPrincipal(), subject.getType()); } private Iterable<SubjectAcl> findLike(@NotNull String domain, @NotNull String node, @NotNull Subject subject) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and node like ? and principal = ? and type = ?", domain, node + "%", subject.getPrincipal(), subject.getType()); } private Iterable<SubjectAcl> find(@NotNull String domain, @NotNull String node) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and node = ?", domain, node); } private Iterable<SubjectAcl> findLike(@NotNull String domain, @NotNull String node) { return orientDbService.list(SubjectAcl.class, "select from " + SubjectAcl.class.getSimpleName() + " where domain = ? and node like ?", domain, node + "%"); } private SubjectAcl find(String domain, String node, Subject subject, String permission) { return orientDbService.findUnique(new SubjectAcl(domain, node, subject, permission)); } @Override public Iterable<Permissions> getSubjectPermissions(final Subject subject) { return Iterables.transform(find(subject), new Function<SubjectAcl, Permissions>() { @Override public Permissions apply(final SubjectAcl from) { return new Permissions() { @Override public Subject getSubject() { return subject; } @Override public String getDomain() { return from.getDomain(); } @Override public String getNode() { return from.getNode(); } @Override public Iterable<String> getPermissions() { return Iterables.transform(find(from.getDomain(), getNode(), from.getSubject()), new Function<SubjectAcl, String>() { @Override public String apply(SubjectAcl from) { return from.getPermission(); } }); } }; } }); } @Override public Iterable<Permissions> getNodePermissions(String domain, String node, SubjectType type) { Map<Subject, Permissions> entries = Maps.newHashMap(); for (SubjectAcl acl : type == null ? find(domain, node) : find(domain, node, type)) { PermissionsImpl perms = (PermissionsImpl) entries.get(acl.getSubject()); if (perms == null) { perms = new PermissionsImpl(domain, node, acl.getSubject()); entries.put(acl.getSubject(), perms); } perms.addPermission(acl.getPermission()); } return entries.values(); } @Override public Iterable<Permissions> getNodeHierarchyPermissions(String domain, String node, SubjectType type) { Map<String, Permissions> entries = Maps.newHashMap(); Iterable<SubjectAcl> acls = type == null ? Iterables.concat(find(domain, node), findLike(domain, node + "/")) : Iterables.concat(find(domain, node, type), findLike(domain, node + "/", type)); for (SubjectAcl acl : acls) { String key = acl.getSubject() + ":" + acl.getNode(); PermissionsImpl perms = (PermissionsImpl) entries.get(key); if (perms == null) { perms = new PermissionsImpl(domain, acl.getNode(), acl.getSubject()); entries.put(key, perms); } perms.addPermission(acl.getPermission()); } return entries.values(); } @Override public Iterable<Subject> getSubjects(String domain, SubjectType type) { return FluentIterable.from(find(domain, type)).transform(new Function<SubjectAcl, Subject>() { @Override public Subject apply(SubjectAcl from) { return from.getSubject(); } }).filter(new Predicate<Subject>() { final Collection<Subject> set = new TreeSet<>(); @Override public boolean apply(Subject input) { // add returns false if the set already contains the element return set.add(input); } }); } /** * @param subjects */ private void notifyListeners(Iterable<Subject> subjects) { for (Subject s : subjects) notifyListeners(s); } /** * @param subject */ private void notifyListeners(Subject subject) { for (SubjectAclChangeCallback c : callbacks) { try { c.onSubjectAclChanged(subject); } catch (Exception e) { log.warn("Ignoring exception during ACL callback", e); } } } private static class PermissionsImpl implements Permissions { private final String domain; private final String node; private final Subject subject; private final List<String> permissions = Lists.newArrayList(); private PermissionsImpl(String domain, String node, Subject subject) { this.domain = domain; this.node = node; this.subject = subject; } @Override public String getDomain() { return domain; } @Override public String getNode() { return node; } @Override public Subject getSubject() { return subject; } @Override public Iterable<String> getPermissions() { return permissions; } public void addPermission(String permission) { if (!permissions.contains(permission)) { permissions.add(permission); } } } }