Skip to main content

Setting challenge questions of users in WSO2 Identity Server using WSO2 ESB

WSO2 Identity server provides the capability to recover user accounts with the help of security questions. This feature is important when we forget the password and need some evidence that the actual user who had forgotton the password is indeed the right owner of the account.

There are three such ways in which we can set these challenge questions for the users. You can read more details about each of these methods in this documentation.
  • From the UserIdentityManagementAdminService SOAP API
  • By manually creating registry resources for questions
  • From Identity Server Management Console

In this blog I will be guiding you through how to use the UserIdentityManagementAdminService SOAP API to set the challenge questions. But we will be doing this with a slight twist. We are going to set these questions using an API created in the WSO2 ESB with the help of some custom sequences. 


For the setting of the challenge questions using the admin service this is the soap message which is expected by the IS as the request payload.

<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:setChallengeQuestionsOfUser>
    <ser:userName>shenavi</ser:userName>
    <!--Zero or more repetitions:-->
    <ser:challengesDTOs>
        <xsd:answer>pasta</xsd:answer>
        <xsd:id>http://wso2.org/claims/challengeQuestion1</xsd:id>
        <xsd:order>0</xsd:order>
        <xsd:primary>false</xsd:primary>
        <xsd:question>Favorite food ?</xsd:question>
        <xsd:verfied>false</xsd:verfied>
    </ser:challengesDTOs>
<ser:challengesDTOs>
<xsd:answer>cricket</xsd:answer>
        <xsd:id>http://wso2.org/claims/challengeQuestion2</xsd:id>
        <xsd:order>1</xsd:order>
        <xsd:primary>false</xsd:primary>
        <xsd:question>Favorite sport ?</xsd:question>
        <xsd:verfied>false</xsd:verfied>
 </ser:challengesDTOs>

</ser:setChallengeQuestionsOfUser>

</soapenv:Body>


</soapenv:Envelope>
And this is the soap payload which is returned on success of setting the challenge questions

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
         <ns:setChallengeQuestionsOfUserResponsexmlns:ns="http://services.mgt.identity.carbon.wso2.org">
             <ns:return xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
         </ns:setChallengeQuestionsOfUserResponse>
   </soapenv:Body>
</soapenv:Envelope>
If you need to set the challenge questions of a particular user by passiing the set of questions and the input parameters as a JSON string and need to write some transformation logic so that it constructs the needed payload then you will need to do a message transformation in order to get it done. 

This is the information which we have about the user. And the answers to the challenge questions as a JSON string. Let's see how we can pass this data and convert it to a format in which it will send the request to the UserIdentityManagementAdminService and set the challenge questions for the user.

{
     "userName": "testUser",
     "challengesDTOArray":{
 "challengesDTOs": [{
   "answer": "pasta",
   "error": "false",
   "id": "http://wso2.org/claims/challengeQuestion1",
   "key": "true",
   "order": "0",
   "primary": "false",
   "question": "Favorite food ?",
   "verfied": "false"
  }, {
   "answer": "cricket",
   "error": "false",
   "id": "http://wso2.org/claims/challengeQuestion2",
   "key": "true",
   "order": "1",
   "primary": "false",
   "question": "Favorite sport ?",
   "verfied": "false"
  }
 ]
     }
}

Now that you have an idea of what we need to achieve let's take a look at how it can be done.For this tutorial I will be using the IS 5.1.0 version and the ESB 4.9.0 but this feature is supported for older versions as well. You can download these products from http://wso2.com/products/identity-server/ and http://wso2.com/products/enterprise-service-bus/.

So let's get started.

Steps

1. Let's name the IS distribution as IS_HOME and the esb distribution as ESB_HOME. Set the port offset of the ESB server to 1. 

2. You must set the following property to false in the <IS_HOME>/repository/conf/carbon.xml file to view the WSDLs of the services.

 <HideAdminServiceWSDLs>false</HideAdminServiceWSDLs>


3. Start both the ESB and the IS servers

4. In the esb create a local entry [1] with an inline xml and add the contents below to it and save it. Mention the name of the local entry key as transformPayload. You can follow this link on how to add a local entry


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//challengesDTOArray">
<xsl:copy-of select="@*|node()"/>
</xsl:template>
</xsl:stylesheet>


5. Create a new sequence in the ESB and name it as ForEachSequence. This sequence would iterate through the provided json payload above and construct the challengesDTOs elements iteratively. The following is the contents of the sequence ForEachSequence.xml.


<sequence name="ForEachSequence" xmlns="http://ws.apache.org/ns/synapse">
<foreach expression="//challengesDTOArray/challengesDTOs"
id="testtForEach" xmlns:ns="http://org.apache.synapse/xsd">
<sequence>
<payloadFactory media-type="xml">
<format>
<ser:challengesDTOs
xmlns:ser="http://services.mgt.identity.carbon.wso2.org" xmlns:xsd="http://dto.mgt.identity.carbon.wso2.org/xsd">
<xsd:answer>$1</xsd:answer>
<xsd:error>$2</xsd:error>
<xsd:id>$3</xsd:id>
<xsd:key>$4</xsd:key>
<xsd:order>$5</xsd:order>
<xsd:primary>$6</xsd:primary>
<xsd:question>$7</xsd:question>
<xsd:verfied>$8</xsd:verfied>
</ser:challengesDTOs>
</format>
<args>
<arg evaluator="json" expression="$.challengesDTOs.answer"/>
<arg evaluator="json" expression="$.challengesDTOs.error"/>
<arg evaluator="json" expression="$.challengesDTOs.id"/>
<arg evaluator="json" expression="$.challengesDTOs.key"/>
<arg evaluator="json" expression="$.challengesDTOs.order"/>
<arg evaluator="json" expression="$.challengesDTOs.primary"/>
<arg evaluator="json" expression="$.challengesDTOs.question"/>
<arg evaluator="json" expression="$.challengesDTOs.verfied"/>
</args>
</payloadFactory>
</sequence>
</foreach>
<log level="full"/>
</sequence>



6. Create another sequence which would be the in sequence we would be using for the API. Name the sequence as sendInSequence and add the contents of the in sequence as mentioned below. This in sequence will call the ForEachSequence within it and then construct the final payload format needed to be sent to the identity server to set the user's challenge questions. Note that from this sequences we are calling the service https://localhost:9443/services/UserIdentityManagementAdminService which will accept and set these challenge questions.

<sequence name="sendInSequence" xmlns="http://ws.apache.org/ns/synapse">
    <sequence key="ForEachSequence"/>
    <payloadFactory media-type="xml">
        <format>
            <soapenv:Envelope
                xmlns:ser="http://services.mgt.identity.carbon.wso2.org"
                xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://dto.mgt.identity.carbon.wso2.org/xsd">
                <soapenv:Header/>
                <soapenv:Body>
                    <ser:setChallengeQuestionsOfUser>
                        <ser:userName>$1</ser:userName>
                        <!--Zero or more repetitions:-->
                                $2
                        </ser:setChallengeQuestionsOfUser>
                </soapenv:Body>
            </soapenv:Envelope>
        </format>
        <args>
            <arg evaluator="xml" expression="//jsonObject/userName" xmlns:ns="http://org.apache.synapse/xsd"/>
            <arg evaluator="xml"
                expression="//jsonObject/challengesDTOArray"
                xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://services.mgt.identity.carbon.wso2.org"/>
        </args>
    </payloadFactory>
    <xslt key="transformPayload"/>
    <log level="full"/>
    <header name="SOAPAction" scope="transport" value="urn:setChallengeQuestionsOfUser"/>
    <property name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>
    <property
        expression="fn:concat('Basic ', base64Encode('admin:admin'))"
        name="Authorization" scope="transport" xmlns:ns="http://org.apache.synapse/xsd"/>
    <send>
        <endpoint>
            <address format="soap12" trace="disable" uri="https://localhost:9443/services/UserIdentityManagementAdminService"/>
        </endpoint>
    </send>
</sequence>


7. Next create a simple out sequence and name it as sendOutSequence and add the contents below to it.

<sequence name="sendOutSequence" xmlns="http://ws.apache.org/ns/synapse">
    <log level="custom">
        <property name="OutSequence" value="*** In the out sequence ***"/>
    </log>
    <send/>
</sequence>


Now that we have created the needed sequences to carry out this task. Lets create an API so we can invoke this API and create the recovery questions in the IS.

8. Create an API with a URI template of "/*" and with the http POST method and name it as ChallengeQuestionsAPI. The contents of the API is included below.


<api xmlns="http://ws.apache.org/ns/synapse" name="ChallengeQuestionsAPI" context="/info">
  <resource methods="POST" uri-template="/*" inSequence="sendInSequence" outSequence="sendOutSequence"/>
</api>


9. Now in order to test the scenario set up the claims as per the documentation [1] and create a user as "testUser" in the identity server.

10. Save the payload below in a file and name is as sampleRequest.txt.



{
     "userName": "testUser",
     "challengesDTOArray":{
 "challengesDTOs": [{
   "answer": "pasta",
   "error": "false",
   "id": "http://wso2.org/claims/challengeQuestion1",
   "key": "true",
   "order": "0",
   "primary": "false",
   "question": "Favorite food ?",
   "verfied": "false"
  }, {
   "answer": "cricket",
   "error": "false",
   "id": "http://wso2.org/claims/challengeQuestion2",
   "key": "true",
   "order": "1",
   "primary": "false",
   "question": "Favorite sport ?",
   "verfied": "false"
  }
 ]
     }
}

11. Then you can invoke the API using the command below and observe that the recovery questions have been updated for the user testUser created before.
curl -k -X POST --header 'Content-Type: application/json' -d '@/(path_to_file)/sampleRequest.txt' -k -v http://172.17.0.1:8281/info

12. Next in order to verify this has been created lets log in with the new user to the identity dashboard using this link. And select the 'Account Recovery' option. You will see the challenge questions has been set successfully.




We have successfully set the challenge questions of the User in the identity server using an API created from ESB. Hope this post was useful to you.



Comments

Popular posts from this blog

Processing large payloads with the esb script mediator iteratively

Overview WSO2 ESB uses Rhino engine to execute JavaScripts. Rhino engine converts the script to a method inside a Java class. Therefore, when processing large JSON data volumes, the code length must be less than 65536 characters, since the Script mediator converts the payload into a Java object. However, you can use the following alternative options to process large JSON data volumes. The script mediator which is used in ESB is powered by the Rhino engine. Therefore, when processing large JSON data volumes, the code length must be less than 65536 characters which is a limitation in the script mediator being used in the esb versions less than 5.0.0. In ESB 5.0.0 there is a higher capability to process larger payloads using script mediator. In order to process such large payloads we can follow the below two approaches. 1. Replace the javascript tranformation logic using java code by writing a custom mediator. [1] 2. Break down the large payload and execute them as sections using

Exposing a SOAP service as a REST API

In this post i will be explaining how we can transform a SOAP based backend to receive requests in a restful manner through the WSO2 API Cloud. Steps. First log into the WSO2 Cloud and navigate to the API Cloud. In the API cloud select the option to add a new API. We will be creating an API to demonstrate an invocation to the backend soap service ws.cdyne.com/phoneverify/phoneverify.asmx?wsdl Give a name, context and version to the API and add a resource name with a GET Method. The resource name can be anything which you like since we will invoke the actual service usiing a custom sequence. Mention the URI template as indicated in the below screenshot. Next go to the implement tab. And select the endpoint type as HTTP/SOAP Endpoint and specify the endpoint as http://ws.cdyne.com/phoneverify/phoneverify.asmx. There is an important step we need to do here. We need to set the SOAP version for this request. In order to do that we need to select the advanced option for the e

Invoking external endpoints using the call mediator in wso2 api manager

Introduction In API Manager if you need to do any service chaining use cases the call mediator comes in handy. If you need to use the response received by invoking one endpoint and then use it to invoke another endpoint you can use the call mediator in API Manager. The call mediator behaves in a synchronous manner. Hence, mediation pauses after the service invocation and resumes from the next mediator in the sequence when the response is received. You can read more about the call mediator in the wso2 esb documentation [1] . In api manager 1.10.0 the call mediator works in the blocking mode. Prerequisite Before we can use the call mediator in API Manager 1.10.0 we need to make the following changes to some configs. We need to comment the jms transport sender in axis2_blocking_client.xml found in the location APIM_HOME/repository/conf/axis2. This will resolve the jms sender initialization issues.   <!--transportSender name="jms"                      class