Wednesday, January 20, 2016

Self Sign Up for User Accounts with WSO2 Identity Server

WSO2 Identity Server provides the capability of self registration of users where a new user can create a user account in the Identity Server by himself/herself rather than letting the administrator create an account for them. Upon creating the account, the user will receive an email (to the email address provided during registration) which contains a confirmation code. Using this confirmation code, the user can verify the account and get it activated.  

This blog post provides a step by step guide for the Self Sign Up feature in WSO2 Identity Server. For this demonstration I am using the Identity Server 5.1.0 (official documentation is available in [1]). If you are using the Identity Server 5.0.0 version, you can still follow this post but there are some configuration file location changes which you can get to know by following [2].

First, we need to configure the Identity Management related properties as given below.
Modify the wso2is-5.1.0/repository/conf/identity/identity-mgt.properties file with below values for the properties.

Notification.Sending.Internally.Managed=true
This enables the internal email sending module. If false, the email sending data is available to the application via a Web service. Thus the application can send the email using its own email sender.
Authentication.Policy.Account.Lock.On.Creation=true
Upon a user signs up, the account will be locked by default until the user verifies the account by providing the confirmation code received via email.
Notification.Expire.Time=7200
The validity period in minutes for the confirmation code received by the user via email. Within the specified time period, the user has to verify the newly created account by providing the confirmation code.
Notification.Sending.Enable=true
This enables the email sending function when recovering the account and verifying the user creation.
Authentication.Policy.Enable=true
This enables the authentication flow level checks for the account lock and account confirmation features. You must enable this to make the account confirmation feature work.

Then we need to enable the IdentityMgtEventListener which listens to the Identity Management related activities.  For that, modify the wso2is-5.1.0/repository/conf/identity/identity.xml file with below.

<EventListener type="org.wso2.carbon.user.core.listener.UserOperationEventListener" name="org.wso2.carbon.identity.mgt.IdentityMgtEventListener" orderId="50" enable="true"/>

Next step is to set the template of the email received by a user upon registering an account with Self Sign Up feature. If you want to have a common template across all the tenants, you can modify the wso2is-5.1.0/repository/conf/email/email-admin-config.xml file and define following template.

<configuration type="accountConfirmation">
<targetEpr></targetEpr>
   <subject>WSO2 Carbon - Account Confirmation</subject>
   <body>
Hi {first-name},

You have created an account with following user name

User Name: {first-name}

Please click the following link to unlock. If clicking the link doesn't seem to work, you can copy and paste the
link into your browser's address window.

https://localhost:8443/InfoRecoverySample/confirmReg?confirmation={confirmation-code}&amp;userstoredomain={userstore-domain}&amp;username={user-name}&amp;tenantdomain={tenant-domain}
   </body>
   <footer>
Best Regards,
WSO2 Identity Server Team
http://www.wso2.com
   </footer>
   <redirectPath></redirectPath>
</configuration>

You can use the following placeholders in the email template which will be replaced by the user’s claims (except for the confirmation-code) when the email is sent to the user.

{first-name}
{confirmation-code}
{userstore-domain}
{user-name}
{tenant-domain}

You can also provide a URL of a client web application with these placeholder values as query parameters where the user can click the link to get the account activated.


Note :
If you are modifying the email-admin-config.xml file and needs to add the ‘&’ sign (for separating query parameters in a URL), then you must use ‘&amp’ to avoid breaking the XML syntax. However if you are setting the email template using the management console, then you can straightaway use ‘&’ without any issue.

You can also modify the email template using the management console which would change the template only for the particular tenant where the admin is logged in. For that, you can go to Configure -> Email Templates -> Account Confirm in the Management Console and set the template.

Next step is providing the email account settings which the Identity Server uses for sending out emails to the end users who gets registered.  For that, enabled the transportSender as below in <IS_HOME>/repository/conf/axis/axis2.xml file. Here I have given sample configurations for a Gmail account. You can use the settings related to your email service provider here.

<transportSender name="mailto"
                    class="org.apache.axis2.transport.mail.MailTransportSender">
       <parameter name="mail.smtp.from">[email protected]</parameter>
       <parameter name="mail.smtp.user">[email protected]</parameter>
       <parameter name="mail.smtp.password">mypassword</parameter>
       <parameter name="mail.smtp.host">smtp.gmail.com</parameter>
       <parameter name="mail.smtp.port">587</parameter>
       <parameter name="mail.smtp.starttls.enable">true</parameter>
       <parameter name="mail.smtp.auth">true</parameter>
</transportSender>

Next step is to add the http://wso2.org/claims/identity/accountLocked claim. For that you can modify the <IS_HOME>/repository/conf/claim-config.xml file adding the following claim. Here you can change the AttributeID value to an attribute supported by your underlying userstore. However if you modify this file, the change is affected to all the tenants created afterwards.  

          <Claim>
              <ClaimURI>http://wso2.org/claims/identity/accountLocked</ClaimURI>
                  <DisplayName>Account Locked</DisplayName>
          <!-- Proper attribute Id in your user store must be configured for this -->
                  <AttributeID>accountLock</AttributeID>
                  <Description>Account Locked</Description>
 </Claim>

You can set this claim by login into the Management Console as the particular tenant’s admin which would add the claim only to that tenant. For that, go to Main -> Claims -> List -> http://wso2.org/claims and if this claim is not already there, add it.




After setting all the above mentioned configuration, restart the Identity Server (for the configuration steps done with Management Console, you can do after restarting the server).

The admin service related to this feature is UserInformationRecoveryService [3]. Using a SOAP client such as SOAP UI, you can try out this feature.

First step is to call the getUserIdentitySupportedClaims operation by providing the WSO2 Carbon default dialect (http://wso2.org/claims). Following is the sample SOAP request.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.mgt.identity.carbon.wso2.org">
  <soapenv:Header/>
  <soapenv:Body>
     <ser:getUserIdentitySupportedClaims>
        <ser:dialect>http://wso2.org/claims</ser:dialect>
     </ser:getUserIdentitySupportedClaims>
  </soapenv:Body>
</soapenv:Envelope>

Then you will receive a SOAP response similar to following (or vary based on the claims set as ‘supported by default’ in your setup). These are the claims that are appearing in the user profile which you can specify when creating the user account. (For more information on Claim Management operations, follow [4]).

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
     <ns:getUserIdentitySupportedClaimsResponse xmlns:ns="http://services.mgt.identity.carbon.wso2.org" xmlns:ax2309="http://mgt.identity.carbon.wso2.org/xsd" xmlns:ax2310="http://base.identity.carbon.wso2.org/xsd" xmlns:ax2313="http://beans.mgt.captcha.carbon.wso2.org/xsd" xmlns:ax2315="http://beans.mgt.identity.carbon.wso2.org/xsd" xmlns:ax2316="http://dto.mgt.identity.carbon.wso2.org/xsd" xmlns:ax2317="http://util.java/xsd">
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/telephone</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/mobile</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/country</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/streetaddress</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/url</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/givenname</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/emailaddress</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/im</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/organization</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
        <ns:return xsi:type="ax2316:UserIdentityClaimDTO" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2316:claimUri>http://wso2.org/claims/lastname</ax2316:claimUri>
           <ax2316:claimValue xsi:nil="true"/>
        </ns:return>
     </ns:getUserIdentitySupportedClaimsResponse>
  </soapenv:Body>
</soapenv:Envelope>

Now we know what are the claim URIs supported in the user profile. Out of them we can specify the claims we need when signing up for the new account. For that, call the registerUser method. Here it is a must that we use the http://wso2.org/claims/emailaddress claim because upon creating the account, Identity Server is sending the email to the address given in this claim for the user to get the account activated. The tenantDomain is the tenant where we need to create the user account.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.mgt.identity.carbon.wso2.org" xmlns:xsd="http://dto.mgt.identity.carbon.wso2.org/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <ser:registerUser>
        <ser:userName>tharindu</ser:userName>
        <ser:password>admin@WSO2</ser:password>
      
        <!--one or more repetitions:-->
        <ser:claims>
           <xsd:claimUri>http://wso2.org/claims/givenname</xsd:claimUri>
           <xsd:claimValue>tharindu</xsd:claimValue>
        </ser:claims>

        <ser:claims>
           <xsd:claimUri>http://wso2.org/claims/lastname</xsd:claimUri>
           <xsd:claimValue>edirisinghe</xsd:claimValue>
        </ser:claims>

        <ser:claims>
           <xsd:claimUri>http://wso2.org/claims/emailaddress</xsd:claimUri>
           <xsd:claimValue>[email protected]</xsd:claimValue>
        </ser:claims>
      
        <ser:profileName>default</ser:profileName>
        <ser:tenantDomain>carbon.super</ser:tenantDomain>
     </ser:registerUser>
  </soapenv:Body>
</soapenv:Envelope>

If the account is created successfully, we receive the following response. Here we receive the Confirmation Code of the account in the key element. The end user will receive the same in the email received.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
     <ns:registerUserResponse xmlns:ns="http://services.mgt.identity.carbon.wso2.org">
        <ns:return xsi:type="ax2315:VerificationBean" xmlns:ax2309="http://mgt.identity.carbon.wso2.org/xsd" xmlns:ax2310="http://base.identity.carbon.wso2.org/xsd" xmlns:ax2313="http://beans.mgt.captcha.carbon.wso2.org/xsd" xmlns:ax2315="http://beans.mgt.identity.carbon.wso2.org/xsd" xmlns:ax2316="http://dto.mgt.identity.carbon.wso2.org/xsd" xmlns:ax2317="http://util.java/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
           <ax2315:error xsi:nil="true"/>
           <ax2315:key>5bcaaa2c-42d7-45e9-be06-3e02e91e2520</ax2315:key>
           <ax2315:notificationData xsi:nil="true"/>
           <ax2315:redirectPath xsi:nil="true"/>
           <ax2315:userId>tharindu</ax2315:userId>
           <ax2315:verified>true</ax2315:verified>
        </ns:return>
     </ns:registerUserResponse>
  </soapenv:Body>
</soapenv:Envelope>

This is the email received by the end user. We can see that the placeholders we had given in the email template are replaced by the claim values of the user.



Now that we have received the confirmation code, we can get the account verified and activated. If you have enabled Captcha Verification by setting the following property in identity-mgt.properties file, follow [5] to call getCaptcha() method and find the captcha answer.

Captcha.Verification.Internally.Managed=true

If you have disabled captcha verification, skip the above step.

Next step is to call the confirmUserSelfRegistration method. Here we to use the confirmation code received via email in the code tag. The captcha information is needed only if you have enabled captcha verification.  The tenantDomain is the tenant where the user is registered in. Here is a sample SOAP request.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.mgt.identity.carbon.wso2.org" xmlns:xsd="http://beans.mgt.captcha.carbon.wso2.org/xsd">
  <soapenv:Header/>
  <soapenv:Body>
     <ser:confirmUserSelfRegistration>
        <ser:username>tharindu</ser:username>
        <ser:code>5bcaaa2c-42d7-45e9-be06-3e02e91e2520</ser:code>

        <ser:captcha>             
<xsd:imagePath>registry/resource/_system/config/repository/components/org.wso2.carbon.captcha-images/9704ed77-652f-4eac-af90-6f78cacfbe54.jpg</xsd:imagePath>
           <xsd:secretKey>9704ed77-652f-4eac-af90-6f78cacfbe54</xsd:secretKey>
           <xsd:userAnswer>xmn4f</xsd:userAnswer>
        </ser:captcha>

        <ser:tenantDomain>carbon.super</ser:tenantDomain>
     </ser:confirmUserSelfRegistration>
  </soapenv:Body>
</soapenv:Envelope>

Upon successful verification of the confirmation code for the account (and captcha information if captcha is enabled), we receive the following response.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
     <ns:confirmUserSelfRegistrationResponse xmlns:ns="http://services.mgt.identity.carbon.wso2.org">
        <ns:return xsi:type="ax2318:VerificationBean" xmlns:ax2309="http://mgt.identity.carbon.wso2.org/xsd" xmlns:ax2319="http://util.java/xsd" xmlns:ax2310="http://base.identity.carbon.wso2.org/xsd" xmlns:ax2313="http://beans.mgt.captcha.carbon.wso2.org/xsd" xmlns:ax2316="http://dto.mgt.identity.carbon.wso2.org/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ax2318="http://beans.mgt.identity.carbon.wso2.org/xsd">
           <ax2318:error xsi:nil="true"/>
           <ax2318:key xsi:nil="true"/>
           <ax2318:notificationData xsi:nil="true"/>
           <ax2318:redirectPath xsi:nil="true"/>
           <ax2318:userId xsi:nil="true"/>
           <ax2318:verified>true</ax2318:verified>
        </ns:return>
     </ns:confirmUserSelfRegistrationResponse>
  </soapenv:Body>
</soapenv:Envelope>

Now we can login to the Management Console of the Identity Server and check if the user account is successfully activated. (If the user still cannot login to the management console, check if the user has login permission)



References


Tharindu Edirisinghe
Platform Security Team
WSO2