/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package org.fcrepo.server.security; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.fcrepo.common.policy.XacmlName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.jboss.security.xacml.sunxacml.EvaluationCtx; import org.jboss.security.xacml.sunxacml.attr.AttributeValue; import org.jboss.security.xacml.sunxacml.attr.BagAttribute; import org.jboss.security.xacml.sunxacml.attr.DateAttribute; import org.jboss.security.xacml.sunxacml.attr.DateTimeAttribute; import org.jboss.security.xacml.sunxacml.attr.IntegerAttribute; import org.jboss.security.xacml.sunxacml.attr.StringAttribute; import org.jboss.security.xacml.sunxacml.attr.TimeAttribute; import org.jboss.security.xacml.sunxacml.cond.EvaluationResult; import org.jboss.security.xacml.sunxacml.ctx.Status; /** * @author Bill Niebel */ public abstract class AttributeFinderModule extends org.jboss.security.xacml.sunxacml.finder.AttributeFinderModule { private static final Logger logger = LoggerFactory.getLogger(AttributeFinderModule.class); protected static final String[] EMPTY_STRING_ARRAY = new String[0]; protected static final Map<URI, EvaluationResult> EMPTY_RESULTS = new HashMap<URI, EvaluationResult>(3); private static EvaluationResult getEmptyResult(URI attributeType) { EvaluationResult empty = EMPTY_RESULTS.get(attributeType); if (empty == null) { empty = new EvaluationResult(BagAttribute .createEmptyBag(attributeType)); EMPTY_RESULTS.put(attributeType, empty); } return empty; } protected AttributeFinderModule() { } private Boolean instantiatedOk = null; private String iAmCache = null; public final void setInstantiatedOk(boolean value) { logger.debug("setInstantiatedOk() {}", value); if (instantiatedOk == null) { instantiatedOk = Boolean.valueOf(value); } } @Override public boolean isDesignatorSupported() { logger.debug("isDesignatorSupported() will return {} {}", iAm(), (instantiatedOk == Boolean.TRUE)); return instantiatedOk == Boolean.TRUE; } private final boolean parmsOk(URI attributeType, URI attributeId, int designatorType) { logger.debug("in parmsOk {}", iAm()); if (!getSupportedDesignatorTypes() .contains(Integer.valueOf(designatorType))) { logger.debug("AttributeFinder:parmsOk{} exit on target not supported [{}]", iAm(), designatorType); return false; } if (attributeType == null) { logger.debug("AttributeFinder:parmsOk{} exit on null attributeType", iAm()); return false; } if (attributeId == null) { logger.debug("AttributeFinder:parmsOk{} exit on null attributeId", iAm()); return false; } logger.debug("AttributeFinder:parmsOk{} looking for {}", iAm(), attributeId); showRegisteredAttributes(); if (hasAttribute(attributeId)) { if (!getAttributeType(attributeId).equals(attributeType)) { logger.debug("AttributeFinder:parmsOk{} exit on attributeType incorrect for attributeId", iAm()); return false; } } else { if (!STRING_ATTRIBUTE_TYPE_URI.equals(attributeType)) { logger.debug("AttributeFinder:parmsOk{} exit on attributeType incorrect for attributeId", iAm()); return false; } } logger.debug("exiting parmsOk normally {}", iAm()); return true; } protected String iAm() { if (iAmCache == null) { iAmCache = this.getClass().getName(); } return iAmCache; } protected final Object getAttributeFromEvaluationResult(EvaluationResult attribute) { if (attribute.indeterminate()) { logger.debug("AttributeFinder:getAttributeFromEvaluationCtx{} exit on couldn't get resource attribute from xacml request indeterminate", iAm()); return null; } if (attribute.getStatus() != null && !Status.STATUS_OK.equals(attribute.getStatus())) { logger.debug("AttributeFinder:getAttributeFromEvaluationCtx{} exit on couldn't get resource attribute from xacml request bad status", iAm()); return null; } // (resourceAttribute.getStatus() == null) == everything is ok AttributeValue attributeValue = attribute.getAttributeValue(); if (!(attributeValue instanceof BagAttribute)) { logger.debug("AttributeFinder:getAttributeFromEvaluationCtx{} exit on couldn't get resource attribute from xacml request no bag", iAm()); return null; } BagAttribute bag = (BagAttribute) attributeValue; if (1 != bag.size()) { logger.debug("AttributeFinder:getAttributeFromEvaluationCtx{} exit on couldn't get resource attribute from xacml request wrong bag n={}", iAm(), bag.size()); return null; } Iterator<?> it = bag.iterator(); Object element = it.next(); if (element == null) { if (logger.isDebugEnabled()) { logger.debug("AttributeFinder:getAttributeFromEvaluationCtx{} exit on couldn't get resource attribute from xacml request null returned", iAm()); } return null; } if (it.hasNext()) { if (logger.isDebugEnabled()) { logger.debug("AttributeFinder:getAttributeFromEvaluationCtx{} exit on couldn't get resource attribute from xacml request too many returned", iAm()); logger.debug(element.toString()); while (it.hasNext()) { logger.debug(it.next().toString()); } } return null; } logger.debug("AttributeFinder:getAttributeFromEvaluationCtx {} returning {}", iAm(), element.toString()); return element; } protected final HashSet<URI> attributesDenied = new HashSet<URI>(); private final HashSet<URI> attributeIdUris = new HashSet<URI>(); private final Hashtable<URI, URI> attributeTypes = new Hashtable<URI, URI>(); @Deprecated protected final void registerAttribute(String id, String type) throws URISyntaxException { logger.debug("registering attribute {} {}", iAm(), id); URI idUri = new URI(id); URI typeUri = new URI(type); attributeIdUris.add(idUri); attributeTypes.put(idUri, typeUri); } protected final void registerAttribute(URI id, URI type) throws URISyntaxException { logger.debug("registering attribute {} {}", iAm(), id); attributeIdUris.add(id); attributeTypes.put(id, type); } protected final void registerAttribute(XacmlName attribute) { logger.debug("registering attribute {} {}", iAm(), attribute.uri); attributeIdUris.add(attribute.attributeId); attributeTypes.put(attribute.attributeId, attribute.datatype); } protected final void denyAttribute(URI id) { logger.debug("Denying attribute {} {}", iAm(), id); attributesDenied.add(id); } @Deprecated protected final URI getAttributeIdUri(String id) { URI test = URI.create(id); return (attributeIdUris.contains(test)) ? test : null; } @Deprecated protected final boolean hasAttribute(String id) { return attributeIdUris.contains(URI.create(id)); } protected final boolean hasAttribute(URI id) { return attributeIdUris.contains(id); } private final void showRegisteredAttributes() { if (!logger.isDebugEnabled()) return; Iterator<URI> it = attributeIdUris.iterator(); while (it.hasNext()) { String key = it.next().toString(); logger.debug("another registered attribute = {} {}", iAm(), key); } } @Deprecated protected final String getAttributeType(String id) { return getAttributeTypeUri(id).toString(); } protected final URI getAttributeTypeUri(String id) { return getAttributeType(URI.create(id)); } protected final URI getAttributeType(URI id) { return attributeTypes.get(id); } private final Set<Integer> supportedDesignatorTypes = new HashSet<Integer>(); protected final void registerSupportedDesignatorType(int designatorType) { logger.debug("registerSupportedDesignatorType() {}", iAm()); supportedDesignatorTypes.add(designatorType); } @Override @SuppressWarnings("rawtypes") public Set getSupportedDesignatorTypes() { if (instantiatedOk != null && instantiatedOk.booleanValue()) { logger.debug("getSupportedDesignatorTypes() will return {} set of elements, n={}", iAm(), supportedDesignatorTypes.size()); return supportedDesignatorTypes; } logger.debug("getSupportedDesignatorTypes() will return {}NULLSET", iAm()); return Collections.emptySet(); } protected abstract boolean canHandleAdhoc(); private final boolean willService(URI attributeId) { if (hasAttribute(attributeId)) { logger.debug("willService() {} accept this known serviced attribute {}", iAm(), attributeId); return true; } if (!canHandleAdhoc()) { logger.debug("willService() {} deny any adhoc attribute {}", iAm(), attributeId); return false; } if (attributesDenied.contains(attributeId)) { logger.debug("willService() {} deny this known adhoc attribute {}", iAm(), attributeId); return false; } logger.debug("willService() {} allow this unknown adhoc attribute {}", iAm(), attributeId); return true; } @Override public EvaluationResult findAttribute(URI attributeType, URI attributeId, URI issuer, URI category, EvaluationCtx context, int designatorType) { logger.debug("AttributeFinder:findAttribute {}", iAm()); logger.debug("attributeType=[{}], attributeId=[{}] {}", attributeType, attributeId, iAm()); if (!parmsOk(attributeType, attributeId, designatorType)) { logger.debug("AttributeFinder:findAttribute exit on parms not ok {}", iAm()); if (attributeType == null) { attributeType = STRING_ATTRIBUTE_TYPE_URI; } return getEmptyResult(attributeType); } if (!willService(attributeId)) { logger.debug("AttributeFinder:willService() {} returns false", iAm()); return getEmptyResult(attributeType); } if (category != null) { logger.debug("++++++++++ AttributeFinder:findAttribute {} category={}", iAm(), category.toString()); } logger.debug("++++++++++ AttributeFinder:findAttribute {} designatorType={}", iAm(), designatorType); logger.debug("about to get temp {}", iAm()); Object temp = getAttributeLocally(designatorType, attributeId, category, context); logger.debug("{} got temp={}", iAm(), temp); if (temp == null) { logger.debug("AttributeFinder:findAttribute{} exit on " + "attribute value not found", iAm()); return getEmptyResult(attributeType); } Collection<AttributeValue> set = null; if (temp instanceof String) { AttributeValue att = null; logger.debug("AttributeFinder:findAttribute will return a String {}", iAm()); if (attributeType.equals(STRING_ATTRIBUTE_TYPE_URI)) { att = StringAttribute.getInstance((String) temp); } else if (attributeType.equals(DATETIME_ATTRIBUTE_TYPE_URI)) { try { att = DateTimeAttribute.getInstance((String) temp); } catch (Throwable t) { } } else if (attributeType.equals(DATE_ATTRIBUTE_TYPE_URI)) { try { att = DateAttribute.getInstance((String) temp); } catch (Throwable t) { } } else if (attributeType.equals(TIME_ATTRIBUTE_TYPE_URI)) { try { att = TimeAttribute.getInstance((String) temp); } catch (Throwable t) { } } else if (attributeType.equals(INTEGER_ATTRIBUTE_TYPE_URI)) { try { att = IntegerAttribute.getInstance((String) temp); } catch (Throwable t) { } } if (att != null) { set = Collections.singleton(att); } } else if (temp instanceof String[]) { String[] strings = (String[]) temp; // Because the number of attributes tends to be small, // we can minimize object creation by avoiding HashSets // and sizing to the size of the value list set = new ArrayList<AttributeValue>(strings.length); logger.debug("AttributeFinder:findAttribute will return a String[] {}", iAm()); for (int i = 0; i < strings.length; i++) { if (strings[i] == null) { continue; } AttributeValue tempAtt = null; if (attributeType.equals(STRING_ATTRIBUTE_TYPE_URI)) { set.add(new StringAttribute(strings[i])); } else if (attributeType.equals(DATETIME_ATTRIBUTE_TYPE_URI)) { logger.debug("USING AS DATETIME:{}", strings[i]); try { tempAtt = DateTimeAttribute .getInstance(strings[i]); } catch (Throwable t) { } } else if (attributeType.equals(DATE_ATTRIBUTE_TYPE_URI)) { logger.debug("USING AS DATE:{}", strings[i]); try { tempAtt = DateAttribute.getInstance(strings[i]); } catch (Throwable t) { } } else if (attributeType.equals(TIME_ATTRIBUTE_TYPE_URI)) { logger.debug("USING AS TIME:{}", strings[i]); try { tempAtt = TimeAttribute.getInstance(strings[i]); } catch (Throwable t) { } } else if (attributeType.equals(INTEGER_ATTRIBUTE_TYPE_URI)) { logger.debug("USING AS INTEGER: {}", strings[i]); try { tempAtt = IntegerAttribute .getInstance(strings[i]); } catch (Throwable t) { } } if (tempAtt != null && !set.contains(tempAtt)) { set.add(tempAtt); } } } if (set == null || set.size() == 0) { return getEmptyResult(attributeType); } return new EvaluationResult(new BagAttribute(attributeType, set)); } protected static final URI DATE_ATTRIBUTE_TYPE_URI = URI.create(DateAttribute.identifier); protected static final URI DATETIME_ATTRIBUTE_TYPE_URI = URI.create(DateTimeAttribute.identifier); protected static final URI INTEGER_ATTRIBUTE_TYPE_URI = URI.create(IntegerAttribute.identifier); protected static final URI STRING_ATTRIBUTE_TYPE_URI = URI.create(StringAttribute.identifier); protected static final URI TIME_ATTRIBUTE_TYPE_URI = URI.create(TimeAttribute.identifier); abstract protected Object getAttributeLocally(int designatorType, URI attributeId, URI resourceCategory, EvaluationCtx context); }