Thursday, July 9, 2015

Enable email login in WSO2 carbon products

To enable email address the below steps can be followed in any carbon product.

1. EnableEmailUserName in carbon.xml

<EnableEmailUserName>true</EnableEmailUserName>

2. Then provide the correct regex to allow email address in user store configuration in user-mgt.xml for JDBC user store
E.g.,

    <Property name="UsernameJavaRegEx">[a-
zA-Z0-9@._-|//]{3,30}$</Property>
3. Create admin user with email address in user in user-mgt.xml.

   <AdminUser>
                     <UserName>admin@wso2.com</UserName>
                     <Password>admin</Password>
  </AdminUser>
By the above configurations, it will enable email address.

If you want to give the both support, email address and username, you can include the below property in user store configuration.

4.  <Property name="
UsernameWithEmailJavaScriptRegEx">[a-zA-Z0-9@._-|//]{3,30}$</Property>
      
To know how to do this for a LDAP, refer this well explained blog post [1] done for Identity server which is applicable for other carbon products as well. This document also explains the properties [2]

Tuesday, July 7, 2015

A reason for getting com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

Sometimes you will end up in getting an exception like below when starting a server pointed to MySQL DB.

ERROR - DatabaseUtil Database Error - Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server



One possible reason can be since you have mapped, bind-address to an IP in /etc/mysql/my.cnf

The default is 0.0.0.0 which is all interfaces. This setting does not restrict which IPs can access the server, unless you specified 127.0.0.1 for localhost only or some other IP.

bind-address            = 0.0.0.0

Once this is done, restart mysql server.

 sudo service mysql restart

Monday, May 11, 2015

Simple explaination for URL configurations done during IS as Key Manager in WSO2 API Manager

When you configure as IS as Key Manager, this document can be refereed. The below explanations for some of the URLs given in the configuration.

In WSO2 IS Side :


Make the following changes in the api-manager.xml file you just copied.

  • Change the <RevokeAPIURL> so that it points to the API Manager server. Note that if API Manager is running in distributed mode (has a separate node for the Gateway), you need to point this URL to the Gateway node. This is done so that when the token is revoked, the Gateway cache is updated as well. The port value you enter here must be the NIO port. See Default Ports of WSO2 Products for more information.
 <RevokeAPIURL>https://${GATEWAY_SERVER_HOST}:{nio/passthrough port}/revoke</RevokeAPIURL>

Why do we point to API Manager ? This is because this will call the Gateway node in API manager which points to the Key Manager

Why we point to the NIO/Passthru port ? This is because, here we will call the _RevokeAPI_.xml which is deployed in synapse folder of the Gateway. (In a distributed scenario, we point to the _RevokeAPI_.xml that resides in the Gateway worker node)

Note : So in a distributed scenario (APIM distributed scenario), In store if you call Revoke or Regenerate, store will call the key Manager/Validator and key Manager/Validator will call the gateway.

So in Store we have to configure KeyValidator/Key manager server url and in Key Manager/Validator we have to configure gateway server url (Passthru). Inside Gateway the apis will be called (NIO)


  • Change the <ServerURL> occurring under the <APIGateway> (of the Key Manager/Key Validator node) section so that it points to the API Manager server. If you are using distributed mode, this needs to point to the Gateway node as well. This is done so that when the token is regenerated, the Gateway cache is updated as well. The port value you enter here must be the management transport port.

<ServerURL>https://${GATEWAY_SERVER_HOST}:{port}/services/</ServerURL>

Why we point to API Manager ? This  is because this will call the Gateway node in API manager. This is to identify the gateway node.

Why we point to servlet port ? This is because it calls the admin services.

Note : This is same like as above explained. Since IS is the Key Validator/Manager it calls the gateway.


In WSO2 APIM Side :

Open the api-manager.xml file found in the <APIM_HOME>/repository/conf directory and change the following. 

  • Change the ServerURL of the AuthManager to point to IS.
  <ServerURL>https://${IS_SERVER_HOST}:{port}/services/</ServerURL>

Why IS : This is because authentication will be done via Key manager/validator

Why we point to servlet port ?
This is because it calls the admin services.

  • Change the ServerURL of the APIKeyManager to point to IS.
    <ServerURL>https://${IS_SERVER_HOST}:{port}/services/</ServerURL>

Why IS : This is because authentication will be done via Key manager/validator
Why we point to servlet ports : This is because it calls admin services

Usage of ports in a gateway cluster when fronted by Nginx:

GW manager : Use to publish APIs - So only the servlet ports will be used
GW worker : Use when invoking - So only the passthrough/NIO ports will be used

Note : When you configure API endpoints in gateway (Which is in synapse folder  (E.g.,     _AuthorizeAPI_.xml, _RevokeAPI_.xml, _TokenAPI_.xml), you should edit them only in gateway manager since it will depsync to workers. Otherwise it can cause issues.

Monday, April 27, 2015

How to Enable and test Custom SSL Profiles in WSO2 ESB used for SSL communicating

For this I have used WSO2 ESB 4.8.1 and WSO2  Application Server 5.2.1.
WSO2 ESB uses the truststore for SSL communicating and keystore-truststore pair for Mutual SSL communicating.

In here I have used a trust store for SSL communicating.

Configure App Server as backend

Configure backend :


1. Use app server as backend

2. Create a new keystore in App server in <Appserver_Home>/repository/resources/security

keytool -genkey -alias appserver -keyalg RSA -keysize 1024 -keypass password -keystore appserver.jks -storepass password

3. Export in to a pem file by following command

keytool -export -alias appserver -keystore appserver.jks -storepass password -file appserver.pem

4. Edit the carbon.xml in appserver as below :

 <KeyStore>  
    <!-- Keystore file location-->  
      <Location>${carbon.home}/repository/resources/security/appserver.jks</Location>  
 <!-- Keystore type (JKS/PKCS12 etc.)-->  
     <Type>JKS</Type>  
 <!-- Keystore password-->  
     <Password>password</Password>  
 <!-- Private Key alias-->  
     <KeyAlias>appserver</KeyAlias>  
 <!-- Private Key password-->  
     <KeyPassword>password</KeyPassword>  
 </KeyStore>  



Configure ESB :


1. Created a new keystore.

keytool -genkey -alias esb -keyalg RSA -keysize 1024 -keypass password -keystore esb.jks -storepass password

2. Copy and paste appserver.pem in to the <ESB_HOME>repository/resources/security folder Import appserver.pem in to esb.jks by following command.

keytool -import -alias appservernewesb -file appserver.pem -keystore esb.jks -storepass password

3. Configure esb for custom profile in axis2.xml as below.

 <parameter name="customSSLProfiles">  
  <profile>  
    <servers>10.100.0.31:9443</servers>  
    <TrustStore>  
     <Location>repository/resources/security/esb.jks</Location>  
     <Type>JKS</Type>  
     <Password>password</Password>   
    </TrustStore>  
  </profile>  
 </parameter>  

Invoke and Test :


1. Restart Appserver (offset=0) and ESB (offset = 10) by the command :

 "sh wso2server.sh" or  "sh wso2server.sh -Djavax.net.debug=ssl:handshake " to view the detailed logs.

Following logs should be printed during restart.

[2015-04-27 18:33:19,397]  INFO - ClientConnFactoryBuilder HTTPS Loading Identity Keystore from : repository/resources/security/wso2carbon.jks
[2015-04-27 18:33:19,400]  INFO - ClientConnFactoryBuilder HTTPS Loading Trust Keystore from : repository/resources/security/client-truststore.jks
[2015-04-27 18:33:19,408]  INFO - ClientConnFactoryBuilder HTTPS Loading custom SSL profiles for the HTTPS sender
[2015-04-27 18:33:19,408]  INFO - ClientConnFactoryBuilder HTTPS Loading Trust Keystore from : repository/resources/security/esb.jks
[2015-04-27 18:33:19,409]  INFO - ClientConnFactoryBuilder HTTPS Custom SSL profiles initialized for 1 servers



2. Create the below proxy in ESB.

 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="SecureHello"  
     transports="https,http"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <outSequence>  
      <send/>  
    </outSequence>  
    <endpoint>  
      <address uri="https://localhost:9443/services/HelloService/"/>  
    </endpoint>  
   </target>  
   <publishWSDL uri="http://localhost:9763/services/HelloService?wsdl"/>  
   <description/>  
 </proxy>  

3. Invoke the Proxy.

 <body>  
   <p:greet xmlns:p="http://www.wso2.org/types">  
    <!--0 to 1 occurrence-->  
    <name>ushani</name>  
   </p:greet>  
 </body>  

Following response will be received.

 <ns:greetResponse xmlns:ns="http://www.wso2.org/types">  
   <return>Hello World, ushani !!!</return>  
 </ns:greetResponse>  


Tuesday, March 17, 2015

How to monitor the created tcp connections for a particular proxy service in WSO2 ESB


As an example if we want to monitor the number of tcp connections created during a proxy invocation, the following steps can be performed.

1. Assume you need to monitor the number of tcp connections created for the following proxy service :


 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="Proxy1"  
     transports="https,http"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <inSequence>  
      <property name="NO_KEEPALIVE" value="true" scope="axis2"/>  
      <clone>  
       <target>  
         <sequence>  
          <send>  
            <endpoint>  
             <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
            </endpoint>  
          </send>  
         </sequence>  
       </target>  
        <target>  
         <sequence>  
          <send>  
            <endpoint>  
             <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
            </endpoint>  
          </send>  
         </sequence>  
       </target>  
       <target>  
         <sequence>  
          <send>  
            <endpoint>  
             <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
            </endpoint>  
          </send>  
         </sequence>  
       </target>  
      </clone>  
    </inSequence>  
    <outSequence>  
      <aggregate>  
       <completeCondition>  
         <messageCount/>  
       </completeCondition>  
       <onComplete xmlns:m0="http://services.samples" expression="//m0:getQuoteResponse">  
         <send/>  
       </onComplete>  
      </aggregate>  
    </outSequence>  
   </target>  
   <description/>  
 </proxy>  


You will see there are 5 clones. Therefore it should create only 5 tcp connections.

2. We have used SimpleStockQuoteService service as the backend.
3. Since you need to monitor the connections created, we should delay the response coming from the backend. Therefore we need to change the code slightly in the SimpleStockQuoteService.


We have include a Thread.sleep() for 10 seconds until we monitor the number of connections.
Therefore go to <ESB_HOME>/samples/axis2Server/src/SimpleStockQuoteService/src/samples/services/SimpleStockQuoteService.java

and add the Thread.sleep(10000); as below to hold the response for sometime.

 public GetQuoteResponse getQuote(GetQuote request) throws Exception {  
 Thread.sleep(10000);  
 if ("ERR".equals(request.getSymbol())) {  
 throw new Exception("Invalid stock symbol : ERR");  
 }  
 System.out.println(new Date() + " " + this.getClass().getName() +  
 " :: Generating quote for : " + request.getSymbol());  
 return new GetQuoteResponse(request.getSymbol());  
 }   


4. Build the SimpleStockQuoteService once again by “ant” in here, <ESB_HOME>/samples/axis2Server/src/SimpleStockQuoteService

5. Now start the axis2server
6. Now you have to open a terminal and provide the following netstat command to get the process id.

sudo netstat --tcp --listening --programs
 

You will see the relevant SimpleStockQuoteService which is up in port 9000 like below.

tcp6 0 0 [::]:9000 [::]:* LISTEN 20664/java

So your process ID will be 20664.


7. Then open a terminal and provide the below command to view the tcp connections for the particular process id.

watch -n1 -d "netstat -n -tap | grep 20664"

8. Now open your soapui and send the following request to Proxy1
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.samples" xmlns:xsd="http://services.samples/xsd">  
   <soapenv:Header/>  
   <soapenv:Body>  
    <ser:getQuote>  
      <!--Optional:-->  
      <ser:request>  
       <!--Optional:-->  
       <xsd:symbol>IBM</xsd:symbol>  
      </ser:request>  
    </ser:getQuote>  
   </soapenv:Body>  
 </soapenv:Envelope>  

9. View the tcp connections created in the terminal which you have been monitoring as soon as you send the request. You should be able to view only 3 connections since we have configured like that in proxy using clone mediator.

tcp6 0 0 127.0.0.1:9000 127.0.0.1:44218 ESTABLISHED 20664/java
tcp6 0 0 127.0.0.1:9000 127.0.0.1:44219 ESTABLISHED 20664/java
tcp6 0 0 127.0.0.1:9000 127.0.0.1:44217 ESTABLISHED 20664/java




Tuesday, February 17, 2015

A sample on a WSO2 ESB proxy with a DBLookup mediator and a dedicated faultSequence to excute during an error

Databases :

DB customer should be created with the required tables.

DB : customerDetails
table :  customers


Proxy :


<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="TestProxyUsh"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence onError="testError">
         <dblookup>
            <connection>
               <pool>
                  <password>root</password>
                  <user>root</user>
                  <url>jdbc:mysql://host:3306/customerDetails</url>
                  <driver>com.mysql.jdbc.Driver</driver>
               </pool>
            </connection>
            <statement>
               <sql>SELECT * FROM customers WHERE name =?</sql>
               <parameter value="WSO2" type="INTEGER"/>
               <result name="company_id" column="id"/>
            </statement>
         </dblookup>
      </inSequence>
      <faultSequence>
         <log level="custom">
            <property name="text" value="An unexpected error occurred for the service"/>
         </log>
      </faultSequence>
   </target>
   <description/>
</proxy>
                               

onError targeting sequence :


<sequence xmlns="http://ws.apache.org/ns/synapse" name="testError">
   <log>
      <property name="error" value="Error Occurred"/>
   </log>
</sequence>


Invoke :

curl -v http://host:8280/services/TestProxyUsh









One possible reason and solution for getting Access denied for user 'username'@'host' in mysql when accessing from outside

Sometimes we might get the below exception when creating a DB connection.

 {org.apache.synapse.mediators.db.DBLookupMediator}
org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Access denied for user 'username'@'203.94.95.133'


Reasons :

The particular IP might not be accessible from outside.

Therefore you need to grant priviledges by the below command in mysql :

GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' IDENTIFIED BY 'password';


FLUSH PRIVILEGES;


Sometimes you might try out below :

GRANT ALL PRIVILEGES ON *.* TO 'password'@'%' WITH GRANT OPTION;

Eventhough it says Query OK, still the issue can be there since you have not used the password.

Also you must do a Flush privileges to update it.

Hope this might help sometimes.

Monday, February 16, 2015

A possible reason and solution for getting 400 Bad Request even when the synapse configuration in WSO2 ESB is correct

Sometimes you might spend lot of time in analyzing the reason for getting 400 bad request when you invoke an up and running backend service through WSO2 ESB.

When you configure and save the synapse configuration of your proxy, you will not see any issue. But sometimes there can a possible reason for this issue.

One good example is explained below :

Look at the below synapse configuration of WSO2 ESB proxy service.


 <proxy name="statuscodeProxy"
          transports="https http"
          startOnLoad="true"
          trace="disable">
      <description/>
      <target>
         <inSequence>
            <log level="full"/>
            <send>
               <endpoint>
                  <address uri="http://10.100.0.31:8090"/>
               </endpoint>
            </send>
         </inSequence>
         <outSequence>
            <log level="full"/>
            <send/>
         </outSequence>
      </target>
   </proxy>



By the look of it, this is alright and you are good to configure it in WSO2 ESB. But the endpoint defined as : http://10.100.0.31:8090 is not exactly the endpoint the backend service expects.

Sometimes there can be missing parameters etc. But if you exactly know your backend service does not expect any parameters and still it throws a 400 bad reques, can you imagine the reason for this?

After spending hours, I accidently found a possible reason :

 it was due to the backend expects a / at the end of the endpoint. So it expects :

http://10.100.0.31:8090/ except http://10.100.0.31:8090


If you configure a tcpmon in between ESB and the backend, you will see the difference as below :

http://10.100.0.31:8090 :  GET  HTTP/1.1  - 400 bad Request

http://10.100.0.31:8090/ : GET / HTTP/1.1  - 200 OK

So if you too come across this situation, please try out this option. Sometimes this might save your time! :)


One Possible Reason and solution for dropping the client's custom headers when sending through nginx

Problem :

Sometimes you may have experienced that the custom header values defined and sent through client has been dropped off when it goes via the nginx in a setup fronted by nginx.


Solution :

1. First you should check whether the custom headers  contain underscores (_)

2. If so you need to check whether you have configured underscores_in_headers in your nginx.conf under each server.

3. By default, underscores_in_headers is off.

4. Therefore you need to configure it to on.


Reason :


By this property,

It enables or disables the use of underscores in client request header fields. When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.

Ref: http://nginx.org/en/docs /http/ngx_http_core_module.html


Example :

Sample configuration would be as below :



server{
      listen 8280;
      server_name wrk.esb.com;
      underscores_in_headers on;

location / {
       proxy_set_header X-Forwarded-Host $host;
       proxy_set_header X-Forwarded-Server $host;.
.
.
.
.
                }
         }

Wednesday, February 11, 2015

Reason and solution for not loading WSDL in a clustered setup fronted by NGINX





For more information about nginx http proxy module please refer : http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version



Issue :
Sometimes a WSDL in a clustered setup fronted by NGINX might not be loaded.



Reason :

By default, http version 1.0 is used in nginx. Version 1.1 is recommended for use with keepalive connections. Therefore sometimes the wsdl will not be loaded.

You can confirm it by doing a curl command to the wsdl ngingx url.

E.g.,  curl http://wrk.test.com:8280/services/test?wsdl
Then you will get half of the wsdl.


Solution :

To avoid this, you will have to configure the nginx configuration file to set it's http version.


       proxy_http_version 1.1;
 

Example :

As an example,

server{
      listen 8280;
      server_name wrk.test.com;

location / {
       proxy_set_header X-Forwarded-Host $host;
       proxy_set_header X-Forwarded-Server $host;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

       proxy_http_version 1.1;

        proxy_pass http://esbworkers;
        proxy_redirect http://esbworkers http://wrk.esb.com:8280/;


        }
}

This configuration is applicable for nginx versions above 1.1.4