All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.security.AuthorizationMatrixProperty Maven / Gradle / Ivy

package hudson.security;

import hudson.model.Item;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.JobPropertyDescriptor;
import hudson.model.Hudson;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

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 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;

/**
 * {@link JobProperty} to associate ACL for each project.
 */
public class AuthorizationMatrixProperty extends JobProperty> {

	public static final JobPropertyDescriptor DESCRIPTOR = new DescriptorImpl();

	private transient ACL acl = new AclImpl();

	private boolean useProjectSecurity;

	public boolean isUseProjectSecurity() {
		return useProjectSecurity;
	}

	public void setUseProjectSecurity(boolean useProjectSecurity) {
		this.useProjectSecurity = useProjectSecurity;
	}

	/**
	 * 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 Set sids = new HashSet();

	public Set getGroups() {
		return sids;
	}

	/**
	 * 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);
	}

	/**
	 * Adds to {@link #grantedPermissions}. Use of this method should be limited
	 * during construction, as this object itself is considered immutable once
	 * populated.
	 */
	protected 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);
	}

	@Override
	public JobPropertyDescriptor getDescriptor() {
		return DESCRIPTOR;
	}

	public static class DescriptorImpl extends JobPropertyDescriptor {

		@Override
		public JobProperty newInstance(StaplerRequest req,
				JSONObject formData) throws FormException {
			boolean useProjectSecurity = formData.has("useProjectSecurity");
			AuthorizationMatrixProperty amp = new AuthorizationMatrixProperty();
			amp.setUseProjectSecurity(useProjectSecurity);
			for (Map.Entry r : (Set>) formData
					.getJSONObject("data").entrySet()) {
				String sid = r.getKey();
				if (r.getValue() instanceof JSONObject) {
					for (Map.Entry e : (Set>) ((JSONObject) r
							.getValue()).entrySet()) {
						if (e.getValue()) {
							Permission p = Permission.fromId(e.getKey());
							amp.add(p, sid);
						}
					}
				}
			}
			return amp;
		}

		protected DescriptorImpl() {
			super(AuthorizationMatrixProperty.class);
		}

		@Override
		public boolean isApplicable(Class jobType) {
            // only applicable when ProjectMatrixAuthorizationStrategy is in charge
            return Hudson.getInstance().getAuthorizationStrategy() instanceof ProjectMatrixAuthorizationStrategy;
		}

		@Override
		public String getDisplayName() {
			return "Authorization Matrix";
		}

		public List getAllGroups() {
			return Collections.singletonList(PermissionGroup.get(Item.class));
		}

	}

	private final class AclImpl extends SidACL {
		protected Boolean hasPermission(Sid sid, Permission p) {
			String s = toString(sid);
			for (; p != null; p = p.impliedBy) {
				Set set = grantedPermissions.get(p);
				if (set != null && set.contains(s))
					return true;
			}
			return false;
		}

		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();
		}
	}

	private Object readResolve() {
		acl = new AclImpl();
		return this;
	}

	public ACL getACL() {
		return acl;
	}

	/**
	 * 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;
	}

	/**
	 * 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));
	}

	/**
	 * Persist {@link ProjectMatrixAuthorizationStrategy} as a list of IDs that
	 * represent {@link ProjectMatrixAuthorizationStrategy#grantedPermissions}.
	 */
	public static final class ConverterImpl implements Converter {
		public boolean canConvert(Class type) {
			return type == AuthorizationMatrixProperty.class;
		}

		public void marshal(Object source, HierarchicalStreamWriter writer,
				MarshallingContext context) {
			AuthorizationMatrixProperty amp = (AuthorizationMatrixProperty) source;

			for (Entry> e : amp.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) {
			AuthorizationMatrixProperty as = new AuthorizationMatrixProperty();

			while (reader.hasMoreChildren()) {
				reader.moveDown();
				String id = (String) context.convertAnother(as, String.class);
				as.add(id);
				reader.moveUp();
			}

			return as;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy