/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.impl;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.geoserver.security.AccessMode;
/**
* Represents a data access rule: identifies a workspace, a layer, an access mode, and the set of
* roles that are allowed to access it
* <p>Mind, two rules are considered equal if the address the same data, if you need full
* comparison, use {@link #equalsExact(DataAccessRule)}</p>
*/
@SuppressWarnings("serial")
public class DataAccessRule implements Comparable<DataAccessRule>, Serializable {
/**
* Any layer, or any workspace, or any role
*/
public static final String ANY = "*";
public static DataAccessRule READ_ALL = new DataAccessRule(ANY, ANY, AccessMode.READ);
public static DataAccessRule WRITE_ALL = new DataAccessRule(ANY, ANY, AccessMode.WRITE);
String root;
String layer;
AccessMode accessMode;
Set<String> roles;
boolean globalGroupRule;
/**
* Builds a new rule
*/
public DataAccessRule(String root, String layer, AccessMode accessMode, Set<String> roles) {
super();
this.root = root;
this.layer = layer;
this.globalGroupRule = (layer == null);
this.accessMode = accessMode;
if (roles == null)
this.roles = new HashSet<String>();
else
this.roles = new HashSet<String>(roles);
}
/**
* Builds a new rule
*/
public DataAccessRule(String root, String layer, AccessMode accessMode, String... roles) {
this(root, layer, accessMode, roles == null ? null : new HashSet<String>(Arrays.asList(roles)));
}
/**
* Copy constructor
*/
public DataAccessRule(DataAccessRule other) {
this.root = other.root;
this.layer = other.layer;
this.accessMode = other.accessMode;
this.globalGroupRule = other.globalGroupRule;
this.roles = new HashSet<String>(other.roles);
}
/**
* Builds the default rule: *.*.r=*
*/
public DataAccessRule() {
this(ANY, ANY, AccessMode.READ);
}
public String getRoot() {
return root;
}
public void setRoot(String root) {
this.root = root;
}
/**
* @deprecated Use getRoot(), the rule root can now be a workspace or a global layer group name
*/
public String getWorkspace() {
return root;
}
/**
* @deprecated Use setRoot(), the rule root can now be a workspace or a global layer group name
*/
public void setWorkspace(String workspace) {
this.root = workspace;
}
public String getLayer() {
return layer;
}
public void setLayer(String layer) {
this.layer = layer;
}
public AccessMode getAccessMode() {
return accessMode;
}
public void setAccessMode(AccessMode accessMode) {
this.accessMode = accessMode;
}
public Set<String> getRoles() {
return roles;
}
public boolean isGlobalGroupRule() {
return globalGroupRule;
}
public void setGlobalGroupRule(boolean globalGroupRule) {
this.globalGroupRule = globalGroupRule;
}
/**
* Returns the key for the current rule. No other rule should have the same
*/
public String getKey() {
if(globalGroupRule) {
return root + "." + accessMode.getAlias();
} else {
return root + "." + layer + "." + accessMode.getAlias();
}
}
/**
* Returns the list of roles as a comma separated string for this rule
*
*/
public String getValue() {
if(roles.isEmpty()) {
return DataAccessRule.ANY;
} else {
StringBuffer sb = new StringBuffer();
for (String role : roles) {
sb.append(role);
sb.append(",");
}
sb.setLength(sb.length() - 1);
return sb.toString();
}
}
/**
* Comparison implemented so that generic rules get first, specific one are compared by name,
* and if anything else is equal, read comes before write
*/
public int compareTo(DataAccessRule other) {
int compareRoot = compareCatalogItems(root, other.root);
if (compareRoot != 0)
return compareRoot;
int compareLayer = compareCatalogItems(layer, other.layer);
if (compareLayer != 0)
return compareLayer;
if (accessMode.equals(other.accessMode))
return 0;
else
return accessMode.equals(AccessMode.READ) ? -1 : 1;
}
/**
* Equality based on ws/layer/mode only
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DataAccessRule))
return false;
return 0 == compareTo((DataAccessRule) obj);
}
/**
* Full equality, roles included
*/
public boolean equalsExact(DataAccessRule obj) {
if(0 != compareTo(obj))
return false;
else
return roles.equals(obj.roles);
}
/**
* Hashcode based on wfs/layer/mode only
*/
@Override
public int hashCode() {
return new HashCodeBuilder().append(root).append(layer).append(accessMode.getAlias())
.toHashCode();
}
/**
* Generic string comparison that considers the use of {@link #ANY}
*/
public int compareCatalogItems(String item, String otherItem) {
if(item == null) {
return otherItem != null ? -1 : 0;
}
if (item.equals(otherItem))
return 0;
else if (ANY.equals(item))
return -1;
else if (ANY.equals(otherItem))
return 1;
else
return item.compareTo(otherItem);
}
@Override
public String toString() {
return getKey() + "=" + getValue();
}
}