Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Amazon s3 从Apex调用S3时AWS访问密钥无效_Amazon S3_Salesforce_Apex_Aws Sts - Fatal编程技术网

Amazon s3 从Apex调用S3时AWS访问密钥无效

Amazon s3 从Apex调用S3时AWS访问密钥无效,amazon-s3,salesforce,apex,aws-sts,Amazon S3,Salesforce,Apex,Aws Sts,我正在尝试使用从AssumeRole返回的凭据从Apex访问s3。但是,我收到以下错误: <Message>The AWS Access Key Id you provided does not exist in our records.</Message> <AWSAccessKeyId>ASIA********</AWSAccessKeyId> 您提供的AWS访问密钥Id在我们的记录中不存在。 亚洲******** 我能够使用从Assume

我正在尝试使用从AssumeRole返回的凭据从Apex访问s3。但是,我收到以下错误:

<Message>The AWS Access Key Id you provided does not exist in our records.</Message>
<AWSAccessKeyId>ASIA********</AWSAccessKeyId>
您提供的AWS访问密钥Id在我们的记录中不存在。
亚洲********
我能够使用从AssumeRole返回的凭据从CLI成功地调用此s3 bucket上的GetObject,因此我可以合理地确保我的bucket权限设置良好。我在Apex中有以下代码:

        Http http = new http();
        Profile p = [SELECT Id FROM Profile WHERE Profile.Name = 'S3 Test User' LIMIT 1];
        S3_Settings__c s3 = S3_Settings__c.getInstance(p.Id);
        String exp = String.valueOf(Cache.Session.get('expiration'));
        String sessionToken = String.valueOf(Cache.Session.get('token'));

        if(exp == null || exp == '' || (DateTime) JSON.deserialize('"' + exp + '"', DateTime.class) < System.now()) {
            requestSessionToken();
        }

        sessionToken = String.valueOf(Cache.Session.get('token'));
        DateTime expires = (DateTime) JSON.deserialize('"' + String.valueOf(Cache.Session.get('expiration')) + '"', DateTime.class);
        String accessKeyId =  String.valueOf(Cache.Session.get('accessKeyId'));
        String accessSecret = String.valueOf(Cache.Session.get('secret'));

        String bucketname = s3.Recording_Bucket__c;
        String host = 's3.amazonaws.com';  
        String formattedDateString = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');
        String method = 'GET';
        String filePath = 'https://' + bucketname + '.' + host + '/' + filename; 
        HttpRequest req = new HttpRequest();
        req.setMethod(method);
        req.setEndpoint(filePath);
        req.setHeader('Host', bucketname + '.' + host);
        req.setHeader('Connection', 'keep-alive');
        String stringToSign = 'GET\n\n' + 'x-amz-security-token=' + sessionToken + '&expiration=' + expires + '\n' + formattedDateString + '\n/' + '/' + bucketname + '/' + filename;
        System.debug('SIGN ' + stringToSign);
        String encodedStringToSign = EncodingUtil.urlEncode(stringToSign, 'UTF-8');
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(accessSecret));
        String signedKey  = EncodingUtil.base64Encode(mac);

        String authHeader = 'AWS' + ' ' + accessKeyId + ':' + signedKey;
        req.setHeader('Date', formattedDateString);
        //req.setHeader('x-amz-security-token', sessionToken); //AWS returns 'invalid signature' if this is set

        req.setHeader('Authorization',authHeader);

        HttpResponse resp = http.send(req);
Http=newhttp();
Profile p=[从Profile中选择Id,其中Profile.Name='S3测试用户'限制1];
S3\u设置\uuuu c S3=S3\u设置\uuuuu c.getInstance(p.Id);
String exp=String.valueOf(Cache.Session.get('expiration');
String sessionToken=String.valueOf(Cache.Session.get('token');
如果(exp==null | | exp==''| |(DateTime)JSON{
requestSessionToken();
}
sessionToken=String.valueOf(Cache.Session.get('token');
DateTime expires=(DateTime)JSON.deserialize(“”+String.valueOf(Cache.Session.get('expirement'))+”,DateTime.class);
String-accessKeyId=String.valueOf(Cache.Session.get('accessKeyId');
String accessSecret=String.valueOf(Cache.Session.get('secret');
字符串bucketname=s3.0\u Bucket\u\c;
字符串host='s3.amazonaws.com';
String formattedDateString=Datetime.now().formattgmt('EEE,dd-MMM-yyyy-HH:mm:ss z');
String方法='GET';
字符串文件路径='https://'+bucketname+'.+host+'/'+文件名;
HttpRequest req=新的HttpRequest();
要求设置方法(方法);
请求setEndpoint(文件路径);
请求setHeader('主机',bucketname+'。+主机);
请求setHeader('连接','保持活动');
字符串stringToSign='GET\n\n'+'x-amz-security-token='+sessionToken+'&Expirement='+expires+'\n'+formattedDateString+'\n/'+'/'+bucketname+'/'+filename;
系统调试('SIGN'+stringToSign);
String encodedStringToSign=EncodingUtil.urlEncode(stringToSign,'UTF-8');
Blob mac=Crypto.generateMac('HMACSHA1',Blob.valueof(stringToSign),Blob.valueof(accessSecret));
String signedKey=EncodingUtil.base64Encode(mac);
字符串authHeader='AWS'++'+accessKeyId+':'+signedKey;
请求setHeader('Date',formattedDateString);
//请求setHeader('x-amz-security-token',sessionToken)//如果设置此项,AWS将返回“无效签名”
请求setHeader(“授权”,authHeader);
HttpResponse resp=http.send(req);

AWS似乎正在读取AccessKeyId/Secret,但没有读取会话令牌。我还尝试将x-amz-security-token设置为头,但这会引发403错误——签名不匹配。我的头或签名中是否缺少可以使此请求成功返回的内容?

结果表明,我将x-amz-security-token头放在了错误的位置。它需要在格式化日期之后立即出现在规范AMZ标题部分,并用逗号分隔名称和值:

String stringToSign = 'GET\n\n\n' + formattedDateString + '\n' + 'x-amz-security-token:' + sessionToken + '\n' + '/' + bucketname + '/' + filename;
此外,需要取消注释以下行:

req.setHeader('x-amz-security-token', sessionToken);

最后,请确保标题和规范化的AMZ标题均未大写。

抱歉-删除注释。