Java client program to consume REST call with authorization - java

I need to invoke a REST call from Java code.
I have credentials in the form of
Id
Security Key
An algorithm provided which
Gets the server time
Using Id, security key & server time it generates a security token
Now authorization is in the below form
"Authorization": "name id=Id, serverTime=serverTime, securitytoken=securitytoken"
Need a java client program to invoke this REST call using above authorization header.
I am getting
HTTP Response 401 error.
Please provide correct way to set authorization header in request for form
Name Id="Id",serverTime="2017-11-18T05:51:05",securityToken="TOKEN"
Code:
package com.rest.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class Sample {
public final static String GATEWAY_ID = "Id";
public final static String KEY = "Key";
public static void main(String[] args) {
try {
HttpURLConnection conn;
conn = (HttpURLConnection) new URL("https://domain/A/B/72968").openConnection();
String serverTime = "2017-11-18T10:51:05";
String securityToken = "TOKEN";
String authorization = "Name Id=\"" + GATEWAY_ID + "\",serverTime=\"" + serverTime + "\",securityToken=\""
+ securityToken + "\"";
// Name Id="Id",serverTime="2017-11-18T10:51:05",securityToken="TOKEN"
conn.addRequestProperty("Authorization", authorization); // Is Header set is correct? It should be part of Request Header. Please correct this
int status = conn.getResponseCode();
System.out.println(status);
BufferedReader br = null;
StringBuilder body = null;
String line = "";
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
body = new StringBuilder();
while ((line = br.readLine()) != null) {
body.append(line);
}
System.out.println(body);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
Error:
java.io.IOException: Server returned HTTP response code: 401 for URL: https://domain/A/B/72968
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1926)
at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1921)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1920)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1490)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at com.rest.client.ApplicationClient.main(ApplicationClient.java:48)
Caused by: java.io.IOException: Server returned HTTP response code: 401 for URL: https://domain/A/B/72968
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1876)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
at com.rest.client.ApplicationClient.main(ApplicationClient.java:38)

try format authorization string this way "Basic Base64". try
authorization ="Basic "+new String(new Base64().encode(authorization.getBytes()));
conn.setRequestProperty("Authorization", authorization);

Related

Cannot invoke rest call from java with SSL TLSv1.2 to get an authentication token

The code below is refactored based on existing code that works fine in the prod environment. I developed the test unit below in order to introduce a few improvements to the rest call from Java, mainly to implement the following:
add scope,
use the authentication header Authorization: Basic <base64 of client-id:client-secret>, and
add the grant_type and scope in the body using the x-www-form-urlencoded format.
The purpose of this rest call is to get the authorization token that will be used to authorize the other needed services (rest calls).
I completed the first round of the change and tried to run the test and it failed.
import static org.junit.Assert.*;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
public class TestValueNETServices {
#Test
public void testGetJWT() throws Exception {
String endPointURLwithToken = "https://<url-base>/path/to/token/service";
String contentType = "application/x-www-form-urlencoded";
String requestMethod = "POST";
URL url;
boolean isSslFlag = true;
HttpsURLConnection httpsURLCon = null;
String webServiceResponse = null;
try {
try {
url = new URL(endPointURLwithToken);
} catch (MalformedURLException malUrlEx) {
System.out.println("Malformed URL: " + malUrlEx.toString());
malUrlEx.printStackTrace();
return;
}
httpsURLCon = (HttpsURLConnection) url.openConnection();
if (isSslFlag) {
String securedProtocol = "TLSv1.2";
SSLContext sc = SSLContext.getInstance(securedProtocol);
sc.init(null, null, new java.security.SecureRandom());
httpsURLCon.setSSLSocketFactory(sc.getSocketFactory());
}
httpsURLCon.setDoOutput(true);
httpsURLCon.setRequestMethod(requestMethod);
httpsURLCon.setRequestProperty("Content-Type", contentType);
System.out.println("Request Method: " + requestMethod + " Content Type: " + contentType);
String client_id = "client-id-value";
String client_secret = "client-secret-value";
String grant_type = "client_credentials";
String scope = "scope-value";
String urlParameters = "client_id=" + client_id + "&client_secret=" + client_secret + "&grant_type=" + grant_type + "scope=" + scope;
System.out.println("Parameters to get Token --> client_id: " + client_id + " client_secret: " + client_secret + " grant_type: " + grant_type);
// Send post request
DataOutputStream wr = new DataOutputStream(httpsURLCon.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
System.out.println("HTTP Status Get JWT call:" + Integer.toString(httpsURLCon.getResponseCode()));
System.out.println("HTTP ResponseMessage " + httpsURLCon.getResponseMessage());
if (httpsURLCon.getResponseCode() == HttpsURLConnection.HTTP_OK) {
InputStream responseInputStr = httpsURLCon.getInputStream();
String tokenResponse = null;
if (responseInputStr != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(responseInputStr));
String output;
StringBuffer responseStrBuf = new StringBuffer();
while ((output = br.readLine()) != null) {
// System.out.println(output);
responseStrBuf.append(output);
}
br.close();
tokenResponse = responseStrBuf.toString();
webServiceResponse = tokenResponse;
}
assertTrue(webServiceResponse != null && (!webServiceResponse.isEmpty()));
} else {
fail("FAILED - HTTP Error code: " + httpsURLCon.getResponseCode());
}
} catch (Exception ex) {
System.out.println(ex.toString());
ex.printStackTrace();
fail(ex.toString());
}
}
}
The error displayed on the console is shown below:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Also, I configured the rest call using postman and it works fine after I disabled SSL Certificate Verification.
The code above still requires further tweaking and implementing Base64 conversion for this part Authorization: Basic <base64 of client-id:client-secret>, however, it is falling for SSL configuration issues. I am not familiar with this part, and I need help. I think the SSL Certificate is configured properly on the prod runtime environment, and I need to do the same on my local dev environment but not sure how. I am OK with bypassing this part to make it work same as in postman for the sake of testing the approach. I appreciate your help.

Received fatal alert: handshake_failure webservice

I have hired a web service that sends sms messages to mobile phone. I have tried to make the post request but I amb getting the error:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
The webservice company gave me all the information needed for making the the url: the user, the password, the params needed, the response etc
The gsm param is the mobile phone number.
msg is the message to send.
import java.net.HttpURLConnection;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class Test3 {
public static void main(String[] args) throws Exception {
Test3 obj = new Test3();
System.out.println("Testing 1 - Send Http POST request");
obj.sendPost();
}
private void sendPost() throws Exception {
//
String url = "https://...url/send";//(that url its just an example, its not the real)
HttpsURLConnection httpClient = (HttpsURLConnection) new URL(url).openConnection();
//add reuqest header
httpClient.setRequestMethod("POST");
httpClient.setRequestProperty("User-Agent", "Mozilla/5.0");
httpClient.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
String urlParameters = "?user=TEST_USER&company=XXX&passwd=TEST_PWD&gsm=666000222&type=plus&msg=hello&sender=me";
// Send post request
httpClient.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(httpClient.getOutputStream())) {
wr.writeBytes(urlParameters);
wr.flush();
}
int responseCode = httpClient.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + urlParameters);
System.out.println("Response Code : " + responseCode);
try (BufferedReader in = new BufferedReader(
new InputStreamReader(httpClient.getInputStream()))) {
String line;
StringBuilder response = new StringBuilder();
while ((line = in.readLine()) != null) {
response.append(line);
}
System.out.println(response.toString());
}
}
}
Also If I tried to acces the the webservice call by writting the url to the navbar of Mozilla Firefox I got that error:
Secure Connection Failed
An error occurred during a connection to 'url' SSL peer was unable to negotiate an acceptable set of security parameters.
Error code: SSL_ERROR_HANDSHAKE_FAILURE_ALERT
The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.
Given that the domain in question (push.tempos21.com) works for me with the browser but does not work for you neither with app nor browser, it is likely that it is not a problem of app or browser but of your connection to the target. I suspect that there is some deep inspection firewall or IPS somewhere in the path which allows the initial TCP connect but then blocks the traffic once the target is known from the ClientHello (start of TLS handshake).

HTTP post request fails

I wrote the below code to send post request to an url. When I ran the code I am getting 500 error code. But, when I tried the same url in SOAP UI with the below headers I got the response back. May I know what is wrong in my code. Thanks in advance. I doubt I didn't add the headers properly.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:arm="http://siebel.com/Webservice">
<soapenv:Header>
<UsernameToken xmlns="http://siebel.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://siebel.com/webservices">password</PasswordText>
<SessionType xmlns="http://siebel.com/webservices">Stateless</SessionType>
</soapenv:Header>
<soapenv:Body>
<arm:QueryList_Input>
<arm:SRNum></arm:SRNum>
</arm:QueryList_Input>
</soapenv:Body>
</soapenv:Envelope>
Below is my code.
package com.siebel.Webservice;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class HttpQueryList {
private final String USER_AGENT = "Mozilla/5.0";
public static void main(String[] args) throws Exception {
HttpQueryList http = new HttpQueryList();
System.out.println("\nTesting 2 - Send Http POST request");
http.sendPost();
}
// HTTP POST request
private void sendPost() throws Exception {
String url = "https://mywebsite.org/start.swe";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("POST");
con.setRequestProperty("UsernameToken", "username");
con.setRequestProperty("PasswordText", "password");
String urlParameters = "SWEExtSource=WebService&SWEExtCmd=Execute&WSSOAP=1";
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + urlParameters);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
}
}
In your XML, you are specifying a token. When I have done this using SOAP UI, I have a certificate file that I use. In my case, I put it in my C:\Program Files (x86)\SmartBear\SoapUI-5.2.1\bin folder. Then I configured SOAP UI to use this. Do you have a certificate? If yes, are you referencing it?

ADAL4j java - use refresh token with username and password to get the access token

I am connecting to Azure AD enabled API using java back-end server. I am able to get the Access Token by following java code.
String tenantId = "************";
String username = "***************";
String password = "*************";
String clientId = "**********";
String resource = "***********";
String userEmail = "**********";
AuthenticationContext authContext = null;
AuthenticationResult authResult = null;
ExecutorService service = null;
try
{
service = Executors.newFixedThreadPool( 1 );
String url = "https://login.microsoftonline.com/" + tenantId + "/oauth2/authorize";
authContext = new AuthenticationContext( url, false, service );
Future<AuthenticationResult> future = authContext.acquireToken(
resource,
clientId,
userEmail,
password,
null );
authResult = future.get();
}
catch( Exception ex )
{
ex.printStackTrace();
}
Please note that API provider is is not supporting client credentials currently.
The issue for me is, using the refresh token received in above code to get a new access token.
ADAL4j java library doesn't seems to have any methods supporting this.
A Documentation for java library
But in .NET library there are methods like,
public AuthenticationResult AcquireTokenByRefreshToken(
string refreshToken,
string clientId,
string resource
)
For refreshing access token without any credential provided.
Why these methods are not provided in Java library?. Are there any restrictions?
And what are possible workarounds?
Thanks in advance.
As far as I know, although the Java ADAL4J library doesn't support the method
public AuthenticationResult AcquireTokenByRefreshToken(
string refreshToken,
string clientId,
string resource
)
which is supported in .Net library, both of the two types of libraries are implemented via HTTP REST API.
You could refer to the Refreshing the access tokens in the official document
// Line breaks for legibility only
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&resource=https%3A%2F%2Fservice.contoso.com%2F
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps
I use Postman to test a request for acquiring accessToken by refreshToken without credentials for your reference:
Corresponded, I implemented the request with the following Java codeļ¼š
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.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
public class AcquireTokenByRefreshToken {
static String tenantId = "***";
static String username = "***";
static String password = "***";
static String clientId = "***";
static String resource = "https://graph.windows.net";
static String userEmail = "***";
public static void main(String[] args) throws MalformedURLException, IOException {
AuthenticationContext authContext = null;
AuthenticationResult authResult = null;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
String url = "https://login.microsoftonline.com/" + tenantId + "/oauth2/authorize";
authContext = new AuthenticationContext(url, false, service);
Future<AuthenticationResult> future = authContext.acquireToken(resource, clientId, userEmail, password,
null);
authResult = future.get();
System.out.println("get access token: \n" + authResult.getAccessToken());
System.out.println("get refresh token: \n" + authResult.getRefreshToken());
} catch (Exception ex) {
ex.printStackTrace();
}
// get access token by refresh token
getToken(authResult.getRefreshToken());
}
public static void getToken(String refreshToken) throws IOException {
String encoding = "UTF-8";
String params = "client_id=" + clientId + "&refresh_token=" + refreshToken
+ "&grant_type=refresh_token&resource=https%3A%2F%2Fgraph.windows.net";
String path = "https://login.microsoftonline.com/" + tenantId + "/oauth2/token";
byte[] data = params.getBytes(encoding);
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
conn.setConnectTimeout(5 * 1000);
OutputStream outStream = conn.getOutputStream();
outStream.write(data);
outStream.flush();
outStream.close();
System.out.println(conn.getResponseCode());
System.out.println(conn.getResponseMessage());
BufferedReader br = null;
if (conn.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((conn.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
}
The result printed in console as below :
Hope it helps you.

Server returned HTTP response code: 415 Unsupported media type

I have a rest web service like below.
#POST
#Path("/startProcess")
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.APPLICATION_JSON)
public String startProcess(InputParams inputParams, #Context HttpServletRequest request, #Context HttpServletResponse response) {
ProjectBean projBean = new ProjectBean();
Helper.loadProjectBean(inputParams, projBean);
return "1";
}
Now I am trying to consume it with below main program.
public static void main(String[] args) throws Exception {
StringBuffer response = new StringBuffer();
String taigaServiceUrl = "http://localhost:8181/restServer/rest/TestWebService/startProcess/";
URL url = new URL(taigaServiceUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json");
String userpass = "admin" + ":" + "admin";
String basicAuth = "Basic " + new String(new Base64().encode(userpass.getBytes()));
conn.setRequestProperty("Authorization", basicAuth);
InputParams inputParams = new InputParams();
inputParams.setXXX("xxxx");
inputParams.setYYYY("123456");
inputParams.setZZZZ("ZZZZ");
String json = new Gson().toJson(inputParams);
DataOutputStream os = new DataOutputStream (conn.getOutputStream());
os.write(json.getBytes());
os.flush();
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String inputLine;
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
br.close();
}
But every time I am getting below error.
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 415 for URL: http://localhost:8181/restServer/rest/TestWebService/startProcess/
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at scm.controllers.Test.main(Test.java:64)
As per error the media type is unsupported. In my rest webservice I am consuming JSON and in my main program I am sending JSON. Then where it is breaking?
Well after lot of debugging I found solution of my problem. I needed to add below jars in classpath. Actually Jersey was not able to bind JSON object to the rest service.
jackson-annotations-2.5.4.jar
jackson-core-2.5.4.jar
jackson-databind-2.5.4.jar
jackson-jaxrs-base-2.5.4.jar
jackson-jaxrs-json-provider-2.5.4.jar
jersey-entity-filtering-2.22.2.jar
jersey-media-json-jackson-2.22.2.jar
Have a look at this guide:
I think you need to define a json processor:
https://www.nabisoft.com/tutorials/java-ee/producing-and-consuming-json-or-xml-in-java-rest-services-with-jersey-and-jackson
thanks.
This is the issue with your #Produces and #Consumes.
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.APPLICATION_JSON)
As per the annotation, your endpoint receives JSON and result would be TEXT.
But in your client program, you have mentioned content type as json.
conn.setRequestProperty("Content-Type", "application/json");
Hence client expects a json, where as its not.
Change this as
conn.setRequestProperty("Content-Type", "text/plain");
would work.

Categories