package hudson.plugins.collabnet.auth; import com.collabnet.ce.webservices.CTFList; import com.collabnet.ce.webservices.CTFRole; import hudson.model.AbstractProject; import hudson.model.Hudson; import hudson.model.Item; import hudson.plugins.collabnet.util.CommonUtil; import hudson.plugins.promoted_builds.Promotion; import hudson.scm.SCM; import hudson.security.ACL; import hudson.security.Permission; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.logging.Logger; import org.acegisecurity.Authentication; /** * An ACL that uses project roles to determine what Hudson permissions to give. */ public class CNProjectACL extends ACL { private String projectId = null; private static Logger log = Logger.getLogger("CNProjectACL"); /** * Constructor. * @param projectId the id of the TeamForge project associated with this ACL */ public CNProjectACL(String projectId) { this.projectId = projectId; } public boolean hasPermission(Authentication a, Permission permission) { if (!(a instanceof CNAuthentication)) { log.severe("Improper Authentication type used with " + "CNAuthorizationStrategy! CNAuthorization " + "strategy cannot be used without " + "CNAuthentication. Please re-configure your " + "Hudson instance."); return false; } if (CommonUtil.isEmpty(projectId)) { log.severe("hasPerission: project id could not be found for project: " + this.projectId + "."); return false; } CNAuthentication cnAuth = (CNAuthentication) a; String username = cnAuth.getPrincipal(); Set<Permission> userPerms = cnAuth.getUserProjectPermSet(username, projectId); for(; permission!=null; permission=permission.impliedBy) { if (userPerms.contains(permission)) { return true; } } return false; } public static class CollabNetRoles { private static Collection<CollabNetRole> roles = Collections.emptyList(); public static final CollabNetRole HUDSON_READ_ROLE = new CollabNetRole("Hudson Read", "Allows users " + "read-access to Hudson jobs.", Hudson.READ, Item.READ); public static final CollabNetRole HUDSON_BUILD_ROLE = new CollabNetRole("Hudson Build/Cancel", "Allow " + "users to start a new build, or " + "to cancel a build.", AbstractProject.BUILD, AbstractProject.ABORT, AbstractProject.WORKSPACE, Item.BUILD, SCM.TAG); public static final CollabNetRole HUDSON_CONFIGURE_ROLE = new CollabNetRole("Hudson Configure", "Allow users" + " to configure a build.", Item.CONFIGURE); public static final CollabNetRole HUDSON_DELETE_ROLE = new CollabNetRole("Hudson Delete", "Allow users to " + "delete builds.", Item.DELETE); /** * Get the applicable hudson roles matching a set of user role names * * @param userRoleSet names of roles to match * @return a collection of hudson roles with names that exist in user role set */ public static Collection<CollabNetRole> getMatchingRoles(CTFList<CTFRole> userRoleSet) { Collection<CollabNetRole> matchRoles = new ArrayList<CollabNetRole>(); for (CollabNetRole role : getAllRoles()) { if (userRoleSet.getTitles().contains(role.getName())) { matchRoles.add(role); } } return matchRoles; } /** * @return all roles. Lazily initialized. */ public static Collection<CollabNetRole> getAllRoles() { if (CollabNetRoles.roles.isEmpty()) { roles = new ArrayList<CollabNetRole>(); roles.add(HUDSON_READ_ROLE); roles.add(HUDSON_BUILD_ROLE); roles.add(HUDSON_CONFIGURE_ROLE); roles.add(HUDSON_DELETE_ROLE); // add build promotion as a permission, if the build promotion // plugin is present. if (Hudson.getInstance().getPlugin("promoted-builds") != null) { // check if we have the PROMOTE permission Field promote = null; Field[] promotionFields = Promotion.class.getFields(); for (Field field: promotionFields) { if (field.getName().equals("PROMOTE")) { promote = field; break; } } Permission promotePermission = null; if (promote != null) { try { promotePermission = (Permission) promote.get(null); } catch (IllegalAccessException iae) {} } roles.add(new CollabNetRole("Hudson Promote", "Allow users to " + "promote builds.", promotePermission!=null ? new Permission[]{promotePermission} : new Permission[0] )); } } return CollabNetRoles.roles; } /** * @return an ordered List of Role names. */ public static List<String> getNames() { List<String> names = new ArrayList<String>(); for (CollabNetRole role: CollabNetRoles.getAllRoles()) { names.add(role.getName()); } return names; } /** * Given a permission, return the CollabNet role which would grant * that permission (if any). Returns the first permission granting * role found (but we expect only one). * * @param permission * @return the CollabNet role which would grant that permission, or * null if none would. */ public static CollabNetRole getGrantingRole(Permission permission) { Collection<Permission> implyingPermissions = CollabNetRoles.expandPermissions(permission); for (CollabNetRole role: CollabNetRoles.getAllRoles()) { for (Permission p: implyingPermissions) { if (role.hasPermission(p)) { return role; } } } return null; } /** * Given a permission, expand it into a collection, containing every * permission implied by this permission (including the starting * permission). * * @param permission * @return the collection of implied permissions. */ private static Collection<Permission> expandPermissions(Permission permission) { Collection<Permission> permissions = new ArrayList<Permission>(); for(Permission p = permission; p != null; p = permission.impliedBy) { permissions.add(p); } return permissions; } } }