Scope validation fails when running the (new) published API of WSO2 AM 1.10.0 - api

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.

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.

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/";
}
}

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":""}

Related

JSR223 Sampler SSL certificate issues

I have the following code in JSR223 Sampler and I get SSL certificate error. Is there any way to do disable?
Problem in JSR223 script JSR223 Sampler, message: javax.script.ScriptException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
import org.apache.http.HttpHeaders;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.http.entity.StringEntity;
List<String> sendRequest(String url, String method, String body) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)
.setSocketTimeout(3000)
.build();
StringEntity entity = new StringEntity(body, "UTF-8");
HttpUriRequest request = RequestBuilder.create(method)
.setConfig(requestConfig)
.setUri(url)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8")
.setEntity(entity)
.build();
String req = "REQUEST:" + "\n" + request.getRequestLine() + "\n" + "Headers: " +
request.getAllHeaders() + "\n" + EntityUtils.toString(entity) + "\n";
HttpClientBuilder.create().build().withCloseable {httpClient ->
httpClient.execute(request).withCloseable {response ->
String res = "RESPONSE:" + "\n" + response.getStatusLine() + "\n" + "Headers: " +
response.getAllHeaders() + "\n" +
(response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "") + "\n";
System.out.println(req + "\n" + res );
return Arrays.asList(req, res);
}
}
}
List test1 = sendRequest("https://testserver.com","POST", "");
log.info(Arrays.toString(test1));
Just use normal HTTP Request sampler instead, as per documentation:
The JMeter HTTP samplers are configured to accept all certificates, whether trusted or not, regardless of validity periods, etc. This is to allow the maximum flexibility in testing servers
However if you're doing something very special and need to do the same in Groovy - here is example solution:
import org.apache.http.HttpHeaders
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.HttpUriRequest
import org.apache.http.client.methods.RequestBuilder
import org.apache.http.conn.ssl.NoopHostnameVerifier
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
import org.apache.http.conn.ssl.TrustStrategy
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.HttpClients
import org.apache.http.ssl.SSLContextBuilder
import org.apache.http.util.EntityUtils
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
List<String> sendRequest(String url, String method, String body) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)
.setSocketTimeout(3000)
.build();
StringEntity entity = new StringEntity(body, "UTF-8");
HttpUriRequest request = RequestBuilder.create(method)
.setConfig(requestConfig)
.setUri(url)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8")
.setEntity(entity)
.build();
String req = "REQUEST:" + "\n" + request.getRequestLine() + "\n" + "Headers: " +
request.getAllHeaders() + "\n" + EntityUtils.toString(entity) + "\n";
def builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
});
def trustAllFactory = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier());
HttpClients.custom().setSSLSocketFactory(trustAllFactory).build().withCloseable { httpClient ->
httpClient.execute(request).withCloseable { response ->
String res = "RESPONSE:" + "\n" + response.getStatusLine() + "\n" + "Headers: " +
response.getAllHeaders() + "\n" +
(response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "") + "\n";
System.out.println(req + "\n" + res);
return Arrays.asList(req, res);
}
}
}
List test1 = sendRequest("https://testserver.com", "POST", "");
println(Arrays.toString(test1));
More information:
Trusting all certificates using HttpClient over HTTPS
Apache Groovy - Why and How You Should Use It

Rally Pull Defect Suite from workspace

i got the code snippet of adding a defect to defect suite from forums.
However, my requirement is to pull defect from defect suite and i am not aware of defect suite information.
Is there a way to pull collection of defect suites and defects from it.
Here is the sample code snippet to add defect to defect suite.
> import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.rallydev.rest.RallyRestApi;
import com.rallydev.rest.request.CreateRequest;
import com.rallydev.rest.request.QueryRequest;
import com.rallydev.rest.request.UpdateRequest;
import com.rallydev.rest.response.CreateResponse;
import com.rallydev.rest.response.QueryResponse;
import com.rallydev.rest.response.UpdateResponse;
import com.rallydev.rest.util.Fetch;
import com.rallydev.rest.util.QueryFilter;
import com.rallydev.rest.util.Ref;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class addDefectToSuite {
public static void main(String[] args) throws URISyntaxException, IOException {
String host = "https://rally1.rallydev.com";
String username = "user#company.com";
String password = "secret";
String wsapiVersion = "v2.0";
String projectRef = "/project/12352608219";
String workspaceRef = "/workspace/12352608129";
String applicationName = "Create defect, add to a defectsuite";
RallyRestApi restApi = new RallyRestApi(
new URI(host),
username,
password);
restApi.setWsapiVersion(wsapiVersion);
restApi.setApplicationName(applicationName);
QueryRequest defectSuiteRequest = new QueryRequest("DefectSuite");
defectSuiteRequest.setFetch(new Fetch("FormattedID","Name", "Defects"));
defectSuiteRequest.setWorkspace(workspaceRef);
defectSuiteRequest.setQueryFilter(new QueryFilter("FormattedID", "=", "DS1"));
QueryResponse defectSuiteQueryResponse = restApi.query(defectSuiteRequest);
JsonObject defectSuiteJsonObject = defectSuiteQueryResponse.getResults().get(0).getAsJsonObject();
System.out.println("defectSuiteJsonObject" + defectSuiteJsonObject);
String defectSuiteRef = defectSuiteJsonObject.get("_ref").getAsString();
int numberOfDefects = defectSuiteJsonObject.getAsJsonObject("Defects").get("Count").getAsInt();
System.out.println(defectSuiteJsonObject.get("Name") + " ref: " + defectSuiteRef + "number of defects: " + numberOfDefects + " " + defectSuiteJsonObject.get("Defects"));
try {
JsonObject defect = new JsonObject();
defect.addProperty("Name", "bad defect 668");
CreateRequest createRequest = new CreateRequest("defect", defect);
CreateResponse createResponse = restApi.create(createRequest);
if (createResponse.wasSuccessful()) {
JsonObject defectJsonObject = createResponse.getObject();
String defectRef = Ref.getRelativeRef(createResponse.getObject().get("_ref").getAsString());
System.out.println(String.format("Created %s", defectRef));
JsonObject defectSuitesOfThisDefect = (JsonObject) defectJsonObject.get("DefectSuites");
int numberOfSuites = defectSuitesOfThisDefect.get("Count").getAsInt();
System.out.println("number of defect suites this defect is part of: " + numberOfSuites);
QueryRequest defectSuitesOfThisDefectRequest = new QueryRequest(defectSuitesOfThisDefect);
JsonArray suites = restApi.query(defectSuitesOfThisDefectRequest).getResults();
System.out.println("suites: " + suites);
suites.add(defectSuiteJsonObject);
System.out.println("suites after add: " + suites);
//Update defect: add to defectsutites collection
JsonObject defectUpdate = new JsonObject();
defectUpdate.add("DefectSuites", suites);
UpdateRequest updateDefectRequest = new UpdateRequest(defectRef,defectUpdate);
UpdateResponse updateResponse = restApi.update(updateDefectRequest);
if (updateResponse.wasSuccessful()) {
System.out.println("Successfully updated defect: " + defectJsonObject.get("FormattedID"));
}
else {
String[] updateErrors;
updateErrors = createResponse.getErrors();
System.out.println("Error");
for (int i=0; i<updateErrors.length;i++) {
System.out.println(updateErrors[i]);
}
}
} else {
System.out.println("error");
}
} finally {
restApi.close();
}
}
}
The Defect object has a DefectSuites collection, so you could just query for all defects where DefectSuites contains your specified DefectSuite:
QueryRequest defectsRequest = new QueryRequest("Defect");
defectsRequest.setFetch(new Fetch("FormattedID","Name"));
defectsRequest.setQueryFilter(new QueryFilter("DefectSuites", "contains", defectSuiteRef));
QueryResponse defectsResponse = restApi.query(defectsRequest);
Or, you can come at it from the other way by querying the Defects collection directly on your DefectSuite in your original code above:
JsonObject defectsCollection = defectSuiteJsonObject.getAsJsonObject("Defects");
QueryRequest defectsRequest = new QueryRequest(defectsCollection);
defectSuiteRequest.setFetch(new Fetch("FormattedID","Name"));
QueryResponse defectsResponse = restApi.query(defectsRequest);

Google API oAuth2.0 -- Consumer is not registered

I have oAuth 2.0 code that works with other services (such as LinkedIn and Facebook) but niot Google.
The code fails with 'Consumer is not registered'. It certainly is. That is if this error means what I think it means but I do have the following in https://code.google.com/apis/console.
a project,
and a valid CLIENT_ID entry
Client ID: 107***********4ek7fl.apps.googleusercontent.com
Client secret: Q6KbA**********FRbL
Redirect URIs: urn:ietf:wg:oauth:2.0:oob, htp://{localhost}
The failure occurs when the request is first sent to https://accounts.google.com/o/oauth2/auth
No page is displayed asking the user to authenticate, the Google server returns "Consumer is not registered" in the response body.
I had a similar problem. I am using the scribe oauth java library, https://github.com/fernandezpablo85/scribe-java. It's support of Google is only oauth 1.0, so I had to write my own class that extends org.scribe.builder.api.DefaultApi20 instead of org.scribe.builder.api.DefaultApi10a.
basically here you are:
package org.scribe.builder.api;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.scribe.exceptions.OAuthException;
import org.scribe.extractors.AccessTokenExtractor;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthConstants;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuth20ServiceImpl;
import org.scribe.oauth.OAuthService;
import org.scribe.utils.OAuthEncoder;
import org.scribe.utils.Preconditions;
/**
* Google OAuth2.0
* Released under the same license as scribe (MIT License)
* #author houman001
* This code borrows from and modifies changes made by #yincrash
* #author yincrash
*
*/
public class Google2Api extends DefaultApi20 {
private static final String AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=%s&redirect_uri=%s";
private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s";
private static final String SUFFIX_OFFLINE = "&" + OAuthConstants.ACCESS_TYPE + "=" + OAuthConstants.ACCESS_TYPE_OFFLINE
+ "&" + OAuthConstants.APPROVAL_PROMPT + "=" + OAuthConstants.APPROVAL_PROMPT_FORCE;
#Override
public String getAccessTokenEndpoint() {
return "https://accounts.google.com/o/oauth2/token";
}
#Override
public AccessTokenExtractor getAccessTokenExtractor() {
return new AccessTokenExtractor() {
public Token extract(String response) {
Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string");
Matcher matcher = Pattern.compile("\"access_token\" : \"([^&\"]+)\"").matcher(response);
if (matcher.find())
{
String token = OAuthEncoder.decode(matcher.group(1));
String refreshToken = "";
Matcher refreshMatcher = Pattern.compile("\"refresh_token\" : \"([^&\"]+)\"").matcher(response);
if (refreshMatcher.find())
refreshToken = OAuthEncoder.decode(refreshMatcher.group(1));
Date expiry = null;
Matcher expiryMatcher = Pattern.compile("\"expires_in\" : ([^,&\"]+)").matcher(response);
if (expiryMatcher.find())
{
int lifeTime = Integer.parseInt(OAuthEncoder.decode(expiryMatcher.group(1)));
expiry = new Date(System.currentTimeMillis() + lifeTime * 1000);
}
Token result = new Token(token, refreshToken, expiry, response);
return result;
}
else
{
throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null);
}
}
};
}
#Override
public String getAuthorizationUrl(OAuthConfig config) {
// Append scope if present
if (config.hasScope()) {
String format = config.isOffline() ? SCOPED_AUTHORIZE_URL + SUFFIX_OFFLINE : SCOPED_AUTHORIZE_URL;
return String.format(format, config.getApiKey(),
OAuthEncoder.encode(config.getCallback()),
OAuthEncoder.encode(config.getScope()));
} else {
String format = config.isOffline() ? AUTHORIZE_URL + SUFFIX_OFFLINE : AUTHORIZE_URL;
return String.format(format, config.getApiKey(),
OAuthEncoder.encode(config.getCallback()));
}
}
#Override
public Verb getAccessTokenVerb() {
return Verb.POST;
}
#Override
public OAuthService createService(OAuthConfig config) {
return new GoogleOAuth2Service(this, config);
}
private static class GoogleOAuth2Service extends OAuth20ServiceImpl {
private DefaultApi20 api;
private OAuthConfig config;
public GoogleOAuth2Service(DefaultApi20 api, OAuthConfig config) {
super(api, config);
this.api = api;
this.config = config;
}
#Override
public Token getAccessToken(Token requestToken, Verifier verifier) {
OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
switch (api.getAccessTokenVerb()) {
case POST:
request.addBodyParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
// API Secret is optional
if (config.getApiSecret() != null && config.getApiSecret().length() > 0)
request.addBodyParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
if (requestToken == null) {
request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
request.addBodyParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.GRANT_TYPE_AUTHORIZATION_CODE);
} else {
request.addBodyParameter(OAuthConstants.REFRESH_TOKEN, requestToken.getSecret());
request.addBodyParameter(OAuthConstants.GRANT_TYPE, OAuthConstants.GRANT_TYPE_REFRESH_TOKEN);
}
break;
case GET:
default:
request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey());
// API Secret is optional
if (config.getApiSecret() != null && config.getApiSecret().length() > 0)
request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret());
request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
}
Response response = request.send();
return api.getAccessTokenExtractor().extract(response.getBody());
}
}
}
from https://raw.githubusercontent.com/codolutions/scribe-java/master/src/main/java/org/scribe/builder/api/Google2Api.java

Using OAuth retrieve access token without redirecting to a webpage

I had written a java program which uses client id and client secret for authentication. When i run my program it gives an url and when i go to that url it gives me access token. How can i programatically get the access token without using a browser?
My code:
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.DirectoryScopes;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.Users;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class DirectoryCommandLine {
private static String CLIENT_ID = "YOUR_CLIENT_ID";
private static String CLIENT_SECRET = "YOUR_CLIENT_SECRET";
private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
public static void main(String[] args) throws IOException {
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_USER))
.setAccessType("online")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
System.out.println("Please open the following URL in your browser then type the authorization code:");
System.out.println(" " + url);
System.out.println("Enter authorization code:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String code = br.readLine();
GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
// Create a new authorized API client
Directory service = new Directory.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("DirectoryCommandLine")
.build();
List<User> allUsers = new ArrayList<User>();
Directory.Users.List request = service.users().list().setCustomer("my_customer");
// Get all users
do {
try {
Users currentPage = request.execute();
allUsers.addAll(currentPage.getUsers());
request.setPageToken(currentPage.getNextPageToken());
} catch (IOException e) {
System.out.println("An error occurred: " + e);
request.setPageToken(null);
}
} while (request.getPageToken() != null &&
request.getPageToken().length() > 0 );
// Print all users
for (User currentUser : allUsers) {
System.out.println(currentUser.getPrimaryEmail());
}
}
}
You do need to use a browser to get user's authorization, but you only have to do it exactly once if you store your refresh token securely.
What's your scenario? You can use embedded browser in mobile, and get the authorization code automatically.

How to login Gmail with Apache's HttpClient?

I want to login my gmail and get the contact list automatically with httpClient,
I've tryed the method described in the page below:
Android: How to login into webpage programmatically, using HttpsURLConnection
but once it ran to:
String cookie = response.getFirstHeader("Set-Cookie").getValue();
a java.lang.NullPointerException was catched.
I thought it was because the page was moved temporarily, then I coded my code like this:
private static String uriLogin = "https://mail.google.com";
private static String uriContacts = "https://mail.google.com/mail/shva=1#contacts";
// the account was registered just for test:
private static String myAcc = "httpclient.test";
private static String myPwd = "testpassword";
public static void main(String[] args) throws ClientProtocolException,
IOException, InterruptedException {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(uriLogin);
List<NameValuePair> params = new ArrayList<NameValuePair>(3);
params.add(new BasicNameValuePair("Email", myAcc));
params.add(new BasicNameValuePair("Passwd", myPwd));
params.add(new BasicNameValuePair("signIn", "Sign in"));
post.setEntity(new UrlEncodedFormEntity(params));
redp("url is:: ", post.getEntity());
HttpResponse rsp = client.execute(post);
if (rsp.getStatusLine().getStatusCode() >= 400) {// returns 302 if
// success
System.err.println("failed to get the web page!!!");
System.err.println("status: " + rsp.getStatusLine());
System.exit(-1);
}
redp("status is:: ", rsp.getStatusLine());
redp("heads of rsp :: ", "");
pHeads(rsp);
redp("content is:: ", EntityUtils.toString(rsp.getEntity()));
String redirect = rsp.getLastHeader("Location").getValue();
HttpGet get = new HttpGet(redirect);
rsp = client.execute(get);
String cookie = rsp.getFirstHeader("Set-Cookie").getValue();
redp("cookie is:: ", cookie);
HttpGet getContacts = new HttpGet(uriContacts);
getContacts.setHeader("Cookie", cookie);
redp("heads of get [contacts]:: ", "");
pHeads(getContacts);
client.getConnectionManager().shutdown();
client = new DefaultHttpClient(); // without these 2 lines,
// "java.lang.IllegalStateException"
// will be catched
rsp = client.execute(getContacts);
redp("heads of rsp (new) ::", "");
pHeads(rsp);
InputStream istream = rsp.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(
istream));
String line;
p("联系人列表: ");
while ((line = reader.readLine()) != null) {
p(line);
}
reader.close();
istream.close();
}// main
public static void pHeads(HttpMessage msg) {
Header[] headers = msg.getAllHeaders();
for (int i = 0; i < headers.length; i++)
p(headers[i].getName() + ": " + headers[i].getValue());
}
public static void p(Object o) {
System.out.println(o);
}
public static void redp(String head, Object o) throws InterruptedException {
System.err.println(head);
if (o.equals("") || o.equals(null))
return;
Thread.sleep(100);
System.out.println(o);
}
}
`
but it still doesn't work... Any help would be great~~
[BTW, I saw a some people says on the Internet that httpClient was not very acceptable for this kind of job, could you tell me in what kind of project HttpClient is most used?]
From what I've seen, You receive the nullPointerEception when you get to response.getLastHeader("Location").getValue();
it looks like there is no "Location" tag in the GMail html header. When Java fails to find this, it just throws "I can't find it"
What you want is the redirect after the POST occurs.
At a quick glance, its something like:
https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1&ltmpl=default&ltmplcache=2
but you should double check this.
Hope this helps.