XACML PIP with WSO2 Identity Server
Access control is a mechanism where we control and limit access to resources and information based on user privileges. Entitlement management is a process where it grants access privileges to users or resources after fine-grained authentication. WSO2 Identity Server uses XACML for providing this functionality. XACML is an OASIS standard which describes a policy language and an access control decision request/ response definition.
WSO2 Identity server supports XACML 3.0 and you can you the features available with it. I'm going to discuss about how to write a custom PIP for WSO2 Identity Server.
I'm going to use a scenario where a bank account going to be updated based on an attribute resides on an external database. Here the customer can update his/ her own account. But if the user is other than the customer coming with the required permission in here it's "/permission/applications/saml2-banking-web-app.com/update_account/POST", then the custom PIP will retrieve the account attributes from the database and if the attribute value is "Standard" the request will get "Permit" response.
Here's the policy I have used to validate users against XACML customer function of permission tree evaluation and the attribute retrieved from the database.
First here's a code snippet depicts a custom PIP which I have used in my XACML policy. You have to implement the PIPAttributeFinder interface for that matter.
WSO2 Identity server supports XACML 3.0 and you can you the features available with it. I'm going to discuss about how to write a custom PIP for WSO2 Identity Server.
I'm going to use a scenario where a bank account going to be updated based on an attribute resides on an external database. Here the customer can update his/ her own account. But if the user is other than the customer coming with the required permission in here it's "/permission/applications/saml2-banking-web-app.com/update_account/POST", then the custom PIP will retrieve the account attributes from the database and if the attribute value is "Standard" the request will get "Permit" response.
Here's the policy I have used to validate users against XACML customer function of permission tree evaluation and the attribute retrieved from the database.
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="pip_evaluate_permission_tree_policy" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable" Version="1.0"> <Description> This policy provides the ability to authorize users based on the below mentioned permission and account type or the account owner </Description> <Target> <AnyOf> <AllOf> <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string"> /permission/applications/saml2-banking-web-app.com/update_account/POST </AttributeValue> <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/> </Match> </AllOf> </AnyOf> </Target> <Rule Effect="Permit" RuleId="permission-tree-authorized"> <Condition> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or"> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and"> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:eval-permission-tree"> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only"> <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"/> </Apply> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only"> <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"/> </Apply> </Apply> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of"> <Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"/> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">STANDARD</AttributeValue> <AttributeDesignator Category="urn:oasis:names:tc:xacml:1.0:subject-category:resource" AttributeId="http://demo.xacml.com/id/account-type" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/> </Apply> </Apply> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">customer</AttributeValue> <AttributeDesignator AttributeId="http://wso2.org/claims/role" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"/> </Apply> </Apply> </Condition> </Rule> <Rule Effect="Deny" RuleId="deny_others"/> </Policy>
First here's a code snippet depicts a custom PIP which I have used in my XACML policy. You have to implement the PIPAttributeFinder interface for that matter.
/** * This is sample implementation of PIPAttributeFinder in WSO2 entitlement engine. Here we are * calling to an external database to find given attribute; */ public class AccountJDBCAttributeFinder extends AbstractPIPAttributeFinder { private static final String ACCOUNT_TYPE = "http://demo.xacml.com/id/account-type"; /** * Connection pool is used to create connection to database */ private DataSource dataSource; /** * List of attribute finders supported by the this PIP attribute finder */ private Set<String> supportedAttributes = new HashSet<String>(); @Override public void init(Properties properties) throws Exception{ String dataSourceName = (String) properties.get("DataSourceName"); if(dataSourceName == null || dataSourceName.trim().length() == 0){ throw new Exception("Data source name can not be null. Please configure it in the entitlement.properties file."); } dataSource = InitialContext.doLookup(dataSourceName); supportedAttributes.add(ACCOUNT_TYPE); } @Override public String getModuleName() { return "Account Attribute Finder"; } @Override public Set<String> getAttributeValues(String subjectId, String resourceId, String actionId, String environmentId, String attributeId, String issuer) throws Exception{ /* * SQL statement to retrieve attribute value for given attribute id from database */ String sqlStmt = "select ACCOUNT_TYPE from ACCOUNT_INFO where ACCOUNT_NO='" + actionId + "';"; Set<String> values = new HashSet<String>(); PreparedStatement prepStmt = null; ResultSet resultSet = null; Connection connection = null; try { connection = dataSource.getConnection(); if (connection != null) { prepStmt = connection.prepareStatement(sqlStmt); resultSet = prepStmt.executeQuery(); while (resultSet.next()) { values.add(resultSet.getString(1)); } } } catch (SQLException e) { throw new Exception("Error while retrieving attribute values", e); }finally { try{ if(resultSet != null){ resultSet.close(); } if(prepStmt != null){ prepStmt.close(); } if(connection != null){ connection.close(); } } catch (Exception e){ e.printStackTrace(); } } return values; } @Override public Set<String> getSupportedAttributes() { return supportedAttributes; } }
And you need to do add the following to the entitlement.properties file in <IS_HOME>/repository/conf/identity/ directory and do the necessary changes.
PIP.AttributeDesignators.Designator.2=org.xacmlinfo.xacml.pip.jdbc.AccountJDBCAttributeFinder #Define JNDI datasource name as property value org.xacmlinfo.xacml.pip.jdbc.AccountJDBCAttributeFinder.1=DataSourceName,jdbc/DEMODB
Comments
Post a Comment