How to get access token using gmail api - java

I got the authorization code following this document. But when I tried to get access token, I always got errors. Can anyone help me ?
public String AccessToken()
{
String accessToken = "";
StringBuilder strBuild = new StringBuilder();
String authURL = "https://accounts.google.com/o/oauth2/token?";
String code = "4/SVisuz_x*********************";
String client_id = "******************e.apps.googleusercontent.com";
String client_secret = "*******************";
String redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
String grant_type="authorization_code";
strBuild.append("code=").append(code)
.append("&client_id=").append(client_id)
.append("&client_secret=").append(client_secret)
.append("&redirect_uri=").append(redirect_uri)
.append("&grant_type=").append(grant_type);
System.out.println(strBuild.toString());
try{
URL obj = new URL(authURL);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
con.setRequestProperty("Host", "www.googleapis.com");
//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()));
//bw.write(strBuild.toString());
//bw.close();
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(strBuild.toString());
wr.flush();
wr.close();
//OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
System.out.println(con.getResponseCode());
System.out.println(con.getResponseMessage());
} catch (Exception e)
{
System.out.println("Error.");
}
return "";
}
when I ran this code, the output is:
400
Bad Request

How to get access token using gmail api?
Ans: As per your following tutorial, you are using OAuth 2.0. So there is a basic pattern for accessing a Google API using OAuth 2.0. It follows 4 steps:
Obtain OAuth 2.0 credentials from the Google Developers Console.
Obtain an access token from the Google Authorization Server.
Send the access token to an API.
Refresh the access token, if necessary.
For details, you can follow the tutorial - Using OAuth 2.0 to Access Google APIs
You have to visit the Google Developers Console to obtain OAuth 2.0 credentials such as a client ID and client secret that are known to both Google and your application
Root Cause Analysis:
Issue-1:
After studying your code, some lacking are found. If your code runs smoothly, then the code always give an empty string. Because your AccessToken() method always return return "";
Issue-2:
catch (Exception e)
{
System.out.println("Error.");
}
Your try catch block is going exception block. Because, it seems that you have not completed your code properly. You have missed encoding as well as using JSONObject which prepares the access token. So it is giving output as
Error.
Solution:
I got that your code is similar with this tutorial
As your code needs more changes to solve your issue. So I offer you to use LinkedHashMap or ArrayList. Those will provide easier way to make solution. So I give you 2 sample code to make your life easier. You can choose any of them. You need to change refresh_token, client id, client secret and grant type as yours.
private String getAccessToken()
{
try
{
Map<String,Object> params = new LinkedHashMap<>();
params.put("grant_type","refresh_token");
params.put("client_id",[YOUR CLIENT ID]);
params.put("client_secret",[YOUR CLIENT SECRET]);
params.put("refresh_token",[YOUR REFRESH TOKEN]);
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");
URL url = new URL("https://accounts.google.com/o/oauth2/token");
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestMethod("POST");
con.getOutputStream().write(postDataBytes);
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuffer buffer = new StringBuffer();
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
String accessToken = json.getString("access_token");
return accessToken;
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
For accessing google play android developer api, you need to pass the
previous refresh token to get access token
private String getAccessToken(String refreshToken){
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/token");
try
{
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("grant_type", "refresh_token"));
nameValuePairs.add(new BasicNameValuePair("client_id", GOOGLE_CLIENT_ID));
nameValuePairs.add(new BasicNameValuePair("client_secret", GOOGLE_CLIENT_SECRET));
nameValuePairs.add(new BasicNameValuePair("refresh_token", refreshToken));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
org.apache.http.HttpResponse response = client.execute(post);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer buffer = new StringBuffer();
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
buffer.append(line);
}
JSONObject json = new JSONObject(buffer.toString());
String accessToken = json.getString("access_token");
return accessToken;
}
catch (IOException e) { e.printStackTrace(); }
return null;
}
Resource Link:
Unable to get the subscription information from Google Play Android Developer API
Using java.net.URLConnection to fire and handle HTTP requests
How to send HTTP request GET/POST in Java
Hope that, this samples and resource link will help you to solve your issue and get access of access token.
What is 400 bad request?
Ans: It indicates that the query was invalid. 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.
For HTTP/1.1 400 Bad Request error, you can go through my another
answer. It will help you to make sense about which host you
need to use and which conditions you need to apply.
Why token expires? What is the limit of token?
A token might stop working for one of these reasons:
The user has revoked access.
The token has not been used for six months.
The user changed passwords and the token contains Gmail, Calendar,
Contacts, or Hangouts scopes.
The user account has exceeded a certain number of token requests.
There is currently a limit of 25 refresh tokens per user account per client. If the limit is reached, creating a new token automatically invalidates the oldest token without warning. This limit does not apply to service accounts.
Which precautions should be followed?
Precautions - 1:
Some requests require an authentication step where the user logs in
with their Google account. After logging in, the user is asked whether
they are willing to grant the permissions that your application is
requesting. This process is called user consent.
If the user grants the permission, the Google Authorization Server
sends your application an access token (or an authorization code that
your application can use to obtain an access token). If the user does
not grant the permission, the server returns an error.
Precautions - 2:
If an access token is issued for the Google+ API, it does not grant
access to the Google Contacts API. You can, however, send that access
token to the Google+ API multiple times for similar operations.
Precautions - 3:
An access token typically has an expiration date of 1 hour, after
which you will get an error if you try to use it. Google Credential
takes care of automatically "refreshing" the token, which simply means
getting a new access token.
Save refresh tokens in secure long-term storage and continue to use
them as long as they remain valid. Limits apply to the number of
refresh tokens that are issued per client-user combination, and per
user across all clients, and these limits are different. If your
application requests enough refresh tokens to go over one of the
limits, older refresh tokens stop working.

You are not using the right endpoint. Try to change the authURL to https://www.googleapis.com/oauth2/v4/token
From the documentation:
To make this token request, send an HTTP POST request to the /oauth2/v4/token endpoint
The actual request might look like the following:
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/v6xr77ewYqhvHSyW6UJ1w7jKwAzu&
client_id=8819981768.apps.googleusercontent.com&
client_secret=your_client_secret&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
Reference https://developers.google.com/identity/protocols/OAuth2InstalledApp#handlingtheresponse

For me your request is fine, I tried it using Curl, I also get a 'HTTP/1.1 400 Bad Request' with the reason why it failed 'invalid_grant' :
curl -X POST https://www.googleapis.com/oauth2/v4/token -d 'code=4/SVisuz_x*********************&client_id=*******************7vet.apps.googleusercontent.com&client_secret=***************&redirect_uri=https://oauth2-login-demo.appspot.com/code&grant_type=authorization_code'
I receive (HTTP/1.1 400 Bad Request) :
{
"error": "invalid_grant",
"error_description": "Code was already redeemed."
}
Now using HttpClient from Apache :
URL obj = new URL(authURL);
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(authURL);
post.addHeader("Content-Type", "application/x-www-form-urlencoded");
post.addHeader("Host", "www.googleapis.com");
post.setEntity(new StringEntity(strBuild.toString()));
HttpResponse resp = client.execute(post);
System.out.println(resp.getStatusLine());
System.out.println(EntityUtils.toString(resp.getEntity()));
I see in my console :
HTTP/1.1 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Code was already redeemed."
}
Are you sure the code you are using is still valid ? Can you try with a new one ?

Firstly, you must look this page :
https://developers.google.com/gmail/api/auth/web-server#create_a_client_id_and_client_secret
The value you see in the query parameter code is a string you have to post to google in order to get the access token.
After the web server receives the authorization code, it may exchange the authorization code for an access token and a refresh token. This request is an HTTPS POST to the URL https://www.googleapis.com/oauth2/v3/token
POST /oauth2/v3/token HTTP/1.1
content-type: application/x-www-form-urlencoded
code=4/v4-CqVXkhiTkn9uapv6V0iqUmelHNnbLRr1EbErzkQw#&redirect_uri=&client_id=&scope=&client_secret=************&grant_type=authorization_code
https://developers.google.com/identity/protocols/OAuth2WebServer

I think I understand what's wrong:
as #newhouse said, you should POST to https://www.googleapis.com/oauth2/v4/token and not https://accounts.google.com/o/oauth2/token (#newhouse I gave you a +1 :) )
(https://www.googleapis.com/oauth2/v4/token is for getting the authorization_code and https://accounts.google.com/o/oauth2/token is for getting the code).
You can't use the same code more than once.
Everything else seems in order so, if you keep getting 400, you are probably trying to use the code you got more than one time (then you'll get 400 every time, again and again).
* You should also lose the con.setRequestProperty("Host", "www.googleapis.com");

Refer : https://developers.google.com/android-publisher/authorization
You already have authorization code that is called "refresh token". Please keep it in safe place. You can use "refresh token" to generate "access token".
To get "access token", please make a post request to following URL
https://accounts.google.com/o/oauth2/token
Parameters:
grant_type
client_id
client_secret
refresh_token
where "grant_type" should be "refresh_token"
We are using PHP to do same, here is PHP's code for your reference
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => 'https://accounts.google.com/o/oauth2/token',
CURLOPT_USERAGENT => 'Pocket Experts Services',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => array(
"grant_type" => "refresh_token",
"client_id" => $GOOGLE_CLIENT_ID,
"client_secret" => $GOOGLE_CLIENT_SECRET,
"refresh_token" => $GOOGLE_REFRESH_TOKEN,
)));
// Send the request & save response to $resp
$resp = curl_exec($curl);
Hope it will help you.

the low security methode was temporary and i couldn't use it in production but I found an article that made it easier using node here
with an example code and it works perfect

Related

How to make a get MS Graph Request with access code?

I'm trying to list items from some list in Office 365 SharePoint from a java native Windows app.
I'm using deprecated office-365-java-sdk to authenticate and get an access token. Yes, this SDK is deprecated but authentication still works. So, I have an access token.
So, next step is to make GET request. In Graph Explorer this URL works fine:
/v1.0/sites/root/lists/{site-id}/items
I followed documentation to build the request and I have to add a header with authentication token so this is my code:
StringBuilder result = new StringBuilder();
URL url = new URL("https://graph.microsoft.com/v1.0/sites/root/lists/{0a506dcb-ecbc-40ed-bf2c-5912e78e3ca8}/items");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + access_token);
conn.setRequestProperty("Content-type", "application/json");
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null)
{
result.append(line);
}
rd.close();
System.out.println(result.toString());
Authentication is working, because if access token header is not added, it returns a status error code of 401 Required authentication information is either missing or not valid for the resource. But with an access code, it returns error code 400 Cannot process the request because it is malformed or incorrect.
I'm stuck with this, I read the documentation again and again and after checking URL is right using Graph Explorer, I don't know if this is not the right way to include headers or what....
The correct header to pass is Accept: application/json.
So, replace the conn.setRequestProperty("Content-type","application/json"); with
conn.setRequestProperty("Accept","application/json");

Post to SharePoint 2013 from Java

I've tried to connect to our SharePoint and POST some data to a list.
A user can interact with a Web-App and send some Information. These data will be send to a Java-Web-Interface running on a tomcat. The Java-Code should connect to our SharePoint and post the data in the list. Today, I read a lot of tutorials and ressources on the web... Most of them are deprecated ore discuss lightly different situations! SO! My mind whispered: "Go on and visit stackoverflow." And here I am, asking this question:
The Situation is described above. I call a web-Interface vie JS (angularJS) and pass an E-Mail-Adress which the user enters in the front-end. Here it goes in:
#Path("webservice")
public class SetEmail {
#POST
#Path("/SetEmail")
#Consumes(MediaType.APPLICATION_JSON + ";charset=UTF-8")
#Produces("text/plain")
public String addItem(String incoming) throws ClientProtocolException, IOException, AuthenticationException{
String result = "error";
JSONObject jsonObj = new JSONObject(incoming);
String listName = "Leads";
String username = "...";
char[] password= new char[]{'...', '...', ...};
String website = "...";
Now, after all I read, I have to get the DigestValue from SharePoint, because I want to make a POST-Request:
//Get the Digestvalue.
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(AuthScope.ANY, new NTCredentials(username, password.toString(), "http://...", "https://..."));
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpPost httpPost = new HttpPost(website + "_api/contextinfo");
httpPost.addHeader("Accept", "application/json;odata=verbose");
httpPost.addHeader("content-type", "application/json;odata=verbose");
httpPost.addHeader("X-ClientService-ClientTag", "SDK-JAVA");
HttpResponse response = client.execute(httpPost);
byte[] content = EntityUtils.toByteArray(response.getEntity());
String jsonString = new String(content, "UTF-8");
System.out.println(response);
JSONObject json = new JSONObject(jsonString);
String FormDigestValue = json.getJSONObject("d").getJSONObject("GetContextWebInformation").getString("FormDigestValue");
After getting the Digest, I am able to execute the actual request:
//POST the data.
CloseableHttpClient client2 = HttpClients.createDefault();
HttpPost httpPost2 = new HttpPost(website + "_api/web/lists/GetByTitle(" + listName + ")");
httpPost2.setEntity(new StringEntity("test post"));
NTCredentials creds = new NTCredentials(username, password.toString(), "http://...", "https://...");
httpPost2.addHeader(new BasicScheme().authenticate(creds, httpPost2, null));
httpPost2.addHeader("X-RequestDigest", FormDigestValue);
httpPost2.addHeader("Accept", "application/json;odata=verbose");
httpPost2.addHeader("Content-Type", "application/json;odata=verbose");
CloseableHttpResponse response2 = client2.execute(httpPost2);
System.out.println(response2);
client2.close();
}
}
I know this isn't the most beautiful Code and yes, I am not an Java expert. My Problems are:
I don't know weather all of these code-Fragments are up to date or
weather I am using deprecated ones. Perhaps someone is able to
enlighten me.
I am using HttpClient from Apache. To me it looked like the most
usable library. Is that right?
Everytime I execute the Action on the front-end and my Code starts
running, I am getting an HTTP 401 Unauthorized error. I tried
various Kinds of Code but none worked well.
HttpResponseProxy{HTTP/1.1 401 Unauthorized [Server: Microsoft-IIS/8.0, SPR..
Perhaps someone has the Patience to tell me how to do it. Thank you.
Whoa... you are really trying some black magic here ;) - I would suggest you to get your HTTP POST / GET in a tool like Postman or some other REST tool working and then return to your code.
I don't know exactly what you are trying to achieve, but it might be easier to go via powershell (if you are trying to create a migration script) or JavaScript (if you are on a website).
Be aware that authentication differs in SharePoint online and SharePoint on premise... this is also customizable by your company (you can for example implement forms-based auth as well). Be sure to know what YOUR SharePoint is using. (Or share some more info, so we can help)

Digest authentication in Android using HttpURLConnection

as the question allready says, I am trying to do digest authentication in android.
Until now i have used the DefaultHttpClient and it's authentication method (using UsernamePasswordCredentials and so on), but it is deprecated since Android 5 and will be removed in Android 6.
So i am about to switch from DefaultHttpClient to HttpUrlConnection.
Now i am trying to achieve digest authentication, which should work pretty simple as explained here:
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
But the getPasswordAuthentication gets never called for some reason.
During my search for this problem i found different posts, saying digest authentication is not supported by the HttpUrlConnection in android, but those posts are from 2010-2012, so i am not sure if this is still true. Also we are using HttpUrlConnection with digest authentication in our desktop java application, where it does work.
I also found some posts, talking about OkHttp. OkHttp seems to be used by Android under the hood (to be more specific the HttpUrlConnectionImpl). But this HttpUrlConnectionImpl is a bit strange, it is not even shown in the Eclipse type hierarchy and i am not able to debug it. Also it should be a com.squareup.okhttp.internal.huc.HttpUrlConnectionImpl, while in android it is a com.android.okhttp.internal.http.HttpUrlConnectionImpl.
So i am just not able to do digest authentication with this HttpUrlConnection in android.
Can anyone tell me how to do that without external libraries?
EDIT:
The server asks for digest authentication:
WWW-Authenticate: Digest realm="Realm Name",domain="/domain",nonce="nonce",algorithm=MD5,qop="auth"
So Basic-Authentication shouldn' work, as the server is asking for digest.
The answer is, that HttpUrlConnection does not support digest.
You therefore have to implement RFC2617 by yourself.
You can use the following code as a baseline implementation: HTTP Digest Auth for Android.
The steps involve (see RFC2617 for reference):
If you get a 401 response, iterate over all WWW-Authenticate headers and parse them:
Check if algorithm is MD5 or undefined, (optionally select the auth qop option), otherwise ignore the challenge and go to the next header.
Get the credentials using Authenticator.requestPasswordAuthentication.
Calculate H(A1) using the username, realm and password.
Store the canonical root URL, realm, HA1, username, nonce (+ optionally algorithm, opaque and the client selected qop option if present).
Retry the request.
On each request, iterate over all realms you have session information stored for by canonical root URL:
Calculate H(A2) using the request method and path.
Calculate H(A3) using HA1, nonce (+ optionally nc, cnonce, qop) and HA2.
Build and add the Authorization header to your HttpUrlConnection.
Implement some sort of session pruning.
By using Authenticator, you can make sure, that as soon as HttpUrlConnection supports digest natively, your code is not being used anymore (because you wont receive the 401 in the first place).
This is just a quick summary on how to implement it, for you to get an idea.
If you want to go further you would probably like to implement SHA256 as well: RFC7616
It is correct that HttpUrlConnection does not support Digest authentication. If your client must authenticate using Digest, you have a few options:
Write your own HTTP Digest implementation. This can be a good option if you know which servers that you need to authenticate with and can ignore the parts of the the digest specification that you do not need. Here is an example where a subset of digest is implemented: https://gist.github.com/slightfoot/5624590.
Use the external lib bare-bones-digest, which is a Digest lib for Android. You can use it to parse Digest challenges and generate responses to them. It supports the common digest use cases and some of the rarely used ones and can be used on top of HttpURLConnection.
Use OkHttp together with okhttp-digest, which is a plugin that adds Http Digest support to OkHttp. Supporting Digest with OkHttp is easy, just add okhttp-digest as an authenticator and you will have transparent Http digest support. If you already use OkHttp or are OK with switching to it this can be an attractive option.
Use the Apache HttpClient which supports Digest. The question explicitly states that HttpClient is not an option so I include it mostly for completion's sake. Google does not recommend using HttpClient and has deprecated it.
Did you try to set the header manually like:
String basic = "Basic " + new String(Base64.encode("username:password".getBytes(),Base64.NO_WRAP ));
connection.setRequestProperty ("Authorization", basic);
Also be aware of some issues in Jellybeans and a bug when you try to perform a post request: HTTP Basic Authentication issue on Android Jelly Bean 4.1 using HttpURLConnection
EDIT: For Digest authentication
Have a look here https://code.google.com/p/android/issues/detail?id=9579
Especially this might work:
try {
HttpClient client = new HttpClient(
new MultiThreadedHttpConnectionManager());
client.getParams().setAuthenticationPreemptive(true);
Credentials credentials = new UsernamePasswordCredentials("username", "password");
client.getState().setCredentials(AuthScope.ANY, credentials);
List<String> authPrefs = new ArrayList<String>(2);
authPrefs.add(AuthPolicy.DIGEST);
authPrefs.add(AuthPolicy.BASIC);
client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY,
authPrefs);
GetMethod getMethod = new GetMethod("your_url");
getMethod.setRequestHeader("Accept", "application/xml");
client.executeMethod(getMethod);
int status = getMethod.getStatusCode();
getMethod.setDoAuthentication(true);
System.out.println("status: " + status);
if (status == HttpStatus.SC_OK) {
String responseBody = getMethod.getResponseBodyAsString();
String resp = responseBody.replaceAll("\n", " ");
System.out.println("RESPONSE \n" + resp);
}
} catch (Exception e) {
e.printStackTrace();
}
I finally replaced the deprecated DefaultHttpClient with my own implementation of the HttpUrlConnection and I implemented digest atuhentication myself, using this as a template.
The finaly code looks something like this:
// requestMethod: "GET", "POST", "PUT" etc.
// Headers: A map with the HTTP-Headers for the request
// Data: Body-Data for Post/Put
int statusCode = this.requestImpl(requestMethod, headers, data);
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED && hasUserNameAndPassword) {
String auth = getResponseHeaderField("WWW-Authenticate");
// Server needs Digest authetication
if(auth.startsWith("Digest")){
// Parse the auth Header
HashMap<String, String> authFields = parseWWWAuthenticateHeader(auth);
// Generate Auth-Value for request
String requestAuth = generateDigestAuth(authFields);
headers.put("Authorization", authStr);
statusCode = this.requestImpl(requestMethod, headers, data);
}
}
So basicly I make a request and if it returns 401, I look, if the server wants digest authentication and if I have username and password. If thats the case, I parse the auth header of the response, which contains all the necessary informations about the authentication.
To parse the auth header I use some kind of StateMachine which is described here.
After parsing the response auth header, I generate the request auth header using the informations from the response:
String digestAuthStr = null;
String uri = getURL().getPath();
String nonce = authFields.get("nonce");
String realm = authFields.get("realm");
String qop = authFields.get("qop");
String algorithm = authFields.get("algorithm");
String cnonce = generateCNonce();
String nc = "1";
String ha1 = toMD5DigestString(concatWithSeparator(":", username, realm, password));
String ha2 = toMD5DigestString(concatWithSeparator(":", requestMethod, uri));
String response = null;
if (!TextUtils.isEmpty(ha1) && !TextUtils.isEmpty(ha2))
response = toMD5DigestString(concatWithSeparator(":", ha1, nonce, nc, cnonce, qop, ha2));
if (response != null) {
StringBuilder sb = new StringBuilder(128);
sb.append("Digest ");
sb.append("username").append("=\"").append(username).append("\", ");
sb.append("realm").append("=\"").append(realm).append("\", ");
sb.append("nonce").append("=\"").append(nonce).append("\", ");
sb.append("uri").append("=\"").append(uri).append("\", ");
sb.append("qop").append("=\"").append(qop).append("\", ");
sb.append("nc").append("=\"").append(nc).append("\", ");
sb.append("cnonce").append("=\"").append(cnonce).append("\"");
sb.append("response").append("=\"").append(response).append("\"");
sb.append("algorithm").append("=\"").append(algorithm).append("\"");
digestAuthStr = sb.toString();
}
To generate the Client-Nonce I am using the following code:
private static String generateCNonce() {
String s = "";
for (int i = 0; i < 8; i++)
s += Integer.toHexString(new Random().nextInt(16));
return s;
}
I hope this helps someone. If the code contains any errors, please let me know so I can fix it. But right now it seems to work.
For Android, I found the bare-bones-digest library worked well: https://github.com/al-broco/bare-bones-digest
Add one line to build.gradle
Use the example code at the above url
Works!

Build and use Cookie for token based authentication to gain access to api through openAM

Please excuse me if any of this sounds very stupid or inexperienced, however I have looked everywhere else and haven't been able to find a simple explanation as to how to properly implement this.
So far I have made a restful call to a server running on openAm; the call sends my user name and password credentials and returns to me a secure token. I then need to make another restful call to request certain json files in their api.
I understand that in my second restful call I need to somehow embed the token with it so the server knows that I am allowed to access the requested data. My question is what is the proper way to go about this. I have found/heard of multiple possibilities such as passing it in the header, parameters, or as a cookie, but each time my request is redirected to the log in url instead of returning my request.
From my understanding it appears the cookie method works best (if I'm wrong then please post a different method). So for openAm authentication, how do I properly build a cookie with my token. Once the cookie is built how do I embed that into the connection. Do I need to make a whole new connection or can I redirect my original connection with the cookie? Any help or advice is greatly appreciated.
Some of my code, using HttpURLConnection:
//takes url and builds our connection
String url = "http://some.url.net/openam/json/authenticate";
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("X-OpenAM-Username", name);
connection.setRequestProperty("X-OpenAM-Password", pass);
connection.setRequestProperty("Content-Type", "application/json");
//takes in the connections response
BufferedReader in = new BufferedReader(new InputStreamReader(response, "UTF-8"));
String output = in.readLine();
//this is to cut the token out of the response
int i = 14;
while(true){
if (output.charAt(i)=='"'){
break;
}
i++;
}
String token = output.substring(14,i);
//build our new connection and second call
url = "https://other.url.net/api/v1/resource/attributes";
HttpURLConnection request_conn = (HttpURLConnection) new URL(url).openConnection();
/*
request_conn.setRequestProperty("iPlanetDirectoryPro", token);
request_conn.setRequestMethod("POST");
request_conn.connect();
*/ //Tried to put the token through the header, doesnt work
/*
Cookie cookie;
cookie = new Cookie("iPlanetDirectoryPro", token);
cookie.setDomain(".di2e.net");
cookie.setPath("/");
cookie.setSecure(true);
request_conn.addCookie(cookie);//addCookie() doesnt work for a urlConection?
*/ //Tried building the cookie and adding it to the new conection

2 legged OAuth using Scribe - java equivalent of php

I'm trying to use scribe to implement 2 legged OAuth in Java with reference to php code.
I believe I'm very close to cracking this. My current error is:
**OAuth - response.getBody: Problem: signature_invalid | Advice: > |
response.getCode(): 200**
I suspect that this has something to do with the form of the token or lack of consumer object while signing the request.
In php, the code is:
$consumer = new OAuthConsumer($consumer_key, $consumer_secret);
//post transaction to pesapal
$iframe_src = OAuthRequest::from_consumer_and_token($consumer, $token, "GET", $iframelink, $params);
$iframe_src->set_parameter("oauth_callback", $callback_url);
$iframe_src->set_parameter("pesapal_request_data", $post_xml);
**$iframe_src->sign_request($signature_method, $consumer, $token);**
From the last line, to sign the request, the consumer is also passed as a parameter.
My code is as follows:
OAuthService service = new ServiceBuilder()
.provider(something.class)
.signatureType(SignatureType.QueryString)
.apiKey(consumer_key)
.apiSecret(consumer_secret)
.callback(callback_url)
.build();
Token token = new Token("", "");
OAuthRequest request = new OAuthRequest(Verb.GET, iframelink);
request.addBodyParameter("pesapal_request_data", post_xml);
request.addOAuthParameter(OAuthConstants.SIGN_METHOD, signature_method);
service.signRequest(token, request);
Response response = request.send();
Can someone please show me where I may have gone wrong ?
I know that I'm close - very close ....
Try to change $iframelink = http://www.pesapal.com/api/PostPesapalDirectOrderV4 to $iframelink = https://www.pesapal.com/api/PostPesapalDirectOrderV4
Had the same issue when live changing from http to https sorted me out.

Categories

Resources