
com.michelin.cio.hudson.plugins.rolestrategy.RoleMap Maven / Gradle / Ivy
The newest version!
/*
* The MIT License
*
* Copyright (c) 2010, Manufacture Française des Pneumatiques Michelin, Thomas Maurel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.michelin.cio.hudson.plugins.rolestrategy;
import hudson.model.User;
import hudson.security.Permission;
import hudson.security.SidACL;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import org.acegisecurity.acls.sid.Sid;
/**
* Class holding a map for each kind of {@link AccessControlled} object, associating
* each {@link Role} with the concerned {@link User}s/groups.
* @author Thomas Maurel
*/
public class RoleMap {
/** ACL for the current {@link AccessControlled} object. */
private transient SidACL acl = new AclImpl();
/** Map associating each {@link Role} with the concerned {@link User}s/groups. */
private final SortedMap > grantedRoles;
RoleMap() {
this.grantedRoles = new TreeMap>();
}
RoleMap(SortedMap> grantedRoles) {
this.grantedRoles = grantedRoles;
}
/**
* Check if the given sid has the provided {@link Permission}.
* @return True if the sid's granted permission
*/
private boolean hasPermission(String sid, Permission p) {
for(Role role : getRolesHavingPermission(p)) {
if(this.grantedRoles.get(role).contains(sid)) {
return true;
}
}
return false;
}
/**
* Check if the {@link RoleMap} contains the given {@link Role}.
* @return True if the {@link RoleMap} contains the given role
*/
public boolean hasRole(Role role) {
return this.grantedRoles.containsKey(role);
}
/**
* Get the ACL for the current {@link RoleMap}.
* @return ACL for the current {@link RoleMap}
*/
public SidACL getACL() {
return acl;
}
/**
* Add the given role to this {@link RoleMap}.
* @param role The {@link Role} to add
*/
public void addRole(Role role) {
if(this.getRole(role.getName()) == null) {
this.grantedRoles.put(role, new HashSet());
}
}
/**
* Assign the sid to the given {@link Role}.
* @param role The {@link Role} to assign the sid to
* @param sid The sid to assign
*/
public void assignRole(Role role, String sid) {
if(this.hasRole(role)) {
this.grantedRoles.get(role).add(sid);
}
}
/**
* Clear all the sids associated to the given {@link Role}.
* @param role The {@link Role} for which you want to clear the sids
*/
public void clearSidsForRole(Role role) {
if(this.hasRole(role)) {
this.grantedRoles.get(role).clear();
}
}
/**
* Clear all the sids for each {@link Role} of the {@link RoleMap}.
*/
public void clearSids() {
for(Map.Entry> entry : this.grantedRoles.entrySet()) {
Role role = entry.getKey();
this.clearSidsForRole(role);
}
}
/**
* Get the {@link Role} object named after the given param.
* @param name The name of the {@link Role}
* @return The {@link Role} named after the given param
*/
public Role getRole(String name) {
for(Role role : this.getRoles()) {
if(role.getName().equals(name)) {
return role;
}
}
return null;
}
/**
* Get an unmodifiable sorted map containing {@link Role}s and their assigned sids.
* @return An unmodifiable sorted map containing the {@link Role}s and their associated sids
*/
public SortedMap> getGrantedRoles() {
return Collections.unmodifiableSortedMap(this.grantedRoles);
}
/**
* Get an unmodifiable set containing all the {@link Role}s of this {@link RoleMap}.
* @return An unmodifiable set containing the {@link Role}s
*/
public Set getRoles() {
return Collections.unmodifiableSet(this.grantedRoles.keySet());
}
/**
* Get all the sids referenced in this {@link RoleMap}, minus the {@code Anonymous} sid.
* @return A sorted set containing all the sids, minus the {@code Anonymous} sid
*/
public SortedSet getSids() {
return this.getSids(false);
}
/**
* Get all the sids referenced in this {@link RoleMap}.
* @param includeAnonymous True if you want the {@code Anonymous} sid to be included in the set
* @return A sorted set containing all the sids
*/
public SortedSet getSids(Boolean includeAnonymous) {
TreeSet sids = new TreeSet();
for(Map.Entry entry : this.grantedRoles.entrySet()) {
sids.addAll((Set)entry.getValue());
}
// Remove the anonymous sid if asked to
if(!includeAnonymous) {
sids.remove("anonymous");
}
return Collections.unmodifiableSortedSet(sids);
}
/**
* Get all the sids assigned to the {@link Role} named after the {@code roleName} param.
* @param roleName The name of the role
* @return A sorted set containing all the sids
*/
public Set getSidsForRole(String roleName) {
Role role = this.getRole(roleName);
if(role != null) {
return Collections.unmodifiableSet(this.grantedRoles.get(role));
}
return null;
}
/**
* Create a sub-map of the current {@link RoleMap} containing only the
* {@link Role}s matching the given pattern.
* @param namePattern The pattern to match
* @return A {@link RoleMap} containing only {@link Role}s matching the given name
*/
public RoleMap newMatchingRoleMap(String namePattern) {
Set roles = getMatchingRoles(namePattern);
SortedMap> roleMap = new TreeMap>();
for(Role role : roles) {
roleMap.put(role, this.grantedRoles.get(role));
}
return new RoleMap(roleMap);
}
/**
* Get all the roles holding the given permission.
* @param permission The permission you want to check
* @return A Set of Roles holding the given permission
*/
private Set getRolesHavingPermission(final Permission permission) {
final Set roles = new HashSet();
final Set permissions = new HashSet();
Permission p = permission;
// Get the implying permissions
for(; p!=null; p=p.impliedBy) {
permissions.add(p);
}
// Walk through the roles, and only add the roles having the given permission,
// or a permission implying the given permission
new RoleWalker() {
public void perform(Role current) {
if(current.hasAnyPermission(permissions)) {
roles.add(current);
}
}
};
return roles;
}
/**
* Get all the roles whose pattern match the given pattern.
* @param namePattern The string to match
* @return A Set of Roles matching the given name
*/
private Set getMatchingRoles(final String namePattern) {
final Set roles = new HashSet();
// Walk through the roles and only add the Roles whose pattern matches the given string
new RoleWalker() {
public void perform(Role current) {
Matcher m = current.getPattern().matcher(namePattern);
if(m.matches()) {
roles.add(current);
}
}
};
return roles;
}
/**
* The Acl class that will delegate the permission check to the {@link RoleMap} object.
*/
private final class AclImpl extends SidACL {
/**
* Checks if the sid has the given permission.
* Actually only delegate the check to the {@link RoleMap} instance.
* @param p The sid to check
* @param permission The permission to check
* @return True if the sid has the given permission
*/
protected Boolean hasPermission(Sid p, Permission permission) {
if(RoleMap.this.hasPermission(toString(p),permission)) {
return true;
}
return null;
}
}
/**
* A class to walk through all the {@link RoleMap}'s roles and perform an
* action on each one.
*/
private abstract class RoleWalker {
RoleWalker() {
walk();
}
/**
* Walk through the roles.
*/
public void walk() {
Set roles = RoleMap.this.getRoles();
Iterator iter = roles.iterator();
while (iter.hasNext()) {
Role current = (Role) iter.next();
perform(current);
}
}
/**
* The method to implement which will be called on each {@link Role}.
*/
abstract public void perform(Role current);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy