Docusign Java API unable to get account Id - java

My code looks like:
ApiClient client = new ApiClient(DEMO_REST_BASEPATH);
String clientId = "65f9b5d9-XXXX-4de6-ab3c-XXXX";
java.util.List<String> scopes = new ArrayList<String>();
scopes.add(OAuth.Scope_SIGNATURE);
byte[] key = Files.readAllBytes(Paths.get("/tmp/privateKey"));
OAuth.OAuthToken token = client.requestJWTApplicationToken(clientId, scopes, key, 3600);
System.err.println(token.getAccessToken());
OAuth.UserInfo userInfo = client.getUserInfo(token.getAccessToken());
System.out.println("UserInfo: " + userInfo);
I see I get an auth token back, however I get an error message when trying to get UserInfo:
Exception in thread "main" com.docusign.esign.client.ApiException: Error while requesting server, received a non successful HTTP code 401 with response Body: '{"error":"internal_server_error","reference_id":"22e7cf18-74b4-48aa-b916-81bde96071ae"}'
at com.docusign.esign.client.ApiClient.getUserInfo(ApiClient.java:760)
Any ideas?

You are missing this line: (example on GitHub)
client.setAccessToken(oAuthToken.getAccessToken(), oAuthToken.getExpiresIn());
Your code should be something like this:
ApiClient client = new ApiClient(DEMO_REST_BASEPATH);
String clientId = "65f9b5d9-XXXX-4de6-ab3c-XXXX";
java.util.List<String> scopes = new ArrayList<String>();
scopes.add(OAuth.Scope_SIGNATURE);
byte[] key = Files.readAllBytes(Paths.get("/tmp/privateKey"));
OAuth.OAuthToken token = client.requestJWTApplicationToken(clientId, scopes, key, 3600);
System.err.println(token.getAccessToken());
client.setAccessToken(oAuthToken.getAccessToken(), oAuthToken.getExpiresIn());
OAuth.UserInfo userInfo = client.getUserInfo(token.getAccessToken());
System.out.println("UserInfo: " + userInfo);

Related

How to decode access token and get username and email in java?

How can I get the name and email from a token .
Structure of the token using jwt.io
http://prntscr.com/yzyf2b
Any help is appreciated.
Update full solution with the help of below posts so credits to them .
String jwtToken = token;
System.out.println("------------ Decode JWT ------------");
String[] split_string = jwtToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
System.out.println("~~~~~~~~~ JWT Header ~~~~~~~");
Base64 base64Url = new Base64(true);
String header = new String(base64Url.decode(base64EncodedHeader));
System.out.println("JWT Header : " + header);
System.out.println("~~~~~~~~~ JWT Body ~~~~~~~");
String body = new String(base64Url.decode(base64EncodedBody));
System.out.println("JWT Body : " + body);
JSONObject jsonObject = new JSONObject(body);
System.out.println(jsonObject.get("email"));
System.out.println(jsonObject.get("name"));
A JWToken has the following structure Header.Body.Signature. Hence, first you should split the token into three parts, namely Header, Body and Signature.
For that you can use
String[] token_part = jwtToken.split("\\.");
then apply what you already have done but for the token_part[1] (i.e., the payload or Body), namely:
sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
String a = new String(decoder.decodeBuffer(token_part[1]));
For the decoding part, alternatively, you can try this SO thread.
After that you can use the org.json.JSONObject to parse the JSON. An example:
public class Token {
public static void main(String[] args) {
String token = "{\"name\":\"john doe\", \"email\": \"john#mail.com\"}";
JSONObject jsonObject = new JSONObject(token);
System.out.println(jsonObject.get("email"));
System.out.println(jsonObject.get("name"));
}
}
Output:
john#mail.com
john doe
Full Example:
String jwtToken = token;
System.out.println("------------ Decode JWT ------------");
String[] split_string = jwtToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
System.out.println("~~~~~~~~~ JWT Header ~~~~~~~");
Base64 base64Url = new Base64(true);
String header = new String(base64Url.decode(base64EncodedHeader));
System.out.println("JWT Header : " + header);
System.out.println("~~~~~~~~~ JWT Body ~~~~~~~");
String body = new String(base64Url.decode(base64EncodedBody));
System.out.println("JWT Body : " + body);
JSONObject jsonObject = new JSONObject(body);
System.out.println(jsonObject.get("email"));
System.out.println(jsonObject.get("name"));

invalid_client for sign in with apple

What I try to achieve:
iOS client sends a JWT token to the backend.
Backend (Java) calls https://appleid.apple.com/auth/token to verify the token.
what I have so far:
to make Apple verification call:
restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("client_id", clientId); // app_id like com.app.id
String token = generateJWT(); // generated jwt
map.add("client_secret", token);
map.add("grant_type", "authorization_code");
map.add("code", authorizationCode); // JWT code we got from iOS
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
final String appleAuthURL = "https://appleid.apple.com/auth/token";
String response = restTemplate.postForObject(appleAuthURL, request, String.class);
token generation:
final PrivateKey privateKey = getPrivateKey();
final int expiration = 1000 * 60 * 5;
String token = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, keyId) // key id I got from Apple
.setIssuer(teamId)
.setAudience("https://appleid.apple.com")
.setSubject(clientId) // app id com.app.id
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.setIssuedAt(new Date(System.currentTimeMillis()))
.signWith(SignatureAlgorithm.ES256, privateKey) // ECDSA using P-256 and SHA-256
.compact();
return token;
to get my private key from the file:
final Reader pemReader = new StringReader(getKeyData());
final PEMParser pemParser = new PEMParser(pemReader);
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
final PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject();
final PrivateKey pKey = converter.getPrivateKey(object);
I confirmed my JWT has all required fields:
{
"kid": "SAME KEY AS MY KEY ID",
"alg": "ES256"
}
{
"iss": "Blahblah",
"aud": "https://appleid.apple.com",
"sub": "com.app.id",
"exp": 1578513833,
"iat": 1578513533
}
This line caught my attention:
map.add("code", authorizationCode); // JWT code we got from iOS
The authorizationCode is not a jwt
JSON Web Tokens consist of 3 parts separated by dots
but the authorizationCode has 4 parts like this:
text1.text2.0.text3
You are probably using the identityToken from the iOS app instead of the authorizationCode
This is how you retrieve it:
let authorizationCode = String(data: appleIDCredential.authorizationCode!, encoding: .utf8)!
print("authorizationCode: \(authorizationCode)")
Also good to have the following in mind for those who might come here after getting the same invalid_client error:
kid is the id for the private key from developer.apple.com/account/resources/authkeys/list
keyFile is the file holding the private key downloaded from developer.apple.com
teamID can be found by logging in to developer.apple.com and clicking on account, the teamID can be seen in the upper right corner
the value in aud should be https://appleid.apple.com
app_id is the bundle identifier for the app
In case it might help, here is a working solution in python to create a client_secret:
# $ pip install pyjwt
import jwt
import time
kid = "myKeyId"
keyFile = "/pathToFile/AuthKey.p8"
key = ""
with open(keyFile, 'r') as myFile:
key = myFile.read()
print(key)
timeNow = int(round(time.time()))
time3Months = timeNow + 86400*90
claims = {
'iss': teamID,
'iat': timeNow,
'exp': time3Months,
'aud': 'https://appleid.apple.com',
'sub': app_id,
}
secret = jwt.encode(claims, key, algorithm='ES256', headers={'kid': kid})
print("secret:")
print(secret)
client_secret = secret.decode("utf-8")
print(client_secret)
Save the clientSecret and appleToken into the local DB at login time with Apple ID.
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
print("didCompleteWithAuthorization : -\(authorization)")
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
// Create an account in your system.
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName?.givenName
let email = appleIDCredential.email
guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identity token")
return
}
guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
return
}
StorageServices.storeInDefaults(object: idTokenString, key: "appleToken")
// Add new code below
if let authorizationCode = appleIDCredential.authorizationCode,
let codeString = String(data: authorizationCode, encoding: .utf8) {
StorageServices.storeInDefaults(object: codeString, key: "clientSecret")
}
default:
break
}
call the apple token revoke api.
func callRevokeTokenAPI() {
guard let clientSecret = StorageServices.readFromDefaults(key: "clientSecret") as? String else {return}
guard let appleToken = StorageServices.readFromDefaults(key: "appleToken") as? String else {return}
let parameters = "client_id=com.oxstren.Actofit-Wear&client_secret=\(clientSecret)&token=\(appleToken)&token_type_hint=access_token"
print(parameters)
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://appleid.apple.com/auth/revoke")!,timeoutInterval: Double.infinity)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let response = response as? HTTPURLResponse, error == nil else {
print("error", error ?? URLError(.badServerResponse))
return
}
print(response)
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
}
task.resume()
} //end function body.

How to get Client Secret Key Expiry date in java

I have applications registered in Azure AD Tenant and these applications have clientid and secret.
I have a requirement to get the azure application credentials expiry date. I am using azure sdk for java in my application.
How can we get the client secret expiry date using java ?
I have googled for it but didn't find any useful links. Can anyone help me on this.
If you want to get secret expiry date in your Java application, you can call the Microsoft Graph API to get the application. Then the application's property passwordCredentials has the information. For example
Register a new application using the Azure portal
Sign in to the Azure portal using either a work or school account or
a personal Microsoft account.
If your account gives you access to more than one tenant, select your account in the top right corner, and set your portal session to the Azure AD tenant that you want.
In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations > New registration.
Configure Microsoft Graph permissions you need for your application
Code
//install ADAL4J get accesss token
String clientId = "your application id";
String appKey = "your client secret";
String tenantId = "your tenant id";
String authority =String.format("https://login.microsoftonline.com/",getTenantContextId())
String resourceUrl = "https://graph.microsoft.com"
ExecutorService service = Executors.newFixedThreadPool(1);
AuthenticationContext context = ew AuthenticationContext(authority, false, service);
ClientCredential clientCred = new ClientCredential(
clientId, appKey);
Future<AuthenticationResult> future = context.acquireToken(resourceUrl, clientCred, null);
AuthenticationResult result = future.get();
//Call Microsoft graph api
String stringUrl ="https://graph.microsoft.com/beta/applications?$filter=appId eq '{ApplicationId}'";
URL url = new URL(stringUrl.replaceAll(" ","%20"));
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + result.getAccessToken());
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
int httpResponseCode = conn.getResponseCode();
if (httpResponseCode == 200 ) {
BufferedReader in = null;
StringBuilder response;
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JSONObject jb = new JSONObject(response.toString());
For more details, please refer to the document
Update
Please use the following code to get access token
String authority = "https://login.microsoftonline.com/" + tenant;
ExecutorService service = Executors.newFixedThreadPool(1);
AuthenticationContext context = new AuthenticationContext(authority, true, service);
ClientCredential cred = new ClientCredential(clientId, clientSecret);
String resourceId ="https://graph.microsoft.com";
Future<AuthenticationResult> future = context.acquireToken(resourceId, cred, null);
AuthenticationResult result = future.get();
String accesstoken = result.getAccessToken();
Add an auth file(optional but suggested, you can directly use client id and secret in your code)
Use Azure Management Libraries for Java
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure</artifactId>
<version>1.24.2</version>
</dependency>
Code sample
public static void main(String[] args) throws IOException {
File credFile = new File(ClassLoader.getSystemResource("./others/xh.auth").getPath());
ApplicationTokenCredentials credentials = ApplicationTokenCredentials.fromFile(credFile);
Azure.Authenticated authenticated = Azure.configure().authenticate(credentials);
String appObjectId = "b48bc188-ff55-4655-a1d0-b8590c179a99";
ActiveDirectoryApplication application = authenticated.activeDirectoryApplications().getById(appObjectId);
Map<String, PasswordCredential> map = application.passwordCredentials();
for ( Map.Entry<String,PasswordCredential> entry: map.entrySet()) {
String key = entry.getKey();
PasswordCredential value = entry.getValue();
System.out.println("Name -> " + key + " ; End date -> " + value.endDate().toString());
}
}
Output
Name -> t o m ; End date -> 2299-12-30T16:00:00.000Z
Name-> 3ba9bb7b-5251-4bbb-a373-658e346eb44d ; End date -> 2299-12-30T16:00:00.000Z
Name-> p o s t m a n ; End date -> 2299-12-30T16:00:00.000Z
Update:
You can get the application object id from portal:
Update2:
There is a getByName method:
ActiveDirectoryApplication byName = authenticated.activeDirectoryApplications().getByName("");
But there is a known problem. As the applications registered in Azure AD could have the same name. This method will not get a correct
ActiveDirectoryApplication instance as you expected. You will always get the first one in the list. (Actually, with REST API and filter, you will get a list too)
But, if you have created all the applications with different names, then you can use the getByName method.

Signature invalid while trying to retrieve accesToken for copy api

I am trying to load a url with headers and trying to get my accessToken
Here is the code
String oauthToken = urls[0];
String tokenVerifier = urls[1];
String responseBody = null;
try {
String url = "https://api.copy.com/oauth/access?oauth_verifier=" + tokenVerifier;
String uniqueID = UUID.randomUUID().toString();
String authorization = "OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\""+ Constants.COPY_CONSUMER_KEY
+"\", oauth_signature=\""+ Constants.COPY_SECRET +"&" + tokenVerifier "\", oauth_nonce=\""+ uniqueID
+"\", oauth_timestamp=\""+String.valueOf(Calendar.getInstance().getTimeInMillis())+"\" , oauth_token=\""+ oauthToken +"\"";
The response gives me error
oauth_problem=signature_invalid&debug_sbs=GET&https%3A%2F%2Fapi.copy.com%2Foauth%2Faccess&oauth_consumer_key%3DCtu6CtdN1PWRo5DstoxgaaIQWZkeeWNg%26oauth_nonce%3D10525625%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1425400347545%26oauth_token%3D6aNkypb7wZoI7dbJiSrtItOTGmpaG0RL%26oauth_verifier%3D496cb46091352c4788603dcfb6e0cfb5%26oauth_version%3D1.0oauth_error_code=2000
What is wrong with my signature, same method is working for ios
You are sending the ouath_token that you have just received when you have to calculate a new Token using that received token and the request_token_secret. This new token is what you need to send as oauth_token parameter in your request.
Check my python code here.

Twitter API status update always returns "Incorrect signature"

I'm using Signpost as OAuth implementation for posting to Twitter. And implemented the GoogleAppEngineOAuthConsumer and GoogleAppEngineOAuthProvider classes, but since they're pretty trivial, so I'm not providing their sources here (yet).
Here's my authentication part, which seems to work just fine.
LoginServlet.java:
// fetching the request token
OAuthConsumer consumer = new GoogleAppEngineOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
OAuthProvider provider = new GoogleAppEngineOAuthProvider(REQUEST_TOKEN_URL, ACCESS_TOKEN_URL, AUTHORIZATION_URL);
String redirectUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
// cache the request token and request token secret
response.sendRedirect(redirectUrl);
CallbackServlet.java
// fetching the access token
String verifier = (String) req.getParameter("oauth_verifier");
// retrieve request token and request token secret from cache
OAuthConsumer consumer = new GoogleAppEngineOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
OAuthProvider provider = new GoogleAppEngineOAuthProvider(REQUEST_TOKEN_URL,
consumer.setTokenWithSecret(token, tokenSecret);
provider.setOAuth10a(true);
provider.retrieveAccessToken(consumer, verifier);
// store access token and access token secret
And here's the actual problematic part.
TweetServlet.java
OAuthConsumer consumer = new GoogleAppEngineOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
// retrieve access token and access token secret from storage
consumer.setTokenWithSecret(accessToken, accessTokenSecret);
final HTTPRequest updateStatus = new HTTPRequest(new URL("http://api.twitter.com/1/statuses/update.json"), HTTPMethod.POST);
updateStatus.setPayload(("status=" + URLEncoder.encode(message, "UTF-8")).getBytes());
consumer.sign(updateStatus);
logger.debug(new String(URLFetchServiceFactory.getURLFetchService().fetch(updateStatus).getContent()));
Each and every time it results: {"request":"/1/statuses/update.json","error":"Incorrect signature"}.
I was able to solve this by myself. The problem was that I wasn't setting a Content-Type header to the request, so the signing didn't sign the parameters and it resulted the invalid signature. Once I set it to application/x-www-form-urlencoded it started working.
final HTTPRequest updateStatus = new HTTPRequest(new URL("http://api.twitter.com/1/statuses/update.json"), HTTPMethod.POST);
updateStatus.addHeader(new HTTPHeader("Content-Type", "application/x-www-form-urlencoded"));

Categories

Resources