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">tharinduatwso2@gmail.com</parameter>
       <parameter name="mail.smtp.user">tharinduatwso2@gmail.com</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>tharinduatwso2@gmail.com</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

9 comments:

  1. Thank you. Much clearer than the official documentation.

    ReplyDelete
  2. Hi,

    Is there any way to use this feature with SMS OTP. I mean to say that, post user registration, user should unlock his account by SMS OTP.

    Thanks,
    Azim

    ReplyDelete
    Replies
    1. Hello Azim,

      Yes it is possible with some custom implementation. I can help you to do that. So in your case, the requirement is that instead of receiving the confirmation code via email, an SMS should be sent and the user can enter the code received in SMS and get the account activated. Am I correct ?

      Delete
  3. Hello Tharindu,

    I am creating users through SCIM APIs. I setup the configuration correctly, rechecked it several times for sending notifications to confirm the account etc. I setup my SMTP server details correctly, I am not receiving emails when I create a new user through SCIM. It is created successfully, I can see it in the admin. In the logs I did not see anything about sending an email for confirmation. In the logs it says accountLocked is true. I could not login with newly created user because it says account is locked.

    I did an experiment with Temporary Password Enable option, I created the user without password, I got the email with link to set the password. That means email sending part is working.

    I am using IS 5.2.0 stand alone, out of the box configuration. Please let me know what else I am missing.

    Thanks
    Ravi Ada

    ReplyDelete
  4. In IS 5.3.0, self signup with email notifications supported only in UserInfoRecoveryService Soap API, it is not supported in SCIM.

    That deature is added In IS 5.3.0 which will be released soon,

    Thanks
    Isura

    ReplyDelete
    Replies
    1. So I am using IS 5.2 - I am using RemoteUserStoreManagerServiceStub::AddUSer to create user. And similar to the issue above, the user is not receiving the account activation email. Is there a way out of this - or do I have to switch to 5.3.0?

      Thanks in advance

      Delete
  5. Hello Tharindu, sorry to trouble you but I am kind of stuck on this issue. I ran out of stackoverflow and don't what else I could try. I would imagine this is a very well implemented functionality, none of the other people seemed to have this issue. Only one of even which is "temporary password" is working (getting email to set the password). Would it be possible to point me to the right direction?

    Thanks

    ReplyDelete
  6. Thank you Isura for the response. I tried SOAP APIs also from this example (https://github.com/tukobit/readpermission) but no success so far. The only this that works is the temporary password through SCIM. I am surprised that no one seems to complain about this feature which is basically needed for all self register type of integrations. Anyways I will wait for 5.3.0, do you know when this will be released? If I build from sources, does this feature available?

    Thanks
    Ravi Ada

    ReplyDelete
  7. Hi,

    I have installed WSO2 API Manager 2.1.0
    I am trying to do this with custom defined claims.
    But I am getting following error.

    Caused by: org.wso2.carbon.user.core.UserStoreException: org.wso2.carbon.user.core.UserStoreException: Mapped attribute cannot be found for claim : http://wso2.org/claims/givenname in user store : PRIMARY
    at org.wso2.carbon.user.core.common.AbstractUserStoreManager.callSecure(AbstractUserStoreManager.java:172)
    at org.wso2.carbon.user.core.common.AbstractUserStoreManager.getUserClaimValues(AbstractUserStoreManager.java:731)
    at org.wso2.carbon.identity.mgt.util.Utils.getClaimFromUserStoreManager(Utils.java:189)
    ... 59 more
    Caused by: java.security.PrivilegedActionException: java.lang.reflect.InvocationTargetException
    at java.security.AccessController.doPrivileged(Native Method)
    at org.wso2.carbon.user.core.common.AbstractUserStoreManager.callSecure(AbstractUserStoreManager.java:162)
    ... 61 more

    I checked the claims and it has mapping mapped attribute to value cn.
    Following is the snippet of my claim-config.xml We have renamed the OpenId dialect with http://wso2.org/claims.


    given_name
    Given Name
    cn
    Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters.
    3

    http://wso2.org/claims/fullname


    Can you please direct me on the issue and exception that I am getting?

    ReplyDelete