How to create pre-signed URL in Objective C for S3 without SDK?

余生颓废 提交于 2019-12-12 19:56:46

问题


I'm building a mac application and not using the AWS iOS SDK. The GET request I'm trying to build should follow this general format:

"Authorization: AWS " + AWSAccessKeyId + ":" + base64(hmac-sha1(VERB + "\n" + CONTENT-MD5 + "\n" + CONTENT-TYPE + "\n" + DATE + "\n" + CanonicalizedAmzHeaders + "\n" + CanonicalizedResource))

As provided as "pseudo syntax" in the Amazon docs. I've been searching all over for clarification and it seems that according to a lot of people, many of the fields in the base64 hash are optional.

Below is what I came up with so far. But the response I get is an error from AWS saying "Unsupported Authorization Type" making reference to the 'Authorization' field in the header. I'm getting really stumped here. Any insight into how to debug or fix this?

Is there any other way to go about generating pre-signed urls in Obj C for S3?

-(NSURLRequest*) requestWithURL: (NSString*) reqURL

{

NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:reqURL]];
NSString* headerField = @"Authorization: ";
NSString* stringToSign = @"GET\n\n\n\n\n";

NSString* hash = [self hmacsha1:stringToSign key:SECRET_KEY];
NSString *authHeader = [NSString stringWithFormat: @"AWS%@:%@", ACCESS_KEY_ID, hash];
NSURLResponse *resp = nil;
NSError *error = nil;


[mutableRequest addValue:authHeader forHTTPHeaderField:headerField];
NSData *response = [NSURLConnection sendSynchronousRequest: mutableRequest returningResponse: &resp error: &error];
NSString *responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];


return (NSURLRequest*) mutableRequest;

}

- (NSString *)hmacsha1:(NSString *)text key:(NSString *)secret {
    NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding];
    unsigned char result[20];
    CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result);

    char base64Result[32];
    size_t theResultLength = 32;
    NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength];
    NSString* encodedData = [NSString stringWithFormat:@"%@",[theData base64Encoding]];

    return encodedData;
}

The base64 encoding is done via an NSData addon from this post


回答1:


To authenticate the query string you need to encode the stringToSign:

Signature = URL-Encode( Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) ) );

StringToSign = HTTP-VERB + "\n" +
        Content-MD5 + "\n" +
        Content-Type + "\n" +
        Expires + "\n" +
        CanonicalizedAmzHeaders +
        CanonicalizedResource;

When a browser makes the GET request, it won't provide a Content-MD5 or a Content-Type header, nor will it set any x-amz- headers, so those parts of the StringToSign are left blank.

You will need to sign the following

GET\n
\n
\n
1175139620\n

/johnsmith/photos/puppy.jpg

And the request that the browser will send is:

GET /photos/puppy.jpg?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&
    Signature=NpgCjnDzrM%2BWFzoENXmpNDUsSn8%3D&
    Expires=1175139620 HTTP/1.1

Host: johnsmith.s3.amazonaws.com

Note that the Content-Type is omitted from both the request and the stringToSign, but \n remains in the stringToSign for it. The same of the rest of the optional parts.

See more examples in Authentication Examples

Check for more details in AWS Documentations



来源:https://stackoverflow.com/questions/13783749/how-to-create-pre-signed-url-in-objective-c-for-s3-without-sdk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!