package org.wso2.carbon.identity.entitlement.pip;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.identity.entitlement.internal.EntitlementServiceComponent;
import com.sun.xacml.EvaluationCtx;
import com.sun.xacml.ParsingException;
import com.sun.xacml.attr.AttributeDesignator;
import com.sun.xacml.attr.AttributeValue;
import com.sun.xacml.attr.BagAttribute;
import com.sun.xacml.attr.BooleanAttribute;
import com.sun.xacml.attr.DateAttribute;
import com.sun.xacml.attr.DateTimeAttribute;
import com.sun.xacml.attr.DoubleAttribute;
import com.sun.xacml.attr.HexBinaryAttribute;
import com.sun.xacml.attr.IntegerAttribute;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.attr.TimeAttribute;
import com.sun.xacml.cond.EvaluationResult;
import com.sun.xacml.finder.AttributeFinderModule;
/**
* CarbonAttributeFinder registers with sun-xacml engine as an AttributeFinderModule and delegate
* functionality to the attribute handlers registered with it self.
*
* Whenever the XACML engine finds a missing attribute in the XACML request - it will call the
* findAttribute() method of this class.
*
*/
public class CarbonAttributeFinder extends AttributeFinderModule {
private Map<String, List<PIPAttributeFinder>> attrFinders = new HashMap<String, List<PIPAttributeFinder>>();
private static Log log = LogFactory.getLog(CarbonAttributeFinder.class);
/**
* Registers PIP attribute handlers with the PDP against their supported attributes. This PIP
* attribute handlers are picked from pip-config.xml file - which should be inside
* [CARBON_HOME]\repository\conf.
*/
public CarbonAttributeFinder() {
List<PIPAttributeFinder> designators = EntitlementServiceComponent.getPipConfig()
.getDesignators();
for (Iterator iterator = designators.iterator(); iterator.hasNext();) {
PIPAttributeFinder pipAttributeFinder = (PIPAttributeFinder) iterator.next();
Set<String> attrs = pipAttributeFinder.getSupportedAttributes();
if (attrs != null) {
for (Iterator attrsIter = attrs.iterator(); attrsIter.hasNext();) {
String attr = (String) attrsIter.next();
if (attrFinders.containsKey(attr)) {
List<PIPAttributeFinder> finders = attrFinders.get(attr);
if (!finders.contains(pipAttributeFinder)) {
finders.add(pipAttributeFinder);
if (log.isDebugEnabled()) {
log.debug(String
.format("PIP attribute handler %1$s registered for the supported attribute %2$s",
pipAttributeFinder.getClass(), attr));
}
}
} else {
List<PIPAttributeFinder> finders = new ArrayList<PIPAttributeFinder>();
finders.add(pipAttributeFinder);
attrFinders.put(attr, finders);
if (log.isDebugEnabled()) {
log.debug(String
.format("PIP attribute handler %1$s registered for the supported attribute %2$s",
pipAttributeFinder.getClass(), attr));
}
}
}
}
}
}
/*
* (non-Javadoc)
*
* @see com.sun.xacml.finder.AttributeFinderModule#findAttribute(java.net.URI, java.net.URI,
* java.net.URI, java.net.URI, com.sun.xacml.EvaluationCtx, int)
*/
public EvaluationResult findAttribute(URI attributeType, URI attributeId, URI issuer,
URI subjectCategory, EvaluationCtx context, int designatorType) {
// Get the list of attribute finders who are registered with this particular attribute.
List<PIPAttributeFinder> finders = attrFinders.get(attributeId.toString());
if (finders == null || finders.size() == 0) {
log.info("No attribute designators defined for the attribute " + attributeId.toString());
return new EvaluationResult(BagAttribute.createEmptyBag(attributeType));
}
List<AttributeValue> attrBag = new ArrayList<AttributeValue>();
EvaluationResult subject = null;
String subjectId = null;
EvaluationResult resource = null;
String resourceId = null;
try {
subject = context.getSubjectAttribute(new URI(StringAttribute.identifier), new URI(
"urn:oasis:names:tc:xacml:1.0:subject:subject-id"), subjectCategory);
if (subject.getAttributeValue().isBag()) {
BagAttribute attr = (BagAttribute) subject.getAttributeValue();
for (Iterator iterator = attr.iterator(); iterator.hasNext();) {
AttributeValue val = (AttributeValue) iterator.next();
subjectId = val.encode();
if (log.isDebugEnabled()) {
log.debug(String.format("Finding attributes for the subject %1$s",
subjectId));
}
break;
}
}
resource = context.getResourceAttribute(new URI(StringAttribute.identifier), new URI(
"urn:oasis:names:tc:xacml:1.0:resource:resource-id"), null);
if (resource.getAttributeValue().isBag()) {
BagAttribute attr = (BagAttribute) resource.getAttributeValue();
for (Iterator iterator = attr.iterator(); iterator.hasNext();) {
AttributeValue val = (AttributeValue) iterator.next();
resourceId = val.encode();
if (log.isDebugEnabled()) {
log.debug(String.format("Finding attributes for the resource %1$s",
resourceId));
}
break;
}
}
for (Iterator iterator = finders.iterator(); iterator.hasNext();) {
PIPAttributeFinder pipAttributeFinder = (PIPAttributeFinder) iterator.next();
if (log.isDebugEnabled()) {
log.debug(String.format(
"Finding attributes with the PIP attribute handler %1$s",
pipAttributeFinder.getClass()));
}
Set<String> attrs = pipAttributeFinder.getAttributeValues(subjectId, resourceId,
attributeId.toString());
if (attrs != null) {
for (Iterator iterAttr = attrs.iterator(); iterAttr.hasNext();) {
final String attr = (String) iterAttr.next();
AttributeValue attribute = getAttribute(attr, attributeType.toString());
attrBag.add(attribute);
}
}
}
} catch (Exception e) {
log.error("Error occured while finding attributes via PIP", e);
return new EvaluationResult(BagAttribute.createEmptyBag(attributeType));
}
return new EvaluationResult(new BagAttribute(attributeType, attrBag));
}
/*
* (non-Javadoc)
*
* @see com.sun.xacml.finder.AttributeFinderModule#isDesignatorSupported()
*/
public boolean isDesignatorSupported() {
return true;
}
/*
* (non-Javadoc)
*
* @see com.sun.xacml.finder.AttributeFinderModule#getSupportedDesignatorTypes()
*/
public Set getSupportedDesignatorTypes() {
HashSet<Integer> set = new HashSet<Integer>();
set.add(Integer.valueOf(AttributeDesignator.ENVIRONMENT_TARGET));
set.add(Integer.valueOf(AttributeDesignator.SUBJECT_TARGET));
set.add(Integer.valueOf(AttributeDesignator.ACTION_TARGET));
set.add(Integer.valueOf(AttributeDesignator.RESOURCE_TARGET));
return set;
}
/*
* (non-Javadoc)
*
* @see com.sun.xacml.finder.AttributeFinderModule#getSupportedIds()
*/
public Set getSupportedIds() {
return null;
}
private AttributeValue getAttribute(final String value, String type) throws ParsingException,
ParseException, URISyntaxException {
if (StringAttribute.identifier.equals(type)) {
return new StringAttribute(value);
}
if (IntegerAttribute.identifier.equals(type)) {
return new IntegerAttribute(Long.parseLong(value));
}
if (BooleanAttribute.identifier.equals(type)) {
return BooleanAttribute.getInstance(value);
}
if (DoubleAttribute.identifier.equals(type)) {
return new DoubleAttribute(Double.parseDouble(value));
}
if (DateAttribute.identifier.equals(type)) {
return new DateAttribute(DateFormat.getDateInstance().parse(value));
}
if (DateTimeAttribute.identifier.equals(type)) {
return new DateTimeAttribute(DateFormat.getDateInstance().parse(value));
}
if (TimeAttribute.identifier.equals(type)) {
return new TimeAttribute(DateFormat.getDateInstance().parse(value));
}
if (HexBinaryAttribute.identifier.equals(type)) {
return new HexBinaryAttribute(value.getBytes());
}
return new AttributeValue(new URI(type)) {
@Override
public String encode() {
return value;
}
};
}
}