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
- I'm running version 1.10.0, from http://wso2.com/api-management/try-it
- WSO2 Published API's that I have on this deployment are all v0.9 (and not v1, as appear in some of the examples)
- I tried the token request with both API_CREATOR_SCOPE, API_PUBLISHER_SCOPE. Both fail.
- In the response of the token request, it says "scope: default". Not sure if this is ok or not.
- 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.