send an email using hotmail access token in java - java

I am trying to send an email using hotmail authorization access token on java env. , I have seen the documentation, but still unable to send an email successfully , here is my code :
private String doPostRequest(String accessToken) throws IOException {
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String url = "https://outlook.office.com/api/v2.0/me/sendmail";
String json = "{"+
"'Message': {"+
"'Subject': 'Meet for lunch?',"+
"'Body': {"+
"'ContentType': 'Text',"+
"'Content': 'The new cafeteria is open.'"+
"},"+
"'ToRecipients': [{"+
"'EmailAddress': {"+
"'Address': 'mymail#gmail.com'"+
"}"+
"}"+
"],"+
"'Attachments': [{"+
"'#odata.type': '#Microsoft.OutlookServices.FileAttachment',"+
"'Name': 'menu.txt',"+
"'ContentBytes': 'bWFjIGFuZCBjaGVlc2UgdG9kYXk='"+
"}"+
"]"+
"},"+
"'SaveToSentItems': 'false'"+
"}";
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder().header("User-Agent", "java-tutorial").header("client-request-id", UUID.randomUUID().toString())
.header("return-client-request-id", "true").header("Authorization", String.format("Bearer %s", accessToken)).url(url).post(body).build();
Response response = client.newCall(request).execute();
System.out.println("response :"+response);
System.out.println("responseHeader :"+response.headers());
System.out.println("responseMessage :"+response.message());
return response.body().string();
}
and here is what I get on the console :
response :Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://outlook.office.com/api/v2.0/me/sendmail}
responseHeader :Set-Cookie: exchangecookie=520b1dfb18d54248ba3bca9becf3a40d; expires=Mon, 29-Oct-2018 08:51:24 GMT; path=/; HttpOnly
WWW-Authenticate: Bearer client_id="00000002-0000-0ff1-ce00-000000000000", trusted_issuers="00000001-0000-0000-c000-000000000000#*", token_types="app_asserted_user_v1 service_asserted_app_v1", authorization_uri="https://login.windows.net/common/oauth2/authorize", error="invalid_token",Basic Realm="",Basic Realm="",Basic Realm=""
request-id: 7d7030b8-c31f-4572-9c18-6a2fce3609a0
client-request-id: 66b1e177-5030-4c0e-892a-7ad276351daf
X-CalculatedFETarget: AM5P190CU001.internal.outlook.com
X-BackEndHttpStatus: 401
X-FEProxyInfo: AM5P190CA0028.EURP190.PROD.OUTLOOK.COM
X-CalculatedBETarget: AM4PR05MB1906.eurprd05.prod.outlook.com
X-BackEndHttpStatus: 401
x-ms-diagnostics: 2000010;reason="ErrorCode: 'PP_E_RPS_CERT_NOT_FOUND'. Message: 'Certificate cannot be found. Certificate required for the operation cannot be found.%0d%0a Internal error: spRPSTicket->ProcessToken failed. Failed to call CRPSDataCryptImpl::UnpackData:Certificate cannot be found. Certificate required for the operation cannot be found.%0d%0a Internal error: Failed to decrypt data. :Failed to get session key. RecipientId=293577. spCache->GetCacheItem returns error.:Cert Name: (null). SKI: ee9f500e98bf0fbc492f0b138028374ec9324da4...'";error_category="invalid_msa_ticket"
X-DiagInfo: AM4PR05MB1906
X-BEServer: AM4PR05MB1906
X-FEServer: AM5P190CA0028
X-Powered-By: ASP.NET
X-FEServer: AM4PR05CA0019
X-MSEdge-Ref: Ref A: 9F523827F0CE47DEB84ECF96913B53AE Ref B: AMS04EDGE0320 Ref C: 2017-10-29T08:51:25Z
Date: Sun, 29 Oct 2017 08:51:24 GMT
Content-Length: 0
OkHttp-Sent-Millis: 1509267094755
OkHttp-Received-Millis: 1509267094903
responseMessage :Unauthorized
Note that the authorization token is correct and looks something similar to :
EwAwA8l6BAAU7p9QDpi/D7xJLwsTgCg3TskyTaQAAYDt8KR/8o7V7P+9ynPu97AHv8CIiJA/Zn+...
And it is the same one used to get the emails on inbox folder and show them to the user as what this tutorial describes .
Also I didn't forget to add the correct scopes for the api to be able to send mail "Mail.Send" .
I need to find a way to send the email successfully using authentication token , please help .

I have found a solution , looks like I need to change the url since I was calling the wrong one according to this documentation , my code now looks
public void tryingOkHttpClientPostt(String accessToken) {
OkHttpClient client = new OkHttpClient();
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://graph.microsoft.com/v1.0/me/sendMail").newBuilder();
String json = "{" + "'Message': {" + "'Subject': 'Meet for lunch?'," + "'Body': {" + "'ContentType': 'Text',"
+ "'Content': 'The new cafeteria is open.'" + "}," + "'ToRecipients': [{" + "'EmailAddress': {" + "'Address': 'myMail#gmail.com'" + "}" + "}"
+ "]," + "'Attachments': [{" + "'#odata.type': '#Microsoft.OutlookServices.FileAttachment'," + "'Name': 'menu.txt',"
+ "'ContentBytes': 'bWFjIGFuZCBjaGVlc2UgdG9kYXk='" + "}" + "]" + "}," + "'SaveToSentItems': 'false'" + "}";
RequestBody body = RequestBody.create(JSON, json);
String url = urlBuilder.build().toString();
Request request = new Request.Builder().header("Content-Type", "application/json")
.header("Authorization", String.format("Bearer %s", accessToken)).method("POST", body).url(url).build();
try {
Response response = client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
}

Related

Spring OAuth 2.0 with jersey request : response 401 Unauthorized after entering correct credentials

Here is my problem: when I try to call this method, I got this error
InboundJaxrsResponse{
context=ClientResponse{method=POST,
uri=http://localhost:9001/oauth/token, status=401,
reason=Unauthorized}}
public String getToken() {
String grant_type ="client_credentials";
String client_id = "abcd";
String client_secret = "mpoo";
Form form = new Form();
form.param("grant_type",grant_type);
form.param("client_id",client_id);
form.param("client_secret",client_secret);
JerseyClientBuilder jerseyClientBuilder = new JerseyClientBuilder();
JerseyWebTarget jerseyWebTarget =
jerseyClientBuilder.build().target("http://localhost:9001/oauth/token");
Response response = jerseyWebTarget.request().post(Entity.form(form));
return response.toString();
}
Any Answer?
That's not the correct way to send the token request. Look at the RFC for client_credentials grant type. The correct format for the request is as follows:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
So only the grant_type should be a part of the Form body. The client_id and client_secret should be Base64 encoded and used for Basic Authentication:
String credentials = client_id + ":" + client_secret;
String base64 = Base64.getEncoder().encode(credentials.getBytes(StandardCharsets.UTF_8));
Response res = jerseyWebTarget.request()
.header(HttpHeaders.AUTHORIZATION, "Basic " + base64)
.post(Entity.form(form));

HttpClientErrorException getResponseBodyAsString() cannot parse byte into string

I have a problem getting the response body from an 403 http code response from third party server. Before april 5 2019 I was able to get the response body from third party correctly but for now I'm retrieving a byte which may not properly converted to string from getResponseBodyAsString. Is this an issue from package org.springframework.web.client?
#Autowired
RestClient restClient;
try{
//Request via restTemplate
ResponseEntity<String> responseEntity = restClient.makeClientRequestJson(batch_type.getEndpoint(), HttpMethod.POST, httpHeaders, batch_payload.getRequest(), ProcessorConstants.moduleId);
} catch (HttpClientErrorException | HttpServerErrorException ex) {
loggingService.writeLogs("Error From Third Party Request, Message: " + ex.getMessage() + "| Response Body: " + ex.getResponseBodyAsString(), this.getClass(), LoggingEnum.ERROR, BatchConstants.moduleId);
...
This is the makeClientRequestJson implementation:
public ResponseEntity<String> makeClientRequestJson(String url, HttpMethod httpMethod, HttpHeaders headers, String jsonBody , String moduleId){
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
loggingService.writeLogs("Third Party Request: " + entity.getBody() + "| url: " + url + " | method: " + httpMethod.toString(), RestClientImpl.class, LoggingEnum.INFO, moduleId);
ResponseEntity<String> response = restTemplate.exchange(url, httpMethod, entity, String.class);
loggingService.writeLogs("Third Party Response: " + response.getBody() + "| url: " + url + " | method: " + httpMethod.toString(), RestClientImpl.class, LoggingEnum.INFO, moduleId);
return response;
}
the problem is when getting ex.getResponseBodyAsString() returning byte array but i get json response from server directly like:
{
"code": "403020",
"transactionID": "1555495478-1409322457-83999786",
"message": "Account is Level 1"
}
Here is sample value I get when debugging the code:
Update: This is due to the response header of the client server, some strange header on their response like connection -> close. if anyone encounter this problem be sure to scan the header responses first.

How to parse asString() unirest response

I have a unirest response that I need to parse and it returns a string response. Kindly check the code below:
HttpResponse<String> response = Unirest.post("http://api.nuvelco.com/token")
.header("content-type", "application/x-www-form-urlencoded")
.header("cache-control", "no-cache")
.body("grant_type=password&username=" + uname + "&password=" + pword + "&client_id=paymentApp")
.asString();
I am unaware how to parse a asString() request so any help would be appreciated.
EDIT:
I forgot to include the response
{
"access_token":"HzDzAtlom6CDqRa0zPetH09hZbDr8tm__hPw7aCx2m0h0gnGwHMaKvBEp64sHRUCJJEAlhCNUqQ3tBSyvod_93gTnt145W2ly9KKw5ISmaZRN75O9NUfJUGPRd0LH87LlxiRgHNFkUGTUDwyJOmhYNajj7TQoncxqkfc3jxL-jEi3Ea1cGRvOSmLH5Aqom81kKmiRzPV_Ss0xwFWjQVsS03y_P720Hv1BQEayO9L7Vic4A64GmXm3PlFQuwcvOk3M_7WOa_EEGOFBZdhwn7dzNQ7gypJ27MSTOD3gI57880unF4XFgTT_H4p4G5V6C8L8yRbRNXPIe80gLKYk3F3nw",
"token_type":"bearer",
"expires_in":3599,
"refresh_token":"f87a5fea7d764826be24bd742626d0d8",
"as:client_id":"paymentApp",
"username":"savemore01",
".issued":"Wed, 05 Dec 2018 03:13:23 GMT",
".expires":"Wed, 05 Dec 2018 04:13:23 GMT"
}
You can use json-simple a simple Java library for JSON. So you can parse the string response value to something like that :
HttpResponse<String> httpResponse = Unirest.post("http://api.nuvelco.com/token")
.header("content-type", "application/x-www-form-urlencoded")
.header("cache-control", "no-cache")
.body("grant_type=password&username=" + uname + "&password=" + pword + "&client_id=paymentApp")
.asString();
String response = EntityUtils.toString(httpResponse.getEntity());
Object object = JSONValue.parse(response);
Note that the package of EntityUtils is org.apache.http.util

the difference between Postman and POST request in Java

I need to get some respones from some URL.
For this purpose I use http://unirest.io/java.html and Java.
Map<String, String> map = new HashMap<>();
map.put(key1, value1);
...
map.put(keyN, valueN);
String authToken = "{token}";
HttpResponse<String> response = Unirest.post(url)
.header("Authorization","Bearer " + authToken)
.header("Content-Type", "application/json")
.fields(map)
.asString();
As a result I receive response.getStatus() = 302 and some unexpected body.
At the same time I use Postman software to get the same responses. The settings are the following:
POST: url
Authorization: Type -> Bearer Token; Token = {{authToken}} // get the value from the previous request
Header :
"Authorization" : "Bearer " + {{authToken}}
Content-Type: application/json
Body:
{
key1 : value1,
...
keyN : valueN
}
And I get some expected response.
What makes the difference?
A 302 is a redirect response. Is it possible Postman is following the redirect and returning the resultant page? Take a look at the Location header in the response you get in Java, and see if following that gives you the same results you're seeing in Postman.

Google Data Api returning an invalid access token

I'm trying to pull a list of contacts from a google account. But Google returns a 401.
The url used for requesting an authorization code:
String codeUrl = 'https://accounts.google.com/o/oauth2/auth' + '?'
+ 'client_id=' + EncodingUtil.urlEncode(CLIENT_ID, 'UTF-8')
+ '&redirect_uri=' + EncodingUtil.urlEncode(MY_URL, 'UTF-8')
+ '&scope=' + EncodingUtil.urlEncode('https://www.google.com/m8/feeds/', 'UTF-8')
+ '&access_type=' + 'offline'
+ '&response_type=' + EncodingUtil.urlEncode('code', 'UTF-8')
+ '&approval_prompt=' + EncodingUtil.urlEncode('force', 'UTF-8');
Exchanging the returned authorization code for an access token (and refresh token):
String params = 'code=' + EncodingUtil.urlEncode(authCode, 'UTF-8')
+ '&client_id=' + EncodingUtil.urlEncode(CLIENT_ID, 'UTF-8')
+ '&client_secret=' + EncodingUtil.urlEncode(CLIENT_SECRET, 'UTF-8')
+ '&redirect_uri=' + EncodingUtil.urlEncode(MY_URL, 'UTF-8')
+ '&grant_type=' + EncodingUtil.urlEncode('authorization_code', 'UTF-8');
Http con = new Http();
Httprequest req = new Httprequest();
req.setEndpoint('https://accounts.google.com/o/oauth2/token');
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setBody(params);
req.setMethod('POST');
Httpresponse reply = con.send(req);
Which returns a JSON array with what looks like a valid access token:
{
"access_token" : "{access_token}",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "{refresh_token}"
}
However when I try and use the access token (either in code or curl) Google returns a 401:
curl -H "Authorization: Bearer {access_token}" https://www.google.com/m8/feeds/contacts/default/full/
Incidentally the same curl command but with an access token acquired via https://code.google.com/oauthplayground/ works. Which leads me to believe there is something wrong with the exchanging authorization code for access token request as the returned access token does not work.
I should add this is all within the expires_in time frame so its not that the access_token has expired
Ok so the problem was in the scope when requesting an authorization code. I had accidentally set the scope to be https://www.google.com/m8/feeds/contacts/default/full (the url for retrieving all contacts), the perils of late night coding. Ironically as the example in the question used the correct hard coded url it did not have the error. I'll leave the question in the hope that those having a similar problem will find it and the code in the question works.

Categories

Resources