2
votes

I provide a working code in the answer below, as this set of API's is relatively new, and I could not see other end-to-end examples in the web, so may be useful as a reference for anyone wishing to use the new set of API's.

I'm trying to use the new set of published APIs of WSO2 AM 1.10.0. I wrote a sample client, based on an article of Sanjeewa Malalgoda: http://wso2.com/library/articles/2015/11/article-introducing-wso2-api-manager-new-rest-api-for-store-and-publisher-operations

Here is the code, based on that article and fixes some minor errors/typos:

  package test;

  import java.io.IOException;
  import java.io.UnsupportedEncodingException;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Base64;
  import java.util.HashMap;
  import java.util.Map;

  import org.json.JSONObject;
  import org.wso2.carbon.automation.engine.exceptions.AutomationFrameworkException;
  import org.wso2.carbon.automation.test.utils.http.client.HttpRequestUtil;
  import org.wso2.carbon.automation.test.utils.http.client.HttpResponse;

  public class test 
  {
    public static void main(String[] args) throws
        UnsupportedEncodingException,
        AutomationFrameworkException,
        InterruptedException,
        MalformedURLException,
        IOException
    {

        //    PHASE 1: REGISTER CLIENT
        //    ------------------------

        String dcrEndpointURL = getKeyManagerURLHttp() +
                              "client-registration/v0.9/register";

        String applicationRequestBody = " {\n" +
                    " \"callbackUrl\": \"google.sk\",\n" +
                    " \"clientName\": \"test_11\",\n" +
                    " \"tokenScope\": \"Production\",\n" +
                    " \"owner\": \"admin\",\n" +
                    " \"grantType\": \"password refresh_token\",\n" +
                    " \"saasApp\": true\n" +
                    " }";
        Map<String, String> dcrRequestHeaders = new HashMap<String, String>();

        //  This is base 64 encoded basic Auth value for user name admin and password admin.
        String basicAuthAdmin = "admin" + ":" + "admin";
        byte [] encodedBytesAdmin = Base64.getEncoder().encode(basicAuthAdmin.getBytes("UTF-8"));
        dcrRequestHeaders.put("Authorization", "Basic " + new String(encodedBytesAdmin, "UTF-8"));
        System.out.println(dcrRequestHeaders.get("Authorization"));

        dcrRequestHeaders.put("Content-Type", "application/json");

        JSONObject clientRegistrationResponse = new JSONObject(HttpRequestUtil.doPost(
             new URL(dcrEndpointURL), 
             applicationRequestBody,dcrRequestHeaders));

        System.out.println(clientRegistrationResponse);

        consumerKey = new JSONObject(clientRegistrationResponse.getString("data")).get("clientId").toString();
        consumerSecret =new JSONObject(clientRegistrationResponse.getString("data")).get("clientSecret").toString();
        System.out.println(consumerKey);
        System.out.println(consumerSecret);

        Thread.sleep(2000);

        //    PHASE 2: REQUEST TOKEN
        //    ----------------------

        String requestBody = "grant_type=password&username=admin&password=admin&scope=API_CREATOR_SCOPE";

        URL tokenEndpointURL = new URL(getGatewayURLNhttp() + "token");

        Map<String, String> authenticationRequestHeaders = new HashMap<String, String>();
        String basicAuthConsumer = consumerKey + ":" + consumerSecret;
        byte [] encodedBytesConsumer = Base64.getEncoder().encode(basicAuthConsumer.getBytes("UTF-8"));
        authenticationRequestHeaders.put("Authorization", "Basic " + new String(encodedBytesConsumer, "UTF-8"));

        JSONObject accessTokenGenerationResponse = new JSONObject(HttpRequestUtil.doPost(tokenEndpointURL, requestBody, authenticationRequestHeaders));
        System.out.println(accessTokenGenerationResponse);

        //Get access token and refresh token from token API call.
        //Now we have access token and refresh token that we can use to invoke API.
        JSONObject tokenData = new JSONObject(accessTokenGenerationResponse.getString("data"));
        String userAccessToken = tokenData.getString("access_token"); 
        String refreshToken = tokenData.getString("refresh_token");
        System.out.println("Access token: " + userAccessToken);     
        System.out.println("Refresh token: " + refreshToken);

        //    PHASE 3: CALL THE API
        //    ---------------------

        Map<String, String> requestHeaders = new HashMap<String, String>();     
        requestHeaders.put("Authorization", "Bearer " + userAccessToken);

        System.out.println(requestHeaders);

        HttpResponse response = HttpRequestUtil.doGet(getKeyManagerURLHttp()+"api/am/publisher/v0.9/apis?query=admin&type=provide",requestHeaders);
        System.out.println(response.getResponseCode());
        System.out.println(response.getResponseMessage());      
    }

    static String getKeyManagerURLHttp()
    {
        return "http://127.0.0.1:9763/";
    }

    static String getGatewayURLNhttp()
    {
        return "http://127.0.0.1:8280/";
    }
  }

The code registers the client and returns access and refresh token successfully.

Here is the response of the token request:

"data":     
    {
      "access_token": "bb5176def22ffbc4a7b12d2fd1ee9733",
      "refresh_token": "357926275971df21f9529ebb30ba36d1",
      "scope":"default",
      "token_type":"Bearer",
      "expires_in":2502
    }

However, when I send this token in the header of the API query:

    {Authorization=Bearer bb5176def22ffbc4a7b12d2fd1ee9733}

I get error code 401/Unauthorized.

Looking at the server log, I get the following:

[2016-02-07 17:38:20,371] ERROR - WebAppAuthenticatorImpl You cannot access API as scope validation failed
[2016-02-07 17:38:20,372]  WARN - PhaseInterceptorChain Interceptor for {http://publisher.api.rest.apimgt.carbon.wso2.org/}SubscriptionsApi has thrown exception, unwinding now
org.apache.cxf.interceptor.security.AuthenticationException: Unauthenticated request
        at org.wso2.carbon.apimgt.rest.api.util.interceptors.auth.OAuthAuthenticationInterceptor.handleMessage(OAuthAuthenticationInterceptor.java:62)
        at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
        at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
        at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251)
        at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
        at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
        at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
        at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:293)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:217)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
        at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:268)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
        at org.wso2.carbon.tomcat.ext.valves.CompositeValve.continueInvocation(CompositeValve.java:99)
        at org.wso2.carbon.tomcat.ext.valves.CarbonTomcatValve$1.invoke(CarbonTomcatValve.java:47)
        at org.wso2.carbon.webapp.mgt.TenantLazyLoaderValve.invoke(TenantLazyLoaderValve.java:57)
        at org.wso2.carbon.tomcat.ext.valves.TomcatValveContainer.invokeValves(TomcatValveContainer.java:47)
        at org.wso2.carbon.tomcat.ext.valves.CompositeValve.invoke(CompositeValve.java:62)
        at org.wso2.carbon.tomcat.ext.valves.CarbonStuckThreadDetectionValve.invoke(CarbonStuckThreadDetectionValve.java:159)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
        at org.wso2.carbon.tomcat.ext.valves.CarbonContextCreatorValve.invoke(CarbonContextCreatorValve.java:57)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1698)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

Some notes

  1. I'm running version 1.10.0, from http://wso2.com/api-management/try-it
  2. WSO2 Published API's that I have on this deployment are all v0.9 (and not v1, as appear in some of the examples)
  3. I tried the token request with both API_CREATOR_SCOPE, API_PUBLISHER_SCOPE. Both fail.
  4. In the response of the token request, it says "scope: default". Not sure if this is ok or not.
  5. The exception says "You cannot access API as scope validation failed", so I guess there is an issue with the scope. But I'm not sure why and how to fix.
3
How do you send the request? Can you attach the parameters?Abimaran Kugathasan
The request can be found in the java code. The request for token is the 2nd API that I call. Anyway, the issue was the scope I was using. I used the one that appeared in the article, and then changed it to apim:api, which made it work.Ofer Lahav

3 Answers

2
votes

Please check roles and scope available in /_system/config/apimgt/applicationdata/tenant-conf.json file. Then request token with scopes mentioned there. Then you will get access token with correct scope. Please note that tokens with default scope cannot use for REST API functionalities.

1
votes

For basic authentication, change beans.xml of repository\deployment\server\webapps\api#am#publisher#v0.9\WEB-INF to:

<bean id="AuthenticationInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.auth.BasicAuthenticationInterceptor" />

And then code is much simplified:

public class test {

public static void main(String[] args) throws
    UnsupportedEncodingException,
    AutomationFrameworkException,
    InterruptedException,
    MalformedURLException,
    IOException
{
    String dcrEndpointURL = getKeyManagerURLHttp()+"client-registration/v0.9/register";

    String basicAuthAdmin = "admin" + ":" + "admin";
    byte [] encodedBytesAdmin = Base64.getEncoder().encode(basicAuthAdmin.getBytes("UTF-8"));
    Map<String, String> requestHeaders = new HashMap<String, String>();     
    requestHeaders.put("Authorization", "Basic " + new String(encodedBytesAdmin, "UTF-8"));

    System.out.println(requestHeaders);

    HttpResponse response = HttpRequestUtil.doGet(getKeyManagerURLHttp()+"api/am/publisher/v0.9/apis",requestHeaders);
    System.out.println(response.getResponseCode());
    System.out.println(response.getResponseMessage());      
    System.out.println(response.getData());

    HttpResponse response1 = HttpRequestUtil.doGet(getKeyManagerURLHttp()+"api/am/publisher/v0.9/subscriptions",requestHeaders);
    System.out.println(response1.getResponseCode());
    System.out.println(response1.getResponseMessage());
    System.out.println(response1.getData());

}

static String getKeyManagerURLHttp()
{
    return "http://127.0.0.1:9763/";
}

static String getGatewayURLNhttp()
{
    return "http://127.0.0.1:8280/";
}
}
0
votes

Here is a working example, following Sanjeewa's fix.

  package test;

  import java.io.IOException;
  import java.io.UnsupportedEncodingException;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Base64;
  import java.util.HashMap;
  import java.util.Map;

  import org.json.JSONObject;
  import org.wso2.carbon.automation.engine.exceptions.AutomationFrameworkException;
  import org.wso2.carbon.automation.test.utils.http.client.HttpRequestUtil;
  import org.wso2.carbon.automation.test.utils.http.client.HttpResponse;

  public class test 
  {
    public static void main(String[] args) throws
        UnsupportedEncodingException,
        AutomationFrameworkException,
        InterruptedException,
        MalformedURLException,
        IOException
    {

        //    PHASE 1: REGISTER CLIENT
        //    ------------------------

        String dcrEndpointURL = getKeyManagerURLHttp() +
                              "client-registration/v0.9/register";

        String applicationRequestBody = " {\n" +
                    " \"callbackUrl\": \"google.sk\",\n" +
                    " \"clientName\": \"test_11\",\n" +
                    " \"tokenScope\": \"Production\",\n" +
                    " \"owner\": \"admin\",\n" +
                    " \"grantType\": \"password refresh_token\",\n" +
                    " \"saasApp\": true\n" +
                    " }";
        Map<String, String> dcrRequestHeaders = new HashMap<String, String>();

        //  This is base 64 encoded basic Auth value for user name admin and password admin.
        String basicAuthAdmin = "admin" + ":" + "admin";
        byte [] encodedBytesAdmin = Base64.getEncoder().encode(basicAuthAdmin.getBytes("UTF-8"));
        dcrRequestHeaders.put("Authorization", "Basic " + new String(encodedBytesAdmin, "UTF-8"));
        System.out.println(dcrRequestHeaders.get("Authorization"));

        dcrRequestHeaders.put("Content-Type", "application/json");

        JSONObject clientRegistrationResponse = new JSONObject(HttpRequestUtil.doPost(
             new URL(dcrEndpointURL), 
             applicationRequestBody,dcrRequestHeaders));

        System.out.println(clientRegistrationResponse);

        consumerKey = new JSONObject(clientRegistrationResponse.getString("data")).get("clientId").toString();
        consumerSecret =new JSONObject(clientRegistrationResponse.getString("data")).get("clientSecret").toString();
        System.out.println(consumerKey);
        System.out.println(consumerSecret);

        Thread.sleep(2000);

        //    PHASE 2: REQUEST TOKEN
        //    ----------------------

        String requestBody = "grant_type=password&username=admin&password=admin&scope=apim:view_api";

        URL tokenEndpointURL = new URL(getGatewayURLNhttp() + "token");

        Map<String, String> authenticationRequestHeaders = new HashMap<String, String>();
        String basicAuthConsumer = consumerKey + ":" + consumerSecret;
        byte [] encodedBytesConsumer = Base64.getEncoder().encode(basicAuthConsumer.getBytes("UTF-8"));
        authenticationRequestHeaders.put("Authorization", "Basic " + new String(encodedBytesConsumer, "UTF-8"));

        JSONObject accessTokenGenerationResponse = new JSONObject(HttpRequestUtil.doPost(tokenEndpointURL, requestBody, authenticationRequestHeaders));
        System.out.println(accessTokenGenerationResponse);

        //Get access token and refresh token from token API call.
        //Now we have access token and refresh token that we can use to invoke API.
        JSONObject tokenData = new JSONObject(accessTokenGenerationResponse.getString("data"));
        String userAccessToken = tokenData.getString("access_token"); 
        String refreshToken = tokenData.getString("refresh_token");
        System.out.println("Access token: " + userAccessToken);     
        System.out.println("Refresh token: " + refreshToken);

        //    PHASE 3: CALL THE API
        //    ---------------------

        Map<String, String> requestHeaders = new HashMap<String, String>();     
        requestHeaders.put("Authorization", "Bearer " + userAccessToken);

        System.out.println(requestHeaders);

        HttpResponse response = HttpRequestUtil.doGet(getKeyManagerURLHttp()+"api/am/publisher/v0.9/apis?query=admin&type=provide",requestHeaders);
        System.out.println(response.getResponseCode());
        System.out.println(response.getResponseMessage());      
        System.out.println(response.getData());     
    }

    static String getKeyManagerURLHttp()
    {
        return "http://127.0.0.1:9763/";
    }

    static String getGatewayURLNhttp()
    {
        return "http://127.0.0.1:8280/";
    }
  }

Result:

200
OK
{"count":1,"next":"","list":[{"name":"employees","context":"/employees","id":"09cef2c8-89f0-405e-97af-225942a52d83","description":null,"version":"1.0.0","provider":"admin","status":"PUBLISHED"}],"previous":""}