Using XACML to control access to a SCIM API - wso2

How can I apply XACML access control policies against the Identity Server's very own SCIM API? My idea is that I want the user to be able to access the user's SCIM endpoint (list endpoint), but it will only return the user itself as the only result (i.e. user can query for oneself). Is this even possible?
The default permissions in WSO2 Identity Server is not fine grained enough to solve this problem. Thus, I started looking into XACML.

Yes, XACML is a good fit for this. What you need to do is model your users, actions, and resources.
For instance, in your case, the resource is the SCIM API. The SCIM API exposes:
manage users
manager user groups
manage user memberships
For each one you can GET / POST / PUT / DELETE per the REST profile.
ALFA Policy
An example policy using the ALFA syntax of XACML could be:
/**
* This policy secures access to the SCIM API
*/
policyset secureSCIM{
target clause stringStartsWith("/scim/v1/", contextPath)
apply firstApplicable
/**
* This policy secures access to the User object of the SCIM API
*/
policy secureUserAccess{
target clause stringEndsWith("Users", contextPath)
apply firstApplicable
/**
* View User object:
*/
rule viewUser{
target clause httpVerb == "GET"
permit
condition scimUser == requestor
}
}
}
XACML Equivalent
<?xml version="1.0" encoding="UTF-8"?>
<!--This file was generated by the ALFA Plugin for Eclipse from Axiomatics AB (http://www.axiomatics.com).
Any modification to this file will be lost upon recompilation of the source ALFA file-->
<xacml3:PolicySet xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
PolicySetId="http://axiomatics.com/alfa/identifier/scim.secureSCIM"
PolicyCombiningAlgId="urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>This policy secures access to the SCIM API</xacml3:Description>
<xacml3:PolicySetDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116</xacml3:XPathVersion>
</xacml3:PolicySetDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:3.0:function:string-starts-with">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">/scim/v1/</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="scim.contextPath"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Policy xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
PolicyId="http://axiomatics.com/alfa/identifier/scim.secureSCIM.secureUserAccess"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>This policy secures access to the User object of the SCIM API</xacml3:Description>
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:3.0:function:string-ends-with">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">Users</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="scim.contextPath"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/scim.secureSCIM.secureUserAccess.viewUser">
<xacml3:Description>View User object:</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">GET</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="scim.http.verb"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Condition>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of-any">
<xacml3:Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"/>
<xacml3:AttributeDesignator
AttributeId="scimUser"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
<xacml3:AttributeDesignator
AttributeId="requestor"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
MustBePresent="false"
/>
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
</xacml3:Policy>
</xacml3:PolicySet>

Related

How can I do that one service provider only use one user store to authenticate in the IS 5.9.0?

I am using a WSO2 Identity Server 5.9.0. I have created 3 User Store and many Service Providers.
I am using a XACML Policy in order to allow that each Service Provider only accept the user that send the request is exist in one User Store. The policy is the next:
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="POLICY-NAME" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable" Version="1.0">
<Description>I wirte a description</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">scope_validation</AttributeValue>
<AttributeDesignator AttributeId="http://wso2.org/identity/identity-action/action-name" Category="http://wso2.org/identity/identity-action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Match>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">ServiceProviderNameHere</AttributeValue>
<AttributeDesignator AttributeId="http://wso2.org/identity/sp/sp-name" Category="http://wso2.org/identity/sp" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Match>
</AllOf>
</AnyOf>
</Target>
<Rule Effect="Permit" RuleId="permit_by_userstores">
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only">
<AttributeDesignator AttributeId="http://wso2.org/identity/user/user-store-domain" Category="http://wso2.org/identity/user" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">USER-STORE-NAME</AttributeValue>
</Apply>
</Condition>
</Rule>
<Rule Effect="Deny" RuleId="deny_others"></Rule>
</Policy>
The problem that I found, it is that the user is being looked for in all the user stores (one to one), when it found the user stop the search and it compare the user store with the user store in the policy. If the 2 user store name is equal, it works fine. However, if I have 2 user store with the same user and the Identity Server found first the user in the user store that is not allowed by the policy, return an error and it don't continue looking for.
How can I do that one service provider only use one user store to authenticate?
Is there any other way to do it?
Thank you.
Your requirement can be satisfied by the userstore preference order feature available since WSO2-IS 5.9.0. It allows you to define only particular userstores' users can access the particular service provider or the order of userstores chain the user should be checked.
Refer to this example customization: https://anuradha-15.medium.com/how-to-configure-your-preferred-user-stores-to-authenticate-users-for-a-service-provider-in-wso2-cdadf43f9366
Feature:https://github.com/wso2/product-is/issues/4350

What is the correct way of linking local user account to federated user in WSO2 Identity server 5.10.0

I am using Google authenticator (Oauth2 client) as an Identity provider in WSO2 5.10.0 . I created a Service provider which uses this google authenticator as Federated authentication.
When the user login for the first time using google credentials(gmail), I am able to make a local user by storing user in local user store through Just-In-Time Provisioning in Identity provider.
https://is.docs.wso2.com/en/latest/learn/configuring-just-in-time-provisioning-for-an-identity-provider/
After the first login i assign roles to the local user manually.
Now when the user login again using federated(google) authentication, the roles that i provided to the local user does not get link with the federated user.
I read of Associating user account https://is.docs.wso2.com/en/latest/learn/associating-user-accounts/ using WSO2 user-portal
I tried adding
[user.association]
enable_for_federated_users = true
in deployment.toml . But when i open user-portal, i only see the option of linking local user account to another local user account.
I want to link user account with federated user such that when the federated user logs in, it takes the roles provided to the local user earlier and pass through the XACML role based policy.
XAMCL policy
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="role_based_login_policy" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable" Version="1.0">
<Description>This policy template provides ability to authorize users to a given service provider(defined by SP_NAME) in the authentication flow based on the roles of the user (defined by ROLE_1 and ROLE_2). Users who have at least one of the given roles, will be allowed and any others will be denied.</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">SP_Name</AttributeValue>
<AttributeDesignator AttributeId="http://wso2.org/identity/sp/sp-name" Category="http://wso2.org/identity/sp" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"></AttributeDesignator>
</Match>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">authenticate</AttributeValue>
<AttributeDesignator AttributeId="http://wso2.org/identity/identity-action/action-name" Category="http://wso2.org/identity/identity-action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="false"></AttributeDesignator>
</Match>
</AllOf>
</AnyOf>
</Target>
<Rule Effect="Permit" RuleId="permit_by_roles">
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">admin</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="true"></AttributeDesignator>
</Apply>
</Apply>
</Condition>
</Rule>
<Rule Effect="Deny" RuleId="deny_others"></Rule>
</Policy>
In the latest versions of the Identity Server (including 5.10.0), when the Just-In-Time provisioning is enabled, federated users and local users are associated automatically. So you don't need to enable the config you have mentioned and as the documentation has mentioned, it is not recommended.
So if you want to send the attributes of the local provisioned user to the application, you have to enable Assert identity using mapped local subject identifier configuration for the application.

Policy Entitlement XACML in WSO2 Identity Server with WSO2 API Manager

I am having an requirement where I have integrated WSO2 Identity server(5.3) internal LDAP with WSO2 API Manager(2.1).
I have done the changes by un-commenting the LDAP configuration in wso2-api-2.1\repository\conf\user-mgt.xml by uncommenting the below code.
<UserStoreManager class="org.wso2.carbon.user.core.ldap.ReadWriteLDAPUserStoreManager">
and commented the below.
<UserStoreManager class="org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager">
I followed all steps mentioned in the WSO2 documentation for Role-based Access control using XACML as below.
https://docs.wso2.com/display/AM210/Enabling+Role-Based+Access+Control+Using+XACML
I created a role 'schooladmin' and a user 'testuser'. I assigned the role'schooladmin' to 'testuser' in Identity server along with all Permissions granted.
I am able to test the PDP in WSO2 Identity store and it works fine.
Issues:
As Identity Server and API Manager are connected via LDAP, I can't see PDP developed in Identity Server available in API Manager. Is this correct behaviour?
I created and deployed an REST API basis a business service and added Entitlement during configuration as mentioned in the WSO2 documentation.
<sequence xmlns="http://ws.apache.org/ns/synapse" name="newEntitlementMediator">
<entitlementService xmlns="http://ws.apache.org/ns/synapse" remoteServiceUrl="https://localhost:9443/services" remoteServiceUserName="admin" remoteServicePassword="admin"
callbackClass="org.wso2.sample.handlers.entitlement.APIEntitlementCallbackHandler"/>
</sequence>
When I am trying to newly developed REST API in Postman, I am always getting the below error.
<am:fault xmlns:am="http://wso2.org/apimanager">
<am:code>0</am:code>
<am:type>Status report</am:type>
<am:message>Runtime Error</am:message>
<am:description>User is not authorized to perform the action</am:description>
</am:fault>
For testing, I am creating new token with correct user 'testuser' using the below service provided - https://localhost:8244/token
Please suggest if there is any limitation or I missed any configuration.
I am adding the Policy created in WSO2 IS server for entitlement.
Please review.
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="iib_policy_entitlement" RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit" Version="1.0">
<Target/>
<Rule Effect="Permit" RuleId="iib_test_rule">
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/login/v1</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="true"/>
</Match>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">POST</AttributeValue>
<AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"/>
</Match>
</AllOf>
</AnyOf>
</Target>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">iib_role</AttributeValue>
</Apply>
<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="true"/>
</Apply>
</Condition>
</Rule>
</Policy>
Thanks,
Abhishek
Answers for question 1: Yes, LDAP is used only as the user store. Meta data is stored in a separate DB. If you need to share the meta data as well then you have share the meta data DBs as well. Please change /repository/conf/datasourses/master-datasourses.xml for that.
Answer for question 2: Cannot answer this question directly but I can give you few points to check.
Check whether you can see that the created user and role from the API manager side.
Do you want IS to act as the key manger for the APIM ? If so please check this documentation. IS as a Key Manager

Is wso2 is 5.0 SP1 case sensitive?

We are using WSO2 Is 5.0 SP1. We have configured ReadOnly LDAP and also using entitlement feature of the identity server. The XACML policy which we have defined on WSO2 IS derives its entitlement from the roles assigned to the user. Our observation is that WSO2 IS does an actual match of the username i.e its case sensitive.If we pass the username in the same case as that is available in WSO2 user list it returns proper entitlement. Is there any fix for the same in WSO2 Is 5.0 SP1? Any workaround would also help.
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="AdministratorPolicy" RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:permit-overrides" Version="1.0">
<Target></Target>
<Rule Effect="Permit" RuleId="Rule1">
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">Test</AttributeValue>
</Apply>
<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"></AttributeDesignator>
</Apply>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">Internal/Administrator</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="true"></AttributeDesignator>
</Apply>
</Apply>
</Condition>
</Rule>
Rule Effect="Deny" RuleId="Rule2"></Rule>
</Policy>
Thanks in advance,
Cijoy
I think this behavior happens because of the way you wrote the xacml policy.
Have you use urn:oasis:names:tc:xacml:1.0:function:string-equal to match username in your xaml policy?
if so, try urn:oasis:names:tc:xacml:3.0:function:string-equal-ignore-case instead of above. It should solve the issue.
EDIT : With the updated question XACML policy, the issue sees to be XACML engine does not retrieve roles when it does not get username from the subjectin correct case.
That means, default PIP does not return roles if the username not in correct case.
Thinking of this angle, to answer your original question
Is wso2 is 5.0 SP1 case sensitive?
For usernames\role-names case sensitivity if the Identity Server inherits from the underlying user store it plugged in to. If you connect IS to a Active Directory, usually usernames\rolenames aren't case sensitive. If you deploy IS over a Oracle user store, usually usernames\rolenames are handled in case sensitive manner.
Solution
But more specifically for your scenario, if you wanted to retrieve (Internal) role list regardless of the case of the username. There is a reported issue regarding this behaviour and Identity Server 5.0.0 does include those fixes. So you can try following,
Open <IS_HOME>/repository/conf/user-mgt.xml file.
Add GetRoleListOfInternalUserSQL property with mentioned value under the <UserManager>/<Realm>/<Configuration> tag as follows,
<UserManager>
<Realm>
<Configuration>
...
<Property name="GetRoleListOfInternalUserSQL">
SELECT UM_ROLE_NAME FROM UM_HYBRID_USER_ROLE, UM_HYBRID_ROLE WHERE UPPER(UM_USER_NAME)=UPPER ( ? ) AND UM_HYBRID_USER_ROLE.UM_ROLE_ID=UM_HYBRID_ROLE.UM_ID AND UM_HYBRID_USER_ROLE.UM_TENANT_ID=? AND UM_HYBRID_ROLE.UM_TENANT_ID=? AND UM_HYBRID_USER_ROLE.UM_DOMAIN_ID=(SELECT UM_DOMAIN_ID FROM UM_DOMAIN WHERE UM_TENANT_ID=? AND UM_DOMAIN_NAME=?)
</Property>
</Configuration>
...
</Realm>
<UserManager>
Restart the server
Now your policy should evaluate as expected for any case of the username

How to Retrieve an resource:root-resource-id in SampleResourceFinderModule from request

i have a scenario in which i am sending resource:root-resource-id from request as below
<Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource">
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" IncludeInResult="true">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
Customer
</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:root-resource-id" IncludeInResult="true">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
Customer
</AttributeValue>
</Attribute>
<Attribute AttributeId="urn:oasis:names:tc:xacml:2.0:resource:scope" IncludeInResult="false">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">
Descendants
</AttributeValue>
</Attribute>
</Attributes>`
Now , i have to access resource:root-resource-id in SampleResourceFinderModule as is if i access resource:resource-id :
if("Customer".equals(parentResourceId.encode())){}
Can you please tell me how i ca do this ?
I am not sure what you are trying to do exactly and what is your exact question. I guess you are trying hierarchical resource profile with WSO2IS that is mentioned as here. It seems to be that you have written new extension by implementing the "PIPResourceFinder". Idea of this extension is to retrieve the children or descendants resources under the given root resource. Therefore in the XACML request you need to send the root resource and the scope (children or descendants).
Then root resource is identified by the "urn:oasis:names:tc:xacml:1.0:resource:resource-id" attribute id. (not "urn:oasis:names:tc:xacml:1.0:resource:root-resource-id" attribute id.. I guess blog post has some mistake. According to the scenario in the blog post, it may need to send the root resource with different attribute id).
Scope is identified by the "urn:oasis:names:tc:xacml:2.0:resource:scope" attribute Id.
Finally you can access the root resource in the "PIPResourceFinder" finder. Then you can return the child resources that is related with root resource. You can go through the sample implementation mentioned in this blog.