Passing access token to CRM API throws unauthorized(401) error - java

I'm trying to access a Dynamics CRM Online REST API with Azure AD oAuth 2 Authentication. In order to do so I followed these steps:
I've registered a web application and/or web api in Azure
Configured the permissions to Dynamics CRM to have Delegated permissions "Access CRM Online as organization user"
And created a Key with a 1 year expiration and kept the Client ID generated.
My code:
package com.JasonLattimer.crm.auth;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.naming.ServiceUnavailableException;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONValue;
public class App {
// CRM URL
private final static String RESOURCE = "xxxxxx.crm8.dynamics.com";
private final static String CLIENT_ID = "xxxxxxx-xxxxx-xxxxxxx-xxxxxxxxx";
private final static String CLIENT_SECRET_KEY = "xxxxxxxxxxxxxxxxxxxxxx";
private final static String TENANTID = "xxxxxxxxxxx-xxxx-xxxxx-xxxxxxx";
private final static String AUTHORITY = "login.microsoftonline.com" + TENANTID + "/oauth2/authorize";
public static void main(String args[]) throws Exception {
AuthenticationResult result = getAccessTokenFromUserCredentials();
System.out.println("Access Token - " + result.getAccessToken());
System.out.println("Token expires on - " + result.getExpiresOn());
//String userId = WhoAmI(result.getAccessToken());
//System.out.println("UserId - " + userId);
String fullname = FindFullname(result.getAccessToken(), "2b8fc8ca-86cd-e611-8109-c4346bdc0e01");
System.out.println("Fullname: " + fullname);
}
private static AuthenticationResult getAccessTokenFromUserCredentials() throws Exception {
AuthenticationContext authContext = null;
AuthenticationResult authResult = null;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
authContext = new AuthenticationContext(AUTHORITY, false, service);
ClientCredential clientCred = new ClientCredential(CLIENT_ID, CLIENT_SECRET_KEY);
Future<AuthenticationResult> future = authContext.acquireToken(RESOURCE, clientCred, null);
authResult = future.get();
} catch (Exception ex) {
System.out.println(ex);
} finally {
service.shutdown();
}
if (authResult == null) {
throw new ServiceUnavailableException("authentication result was null");
}
return authResult;
}
private static String FindFullname(String token, String userId) throws MalformedURLException, IOException {
System.out.println("AAAAAAAAAAAAAAAAAA");
HttpURLConnection connection = null;
//The URL will change in 2016 to include the API version - /api/data/v8.0/systemusers
URL url = new URL(RESOURCE + "/api/data/systemusers(" + userId + ")?$select=fullname");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("OData-MaxVersion", "4.0");
connection.setRequestProperty("OData-Version", "4.0");
connection.setRequestProperty("Accept", "application/json");
connection.addRequestProperty("Authorization", "Bearer " + token);
int responseCode = connection.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
Object jResponse;
jResponse = JSONValue.parse(response.toString());
JSONObject jObject = (JSONObject) jResponse;
String fullname = jObject.get("fullname").toString();
System.out.println("FULL NAME" + fullname);
return fullname;
}
private static String WhoAmI(String token) throws MalformedURLException, IOException {
HttpURLConnection connection = null;
//The URL will change in 2016 to include the API version - /api/data/v8.0/WhoAmI
URL url = new URL(RESOURCE + "/api/data/WhoAmI");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("OData-MaxVersion", "4.0");
connection.setRequestProperty("OData-Version", "4.0");
connection.setRequestProperty("Accept", "application/json");
connection.addRequestProperty("Authorization", "Bearer " + token);
int responseCode = connection.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
Object jResponse;
jResponse = JSONValue.parse(response.toString());
JSONObject jObject = (JSONObject) jResponse;
String userId = jObject.get("UserId").toString();
return userId;
}
}
I retrieve an access token successfully but when I try to do a httprequest to CRM I always get a 401 - Unauthorized status code. What am I missing?

You have 2 options:
The old way where you authenticate as a "normal" user in CRM (you'll need their password but can avoid a popup flow). C# example here.
The new way is "Server to Server authentication" which requires you to create an Application User. NOTE this example is also C# but the ADAL code should be very similar in Java.

Related

How can I make a POST request in the same manner as Apache HttpClient lib, using HttpURLConnection

I'm trying to make a POST request to a website. As the response to the POST request, I expect some JSON data.
Using Apache's HttpClient library, I am able to do this without any problems. The response data is JSON so I just parse it.
package com.mydomain.myapp;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class MyApp {
private static String extract(String patternString, String target) {
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(target);
matcher.find();
return matcher.group(1);
}
private String getResponse(InputStream stream) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String inputLine;
StringBuffer responseStringBuffer = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
responseStringBuffer.append(inputLine);
}
in.close();
return responseStringBuffer.toString();
}
private final static String BASE_URL = "https://www.volkswagen-car-net.com";
private final static String BASE_GUEST_URL = "/portal/en_GB/web/guest/home";
private void run() throws Exception {
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(BASE_URL + BASE_GUEST_URL);
CloseableHttpResponse getResponse = client.execute(httpGet);
HttpEntity responseEntity = getResponse.getEntity();
String data = getResponse(responseEntity.getContent());
EntityUtils.consume(responseEntity);
String csrf = extract("<meta name=\"_csrf\" content=\"(.*)\"/>", data);
System.out.println(csrf);
HttpPost post = new HttpPost(BASE_URL + "/portal/web/guest/home/-/csrftokenhandling/get-login-url");
post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
post.setHeader("User-Agent'", "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36");
post.setHeader("Referer", BASE_URL + "/portal");
post.setHeader("X-CSRF-Token", csrf);
CloseableHttpResponse postResponse = client.execute(post);
HttpEntity postResponseEntity = postResponse.getEntity();
String postData = getResponse(postResponseEntity.getContent());
System.out.println(postData);
EntityUtils.consume(postResponseEntity);
postResponse.close();
}
public static void main(String[] args) throws Exception {
MyApp myApp = new MyApp();
myApp.run();
}
}
But I can't use the HttpClient library in my project. I need to be able to do the same thing with "just" HttpURLConnection.
But there is some magic going on with the HttpClient library that I cannot fathom. Because the response to my POST request using HttpURLConnection is just a redirect to a different webpage alltogheter.
Can someone point me in the right direction here?
Here's my current HttpURLConnection attempt:
package com.mydomain.myapp;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MyApp {
private static String extract(String patternString, String target) {
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(target);
matcher.find();
return matcher.group(1);
}
private final static String BASE_URL = "https://www.volkswagen-car-net.com";
private final static String BASE_GUEST_URL = "/portal/en_GB/web/guest/home";
private String getResponse(InputStream stream) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String inputLine;
StringBuffer responseStringBuffer = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
responseStringBuffer.append(inputLine);
}
in.close();
return responseStringBuffer.toString();
}
private String getResponse(HttpURLConnection connection) throws Exception {
return getResponse(connection.getInputStream());
}
private void run() throws Exception {
HttpURLConnection getConnection1;
URL url = new URL(BASE_URL + BASE_GUEST_URL);
getConnection1 = (HttpURLConnection) url.openConnection();
getConnection1.setRequestMethod("GET");
if (getConnection1.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new Exception("Request failed");
}
String response = getResponse(getConnection1);
getConnection1.disconnect();
String csrf = extract("<meta name=\"_csrf\" content=\"(.*)\"/>", response);
System.out.println(csrf);
HttpURLConnection postRequest;
URL url2 = new URL(BASE_URL + "/portal/web/guest/home/-/csrftokenhandling/get-login-url");
postRequest = (HttpURLConnection) url2.openConnection();
postRequest.setDoOutput(true);
postRequest.setRequestMethod("POST");
postRequest.setInstanceFollowRedirects(false);
postRequest.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
postRequest.setRequestProperty("User-Agent'", "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36");
postRequest.setRequestProperty("Referer", BASE_URL + "/portal");
postRequest.setRequestProperty("X-CSRF-Token", csrf);
postRequest.disconnect();
}
public static void main(String[] args) throws Exception {
MyApp myApp = new MyApp();
myApp.run();
}
}
Courtesy of a great programmer resource, e.g. MKYong (you know you've run into his site before ;-)) and I'll go over the gist of it in case the link ever goes down.
Gist:
The HttpURLConnection‘s follow redirect is just an indicator, in fact it won’t help you to do the “real” http redirection, you still need to handle it manually.
If a server is redirected from the original URL to another URL, the response code should be 301: Moved Permanently or 302: Temporary Redirect. And you can get the new redirected url by reading the “Location” header of the HTTP response header.
For example, access to the normal HTTP twitter website – http://www.twitter.com , it will auto redirect to the HTTPS twitter website – https://www.twitter.com.
Sample code
package com.mkyong.http;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpRedirectExample {
public static void main(String[] args) {
try {
String url = "http://www.twitter.com";
URL obj = new URL(url);
HttpURLConnection conn = (HttpURLConnection) obj.openConnection();
conn.setReadTimeout(5000);
conn.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
conn.addRequestProperty("User-Agent", "Mozilla");
conn.addRequestProperty("Referer", "google.com");
System.out.println("Request URL ... " + url);
boolean redirect = false;
// normally, 3xx is redirect
int status = conn.getResponseCode();
if (status != HttpURLConnection.HTTP_OK) {
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER)
redirect = true;
}
System.out.println("Response Code ... " + status);
if (redirect) {
// get redirect url from "location" header field
String newUrl = conn.getHeaderField("Location");
// get the cookie if need, for login
String cookies = conn.getHeaderField("Set-Cookie");
// open the new connnection again
conn = (HttpURLConnection) new URL(newUrl).openConnection();
conn.setRequestProperty("Cookie", cookies);
conn.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
conn.addRequestProperty("User-Agent", "Mozilla");
conn.addRequestProperty("Referer", "google.com");
System.out.println("Redirect to URL : " + newUrl);
}
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer html = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
html.append(inputLine);
}
in.close();
System.out.println("URL Content... \n" + html.toString());
System.out.println("Done");
} catch (Exception e) {
e.printStackTrace();
}
}
}

"AADSTS50058: A silent sign-in request was sent but no user is signed in

Use Case :
I have two application :
1) First one is a Spring boot application, we are exposing our rest endpoint from here.
I want to secure my first application using Azure AD when called from second application and I want to do it in a silent way, that is I should not be prompted for username and password when service to service call happens.
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AADAuthenticationFilter aadAuthFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/home").permitAll();
http.authorizeRequests().antMatchers("/api/**").authenticated();
http.logout().logoutSuccessUrl("/").permitAll();
http.authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
}
#RestController
public class MyRestController{
#RequestMapping(value = "/api/todolist", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> addNewTodoItem(#RequestBody TodoItem item) {
item.setID(todoList.size() + 1);
todoList.add(todoList.size(), item);
return new ResponseEntity<>("Entity created", HttpStatus.CREATED);
}
}
2) Second application is calling this Rest service. (Can you consider this as a java client which is just calling our rest service and then doing some processing).
I want to secure my first application using Azure AD when called from second application and I want to do it in a silent way that is we should not be prompted for username and password when service to service call happens
below is the code :
package sample.aad.security;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import org.json.JSONObject;
import ch.qos.logback.core.net.SyslogOutputStream;
public class MyClass {
public static void main(String[] args) throws Exception {
URL url = new URL("https://login.microsoftonline.com/{tenantId}/oauth2/token");
Map<String, Object> params = new LinkedHashMap<>();
params.put("grant_type", "client_credentials");
params.put("client_id", "b2846a59-33e9-4046-8c94-795d8087f453");
params.put("client_secret", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
params.put("resource", APPID);
StringBuilder postData = new StringBuilder();
for (Map.Entry<String, Object> param : params.entrySet()) {
if (postData.length() != 0)
postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// multipart/form-data
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
conn.getOutputStream().write(postDataBytes);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String output;
String last = null;
System.out.println("Output from Server .... \n");
while ((output = in.readLine()) != null) {
System.out.println(output);
if (last == null) {
last = output;
} else {
last.concat(output);
}
}
JSONObject jsonObj = new JSONObject(last.toString());
System.out.println(jsonObj.get("access_token"));
System.out.println(jsonObj.get("token_type"));
invokeRestUrlClientStatic(jsonObj.get("token_type") + " " + jsonObj.get("access_token"));
}
public static void invokeRestUrlClientStatic(String accessToken) {
try {
System.out.println("Invoking");
System.out.println(accessToken);
// Call to Rest service from First Application
URL url = new URL(" http://localhost:8080/api/todolist/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", accessToken);
String input = "{\"qty\":100,\"name\":\"iPad 4\"}";
OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Note : I dont have any WebUi in either of the application from where user can login.
But I am getting below error :
Caused by: com.microsoft.aad.adal4j.AuthenticationException: {"error_description":"AADSTS50058: A silent sign-in request was sent but no user is signed in.\r\nTrace ID: b27a4ce6-f1ed-4a5c-b28f-6ee16f990400\r\nCorrelation ID: 168e6a13-8cf6-409f-864a-9f190746edfd\r\nTimestamp: 2018-03-17 10:46:35Z","error":"invalid_grant"}
at com.microsoft.aad.adal4j.AdalTokenRequest.executeOAuthRequestAndProcessResponse(AdalTokenRequest.java:107) ~[adal4j-1.2.0.jar:1.2.0]
at com.microsoft.aad.adal4j.AuthenticationContext.acquireTokenCommon(AuthenticationContext.java:816) ~[adal4j-1.2.0.jar:1.2.0]
at com.microsoft.aad.adal4j.AuthenticationContext.access$100(AuthenticationContext.java:64) ~[adal4j-1.2.0.jar:1.2.0]
Am I missing something so that it works.
I have also tried below code (for my second Application): But still getting same error
public static void main(String[] args) throws MalformedURLException, Exception {
String app_id_uri = "APP ID URL";
String authority = "https://login.microsoftonline.com/common/";
String clientId = "b2846a59-33e9-4046-8c94-795d8087f453";
String clientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
AuthenticationContext context = null;
AuthenticationResult result = null;
ExecutorService service = null;
ClientCredential credential= null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(authority, true, service);
credential = new ClientCredential(clientId, clientSecret);
Future<AuthenticationResult> future = context.acquireToken(app_id_uri, credential,null);
result = future.get();
} finally {
service.shutdown();
}
String accessToken = null;
if (result == null) {
throw new ServiceUnavailableException("authentication result was null");
} else {
accessToken = result.getAccessToken();
System.out.println("Access Token: " + accessToken);
}
// Call to my rest service using above accessToken
}

HTTP requests in android

I am currently working on a school project using android. I have java code that sends an HTTP request to a server. It works just find on my laptop using eclipse, but when I try it on my android tablet (an android trio using android 4.4), it does not work. Instead it returns an error (An error occurred while sending the request: in the catch). It is going by the try block and moving to the catch block.
I am attaching the code used for the HTTP request below. I will be leaving out the server information for security reasons. I know the code works, like I said It works on my desktop. Why won't it work with my tablet? Can someone give me a hand with this?
package com.example.tito.profile1;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import android.widget.Toast;
import com.google.gson.Gson;
public class GetUserTest
{
String userName;
public GetUserTest()
{
userName = "Before try";
GetUserRequest request = new GetUserRequest();
request.setSecurityString("Left out for security");
request.setUserId(1);
request.setUserIdToGet(1);
Gson gson = new Gson();
String data = gson.toJson(request);
try
{
URL urlObject = new URL("http://Left out for security");
HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
//userName = connection.toString();
connection.setDoInput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setConnectTimeout(120000);
connection.setReadTimeout(120000);
connection.setRequestMethod("POST");
connection.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream());
wr.write(data);
wr.flush();
wr.close();
if(connection.getResponseCode() == HttpURLConnection.HTTP_OK)
{
InputStream inputStream = connection.getInputStream();
BufferedReader reader = null;
String inputLine;
StringBuilder builder = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
while ((inputLine = reader.readLine()) != null)
{
builder.append(inputLine);
}
if (reader != null)
{
reader.close();
}
String result = builder.toString();
GetUserResponse response = gson.fromJson(result, GetUserResponse.class);
System.out.println(response.getMessage());
if (response.getSuccess() == true)
{
UserInfo user = response.getUser();
/*System.out.println("UserName: " + user.getUserName());
System.out.println("DisplayName: " + user.getDisplayName());
System.out.println("Description: " + user.getDescription());
System.out.println("Email: " + user.getEmail());
System.out.println("ProductCount: " + user.getProductCount());
System.out.println("FollowedUsers: " + user.getFollowedUsers());
System.out.println("FollowingUsers: " + user.getFollowingUsers());*/
//System.out.println("Join Date:" + user.getCreatedDate());
// userName = "in if statement";
// userName = user.getDisplayName();
}
}
else
{
userName = "error in after else";
//userName = "An error occurred while sending the request: " + connection.getResponseMessage();
}
}
catch (Exception ex)
{
ex.printStackTrace();
userName = "An error occurred while sending the request: in the catch ";
}
}
public String sendBack()
{
return userName;
}
}

Server returned HTTP response code: 401 for url when using shopify API

My url as given by the shopify is in this format
https://apikey:password#hostname/admin/orders.json
So when trying to get the orders using HttpURLConnection, I am getting 401 unauthorised error. Here is my code
import java.io.*;
import java.net.*;
import java.util.Properties;
/**
* Created by admin on 22/8/15.
*/
public class Hello {
// This method should be removed in production
static void setProxy(){
Properties systemProperties = System.getProperties();
systemProperties.setProperty("http.proxyHost","lotus");
systemProperties.setProperty("http.proxyPort", "8080");
}
public static void main(String [] args)
{
try
{
setProxy();
URL url = new URL("https://apikey:password#go-frugal.myshopify.com/admin/orders.json");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("user-agent","Mozilla/5.0");
connection.setRequestProperty("Content-Type","application/json");
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String urlString = "";
String current;
while((current = in.readLine()) != null)
{
urlString += current;
}
System.out.println(urlString);
}catch(IOException e)
{
e.printStackTrace();
}
}
}
Here is the error
java.io.IOException: Server returned HTTP response code: 401 for URL: https://apikey:password#go-frugal.myshopify.com/admin/orders.json
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1313)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at Hello.main(Hello.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Process finished with exit code 0<br>
getErrorStream returns this
{"errors":"[API] Invalid API key or access token (unrecognized login or wrong password)"}
try this ... your call sequence is wrong. hope this help.
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import org.jboss.util.Base64;
public class test9 {
public static void main(String[] args) {
URL url;
URLConnection urlConn = null;
HttpURLConnection htcon = null;
InputStream is = null;
StringBuffer sb = new StringBuffer();
String authStr = "apikey:password";
String authStringEnc = Base64.encodeBytes(authStr.getBytes());
//String authStringEnc = new String(Base64Encoder.encode(authString.getBytes()));
try {
url = new URL("https:go-frugal.myshopify.com/admin/orders.json");
urlConn = url.openConnection();
urlConn.setRequestProperty("Authorization", "Basic " + authStringEnc);
urlConn.setRequestMethod("GET");
urlConn.setRequestProperty("user-agent","Mozilla/5.0");
urlConn.setRequestProperty("Content-Type","application/json");
htcon = (HttpURLConnection) urlConn;
is = htcon.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
int numCharsRead;
char[] charArray = new char[1024];
while ((numCharsRead = isr.read(charArray)) > 0) {
sb.append(charArray, 0, numCharsRead);
}
System.out.println("sb: "+sb);
} catch (IOException e) {
e.printStackTrace();
}
}
}
This is an oversight in the way Java handles authorization at the connection level. Took me a good long time to debug; it works in the browser, so why doesn't it work in Java?
Turns out that web browsers will automatically encode the authorization token for any URLs with a user info space. Java doesn't do this by default, so you have to do it yourself:
URI uri = new URL("http://username:password#protected.domain.example/resource").toURI();
String userInfo = uri.getRawUserInfo();
if(userInfo != null && userInfo.length() > 0)
userInfo = Base64.getEncoder().encodeToString(userInfo.getBytes());
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
if(userInfo != null && userInfo.length() > 0)
connection.setRequestProperty("Authorization", "Basic " + userInfo);
connection.connect();
A few notes:
You can try using URL#getUserInfo() or URI#getUserInfo(), but there's a small chance that it won't encode passwords with legal special characters correctly.
This should work for all HTTP URLs, even if they don't have a user info segment.

Fail to Facebook api request using URLConnection in JAVA

I am trying to developing Facebook API using Java.
It is success to get access_token from facebook as flow.
String access_token_url = targetURI +
"client_id=" + appId +
"&client_secret=" + appSecret +
"&code=" + code +
"&redirect_uri=" + redirectURI; // 호출되지 않음
URL url = new URL (access_token_url);
URLConnection urlConn = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
String accessTokenStr="";
while ((accessTokenStr=in.readLine()) != null) {
int endPnt = accessTokenStr.indexOf("&");
access_token = accessTokenStr.substring(13, endPnt);
System.out.println("############# access_token = " + access_token);
}
in.close();
This case(see the below source) occurred exception (code: 400) for get the own information using above access_token.
String access_userInfo_url = "https://graph.facebook.com/me?" + "access_token=" + access_token;
System.out.println("########### access_userInfo_url==============" + access_userInfo_url);
URL url = new URL (access_userInfo_url);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
BufferedReader input = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
urlConn.setRequestMethod("GET");
//urlConn.setConnectTimeout(1000);
//urlConn.setReadTimeout(1000);
//urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//urlConn.setRequestProperty("Content-Length", String.valueOf(access_userInfo_url.length()));
String userInfoStr="";
while ((userInfoStr=input.readLine()) != null) {
System.out.println("############# userInfoStr = " + userInfoStr);
}
input.close();
Recieved excetion message as flow.
java.io.IOException: Server returned HTTP response code: 400 for URL: https://graph.facebook.com/me?access_token=CAAC7APV7WpoBAHVfr2ChZAK4wVrQZCjNSbro3LgABvoFSMMSHmiloS5m95z3DCeNsZBoOHFsClrgBVIqZCCwg8JZCK3Xd0fq6uyu8GJbYNENFQCDKz25IsguBSXuReapPvZA3ZC3BuJVLPwpZAfVCZCqFW0wj6o6ZA6nXO5JzCutZBAum2cJQjiBwctFkzxWqxinz8ZD
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
at biztopia.facebook.web.FacebookController.requestUserInfo(FacebookController.java:318)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
~
~
~
~
I'm confused that it is success when request on web-browser(explorer) as "https://graph.facebook.com/me?access_token=Token value".
Please help me who have solutions.
Do it this way:
public String getUserInfo(String access_token) throws MalformedURLException, ProtocolException, IOException {
try {
String connection = connectionGet("https://graph.facebook.com/me?access_token=" + access_token, "");
return connection;
} catch (Exception e) {
return null;
}
}
public static String connectionGet(String url, String parameter) throws MalformedURLException, ProtocolException, IOException {
URL url1 = new URL(url);
HttpURLConnection request1 = (HttpURLConnection) url1.openConnection();
request1.setRequestMethod("GET");
request1.connect();
String responseBody = convertStreamToString(request1.getInputStream());
return responseBody;
}
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
} catch (IOException e) {
} finally {
try {
is.close();
} catch (IOException e) {
}
}
return sb.toString();
}
The necessary imports will be:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
I found the solutions.
That is append appsecret_proof parameter at call API as "http://graph.facebook.com/me?access_token={access_token value}$appsecret_proof={appsecret_proof value}.
If you are no want append appsecret_proof parameter then you can change set to no use appsecret_proof paameter on your app management site.
The management site menu is setting>advanced>Require AppSecret Proof for Server API calls -> set to disabled.

Categories

Resources