Following is one possible approach to carryout XACML authorization in node.js.
1.) Wrap WSO2 Balana PDP implementation to expose a simple interface to process incoming XACML requests.
package edu.purdue.cs.endtoendsoa;
public class AccessController {
public String evaluate(String policy, String request) {
PDP pdp = this.getPDPInstance(policy);
return this.evaluate(request, pdp);
}
private String evaluate(String request, PDP pdp) {
String res = pdp.evaluate(request);
ByteArrayInputStream in = new ByteArrayInputStream(res.getBytes());
OMElement elem = OMXMLBuilderFactory.createOMBuilder(in).getDocumentElement();
OMElement tmp = elem.getFirstChildWithName(new QName("urn:oasis:names:tc:xacml:3.0:core:schema:wd-17", "Result"));
tmp = tmp.getFirstChildWithName(new QName("urn:oasis:names:tc:xacml:3.0:core:schema:wd-17", "Decision"));
return tmp.getText();
}
private PDP getPDPInstance(String policyLocation) {
PolicyFinder finder= new PolicyFinder();
Set policyLocations = new HashSet();
policyLocations.add(policyLocation);
FileBasedPolicyFinderModule testPolicyFinderModule = new FileBasedPolicyFinderModule(policyLocations);
Set policyModules = new HashSet();
policyModules.add(testPolicyFinderModule);
finder.setModules(policyModules);
Balana balana = Balana.getInstance();
PDPConfig pdpConfig = balana.getPdpConfig();
pdpConfig = new PDPConfig(pdpConfig.getAttributeFinder(), finder,
pdpConfig.getResourceFinder(), true);
return new PDP(pdpConfig);
}
}
The objective of this wrapper class is only to make things easy when integrating with node.js. Source code is available here:
https://code.google.com/p/end-to-end-soa/source/browse/policy. When building this project with maven it collects all the dependencies into 'target/lib' directory.
2.) Import the above implementation into Javascript and try it out.
var java = require('java');
var xml2js = require('xml2js');
var fs = require('fs');
var jars_dir = process.cwd() + '/lib/';
java.classpath.push(jars_dir + "apache-mime4j-core-0.7.2.jar");
java.classpath.push(jars_dir + "balana-distribution-1.0.0-wso2v7.jar");
java.classpath.push(jars_dir + "geronimo-activation_1.1_spec-1.1.jar");
java.classpath.push(jars_dir + "jaxen-1.1.3.jar");
java.classpath.push(jars_dir + "wstx-asl-3.2.9.jar");
java.classpath.push(jars_dir + "axiom-api-1.2.13.jar");
java.classpath.push(jars_dir + "commons-io-1.3.2.jar");
java.classpath.push(jars_dir + "geronimo-javamail_1.4_spec-1.7.1.jar");
java.classpath.push(jars_dir + "junit-3.8.1.jar");
java.classpath.push(jars_dir + "axiom-impl-1.2.13.jar");
java.classpath.push(jars_dir + "commons-logging-1.1.1.jar");
java.classpath.push(jars_dir + "geronimo-stax-api_1.0_spec-1.0.1.jar");
java.classpath.push(jars_dir + "org.wso2.balana-1.0.0-wso2v7.jar");
java.classpath.push(jars_dir + "policy-1.0-SNAPSHOT.jar");
var req_text = fs.readFileSync('./req_1.json','utf8');
var req = JSON.parse(req_text);
//Update request template with values
for(var i in req.Request.Attributes) {
var attr = req.Request.Attributes[i];
var attr_id = attr.Attribute[0].$.AttributeId;
if(attr_id == 'urn:oasis:names:tc:xacml:1.0:resource:resource-id') {
attr.Attribute[0].AttributeValue[0]._='localhost:6102';
} else if(attr_id == 'http://endtoendsoa.cs.purdue.edu/policy/service_uri') {
attr.Attribute[0].AttributeValue[0]._='localhost:6101';
} else if(attr_id == 'urn:oasis:names:tc:xacml:1.0:action:action-id') {
attr.Attribute[0].AttributeValue[0]._='READ';
} else if(attr_id == 'http://test.org/trust_level') {
attr.Attribute[0].AttributeValue[0]._=10;
}
}
//Convert populated request template to XML
var builder = new xml2js.Builder();
var req_xml = builder.buildObject(req);
var AccessController = java.import('edu.purdue.cs.endtoendsoa.AccessController');
var ac = new AccessController();
ac.evaluate(process.cwd() + '/policy_1.xml', req_xml, function(err, result) {
if(err) {
console.log(err);
} else {
console.log('Response from access controller : ' + result);
}
});
Note that the a template was used in the above code to create a XACML request. This template was generated using a regular XML XACML request.
The original XACML request was simply converted into JSON. This was loaded as a JSON object, which is very convenient to traverse in Javascript.
The policy file used in the above example is available
here. Request template is available
here.