Can't use Dynamics CRM token (401 Unauthorized) - java

I'm writing a simple android app in Java and recently implemented retrieving a token for a user from Microsoft Dynamics CRM (I have created a connected app in Azure, got application id, secret etc).
I want other users of this application to be able to connect to their CRMs and organizations.
Now I'm trying to use the token with the REST API and getting 401 error.
Read all the related answers here, nothing helped. The code I'm using:
//retrieved the authorization code by this url:
mAuthorizationUrl = Configuration.AUTHORIZE_ENDPOINT + "?response_type=code&client_id="
+ Configuration.CLIENT_ID + "&redirect_uri=" + Configuration.REDIRECT_URI;
...
//Retrieving access_token:
String body_content = "grant_type=authorization_code&client_id=" +
Configuration.CLIENT_ID + "&redirect_uri=" + Configuration.REDIRECT_URI
+ "&code=" + code + "&resource=" + Configuration.CLIENT_ID;
//I don't have app URI (resource) in Azure, so I used app id (client id).
//This worked (see above).
RequestBody body = RequestBody.create(
MediaType.parse("application/x-www-form-urlencoded; charset=utf-8"),
body_content);
Request request = new Request.Builder()
.url(Configuration.TOKEN_RETRIEVAL_ENDPOINT)
.post(body)
.build();
Response response = new OkHttpClient().newCall(request).execute();
String responseString = response.body().string();
JSONObject json = new JSONObject(responseString);
String token = json.getString("access_token");
//NOT WORKING CODE:
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.protocols(Collections.singletonList(Protocol.HTTP_1_1))
.build();
Map<String, String> headers = new ArrayMap<>();
headers.put("Authorization", "Bearer " + token));
headers.put("Accept", "application/json");
request = new Request.Builder()
.url(Configuration.REST_ENDPOINT)
.headers(Headers.of(headers))
.build();
try {
response = okHttpClient
.newCall(request)
.execute();
statusCode = response.code();
}
...
//401 UNAUTHORIZED
Endpoints I used:
AUTHORIZE_ENDPOINT = https://login.microsoftonline.com/common/oauth2/authorize
TOKEN_RETRIEVAL_ENDPOINT = https://login.microsoftonline.com/common/oauth2/token
REST_ENDPOINT = url_to_crm/api/data/v9.0/

Here are two sample Java projects that connect and authenticate with the Dynamics Web API via Azure:
Link 1
Link 2
Hope this helps.

Related

Not authorized to access scope - Amazon Advertising API

My purpose is to download the advertising report using existing application details such as AMAZON_CLIENT_ID, AMAZON_CLIENT_SECRET & Access tokens to other java application.
I was able to get the new access token using AMAZON_CLIENT_ID, AMAZON_CLIENT_SECRET & refresh_token. Below is the code to fetch a new access token.
OkHttpClient client = new OkHttpClient();
Response response;
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "grant_type=refresh_token&refresh_token=" + refreshToken + "&client_id=" + amzClientId + "&client_secret=" + amzClientSceret);
Request request = new Request.Builder()
.url(“https://api.amazon.com/auth/o2/token”)
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.build();
response = client.newCall(request).execute();
After sending the api request to fetch the campaign level stats data, is gives the following error
{"code":"UNAUTHORIZED","
details":"Not authorized to access scope XXXXXXXXXXXXXXXXXX","
requestId":"xxxxxxxxxxxxx"}"
My question here is, Can I use the same existing AMAZON_CLIENT_ID, AMAZON_CLIENT_SECRET & Access tokens to fetch stats to different java applications(without using login with amazon)?
Any help would be appreciated. Thank you!!
You need to include the access token and client ID for subsequent requests.
.addHeader("Authorization", "Bearer " + access_token)
.addHeader("Amazon-Advertising-API-ClientId", client_id)

How to set OAuth realm in RestAssured

I am using RestAssured library for automating NetSuite Restlets. This Restlets are using OAuth 1.0 for authentication. Apart from consumer key, consumer secret, access token and token secret, I need to set advanced fields like REALM. But I couldn't find any way to set that in RestAssured.
RequestSpecification request = new RequestSpecBuilder()
.addHeader("Content-Type", ContentType.JSON.toString())
.setBaseUri(url).build()
.auth().oauth(
netsuiteConfig.getNetsuiteConsumerKey(),
netsuiteConfig.getNetsuiteConsumerSecret(),
netsuiteConfig.getNetsuiteTokenId(),
netsuiteConfig.getNetsuiteTokenSecret()
);
Here is the api call using Postman
RestAssured does not support this. Create OAuth 1.0 string using some library (I have used com.github.seratch:signedrequest4j) and set Authorization header in RestAssured RequestSpecification.
OAuthConsumer consumer = new OAuthConsumer(consumerKey, consumerSecret);
OAuthAccessToken accessToken = new OAuthAccessToken(tokenId, tokenSecret);
OAuthRealm realm = new OAuthRealm(myRealm);
SignedRequest request =
SignedRequestFactory.create(realm, consumer, accessToken);
request.readQueryStringAndAddToSignatureBaseString(url);
request.setHeader("Content-Type", "application/json");
String oAuthNonce = String.valueOf((new SecureRandom()).nextLong());
Long oAuthTimestamp = System.currentTimeMillis() / 1000L;
String signature = request.getSignature(url,
HttpMethod.POST, oAuthNonce, oAuthTimestamp);
String authorizationHeader = request
.getAuthorizationHeader(signature, oAuthNonce, oAuthTimestamp);
I was using the library mentioned in the previous answer but then I realised I needed to use PATCH requests which wasn't supported.
I started using the google oauth client instead and after days of trying, finally got this example working:
val signer = OAuthHmacSigner()
signer.clientSharedSecret = CONSUMER_SECRET
signer.tokenSharedSecret = TOKEN_SECRET
val oauthParameters = OAuthParameters()
oauthParameters.consumerKey = CONSUMER_KEY
oauthParameters.token = ACCESS_TOKEN
oauthParameters.signer = signer
val genericUrl = GenericUrl("https://{ACC_ID}.suitetalk.api.netsuite.com/path/to/endpoint")
oauthParameters.version = "1.0"
oauthParameters.computeNonce()
oauthParameters.computeTimestamp()
oauthParameters.computeSignature("GET", genericUrl)
oauthParameters.realm = REALM
val authHeader = oauthParameters.authorizationHeader
RestAssured.with()
.log().all()
.header("Authorization", authHeader)
.urlEncodingEnabled(false)
.request(Method.GET, genericUrl.toString())
.then()
.statusCode(200)
urlEncoding is set to false for urls with query params that are already encoded. For example:
{url}/invoice?q=internalid%20IS%2012
I hope it helps someone in the future!

Calling a WS with Postman is done, but not from Java code

I did a Post request by using Postman and I got a response, but when did the same resquest using OkHttpClient (same problem with HttpsURLConnection) in java I got a connection refused exception.
Below is my code (with fake data) :
OkHttpClient client = new OkHttpClient();
String req = "<?xml version=\"1.0\"?>\r\n" +
"<ApplicantTestRequest\r\n" +
"PositionID=\"48939014-b24f-4d74-8a44-9913cd9f8936\"\r\n" +
"ThirdPartyCandidateID=\"4152ab4r\"\r\n" +
"FirstName=\"Danny\"\r\n" +
"LastName=\"Givaty\"\r\n" +
"UserName=\"dannyg\"\r\n" +
"Password=\"2sEr#d!w#\"\r\n" +
"email=\"dannyg#careerharmony.com\"\r\n" +
"Telephone=\"5558586858\"\r\n" +
"Source=\"LinkeIn\"\r\n" +
"SkipToFirstRecruiterComponent = \"1\"\r\n" +
"Gender = \"1\"\r\n" +
"/>";
RequestBody reqbody = RequestBody.create(null, req);
Request request = new Request.Builder()
.url("https://staging.direct-assessment.net/RomaTestUI/forms/xmlregistrationandtestentry.aspx?XMLReadType=1")
.method("POST",reqbody)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
int responseCode = response.code();
System.out.println("Response Code : " + responseCode);
The result I got is :
Exception in thread "main" java.net.ConnectException: Failed to connect to staging.direct-assessment.net/185.52.110.193:443
...........
Caused by: java.net.ConnectException: Connection refused: connect
Any suggestion ?
I can see below reason for this, I am also including a possible solution -
The issue could be related to HTTP_TRANSPORT_VERSION, can you check what version is sent via Postman and what is sent from the Java program. If the versions are different then set the HTTP_TRANSPORT_VERSION (similar to that of Postman request) in your java call.

Making requests to another App Engine app

From my GAE server side code, Iam using urlfetchservice to update the datastore on another GAE. This results in Response code 302
Please find the code snippet below,
String urlVal = "https://valeo-is-qc-dev.appspot.com/a/qccards/"+modelObj.getQc_reference_id()+"/updatellcreference?llcref="+modelObj.getReference()+"&llcrefid="+modelObj.getId();
URL url = new URL(urlVal);
// Create HTTPRequest and set headers
com.google.appengine.api.urlfetch.FetchOptions fetchOptions = com.google.appengine.api.urlfetch.FetchOptions.Builder.withDefaults();
fetchOptions.doNotValidateCertificate();
fetchOptions.doNotFollowRedirects();
HTTPRequest httpRequest = null;
httpRequest = new HTTPRequest(new URL(url.toString()), HTTPMethod.PUT,fetchOptions);
httpRequest.addHeader(new HTTPHeader("Authorization", "OAuth " + token_id));
httpRequest.addHeader(new HTTPHeader("X-Appengine-Inbound-Appid", "valeo-is-llc-dev"));
httpRequest.addHeader(new HTTPHeader("Host", "https://test-is-abc-dev.appspot.com"));
httpRequest.addHeader(new HTTPHeader("Content-Type", "text/plain"));
URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();
HTTPResponse httpResponse = null;
httpResponse = fetcher.fetch(httpRequest);
if (httpResponse.getResponseCode() == HttpURLConnection.HTTP_OK) {
LOGGER.log(Level.INFO, "abc def Bridge Response OK --- " + httpResponse.getResponseCode());
LOGGER.log(Level.INFO, "abc def Bridge Response OK --- " + httpResponse.toString());
} else {
// Server returned HTTP error code.
LOGGER.log(Level.INFO, "abc def Bridge Response FAIL --- " + httpResponse.getResponseCode());
}

java client program to send digest authentication request using HttpClient API

I have restlet sample client program which sends the digest request. Similar to this I need java client program which sends a digest request using HttpClient api.
Can anybody send me sample code. Thanks in advance.
Reference reference = new Reference("http://localhost:8092/authenticate");
Client client = new Client(Protocol.HTTP);
Request request = new Request(Method.GET, reference);
Response response = client.handle(request);
System.out.println("response: "+response.getStatus());
Form form = new Form();
form.add("username", "rajesh");
form.add("uri", reference.getPath());
// Loop over the challengeRequest objects sent by the server.
for (ChallengeRequest challengeRequest : response
.getChallengeRequests()) {
// Get the data from the server's response.
if (ChallengeScheme.HTTP_DIGEST
.equals(challengeRequest.getScheme())) {
Series<Parameter> params = challengeRequest.getParameters();
form.add(params.getFirst("nonce"));
form.add(params.getFirst("realm"));
form.add(params.getFirst("domain"));
form.add(params.getFirst("algorithm"));
form.add(params.getFirst("qop"));
}
}
// Compute the required data
String a1 = Engine.getInstance().toMd5(
"rajesh" + ":" + form.getFirstValue("realm") + ":" + "rajesh");
String a2 = Engine.getInstance().toMd5(
request.getMethod() + ":" + form.getFirstValue("uri"));
form.add("response", Engine.getInstance().toMd5(
a1 + ":" + form.getFirstValue("nonce") + ":" + a2));
ChallengeResponse challengeResponse = new ChallengeResponse(
ChallengeScheme.HTTP_DIGEST, "", "");
challengeResponse.setCredentialComponents(form);
// Send the completed request
request.setChallengeResponse(challengeResponse);
response = client.handle(request);
// Should be 200.
System.out.println(response.getStatus());
Have you tried the following:
ChallengeResponse challengeResponse = new ChallengeResponse(challengeRequest, "rajesh", <password>);
Here you go:
HttpClient client = new HttpClient();
Credentials creds = new UsernamePasswordCredentials(username, password);
client.getState().setCredentials(new AuthScope(host, port, realmName), creds);
GetMethod get = new GetMethod(url);
get.setDoAuthentication(true);
client.getParams().setAuthenticationPreemptive(true); // seems to be necessary in most cases
client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, Collections.singleton(AuthPolicy.DIGEST));//need to register DIGEST scheme not the basic
client.getAuthSchemes().register(AuthPolicy.DIGEST, new DigestSchemeFactory());
client.executeMethod(get);
result = get.getResponseBodyAsString();

Categories

Resources