OASIS eXtensible Access Control Markup Language (XACML) TC

  • 1.  Attributes of relations code sample

    Posted 01-28-2013 15:07
    All, I have written a small sample for the attributes of relations discussion. 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? Did you implement a PoC already? What kind of performance do you see? 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(); } } }


  • 2.  Re: [xacml] Attributes of relations code sample

    Posted 01-29-2013 04:00
    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. 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


  • 3.  Re: [xacml] Attributes of relations code sample

    Posted 01-30-2013 16:07
    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


  • 4.  Re: [xacml] Attributes of relations code sample

    Posted 01-31-2013 06:52
    Hi Erik, On 31/01/2013 3:06 AM, Erik Rissanen wrote: 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. You would need to define a new attribute to enable both possibilities, whereas I could just edit my policy. 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. Mechanically, all attributes are similarly configured, but what attributes one chooses to configure make a big difference. It determines what logic appears in standardized XACML policies and what logic is buried in proprietary context handler configuration, which in turn determines how interoperable a deployment is. Mohammad identified one extreme of the spectrum: accessIsAllowed. I, and Mohammad too I think, have been working close to the other extreme, where PIP repositories are accessed using nothing more sophisticated than AttributeQuery. The further one moves towards accessIsAllowed, the more obscure the policies become, the more restrictions are placed on policy writers as to what they can express in policy (unless you want to let them manage policy by fiddling with the context handler configuration), and the less transportable those policies are. I think number-of-valid-contracts has already gone too far towards accessIsAllowed. It is not discernable that the policy actually depends on the resource-id and location provided by the PEP. The policy is only going to work in another PDP if it also has a configured number-of-valid-contracts attribute that does the same thing. It might if there's a profile describing it, but the more one moves towards accessIsAllowed the harder it becomes to anticipate all the attributes needed to express all the policy logic that deployers might need or want. If the attribute is outside what a profile defines, then the policy itself isn't enough for another PDP. The configuration of the context handler is also needed, though it might not be much help if the original PDP's context handler uses SQL and the second PDP uses a database or directory that doesn't support SQL. The goal of a group interested in standards for interoperability should be to stay as close to the AttributeQuery end of the spectrum as possible. Note that that doesn't mean sacrificing performance. An implementation that chooses to disregard the standard PIP interface and have the context handler closely coupled to a database is always free to have the PDP/context-handler factor out any part of a policy, e.g., parts expressed using the iterator expressions, and convert that into an optimized query on its database of choice. By having the policy logic in a standardized form it is feasible to do such conversions automatically. The original policies can be exported to various PDPs, each doing conversions suited to their particular databases, or to PDPs that do no optimization at all, and they will all operate equivalently. 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. If you do manage to find an example that is realistic, uncontrived and that I can't morph into a form suitable for efficient processing using iterator expressions, then I will just turn around and say that it is a case where a PDP with a closely-coupled database has an opportunuity to perform a significant optimization, so you might want to save us both the trouble. Regards, Steven 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


  • 5.  Re: [xacml] Attributes of relations code sample

    Posted 01-31-2013 10:47
    Hi Steven, Ok, I'll save the trouble then. You have many good points there which I agree with. I just posted another response to Mohammad's email, and I think it covers this thread as well, so I won't write more here. Best regards, Erik On 2013-01-31 07:52, Steven Legg wrote: Hi Erik, On 31/01/2013 3:06 AM, Erik Rissanen wrote: 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. You would need to define a new attribute to enable both possibilities, whereas I could just edit my policy. 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. Mechanically, all attributes are similarly configured, but what attributes one chooses to configure make a big difference. It determines what logic appears in standardized XACML policies and what logic is buried in proprietary context handler configuration, which in turn determines how interoperable a deployment is. Mohammad identified one extreme of the spectrum: accessIsAllowed. I, and Mohammad too I think, have been working close to the other extreme, where PIP repositories are accessed using nothing more sophisticated than AttributeQuery. The further one moves towards accessIsAllowed, the more obscure the policies become, the more restrictions are placed on policy writers as to what they can express in policy (unless you want to let them manage policy by fiddling with the context handler configuration), and the less transportable those policies are. I think number-of-valid-contracts has already gone too far towards accessIsAllowed. It is not discernable that the policy actually depends on the resource-id and location provided by the PEP. The policy is only going to work in another PDP if it also has a configured number-of-valid-contracts attribute that does the same thing. It might if there's a profile describing it, but the more one moves towards accessIsAllowed the harder it becomes to anticipate all the attributes needed to express all the policy logic that deployers might need or want. If the attribute is outside what a profile defines, then the policy itself isn't enough for another PDP. The configuration of the context handler is also needed, though it might not be much help if the original PDP's context handler uses SQL and the second PDP uses a database or directory that doesn't support SQL. The goal of a group interested in standards for interoperability should be to stay as close to the AttributeQuery end of the spectrum as possible. Note that that doesn't mean sacrificing performance. An implementation that chooses to disregard the standard PIP interface and have the context handler closely coupled to a database is always free to have the PDP/context-handler factor out any part of a policy, e.g., parts expressed using the iterator expressions, and convert that into an optimized query on its database of choice. By having the policy logic in a standardized form it is feasible to do such conversions automatically. The original policies can be exported to various PDPs, each doing conversions suited to their particular databases, or to PDPs that do no optimization at all, and they will all operate equivalently. 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. If you do manage to find an example that is realistic, uncontrived and that I can't morph into a form suitable for efficient processing using iterator expressions, then I will just turn around and say that it is a case where a PDP with a closely-coupled database has an opportunuity to perform a significant optimization, so you might want to save us both the trouble. Regards, Steven 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