package org.pentaho.platform.engine.security;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.Authentication;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.vote.AccessDecisionVoter;
/**
* Similar to {@link org.springframework.security.vote.RoleVoter} except that it does not use a role prefix; instead it
* uses a config attribute prefix which serves a similar, but not the same, purpose. In
* {@code RoleVoter}, the role prefix serves as an indicator to the {@code RoleVoter} to participate in the voting.
* {@code RoleVoter} assumes that the config attributes are role names. In this voter implementation, the
* {@code processConfigAttributePrefix} is stripped from the config attribute before comparison to the roles granted to
* the user.
*
* <p>
* For example, assume that a user has the role {@code Authenticated}. Also assume that the config attribute for a
* method invocation is {@code VOTE_ROLE_FILE_Authenticated}. Finally assume that this voter instance is configured with
* a {@code processConfigAttributePrefix} of {@code VOTE_ROLE_FILE_}. This voter implementation will strip the
* {@code processConfigAttributePrefix} from the config attribute and compare to the roles granted to the user. In this
* example, access will be granted.
* </p>
*
* @author mlowery
*/
public class PentahoSubstringRoleVoter implements AccessDecisionVoter {
// ~ Static fields/initializers ======================================================================================
private static final Log logger = LogFactory.getLog(PentahoSubstringRoleVoter.class);
// ~ Instance fields =================================================================================================
private String processConfigAttributePrefix;
// ~ Constructors ====================================================================================================
public PentahoSubstringRoleVoter(final String processConfigAttributePrefix) {
super();
this.processConfigAttributePrefix = processConfigAttributePrefix;
}
//~ Methods =========================================================================================================
public boolean supports(final ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(processConfigAttributePrefix)) {
return true;
} else {
return false;
}
}
/**
* This implementation supports any type of class, because it does not query
* the presented secure object.
*
* @param clazz the secure object
*
* @return always <code>true</code>
*/
public boolean supports(final Class clazz) {
return true;
}
public int vote(final Authentication authentication, final Object object, final ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes().iterator();
GrantedAuthority[] authorities = extractAuthorities(authentication);
while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();
if (this.supports(attribute)) {
result = ACCESS_DENIED;
// Attempt to find a matching granted authority
for (int i = 0; i < authorities.length; i++) {
if (attribute.getAttribute().substring(processConfigAttributePrefix.length()).equals(
authorities[i].getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
private GrantedAuthority[] extractAuthorities(Authentication authentication) {
return authentication.getAuthorities();
}
}