I am trying to access s3 bucket. I am able to do so using my local machine(i.e. from my local machine to S3 bucket), but getting access denied issue while trying to access it from EC2 instance running tomcat 8 and java 8.
Also when i upload the file the permissions are set for root user and if I keep my bucket as public and upload the file from EC2 the permissions are not set for the root user.
public class AmazonS3UtilService {
public static final String NAME = "amazonS3Util";
private static String S3_SECRET = "S3_SECRET";
private static String S3_ID = "S3_ID";
private static String BUCKET_NAME = "S3_BUCKET";
private static final String SUFFIX = "/";
private static final String DEFAULT_FOLDER_PATH = "PHR/Reports/";
#Autowired
protected Environment props;
private AWSCredentials awsCredentials = null;
private AmazonS3 s3Client = null;
private String bucketName = null;
private static final Logger log = Logger.getLogger(AmazonS3UtilService.class);
private void prepareAWSCredentials() {
if (awsCredentials == null) {
log.info("Preparing AWS Credentials");
awsCredentials = new AWSCredentials() {
#SuppressWarnings("unused")
Map<String, String> env = System.getenv();
public String getAWSSecretKey() {
String S3_SECRET = System.getProperty(AmazonS3UtilService.S3_SECRET);
if (S3_SECRET == null) {
S3_SECRET = System.getenv(AmazonS3UtilService.S3_SECRET);
if (S3_SECRET == null) {
S3_SECRET = props.getProperty(AmazonS3UtilService.S3_SECRET);
}
}
log.info("S3_SECRET ---->" + S3_SECRET);
return S3_SECRET;
}
public String getAWSAccessKeyId() {
String S3_ID = System.getProperty(AmazonS3UtilService.S3_ID);
if (S3_ID == null) {
S3_ID = System.getenv(AmazonS3UtilService.S3_ID);
if (S3_ID == null) {
S3_ID = props.getProperty(AmazonS3UtilService.S3_ID);
}
}
log.info("S3_ID ---->" + S3_ID);
return S3_ID;
}
};
}
}
private void prepareAmazonS3Client() {
if (s3Client == null) {
log.info("Preparing S3 Client");
ClientConfiguration clientCfg = new ClientConfiguration();
clientCfg.setProtocol(Protocol.HTTP);
s3Client = new AmazonS3Client(awsCredentials, clientCfg);
Region region = Region.getRegion(Regions.fromName(props.getProperty("s3client.region")));
log.info("Region ----->" + props.getProperty("s3client.region"));
s3Client.setRegion(region);
}
}
private void prepareBucketName() {
bucketName = System.getenv(AmazonS3UtilService.BUCKET_NAME);
log.info("bucketName ------>" + bucketName);
}
}
private void prepare() {
try {
awsCredentials = null;
prepareAWSCredentials();
prepareAmazonS3Client();
prepareBucketName();
} catch (AmazonServiceException ase) {
log.error("Caught an AmazonServiceException, which means your request made it "
+ "to Amazon S3, but was rejected with an error response for some reason.");
log.error("Error Message: " + ase.getMessage() + " HTTP Status Code: " + ase.getStatusCode()
+ " AWS Error Code: " + ase.getErrorCode() + " Error Type: " + ase.getErrorType()
+ " Request ID: " + ase.getRequestId());
new AmazonS3ClientException(ase, ase.getMessage());
} catch (AmazonClientException ace) {
log.error(ace);
new AmazonS3ClientException(ace, ace.getMessage());
}
}
#SuppressWarnings("unused")
public String uploadDocument(UploadDocumentDetailDTO uploadDocumentDetail) {
prepare();
String tempFileName = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss").format(new Date());
String fileURL = null;
try {
File uploadFileContent = readBase64File(uploadDocumentDetail.getFileContent(), tempFileName);
uploadDocumentDetail.setContentType(FileContentTypeEnum.PDF);
String uploadFileName = getUploadFileName(uploadDocumentDetail);
PutObjectRequest request = new PutObjectRequest(bucketName, uploadFileName, uploadFileContent);
request.putCustomRequestHeader("Content-Type", "application/pdf");
request.putCustomRequestHeader("Content-Disposition", "inline");
PutObjectResult putObjectResult = s3Client.putObject(request);
URL url = generatePresignedUrlRequest(uploadFileName);
fileURL = url.toString();
} catch (Exception e) {
log.info(LoggerException.printException(e));
fileURL = "";
}
return fileURL;
}
public URL generatePresignedUrlRequest(String fileURL) {
log.info("Inside generatePresignedUrlRequest");
java.util.Date expiration = new java.util.Date();
long msec = expiration.getTime();
msec += 1000 * 60 * 60; // 1 hour.
expiration.setTime(msec);
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, fileURL);
generatePresignedUrlRequest.setMethod(HttpMethod.GET); // Default.
generatePresignedUrlRequest.setExpiration(expiration);
URL s = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
log.info("Url --->" + s);
return s;
}
private String getUploadFileName(UploadDocumentDetailDTO uploadDocumentDetail) {
StringBuffer uploadFileName = new StringBuffer();
uploadFileName.append(DEFAULT_FOLDER_PATH);
if (uploadDocumentDetail.getBeneficiaryId() != null)
uploadFileName.append(uploadDocumentDetail.getBeneficiaryId() + SUFFIX);
if (uploadDocumentDetail.getDocumentType() != null)
uploadFileName.append(uploadDocumentDetail.getDocumentType().getName() + SUFFIX);
// Check and create Folder
validateAndCreateFolder(uploadFileName.toString());
if (uploadDocumentDetail.getAssesmentId() != null)
uploadFileName.append(
uploadDocumentDetail.getAssesmentId() + "." + uploadDocumentDetail.getContentType().getName());
else
uploadFileName.append(
uploadDocumentDetail.getDefaultFileName() + "." + uploadDocumentDetail.getContentType().getName());
return uploadFileName.toString();
}
private static File readBase64File(String content, String fileName) throws Exception {
File file = File.createTempFile(fileName, ".tmp");
file.deleteOnExit();
FileOutputStream fileOuputStream = new FileOutputStream(file);
fileOuputStream.write(Base64.decodeBase64(content));
fileOuputStream.close();
return file;
}
public void validateAndCreateFolder(String folderName) {
List<S3ObjectSummary> fileList = null;
try {
fileList = s3Client.listObjects(bucketName, folderName).getObjectSummaries();
} catch (AmazonServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AmazonClientException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (fileList == null || fileList.isEmpty()) {
// create meta-data for your folder and set content-length to 0
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(0);
// create empty content
InputStream emptyContent = new ByteArrayInputStream(new byte[0]);
// create a PutObjectRequest passing the folder name suffixed by /
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, folderName, emptyContent, metadata);
// send request to S3 to create folder
s3Client.putObject(putObjectRequest);
}
}
/**
* This method first deletes all the files in given folder and than the
* folder itself
*/
}
Following is the exception while access S3 from EC2 instance.
INFO com.medscheme.common.util.AmazonS3UtilService - com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 926E1213366626B9), S3 Extended Request ID: zQbb4JCalYExHZtDSv0GmWxoHrQZJUV3M+jlUiaVJY/sDxW/qoNFC8hizfangVCjweWZtOqC7/A=
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1275)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:873)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:576)
at com.amazonaws.http.AmazonHttpClient.doExecute(AmazonHttpClient.java:362)
at com.amazonaws.http.AmazonHttpClient.executeWithTimer(AmazonHttpClient.java:328)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:307)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3649)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3602)
at com.amazonaws.services.s3.AmazonS3Client.listObjects(AmazonS3Client.java:679)
at com.amazonaws.services.s3.AmazonS3Client.listObjects(AmazonS3Client.java:664)
at com.medscheme.common.util.AmazonS3UtilService.validateAndCreateFolder(AmazonS3UtilService.java:222)
at com.medscheme.common.util.AmazonS3UtilService.getUploadFileName(AmazonS3UtilService.java:200)
at com.medscheme.common.util.AmazonS3UtilService.uploadDocument(AmazonS3UtilService.java:166)
at com.medscheme.service.impl.ReportsServiceImpl.getReport(ReportsServiceImpl.java:133)
at com.medscheme.service.impl.ReportsServiceImpl.getReport(ReportsServiceImpl.java:1)
at com.medscheme.controller.ReportsController.getWellnessReportDetails(ReportsController.java:69)
I was able to resolve the issue by using BasicAWSCredentials class instead of AWSCredentials while creating the amazon client.
The problem was only with EC2 instance.
Does anybody know what was going wrong on EC2.
Related
I am making an app which stores its SQLite Database backup on GDrive. I succeeded in signing in and uploading the file in the drive but failed to restore it. Following is the code.
I use SQLiteDatabase to store the fileID so that when it is required while updating and restoring, it can be used. I am looking for a method which will make use of FileID to restore.
Error occurs at file.getDownloadUrl() and file.getContent().
class DriveClassHelper
{
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private static Drive mDriveService;
private String FileID = null;
private static String filePath = "/data/data/com.example.gdrivebackup/databases/Data.db";
DriveClassHelper(Drive mDriveService)
{
DriveClassHelper.mDriveService = mDriveService;
}
// ---------------------------------- TO BackUp on Drive -------------------------------------------
public Task<String> createFile()
{
return Tasks.call(mExecutor, () ->
{
File fileMetaData = new File();
fileMetaData.setName("Backup");
java.io.File file = new java.io.File(filePath);
String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("application/x-sqlite-3");
FileContent mediaContent = new FileContent(mimeType, file);
File myFile = null;
FileID = getFileIDFromDatabase();
try {
if (FileID != null) {
Log.i("CALLED : ", FileID);
//mDriveService.files().delete().execute();
myFile = mDriveService.files().update(FileID, fileMetaData, mediaContent).execute();
} else {
myFile = mDriveService.files().create(fileMetaData, mediaContent).execute();
MainActivity.demoSQLite.insertData(myFile.getId());
}
} catch (Exception e) {
e.printStackTrace();
}
if (myFile == null) {
throw new IOException("Null Result when requesting file creation");
}
Log.i("ID:", myFile.getId());
return myFile.getId();
}
);
}
// -------------------------------------------------------------------------------------------------
// ---------------------------------- TO get File ID -------------------------------------------
private static String getFileIDFromDatabase()
{
String FileIDFromMethod = null;
Cursor result = MainActivity.demoSQLite.getData();
if (result.getCount() == 0) {
Log.i("CURSOR :", "NO ENTRY");
return null;
} else {
while (result.moveToNext()) {
FileIDFromMethod = result.getString(0);
}
return FileIDFromMethod;
}
}
// -------------------------------------------------------------------------------------------------
// ---------------------------------- TO Restore -------------------------------------------
public static class Restore extends AsyncTask<Void, Void, String>
{
#Override
protected String doInBackground(Void... params) {
String fileId = null;
try
{
fileId = getFileIDFromDatabase();
if (fileId != null)
{
File file = mDriveService.files().get(fileId).execute();
downloadFile(file);
}
else
{
return null;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return fileId;
}
private void downloadFile(File file)
{
InputStream mInput = null;
FileOutputStream mOutput = null;
if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0) //Error occurs at file.getDownloadUrl()
{
try
{
HttpResponse resp = mDriveService.getRequestFactory().buildGetRequest(new GenericUrl(file.getDownloadUrl())).execute();
mInput = resp.getContent();
String outFileName = "file://" + Environment.getDataDirectory().getPath() + filePath;
// Log.e("com.example.myapp", "getDatabasePath="+ getDatabasePath(""));
//Log.e("com.example.myapp", "outFileName="+outFileName);
// String outFileName = "../databases/" + "Quickpay.db";
mOutput = new FileOutputStream(outFileName);
byte[] mBuffer = new byte[1024];
int mLength;
while ((mLength = mInput.read(mBuffer)) > 0)
{
mOutput.write(mBuffer, 0, mLength);
}
mOutput.flush();
}
catch (IOException e)
{
// An error occurred.
e.printStackTrace();
// return null;
}
finally
{
try
{
//Close the streams
if (mOutput != null)
{
mOutput.close();
}
if (mInput != null)
{
mInput.close();
}
}
catch (IOException e)
{
Log.e("com.example.myapp", "failed to close databases");
}
}
}
else
{
// The file doesn't have any content stored on Drive.
// return null;
Log.e("com.example.myapp", "No content on Drive");
}
}
}
}
The Gradle file is like
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0')
{
exclude group: 'org.apache.httpcomponents'
}
implementation('com.google.api-client:google-api-client-android:1.26.0')
{
exclude group: 'org.apache.httpcomponents'
}
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
As far as i know Download URL is only avalibale in Google drive api v2 and not in V3.
Short lived download URL for the file. This field is only populated for files with content stored in Google Drive; it is not populated for Google Docs or shortcut files.
It was not very stable in my opinion as not all file types would return a download url.
Using Google Drive v3 you should download the file using a stream.
String fileId = "0BwwA4oUTeiV1UVNwOHItT0xfa2M";
OutputStream outputStream = new ByteArrayOutputStream();
driveService.files().get(fileId)
.executeMediaAndDownloadTo(outputStream);
This should work with the restore. Let me know if it doesnt and i will have a look its been a while since i have tried restore.
In this service class where can i write the file compression code and am saving the file as "Base64" format in database. The single file is uploaded in s3 bucket but when i upload the MultipartFile[] using postman in aws s3 bucket am getting the "413 Request Entity Too Large" error.How can i solve this error.
This is my service class
#Component
public class TeacherGalleryService {
#Autowired
TeacherGalleryRepository galleryRepo;
private AmazonS3 amazonS3;
#Value("${aws.access.key.id}")
private String accessKey;
#Value("${aws.access.key.secret}")
private String secretKey;
#Value("${aws.region}")
private String region;
#Value("${aws.s3.audio.bucket}")
private String s3Bucket;
#Value("${aws.endpointUrl}")
private String endpointUrl;
#SuppressWarnings("deprecation")
#PostConstruct
private void initializeAmazon() {
System.out.println(accessKey);
AWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);
this.amazonS3 = new AmazonS3Client(credentials);
}
public String uploadFile(MultipartFile file) {
String fileUrl = "";
try {
File myFile = convertMultiPartToFile(file);
String fileName = generateFileName(file);
fileUrl = endpointUrl + "/" + s3Bucket + "/" + fileName;
uploadFileTos3bucket(fileName, myFile);
myFile.delete();
} catch (Exception e) {
e.printStackTrace();
}
return fileUrl;
}
private File convertMultiPartToFile(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
return convFile;
}
private String generateFileName(MultipartFile multiPart) {
return multiPart.getOriginalFilename().replace(" ", "_");
}
private void uploadFileTos3bucket(String fileName, File file) {
amazonS3.putObject(new PutObjectRequest(s3Bucket, fileName, file)
.withCannedAcl(CannedAccessControlList.PublicRead));
}
public TeacherGallery storeFile(TeacherGallery teacherGallery, MultipartFile file) {
String fileNames = StringUtils.cleanPath(file.getOriginalFilename());
String fileUrls = endpointUrl + "/" + s3Bucket + "/" + fileNames;
byte[] images = null;
try {
images = Base64.encodeBase64(file.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
teacherGallery = new TeacherGallery(images, fileNames, fileUrls, teacherGallery.getTitle());
return galleryRepo.save(teacherGallery)
}
}
This does seem to be low size configured in Spring's servlet container. Take a look at Web properties for your Spring Boot:
You want to look into these properties
spring.servlet.multipart.max-file-size (default 1MB)
spring.servlet.multipart.max-request-size (default 10 MB)
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());
}
For some reason i can't figure out why it downloads the new applet every time even though i have the newest application on my computer already (that's what this downloader/checker does, to check the hash, and if its outdated, it re-downloads the newer version which is uploaded to web host)
My downloader class
public class Downloader {
private static final String HASH_URL = "/current";
private static final String DOWNLOAD_URL = ".jar";
private LoadingFrame loadingFrame;
public Downloader(LoadingFrame loadingFrame) {
this.loadingFrame = loadingFrame;
}
private String getLatestHash() {
loadingFrame.setLoadingText("Checking if client is up to date...");
try (InputStream in = new URL(HASH_URL).openStream()) {
return new String(IOUtils.toByteArray(in)).trim();
} catch (IOException e) {
loadingFrame.setLoadingText("Error loading client [ErrorCode: 7A]");
throw new RuntimeException("Error loading client");
}
}
public File downloadLatestPack() {
try {
File dir = new File(System.getProperty("user.home") + File.separator + "Project" + File.separator + "client");
if (!dir.exists()) {
dir.mkdirs();
}
loadingFrame.setLoadingText("Checking if client is up to date...");
String latestHash = getLatestHash();
File latest = new File(dir.getPath() + File.separator + latestHash + ".jar");
if (!latest.exists() || !com.google.common.io.Files.hash(latest, Hashing.sha1()).toString().equals(latestHash)) {
loadingFrame.setLoadingText("Doing some house keeping...");
for (File f : dir.listFiles()) {
if (f.getName().endsWith(".jar") && !f.getName().equals(latest.getName())) {
f.delete();
}
}
loadingFrame.setLoadingText("Downloading latest client...");
latest.createNewFile();
try (InputStream in = new URL(DOWNLOAD_URL).openStream()) {
Files.copy(in, latest.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
} else {
loadingFrame.setLoadingText("Client is up to date!");
}
return latest;
} catch (IOException e) {
loadingFrame.setLoadingText("Error loading client [ErrorCode: 6B]");
throw new RuntimeException("Error loading client");
}
}
}
I am using this gwt upload system here(http://code.google.com/p/gwtupload/). I am getting some problems with it.
Show to feed it with a path from the client
Get the path on the server where the file was saved
set a path on the server where the file is to be saved
This the servlet to handle the file upload
public class SampleUploadServlet extends UploadAction {
private static final long serialVersionUID = 1L;
Hashtable<String, String> receivedContentTypes = new Hashtable<String, String>();
/**
* Maintain a list with received files and their content types.
*/
Hashtable<String, File> receivedFiles = new Hashtable<String, File>();
/**
* Override executeAction to save the received files in a custom place
* and delete this items from session.
*/
#Override
public String executeAction(HttpServletRequest request, List<FileItem> sessionFiles) throws UploadActionException {
String response = "";
int cont = 0;
for (FileItem item : sessionFiles) {
if (false == item.isFormField()) {
cont ++;
try {
/// Create a new file based on the remote file name in the client
// String saveName = item.getName().replaceAll("[\\\\/><\\|\\s\"'{}()\\[\\]]+", "_");
// File file =new File("/tmp/" + saveName);
/// Create a temporary file placed in /tmp (only works in unix)
// File file = File.createTempFile("upload-", ".bin", new File("/tmp"));
/// Create a temporary file placed in the default system temp folder
File file = File.createTempFile("upload-", ".bin");
item.write(file);
/// Save a list with the received files
receivedFiles.put(item.getFieldName(), file);
receivedContentTypes.put(item.getFieldName(), item.getContentType());
/// Compose a xml message with the full file information which can be parsed in client side
response += "<file-" + cont + "-field>" + item.getFieldName() + "</file-" + cont + "-field>\n";
response += "<file-" + cont + "-name>" + item.getName() + "</file-" + cont + "-name>\n";
response += "<file-" + cont + "-size>" + item.getSize() + "</file-" + cont + "-size>\n";
response += "<file-" + cont + "-type>" + item.getContentType()+ "</file-" + cont + "type>\n";
} catch (Exception e) {
throw new UploadActionException(e);
}
}
}
/// Remove files from session because we have a copy of them
removeSessionFileItems(request);
/// Send information of the received files to the client.
return "<response>\n" + response + "</response>\n";
}
/**
* Get the content of an uploaded file.
*/
#Override
public void getUploadedFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fieldName = request.getParameter(PARAM_SHOW);
File f = receivedFiles.get(fieldName);
if (f != null) {
response.setContentType(receivedContentTypes.get(fieldName));
FileInputStream is = new FileInputStream(f);
copyFromInputStreamToOutputStream(is, response.getOutputStream());
} else {
renderXmlResponse(request, response, ERROR_ITEM_NOT_FOUND);
}
}
/**
* Remove a file when the user sends a delete request.
*/
#Override
public void removeItem(HttpServletRequest request, String fieldName) throws UploadActionException {
File file = receivedFiles.get(fieldName);
receivedFiles.remove(fieldName);
receivedContentTypes.remove(fieldName);
if (file != null) {
file.delete();
}
}
}
Thanks
Try with this:
public String executeAction(HttpServletRequest request, List<FileItem> sessionFiles) throws UploadActionException {
for (FileItem item : sessionFiles) {
if (false == item.isFormField()) {
String uploadedFileName = "";
try {
String uploadsDir = "/uploads";
File dirFile = new File(uploadsDir);
dirFile.mkdirs();
String filename = FilenameUtils.getName(item.getName()); // uploaded file filename
File file = new File(uploadsDir, filename);
item.write(file);
uploadedFileName = uploadsDir + "/" + filename;
} catch (Exception e) {
logger.error("ERROR UPLOADING FILE: " + uploadedFileName + ", Exception: " + e);
throw new UploadActionException(e.getMessage());
}
}
removeSessionFileItems(request);
}
return null;
}
Happy coding!
Regards.