OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

xacml message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Re: [xacml] Attributes of relations code sample


Hi Steven,

On 2013-01-29 04:59, Steven Legg wrote:

Hi Erik,

On 29/01/2013 2:06 AM, Erik Rissanen wrote:
All,

I have written a small sample for the attributes of relations discussion.

You haven't shown what an XACML expression in the condition of an XACML rule looks like, or how you get from an XACML attribute designator to a SQL query
that takes three parameters drawn from three different attributes in the
request context.


Oh, sorry about forgetting that. It's simply an attribute which is matched against:

<Match integer-less-than>
  <AttributeValue>0</AttributeValue>
  <AttributeDesignator
        Category="access-subject"
        AttributeId="number-of-valid-contracts"
        DataType="integer"/>
</Match>

The attribute category and id are of course arbitrary. Also note that it might be more practical to return one of the contract identifiers instead of a count, so it could be used in an obligation for billing purposes, etc, but I tried to keep the sample small.

The context handler implementation would have a configuration of some kind to look up the attribute. The configuration will contain the template for the database query with the blanks for the key values as well as information about which attributes of the request to use to fill in the values. This is no different from any other attribute, say looking up the role of a user in a directory/database based on the subject-id.

Also, thank you for the thorough write up of this example using your proposed solution. That is most helpful. I will have to devote a bit more time to understanding it fully, and I will see if I can modify the example in order to break the solution. ;-) Like I said in my response to Mohammad, I suspect that it won't scale to do this kind of processing on the PDP, and I will see if I can find an example which demonstrates that.

Best regards,
Erik


The example has contracts for customers who can access resources from locations specified in the contracts. Each contract may have multiple locations, but only one resource. The contract also has a limit for the
number of accesses purchased and accesses are logged into an audit log.

An access policy would like to check that there exists a contract for the customer and resource in question, such that the contract has not been spent up and the location from where the access is done is permitted by
the contract.

I did this as a code sample, using the "PIP approach" for attributes of relations. I have pasted the code at the end of this email. I ran the code sample using PostgreSQL (an open source database engine), so you may
need to tweak it a bit if you port it to something else.

The tables look like this:

Table contract:
  contract_id |   customer   |  resource   | use_limit

Table contract_locations:
  contract_id | allowed_location

Table usage:
  contract_id | log_entry

The program will create some random records. The parameters, as they are now create about 700k something
usage records.

At the end of the program you will find an example query for how a context handler can query a PIP using the
customer, resource and location as keys from the XACML request.

This works quite well and the query returns the number of contracts which exist. It could be modified also
to return one of the contract ids instead, which might be more useful.

This is a small and simple example, but I think this is already complex enough to break the iterator approach proposed by Steven. The iterators will construct the cross product using higher order functions,
leading to millions of entries to traverse in the PDP.

Steven, could you have a look at the example and say if you think I am mistaken. Also, what will the
iterators look like in this case?

XACML allows multi-valued attributes, so for a start I would describe a
contract object that had these attributes:

    contract_id (single-valued)
    customer (single-valued)
    resource-id (multi-valued)
    use_limit (single-valued)
    allowed_location (multi-valued)
    log_entry (multi-valued)

And for the access-subject category, a multi-valued attribute called contract that lists the contract objects relevant to the access-subject, and a location
attribute.

The expression in an XACML rule would look something like this, trimming the
URI prefixes as usual:

    <ForAny VariableId="$contract">
      <AttributeDesignator
        Category="access-subject"
        AttributeId="contract"
        DataType="anyURI"
        MustBePresent="false"/>
      <Apply FunctionId="and">
        <Apply FunctionId="string-is-in">
          <Apply FunctionId="string-one-and-only">
            <AttributeDesignator
              Category="access-subject"
              AttributeId="location"
              DataType="string"
              MustBePresent="false"/>
          </Apply>
          <Apply FunctionId="attribute-designator">
            <VariableReference VariableId="$contract"/>
<AttributeValue DataType="anyURI">allowed-location</AttributeValue>
            <AttributeValue DataType="anyURI">string</AttributeValue>
            <AttributeValue DataType="boolean">false</AttributeValue>
          </Apply>
        </Apply>
        <Apply FunctionId="anyURI-is-in">
          <Apply FunctionId="anyURI-one-and-only">
            <AttributeDesignator
              Category="resource"
              AttributeId="resource-id"
              DataType="anyURI"
              MustBePresent="false"/>
          </Apply>
          <Apply FunctionId="attribute-designator">
            <VariableReference VariableId="$contract"/>
<AttributeValue DataType="anyURI">resource-id</AttributeValue>
            <AttributeValue DataType="anyURI">anyURI</AttributeValue>
            <AttributeValue DataType="boolean">false</AttributeValue>
          </Apply>
        </Apply>
        <Apply FunctionId="integer-less-than">
          <Apply FunctionId="string-bag-size">
            <Apply FunctionId="attribute-designator">
              <VariableReference VariableId="$contract"/>
<AttributeValue DataType="anyURI">log_entry</AttributeValue>
              <AttributeValue DataType="anyURI">string</AttributeValue>
              <AttributeValue DataType="boolean">false</AttributeValue>
            </Apply>
          </Apply>
          <Apply FunctionId="integer-one-and-only">
            <Apply FunctionId="attribute-designator">
              <VariableReference VariableId="$contract"/>
<AttributeValue DataType="anyURI">use_limit</AttributeValue>
              <AttributeValue DataType="anyURI">integer</AttributeValue>
              <AttributeValue DataType="boolean">false</AttributeValue>
            </Apply>
          </Apply>
        </Apply>
      </Apply>
    </ForAny>

> Did you implement a PoC already?

Not yet.

> What kind of performance do you see?

The PDP would only need to look at the specific contract objects that
are relevant to the access subject; about 10 of them if I've read your
code correctly.

Regards,
Steven


I believe that any solution to this problem has to be something which can be executed at the data source, so that the data does not need to be pulled. Also, it would be good if the language is something which can be easily translated into something like SQL for implementation. However, a special language would have the benefit of visibility, though it would be a lot of design effort in duplicating something which already works.

With apologies to Mohammad, I have not yet had the time to read the SQL profile proposal. I will do so asap.

Best regards,
Erik

package com.axiomatics.demo.relations;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import java.util.Random;

public class CreateData {

     private static final String[] locations =
         {"London", "Tokyo", "New York", "Paris", "Milan"};

     public static void main(String[] args) throws Exception {
         String url = "jdbc:postgresql://localhost/relationsdb";
         Properties props = new Properties();
         props.setProperty("user","user");
         props.setProperty("password","password");
         Connection conn = DriverManager.getConnection(url, props);

         // Create tables

         String table_contract = "CREATE TABLE contract ("
                 + "contract_id INTEGER,"
                 + "customer VARCHAR(20),"
                 + "resource VARCHAR(20),"
                 + "use_limit INTEGER)";
         PreparedStatement ps0 = conn.prepareStatement(table_contract);
         try {
             ps0.executeUpdate();
         } finally {
             ps0.close();
         }

         String table_usage = "CREATE TABLE usage ("
                 + "contract_id INTEGER, log_entry VARCHAR(20))";
         ps0 = conn.prepareStatement(table_usage);
         try {
             ps0.executeUpdate();
         } finally {
             ps0.close();
         }

String table_contract_locations = "CREATE TABLE contract_locations ("
                 + "contract_id INTEGER, allowed_location VARCHAR(10))";
         ps0 = conn.prepareStatement(table_contract_locations);
         try {
             ps0.executeUpdate();
         } finally {
             ps0.close();
         }

         // Create data

         int locationSelector = 0;

         // These determine the size of the data set
         int numContracts = 10000;
         int maxLimit = 200;

         // These determine the spread in the random data created
         int numCustomers = numContracts / 10;
         int numResources = 20;

         Random random = new Random(System.currentTimeMillis());

         for(int contract = 0; contract < numContracts; contract++) {
             int limit = random.nextInt(maxLimit);
String customer = "customer_" + random.nextInt(numCustomers); String resource = "resource_" + random.nextInt(numResources);

String createContract = "INSERT INTO contract (contract_id," +
                     " customer, resource, use_limit) VALUES (?,?,?,?)";
PreparedStatement ps1 = conn.prepareStatement(createContract);

             try {
                 ps1.setInt(1, contract);
                 ps1.setString(2, customer);
                 ps1.setString(3, resource);
                 ps1.setInt(4, limit);

                 ps1.executeUpdate();
             } finally {
                 ps1.close();
             }


             int numUseForContract = random.nextInt(limit+1);
             // 50% probability that the contract has been used maximum
             // number of times
             if(random.nextInt(2) == 0) {
                 numUseForContract = limit;
             }
for(int useCount = 0; useCount < numUseForContract; useCount++) {

String createUsegeRecord = "INSERT INTO usage (contract_id," +
                         " log_entry) VALUES (?,?)";
PreparedStatement ps2 = conn.prepareStatement(createUsegeRecord);

                 try {
                     ps2.setInt(1, contract);
                     ps2.setString(2, "Used: " + useCount);

                     ps2.executeUpdate();
                 } finally {
                     ps2.close();
                 }

             }

             // For simplicity add three locations for each contract
             for(int i = 0; i < 3; i++) {
String createUsegeRecord = "INSERT INTO contract_locations (contract_id," +
                         " allowed_location) VALUES (?,?)";
PreparedStatement ps2 = conn.prepareStatement(createUsegeRecord);

                 try {
                     ps2.setInt(1, contract);
ps2.setString(2, locations[locationSelector%locations.length]);

                     ps2.executeUpdate();
                 } finally {
                     ps2.close();
                 }
                 locationSelector++;
             }

             if(contract%(numContracts/1000) == 0) {
System.out.println(((double) contract)/numContracts*100.0 + "% done");
             }
         }

// Here is a sample query to see how many a valid contracts there exist
         // for customer_0 in London for resource_0
         String customer = "customer_0";
         String resource = "resource_0";
         String location = "London";
         String query = "select count(distinct contract.contract_id)" +
                 "FROM contract, contract_locations where" +
" contract.contract_id=contract_locations.contract_id" +
                 " and contract_locations.allowed_location=?" +
                 " and contract.customer=? and contract.resource=?" +
                 " and (select count(*) from usage" +
" where usage.contract_id=contract.contract_id)<contract.use_limit";
         PreparedStatement ps2 = conn.prepareStatement(query);

         try {
             ps2.setString(1, location);
             ps2.setString(2, customer);
             ps2.setString(3, resource);

             ResultSet rs = ps2.executeQuery();

             rs.next();
             int result = rs.getInt(1);
             rs.close();
System.out.println("The number of valid contracts is " + result);
         } finally {
             ps2.close();
         }
     }
}


---------------------------------------------------------------------
To unsubscribe from this mail list, you must leave the OASIS TC that generates this mail. Follow this link
to all your TCs in OASIS at:
https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php




[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]