2

I have created a Named Credential within SF that stores the Authentication information for our AmazonS3 instance.

Here is the Named Credential Setup enter image description here

We have code that is working when the AmazonS3 credentials are stored directly within the VisualForce page, but, for obvious reasons, this is not ideal.

The idea is the VF page takes an input of images from a user and uploads them to AmazonS3, creating its own folder based on the UniqueID entered by the user.

How can I have the VisualForce page access the information from the Named Credential easily for a PUT request?

I have reviewed SalesForce documentation and believe I am just missing a small piece, but cannot figure out what that is. Any straightforward assistance is appreciated in this matter.

Here is my custom Apex Code:

public class AmazonS3{
    public string AmazonS3Request { get; set; }
    public static void AmazonS3Request() {
        HttpRequest request = new HttpRequest();
        request.setMethod('PUT');
        request.setEndpoint('callout:AWSS3');
        HttpResponse response = new Http().send(request);
        System.debug(response.getStatusCode());
        System.debug(response.getBody());
    }
}

Here's how I'm referencing it in the VF Page:

<apex:page controller="AmazonS3" standardStyleSheets="false" showHeader="false" sidebar="false">

Here is how I'm calling AmazonS3Request in my VF page

<input type="button" class="top-buffer" value="Submit All Images" onclick="{!AmazonS3Request} s3upload()"/>

I am getting this:

HTTP Header Authorization=Not Set 
and a 403 Error.

Here is the full VF page - As you can see, the bucket is configured at the beginning of the Script.

<apex:page controller="AmazonS3" standardStyleSheets="false" showHeader="false" sidebar="false">
<apex:stylesheet value="{!$Resource.styleForImageUpload}"/>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"/>
</head>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.839.0.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
    
    
//Bucket Configurations
var bucketName = "salesforce-simplyhome-images";
var bucketRegion = "us-east-1";

            var s3 = new AWS.S3({
                apiVersion: '2006-03-01',
                params: {Bucket: bucketName}
        });
        
function addRow(tableID) {
  var table = document.getElementById(tableID);
  var rowCount = table.rows.length;
  var row = table.insertRow(rowCount);
  var colCount = table.rows[0].cells.length;
  for(var i=0; i<colCount; i++) {
    var newRow = row.insertCell(i);
    newRow.innerHTML = table.rows[0].cells[i].innerHTML;
    newRow.childNodes[0].value = "";
  }
}
function deleteRow(row) {
  var table = document.getElementById("data");
  var rowCount = table.rows.length;
  if (rowCount > 1) {
    var rowIndex = row.parentNode.parentNode.rowIndex;
    document.getElementById("data").deleteRow(rowIndex);
  }
  else {
    alert("Please specify at least one value.");
  }
}


async function s3upload() {
  var uniqueId,
  element = document.getElementById("uniqueId").value;
  if (element != "") {
      uniqueId = element;
  }
  else {
       alert("Please specify a Unique ID. This has been emailed to you.");
       return;
  }
  var updatedFileName = document.getElementsByClassName("updatedFileName");  
  var files = document.getElementsByClassName("uploadFile");
  function toArray(arr) {
    return [].slice.call(arr);
  }
  var files_arr = toArray(files).filter(v => v.files[0] != null);
  var actual_files = new Array();
  var errors_arr = new Array();
  files_arr.forEach(function callback(file_obj,i){
    actual_files[i] = file_obj.files[0]
  })   
  var updated_file_names_arr = toArray(updatedFileName);
  var image_count = actual_files.length;
  var final_image_index = image_count-1;
  var success_count = 0;
  var error_count = 0;
  var final_message = "";
  for ( var i = 0; i <= final_image_index; i++ ) {
    var file = actual_files[i];
    var fileName = updatedFileName[i].value; 
    var filePath = uniqueId + '/' + fileName + '.jpg';
    var fileUrl = 'https://' + bucketRegion + '.amazonaws.com/' + uniqueId + '/' +  filePath;
    var params = { Body: file, Key: filePath };
   try { 
      var result = await s3.upload(params).promise()
      console.log(result)
      var upload_success = true
    } catch (err) {
      console.log(err)
      var upload_success = false
    };
    if (upload_success == true) {
      success_count++;
    } else {
      error_count++;
      errors_arr.push(fileName);
    };
    var total_count = success_count + error_count;
    var uploaded_percent = 100 * total_count / image_count;
    document.getElementById("progress").value = uploaded_percent;
    if (uploaded_percent == 100) {
      var final_message = success_count + " images uploaded successfully. ";
      if (error_count != 0) {
          final_message += "Errors encountered uploading: ";
          final_message += errors_arr;
      };
      setTimeout(function() {
        alert(final_message);
      },5);
    };
  };
};
  
</script>
<br></br><br></br><br></br>
<div id="main">
  <h1>Please Upload Home Images</h1>
  <table id="header" class="data-table data-table-horizontal data-table-highlight">
    <tbody>
      <tr>
        <td> Please Enter Unique ID (Emailed to you)</td>
        <td> <input type="text" id="uniqueId" value="" placeholder="Enter Unique ID" required="true"/></td>
        <td></td>
     </tr>
    </tbody>
  </table>
  <table id="data" class="data-table data-table-horizontal data-table-highlight">
    <tbody>
      <tr>
        <td><input type="file" class="uploadFile" value="false"/></td>
        <td><input type="text" placeholder="Image of what?" class="updatedFileName"/></td>
 <td><a type="button" value="Delete" onclick="deleteRow(this)"><i class="fa fa-trash-o fa-fw"></i></a></td>      
 </tr>
      <tr>
        <td><input type="file" class="uploadFile" value="false"/></td>
        <td><input type="text" placeholder="Image of what?" class="updatedFileName"/></td>
 <td><a type="button" value="Delete" onclick="deleteRow(this)"><i class="fa fa-trash-o fa-fw"></i></a></td>      </tr>
      <tr>
        <td><input type="file" class="uploadFile" value="false"/></td>
        <td><input type="text" placeholder="Image of what?" class="updatedFileName"/></td>
 <td><a type="button" value="Delete" onclick="deleteRow(this)"><i class="fa fa-trash-o fa-fw"></i></a></td>      </tr>
      <tr>
        <td><input type="file" class="uploadFile" value="false"/></td>
        <td><input type="text" placeholder="Image of what?" class="updatedFileName"/></td>
 <td><a type="button" value="Delete" onclick="deleteRow(this)"><i class="fa fa-trash-o fa-fw"></i></a></td>      </tr>
      </tbody>
  </table>
  <table>    
  <tr>
  <div class="pull-right">
    <input type="button" value="Add" class="top-buffer" onclick="addRow('data')" />
  </div>
  </tr>
  <tr>
      <div class="pull-center">
<input type="button" class="top-buffer" value="Submit All Images" onclick="{!AmazonS3Request} s3upload()"/>
    </div>
  </tr>
  <tr>
    <progress id="progress" max='100' value='0'></progress>
   
  </tr>
  </table>
  </div>
  </apex:page>

I've been getting redirected here, BUT THIS IS NOT HELPFUL. My previous question was closed, stating this was a solution, but it does not address the issue I'm having.

Thank you for any assistance here.

25
  • 1
    @ScottPelak - This has been added to the question above Mar 11, 2021 at 19:09
  • 1
    Have you tried to change Authentication Protocol to Password Authentication? Instead AWS Signature Version 4. Mar 11, 2021 at 19:35
  • 4
    I also noticed that the setEndpoint is pointing to the root of S3, not any bucket, plus it is not sending anything on the body at the code provided. Mar 11, 2021 at 20:57
  • 2
    In the backend, Named Credentials are a safe place to store secrets + it sets some headers + endpoint for you automatically. Have you tried constructing your HttpRequest and manually set endpoint + headers to verify you are connecting successfully? Then you can work backwards to make sure you set up your Named Credential properly. As noted above, your HttpRequest endpoint resolves to just https://s3.us-east.1.amazonaws.com/. Don't you need a path to your bucket? Mar 12, 2021 at 14:39
  • 2
    Try getting some files first (to make sure it's working) , because for PUT you need to set Body
    – ytiq
    Mar 16, 2021 at 5:54

0

You must log in to answer this question.

Browse other questions tagged .