Friday, May 1, 2015

A Workaround for Renaming Username of Existing Users in JDBC Userstores of WSO2 Identity Server

WSO2 Identity Server 5.0.0 currently does not support renaming users in the existing UserStores through the UserStore Management APIs it exposes. However if it is required to rename existing users in a userstore, it can be achieved through a workaround which is demonstrated here. This example shows how to write a custom JDBC UserStoreManager that provides capability of renaming the usernames of the users in the UserStore.

The source code of this sample is available in git repository [1] and the source path is [2]. Once you build the source, you get the ‘org.wso2.sample.user.store.manager-1.0.jar’ file which should be put in <IS_HOME>/repository/components/dropins directory. If you do not want to build from source and try out the sample, the built jar can be found in [3].

In this example, I am using this custom userstore as a secondary userstore inside the Identity Server. It is also possible to use this as the primary userstore as well. I am using a MySQL database and therefore the JDBC MySQL connector [4] jar file should be placed in the <IS_HOME>/repository/components/lib directory for the Identity Server to access the database. (Restart the server after copying)

Login to the Management Console of the Identity Server as the admin. Add a Secondary UserStore.


If the custom JDBC userstore is correctly deployed, you should see the org.wso2.sample.user.store.manager.CustomUserStoreManager in the User Store Manager Class dropdown in the UserStore configuration.

Set the configurations as following. I am using wso2.com as the domain name of the secondary userstore. I have already created a database with the name ‘userstore’ in MySQL server. I provide the connection url according to that for connecting the database with the userstore.

Once you expand the Optional properties of the userstore, you can see ‘Username Rename Claim URI’. We are renaming the username of the users using a claim. Here you can define any claim uri where you have to add a Claim later with the same Claim URI. Once the configuration is set, add the userstore.


Go to http://wso2.org/claims Claim Dialect.


Add a new Claim Mapping.


Give the same Claim URI which was defined in the UserStore added previously. For the mapped attribute, any name can be specified because this claim is specially handled in the custom userstore manager. Mark the ‘Supported by Default’ as checked so that this attribute appears in the Users’ profile. Add the claim.

Now go to ‘Users and Roles’.
Add a new user.


As the domain, select the secondary userstore created previously.



You can see the user is successfully created.


If you query the database and list the user in UM_USER table, you can see the user is successfully added.


Next step is to add a Role in the same userstore.

Add a new role.


Select the domain as the secondary userstore we created.

Here I am granting all permissions just for the demonstration.


Assign the previously created user to the role.


Login to the Management Console of the Identity Server with this user. (Since the user’s role was given all permissions, user can login to the management console as the Login permission is also granted along with them)



The user can successfully login.


Next step is to rename the user. Login to the management console as admin and list the users. Go to the User Profile of the particular user in this userstore.


As the available user profiles, ‘default’ profile is listed. Click on that.

Initially the attributes will be empty. Fill in the required fields so that we can save the profile. You can see the UserName attribute here. That is coming from the claim we defined previously. If you fill any name here, the custom userstore manager will rename this user with the name given here. If you leave it blank, only the other claims will be updated and username will not be changed. Here I give a new name and update the profile.


Now when I list the users, I can see that the username of the user is renamed.


If I query the UM_USER table, this change is reflected in the database as well.


Now I try to login to the management console with the new username.

I can successfully login.


In the custom userstore manager, I have extended the org.wso2.carbon.user.core.jdbc.JDBCUserStoreManager class and overridden the doSetUserClaimValue and doSetUserClaimValues methods. If you update the user's profile from the management console, it will call the doSetUserClaimValues method. If you are calling these methods form the service using SOAP UI or a similar client, you can call either of them. These methods receive the user’s claim/s in the profile as a parameter and in the claims map, it is checking whether it contains the particular Claim URI defined in the properties of the userstore. (The default claim uri is http://wso2.org/claims/userName). If a value is received for this claim, it directly updates the UM_USER_NAME column of the UM_USER table for the particular user. (If the new name received for renaming the user is already existing in the database, it will throw an exception and in the management console, it will display an error message)



Note :

This solution works successfully when SCIM is disabled for the userstore from the user store properties as following. (For primary userstores, in <IS_HOME>/repository/conf/user-mgt.xml file. For secondary userstores, in <IS_HOME>/repository/deployment/server/userstores/<userstorename.xml> file)

<Property name="SCIMEnabled">false</Property>

If SCIM is Enabled, you can call the web services from a SOAP client and get the username renamed, however if you use management console for updating the profile, you may get an error.

If it is needed to provide SCIM support, org.wso2.carbon.identity.scim.common component will need to be patched.

If you are setting the up as the primary userstore of the Identity Server, following configuration should be added in the <IS_HOME>/repository/conf/user-mgt.xml file.

<UserStoreManager class="org.wso2.sample.user.store.manager.CustomUserStoreManager">
           <Property name="TenantManager">org.wso2.carbon.user.core.tenant.JDBCTenantManager</Property>
       <Property name="ReadOnly">false</Property>
           <Property name="MaxUserNameListLength">100</Property>
           <Property name="IsEmailUserName">false</Property>
           <Property name="DomainCalculation">default</Property>
           <Property name="PasswordDigest">SHA-256</Property>
           <Property name="StoreSaltedPassword">true</Property>
           <Property name="ReadGroups">true</Property>
       <Property name="WriteGroups">true</Property>
           <Property name="UserNameUniqueAcrossTenants">false</Property>
           <Property name="PasswordJavaRegEx">^[\S]{5,30}$</Property>
           <Property name="PasswordJavaScriptRegEx">^[\S]{5,30}$</Property>
       <Property name="UsernameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
       <Property name="UsernameJavaScriptRegEx">^[\S]{3,30}$</Property>
       <Property name="RolenameJavaRegEx">^[^~!#$;%^*+={}\\|\\\\&lt;&gt;,\'\"]{3,30}$</Property>
       <Property name="RolenameJavaScriptRegEx">^[\S]{3,30}$</Property>
           <Property name="UserRolesCacheEnabled">true</Property>
           <Property name="MaxRoleNameListLength">100</Property>
           <Property name="MaxUserNameListLength">100</Property>
       <Property name="SharedGroupEnabled">false</Property>
           <Property name="SCIMEnabled">false</Property>
     <Property name="UserNameRenameClaim">http://wso2.org/claims/userName</Property>

You can also rename the username by updating the claims of the user by calling the following Admin Service from a client like SOAP UI.


If you are calling the setUserClaimValue method, the SOAP request is as following.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.ws.um.carbon.wso2.org">
  <soapenv:Header/>
  <soapenv:Body>
     <ser:setUserClaimValue>
        <!--Optional:-->
        <ser:userName>EXISTING_NAME</ser:userName>
        <!--Optional:-->
        <ser:claimURI>http://wso2.org/claims/userName</ser:claimURI>
        <!--Optional:-->
        <ser:claimValue>NEW_NAME</ser:claimValue>
        <!--Optional:-->
        <ser:profileName>default</ser:profileName>
     </ser:setUserClaimValue>
  </soapenv:Body>
</soapenv:Envelope>

If you are calling the setUserClaimValues method, SOAP request is as follows. If you are updating other claims, you can include another set of <ser:claims> tags in the request.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.ws.um.carbon.wso2.org" xmlns:xsd="http://common.mgt.user.carbon.wso2.org/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <ser:setUserClaimValues>
        <!--Optional:-->
        <ser:userName>EXISTING_NAME</ser:userName>
        <!--Zero or more repetitions:-->
        <ser:claims>
           <!--Optional:-->
           <xsd:claimURI>http://wso2.org/claims/userName</xsd:claimURI>
           <!--Optional:-->
           <xsd:value>NEW_NAME</xsd:value>
        </ser:claims>
        <!--Optional:-->
        <ser:profileName>default</ser:profileName>
     </ser:setUserClaimValues>
  </soapenv:Body>
</soapenv:Envelope>


There are features like Account Lock feature in Identity Server which keeps data in UM_USER_ATTRIBUTE or IDN_IDENTITY_USER_DATA table along with the username. If you are using such features, you will need to update those records as well when renaming the username.

References :





Tharindu Edirisinghe
Identity Server Team
WSO2

No comments:

Post a Comment