I have an Azure webapp (App Service) running with Tomcat. I'd deployed 2 war applications. WAR-1 provides web service call which return a json files using Springboot. WAR-2 is a web application which call this web services in WAR-1. This webapp has system assigned managed identity (or MSI). In addition, this webapp has authentication on with AAD, using Express configuration.
I can access static pages in WAR-2, after authentication through AAD. Now I need to fetch data from WAR-1. I have a servlet which contains code like this:
String subscriptionId = "xxxx";
String testURL = "https://yyy.azurewebsites.net/war1/person/100";
String resourceId = "https://management.azure.com/";
AppServiceMSICredentials credentials = new AppServiceMSICredentials(AzureEnvironment.AZURE);
Azure azure = Azure.configure()
.withLogLevel(LogLevel.BODY_AND_HEADERS)
.authenticate(credentials)
.withSubscription(subscriptionId);
String token = credentials.getToken(resourceId);
HttpURLConnection conn = (HttpURLConnection) new URL(testURL).openConnection();
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + token);
int responseCode = conn.getResponseCode();
OutputStream os = conn.getOutputStream();
....
I do able to get a token, but the response code is 500 when I make the GET call.
So my question is ... is this the correct way to do this call ? I did found an articlehttps://dotnetdevlife.wordpress.com/2018/10/22/call-azure-ad-protected-website-using-managed-service-identity-msi/ similar to this situation but it uses .Net. I cannot find any Java equivalent of this.
I tested at my side, and here are my steps:
1. Two apps in one Azure web app.
App1: https://jackdemoapp1.azurewebsites.net/app1/
App2: https://jackdemoapp1.azurewebsites.net/app2/
2. Configure Authentication/Authorization on Azure portal.
And you can get the client ID by clicking into the details, note it down and we will use it in app2:
3. Configure managed identity on Azure portal
To simplify the test, the app1 will just return a "Hello" string.
4. Code in app2
#ResponseBody
#RequestMapping("/")
public String index() {
JSONObject json = new JSONObject();
try {
AppServiceMSICredentials credential = new AppServiceMSICredentials(AzureEnvironment.AZURE);
// As we want to get token for accessing the aad-protected app, change the
// resource to the client ID you get in step 2
String token = credential.getToken("ac07d701-6f7d-462e-8b67-5dffa1df955f");
json.put("token", token);
// The URL for app1 API
String app1 = "https://jackdemoapp1.azurewebsites.net/app1/";
HttpURLConnection conn = (HttpURLConnection) new URL(app1).openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + token);
conn.setDoOutput(true);
conn.setDoInput(true);
// Open the connection
conn.connect();
int code = conn.getResponseCode();
if (code >= 200 && code <= 300) {
try (InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line);
}
String response = stringBuilder.toString();
json.put("response", response);
}
} else {
json.put("Error", "Response Code" + conn.getResponseCode());
}
conn.disconnect();
} catch (Exception e) {
json.put("Exception", e.getStackTrace());
}
return json.toString();
}
Result
Related
I am using Graph API to import users from Azure AD. In my active directory I am configuring application following this link .
In my code I am generating an accesstoken and pass that access token to get user list.
//get token
String secretKey = EncryptionUtils.decryptAES(encodedSecretKey);
secretKey = URLEncoder.encode(secretKey);
String urltoConnect = loginUrlPrefix+tenantId+loginUrlSufix;
String payLoad = "resource=https%3A%2F%2Fmanagement.core.windows.net%2F&client_id="+clientId+"&grant_type=client_credentials&client_secret=" + secretKey;
System.out.println(payLoad);
URL url = new URL(urltoConnect);
URLConnection connection = null;
connection = url.openConnection();
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
java.io.OutputStreamWriter wr = new java.io.OutputStreamWriter(connection.getOutputStream());
wr.write(payLoad);
wr.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String content;
String html = "";
while ((content = br.readLine()) != null) {
if (!content.equals("") && content.length() != 0)
html += content.trim();
}
return html;
//get user list
URL url = new URL(String.format("https://graph.windows.net/%s/users?api-version=2013-04-05", tenant,
accessToken));
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Set the appropriate header fields in the request header.
conn.setRequestProperty("api-version", "2013-04-05");
conn.setRequestProperty("Authorization","Bearer "+ accessToken);
conn.setRequestProperty("Accept", "application/json;odata=minimalmetadata");
String goodRespStr = HttpClientHelper.getResponseStringFromConn(conn, true);
int responseCode = conn.getResponseCode();
org.json.JSONObject response = HttpClientHelper.processGoodRespStr(responseCode, goodRespStr);
org.json.JSONArray users;
users = JSONHelper.fetchDirectoryObjectJSONArray(response);
If I add multiple applications it works for few gives this error for rest
{ "odata.error": {
"code": "Authorization_RequestDenied",
"message": {
"lang": "en",
"value": "Insufficient privileges to complete the operation."
} } }
Once you click "Grant Permissions" button the change needs time (could be well more than 10 minutes) to be applied, can you wait for that amount of time and then try again - does the issue still exist?
I want to set a successful request to Neteller, I am trying to get an access token using the code from the Neteller documentation. However, it consistently fails with with the following exception:
java.io.IOException: Server returned HTTP response code: 401 for URL: https://test.api.neteller.com/v1/oauth2/token?grant_type=client_credentials
Here's the code (again, from the Neteller documentation):
String testUrl = " https://test.api.neteller.com";
String secureUrl = "https://api.neteller.com";
String url = testUrl;
if("live".equals(configBean.get("environment"))){
url = secureUrl;
}
url += "/v1/oauth2/token?grant_type=client_credentials";
String xml = "grant_type=client_credentials?grant_type=client_credentials";
xml = "";
String test = Base64.encodeBytes((accountID + ":" + secureID).getBytes());
try {
URL urls = new URL ("https://test.api.neteller.com/v1/oauth2/token?grant_type=client_credentials");
HttpURLConnection connection = (HttpURLConnection) urls.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty ("Authorization", "Bearer " + test);
connection.setRequestProperty ("Content-Type", "application/json");
connection.setRequestProperty ("Cache-Control", "no-cache");
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.flush();
wr.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
String accessToken = "";
} catch(Exception e) {
e.printStackTrace();
}
Why is my implementation failing here?
There is nothing wrong with your code. The problem is that you are trying use a regular member account for the API integration, where you need to be using a merchant account for that. Below are the steps you will need to complete in order to get it to work:
You need to get a test merchant account (http://www.neteller.com/business/contact-sales/). Registering on www.neteller.com creates a regular member account, which cannot receive payments via the API.
Once you have a test merchant account, you will need to white-list the IP address from which you will be making requests to the API. (pg. 31 of the manual).
Then, you will need to add an application to it (pg. 32 of the manual).
Once you have added the application, use the "client ID" and "client secret" in the Authorization header - just like you do now, base64 encoded values, separated with colon (:).
So I have a problem where if I type this link on the browser and hit enter, an activation happens. I just want to do the same through Java. I don't need any kind of response from the URL. It should just do the same as entering the URL on a browser. Currently my code doesn't throw an error, but I don't think its working because the activation is not happening. My code:
public static void enableMachine(String dns){
try {
String req= "http://"+dns+"/username?username=sputtasw";
URL url = new URL(req);
URLConnection connection = url.openConnection();
connection.connect();
/*BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
String strTemp = "";
while (null != (strTemp = br.readLine())) {
System.out.println(strTemp);
}*/
} catch (Exception ex) {
ex.printStackTrace();
}
}
What's the problem?
If you want to do that with an URLConnection, it isn't sufficient to just open the connection with connect, you also have to send e.g. an HTTP request etc.
That said, i think it would be easier, if you use an HTTP client like the one from Apache HttpComponents (http://hc.apache.org/). Just do a GET request with the HTTP client, this would be the same as visiting the page with a browser (those clients usually also supports redirection etc.).
You may use HttpUrlConnectionClass to do the job:
URL url = new URL("http://my.url.com");
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setRequestProperty("Content-Type", "application/json");
httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");
String params = "foo=42&bar=buzz";
DataOutputStream wr = new DataOutputStream(httpCon.getOutputStream());
wr.writeBytes(params);
wr.flush();
wr.close();
httpCon.connect();
int responseCode = httpCon.getResponseCode();
You may as well use "GET" request method and just append parameters to the url.
At my site a user is allowed to sign in with facebook. When doing that I ask for permission
to post to the users feed. This works like a charm.
When signed in, a user is allowed to write a review and when saving the review the user is asked if the user wants to post the review to the users feed on facebook. Since the post to facebook should be done after the review is saved in my local db, I understand that I need to perform an authentication serverside and then when I have a token I'm able to POST to eg.
http://graph.facebook.com/10XXXX40308/feed
with
message : "This works"
I have been trying to implement the facebook web login as described here:
The steps are:
Perform a request against
https://graph.facebook.com/oauth/authorize?client_id=MY_API_KEY&
redirect_uri=http://www.facebook.com/connect/login_success.html&
scope=publish_stream
Facebook will redirect you to
http://www.facebook.com/connect/login_success.html?
code=MY_VERIFICATION_CODE
Request
https://graph.facebook.com/oauth/access_token?client_id=MY_API_KEY&
redirect_uri=http://www.facebook.com/connect/login_success.html&
client_secret=MY_APP_SECRET&code=MY_VERIFICATION_CODE Facebook will
respond with access_token=MY_ACCESS_TOKEN
When doing 1. in a browser the application behaves accordingly. I get a redirect back from facebook with the MY_VERIFICATION_CODE:
So I try to do it in code like this:
String url = "https://graph.facebook.com/oauth/authorize?client_id="+clientId+"&scope=publish_stream&redirect_uri=http://www.facebook.com/connect/login_success.html";
URL obj = new URL(url);
conn = (HttpURLConnection) obj.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
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);
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");
But what happens is that instead of getting the 302 back I get a 200 back and the login
page in code:
It seems that I have missed a step or do not understand the flow.
What I'm trying to accomplish is to implement a similar call like to janrain's:
https://rpxnow.com/api/v2/facebook/stream.publish
where you are allowed to do this.
Thank you!
I guess rtfm is in place here. The user need to authenticate, so what I'm really trying to do here is to bypass the authentication process. This is of course not allowed. So
how do you solve this?
When the user authenticates I need to save the access token and the expire time so that
I can add that to the request later on.
I think that is the only way...Correct me if i'm wrong.
So in the authentication process i create a regexp:
Pattern pattern = Pattern.compile("access_token=([a-zA-Z0-9]+)&expires=([0-9]+)");
Then in the callback from facebook I extract the token with the regexp:
String accessToken = "";
String expires = "";
Matcher matcher = pattern.matcher(token.trim());
if(matcher.matches()) {
accessToken = matcher.group(1);
expires = matcher.group(2);
} else {
return new JSONObject()
.put("error", "OathBean: accessToken is null");
}
I then call facebook to get the values for the user and return all the values so that I can work with them:
return new JSONObject()
.put("facebookId", facebookId)
.put("firstName", firstName)
.put("lastName", lastName)
.put("email", email)
.put("photo", photo)
.put("accessToken", accessToken)
.put("expires", expires);
Later on when the user wants post a review to facebook. I populate the request and post the review.
Map<String, String> requestData = new HashMap<String, String>();
requestData.put("link",url(newReview));
requestData.put("description", "reviewText");
requestData.put("access_token", credential.getPassword());
String query = createQuery(requestData);
JSONObject result = null;
try {
URL url = new URL("https://graph.facebook.com/"+identifier+"/feed");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.connect();
OutputStreamWriter osw = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
osw.write(query);
osw.close();
result = new JSONObject(IOUtils.toString(conn.getInputStream()));
}
catch (Exception e) {
log.error("Could not call graph feed to publish for id: "+identifier, e);
}
if(result != null) {
boolean success = StringUtils.isNotBlank(result.getString("id"));
entityManager.persist(new FBPublishEvent(currentUser, newReview, success, result.toString()));
}
If you have a better solution, please share =)
I am trying to login to a website and get page source of a page site after I login to the web site with java URLConnection. The problem I am facing is I can't maintain session so server gives me this warning and doesn't let me to get connected:
This system requires the use of HTTP cookies to verify authorization information.
Our system has detected that your browser has disabled HTTP cookies, or does not support them.
Please refer to the Help page in your browser for more information on how to correctly configure your browser for use with this system.
At first I am trying to send empty cookie to let server to understand I am handling sessions but it doesn't give me session id either.
This is my source code:
try {
// Construct data
String data = URLEncoder.encode("usr", "UTF-8") + "=" + URLEncoder.encode("usr", "UTF-8");
data += "&" + URLEncoder.encode("password", "UTF-8") + "=" + URLEncoder.encode("pass", "UTF-8");
// Send data
URL url = new URL("https://loginsite.com");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setRequestProperty("Cookie", "SESSID=");
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
wr.close();
rd.close();
String headerName=null;
for (int i=1; (headerName = conn.getHeaderFieldKey(i))!=null; i++) {
if (headerName.equals("Set-Cookie")) {
String cookie = conn.getHeaderField(i);
System.out.println(cookie.split(";", 2)[0]);
}
}
} catch (Exception e) {
}
You should use an HTTP library which handles session management and other details of the HTTP protocol for you, e.g. supports Cookies and things like Keep-Alive, Proxies etc. out of the box. Try Apache HttpComponents