
hudson.security.GlobalMatrixAuthorizationStrategy Maven / Gradle / Ivy
package hudson.security;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import hudson.model.Descriptor;
import net.sf.json.JSONObject;
import org.acegisecurity.Authentication;
import org.acegisecurity.acls.sid.GrantedAuthoritySid;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.kohsuke.stapler.StaplerRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Role-based authorization via a matrix.
*
* @author Kohsuke Kawaguchi
*/
// TODO: think about the concurrency commitment of this class
public class GlobalMatrixAuthorizationStrategy extends AuthorizationStrategy {
private transient ACL acl = new AclImpl();
/**
* List up all permissions that are granted.
*
* Strings are either the granted authority or the principal,
* which is not distinguished.
*/
private final Map> grantedPermissions = new HashMap>();
private final Set sids = new HashSet();
/**
* Adds to {@link #grantedPermissions}.
* Use of this method should be limited during construction,
* as this object itself is considered immutable once populated.
*/
public void add(Permission p, String sid) {
Set set = grantedPermissions.get(p);
if(set==null)
grantedPermissions.put(p,set = new HashSet());
set.add(sid);
sids.add(sid);
}
/**
* Works like {@link #add(Permission, String)} but takes both parameters
* from a single string of the form PERMISSIONID:sid
*/
private void add(String shortForm) {
int idx = shortForm.indexOf(':');
add(Permission.fromId(shortForm.substring(0,idx)),shortForm.substring(idx+1));
}
@Override
public ACL getRootACL() {
return acl;
}
public Set getGroups() {
return sids;
}
private Object readResolve() {
acl = new AclImpl();
return this;
}
/**
* Checks if the given SID has the given permission.
*/
public boolean hasPermission(String sid, Permission p) {
for(; p!=null; p=p.impliedBy) {
Set set = grantedPermissions.get(p);
if(set!=null && set.contains(sid))
return true;
}
return false;
}
/**
* Returns all SIDs configured in this matrix, minus "anonymous"
*
* @return
* Always non-null.
*/
public List getAllSIDs() {
Set r = new HashSet();
for (Set set : grantedPermissions.values())
r.addAll(set);
r.remove("anonymous");
String[] data = r.toArray(new String[r.size()]);
Arrays.sort(data);
return Arrays.asList(data);
}
private final class AclImpl extends SidACL {
protected Boolean hasPermission(Sid p, Permission permission) {
if(GlobalMatrixAuthorizationStrategy.this.hasPermission(toString(p),permission))
return true;
return null;
}
protected Boolean _hasPermission(Authentication a, Permission permission) {
Boolean b = super._hasPermission(a,permission);
// permissions granted to anonymous users are granted to everyone
if(b==null) b=hasPermission(ANONYMOUS,permission);
return b;
}
private String toString(Sid p) {
if (p instanceof GrantedAuthoritySid)
return ((GrantedAuthoritySid) p).getGrantedAuthority();
if (p instanceof PrincipalSid)
return ((PrincipalSid) p).getPrincipal();
// hmm...
return p.toString();
}
}
public Descriptor getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor DESCRIPTOR = new DescriptorImpl(GlobalMatrixAuthorizationStrategy.class);
/**
* Persist {@link GlobalMatrixAuthorizationStrategy} as a list of IDs that
* represent {@link GlobalMatrixAuthorizationStrategy#grantedPermissions}.
*/
public static final class ConverterImpl implements Converter {
public boolean canConvert(Class type) {
return type== GlobalMatrixAuthorizationStrategy.class;
}
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
GlobalMatrixAuthorizationStrategy strategy = (GlobalMatrixAuthorizationStrategy)source;
for (Entry> e : strategy.grantedPermissions.entrySet()) {
String p = e.getKey().getId();
for (String sid : e.getValue()) {
writer.startNode("permission");
context.convertAnother(p+':'+sid);
writer.endNode();
}
}
}
public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingContext context) {
GlobalMatrixAuthorizationStrategy as = new GlobalMatrixAuthorizationStrategy();
while (reader.hasMoreChildren()) {
reader.moveDown();
String id = (String)context.convertAnother(as,String.class);
as.add(id);
reader.moveUp();
}
return as;
}
}
static {
LIST.add(DESCRIPTOR);
}
public static class DescriptorImpl extends Descriptor {
protected DescriptorImpl(Class extends GlobalMatrixAuthorizationStrategy> clazz) {
super(clazz);
}
public String getDisplayName() {
return Messages.GlobalMatrixAuthorizationStrategy_DisplayName();
}
public AuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException {
GlobalMatrixAuthorizationStrategy gmas = create();
for(Map.Entry r : (Set>)formData.getJSONObject("data").entrySet()) {
String sid = r.getKey();
for(Map.Entry e : (Set>)r.getValue().entrySet()) {
if(e.getValue()) {
Permission p = Permission.fromId(e.getKey());
gmas.add(p,sid);
}
}
}
return gmas;
}
protected GlobalMatrixAuthorizationStrategy create() {
return new GlobalMatrixAuthorizationStrategy();
}
public String getHelpFile() {
return "/help/security/global-matrix.html";
}
public List getAllGroups() {
List groups = new ArrayList(PermissionGroup.getAll());
groups.remove(PermissionGroup.get(Permission.class));
return groups;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy