Monday, May 11, 2015

Reason for 'javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?' while working with WSO2 products

While configuring WSO2 API manage to work with WSO2 IS as the Auth Manager, while trying to login to API Store/API Publisher, noticed the following exception.


javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? at com.sun.net.ssl.internal.ssl.InputRecord.handleUnknownRecord(Unknown Source) at com.sun.net.ssl.internal.ssl.InputRecord.read(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source) at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source) The reason for this was that we have configured a HTTP port for an HTTPS URL.

  E.g.:-
<authmanager>
        <!--
            Server URL of the Authentication service
        -->
        <serverurl>https://localhost:9763/services/</serverurl>
        <!--
            Admin username for the Authentication manager.
        -->
        <username>admin</username>
        <!--
            Admin password for the Authentication manager.
        -->
        <password>admin</password>
    </authmanager>

   

Tuesday, November 25, 2014

Salesforce Outbound Provisioning with WSO2 IS - Configuration that needs to be done in Salesforce

1. Go to https://developer.salesforce.com/signup and sign up as a new user giving your email address (use the email address as the Username)

2. You will get an email asking you to activate your account. Click on the given link and specify a password and other required information (Secret Question, etc). Once you do that, you will be logged into Salesforce

3. Next you need to create a domain for your account. To do this, traverse to Administer -> Domain Management -> My Domain and specify a new of your choice to be registered as your domain.

E.g.:- In my case, I have given the domain name as evanthika so once the domain is registered, the domain URL comes as https://evanthika-dev-ed.my.salesforce.com


Once the domain is registered successfully, you will see a message saying ‘Your domain name is available for testing. Click here to Login’. Click on the button and login using your Salesforce username (email which you specified at account sign-up time) and password (which you set after clicking on the activation link which you got through the email).



It will take you to a page asking you to specify your mobile number to send a security code in order to verify your details. You can either give a mobile number and get the code to do the verification or you can just click on ‘I'll try again later. Just log me in »’ link. Either way, you will be directed to the Salesforce home page from your domain name (If you check the URL, you should see something similar to - https://evanthika-dev-ed.my.salesforce.com/domainname/DomainName.apexp)

4. You need to create a new ‘Connected App’ first. For that, click on Build -> Create -> Apps from the left menu pane. Then specify details as follows and click on the ‘Save’ button.

Connected App Name - IdentityServer
API Name - IdentityServer
Contact Email - evanthika@wso2.com

Under ‘API (Enable OAuth Settings)’ tick the check-box ‘Enable OAuth Settings’.

Callback URL - https://login.salesforce.com/services/oauth2/token
Selected OAuth Scopes - Full access (full)


Then click on ‘Save’

Once saved, you will get a Client Key and a Secret key for the particular Application which you created.

5. Now lets assign the app we created to a user profile. In order to do this, go to Administer -> Profiles -> Select a user and click ‘Edit’ (E.g.:- Chatter Free User) -> Tick the check box under ‘Connected App Access’ to select the App (IdentityServer) which we created in the above step & click on the ‘Save’ button.


6. In order to capture the ProfileId for the above user profile, click on the profile name (Chatter Free User) and check the URL. Extract the value at the end of the URL and keep it safe. We need this to use as the ProfileId when we configure the IDP at WSO2 Identity Server side.
E.g.:- In my case, when I click on the user profile ‘Chatter Free User’ I would see the URL as https://evanthika-dev-ed.my.salesforce.com/00e90000001jZnj so my ProfileId would be 00e90000001jZnj.

7. You will need a security token to work with this scenario. In case you do not get a security token by email, you can request for a new one.

To reset your security token:

i) At the top of any Salesforce page, click the down arrow next to your name. From the menu under your name, select Setup or My Settings—whichever one appears.


ii) From the left pane, select one of the following:
        If you clicked Setup, select My Personal Information | Reset My Security Token.
        If you clicked My Settings, select Personal | Reset My Security Token.
iii) Click the Reset Security Token button. The new security token is sent via email to the email address on your Salesforce user record.


This covers the configuration that needs to be done in Salesforce. The rest of the configuration is explained clearly in the blog written by Ushani Balasooriya.

Monday, October 6, 2014

I want to read the request message from a file in JMeter. How can I do this?

Assume that you need to do a load test with a request which is in a file. Assume you need not to copy it to JMeter, you need to read the request body from a text file and do the POST operation.

All you have to do is, use the below command instead of the POST body.

${__FileToString(large_message.txt,,)}


Friday, September 19, 2014

How to solve the famous token regeneration issue in an API-M cluster

In a API Manager clustered environment (in my case, I have a publisher, a store, two gateway nodes and two key manager nodes fronted by a WSO2 ELB 2.1.1), while regenerating tokens, if you come across an error saying Error in getting new accessToken with an exception as below at Key Manager node, then this is due to a configuration issue.

TID: [0] [AM] [2014-09-19 05:41:28,321]  INFO {org.wso2.carbon.core.services.util.CarbonAuthenticationUtil} -  'Administrator@carbon.super [-1234]' logged in at [2014-09-19 05:41:28,321-0400] {org.wso2.carbon.core.services.util.CarbonAuthenticationUtil}
TID: [0] [AM] [2014-09-19 05:41:28,537] ERROR {org.wso2.carbon.apimgt.keymgt.service.APIKeyMgtSubscriberService} -  Error in getting new accessToken {org.wso2.carbon.apimgt.keymgt.service.APIKeyMgtSubscriberService}
TID: [0] [AM] [2014-09-19 05:41:28,538] ERROR {org.apache.axis2.rpc.receivers.RPCMessageReceiver} -  Error in getting new accessToken {org.apache.axis2.rpc.receivers.RPCMessageReceiver}
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:94)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
    at java.lang.reflect.Method.invoke(Method.java:619)
    at org.apache.axis2.rpc.receivers.RPCUtil.invokeServiceClass(RPCUtil.java:212)
    at org.apache.axis2.rpc.receivers.RPCMessageReceiver.invokeBusinessLogic(RPCMessageReceiver.java:117)
    at org.apache.axis2.receivers.AbstractInOutMessageReceiver.invokeBusinessLogic(AbstractInOutMessageReceiver.java:40)
    at org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:110)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
    at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
    at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:146)
    at org.wso2.carbon.core.transports.CarbonServlet.doPost(CarbonServlet.java:231)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.eclipse.equinox.http.servlet.internal.ServletRegistration.service(ServletRegistration.java:61)
    at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:128)
    at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:68)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.wso2.carbon.tomcat.ext.servlet.DelegationServlet.service(DelegationServlet.java:68)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.wso2.carbon.tomcat.ext.filter.CharacterSetFilter.doFilter(CharacterSetFilter.java:61)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.wso2.carbon.tomcat.ext.valves.CompositeValve.continueInvocation(CompositeValve.java:178)
    at org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve$1.invoke(CarbonTomcatValve.java:47)
    at org.wso2.carbon.webapp.mgt.TenantLazyLoaderValve.invoke(TenantLazyLoaderValve.java:56)
    at org.wso2.carbon.tomcat.ext.valves.TomcatValveContainer.invokeValves(TomcatValveContainer.java:47)
    at org.wso2.carbon.tomcat.ext.valves.CompositeValve.invoke(CompositeValve.java:141)
    at org.wso2.carbon.tomcat.ext.valves.CarbonStuckThreadDetectionValve.invoke(CarbonStuckThreadDetectionValve.java:156)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    at org.wso2.carbon.tomcat.ext.valves.CarbonContextCreatorValve.invoke(CarbonContextCreatorValve.java:52)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1653)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:853)
Caused by:
org.wso2.carbon.apimgt.keymgt.APIKeyMgtException: Error in getting new accessToken
    at org.wso2.carbon.apimgt.keymgt.service.APIKeyMgtSubscriberService.renewAccessToken(APIKeyMgtSubscriberService.java:281)
    ... 45 more
Caused by:
java.lang.RuntimeException: Token revoke failed : HTTP error code : 404
    at org.wso2.carbon.apimgt.keymgt.service.APIKeyMgtSubscriberService.renewAccessToken(APIKeyMgtSubscriberService.java:252)
    ... 45 more


This is what you have to do to solve this issue.

1. In you Gateway nodes, you need to change the host and the port values of the below APIs that resides under $APIM_HOME/repository/deployment/server/synapse-configs/default/api                                                      _TokenAPI_.xml                                                                                                                                         _AuthorizeAPI_.xml                                                                                                                                       _RevokeAPI_.xml                                                                                                                                        
If you get a HTTP 302 error at Key manager side while regenerating the token, make sure to check the RevokeURL of the api-manager.xml of the Key Manager node to see if it is pointing to the NIO port of the Gateway Node.

Friday, July 11, 2014

Resolving "ORA-12516, TNS:listener could not find available handler with matching protocol stack"


While testing a WSO2 G-Reg pack pointing to an Oracle database (with ojdbc6.jar), came up with the below exception

Caused by: oracle.net.ns.NetException: Listener refused the connection with the following error: ORA-12516, TNS:listener could not find available handler with matching protocol stack at oracle.net.ns.NSProtocol.connect(NSProtocol.java:399) at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1140) at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:340) ... 88 more 

In addition to that, noticed the below warning as well.
  TID: [0] [Greg] [2014-07-11 18:31:52,652] WARN {java.util.prefs.FileSystemPreferences} - Couldn't flush system prefs: java.util.prefs.BackingStoreException: Couldn't get file lock. {java.util.prefs.FileSystemPreferences}

So after doing some googling, I found out about the below parameter and added it to the server start-up script solves the issue. You can read more about this on http://allaboutbalance.com/articles/disableprefs/.

-Djava.util.prefs.syncInterval=2000000 \

Tuesday, April 29, 2014

Expiration times of L1 & L2 caches with Hazelcast for WSO2 products

Recently I had a doubt about how L1 & L2 caches work with WSO2 products. Then I went through the blog on WSO2 Multi-tenant Cache: JSR-107 (JCache) implementation based on Hazelcast by Azeez and got an idea about the caches and how they work.

Then I had a doubt about the expiration times of these two caches, whether they have separate cache expiration times or whether they share the same expiration time value. After having a discussion about this, found out that both caches are using the same expiration time value.

In Cabon 4.2.0 based products, which is using Hazelcast, the cache expiration time cannot be configured and right now, it is hard coded. The default timeout value used with our products is 15 minutes.

Friday, April 25, 2014

Retrieving availble HTTP methods from a back-end server through WSO2 ESB APIs

Assume you have a set of back-end servers that supports different combinations of HTTP methods and you have a need to retrieve which server supports what methods. This can be achieved using WSO2 ESB with the help of an API. Lets see how this can be done using a simple example.

Pre-requisites
  • Download the latest version of WSO2 ESB distribution (WSO2 ESB) to a preferred location on you file system.
  • Download an instance of WSO2 Application Server (WSO2 AS) distribution to host your web application. I will be using version 5.0.1 in this example.

Step 1 - Deploying the web application in WSO2 AS.

Extract the WSO2 AS distribution to a preferred location and start the server. Follow the instructions in the guide Deploying JAX-WS and JAX-RS Applications and deploy the sample web application.

Step 2 - Creating the API in WSO2 ESB

Now lets create an API pointing to the above web application to retrieve it's HTTP methods.

Follow the instructions given under Adding APIs in the Management Console and add an API with the below configuration.


<api xmlns="http://ws.apache.org/ns/synapse" name="CustomerAPI" context="/customer">
   <resource methods="POST GET DELETE PUT" url-mapping="/*">
      <inSequence>
         <send>
            <endpoint>
               <address uri="http://localhost:8280/proxyapi"></address>
            </endpoint>
         </send>
      </inSequence>
      <outSequence>
         <send></send>
      </outSequence>
   </resource>
</api>


Step 3 - Invoking the API to retrieve the available methods of the back-end service.

$ curl -v -X OPTIONS http://localhost:8280/customer/customerservice


When you invoke the above curl command, it would return you all the available methods as below.


* About to connect() to localhost port 8281 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8281 (#0)
> OPTIONS /customer/customerservice HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8280
> Accept: */*
>
< HTTP/1.1 200 OK
< Max-Forwards: 1
< Host: 127.0.0.1:8280
< Allow: POST,GET,DELETE,PUT,OPTIONS,HEAD
< Accept: */*
< Date: Fri, 25 Apr 2014 13:09:10 GMT
< Server: WSO2-PassThrough-HTTP
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact


This is a simple scenario where there is only one layer between your back-end server and your client (which is the API). But assume that the message flows through another API/proxy service before reaching the back-end and still you need to get the methods allowed by the back-end server. To enable this, you can use the parameter Max-Forwards.

Assume a configuration as below.


<api xmlns="http://ws.apache.org/ns/synapse" name="CustomerAPI" context="/customer">
   <resource methods="DELETE POST PUT OPTIONS" url-mapping="/*">
      <inSequence>
         <send>
            <endpoint>
               <address uri="http://localhost:8280/proxyapi"></address>
            </endpoint>
         </send>
      </inSequence>
      <outSequence>
         <send></send>
      </outSequence>
   </resource>
</api>

<api xmlns="http://ws.apache.org/ns/synapse" name="ProxyAPI" context="/proxyapi">
   <resource methods="PUT OPTIONS" url-mapping="/*">
      <inSequence>
         <send>
            <endpoint>
               <address uri="http://localhost:10763/jaxrs_basic_44/services/customers"></address>
            </endpoint>
         </send>
      </inSequence>
      <outSequence>
         <send></send>
      </outSequence>
   </resource>
</api>



To retrieve the methods of the first API, you can specify the MAX-Forwards parameter as below.

$ curl -v -X OPTIONS http://localhost:8280/customer/customerservice -H "Max-Forwards: 0"

It would return the methods available of the first API which is CustomerAPI

* About to connect() to localhost port 8281 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8281 (#0)
> OPTIONS /customer/customerservice HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8280
> Accept: */*
> Max-Forwards: 0
>
< HTTP/1.1 200 OK
< Max-Forwards: 0
< Host: localhost:8280
< Allow: POST, DELETE, PUT
< Content-Type: application/x-www-form-urlencoded; charset=UTF-8
< Accept: */*
< Date: Fri, 25 Apr 2014 12:17:02 GMT
< Server: WSO2-PassThrough-HTTP
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact


If you need to retrieve the methods of the second API, which is ProxyAPI, you need to give the command with Max-Forwards parameter set to 1. Then, it would return the methods allowed by that API only.

$ curl -v -X OPTIONS http://localhost:8280/customer/customerservice -H "Max-Forwards: 1"

The result would be as follows. It returns the available methods of the second API.

* About to connect() to localhost port 8281 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8281 (#0)
< OPTIONS /customer/customerservice HTTP/1.1
< User-Agent: curl/7.29.0
< Host: localhost:8280
< Accept: */*
< Max-Forwards: 1
<
> HTTP/1.1 200 OK
> Max-Forwards: 0
> Host: localhost:8280
> Allow: PUT
> Content-Type: application/x-www-form-urlencoded; charset=UTF-8
> Accept: */*
> Date: Fri, 25 Apr 2014 18:20:16 GMT
> Server: WSO2-PassThrough-HTTP
> Transfer-Encoding: chunked
>
* Connection #0 to host localhost left intact



If you need the HTTP methods of the actual back-end server, you need to call the first API using a command as shown below

curl -v -X OPTIONS http://localhost:8280/customer/customerservice -H "Max-Forwards: 2"

It would give the result as below with all the HTTP methods allowed by the back-end.

* About to connect() to localhost port 8281 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8281 (#0)
< OPTIONS /customer/customerservice HTTP/1.1
< User-Agent: curl/7.29.0
< Host: localhost:8281
< Accept: */*
< Max-Forwards: 2
<
> HTTP/1.1 200 OK
> Allow: POST,GET,DELETE,PUT,OPTIONS,HEAD
> Content-Type: application/octet-stream
> Date: Fri, 25 Apr 2014 18:20:13 GMT
> Server: WSO2-PassThrough-HTTP
> Transfer-Encoding: chunked
>
* Connection #0 to host localhost left intact