when I use aws ses to send a email exception happened which show me that
com.amazonaws.AmazonServiceException:
Invalid date Mon, 14 Dec 2015 02:08:56 +00:00. It must be in one of
the formats specified by HTTP RFC 2616 section 3.3.1 (Service:
AmazonSimpleEmailService; Status Code: 400; Error Code:
InvalidParameterValue; Request ID:
e2716096-a207-11e5-9615-8135b4d7f5f9)
follows is my code :
public class SESEmailUtil {
private final String accesskey = "XXXXXXXXX";
private final String secretkey = "XXXXXXXXXXXXXXXX";
private String REGION = "us-east-1";
private Region region;
private static AWSCredentials credentials;
private static AmazonSimpleEmailServiceClient sesClient;
private static SESEmailUtil sesEmailUtil = null;
private SESEmailUtil() {
init(accesskey, secretkey);
};
public void init(String accesskey, String secretkey) {
credentials = new BasicAWSCredentials(accesskey, secretkey);
sesClient = new AmazonSimpleEmailServiceClient(credentials);
region = Region.getRegion(Regions.fromName(REGION));
sesClient.setRegion(region);
}
public static SESEmailUtil getInstance() {
if (sesEmailUtil == null) {
synchronized (SESEmailUtil.class) {
return new SESEmailUtil();
}
} else {
return sesEmailUtil;
}
}
public void sendEmail(String sender, LinkedList<String> recipients,
String subject, String body) {
Destination destination = new Destination(recipients);
try {
Content subjectContent = new Content(subject);
Content bodyContent = new Content(body);
Body msgBody = new Body(bodyContent);
Message msg = new Message(subjectContent, msgBody);
SendEmailRequest request = new SendEmailRequest(sender,
destination, msg);
SendEmailResult result = sesClient.sendEmail(request);
System.out.println(result + "Email sent");
} catch (Exception e) {
e.printStackTrace();
System.out
.println("Exception from EmailSender.java. Email not send");
}
}
}
public class TestSend {
private static String sender = "";
private static LinkedList<String> recipients = new LinkedList<String>();
static final String BODY = "This email was sent through Amazon SES by using the AWS SDK for Java.";
static final String SUBJECT = "Amazon SES test (AWS SDK for Java)";
public static void main(String args[]) {
SESEmailUtil sendUtil = SESEmailUtil.getInstance();
String receive = "qinwanghao#XXXX.com.cn";
recipients.add(receive);
sendUtil.sendEmail(sender, recipients, SUBJECT, BODY);
}
}
The code is based on the example provided by aws.
the date Mon, 14 Dec 2015 02:08:56 +00:00 is invalid , but where can I modify the format?
wish someone can help me.THK.
Issue is likely with Joda-time version. In case of this error you should check your dependency tree, with maven (mvn dependency:tree). Look for any joda-time versions conflicting with one supplied by aws-sdk. To fix: add the conflicting version of joda-time to exclusions in your pom.xml (or equivalent).
Related
I am using DocuSign java client first time. I am create custom template for my pdf file. I am using DocuSign APIs. But facing following error:
javax.servlet.ServletException: java.lang.NoClassDefFoundError:
com/migcomponents/migbase64/Base64
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:420)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
I have created REST API and in that API i am trying to use createTemplate code but facing above issue.
I have imported all required jars in my project using maven. All jars are also present in my classpath. It seems at compile time all jar are found but at runtime not able to find the jars.
#Path("/template")
public class CreateTemplate {
private static final String UserName = "xyz.abc#gmail.com";
private static final String UserId = "fcc5726c-cd73-4844-b580-40bbbe6ca126";
private static final String IntegratorKey = "ae30ea4e-3959-4d1c-b867-fcb57d2dc4df";
private static final String IntegratorKeyImplicit = "68c1711f-8b19-47b1-888f-b49b4211d831";
//private static final String ClientSecret = "b4dccdbe-232f-46cc-96c5-b2f0f7448f8f";
private static final String RedirectURI = "https://www.docusign.com/api";
private static final String BaseUrl = "https://demo.docusign.net/restapi";
//private static final String OAuthBaseUrl = "account-d.docusign.com";
private static final String privateKeyFullPath = System.getProperty("user.dir") + "/src/test/keys/docusign_private_key.txt";
private static final String SignTest1File = "C:\\Users\\xyz\\Documents\\testDocuments\\SignTest1.pdf";
//private static final String TemplateId = "cf2a46c2-8d6e-4258-9d62-752547b1a419";
private String[] envelopeIds = new String[0];
TemplateSummary templateSummary;
#GET
#Path("/createTemplate")
#Produces("text/plain")
public TemplateSummary createTemplate() {
System.out.println("\nCreateTemplateTest:\n" + "===========================================");
byte[] fileBytes = null;
File f;
try {
// String currentDir = new java.io.File(".").getCononicalPath();
String currentDir = System.getProperty("user.dir");
java.nio.file.Path path = Paths.get(SignTest1File);
fileBytes = Files.readAllBytes(path);
f = new File(path.toString());
//Assert.assertTrue(f.length() > 0);
System.out.println("f.length()-->"+f.length());
} catch (IOException ioExcp) {
//Assert.assertEquals(null, ioExcp);
ioExcp.printStackTrace();
}
// create an envelope to be signed
EnvelopeTemplate templateDef = new EnvelopeTemplate();
templateDef.setEmailSubject("Please Sign my Java SDK Envelope");
templateDef.setEmailBlurb("Hello, Please sign my Java SDK Envelope.");
// add a document to the envelope
Document doc = new Document();
String base64Doc = Base64.encodeToString(fileBytes, false);
//String base64Doc = Base64.encodeToString(str.getBytes("UTF-8"), false))
doc.setDocumentBase64(base64Doc);
doc.setName("TestFile.pdf");
doc.setDocumentId("1");
List<Document> docs = new ArrayList<Document>();
docs.add(doc);
templateDef.setDocuments(docs);
// Add a recipient to sign the document
Signer signer = new Signer();
signer.setRoleName("Signer1");
signer.setRecipientId("1");
// Create a SignHere tab somewhere on the document for the signer to
// sign
SignHere signHere = new SignHere();
signHere.setDocumentId("1");
signHere.setPageNumber("1");
signHere.setRecipientId("1");
signHere.setXPosition("100");
signHere.setYPosition("100");
signHere.setScaleValue("0.5");
List<SignHere> signHereTabs = new ArrayList<SignHere>();
signHereTabs.add(signHere);
Tabs tabs = new Tabs();
tabs.setSignHereTabs(signHereTabs);
signer.setTabs(tabs);
templateDef.setRecipients(new Recipients());
templateDef.getRecipients().setSigners(new ArrayList<Signer>());
templateDef.getRecipients().getSigners().add(signer);
EnvelopeTemplateDefinition envTemplateDef = new EnvelopeTemplateDefinition();
envTemplateDef.setName("myTemplate");
templateDef.setEnvelopeTemplateDefinition(envTemplateDef);
ApiClient apiClient = new ApiClient(BaseUrl);
//String currentDir = System.getProperty("user.dir");
try {
// IMPORTANT NOTE:
// the first time you ask for a JWT access token, you should grant access by making the following call
// get DocuSign OAuth authorization url:
//String oauthLoginUrl = apiClient.getJWTUri(IntegratorKey, RedirectURI, OAuthBaseUrl);
// open DocuSign OAuth authorization url in the browser, login and grant access
//Desktop.getDesktop().browse(URI.create(oauthLoginUrl));
// END OF NOTE
byte[] privateKeyBytes = null;
try {
privateKeyBytes = Files.readAllBytes(Paths.get(privateKeyFullPath));
} catch (IOException ioExcp) {
//Assert.assertEquals(null, ioExcp);
ioExcp.printStackTrace();
}
if (privateKeyBytes == null) return null;
java.util.List<String> scopes = new ArrayList<String>();
scopes.add(OAuth.Scope_SIGNATURE);
OAuth.OAuthToken oAuthToken = apiClient.requestJWTUserToken(IntegratorKey, UserId, scopes, privateKeyBytes, 3600);
//Assert.assertNotSame(null, oAuthToken);
// now that the API client has an OAuth token, let's use it in all
// DocuSign APIs
apiClient.setAccessToken(oAuthToken.getAccessToken(), oAuthToken.getExpiresIn());
UserInfo userInfo = apiClient.getUserInfo(oAuthToken.getAccessToken());
/*Assert.assertNotSame(null, userInfo);
Assert.assertNotNull(userInfo.getAccounts());
Assert.assertTrue(userInfo.getAccounts().size() > 0);
*/
System.out.println("userInfo.getAccounts().size()-->"+userInfo.getAccounts().size());
System.out.println("UserInfo: " + userInfo);
// parse first account's baseUrl
// below code required for production, no effect in demo (same
// domain)
apiClient.setBasePath(userInfo.getAccounts().get(0).getBaseUri() + "/restapi");
Configuration.setDefaultApiClient(apiClient);
String accountId = userInfo.getAccounts().get(0).getAccountId();
TemplatesApi templatesApi = new TemplatesApi();
templateSummary = templatesApi.createTemplate(accountId, templateDef);
//Assert.assertNotNull(templateSummary);
//Assert.assertNotNull(templateSummary.getTemplateId());
System.out.println("templateSummary-->"+templateSummary);
System.out.println("templateSummary.getTemplateId()-->"+templateSummary.getTemplateId());
//System.out.println("TemplateSummary: " + templateSummary);
} catch (ApiException ex) {
System.out.println("Exception: 123");
ex.printStackTrace();
} catch (Exception e) {
//System.out.println("Exception: " + e.getLocalizedMessage());
System.out.println("Exception: 234");
e.printStackTrace();
}
return templateSummary;
}
}
I feel like I am facing missing runtime jar files.
I run a custom WebSocketServlet for Jetty, which sends short text push notifications (for an async mobile and desktop word game) to many platforms (Facebook, Vk.com, Mail.ru, Ok.ru also Firebase and Amazon messaging) using a Jetty HttpClient instance:
public class MyServlet extends WebSocketServlet {
private final SslContextFactory mSslFactory = new SslContextFactory();
private final HttpClient mHttpClient = new HttpClient(mSslFactory);
#Override
public void init() throws ServletException {
super.init();
try {
mHttpClient.start();
} catch (Exception ex) {
throw new ServletException(ex);
}
mFcm = new Fcm(mHttpClient); // Firebase
mAdm = new Adm(mHttpClient); // Amazon
mApns = new Apns(mHttpClient); // Apple
mFacebook = new Facebook(mHttpClient);
mMailru = new Mailru(mHttpClient);
mOk = new Ok(mHttpClient);
mVk = new Vk(mHttpClient);
}
This has worked very good for the past year, but since I have recently upgraded my WAR-file to use Jetty 9.4.14.v20181114 the trouble has begun -
public class Facebook {
private final static String APP_ID = "XXXXX";
private final static String APP_SECRET = "XXXXX";
private final static String MESSAGE_URL = "https://graph.facebook.com/%s/notifications?" +
// the app access token is: "app id | app secret"
"access_token=%s%%7C%s" +
"&template=%s";
private final HttpClient mHttpClient;
public Facebook(HttpClient httpClient) {
mHttpClient = httpClient;
}
private final BufferingResponseListener mMessageListener = new BufferingResponseListener() {
#Override
public void onComplete(Result result) {
if (!result.isSucceeded()) {
LOG.warn("facebook failure: {}", result.getFailure());
return;
}
try {
// THE jsonStr SUDDENLY CONTAINS PREVIOUS CONTENT!
String jsonStr = getContentAsString(StandardCharsets.UTF_8);
LOG.info("facebook success: {}", jsonStr);
} catch (Exception ex) {
LOG.warn("facebook exception: ", ex);
}
}
};
public void postMessage(int uid, String sid, String body) {
String url = String.format(MESSAGE_URL, sid, APP_ID, APP_SECRET, UrlEncoded.encodeString(body));
mHttpClient.POST(url).send(mMessageListener);
}
}
Suddenly the getContentAsString method called for successful HttpClient invocations started to deliver the strings, which were fetched previously - prepended to the the actual result string.
What could it be please, is it some changed BufferingResponseListener behaviour or maybe some non-obvious Java quirk?
BufferingResponseListener was never intended to be reusable across requests.
Just allocate a new BufferingResponseListener for every request/response.
So I'm working on a basic Twitch Bot for my channel and the code is as follows:
Config.java
import java.io.IOException;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
public class Config {
private static final String OAUTH = "MYOAUTHHERE";
private static final String ADRESS = "irc.chat.twitch.tv.";
private static final int PORT = 6667;
private static final String channelName = "#MYCHANNELNAMEHERE";
public static void main(String[] args) throws NickAlreadyInUseException, IOException, IrcException {
TwitchBot bot = new TwitchBot();
bot.setVerbose(true);
bot.connect(ADRESS, PORT, OAUTH);
// bot.onMessage(channelName, "Bot", channelName, channelName, channelName);
System.out.println("Connected!");
bot.joinChannel(channelName);
System.out.println("Successfully joined channel!");
bot.sendMessage(channelName, "Hello, I am a bot");
}
}
TwitchBot.java
import org.jibble.pircbot.*;
public class TwitchBot extends PircBot {
private static final String channelName = "#MYCHANNELNAME";
private final String botName = "THEBOTNAME";
public TwitchBot() {
this.setName(botName);
this.setLogin(botName);
}
public String getchannelName() {
return channelName;
}
#Override
public void onMessage(String channel, String sender, String login, String hostname, String message) {
if (message.equalsIgnoreCase("time")) {
String time = new java.util.Date().toString();
sendMessage(channel, sender + ": The time is now " + time);
}
}
}
The console displays "Connected!" and "Successfully joined channel" however the bot is unresponsive, and is not in the channel I specified. It also does not print "Hello I am a bot" in the chat.
There are few things to consider about Twitch.
Your email must be validated. Settings -> Profile -> Profile Settings
Channel names must be entered as lowercase.
Nickname are useless, twitch are using your profile nickname.
Twitch uses IRCv3 Client Capability Negotiation aka CAP, which means you should be use it as well.
You should only try enter existing channels, otherwise the server will ignore your JOIN channel.
Twitch, allow themselves the opportunity to change your nickname while you logged in, which means, that the expected nick results, provided by TwitchBot class, can, and probably be incorrect if you supply any name different from your logged in profile nickname.
Twitch IRC Capabilities, can be found Here, here are few..
membership: JOIN, MODE, NAMES, PART
tags: PRIVMSG, etc'
You should add those CAP, first thing you are logged in.
Important Notice: PIRCBot, doesn't look to support twitch PRIVMSG format, which means onMessage callback, will not be called. which leaves you to handle the parsing of received messages, through handleLine general callback.
Code as been updated to apply to above changes, and you should set the final variables in order it to work.
TwitchBot.java
import org.jibble.pircbot.*;
public class TwitchBot extends PircBot {
private final String requestedNick;
private String realNick;
private String realServer;
public TwitchBot(String nick) {
this.requestedNick = nick;
setName(this.requestedNick);
setLogin(this.requestedNick);
}
#Override
protected void onConnect() {
super.onConnect();
System.out.println("Connected!");
// Sending special capabilities.
sendRawLine("CAP REQ :twitch.tv/membership");
sendRawLine("CAP REQ :twitch.tv/commands");
sendRawLine("CAP REQ :twitch.tv/tags");
}
#Override
protected void handleLine(String line) {
super.handleLine(line);
if (line.startsWith(":")) {
String[] recvLines = line.split(" ");
// First message is 001, extract logged in information.
if (recvLines[1].equals("001")) {
this.realServer = recvLines[0].substring(1);
this.realNick = recvLines[2];
System.out.println("realServer: " + this.realServer);
System.out.println("realNick: " + this.realNick);
}
}
}
#Override
protected void onJoin(String channel, String sender, String login, String hostname) {
super.onJoin(channel, sender, login, hostname);
if (sender.equals(this.realNick)){
System.out.println("Successfully joined: " + channel);
}
}
#Override
protected void onMessage(String channel, String sender, String login, String hostname, String message) {
if (message.equalsIgnoreCase("time")) {
String time = new java.util.Date().toString();
sendMessage(channel, sender + ": The time is now " + time);
}
}
}
goFile.java
import java.io.IOException;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
public class goFile {
private static final String OAUTH = "MYOAUTHHERE";
private static final String ADDRESS = "irc.twitch.tv.";
private static final int PORT = 6667;
private static final String Nick = "MYNICKHERE";
private static final String Channel = "#MYCHANNELHERE";
public static void main(String[] args) throws NickAlreadyInUseException, IOException, IrcException {
TwitchBot bot = new TwitchBot(Nick);
bot.setVerbose(true);
bot.connect(ADDRESS, PORT, OAUTH);
bot.joinChannel(Channel);
bot.sendMessage(Channel, "Hello, I am a bot");
}
}
I want to generate a SAS token for access to my blob container where are some of my media files.
So I created a class SharedAccessSignature.java with this code:
public class SharedAccessSignature
{
private final String signature;
private final String signedPermission;
private final String signedStart;
private final String signedExpiry;
private final String signedIdentifier;
private final String signedIp;
private final String signedProtocol;
private final String signedVersion;
private final String signedResource;
private SharedAccessSignature(SasBuilder builder)
{
signedPermission = formatAsUrlParameter("sp", builder.signedPermission);
signedStart = formatAsUrlParameter("st", builder.signedStart);
signedExpiry = formatAsUrlParameter("se", builder.signedExpiry);
signedIdentifier = formatAsUrlParameter("si", builder.signedIdentifier);
signedIp = formatAsUrlParameter("sip", builder.signedIp);
signedProtocol = formatAsUrlParameter("spr", builder.signedProtocol);
signedVersion = formatAsUrlParameter("sv", builder.signedVersion);
signedResource = formatAsUrlParameter("sr", builder.signedResource);
signature = "sig=" + new SasBuilder().encodeUtf8(builder.signature);
}
private String formatAsUrlParameter(String parameterKey, String parameterValue)
{
if (StringUtils.isNotBlank(parameterValue))
{
return parameterKey + "=" + parameterValue + "&";
}
return "";
}
#Override
public String toString()
{
return new StringBuilder()
.append(signedVersion)
.append(signedResource)
.append(signedStart)
.append(signedExpiry)
.append(signedPermission)
.append(signedIp)
.append(signedProtocol)
.append(signedIdentifier)
.append(signature)
.toString();
}
public static class SasBuilder
{
private String signature = "";
private String signedPermission = "";
private String signedStart = "";
private String signedExpiry = "";
private String canonicalizedResource = "";
private String signedIdentifier = "";
private String signedIp = "";
private String signedProtocol = "";
private String signedVersion = "";
private String signedResource = "";
public SasBuilder signedVersion(String signedVersion)
{
this.signedVersion = signedVersion;
return this;
}
public SasBuilder signedPermission(String signedPermission)
{
this.signedPermission = signedPermission;
return this;
}
public SasBuilder canonicalizedResource(String canonicalizedResource)
{
this.canonicalizedResource = canonicalizedResource;
return this;
}
public SasBuilder signedIp(String signedIp)
{
this.signedIp = signedIp;
return this;
}
public SasBuilder signedProtocol(String signedProtocol)
{
this.signedProtocol = signedProtocol;
return this;
}
public SasBuilder signedIdentifier(String signedIdentifier)
{
this.signedIdentifier = signedIdentifier;
return this;
}
public SasBuilder signedExpiry(String signedExpiry)
{
this.signedExpiry = signedExpiry;
return this;
}
public SasBuilder signedStart(String signedStart)
{
this.signedStart = signedStart;
return this;
}
public SasBuilder signedResource(String signedResource)
{
this.signedResource = signedResource;
return this;
}
public SharedAccessSignature build()
{
String toBeAsEnvironmentVariable_securityKey = "....";
signature = generateSasSignature(toBeAsEnvironmentVariable_securityKey, stringToSign());
checkPreconditions();
return new SharedAccessSignature(this);
}
private String generateSasSignature(String key, String input)
{
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
Encoder encoder = Base64.getEncoder();
Mac sha256_HMAC = null;
String hash = null;
try
{
sha256_HMAC = Mac.getInstance("HmacSHA256");
sha256_HMAC.init(secret_key);
hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
}
catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e)
{
e.printStackTrace();
}
return hash;
}
private String stringToSign()
{
StringBuilder strToSign = new StringBuilder();
strToSign.append(signedPermission).append("\n");
strToSign.append(signedStart).append("\n");
strToSign.append(signedExpiry).append("\n");
strToSign.append(canonicalizedResource).append("\n");
strToSign.append(signedIdentifier).append("\n");
strToSign.append(signedIp).append("\n");
strToSign.append(signedProtocol).append("\n");
strToSign.append(signedVersion).append("\n");
strToSign.append("").append("\n");
strToSign.append("").append("\n");
strToSign.append("").append("\n");
strToSign.append("").append("\n");
strToSign.append("");
return strToSign.toString();
}
private void checkPreconditions()
{
if (StringUtils.isBlank(signedVersion) || StringUtils.isBlank(signedResource) || StringUtils.isBlank(signedPermission) || StringUtils.isBlank(signedExpiry) || StringUtils.isBlank(signature))
{
throw new IllegalStateException("SAS Builder: SignedVersion, signedResource, SignedPermission, SignedExpiry, Signature must be set.");
}
}
private String encodeUtf8(String textToBeEncoded)
{
try
{
return URLEncoder.encode(textToBeEncoded, "UTF-8");
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return textToBeEncoded;
}
}
}
And then I try to generate a SAS token like this:
SharedAccessSignature s = new SharedAccessSignature.SasBuilder()
.signedPermission("rwd")
.signedStart("2018-01-31T10:48:41Z")
.signedExpiry("2018-04-06T18:48:41Z")
.signedVersion("2015-04-05")
.signedResource("b")
.canonicalizedResource("/blob/myaccount")
.signedProtocol("https")
.build();
outcome:
sv=2015-04-05&sr=b&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D
GET request:
https://account.blob.core.cloudapi.de/container/filename.mp4?sv=2015-04-05&sr=b&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D
But as I am sending that request with this generated token there commes this Error from azure:
<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rwd 2018-01-31T10:48:41Z
2018-04-06T18:48:41Z /blob/globalweb/..... https 2015-04-05
</AuthenticationErrorDetail>
</Error>
EDIT:
I am desperate... I donĀ“t understand it... What is wrong on this "string-to-sign"? Why the "Signature did not match"?
--------
rwd\n
2018-01-31T10:48:41Z\n
2018-04-06T18:48:41Z\n
/blob/globalweb/videos-martindale\n
\n
\n
https\n
2015-04-05\n
\n
\n
\n
\n
-------
//link: https://globalweb.blob.core.cloudapi.de/videos-martindale/somevideo.mp4?sv=2015-04-05&sr=c&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D
<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:644e47a6-001e-0050-3f20-abc0f0000000 Time:2018-02-21T14:31:10.9429817Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rwd 2018-01-31T10:48:41Z 2018-04-06T18:48:41Z /blob/globalweb/videos-martindale https 2015-04-05
</AuthenticationErrorDetail>
</Error>
The main problem is on you generateSasSignature method. It should decode the key from Base64. Like the following:
public static String generateSasSignature(String key, String input) {
SecretKeySpec secret_key = new SecretKeySpec(Base64.getDecoder().decode(key), "HmacSHA256");
Encoder encoder = Base64.getEncoder();
Mac sha256_HMAC = null;
String hash = null;
try {
sha256_HMAC = Mac.getInstance("HmacSHA256");
sha256_HMAC.init(secret_key);
hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
}
catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return hash;
}
Then, assuming you're interested in having access to the container called mycontainer, this is how you should do:
SharedAccessSignature s = new SharedAccessSignature.SasBuilder()
.signedPermission("rwd")
.signedStart("2018-01-31T10:48:41Z")
.signedExpiry("2018-04-06T18:48:41Z")
.signedVersion("2015-04-05")
.signedResource("c") // <<---- note here
.canonicalizedResource("/blob/globalweb/mycontainer") // No ending slash!
.signedProtocol("https")
.build();
However, if you want to generate an Account SAS, the following code does the trick:
public static void main(String[] args) throws UnsupportedEncodingException {
String accountName = "globalweb";
String signedPermissions = "rl"; //read and list
String signedService = "b"; //blob
String signedResType = "sco"; //service, container, objects
String start = "2018-02-22T17:16:25Z";
String expiry = "2018-02-28T01:16:25Z";
String signedIp = "";
String protocol = "https";
String signedVersion = "2017-07-29";
String stringToSign =
accountName + "\n" +
signedPermissions + "\n" +
signedService + "\n" +
signedResType + "\n" +
start + "\n" +
expiry + "\n" +
signedIp + "\n" +
protocol + "\n" +
signedVersion + "\n";
//outputs SAS Token
System.out.println(
"?sv="+signedVersion +
"&ss="+signedService +
"&srt="+signedResType +
"&sp="+signedPermissions +
"&st="+start+
"&se="+expiry+
"&spr="+protocol+
"&sig="+
URLEncoder.encode(SasBuilder.generateSasSignature(MY_KEY_BASE64, stringToSign), "UTF-8"));
}
Got this same error which led me to this post:
403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
In my case I had an EncodeURI() on the already encoded uri.
Removing this also fixed the error.
Please try this if you are using 12.5. I was able to get this working with the following:
try {
//Authenticate
StorageSharedKeyCredential credential = new StorageSharedKeyCredential(this.getAzureAccountName(), this.getAzureAccountKey());
//Get the Blob Service Client
BlobServiceClient client = new BlobServiceClientBuilder()
.endpoint(this.getAzureEndPoint())
.credential(credential)
.buildClient();
//Get the blobContainerClient
BlobContainerClient blobContainerClient =
blobServiceClient.get().getBlobContainerClient(containerName);
BlockBlobClient blockBlobClient = blobContainerClient
.getBlobClient(bolbName)
.getBlockBlobClient();
//Setting Account Permission
AccountSasPermission permissions = new AccountSasPermission()
.setListPermission(true)
.setReadPermission(true);
//Following line is required if signature to be generated at container level
//AccountSasResourceType resourceTypes = new AccountSasResourceType().setContainer(true);
//In case you want to generate the signature at the object level use
AccountSasResourceType resourceTypes = new AccountSasResourceType().setObject(true);
AccountSasService services = new AccountSasService().setBlobAccess(true).setFileAccess(true);
//Valid for 2 days starting today
OffsetDateTime expiryTime = OffsetDateTime.now().plus(Duration.ofDays(2));
AccountSasSignatureValues sasValues =
new AccountSasSignatureValues(expiryTime, permissions, services, resourceTypes);
String sasToken = blobServiceClient.get().generateAccountSas(sasValues);
sasToken = blockBlobClient.getBlobUrl()+"?"+sasToken;
System.out.println("URL to get view the Blob in Browser "+sasToken);
} catch (Exception e) {
log.error("Error = {}",e.getMessage());
}
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