Friday, August 21, 2015

Claim Management Operations in WSO2 Identity Server via ClaimManagementService API

WSO2 Identity Server exposes the Claim Management [1] operations through ClaimManagementService SOAP API. If you are new to this area, you can follow the article in [2] which explains the Claims and Claim Management before reading this post.

Here I am using WSO2 Identity Server 5.0.0 with Service Pack 1 installed for demonstrating the use of the API.

The ClaimManagementService [3] API exposes the following methods for managing claims.

addNewClaimDialect
addNewClaimMapping
getClaimMappingByDialect
getClaimMappings
removeClaimDialect
removeClaimMapping
updateClaimMapping

A Claim Dialect is a group of Claims. You can add a new Claim Dialect by calling the addNewClaimDialect method. When adding a claim dialect, we need to define at-least one Claim inside the dialect. This is a sample SOAP request we need to send. For better readability, the request is divided into several sections.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd" xmlns:xsd1="http://dto.mgt.claim.carbon.wso2.org/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:addNewClaimDialect>       
        <xsd:claimDialectDTO>
           <!--Zero or more repetitions:-->
  
           <xsd1:claimMappings>                 
    <xsd1:claim>                
                 <xsd1:checkedAttribute>false</xsd1:checkedAttribute>
               
                 <xsd1:claimUri>http://mydialect.com/claims/email</xsd1:claimUri>
               
                 <xsd1:description>Email Address</xsd1:description>
               
                 <xsd1:dialectURI>http://mydialect.com/claims</xsd1:dialectURI>
               
                 <xsd1:displayOrder>1</xsd1:displayOrder>
               
                 <xsd1:displayTag>Email</xsd1:displayTag>
               
                 <xsd1:readOnly>false</xsd1:readOnly>
               
                 <xsd1:regEx></xsd1:regEx>
               
                 <xsd1:required>false</xsd1:required>
               
                 <xsd1:supportedByDefault>false</xsd1:supportedByDefault>
               
                 <xsd1:value></xsd1:value>
              </xsd1:claim>  

              <xsd1:mappedAttribute>emailaddress</xsd1:mappedAttribute>

              <!--Zero or more repetitions:-->
              <xsd1:mappedAttributes>                
                 <xsd1:attributeName>mail</xsd1:attributeName>                
                 <xsd1:domainName>WSO2.com</xsd1:domainName>
              </xsd1:mappedAttributes>

           </xsd1:claimMappings>
         
           <xsd1:dialectURI>http://mydialect.com/claims</xsd1:dialectURI>
         
           <xsd1:userStore></xsd1:userStore>
        </xsd:claimDialectDTO>
     </xsd:addNewClaimDialect>
  </soapenv:Body>
</soapenv:Envelope>


Although we define the dialectURI for the dialect, we need to add the same dialect uri in the claim as well.

The claim dialects are added to the UM_DIALECT table in the database. (If the userstore is not JDBC, then these will be stored in the internal database of Identity Server. You can find more information about the database from [4]).


From the management console, we can go to Configure -> Claim Management to view the created claim dialect.  


When we click on the claim dialect, we can view the claims inside the dialect. Here we can see that the claim we added with the dialect is correctly stored.

The claims inside the claim dialects are stored in UM_CLAIM table in the database. Here the UM_DIALECT_ID column is a foreign key to the UM_ID column of UM_DIALECT table.

From the getClaimMappingByDialect method in the API, we can get the claims of a particular claim dialect by sending the uri of the dialect. This is the SOAP request we need to send.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:getClaimMappingByDialect>
        <xsd:dialectUri>http://mydialect.com/claims</xsd:dialectUri>
     </xsd:getClaimMappingByDialect>
  </soapenv:Body>
</soapenv:Envelope>



We receive the SOAP response as following. For better readability, the response is divided into three sections.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
     <ns:getClaimMappingByDialectResponse xmlns:ns="http://org.apache.axis2/xsd">
        <ns:return xsi:type="ax25:ClaimDialectDTO" xmlns:ax25="http://dto.mgt.claim.carbon.wso2.org/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

           <ax25:claimMappings xsi:type="ax25:ClaimMappingDTO">
              <ax25:claim xsi:type="ax25:ClaimDTO">
                 <ax25:checkedAttribute>false</ax25:checkedAttribute>
                 <ax25:claimUri>http://mydialect.com/claims/email</ax25:claimUri>
                 <ax25:description>Email Address</ax25:description>
                 <ax25:dialectURI>http://mydialect.com/claims</ax25:dialectURI>
                 <ax25:displayOrder>1</ax25:displayOrder>
                 <ax25:displayTag>Email</ax25:displayTag>
                 <ax25:readOnly>false</ax25:readOnly>
                 <ax25:regEx/>
                 <ax25:required>false</ax25:required>
                 <ax25:supportedByDefault>false</ax25:supportedByDefault>
                 <ax25:value/>
              </ax25:claim>
              <ax25:mappedAttribute>emailaddress</ax25:mappedAttribute>
              <ax25:mappedAttributes xsi:type="ax25:ClaimAttributeDTO">
                 <ax25:attributeName>mail</ax25:attributeName>
                 <ax25:domainName>WSO2.COM</ax25:domainName>
              </ax25:mappedAttributes>
           </ax25:claimMappings>
           <ax25:dialectURI>http://mydialect.com/claims</ax25:dialectURI>
           <ax25:userStore xsi:nil="true"/>
        </ns:return>
     </ns:getClaimMappingByDialectResponse>
  </soapenv:Body>
</soapenv:Envelope>


We can retrieve all the claims for all claim dialects by calling the getClaimMappings method. This is the SOAP request we need to send.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:getClaimMappings/>
  </soapenv:Body>
</soapenv:Envelope>

A part of the response is listed below as the response contains many (all) claims and too large to display here. Each claim will be received with claimMappings tags.  

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
     <ns:getClaimMappingsResponse xmlns:ns="http://org.apache.axis2/xsd" xmlns:ax25="http://dto.mgt.claim.carbon.wso2.org/xsd">
        <ns:return xsi:type="ax25:ClaimDialectDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

           <ax25:claimMappings xsi:type="ax25:ClaimMappingDTO">
              <ax25:claim xsi:type="ax25:ClaimDTO">
                 <ax25:checkedAttribute>false</ax25:checkedAttribute>
                 <ax25:claimUri>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country</ax25:claimUri>
                 <ax25:description>Country</ax25:description>
                 <ax25:dialectURI>http://schemas.xmlsoap.org/ws/2005/05/identity</ax25:dialectURI>
                 <ax25:displayOrder>0</ax25:displayOrder>
                 <ax25:displayTag>Country</ax25:displayTag>
                 <ax25:readOnly>false</ax25:readOnly>
                 <ax25:regEx xsi:nil="true"/>
                 <ax25:required>false</ax25:required>
                 <ax25:supportedByDefault>true</ax25:supportedByDefault>
                 <ax25:value xsi:nil="true"/>
              </ax25:claim>
              <ax25:mappedAttribute>country</ax25:mappedAttribute>
           </ax25:claimMappings>

                   <ax25:claimMappings xsi:type="ax25:ClaimMappingDTO">
              <ax25:claim xsi:type="ax25:ClaimDTO">
                 <ax25:checkedAttribute>false</ax25:checkedAttribute>
                 <ax25:claimUri>http://wso2.org/claims/url</ax25:claimUri>
                 <ax25:description>URL</ax25:description>
                 <ax25:dialectURI>http://wso2.org/claims</ax25:dialectURI>
                 <ax25:displayOrder>10</ax25:displayOrder>
                 <ax25:displayTag>URL</ax25:displayTag>
                 <ax25:readOnly>false</ax25:readOnly>
                 <ax25:regEx xsi:nil="true"/>
                 <ax25:required>false</ax25:required>
                 <ax25:supportedByDefault>true</ax25:supportedByDefault>
                 <ax25:value xsi:nil="true"/>
              </ax25:claim>
              <ax25:mappedAttribute>url</ax25:mappedAttribute>
           </ax25:claimMappings>
           <ax25:dialectURI>http://wso2.org/claims</ax25:dialectURI>
           <ax25:userStore xsi:nil="true"/>
        </ns:return>
     </ns:getClaimMappingsResponse>
  </soapenv:Body>
</soapenv:Envelope>



We can add a new claim mapping to a dialect by calling the addNewClaimMapping method. Here, the claim can have multiple mapped attributes if we have multiple userstores. In such case, we can define the mapped attribute specific to the userstore in the mappedAttributes tag. Inside that we need to specify the attributeName and the domainName of the userstore. The mapped attribute of the primary userstore is given in mappedAttribute tag. mappedAttributes section is optional and if you are adding the mapped attribute only for the primary domain, you can exclude the mappedAttributes tag and it’s child elements from the request.


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd" xmlns:xsd1="http://dto.mgt.claim.carbon.wso2.org/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:addNewClaimMapping>
      
        <xsd:claimMappingDTO>
         
           <xsd1:claim>
            
              <xsd1:checkedAttribute>false</xsd1:checkedAttribute>
            
              <xsd1:claimUri>http://mydialect.com/claims/lastname</xsd1:claimUri>
            
              <xsd1:description>Last Name</xsd1:description>
            
              <xsd1:dialectURI>http://mydialect.com/claims</xsd1:dialectURI>
            
              <xsd1:displayOrder>2</xsd1:displayOrder>
            
              <xsd1:displayTag>Last Name</xsd1:displayTag>
            
              <xsd1:readOnly>false</xsd1:readOnly>
            
              <xsd1:regEx></xsd1:regEx>
            
              <xsd1:required>false</xsd1:required>
            
              <xsd1:supportedByDefault>false</xsd1:supportedByDefault>
            
              <xsd1:value></xsd1:value>
           </xsd1:claim>
         
           <xsd1:mappedAttribute>lastname</xsd1:mappedAttribute>

           <!--Zero or more repetitions:-->
           <xsd1:mappedAttributes>
            
              <xsd1:attributeName>surname</xsd1:attributeName>
            
              <xsd1:domainName>WSO2.COM</xsd1:domainName>
           </xsd1:mappedAttributes>
        </xsd:claimMappingDTO>
     </xsd:addNewClaimMapping>
  </soapenv:Body>
</soapenv:Envelope>

These operations are one-way operations [5] and upon successfully adding the claim it will not produce SOAP output.

We can view the claim from the management console as shown below.  

We also can verify by querying the UM_CLAIM table.



We can update an existing claim by calling upateClaimMapping method. This is a sample SOAP request for updating an existing claim mapping.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd" xmlns:xsd1="http://dto.mgt.claim.carbon.wso2.org/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:upateClaimMapping>
      
        <xsd:claimMappingDTO>
         
           <xsd1:claim>
            
              <xsd1:checkedAttribute>false</xsd1:checkedAttribute>
            
              <xsd1:claimUri>http://mydialect.com/claims/email</xsd1:claimUri>
            
              <xsd1:description>User Email Address</xsd1:description>
            
              <xsd1:dialectURI>http://mydialect.com/claims</xsd1:dialectURI>
            
              <xsd1:displayOrder>1</xsd1:displayOrder>
            
              <xsd1:displayTag>UserEmail</xsd1:displayTag>
            
              <xsd1:readOnly>false</xsd1:readOnly>
            
              <xsd1:regEx></xsd1:regEx>
            
              <xsd1:required>true</xsd1:required>
            
              <xsd1:supportedByDefault>true</xsd1:supportedByDefault>
            
              <xsd1:value></xsd1:value>
           </xsd1:claim>
         
           <xsd1:mappedAttribute>givenname</xsd1:mappedAttribute>
           <!--Zero or more repetitions:-->
           <xsd1:mappedAttributes>
            
              <xsd1:attributeName>useremail</xsd1:attributeName>
            
              <xsd1:domainName>WSO2.COM</xsd1:domainName>
           </xsd1:mappedAttributes>
        </xsd:claimMappingDTO>
     </xsd:upateClaimMapping>
  </soapenv:Body>
</soapenv:Envelope>

We can view the claim in management console and verify that the claim is correctly updated.
When we query the UM_CLAIM table, we see the values are correctly updated for the particular claim.

We can delete an existing claim by calling the removeClaimMapping method. We need to provide the dialectUri and the claimUri of the claim in the SOAP request in order to delete a particular claim. This is a sample SOAP request.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:removeClaimMapping>
        <xsd:dialectUri>http://mydialect.com/claims</xsd:dialectUri>
        <xsd:claimUri>http://mydialect.com/claims/email</xsd:claimUri>
     </xsd:removeClaimMapping>
  </soapenv:Body>
</soapenv:Envelope>

Upon sending the SOAP request we can see that the claim is successfully deleted.

We can also query the UM_CLAIM table and verify this.

In order to delete a claim dialect, we can use the removeClaimDialect method. Here we need to specify the dialectUri of the claim dialect to be deleted. This is a sample SOAP request.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://org.apache.axis2/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <xsd:removeClaimDialect>
        <xsd:dialectUri>http://mydialect.com/claims</xsd:dialectUri>
     </xsd:removeClaimDialect>
  </soapenv:Body>
</soapenv:Envelope>

Upon deleting the claim dialect, we can see the deleted dialect uri is not visible in the management console.

Deleting a claim dialect deletes all the associated claims in that dialect. If we query the UM_CLAIM table by giving the dialect ID, we see all the claims in the deleted dialect are no longer there.

However if you query the UM_DIALECT table, you will still see the record of the claim dialect which we deleted. This is a known issue [6] in Identity Server 5.0.0 version and will be fixed in a later version.

References :


Tharindu Edirisinghe
Identity Server Team
WSO2

1 comment:

  1. Hey,
    Thank you for sharing such an amazing and informative post. Really enjoyed reading it. :)

    Apu

    Claims Management Service

    ReplyDelete