Search code examples
authorizationaccess-controlxacmlabacbalana

Implementing a custom XACML function in Balana


After a lot of work trying to install a custom function inside balana (for using in apply condition in policies), i'm trying to ask here. Basically what documentation tell you about install new function inside balana engine it's: 1) insert in config something like this:

    <functionFactory name="func" useStandardFunctions="true">
    <general>
        <function class="singlerequestandpolicybalanatester.GpsFunction"/>
    </general>
    <!--      <target>
                <function class="singlerequestandpolicybalanatester.GpsFunction"/>
            </target>
            <condition>
                <function class="singlerequestandpolicybalanatester.GpsFunction"/>
            </condition>
    -->
</functionFactory>

and offcourse implement that class

public class GpsFunction extends FunctionBase {

public static final String NAME_GPS = "coolfunctiongps";

public static Set getSupportedIdentifiers() {

    Set set = new HashSet();
    set.add(NAME_GPS);
    return set;
}

public GpsFunction() {
    super(NAME_GPS, 0, StringAttribute.identifier, false, 3, 3, BooleanAttribute.identifier, false);
    System.out.println(NAME_GPS);
}

@Override
public EvaluationResult evaluate(List inputs, EvaluationCtx context) {
blablabla

Indeed overriding getsupportedidentifiers it's not even required, but whatever..

Now when balana start you see your class initialized, constructor it's called. Then even after balana it's initialized, you can do:

Set sup = balana.getFunctionGeneralFactory().getSupportedFunctions();

    Iterator<String> it = sup.iterator();
    System.out.println("General:");
    while (it.hasNext()) {
        String thisfunc = (String) it.next();
            System.out.println(thisfunc);
    }

and you SEE your function loaded and ready to go. Nice. No, fail. After debugging using my own custom balana core build with a lot of debug message, you clearly see when Apply element it's resolved runtime in one policy and the Apply.getInstance( it's called, and factory it's passed along with your function name, in THAT factory there isn't your function, so all you get it's an exception runtime with "Unknown FunctionId". I even tryed to install by hand the function factory, like:

FunctionFactoryProxy ff = StandardFunctionFactory.getNewFactoryProxy();
    // ff.getGeneralFactory().addFunction(new GpsFunction());
    balana.setFunctionGeneralFactory(ff.getGeneralFactory());
    balana.setFunctionConditionFactory(ff.getConditionFactory());
    balana.setFunctionTargetFactory(ff.getTargetFactory());
    balana.getFunctionGeneralFactory().addFunction(new GpsFunction());

    PDP pdp = new PDP(balana.getPdpConfig());

Again i can see my function inside this proxy, but in the end of the day, at runtime, when engine resolve the

<Rule Effect="Deny" RuleId="itsatrap">
    <Target/>
    <Condition>
        <Apply FunctionId="coolfunctiongps">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only">
                <AttributeDesignator AttributeId="attributoid" Category="attributocategory" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true" />
            </Apply>
        </Apply>
    </Condition>

</Rule>

an exception it's trown, Unknow FunctionId. So clearly i miss something, and i'm asking who can accomplish a WORKING example of custom function inside and apply element. Thanks everybody.


Solution

  • After long time surfing in balana source, i can answer myself. Maybe someone else will find this helpful. Forget anythings about balana.xml. You need the to handmade this, and this is amazing pretty simple. (But was not find this :) )

    It's consist in 4 steps.

    1)Get new factory proxy from standardFunctionFactory. So now you have proxy with mutable standards (i mean standard functions) factory.

    2)Get general factory from that proxy (General if you want visibility of you function anywhere or just Targetfactory if you want only target or conditionfactory if only in condition section of policies).

    3)Add your new function to that factory

    4) TRICKY PART Impose to abstract FunctionFactory to use your new proxy at runtime. This is done by pointing static member defaultproxy to your new one.

    So, long story short:

    FunctionFactoryProxy ff = StandardFunctionFactory.getNewFactoryProxy();
    FunctionFactory f = ff.getGeneralFactory();
    f.addFunction(new GpsFunction());
    FunctionFactory.setDefaultFactory(ff);
    

    Done.

    In case someone miss how to create your own new function you need just to extends FunctionBase , Override evaluate, call super costructor inside your own constructor, and override public static Set getSupportedIdentifiers().

    Bye.