Create digest auth header - java

I want to create a header in order to get a resource from a web service which is protected by a digest auth, I have the login and password but I did not find the right way to create this header like postman.

There're two key points, one is calculate the auth key, the other is pass key in request header. Depending on the service authentication method, you can read documentation of the service to do the calculation. I focus on later part, that you can pass the key in header like below:
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.StringEntity;
public void post() throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
String url = "http://127.0.0.1:5050/vaccine/report";
HttpPost post = new HttpPost(url);
post.addHeader("x-auth-token", "computed value");
String body = "{\n" +
" \"siteId\":3,\n" +
" \"injectCount\":3,\n" +
" \"email\":\"yanghe#xyz.com\"\n" +
"}";
HttpEntity entity = new StringEntity(body, ContentType.APPLICATION_JSON);
post.setEntity(entity);
CloseableHttpResponse response = httpClient.execute(post);
System.out.println("response code: "+ response.getCode());
}
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1.3</version>
</dependency>

No example like the source example. If you want to use request headers:
Select the API Key option from the list in the request Authorization tab
Enter your key in the dialogue box in front of “Key.”
Enter the value corresponding to your key in the dialogue box in front of “value.”
Select between Header and Query params from the list.
This is what the Postman team are saying:
"This method of authorization is a little more complex than the
methods mentioned above. In this method, the server sends some details
when a client sends the first request to the API. During this time,
the server generates an encrypted string using this passed data and
stores it for future purposes. This data contains a “nonce” field ( a
number that you can use only one time), other few details, and a 401
unauthorized response.
After receiving these details from the server, send an array of
data(encrypted), which also contains username and password and the
data that the server sent you in the first place.
When you send the second request, the server matches the stored
encrypted string with the data you sent in your request and decides
whether to authenticate you. Select Digest Auth from the dropdown
list in the Authorization section of a request to use this method."
And they provide exactly how to enter a digest request on Postman:

Related

Getting Invalid Grant on OAuth2 authorization_code post request for Google Play Billing purchase verification

I'm trying to implement purchase verification in my backend as the Google-Play-Billing docs recommend. Following this documentation for subscription purchase verification, it tells me I must make a get request to that URL (Purchases.subscriptions: get) with my android app's package name, subscription_id, and purchase token. However, before I can make a get request to that URL, I must authorize my backend server for API requests. So, following the link in that documentation to here, I began following those steps. I created an OAuth 2.0 client ID, then generated the initial refresh token by going to the next url in my browser. My client_id was set to my OAuth 2.0 client ID that was just generated, and my redirect_uri was set to urn:ietf:wg:oauth:2.0:oob, which I received from the JSON file I downloaded from the Google API Console. I successfully retrieved my initial refresh token and put it in my backend code.
Now the goal is to make a successful purchase in my android app, then send a post request to my backend with the necessary parameters. This part works just fine. However, when following the next steps of the authorization documentation, the part where it says to "Exchange this code for an access and refresh token pair by sending a POST request to..." in order to get my access_code, I set the fields to what the docs say to set the fields to, but my request comes back as a 400 error with the error message: "invalid_grant". I don't understand why I am receiving this error.
Here is my post request code:
List <NameValuePair> parameters = new ArrayList <>();
parameters.add(new BasicNameValuePair("grant_type", "authorization_code"));
parameters.add(new BasicNameValuePair("code", initial_code));
parameters.add(new BasicNameValuePair("client_id", client_id));
parameters.add(new BasicNameValuePair("client_secret", client_secret));
parameters.add(new BasicNameValuePair("redirect_uri", redirect_uri));
RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
HttpClientBuilder httpClientBuilder = HttpClients.custom().setDefaultRequestConfig(requestConfig);
try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
HttpPost request = new HttpPost("https://accounts.google.com/o/oauth2/token");
request.addHeader("content-type", "application/x-www-form-urlencoded");
request.setEntity(new UrlEncodedFormEntity(parameters));
try (CloseableHttpResponse response = httpClient.execute(request)) {
HttpEntity entity = response.getEntity();
final StatusLine statusLine = response.getStatusLine();
if (entity != null) {
System.out.println("Response returned: " + statusLine.getStatusCode() + " - " + EntityUtils.toString(entity));
}
}
}
Please help!
Okay, I figured out my problem. I need to be faster about making that first post request to exchange the initial refresh_token for and access_code and new refresh_token. That new refresh_token will end up being my permanent refresh_token for all future api requests. My problem was that the initial refresh_token kept expiring before I made my initial post request. I didn't realize it would expire in 1 hour, and so I kept using the same initial refresh_token without realizing that it was expired.
I followed the rest of the steps on google's docs, and now my backend server is successfully validating my in app subscription purchases.

AKAMAI CCU Fast Purge implementation

Am trying to implement the CCU fast purge call via JAVA and am referencing this doucument
https://developer.akamai.com/api/purge/ccu/reference.html
import javax.ws.rs.core.MediaType;
Client client = ClientBuilder.newClient();
Entity payload = Entity.json("{ 'hostname': 'www.example.com', 'objects': [ '/graphics/picture.gif', '/documents/brochure.pdf' ]}");
Response response = client.target("https://private-anon-3f6068ab95-akamaiopen2ccuccuproduction.apiary-mock.com/ccu/v3/delete/url/{network}")
.request(MediaType.APPLICATION_JSON_TYPE)
.post(payload);
System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));
here am getting confused with the objects and the client.target url that needs to be specified.
" objects': [ '/graphics/picture.gif', '/documents/brochure.pdf'
] "
Are these objects and client.target urls will be unique to my application and the account that is going to be created.?
and also is there any thing that i have to pass in headers for the validation or authentications.?
You need to:
Get credentials for your client using Luna (https://control.akamai.com)
Click "Configure... Manage APIs"
Select "CCU APIs" in the left hand side
Create new collection, create new client
Create authorization
Click the "Export" button at the top to grab the credentials, including the URL
Use these credentials and the Java signing client at https://github.com/akamai-open/AkamaiOPEN-edgegrid-java to make the call
There is sample code on the page for the Java signing client showing how to make calls to the system.

Sending an HTTP POST request in Java and accepting the POST request in PHP

What I need to do is send a username and password to a php script via a HTTP POST request so that I can query a database for the correct information. Currently I am stuck on both sending the POST request as well as receiving it.
To send a username and password I am using the following:
public class post {
public static void main(String[] args) throws ClientProtocolException, IOException {
HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost("http://www.example.com/practice.php");
// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>(2);
params.add(new BasicNameValuePair("username", "user"));
params.add(new BasicNameValuePair("password", "hunter2"));
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
//Execute and get the response.
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
try {
// do something useful
} finally {
instream.close();
}
}
}
}
The php script I am using to collect the information is the following, it's simple but it's just for testing at the moment.
<?php
$username = $_POST['username'];
$password = $_POST['password'];
echo "username = $username<br>";
echo "password = $password<br>";
?>
I was wondering if someone could help me out by moving me in the correct direction of accepting a HTTP POST request in php from Java, or if I am even sending the post request correctly, any help is greatly appreciated.
Now, there are a few things, I would suggest you to keep in mind, while doing this.
Try Making use of JSON:
Json stands for JavaScript Object Notation. Itis a lightweight, text-based, language-independent data exchange format that is easy for humans and machines to read and write.
public static void main(String[] args){
JSONObject obj = new JSONObject();
obj.put("username", username);
obj.put("password", password);
System.out.print(obj);
// And then, send this via POST Method.
}
}
For Php part,
...
$data = file_get_contents("php://input");
$json = json_decode($data);
$username = $json['username'];
$password = $json['password'];
...
Here is a good reference for that Json
Make Use of Sessions When you work with an application, you open it, do some changes, and then you close it. This is much like a Session. The computer knows who you are. It knows when you start the application and when you end. But on the internet there is one problem: the web server does not know who you are or what you do, because the HTTP address doesn't maintain state.
Session variables solve this problem by storing user information to be used across multiple pages (e.g. username, favorite color, etc). By default, session variables last until the user closes the browser.
<?php
$_SESSION["user"] = "green";
echo "Session variables are set.";
// Now store this in your database in a separate table and set its expiry date and time.
?>
Here is a reference to that as well sessions.
Use SSL : Secure Socket Layer (SSL) technology is security that is implemented at the transport layer.SSL allows web browsers and web servers to communicate over a secure connection. In this secure connection, the data that is being sent is encrypted before being sent and then is decrypted upon receipt and before processing. Both the browser and the server encrypt all traffic before sending any data. SSL addresses the following important security considerations.
a. Authentication: During your initial attempt to communicate with a web server over a secure connection, that server will present your web browser with a set of credentials in the form of a server certificate. The purpose of the certificate is to verify that the site is who and what it claims to be. In some cases, the server may request a certificate that the client is who and what it claims to be (which is known as client authentication).
b. Confidentiality: When data is being passed between the client and the server on a network, third parties can view and intercept this data. SSL responses are encrypted so that the data cannot be deciphered by the third party and the data remains confidential.
c. Integrity: When data is being passed between the client and the server on a network, third parties can view and intercept this data. SSL helps guarantee that the data will not be modified in transit by that third party.
And, Here are a few references for that as well.
SSL Establishment Documentation, SSL with Java

Google Play Developer API - Query purchase token returns Invalid Value

I am trying to set up a web service to query Google Play purchases. We store the order information for customers and this service would call Google Play API to query the subscription details.
Every time i try to query a purchase, it gives me the error:
HTTP/1.1 400 Bad Request
{
"error":{
"errors":[
{
"domain":"global",
"reason":"invalid",
"message":"Invalid Value"
}
],
"code":400,
"message":"Invalid Value"
}
}
Here is what I tried:
Created a project in https://console.developers.google.com enabled the "Google Play Android Developer API"
Created an oAuth 2.0 client_id and client_secret for type Web application
Logged in as the account owner, I generated a refresh_token
In https://play.google.com/apps/publish I went to Settings -> API Access and linked the the project to my app
Code wise, I used the refresh_token to get an access_token:
String refreshToken = "1/ljll6d9ME3Uc13jMrBweqXugV4g4timYcXXXXXXXXX";
HttpPost request = new HttpPost("https://accounts.google.com/o/oauth2/token");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("client_id", client_id));
params.add(new BasicNameValuePair("client_secret", client_secret));
params.add(new BasicNameValuePair("refresh_token", refreshToken));
params.add(new BasicNameValuePair("grant_type", "refresh_token"));
request.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
JSONObject json = new JSONObject(body);
String accessToken = json.getString("access_token");
The access_token from this works because i can call this API with it and get the response back:
String url = String.format("https://www.googleapis.com/androidpublisher/v2/applications/%s/inappproducts/%s", packageName, productId);
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
get.setHeader("Authorization", "Bearer " + accessToken);
HttpResponse response = client.execute(get);
// parse response etc...
This returns:
{
"packageName":"com.my.app",
"sku":"com.my.app.premium",
"status":"active",
"purchaseType":"subscription",
"defaultPrice":{
//...
}
},
"listings":{
"en-US":{
"title":"My App Premium",
"description":"My App"
}
},
"defaultLanguage":"en-US",
"subscriptionPeriod":"P1Y"
}
Now, I want to get informatoin about a purchase. I have a information from a purchase as such:
{
"orderId":"GPA.1111-1111-1111-11111",
"packageName":"com.my.app",
"productId":"com.my.app.premium",
"purchaseTime":1452801843877,
"purchaseState":0,
"developerPayload":"XXXXXXXd9261023a407ae5bb6ab8XXXXXXX",
"purchaseToken":"xxxxxxxxxxxxxx.YY-J123o12-xxxxxxxxxxxxxxxmYRk2itBkNdlXhyLMjXsxxxxxxxxxxxxLfBxabaAjKbeBC0PVhHnHd1DDbFkgZtbQxxk5pDIAH3xBHu8HrcWfRgewAYnFeW9xxxxxxxxxxxxxC5TDjcBL8fhf",
"autoRenewing":true
}
String url = String.format("https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/products/%s/tokens/%s",packageName, productId, purchaseToken);
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
get.setHeader("Authorization", "Bearer " + accessToken);
HttpResponse response = client.execute(get);
// parse response etc...
Since the packageName / productId and access_token seem to work for the first call, and the purchaseToken is right out of the order info. What is giving the invalid value error?
Any help appreciated - not sure what else to try. Thanks!
UPDATE:
I went through and validated all the package names and account setup
The real issue seemed to be the service i was hitting. I switched it to:
https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/purchaseToken
I also swapped to use the Google Client API as it was much cleaner looking that manually creating requests.
Thanks for help and replies
First I want to share with you what is 400 bad request and what is the
real cause for occuring it?
Ans: It indicates that the query was invalid. E.g., parent ID was missing or the combination of dimensions or metrics requested was not valid.
Recommended Action: You need to make changes to the API query in order for it to work.
Resource Link: Standard Error Responses
Your problem:
Your code was running properly and returning related json file as output. But after a period,it is not working when you want to get information about purchase. It gives error message "HTTP/1.1 400 Bad Request"
Root cause:
For refresh token, the response always includes a new access token. A response is shown below:
{
"access_token":"1/fFBGRNJru1FQd44AzqT3ZgXXXXXX",
"expires_in":3920,
"token_type":"Bearer",
}
So, access token has a expiry time. after a expiry time, the access token will not work.
There is another restriction also. There are limits on the number of refresh tokens that will be issued; one limit per client/user combination, and another per user across all clients.
So, in your case, you have already crossed your limit of creating refresh token.
Solution:
So, you first need to revoke the token. Then save refresh tokens in long-term storage and continue to use them as long as they remain valid.
As you are using refresh token, then you need to change the http post request https://accounts.google.com/o/oauth2/token to https://www.googleapis.com/oauth2/v4/token
So your code will be look like below:
String refreshToken = "1/ljll6d9ME3Uc13jMrBweqXugV4g4timYcXXXXXXXXX";
HttpPost request = new HttpPost("https://www.googleapis.com/oauth2/v4/token");
List<NameValuePair> params = new ArrayList<NameValuePair>();
...............
...............
Revoking procedure:
There are 2 ways for revoking.
A user can revoke access by visiting Account Settings
It is also possible for an application to programmatically revoke the access given to it.
To programmatically revoke a token, your application makes a request to https://accounts.google.com/o/oauth2/revoke and includes the token as a parameter:
curl https://accounts.google.com/o/oauth2/revoke?token={token}
The token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.
N.B: If the revocation is successfully processed, then the status code
of the response is 200. For error conditions, a status code 400 is
returned along with an error code.
Resource Link:
Offline access, Using refresh token and Revoke a token
This happened to me when I was testing with Static Responses, i.e. using reserved product IDs for testing (like android.test.purchased). SkyWalker's solution did not help in this case.
Then I used real product IDs, published my app as alpha to google play and side-loaded the release apk into my device and now everything works as expected.
Be sure to read carefully chapter Setting Up for Test Purchases in google docs to prepare your app and account properly for testing.
Check out this to see API request and response. Need help with the API Explorer
API: https://www.googleapis.com/androidpublisher/v1.1/applications/packageName/subscriptions/subscriptionId/purchases/token
Request parameters:
packageName:PACKAGE_NAME
subscriptionId:SUBSCRIPTION_ID
token:PURCHASE_TOKEN

What is the right way to sign POST requests with OAuth-Signpost and Apache HttpComponents?

I'm currently using the OAuth-Signpost Java library to sign requests sent from a client to a server which implements OAuth authentication. When making GET requests (using HttpURLConnection) everything works fine: requests are signed, parameters are included and signatures match in destination. However, it doesn't seem to work with POST requests. I'm aware of the issues that may come up when signing POST using HttpURLConnection, so I moved to the Apache HttpComponents library for these requests. The parameters I send in the following example are plain strings and a XML-like string ('rxml'). My code goes as follows:
public Response exampleMethod(String user, String sp, String ep, String rn, String rxml){
//All these variables are proved to be correct (they work right in GET requests)
String uri = "...";
String consumerKey = "...";
String consumerSecret = "...";
String token = "...";
String secret = "...";
//create the parameters list
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("user", user));
params.add(new BasicNameValuePair("sp", sp));
params.add(new BasicNameValuePair("ep", ep));
params.add(new BasicNameValuePair("rn", rn));
params.add(new BasicNameValuePair("rxml", rxml));
// create a consumer object and configure it with the access
// token and token secret obtained from the service provider
OAuthConsumer consumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
consumer.setTokenWithSecret(token, secret);
// create an HTTP request to a protected resource
HttpPost request = new HttpPost(uri);
// sign the request
consumer.sign(request);
// set the parameters into the request
request.setEntity(new UrlEncodedFormEntity(params));
// send the request
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
//if request was unsuccessful
if(response.getStatusLine().getStatusCode()!=200){
return Response.status(response.getStatusLine().getStatusCode()).build();
}
//if successful, return the response body
HttpEntity resEntity = response.getEntity();
String responseBody = "";
if (resEntity != null) {
responseBody = EntityUtils.toString(resEntity);
}
EntityUtils.consume(resEntity);
httpClient.getConnectionManager().shutdown();
return Response.status(200).entity(responseBody).build();
}
When I send a POST request to the server I get an error telling that the signatures (the one I send and the one the server calculates by itself) don't match, so I guess it has to do with the base string they are signing and the way the POST signing works, since they're handling the same keys and secrets in both sides (checked).
I've read that a way to go through this is setting the parameters as part of the URL (as in a GET request). It wouldn't work for me though, since the XML parameter may exceed the URL length so it needs to be sent as a POST parameter.
I suppose I'm doing something wrong either signing the POST requests or handling the parameters, but I don't know what it is. Please, could you help me out?
P.S: I apologize if I lack context, error traces or additional information regarding this issue, but I'm newbie around here. So please don't hesitate to ask me for more information if you need it.
A bit of backstory/explanation
I've been having a similar problem for the past couple of days, and had almost given up. Until I heard that the guy at my company that was putting up the services I was communicating with, had configured them to read the OAuth information from the query string instead of header parameters.
So instead of reading it from the header parameter Authorization that Signpost puts into the request when you pass it on to be signed, for instance [Authorization: OAuth oauth_consumer_key="USER", oauth_nonce="4027096421883800497", oauth_signature="Vd%2BJEb0KnUhEv1E1g3nf4Vl3SSM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1363100774", oauth_version="1.0"], the services where trying to read the query string, for example http://myservice.mycompany.com?oauth_consumer_key=USER&oauth_nonce=4027096421883800497&oauth_signature=Vd%2BJEb0KnUhEv1E1g3nf4Vl3SSM%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1363100774&oauth_version=1.0.
The problem with this is that when I tried to sign the url and then build a HttpPost request with it, the url got a basestring with the prefix GET instead of POST which gave another signature then the one the service computed. Signpost isn't doing anything wrong, its url signing method is just by default set to GET with no other possibility available out of the box. This is so because you should read header parameters when doing POST, not the query string (Going to egg the house of that "colleague" of mine), and Signpost adds these when signing request which you should do when doing POST.
The signingbasestring can be observed in the SigningBaseString class method generate in Signpost.
Solution
Now this is how I did it, but other ways may be possible or even better.
Get the signpost source code and add it to your project. Can get it here
Locate the OAuthConsumer class and change the signing method so that you can pass on information that the request should be POST. In my case I added a boolean like so public String sign(String url, boolean POST)
Now you need to change the sign method in the AbstractOAuthConsumer class, which CommonsHttpOAuthConsumer and DefaultOAuthConsumer extend. In my case I added the boolean variable to the method and the following if(POST) request.setMethod("POST"); right before the method calls sign(request);
Now the request is a Signpost specific object, HTTPRequest, so this will throw an error. You'll need to change it and add the method public void setMethod(String method);.
This will cause an error in the following classes HttpURLConnectionRequestAdapter, HttpRequestAdapter and UrlStringRequestAdapter. You'll need to add the method implementation to them all, but in different flavors. For the first you'll add
public void setMethod(String method){
try {
this.connection.setRequestMethod(method);
} catch (ProtocolException e) {
e.printStackTrace();
}
}
for the second you'll add
public void setMethod(String method){
try {
RequestWrapper wrapper = new RequestWrapper(this.request);
wrapper.setMethod(method);
request = wrapper;
} catch (org.apache.http.ProtocolException e) {
e.printStackTrace();
}
}
and for the last you'll add
public void setMethod(String method){
mMethod = method;
}
Be warned that I've only used and tried the first and last. But this at least gives you an idea about how to fix the problem, if you are having the same one as I.
Hope this helps in anyway.
-MrDresden
Signing POST requests using oauth-signpost and HttpURLConnection is doable, but it requires a bit of a hack:
The trick is to percent-encode the POST parameters, and add them to the OAuth library using method setAdditionalParameters().
See this article for an example.
This answer helped me.
but for PALINTEXT method, you do not need to have params and also url.
they don't change the signature. signature is constant and based on secrets.
but for SHA1 (and other methods) you can use the above answer.

Categories