bad base-64 runtime exception - java

I am working on an android application for on online taxi service , in which it supports in app calling using sinch SDK. To authorize a client, we need to share our APP_KEY and SECRET_KEY and userId with the sinch server and that's cryptographically signed with the Application Secret.
From their tutorial they have made a class to share these data as base 64 . But once I tried this I got a runtime exception as "bad base-64" like:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tukxi.ride, PID: 17870
java.lang.RuntimeException: bad base-64
at com.general.files.JWT.create(JWT.java:50)
at com.general.files.SinchService$MySinchClientListener.onCredentialsRequired(SinchService.java:252)
at com.sinch.android.rtc.internal.client.DefaultSinchClient$2.onCredentialsRequired(Unknown Source:22)
here is my code :
public static String create(String appKey, String appSecret, String userId) {
JSONObject header = new JSONObject();
JSONObject payload = new JSONObject();
final long issuedAt = System.currentTimeMillis() / 1000;
String kid = "hkdfv1-" + formatDate(issuedAt);
try {
header.put("alg", "HS256");
header.put("typ", "JWT");
header.put("kid", kid);
payload.put("iss","//rtc.sinch.com/applications/" + appKey);
payload.put("sub","//rtc.sinch.com/applications/" + appKey + "/users/" + userId);
payload.put("iat",issuedAt);
payload.put("exp",issuedAt + 600);
payload.put("nonce", UUID.randomUUID());
} catch (JSONException e) {
throw new RuntimeException(e.getMessage(), e.getCause());
}
String headerStr = header.toString().trim().replace("\\/","/");
String payloadStr = payload.toString().trim().replace("\\/","/");
String headerBase64 = Base64.encodeToString(headerStr.getBytes(), Base64.NO_PADDING | Base64.NO_WRAP | Base64.DEFAULT);
String payloadBase64 = Base64.encodeToString(payloadStr.getBytes(), Base64.NO_PADDING | Base64.NO_WRAP | Base64.DEFAULT);
String jwtToSign = headerBase64 + "." + payloadBase64;
String jwtSignature;
try {
byte[] origKey = Base64.decode(appSecret, Base64.DEFAULT);
byte[] signingKey = deriveSigningKey(origKey, issuedAt);
final byte[] macData = Hmac.hmacSha256(signingKey, jwtToSign);
String signature = Base64.encodeToString(macData, Base64.NO_PADDING | Base64.NO_WRAP | Base64.DEFAULT);
jwtSignature = jwtToSign + "." + signature;
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e.getCause());
}
return jwtSignature;
}
private static String formatDate(long time) {
String format = "yyyyMMdd";
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(new Date(time * 1000));
}
private static byte[] deriveSigningKey(byte[] key, long issuedAt) {
return Hmac.hmacSha256(key, formatDate(issuedAt));
}

Related

Oauth2 authentication with Private Key C#

I am attempting to authenticate via Oauth2 to an API however, I had trouble creating the request because of a private key. I was provided a sample code by the vendor which is Java and I converted it over to C# but I can't seem to get the private key into the JWT request.
Side note, the client, secret and URL's have been masked for this example.
Working Java code
public class Test {
private static final String RSSO_URL = "https://test-dev.onbmc.com/rsso";
private static final String CLIENT_ID = "36fa1bd2-6f92-408e-b7e4-dd4df7a9cfaz";
private static final String CLIENT_SECRET = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjBgEAAoIBAQC169y6kMo/hZ/3oRFKwU1bxmzCJhWgH54j3Vn1JW4SmgO3rH5bHkVcqt03aaQmQms/fBDe2SlCKS3pxH6pVXB8aKQj8EOPWstwjvjsQrCiKLyqAMbc6E7IBVp1Dq77wFtv+P3fk80/9OA4a6ahr9Dp14+3YawyOU/5Ebf/i2WwKkySTgQOGLXvk3+LtsoODubMAnyJYWb6e+Uhrbn/vSqlGDDjGtANahw5oWjqFy8IYFttzMNB0VF2+sKIzGvQ+Izlo+u4wTgN7pB5g8bSz9Q92QzeWRVh7OCaef3L0i6Ozp3rO46bo3+G+QJdn4UKPcYMubtNGMC511aDU8Yay4IPAgMBAAECggEAMGTwMQk3ZDKN3XgRe4t0osdCNlufQRtoHC5UMeylHXmvJ3tRmbexx/cdqwgxTKQ6l4bPjhjC6wC9YASPlUhPRikoEQ9nSYljuSuveFo9VsXzel3+iOGbo4YZDC69yebf7CeWkZVl8m+X/ipVB4oXzz0y1Bu9jRbF+YIHKonQoU4MgsQQrYa8J8cSx75fkByNj9HdQtd99aK2jsMSArQ1R+PnUjDWpxlZBAowRmaw6iPWJbHmhLUSyrIvBJOo3fNZlXPS/S8jL5s0n137K640WFjy5LBakooHqmjfaFk/5z5krBaWaehDXU2AXLcKRQi946QhC99leSxBTastfjIh0QKBgQDZDZRME+GvJwnnMOht0BuVjcazCkY5LcfxD4vwQeK8p7zyqaxcvNu0+0ulKy+kqP6d/Q1ITIXlQDEA8a2d/iiOhSI84Y/g9az9ZSvRHH/Z5gRdRrymZJcqCzzpxjqi0uvaKOQUWwrKthnxnAS+1oJPlqOc1CtO/j4qzc7I2D7VxQKBgQDWkH5YTYLM5EWos1zdEmVqnIrUYbKlkyHJWSYnC/f5VsOoVEV4R1012w3HfwPceRjYOxeUtHTPN3MB9B5Xn5d3oBFBk8Md9phD5St9KXGakPY0sWC1yFEg8/Zr9fVm5jren6tJQmhKEeiV6DtueqQShEVVIEJixrQQkwFQ4SvJwwKBgCKh+Qyei38gEoNyGVQURaJ6Sb8dn5DWDjYXjfOa/6usdAigLCFr/P6Grk4/cs2qLV5WFz13AFJRCMCmz1YLTLtY4Nqn/wYdDSotb21hR8Ej44Rimg1OtZP+0QxYFdkPIJThu2rIEBPCNKeJhnRQ0+ARIDAQ5ownIxI/XoRLhNMlAoGAQl9mRgiMKrd+eOYrFtPm/Wi5ZWNncOKns/JY5AFGzyGw2rRe3QsuYUeG5qx61Eu9jL4S2FROQf+EGxmZ/T8ICuBAFkoQNIegqHgO0OPuGYM4NiqcoP77Ybc2BkWKiS81DMLVqI7bVfZePWkeYVmcwYGbNO8KuiV/dBUVdiCBfCMCgYEAoUvJefM+ENuhnxrH6A+4lEH4CI64gkQ5tkF3JeAMCiIov5OEuJx+65ULXeAwhrvcLB3Ginh0hI2RNQGV5iOeu0+sHmNA8yt0ivoCweNxiPM0RGWcH5FFBzI88WlGbMl0eg3NHt9jV5yTwNJYonjPFgCUkasaclhDZlZxgN891LA=";
private static final String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhY8LmtZ7fZOAX\n" +
"gw7SKyHzZ6Q0H0ss+3cJ7NEkEofUN2IfycE5u6eQb396uN16bzZaQcwnK9He3xwk\n" +
"3H4wWLzOUlhfuo87bJ34VdNBa1hfAk4iyk1ZgyufGy6MKgwycXhIl9wibX/f1fmF\n" +
"khHnkXVyYY5hSewceCT51bMzcv+psGf7KkN8jh/bRb+/GGfxVy13GKfFTzwY1Y7G\n" +
"SH7J00EaUQsEVCbkV3HK185v6t1fb2faao2imgj/Xqzc/DBbConBoF8/89SJSuf9\n" +
"1RVGdctNwqerMOUoDJ2ynHNqhbO3POq6O1XMi0c75q4xdtrNWLa8A5ONPUXDgIo/\n" +
"Ddwj1tTNAgMBAAECggEACG83yXNtfRWkzyxv3wyPKjEsM2kiYo4Mf9oVX4C0BYyH\n" +
"BwKBURxFIoIRprGJVD4aLhl9PtAEfA8kWfrIXB3N/viU5wwvtP0VEkh/7dhLB88p\n" +
"xmKEr39ZoAwf203tg+u8IRdRvRYU7Xbv7gAv3FcUqpGdBuYByHT0iUbmfFvm1l46\n" +
"HD2ypQFKr3a536w2sFR6XKK6G+Al69lyg0Hg4jXmmDMo+xoxqrJeYxT11G6iBWmy\n" +
"UXKDdOVx4BarT+dcnCUP0yahmQz08XObNDNphWG/aOFF6cMyU4hNkK9q0AC6sAzQ\n" +
"89dTVTPErjEJcJZ16mtI9nv5u4VKfbL1mU+ivb4pQQKBgQD+FdFx+BKojVYilT1i\n" +
"WMbXabRtm03NezgzSgIDKTxiewoQAy+n+InGPy2pz18/1DP8kasnsU8VZvRM7dXV\n" +
"lJTXrqOM/lMN8vMt7/fpz0PYEDP6Qz7CLxA0xEcW2qFR4RAQzq3xXIH/7M4VUZzD\n" +
"qzznD8aJaG5fsSExt7aITU984QKBgQDjFpVsxDxF3YZBhonuNaSrvTdDwbMqdCLT\n" +
"ZoXUL+4aKY78cD2FCfdqJ5O1uyrAqgCgjouiVnNRzDy3qSSGxaiwpI3+FA8cCNiS\n" +
"W0CE/urjDDeXU0Q5jDSBdljBF23wf9mNmXpgXSHfgQVTIiVMVD5tNhU/ORu5PXzo\n" +
"SdW67DLJbQKBgDYYbRQnrclG9hy8y2nh3svEDI70bq4d2tRIoG8N23ZYHcdU9lN7\n" +
"vdGAZ/dsWCodwse2N8tmm6DB36d1R36GeL4Gx3lgOEyS+iVAnvafkyEwKfDRWk47\n" +
"eObTFxONjqUBFsuNRUlK2b6kKygszQR3s6q6GBnvKviinJ+aLnmMhCzhAoGBAKLC\n" +
"gP6f87/kcmFsiFePYyMkTwPlRQDclEloZesbH1DpEG6mE7HS3t3a1+ec6puEPUbW\n" +
"ZAZKaATsmWgZdvCRosJYbtz4i4vQW0kq1id8feWV1BJJv9BvSQKxTBO5Mzb4q3jt\n" +
"0+RVW/3Rf3uCMbFvf/7OkJPr3o76HxhuMx3yRMRRAoGAZiFbVjd3EKUdyE0O3QSh\n" +
"46KzTdT0ENhBlN2dpCdJjHJm3Lcxa7uY4sxa8NqYUW0NO2qRSd42IKfGX3qqi7wf\n" +
"+rUFFixCzQOoucR/ekTw+542Nbc0QejAQ0SUDwgHWX8L8Yi+W3UsBL2YLLIw5ged\n" +
"7Ghsl3cgdKPMlAh1kzxsWic=";
public static JsonPath getOAuthToken() throws InvalidKeySpecException, NoSuchAlgorithmException {
return with().log().all()
.contentType(ContentType.URLENC)
.formParam("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
.formParam("assertion", getClientJwt())
.formParam("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
.formParam("redirect_uri", "https://test-dev-restapi.us.onbmc.com/api/jwt/login")
.formParam("audience", "test-dev-restapi.us.onbmc.com")
.formParam("client_id", CLIENT_ID)
.formParam("client_secret", CLIENT_SECRET)
.when()
.post(RSSO_URL + "/oauth2/token")
.then()
.log().all()
.statusCode(HttpURLConnection.HTTP_OK)
.extract()
.response()
.getBody()
.jsonPath();
}
static String getClientJwt() throws InvalidKeySpecException, NoSuchAlgorithmException {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 1);
return Jwts.builder()
.signWith(loadPrivateKey(PRIVATE_KEY))
.setIssuer(CLIENT_ID)
.setSubject("JWT")
.setAudience("test-dev-restapi.us.onbmc.com")
.setExpiration(calendar.getTime())
.compact();
}
static PrivateKey loadPrivateKey(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(privateKeyStr));
return kf.generatePrivate(keySpecPKCS8);
}
//#Test
public void getOauthAccessTokenUsingJwtGrantType() throws Exception {
System.out.println("Trying to get OAuth Access and Refresh tokens");
JsonPath response = getOAuthToken();
System.out.println("Access Token = " + response.getString("access_token"));
System.out.println("Refresh Token = " + response.getString("refresh_token"));
System.out.println("Expires in = " + response.getString("expires_in"));
System.out.println("OAuth2 Token was successfully obtained.");
}
public static void main(String str[]) throws Exception {
JsonPath response = getOAuthToken();
}
}
Converted Java code to C#
using java.security;
using java.security.spec;
using JWT;
using JWT.Algorithms;
using JWT.Builder;
using JWT.Serializers;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Buffers.Text;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
namespace TestApp
{
class Program
{
private static string RSSO_URL = "https://test-dev.onbmc.com/rsso";
`enter code here`private static string CLIENT_ID = "36fa1bd2-6f92-408e-b7e4-dd4df7a9cfaz";
private static string CLIENT_SECRET = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjBgEAAoIBAQC169y6kMo/hZ/3oRFKwU1bxmzCJhWgH54j3Vn1JW4SmgO3rH5bHkVcqt03aaQmQms/fBDe2SlCKS3pxH6pVXB8aKQj8EOPWstwjvjsQrCiKLyqAMbc6E7IBVp1Dq77wFtv+P3fk80/9OA4a6ahr9Dp14+3YawyOU/5Ebf/i2WwKkySTgQOGLXvk3+LtsoODubMAnyJYWb6e+Uhrbn/vSqlGDDjGtANahw5oWjqFy8IYFttzMNB0VF2+sKIzGvQ+Izlo+u4wTgN7pB5g8bSz9Q92QzeWRVh7OCaef3L0i6Ozp3rO46bo3+G+QJdn4UKPcYMubtNGMC511aDU8Yay4IPAgMBAAECggEAMGTwMQk3ZDKN3XgRe4t0osdCNlufQRtoHC5UMeylHXmvJ3tRmbexx/cdqwgxTKQ6l4bPjhjC6wC9YASPlUhPRikoEQ9nSYljuSuveFo9VsXzel3+iOGbo4YZDC69yebf7CeWkZVl8m+X/ipVB4oXzz0y1Bu9jRbF+YIHKonQoU4MgsQQrYa8J8cSx75fkByNj9HdQtd99aK2jsMSArQ1R+PnUjDWpxlZBAowRmaw6iPWJbHmhLUSyrIvBJOo3fNZlXPS/S8jL5s0n137K640WFjy5LBakooHqmjfaFk/5z5krBaWaehDXU2AXLcKRQi946QhC99leSxBTastfjIh0QKBgQDZDZRME+GvJwnnMOht0BuVjcazCkY5LcfxD4vwQeK8p7zyqaxcvNu0+0ulKy+kqP6d/Q1ITIXlQDEA8a2d/iiOhSI84Y/g9az9ZSvRHH/Z5gRdRrymZJcqCzzpxjqi0uvaKOQUWwrKthnxnAS+1oJPlqOc1CtO/j4qzc7I2D7VxQKBgQDWkH5YTYLM5EWos1zdEmVqnIrUYbKlkyHJWSYnC/f5VsOoVEV4R1012w3HfwPceRjYOxeUtHTPN3MB9B5Xn5d3oBFBk8Md9phD5St9KXGakPY0sWC1yFEg8/Zr9fVm5jren6tJQmhKEeiV6DtueqQShEVVIEJixrQQkwFQ4SvJwwKBgCKh+Qyei38gEoNyGVQURaJ6Sb8dn5DWDjYXjfOa/6usdAigLCFr/P6Grk4/cs2qLV5WFz13AFJRCMCmz1YLTLtY4Nqn/wYdDSotb21hR8Ej44Rimg1OtZP+0QxYFdkPIJThu2rIEBPCNKeJhnRQ0+ARIDAQ5ownIxI/XoRLhNMlAoGAQl9mRgiMKrd+eOYrFtPm/Wi5ZWNncOKns/JY5AFGzyGw2rRe3QsuYUeG5qx61Eu9jL4S2FROQf+EGxmZ/T8ICuBAFkoQNIegqHgO0OPuGYM4NiqcoP77Ybc2BkWKiS81DMLVqI7bVfZePWkeYVmcwYGbNO8KuiV/dBUVdiCBfCMCgYEAoUvJefM+ENuhnxrH6A+4lEH4CI64gkQ5tkF3JeAMCiIov5OEuJx+65ULXeAwhrvcLB3Ginh0hI2RNQGV5iOeu0+sHmNA8yt0ivoCweNxiPM0RGWcH5FFBzI88WlGbMl0eg3NHt9jV5yTwNJYonjPFgCUkasaclhDZlZxgN891LA=";
private static string PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhY8LmtZ7fZOAX\n" +
"gw7SKyHzZ6Q0H0ss+3cJ7NEkEofUN2IfycE5u6eQb396uN16bzZaQcwnK9He3xwk\n" +
"3H4wWLzOUlhfuo87bJ34VdNBa1hfAk4iyk1ZgyufGy6MKgwycXhIl9wibX/f1fmF\n" +
"khHnkXVyYY5hSewceCT51bMzcv+psGf7KkN8jh/bRb+/GGfxVy13GKfFTzwY1Y7G\n" +
"SH7J00EaUQsEVCbkV3HK185v6t1fb2faao2imgj/Xqzc/DBbConBoF8/89SJSuf9\n" +
"1RVGdctNwqerMOUoDJ2ynHNqhbO3POq6O1XMi0c75q4xdtrNWLa8A5ONPUXDgIo/\n" +
"Ddwj1tTNAgMBAAECggEACG83yXNtfRWkzyxv3wyPKjEsM2kiYo4Mf9oVX4C0BYyH\n" +
"BwKBURxFIoIRprGJVD4aLhl9PtAEfA8kWfrIXB3N/viU5wwvtP0VEkh/7dhLB88p\n" +
"xmKEr39ZoAwf203tg+u8IRdRvRYU7Xbv7gAv3FcUqpGdBuYByHT0iUbmfFvm1l46\n" +
"HD2ypQFKr3a536w2sFR6XKK6G+Al69lyg0Hg4jXmmDMo+xoxqrJeYxT11G6iBWmy\n" +
"UXKDdOVx4BarT+dcnCUP0yahmQz08XObNDNphWG/aOFF6cMyU4hNkK9q0AC6sAzQ\n" +
"89dTVTPErjEJcJZ16mtI9nv5u4VKfbL1mU+ivb4pQQKBgQD+FdFx+BKojVYilT1i\n" +
"WMbXabRtm03NezgzSgIDKTxiewoQAy+n+InGPy2pz18/1DP8kasnsU8VZvRM7dXV\n" +
"lJTXrqOM/lMN8vMt7/fpz0PYEDP6Qz7CLxA0xEcW2qFR4RAQzq3xXIH/7M4VUZzD\n" +
"qzznD8aJaG5fsSExt7aITU984QKBgQDjFpVsxDxF3YZBhonuNaSrvTdDwbMqdCLT\n" +
"ZoXUL+4aKY78cD2FCfdqJ5O1uyrAqgCgjouiVnNRzDy3qSSGxaiwpI3+FA8cCNiS\n" +
"W0CE/urjDDeXU0Q5jDSBdljBF23wf9mNmXpgXSHfgQVTIiVMVD5tNhU/ORu5PXzo\n" +
"SdW67DLJbQKBgDYYbRQnrclG9hy8y2nh3svEDI70bq4d2tRIoG8N23ZYHcdU9lN7\n" +
"vdGAZ/dsWCodwse2N8tmm6DB36d1R36GeL4Gx3lgOEyS+iVAnvafkyEwKfDRWk47\n" +
"eObTFxONjqUBFsuNRUlK2b6kKygszQR3s6q6GBnvKviinJ+aLnmMhCzhAoGBAKLC\n" +
"gP6f87/kcmFsiFePYyMkTwPlRQDclEloZesbH1DpEG6mE7HS3t3a1+ec6puEPUbW\n" +
"ZAZKaATsmWgZdvCRosJYbtz4i4vQW0kq1id8feWV1BJJv9BvSQKxTBO5Mzb4q3jt\n" +
"0+RVW/3Rf3uCMbFvf/7OkJPr3o76HxhuMx3yRMRRAoGAZiFbVjd3EKUdyE0O3QSh\n" +
"46KzTdT0ENhBlN2dpCdJjHJm3Lcxa7uY4sxa8NqYUW0NO2qRSd42IKfGX3qqi7wf\n" +
"+rUFFixCzQOoucR/ekTw+542Nbc0QejAQ0SUDwgHWX8L8Yi+W3UsBL2YLLIw5ged\n" +
"7Ghsl3cgdKPMlAh1kzxsWic=";
static void Main(string[] args)
{
try
{
//create RestSharp client and POST request object
var client = new RestClient(RSSO_URL + "/oauth2/token");
var request = new RestRequest();
request.Method = Method.Post;
client.Authenticator = new HttpBasicAuthenticator(CLIENT_ID, CLIENT_SECRET);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
request.AddParameter("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
request.AddParameter("redirect_uri", "https://test-dev-restapi.us.onbmc.com/api/jwt/login");
request.AddParameter("audience", "test-dev-restapi.us.onbmc.com");
request.AddParameter("client_id", CLIENT_ID);
request.AddParameter("client_secret", CLIENT_SECRET);
request.AddParameter("assertion", Program.getClientJwt());
RestResponse response = client.Execute(request);
//return an AccessToken
var poo = JsonConvert.DeserializeObject(response.Content);
}
catch(Exception ex)
{
}
}
public static string getClientJwt() {
DateTime exp = DateTime.UtcNow.AddYears(1);
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(PRIVATE_KEY));
var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature);
var token = new JwtSecurityToken(CLIENT_ID, "miamidade-dev-restapi.us.onbmc.com", null, null, DateTime.UtcNow.AddYears(1), signIn);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public static PrivateKey loadPrivateKey(String privateKeyStr)
{
KeyFactory kf = KeyFactory.getInstance("RSA");
byte[] decodedBytes = Convert.FromBase64String(privateKeyStr);
PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(decodedBytes);
return kf.generatePrivate(keySpecPKCS8);
}
}
}
When I send the request, I get the error
{"error_description":"Not valid request, JWT is rejected","error":"invalid_grant"}

Facing problem with signature parameter using Java in Android App

I am unable to do this in my android app using java language. I am using the retrofit library for this but the problem is the signature. unable to generate proper signature which gives me an error. It is working in POSTMAN and getting proper responses. Help me to convert this in JAVA.
Documentation of API - https://docs.wazirx.com/#fund-details-user_data
POSTMAN PRE-REQUEST SCRIPT
MAIN PARAMS --> BASE_URL, API_KEY, SECRET_KEY, SIGNATURE & TIMESTAMP in miliseconds.
var navigator = {}; //fake a navigator object for the lib
var window = {}; //fake a window object for the lib
const privateKey = pm.environment.get("rsa_private_key");
const secretKey = pm.environment.get("secret_key");
// Set Current Time
var time = new Date().getTime()
postman.setEnvironmentVariable("current_time", time)
query_a = pm.request.url.query.toObject(true)
// Generate Request Payload
let query_string_array = []
Object.keys(query_a).forEach(function(key) {
if (key == 'signature') { return }
if (key == 'timestamp') {
query_string_array.push(key + "=" + time)
}
else if (typeof query_a[key] == "string") {
query_string_array.push(key + "=" + query_a[key])
} else {
query_a[key].forEach(function(value){
query_string_array.push(key + "=" + value)
})
}
})
const payload = query_string_array.join("&")
console.log("Request Payload = ", payload)
if(secretKey) {
const signature = CryptoJS.HmacSHA256(payload, secretKey) + ''
pm.environment.set("signature", signature)
console.log("Signature = "+signature);
} else {
// Download RSA Library
pm.sendRequest(pm.environment.get("rsa_library_js"), function (err, res) {
if (err){
console.log("Error: " + err);
}
else {
// Compile & Run RSA Library
eval(res.text())();
// Sign Payload
var signatureLib = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
signatureLib.init(privateKey);
signatureLib.updateString(payload);
var signatureHash = hex2b64(signatureLib.sign());
console.log("Signature = ", signatureHash)
// Assign Values
pm.environment.set("signature", encodeURIComponent(signatureHash, "UTF-8"))
}
})
}
Java Code:
//REQUEST CLASS START -->
public class Request {
String baseUrl;
String apiKey="1***uR7";
String apiSecret="b1**qVmh";
Signature sign = new Signature();
public Request(String baseUrl, String apiKey, String apiSecret) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
this.apiSecret = apiSecret;
}
private void printResponse(HttpURLConnection con) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
}
private void printError(HttpURLConnection con) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getErrorStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println(response.toString());
}
private String getTimeStamp() {
long timestamp = System.currentTimeMillis();
return "timestamp=" + timestamp;
}
//concatenate query parameters
private String joinQueryParameters(HashMap<String,String> parameters) {
String urlPath = "";
boolean isFirst = true;
for (Map.Entry mapElement : parameters.entrySet()) {
if (isFirst) {
isFirst = false;
urlPath += mapElement.getKey() + "=" + mapElement.getValue();
} else {
urlPath += "&" + mapElement.getKey() + "=" + mapElement.getValue();
}
}
return urlPath;
}
private void send(URL obj, String httpMethod) throws Exception {
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
if (httpMethod != null) {
con.setRequestMethod(httpMethod);
}
//add API_KEY to header content
con.setRequestProperty("X-API-KEY", apiKey);
int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // success
printResponse(con);
} else {
printError(con);
}
}
public void sendPublicRequest(HashMap<String,String> parameters, String urlPath) throws Exception {
String queryPath = joinQueryParameters(parameters);
URL obj = new URL(baseUrl + urlPath + "?" + queryPath);
System.out.println("url:" + obj.toString());
send(obj, null);
}
public void sendSignedRequest(HashMap<String,String> parameters, String urlPath, String httpMethod) throws Exception {
String queryPath = "";
String signature = "";
if (!parameters.isEmpty()) {
queryPath += joinQueryParameters(parameters) + "&" + getTimeStamp();
} else {
queryPath += getTimeStamp();
}
try {
signature = sign.getSignature(queryPath, apiSecret);
}
catch (Exception e) {
System.out.println("Please Ensure Your Secret Key Is Set Up Correctly! " + e);
System.exit(0);
}
queryPath += "&signature=" + signature;
URL obj = new URL(baseUrl + urlPath + "?" + queryPath);
System.out.println("url:" + obj.toString());
send(obj, httpMethod);
}
}
//REQUEST CLASS END -->
//SPOT CLASS START -->
public class Spot {
private static final String API_KEY = System.getenv("1***57");
private static final String API_SECRET = System.getenv("b****n8");
HashMap<String,String> parameters = new HashMap<String,String>();
Request httpRequest;
public Spot() {
String baseUrl = "https://api.wazirx.com";
httpRequest = new Request(baseUrl, API_KEY, API_SECRET);
}
public void account() throws Exception {
httpRequest.sendSignedRequest(parameters, "/sapi/v1/funds", "GET");
}
}
//SPOT CLASS END-->
//SIGNATURE CLASS START-->
public class Signature {
final String HMAC_SHA256 = "HmacSHA256";
//convert byte array to hex string
private String bytesToHex(byte[] bytes) {
final char[] hexArray = "0123456789abcdef".toCharArray();
char[] hexChars = new char[bytes.length * 2];
for (int j = 0, v; j < bytes.length; j++) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public String getSignature(String data, String key) {
byte[] hmacSha256 = null;
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA256);
Mac mac = Mac.getInstance(HMAC_SHA256);
mac.init(secretKeySpec);
hmacSha256 = mac.doFinal(data.getBytes());
} catch (Exception e) {
throw new RuntimeException("Failed to calculate hmac-sha256", e);
}
return bytesToHex(hmacSha256);
}
}
//SIGNATURE CLASS END-->

How to decode a .csr file in java to extract its content

I have three kinds of files to decode namely .csr and .der and .key files.I am able to decode .der file using the java as below.
public class Base64Decoder {
public static void main(String[] args) throws FileNotFoundException, IOException {
Certificate cert=null;
try{
FileInputStream fis = new FileInputStream("C:/Users/patillat/Downloads/device-ee/csr/00db1234567890A5-ka.der");
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
cert = cf.generateCertificate(bis);
try {
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(DatatypeConverter.printBase64Binary(cert.getEncoded()));
System.out.println("-----END CERTIFICATE-----");
//System.out.println("key:"+cert.getPublicKey());
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
System.out.println(cert.toString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
I am able to generate details of .der certificate
In the same way I am not able to decode my .csr file.
Are there any other ways to decode .csr files?
Using BouncyCastle you can easily decode a csr, from binary format.
JcaPKCS10CertificationRequest p10Object = new JcaPKCS10CertificationRequest(byte[] csrBytes);
There are also htlper classes for decoding/decoding to/from PEM format (base64 encoded).
Here's the code that I have used to decode .csr file.
public class CSRInfoDecoder {
private static Logger LOG = Logger.getLogger(CSRInfoDecoder.class.getName());
private static final String COUNTRY = "2.5.4.6";
private static final String STATE = "2.5.4.8";
private static final String LOCALE = "2.5.4.7";
private static final String ORGANIZATION = "2.5.4.10";
private static final String ORGANIZATION_UNIT = "2.5.4.11";
private static final String COMMON_NAME = "2.5.4.3";
private static final String EMAIL = "2.5.4.9";
private static final String csrPEM = "-----BEGIN CERTIFICATE REQUEST-----\n"
+ "MIICxDCCAawCAQAwfzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw\n"
+ "DgYDVQQHDAdDaGljYWdvMQ4wDAYDVQQKDAVDb2RhbDELMAkGA1UECwwCTkExDjAM\n"
+ "BgNVBAMMBUNvZGFsMR4wHAYJKoZIhvcNAQkBFg9rYmF4aUBjb2RhbC5jb20wggEi\n"
+ "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSrEF27VvbGi5x7LnPk4hRigAW\n"
+ "1feGeKOmRpHd4j/kUcJZLh59NHJHg5FMF7u9YdZgnMdULawFVezJMLSJYJcCAdRR\n"
+ "hSN+skrQlB6f5wgdkbl6ZfNaMZn5NO1Ve76JppP4gl0rXHs2UkRJeb8lguOpJv9c\n"
+ "tw+Sn6B13j8jF/m/OhIYI8fWhpBYvDXukgADTloCjOIsAvRonkIpWS4d014deKEe\n"
+ "5rhYX67m3H7GtZ/KVtBKhg44ntvuT2fR/wB1FlDws+0gp4edlkDlDml1HXsf4FeC\n"
+ "ogijo6+C9ewC2anpqp9o0CSXM6BT2I0h41PcQPZ4EtAc4ctKSlzTwaH0H9MbAgMB\n"
+ "AAGgADANBgkqhkiG9w0BAQsFAAOCAQEAqfQbrxc6AtjymI3TjN2upSFJS57FqPSe\n"
+ "h1YqvtC8pThm7MeufQmK9Zd+Lk2qnW1RyBxpvWe647bv5HiQaOkGZH+oYNxs1XvM\n"
+ "y5huq+uFPT5StbxsAC9YPtvD28bTH7iXR1b/02AK2rEYT8a9/tCBCcTfaxMh5+fr\n"
+ "maJtj+YPHisjxKW55cqGbotI19cuwRogJBf+ZVE/4hJ5w/xzvfdKjNxTcNr1EyBE\n"
+ "8ueJil2Utd1EnVrWbmHQqnlAznLzC5CKCr1WfmnrDw0GjGg1U6YpjKBTc4MDBQ0T\n"
+ "56ZL2yaton18kgeoWQVgcbK4MXp1kySvdWq0Bc3pmeWSM9lr/ZNwNQ==\n"
+ "-----END CERTIFICATE REQUEST-----\n";
public static void main(String[] args) {
InputStream stream = new ByteArrayInputStream(csrPEM.getBytes(StandardCharsets.UTF_8));
CSRInfoDecoder m = new CSRInfoDecoder();
m.readCertificateSigningRequest(stream);
}
public String readCertificateSigningRequest(InputStream csrStream) {
PKCS10CertificationRequest csr = convertPemToPKCS10CertificationRequest(csrStream);
String compname = null;
if (csr == null) {
LOG.warn("FAIL! conversion of Pem To PKCS10 Certification Request");
} else {
X500Name x500Name = csr.getSubject();
System.out.println("x500Name is: " + x500Name + "\n");
RDN cn = x500Name.getRDNs(BCStyle.EmailAddress)[0];
System.out.println(cn.getFirst().getValue().toString());
System.out.println(x500Name.getRDNs(BCStyle.EmailAddress)[0]);
System.out.println("COUNTRY: " + getX500Field(COUNTRY, x500Name));
System.out.println("STATE: " + getX500Field(STATE, x500Name));
System.out.println("LOCALE: " + getX500Field(LOCALE, x500Name));
System.out.println("ORGANIZATION: " + getX500Field(ORGANIZATION, x500Name));
System.out.println("ORGANIZATION_UNIT: " + getX500Field(ORGANIZATION_UNIT, x500Name));
System.out.println("COMMON_NAME: " + getX500Field(COMMON_NAME, x500Name));
System.out.println("EMAIL: " + getX500Field(EMAIL, x500Name));
}
return compname;
}
private String getX500Field(String asn1ObjectIdentifier, X500Name x500Name) {
RDN[] rdnArray = x500Name.getRDNs(new ASN1ObjectIdentifier(asn1ObjectIdentifier));
String retVal = null;
for (RDN item : rdnArray) {
retVal = item.getFirst().getValue().toString();
}
return retVal;
}
private PKCS10CertificationRequest convertPemToPKCS10CertificationRequest(InputStream pem) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
PKCS10CertificationRequest csr = null;
ByteArrayInputStream pemStream = null;
pemStream = (ByteArrayInputStream) pem;
Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
PEMParser pemParser = null;
try {
pemParser = new PEMParser(pemReader);
Object parsedObj = pemParser.readObject();
System.out.println("PemParser returned: " + parsedObj);
if (parsedObj instanceof PKCS10CertificationRequest) {
csr = (PKCS10CertificationRequest) parsedObj;
}
} catch (IOException ex) {
LOG.error("IOException, convertPemToPublicKey", ex);
} finally {
if (pemParser != null) {
IOUtils.closeQuietly(pemParser);
}
}
return csr;
}
}
In the above code, I have converted the csrPem String into a InputStream for my own testing purposes so you can eliminate that step and directly useByteArrayInputStream`.
One can utilize Bouncycastle in order to achieve this. See code snippet below for parsing a String to a PKCS10CertificationRequest. Of course you can replace the ByteArrayInputStream to a arbitrary input stream of your choice.
try (final ByteArrayInputStream bais = new ByteArrayInputStream(csrAsString.getBytes());
final InputStreamReader isr = new InputStreamReader(bais, StandardCharsets.UTF_8);
final PEMParser pem = new PEMParser(isr))
{
PKCS10CertificationRequest csr = (PKCS10CertificationRequest) pem.readObject();
// Do your verification here
}

how to connect to google storage API with java

I am unable to connect the google storage api through java class. any one provide sample code for this
#SuppressWarnings("serial")
public class GoogleServlet {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final String PROJECT_ID = "";
public static String Base64Encoding()
throws java.security.SignatureException, UnsupportedEncodingException {
String access_id = "GOOG37E2YNNQW6FIGGDS ";
String secret_key = URLEncoder.encode("","UTF-8");
String bucket = "";
String version_header = "x-goog-api-version:1";
String project_header = "x-goog-project-id:"+PROJECT_ID;
String canonicalizedResources = "/"+bucket+"/";
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 30);
long expiration = calendar.getTimeInMillis();
String stringToSign = URLEncoder.encode("GET\n\n\n"+expiration+"\n"+version_header+"\n"+project_header+"\n"+canonicalizedResources,"UTF-8");
//String stringToSign = URLEncoder.encode("GET\n\n\n"+getdate()+"\n"+version_header+"\n"+project_header+"\n"+canonicalizedResources,"UTF-8");
String authSignature="";
try {
SecretKeySpec signingKey = new SecretKeySpec(secret_key.getBytes(),HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(stringToSign.getBytes("UTF-8"));
// base64-encode the hmac
authSignature = new String(Base64.encodeBase64(rawHmac));
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
authSignature = (access_id +":"+ authSignature);
return authSignature;
}
public static void main(String[] args) {
ClientConfig config = new DefaultClientConfig();-->ClientConfig cannot be resolved to a type
Client client = Client.create(config);
String authSignature = null;
try {
authSignature = "GOOG1 "+ Base64Encoding();
} catch (SignatureException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
WebResource service = client.resource(getBaseURI());
ClientResponse response = service.accept(MediaType.APPLICATION_XML)-->ClientResponse cannot be resolved to a type
.header("Authorization",authSignature)
.header("Date", getdate())
.header("Content-Length", "0")
.header("x-goog-api-version", "1")
.header("x-goog-project-id", PROJECT_ID)
.get(ClientResponse.class);
System.out.println(response.getClientResponseStatus().getFamily());
System.out.println("response1 :: " + response.getEntity(String.class));
}
private static URI getBaseURI() {
String url = "https://storage.cloud.google.com/mss/";
return UriBuilder.fromUri(url).build();--->The method resource(URI) is undefined for the type Client
}
private static String getdate(){
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z ", new Locale("US"));
Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
format.setCalendar(cal);
return format.format(new Date(0));
}
}
Error:
StringToSign : GET%0A%0A%0A1375378824994%0Ax-goog-api-version%3A1%0Ax-goog-project-id%3A883684764795%0A%2Fmss%2F
Auth Signature : GOOG1 GOOG37E2YNNQW6FIGGDS:3WcA0BQodfq0NrFenFilgJi1tq8=
CLIENT_ERROR
response1 :: <?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GET
Your secret key is empty:
String secret_key = URLEncoder.encode("","UTF-8");
So signing key is also wrong
SecretKeySpec signingKey = new SecretKeySpec(secret_key.getBytes(),HMAC_SHA1_ALGORITHM);

XMPP with Java Asmack library supporting X-FACEBOOK-PLATFORM

I'm trying to make a Facebook Chat on Android with the Smack library. I've read the Chat API from Facebook, but I cannot understand how I have to authenticate with Facebook using this library.
Can anyone point me how to accomplish this?
Update: According to the no.good.at.coding answer, I have this code adapted to the Asmack library. All works fine except I receive as response to the login: not-authorized. Here is the code I use:
public class SASLXFacebookPlatformMechanism extends SASLMechanism
{
private static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String applicationSecret = "";
private String sessionKey = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication)
{
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException
{
getSASLAuthentication().send(new AuthMechanism(NAME, ""));
}
#Override
public void authenticate(String apiKeyAndSessionKey, String host,
String applicationSecret) throws IOException, XMPPException
{
if (apiKeyAndSessionKey == null || applicationSecret == null)
{
throw new IllegalArgumentException("Invalid parameters");
}
String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
if (keyArray.length < 2)
{
throw new IllegalArgumentException(
"API key or session key is not present");
}
this.apiKey = keyArray[0];
Log.d("API_KEY", apiKey);
this.applicationSecret = applicationSecret;
Log.d("SECRET_KEY", applicationSecret);
this.sessionKey = keyArray[1];
Log.d("SESSION_KEY", sessionKey);
this.authenticationId = sessionKey;
this.password = applicationSecret;
this.hostname = host;
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
this);
authenticate();
}
#Override
protected String getName()
{
return NAME;
}
#Override
public void challengeReceived(String challenge) throws IOException
{
byte[] response = null;
if (challenge != null)
{
String decodedChallenge = new String(Base64.decode(challenge));
Log.d("DECODED", decodedChallenge);
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis() / 1000L;
String sig =
"api_key=" + apiKey + "call_id=" + callId + "method="
+ method + "nonce=" + nonce + "session_key="
+ sessionKey + "v=" + version + applicationSecret;
try
{
sig = md5(sig);
sig = sig.toUpperCase();
} catch (NoSuchAlgorithmException e)
{
throw new IllegalStateException(e);
}
String composedResponse =
"api_key=" + URLEncoder.encode(apiKey, "utf-8")
+ "&call_id=" + callId + "&method="
+ URLEncoder.encode(method, "utf-8") + "&nonce="
+ URLEncoder.encode(nonce, "utf-8")
+ "&session_key="
+ URLEncoder.encode(sessionKey, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8") + "&sig="
+ URLEncoder.encode(sig, "utf-8");
Log.d("COMPOSED", composedResponse);
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null)
{
authenticationText =
Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
private Map<String, String> getQueryMap(String query)
{
Map<String, String> map = new HashMap<String, String>();
String[] params = query.split("\\&");
for (String param : params)
{
String[] fields = param.split("=", 2);
map.put(fields[0], (fields.length > 1 ? fields[1] : null));
}
return map;
}
private String md5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(text.getBytes("utf-8"), 0, text.length());
return convertToHex(md.digest());
}
private String convertToHex(byte[] data)
{
StringBuilder buf = new StringBuilder();
int len = data.length;
for (int i = 0; i < len; i++)
{
int halfByte = (data[i] >>> 4) & 0xF;
int twoHalfs = 0;
do
{
if (0 <= halfByte && halfByte <= 9)
{
buf.append((char) ('0' + halfByte));
}
else
{
buf.append((char) ('a' + halfByte - 10));
}
halfByte = data[i] & 0xF;
} while (twoHalfs++ < 1);
}
return buf.toString();
}
}
And this, is the communication with the server with the sent and received messages:
PM SENT (1132418216): <stream:stream to="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">
PM RCV (1132418216): <?xml version="1.0"?><stream:stream id="C62D0F43" from="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xml:lang="en"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>X-FACEBOOK-PLATFORM</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features>
PM SENT (1132418216): <auth mechanism="X-FACEBOOK-PLATFORM" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth>
PM RCV (1132418216): <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">dmVyc2lvbj0xJm1ldGhvZD1hdXRoLnhtcHBfbG9naW4mbm9uY2U9NzFGNkQ3Rjc5QkIyREJCQ0YxQTkwMzA0QTg3OTlBMzM=</challenge>
PM SENT (1132418216): <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">YXBpX2tleT0zMWYzYjg1ZjBjODYwNjQ3NThiZTZhOTQyNjVjZmNjMCZjYWxsX2lkPTEzMDA0NTYxMzUmbWV0aG9kPWF1dGgueG1wcF9sb2dpbiZub25jZT03MUY2RDdGNzlCQjJEQkJDRjFBOTAzMDRBODc5OUEzMyZzZXNzaW9uX2tleT0yNjUzMTg4ODNkYWJhOGRlOTRiYTk4ZDYtMTAwMDAwNTAyNjc2Nzc4JnY9MS4wJnNpZz04RkRDRjRGRTgzMENGOEQ3QjgwNjdERUQyOEE2RERFQw==</response>
PM RCV (1132418216): <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
As read in the developers Facebook forum, it is needed to disable the "Disable Deprecated Auth Methods" setting from the Facebook settings page of your app. But, even doing that, I can't login. And the session key is the second part of the OAuth token in the form AAA|BBB|CCC, I mean, BBB.
Finally, thanks to the no.good.at.coding code and the suggestion of harism, I've been able to connect to the Facebook chat. This code is the Mechanism for the Asmack library (the Smack port for Android). For the Smack library is necessary to use the no.good.at.coding mechanism.
SASLXFacebookPlatformMechanism.java:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
import org.apache.harmony.javax.security.sasl.Sasl;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;
public class SASLXFacebookPlatformMechanism extends SASLMechanism
{
private static final String NAME = "X-FACEBOOK-PLATFORM";
private String apiKey = "";
private String applicationSecret = "";
private String sessionKey = "";
/**
* Constructor.
*/
public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication)
{
super(saslAuthentication);
}
#Override
protected void authenticate() throws IOException, XMPPException
{
getSASLAuthentication().send(new AuthMechanism(NAME, ""));
}
#Override
public void authenticate(String apiKeyAndSessionKey, String host,
String applicationSecret) throws IOException, XMPPException
{
if (apiKeyAndSessionKey == null || applicationSecret == null)
{
throw new IllegalArgumentException("Invalid parameters");
}
String[] keyArray = apiKeyAndSessionKey.split("\\|", 2);
if (keyArray.length < 2)
{
throw new IllegalArgumentException(
"API key or session key is not present");
}
this.apiKey = keyArray[0];
this.applicationSecret = applicationSecret;
this.sessionKey = keyArray[1];
this.authenticationId = sessionKey;
this.password = applicationSecret;
this.hostname = host;
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
this);
authenticate();
}
#Override
public void authenticate(String username, String host, CallbackHandler cbh)
throws IOException, XMPPException
{
String[] mechanisms = { "DIGEST-MD5" };
Map<String, String> props = new HashMap<String, String>();
this.sc =
Sasl.createSaslClient(mechanisms, null, "xmpp", host, props,
cbh);
authenticate();
}
#Override
protected String getName()
{
return NAME;
}
#Override
public void challengeReceived(String challenge) throws IOException
{
byte[] response = null;
if (challenge != null)
{
String decodedChallenge = new String(Base64.decode(challenge));
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis();
String sig =
"api_key=" + apiKey + "call_id=" + callId + "method="
+ method + "nonce=" + nonce + "session_key="
+ sessionKey + "v=" + version + applicationSecret;
try
{
sig = md5(sig);
} catch (NoSuchAlgorithmException e)
{
throw new IllegalStateException(e);
}
String composedResponse =
"api_key=" + URLEncoder.encode(apiKey, "utf-8")
+ "&call_id=" + callId + "&method="
+ URLEncoder.encode(method, "utf-8") + "&nonce="
+ URLEncoder.encode(nonce, "utf-8")
+ "&session_key="
+ URLEncoder.encode(sessionKey, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8") + "&sig="
+ URLEncoder.encode(sig, "utf-8");
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null)
{
authenticationText =
Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
private Map<String, String> getQueryMap(String query)
{
Map<String, String> map = new HashMap<String, String>();
String[] params = query.split("\\&");
for (String param : params)
{
String[] fields = param.split("=", 2);
map.put(fields[0], (fields.length > 1 ? fields[1] : null));
}
return map;
}
private String md5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(text.getBytes("utf-8"), 0, text.length());
return convertToHex(md.digest());
}
private String convertToHex(byte[] data)
{
StringBuilder buf = new StringBuilder();
int len = data.length;
for (int i = 0; i < len; i++)
{
int halfByte = (data[i] >>> 4) & 0xF;
int twoHalfs = 0;
do
{
if (0 <= halfByte && halfByte <= 9)
{
buf.append((char) ('0' + halfByte));
}
else
{
buf.append((char) ('a' + halfByte - 10));
}
halfByte = data[i] & 0xF;
} while (twoHalfs++ < 1);
}
return buf.toString();
}
}
To use it:
ConnectionConfiguration config = new ConnectionConfiguration("chat.facebook.com", 5222);
config.setSASLAuthenticationEnabled(true);
XMPPConnection xmpp = new XMPPConnection(config);
try
{
SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM", SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
xmpp.connect();
xmpp.login(apiKey + "|" + sessionKey, sessionSecret, "Application");
} catch (XMPPException e)
{
xmpp.disconnect();
e.printStackTrace();
}
apiKey is the API key given in the application settings page in Facebook. sessionKey is the second part of the access token. If the token is in this form, AAA|BBB|CCC, the BBB is the session key. sessionSecret is obtained using the old REST API with the method auth.promoteSession. To use it, it's needed to make a Http get to this url:
https://api.facebook.com/method/auth.promoteSession?access_token=yourAccessToken
Despite of the Facebook Chat documentation says that it's needed to use your application secret key, only when I used the key that returned that REST method I was able to make it works. To make that method works, you have to disable the Disable Deprecated Auth Methods option in the Advance tab in your application settings.
I'd used this about 6 months ago with Smack (not asmack) so I'm not sure how it'll hold up now but here goes, hope it helps!
I found an implementation of Facebook's X-FACEBOOK-PLATFORM authentication mechanism on the Ignite Realtime Smack forum where someone got it from the fbgc project. You'll find the a ZIP with the SASLXFacebookPlatformMechanism.java source in the answer I linked to. You can use it as follows:
public void login() throws XMPPException
{
SASLAuthentication.registerSASLMechanism(SASLXFacebookPlatformMechanism.NAME,
SASLXFacebookPlatformMechanism.class);
SASLAuthentication.supportSASLMechanism(SASLXFacebookPlatformMechanism.NAME, 0);
ConnectionConfiguration connConfig = new ConnectionConfiguration(host, port);
XMPPConnection connection = new XMPPConnection(connConfig);
connection.connect();
log.info("XMPP client connected");
connection.login(Utils.FB_APP_ID + "|" + this.user.sessionId, Utils.FB_APP_SECRET, "app_name");
log.info("XMPP client logged in");
}
I was doing this on the server without an SDK. I don't remember the details (and the Facebook documentation isn't very good) but from what I can tell from my code, after getting the user to authorize the app, I get a callback request from Facebook with a code parameter. I open a URLConnection to https://graph.facebook.com/oauth/access_token?client_id=<app_id>&redirect_uri=http://myserver/context/path/&client_secret=<app_secret>&code=<code>. The response should be the access token where the session id is the part after the | - something of the form XXX|<sessionId>.
Here's code I've been using successfully for authentication. Maybe this helps even though this is not related to Smack in any way. You can get sessionKey from access token received from FB, and for getting sessionSecret I've been using oldish REST API;
http://developers.facebook.com/docs/reference/rest/auth.promoteSession/
private final void processChallenge(XmlPullParser parser, Writer writer,
String sessionKey, String sessionSecret) throws IOException,
NoSuchAlgorithmException, XmlPullParserException {
parser.require(XmlPullParser.START_TAG, null, "challenge");
String challenge = new String(Base64.decode(parser.nextText(),
Base64.DEFAULT));
String params[] = challenge.split("&");
HashMap<String, String> paramMap = new HashMap<String, String>();
for (int i = 0; i < params.length; ++i) {
String p[] = params[i].split("=");
p[0] = URLDecoder.decode(p[0]);
p[1] = URLDecoder.decode(p[1]);
paramMap.put(p[0], p[1]);
}
String api_key = "YOUR_API_KEY";
String call_id = "" + System.currentTimeMillis();
String method = paramMap.get("method");
String nonce = paramMap.get("nonce");
String v = "1.0";
StringBuffer sigBuffer = new StringBuffer();
sigBuffer.append("api_key=" + api_key);
sigBuffer.append("call_id=" + call_id);
sigBuffer.append("method=" + method);
sigBuffer.append("nonce=" + nonce);
sigBuffer.append("session_key=" + sessionKey);
sigBuffer.append("v=" + v);
sigBuffer.append(sessionSecret);
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(sigBuffer.toString().getBytes());
byte[] digest = md.digest();
StringBuffer sig = new StringBuffer();
for (int i = 0; i < digest.length; ++i) {
sig.append(Integer.toHexString(0xFF & digest[i]));
}
StringBuffer response = new StringBuffer();
response.append("api_key=" + URLEncoder.encode(api_key));
response.append("&call_id=" + URLEncoder.encode(call_id));
response.append("&method=" + URLEncoder.encode(method));
response.append("&nonce=" + URLEncoder.encode(nonce));
response.append("&session_key=" + URLEncoder.encode(sessionKey));
response.append("&v=" + URLEncoder.encode(v));
response.append("&sig=" + URLEncoder.encode(sig.toString()));
StringBuilder out = new StringBuilder();
out.append("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>");
out.append(Base64.encodeToString(response.toString().getBytes(),
Base64.NO_WRAP));
out.append("</response>");
writer.write(out.toString());
writer.flush();
}
I'm sorry to make new answer but I had to include the new code #YShinkarev sorry for being late
By modifying #Adrian answer to make challengeReceived we can use APIKey and accessToken all I modified was the composedResponse
#Override
public void challengeReceived(String challenge) throws IOException {
byte[] response = null;
if (challenge != null) {
String decodedChallenge = new String(Base64.decode(challenge));
Map<String, String> parameters = getQueryMap(decodedChallenge);
String version = "1.0";
String nonce = parameters.get("nonce");
String method = parameters.get("method");
long callId = new GregorianCalendar().getTimeInMillis();
String composedResponse = "api_key="
+ URLEncoder.encode(apiKey, "utf-8") + "&call_id=" + callId
+ "&method=" + URLEncoder.encode(method, "utf-8")
+ "&nonce=" + URLEncoder.encode(nonce, "utf-8")
+ "&access_token="
+ URLEncoder.encode(access_token, "utf-8") + "&v="
+ URLEncoder.encode(version, "utf-8");
response = composedResponse.getBytes("utf-8");
}
String authenticationText = "";
if (response != null) {
authenticationText = Base64.encodeBytes(response,
Base64.DONT_BREAK_LINES);
}
// Send the authentication to the server
getSASLAuthentication().send(new Response(authenticationText));
}
What do you want to do?
If you just want to login on FB chat, you connect to FB just like any other XMPP server.
I would look at and use "Authenticating with Username/Password" from Chat API, wich is supported by Smack. Unless I would like to write an FaceBook-application. Then I would try to login in with "Authenticating with Facebook Platform".
So, just use Smack to connect to FB chat as you would do with your ordinary Jabber client.
For the username, use your Facebook username. (see http://www.facebook.com/username/ )
For the domain, use: chat.facebook.com
For the password, use your Facebook password
Turn off SSL and TSL
Set connect port to: 5222 (which is the default for XMPP)
Set connect server to chat.facebook.com

Categories