SignatureDoesNotMatch error when creating signed url - google-cloud-storage

I'm getting SignatureDoesNotMatch error when trying to generate a signed URL for a bucket resource. I've gone over the examples in the GCP github project and looked at the code in other posts to tweak mine but something is still off about how I'm signing my data I guess.
Error Response:
<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 2944813518 /bucketName/file.mp3
</StringToSign>
</Error>
Code
public String getSignedURL(String objectName, String contentType){
long timeStamp = System.currentTimeMillis() / 1000L;
timeStamp = timeStamp + (3600 * 24 * 365 * 1000);
String dataToBeSigned = "GET\n" + contentType +"\n" + timeStamp + "\n" + "/" + settings.getStorageBucketName() + "/" + objectName;
System.out.println(dataToBeSigned);
String signature = signData(dataToBeSigned);
String urlEncodedSignature = URLEncoder.encode(signature, "UTF-8");
return new StringBuilder("https://storage.googleapis.com")
.append("/")
.append(settings.getStorageBucketName())
.append("/")
.append(objectName)
.append("?GoogleAccessId=")
.append(settings.getStorageServiceAccountId())
.append("&Expires=")
.append(timeStamp)
.append("&Signature=")
.append(urlEncodedSignature).toString();
}
private String signData(String dataToBeSigned) {
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initSign(getPrivateKey());
signer.update(dataToBeSigned.getBytes("UTF-8"));
byte[] rawSignature = signer.sign();
String base64EncodedSignature = new String(Base64.encodeBase64(rawSignature,false),"UTF-8");
return base64EncodedSignature;
}
private PrivateKey getPrivateKey() {
InputStream inputStream = new FileInputStream(settings.getStorageAccessKeyLocation());
String password = settings.getStorageAccessKeyPassword();
return SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), inputStream, password, "privatekey", password);
}

If you use Spring, the easiest way to sign GCP URL is via GCP SDK https://cloud.google.com/storage/docs/reference/libraries#client-libraries-usage-java
spring-cloud-gcp-starter-storage
To set up integration with GCP define properties in the application.yml:
spring:
cloud:
gcp:
project-id: PROJECT_ID
credentials:
location: classpath:GCP_SERVICE_ACCOUNT_KEY.json
#Autowired
private Storage storage;
public String getSignedUrlToWinReleasesBucketViaSdk() {
GoogleStorageResource googleStorageResource = new GoogleStorageResource(storage, "gs://BUCKET_NAME");
URL signedUrl = googleStorageResource.getBucket().get("OBJECT_NAME")
.signUrl(15, TimeUnit.MINUTES);
return signedUrl.toString();
}
Solution without GCP SDK:
public String getSignedUrlToWinReleasesBucket(String bucketName, String objectName) {
String expirationTime = nowPlusMinutes(15);
String urlTemplate = "GET" + "\n"
+ "" + "\n"
+ "" + "\n"
+ expirationTime + "\n"
+ "/" + bucketName + "/" + objectName;
String signature = getSignedString(urlTemplate, privateKey());
// URL encode the signed string so that we can add this URL
signature = URLEncoder.encode(signature, StandardCharsets.UTF_8);
String signedUrl = baseStorageUrl + "/" + bucketName + "/" + objectName
+ "?GoogleAccessId=" + gcpStorageClientEmail
+ "&Expires=" + expirationTime
+ "&Signature=" + signature;
return signedUrl;
}
private static String nowPlusMinutes(int minutes) {
long now = System.currentTimeMillis();
long expiredTimeInSeconds = (now + 60 * 1000L * minutes) / 1000;
return String.valueOf(expiredTimeInSeconds);
}
private static String getSignedString(String input, PrivateKey privateKey) {
try {
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(privateKey);
privateSignature.update(input.getBytes(StandardCharsets.UTF_8));
byte[] s = privateSignature.sign();
return Base64.encodeBase64String(s);
} catch (GeneralSecurityException e) {
throw new Exception("Cannot sign url with GCP Storage private key.", e, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private PrivateKey privateKey() {
String key = gcpStoragePrivateKey
.replaceAll("-----END PRIVATE KEY-----", "")
.replaceAll("-----BEGIN PRIVATE KEY-----", "")
.replaceAll("\n", "");
byte[] keyDecoded = Base64.decodeBase64(key);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyDecoded);
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new Exception("Cannot get GCP Storage private key.", e, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

Related

Created OAuth bearer token generated with jwt token is invalid for REST calls

I am new to DocuSign and the REST-API. I created a developer account and added a new "Apps and Keys" entry for my application (Authentication = Implicit Grant and RSA key pairs). The keys were stored in two seperate files.
I activated the Keys using the following URL:
http://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=_the_integration_key&redirect_uri=http://localhost
I am trying to write a JAVA application without spring security framework (or any other framework).
To read the key files I used and modified (a little bit) the functions from the DocuSign examples.
private static RSAPublicKey readPublicKeyFromFile(String filepath, String algorithm) throws IOException {
File pemFile = new File(filepath);
if (!pemFile.isFile() || !pemFile.exists()) {
throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
}
PemReader reader = new PemReader(new FileReader(pemFile));
try {
PemObject pemObject = reader.readPemObject();
byte[] bytes = pemObject.getContent();
RSAPublicKey publicKey = null;
try {
KeyFactory kf = KeyFactory.getInstance(algorithm);
EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
publicKey = (RSAPublicKey) kf.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
System.out.println("Could not reconstruct the public key, the given algorithm could not be found.");
} catch (InvalidKeySpecException e) {
System.out.println("Could not reconstruct the public key");
}
return publicKey;
} finally {
reader.close();
}
}
private static RSAPrivateKey readPrivateKeyFromFile(String filepath, String algorithm) throws IOException {
File pemFile = new File(filepath);
if (!pemFile.isFile() || !pemFile.exists()) {
throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
}
PemReader reader = new PemReader(new FileReader(pemFile));
try {
PemObject pemObject = reader.readPemObject();
byte[] bytes = pemObject.getContent();
RSAPrivateKey privateKey = null;
try {
Security.addProvider(new BouncyCastleProvider());
KeyFactory kf = KeyFactory.getInstance(algorithm, "BC");
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
privateKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
System.out.println("Could not reconstruct the private key, the given algorithm could not be found.");
} catch (InvalidKeySpecException e) {
System.out.println("Could not reconstruct the private key");
} catch (NoSuchProviderException e) {
System.out.println("Could not reconstruct the private key, invalid provider.");
}
return privateKey;
} finally {
reader.close();
}
}
private static RSAPrivateKey readPrivateKeyFromByteArray(byte[] privateKeyBytes, String algorithm) throws IOException {
PemReader reader = new PemReader(new StringReader(new String(privateKeyBytes)));
try {
PemObject pemObject = reader.readPemObject();
byte[] bytes = pemObject.getContent();
RSAPrivateKey privateKey = null;
try {
Security.addProvider(new BouncyCastleProvider());
KeyFactory kf = KeyFactory.getInstance(algorithm, "BC");
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
privateKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
System.out.println("Could not reconstruct the private key, the given algorithm could not be found.");
} catch (InvalidKeySpecException e) {
System.out.println("Could not reconstruct the private key");
} catch (NoSuchProviderException e) {
System.out.println("Could not reconstruct the private key, invalid provider.");
}
return privateKey;
} finally {
reader.close();
}
}
To get the JWT token I used the following function:
public static String generateJWTAssertion(String publicKeyFilename, String privateKeyFilename, String oAuthBasePath, String clientId, String userId, long expiresIn) throws JWTCreationException, IOException {
String token = null;
if (expiresIn <= 0L) {
throw new IllegalArgumentException("expiresIn should be a non-negative value");
}
if (publicKeyFilename == null || "".equals(publicKeyFilename) || privateKeyFilename == null || "".equals(privateKeyFilename) || oAuthBasePath == null || "".equals(oAuthBasePath) || clientId == null || "".equals(clientId)) {
throw new IllegalArgumentException("One of the arguments is null or empty");
}
try {
RSAPublicKey publicKey = readPublicKeyFromFile(publicKeyFilename, "RSA");
RSAPrivateKey privateKey = readPrivateKeyFromFile(privateKeyFilename, "RSA");
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
long now = System.currentTimeMillis();
token = JWT.create()
.withIssuer(clientId) // integration key
.withSubject(userId) // null
.withAudience(oAuthBasePath) // account-d.docusign.com
.withNotBefore(new Date(now))
.withExpiresAt(new Date(now + expiresIn * 1000))
.withClaim("scope", "signature impersonation")
.sign(algorithm);
} catch (JWTCreationException e){
throw e;
} catch (IOException e) {
throw e;
}
return token;
}
I checked the generated token on https://jwt.io/ and the content looks fine.
To get the bearer token I use the following code:
public Boolean getBearer(long expiresIn) throws IOException {
String jwtToken = JwtUtils.generateJWTAssertion(
RESOURCES_DIR + "public.key",
RESOURCES_DIR + "private.key",
oAuthBasePath,
integrationKey,
null,
expiresIn
);
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("text/plain");
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
.addFormDataPart("assertion", jwtToken)
.build();
Request request = new Request.Builder()
.url("https://" + oAuthBasePath + "/oauth/token") // https://account-d.docusign.com/oauth/token
.method("POST", body)
.build();
Response response = client.newCall(request).execute();
int responseCode = response.code();
String responseText = response.body().string();
Gson gson = new Gson();
OAuthResponse oAuthResponse = gson.fromJson(responseText, OAuthResponse.class);
if (responseCode >= 200 && responseCode <= 299) {
bearerToken = oAuthResponse.getAccess_token();
return true;
}
System.out.println("Errorcode: " + oAuthResponse.getError());
System.out.println("Error: " + oAuthResponse.getError_description());
return false;
}
I get the bearer token and want to use it for the following REST calls.
For example:
public void getUsers () throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url(getRestBaseUrl() +"/users") // https://demo.docusign.net/restapi/v2.1/accounts/_API_account_id/users
.method("GET", null)
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer " + bearerToken)
.build();
Response response = client.newCall(request).execute();
String responseText = response.body().string();
System.out.println(responseText);
}
But instead of a JSON structure with the users of my developer account, I got the following response:
{"errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"The access token provided is expired, revoked or malformed. Authentication for System Application failed."}
When I use the API explorer and the bearer token, I can use it for authentication (it is shown as valid), but the REST call for "users" get the same error response.
So I used the API explorer for login and the REST call works.
I used the bearer token from the API explorer and used it (as fixed entered string value) as bearer token. And the JAVA REST calls works.
So, there must be an error in generating / requesting the JWT token or bearer token.
Any idea what's wrong?
Regards,
Rainer
I found the reason.
The API username was missing.
String jwtToken = JwtUtils.generateJWTAssertion(
RESOURCES_DIR + "public.key",
RESOURCES_DIR + "private.key",
oAuthBasePath,
integrationKey,
"_here_the_API_username",
expiresIn
);
After adding the username I could use the API.

iOS JWE AES GCM 256

I am trying to implement JWE token in Swift using JOSESwift (modified to support AES-GCM 256) and CryptoSwift(need to support iOS 11+). I am able to encrypt and decrypt using public/private key pair. But when the same JWE token passed on to Java (server-side program) it's not able to decrypt. Vice e versa is also not working. Need help, can share my github project
https://github.com/sreekanthps/VAMDemoJava.git - Java project https://github.com/sreekanthps/VMADemo.git - iOS project https://github.com/sreekanthps/JOSESwift-AES256GCM.git - modified JOSESwift project
Nimbus
Exception in thread "main" com.nimbusds.jose.JOSEException: AES/GCM/NoPadding decryption failed: Tag mismatch!
at com.nimbusds.jose.crypto.impl.AESGCM.decrypt(AESGCM.java:301)
at com.nimbusds.jose.crypto.impl.ContentCryptoProvider.decrypt(ContentCryptoProvider.java:279)
at com.nimbusds.jose.crypto.RSADecrypter.decrypt(RSADecrypter.java:285)
at com.nimbusds.jose.JWEObject.decrypt(JWEObject.java:415)
at me.txedo.security.Main.numbusJWe(Main.java:127)
at me.txedo.security.Main.main(Main.java:52)
Jose4j
Exception in thread "main" org.jose4j.lang.JoseException: javax.crypto.AEADBadTagException: Tag mismatch!
at org.jose4j.jwe.SimpleAeadCipher.decrypt(SimpleAeadCipher.java:114)
at org.jose4j.jwe.SimpleAeadCipher.decrypt(SimpleAeadCipher.java:101)
at org.jose4j.jwe.AesGcmContentEncryptionAlgorithm.decrypt(AesGcmContentEncryptionAlgorithm.java:79)
at org.jose4j.jwe.JsonWebEncryption.decrypt(JsonWebEncryption.java:249)
at org.jose4j.jwe.JsonWebEncryption.getPlaintextBytes(JsonWebEncryption.java:85)
at org.jose4j.jwe.JsonWebEncryption.getPlaintextString(JsonWebEncryption.java:78)
at org.jose4j.jwe.JsonWebEncryption.getPayload(JsonWebEncryption.java:93)
at me.txedo.security.Main.jose4JDeryption(Main.java:166)
at me.txedo.security.Main.main(Main.java:55)
Swift code
keyData = try! randomData(ofLength: 32)
ivData = try! randomData(ofLength: 16)
let message = "Summer ⛱, Sun ☀️, Cactus 🌵".data(using: .utf8)!
let header = JWEHeader(keyManagementAlgorithm: .RSAOAEP256, contentEncryptionAlgorithm: .AES256GCM)
let payload = Payload(message)
let publickey = RSAKeyGenerator.shared.getPublicKey()
let privateKey = RSAKeyGenerator.shared.getPrivateKey()
let encrypter = Encrypter(keyManagementAlgorithm: .RSAOAEP256, contentEncryptionAlgorithm: .AES256GCM, encryptionKey: publickey!)!
if let jwe = try? JWE(header: header, payload: payload, encrypter: encrypter) {
jwtString = jwe.compactSerializedString
print("jwtString : \(jwtString!)")
}
do {
let jwe = try JWE(compactSerialization: jwtString!)
let decrypter = Decrypter(keyManagementAlgorithm: .RSAOAEP256, contentEncryptionAlgorithm: .AES256GCM, decryptionKey: privateKey!)!
let payload = try jwe.decrypt(using: decrypter)
let message = String(data: payload.data(), encoding: .utf8)!
print(message) // Summer ⛱, Sun ☀️, Cactus 🌵
}catch {
print("Decryption error :\(error.localizedDescription)")
}
Java Code
protected final static Logger LOGGER = Logger.getLogger(Main.class);
public final static String RESOURCES_DIR = "/Users/swesree/Desktop/KH802/CERTS/";
public static void main(String[] args) throws FileNotFoundException,
IOException, NoSuchAlgorithmException, NoSuchProviderException, ParseException, JOSEException, JoseException {
Security.addProvider(new BouncyCastleProvider());
LOGGER.info("BouncyCastle provider added.");
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
try {
PrivateKey priv = generatePrivateKey(factory, RESOURCES_DIR + "vmaprivate.pem");
LOGGER.info(String.format("Instantiated private key: %s", priv));
PublicKey pub = generatePublicKey(factory, RESOURCES_DIR + "vmapublic.pem");
LOGGER.info(String.format("Instantiated public key: %s", pub));
//numbusJWe(pub,priv);
String jweString = jose4JEcnryption(pub);
jose4JDeryption(priv,jweString);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
}
private static PrivateKey generatePrivateKey(KeyFactory factory, String filename)
throws InvalidKeySpecException, FileNotFoundException, IOException {
PemFile pemFile = new PemFile(filename);
byte[] content = pemFile.getPemObject().getContent();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
return factory.generatePrivate(privKeySpec);
}
private static PublicKey generatePublicKey(KeyFactory factory, String filename)
throws InvalidKeySpecException, FileNotFoundException, IOException {
PemFile pemFile = new PemFile(filename);
byte[] content = pemFile.getPemObject().getContent();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return factory.generatePublic(pubKeySpec);
}
private static void numbusJWe(PublicKey publicKey, PrivateKey privKey) throws ParseException, JOSEException {
Date now = new Date();
JWTClaimsSet jwtClaims = new JWTClaimsSet.Builder()
.issuer("https://openid.net")
.subject("alice")
.audience(Arrays.asList("https://app-one.com", "https://app-two.com"))
.expirationTime(new Date(now.getTime() + 1000*60*10)) // expires in 10 minutes
.notBeforeTime(now)
.issueTime(now)
.jwtID(UUID.randomUUID().toString())
.build();
System.out.println(jwtClaims.toJSONObject());
// Request JWT encrypted with RSA-OAEP-256 and 128-bit AES/GCM
JWEHeader header = new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM);
// Create the encrypted JWT object
EncryptedJWT jwt = new EncryptedJWT(header, jwtClaims);
// Create an encrypter with the specified public RSA key
RSAEncrypter encrypter = new RSAEncrypter((RSAPublicKey) publicKey);
// Do the actual encryption
jwt.encrypt(encrypter);
// Serialise to JWT compact form
String jwtString = jwt.serialize();
System.out.println("jwtString : "+jwtString);
//
//
// Parse back
//String jwtStringNew = "eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.hJ905rCCsW0u07cCleTh_eYKAyDP7ZHNnRA50qDWXo7seygePzIkr37ZCeaW2hmZ-c6v_c7Yp3Y0kzE5OE0h93J09XAtYfwZk3zZVKXH8hd6fWjeY7ZgB8I4CpQaa9BX-Zp9bBznXHh5WqpckkMAXZVT-wiLNVqQDpyg8Jifi5tuw4SjT4irRrFYF5LfSDLU4EigKKC3Rn1IOlwEKhHuvqLFuCbqgXVh_Ps75P9_wXr3XoKSwEDf5zbOh42cPlenKfG0TQpeEhKamEbmpuRnOZYRHmOQ0d6KTI7t8xxRQ0g3nF0AJGQKwnbZDgZPli8v3dI8XZY9rca03rG8aQpCag.JFWISQTeuw2euVfT.5ekMlQk5tkPFLdUnZIh-GMfFGS36UPKAd_obtu-YCy_vv_iuNPVbxZyzjJFRnK2-G8Cf3UuKvpNusyjpd_AfIvoxg7fqCr95CZ8IulBGo1SddvcXx-kCsCNPawK97pN7qclHc6oqrIpK4CjUR0msJtgNbdTrFI0VOw1dLXoz_jFJ13xO1LQiXkxdJltD6qpEfE3x1UyNFpDHudplur7v6cd9WOXNFlQ6zQYfn-9ZHOMGoGFcQAB9u9crCkoyIX4vifNrJA.zD8126ElxZvp-RODUr5qSg";
String jwtStringNew = "eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.wDiB-oEawb6cBHUyHT-_LVtRwaA7bwL8qwoqXGYayXae6EFr6wKIP2M5woq9HSGWRFH48JIyNS6V_K3MdXfh9oqjVd3djBeUKtcP6b-2jWjFxLL-WOgZpHmSMpWhOB55ogKQRumo0YYn4HMd8JrQ48uYGa7NoWOxMIBajKNu4utkOW-1q-ccbN4_6mds90brEJDnlbcHyo22sjufiXeKhN8_JaN6uqx3qet08ouhEEOaFhssj7nyP3ynz75rT17iw_VAoS91JP6lb-Q4T4ZsA_9_ibZUZn4vkk1mWU0Kul2Hp0z5GXw_ZPNi7IsTv0D4xvDnWmwTUb3ekdj0cCYmMg.e0w_dONIFxka8bXU.bEAl8JYqj-4xSlC1i4xXSbdMqBz61TuKUHdYq46L2_vxTpTjh04o5juH4eDbs6cfEgGy.44dOKOY7h-Hg27OnHxIBsg";
EncryptedJWT jwt1= EncryptedJWT.parse(jwtStringNew);
// Create a decrypter with the specified private RSA key
RSADecrypter decrypter = new RSADecrypter(privKey);
// Decrypt
jwt1.decrypt(decrypter);
System.out.println(jwt1.getHeader());
System.out.println("numbusJWe::: "+jwt1.getPayload());
// TODO Auto-generated method stub
}
private static String jose4JEcnryption(PublicKey key) throws JoseException {
JsonWebEncryption jwe = new JsonWebEncryption();
jwe.setPayload("Hello World!");
jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.RSA_OAEP_256);
jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_256_GCM);
jwe.setKey(key);
String serializedJwe = jwe.getCompactSerialization();
System.out.println("Serialized Encrypted JWE: " + serializedJwe);
return serializedJwe;
}
private static void jose4JDeryption(PrivateKey key, String jweToken) throws JoseException {
String jwtStringNew1 = "eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.wDiB-oEawb6cBHUyHT-_LVtRwaA7bwL8qwoqXGYayXae6EFr6wKIP2M5woq9HSGWRFH48JIyNS6V_K3MdXfh9oqjVd3djBeUKtcP6b-2jWjFxLL-WOgZpHmSMpWhOB55ogKQRumo0YYn4HMd8JrQ48uYGa7NoWOxMIBajKNu4utkOW-1q-ccbN4_6mds90brEJDnlbcHyo22sjufiXeKhN8_JaN6uqx3qet08ouhEEOaFhssj7nyP3ynz75rT17iw_VAoS91JP6lb-Q4T4ZsA_9_ibZUZn4vkk1mWU0Kul2Hp0z5GXw_ZPNi7IsTv0D4xvDnWmwTUb3ekdj0cCYmMg.e0w_dONIFxka8bXU.bEAl8JYqj-4xSlC1i4xXSbdMqBz61TuKUHdYq46L2_vxTpTjh04o5juH4eDbs6cfEgGy.44dOKOY7h-Hg27OnHxIBsg";
JsonWebEncryption jwe = new JsonWebEncryption();
jwe.setAlgorithmConstraints(new AlgorithmConstraints(ConstraintType.PERMIT,
KeyManagementAlgorithmIdentifiers.RSA_OAEP_256));
jwe.setContentEncryptionAlgorithmConstraints(new AlgorithmConstraints(ConstraintType.PERMIT,
ContentEncryptionAlgorithmIdentifiers.AES_256_GCM));
jwe.setKey(key);
jwe.setCompactSerialization(jwtStringNew1);
System.out.println("JOSE4J ::: getHeaders :::: " + jwe.getHeaders());
System.out.println("JOSE4J ::: getContentEncryptionAlgorithm :::: " + jwe.getContentEncryptionAlgorithm());
System.out.println("JOSE4J ::: getEncryptedKey :::: " + jwe.getEncryptedKey());
System.out.println("JOSE4J ::: getIv :::: " + jwe.getIv());
System.out.println("JOSE4J ::: Payload :::: " + jwe.getPayload());
}

How to display error message in multi file uploading with Rest webservices

Hi am in way of uploading multiple files into aws bucket using spring mvc and rest web services.
The positive scenario is working like if I select more one file its saved in aws bucket and am getting 200 here
String json1 = handler.handleResponse(response1);
System.out.println(json1);
My question is I have selected three files called x ,y and z as usual way the first file gets saved into bucket due to some issue y and z files failed to save how to inform the user that y and z are not saved into bucket
#PostMapping("/upload")
public String handleFileUpload(#RequestParam("specifications") MultipartFile[] specifications,
HttpServletRequest request,HttpSession session,final RedirectAttributes redirectAttributes) throws Exception {
for (int i = 0; i < specifications.length; i++) {
MultipartFile file = specifications[i];
String path = "Specification/";
String bucketName="BUcket/";
String inJson = "{\"filename\":\"" + file.getOriginalFilename() + "\",\"bucketname\":\""+ bucketName + "\",\"path\":\""+ path + "\"}";
addLogo(file, inJson);
}
code upload file
public void addLogo(MultipartFile file ,String inJson) throws IOException
{
String message="";
byte[] bytes = file.getBytes();
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
HttpPost httppost = new HttpPost(fileUploadURL);
HttpEntity entity = MultipartEntityBuilder.create().addTextBody("json", inJson).addBinaryBody("file", bytes).build();
httppost.setEntity(entity);
HttpResponse response1 = httpclient.execute(httppost);
System.out.print(response1.getStatusLine());
ResponseHandler<String> handler = new BasicResponseHandler();
String json1 = handler.handleResponse(response1);
System.out.println(json1);
message = message + "You successfully uploaded " + file.getOriginalFilename() + "\n";
System.out.println(message);
}
by using ResponseEntity spring object, you can customize your returns based upload results. you catch IOEXception and create a specific return String,
I modified your method to be like this :
#PostMapping("/upload")
public ResponseEntity<?> handleFileUpload(#RequestParam("specifications")
MultipartFile[] specifications,
HttpServletRequest request,HttpSession session,final RedirectAttributes
redirectAttributes) throws Exception {
String failed_upload="";
for (int i = 0; i < specifications.length; i++) {
try{
MultipartFile file = specifications[i];
String path = "Specification/";
String bucketName="BUcket/";
String inJson = "{\"filename\":\"" + file.getOriginalFilename()
+ "\",\"bucketname\":\""+ bucketName + "\",\"path\":\""+ path + "\"}";
addLogo(file, inJson);
}catch(IOException){
failed_upload=failed_upload+specifications[i]+" ,";
}
} if(!failed_upload.equals("")){
return new ResponseEntity<>("Files"+failed_upload+" not uploaded",
HttpStatus.INTERNAL_SERVER_ERROR);
}else{
return new ResponseEntity<>("Everything is ok", HttpStatus.OK);
}

Google Cloud Storage - JAVA REST API - Getting SignatureDoesNotMatch

I am using jersey-client to make REST Call . I am getting SignatureDoesNotMatch error in response.
I was trying to List down Bucket names using GET Service , also tried to list Bucket object using GET Bucket method.
here is my sample code.
Any hint or solution ?
public class restSample {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final String PROJECT_ID = "10XXXXXXXX478";
public static String Base64Encoding()
throws java.security.SignatureException, UnsupportedEncodingException {
String access_id = "GOOGBAXXXXXXXXXXBI";
String secret_key = URLEncoder.encode("pWTXXXXXXXXXXXXXXXRo85T+XXXXXXXXX3O","UTF-8");
String bucket = "bucket_name";
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.encode(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();
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)
.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://bucket_name.storage.googleapis.com";
return UriBuilder.fromUri(url).build();
}
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());
}
}
Thanks!
Make sure the string you are signing matches the expected string to sign. Google cloud storage returns the expected string to sign in the HTTP response if authentication fails.
In your particular example it looks like you are adding both the version_header and project_header into the string to sign. These are not in the list of CanonicalHeaders nor CanonicalExtensionHeaders, so you are signing a different string than the server.
You can review the list here: https://developers.google.com/storage/docs/reference/v1/developer-guidev1#authentication

Stackmob is giving 401 error while registering device

I am registering the device to stackmob with username and device token . I am getting valid tokens from c2dn and then storing it into db for that user and then while registering to stackmob i am using these parameters. On dev environment its working fine but same piece of code is giving 401 while registering the device. Please suggest me in this.
The code for this is below :
public String registerWithNotificationServiceProvider(final String userName, final String deviceToken) throws UserException
{
if (userName.isEmpty() || deviceToken.isEmpty()) {
throw new UserException(ResponseCodes.STATUS_BAD_REQUEST, "User Name or device token is null",## Heading ## "label.invalid.user.device.details");
}
StackMobRequestSendResult deviceRegisterResult = null;
deviceRegisterResult = StackMob.getStackMob().registerForPushWithUser(userName, deviceToken,
new StackMobRawCallback() {
#Override
public void done(HttpVerb requestVerb, String requestURL,
List<Map.Entry<String, String>> requestHeaders, String requestBody,
Integer responseStatusCode, List<Map.Entry<String, String>> responseHeaders,
byte[] responseBody) {
String response = new String(responseBody);
logger.info("request Body is " + requestBody);
logger.info("request Url is " + requestURL);
for(Map.Entry<String, String> entry : requestHeaders){
logger.info("Request Header is " + entry.getKey());
logger.info("Request Header content is " + entry.getValue());
}
for(Map.Entry<String, String> entry : responseHeaders){
logger.info("Response Header is " + entry.getKey());
logger.info("Response Header content is " + entry.getValue());
}
logger.info("response while registering the device is " + response);
logger.info("responseCode while registering device " + responseStatusCode);
}
});
String status = null;
if (deviceRegisterResult.getStatus() != null) {
status = deviceRegisterResult.getStatus().name();
logger.debug("For user : " + userName + " Status for registering device is " + status);
}
if (Status.SENT.getStatus().equalsIgnoreCase(status)) {
return Status.SUCCESS.getStatus();
} else {
return Status.FAILURE.getStatus();
}
}
When you setup your StackMob object with the api key and secret, do you remember to use apiVersion 1 with your production key and secret? That's the most likely problem.
StackMobCommon.API_KEY = KEY;
StackMobCommon.API_SECRET = SECRET;
StackMobCommon.USER_OBJECT_NAME = "user";
StackMobCommon.API_VERSION = 1; //! 0 for dev, 1 for production
If that doesn't work also set
StackMob.getStackMob().getLogger().setLogging(true);
at the beginning and post the resulting logs