Skip to content

Commit

Permalink
support signatrue v4
Browse files Browse the repository at this point in the history
  • Loading branch information
huiguangjun authored Jan 3, 2025
1 parent 9e5cc3c commit 1f0599d
Show file tree
Hide file tree
Showing 46 changed files with 2,849 additions and 247 deletions.
172 changes: 169 additions & 3 deletions AliyunOSSSDK.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions AliyunOSSSDK/NSData+OSS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// NSData+OSS.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSData (OSS)

- (NSString *)hexString;
- (NSData *)calculateSha256;

@end

NS_ASSUME_NONNULL_END
41 changes: 41 additions & 0 deletions AliyunOSSSDK/NSData+OSS.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// NSData+OSS.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//

#import "NSData+OSS.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSData (OSS)

- (NSString *)hexString {
NSMutableString *hexString = [NSMutableString string];
Byte *byte = (Byte *)[self bytes];
for (int i = 0; i<[self length]; i++) {
[hexString appendFormat:@"%x", (*(byte + i) >> 4) & 0xf];
[hexString appendFormat:@"%x", *(byte + i) & 0xf];
}
return hexString;
}

- (NSData *)calculateSha256 {
unsigned char *digest = NULL;

digest = malloc(CC_SHA256_DIGEST_LENGTH * sizeof(unsigned char));
memset(digest, 0x0, CC_SHA256_DIGEST_LENGTH);
CC_SHA256(self.bytes, (CC_LONG)self.length, digest);

if (digest) {
NSData *data = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
free(digest);
return data;
}
free(digest);

return nil;
}

@end
3 changes: 3 additions & 0 deletions AliyunOSSSDK/NSDate+OSS.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@
+ (NSDate *)oss_dateFromString:(NSString *)string;
+ (NSDate *)oss_clockSkewFixedDate;
- (NSString *)oss_asStringValue;
+ (NSDate *)oss_dateFromString:(NSString *)string
dateFormat:(NSString *)dateFormat;
- (NSString *)oss_asStringValueWithDateFormat:(NSString *)dateFormat;
@end
19 changes: 19 additions & 0 deletions AliyunOSSSDK/NSDate+OSS.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,23 @@ - (NSString *)oss_asStringValue {
return [dateFormatter stringFromDate:self];
}

+ (NSDate *)oss_dateFromString:(NSString *)string
dateFormat:(NSString *)dateFormat {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.dateFormat = dateFormat;

return [dateFormatter dateFromString:string];
}

- (NSString *)oss_asStringValueWithDateFormat:(NSString *)dateFormat {
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
dateFormatter.dateFormat = dateFormat;

return [dateFormatter stringFromDate:self];
}

@end
19 changes: 19 additions & 0 deletions AliyunOSSSDK/NSSet+OSS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// NSSet+OSS.h
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSSet (OSS)

- (NSString *)componentsJoinedByString:(NSString *)separator;

@end

NS_ASSUME_NONNULL_END
30 changes: 30 additions & 0 deletions AliyunOSSSDK/NSSet+OSS.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// NSSet+OSS.m
// AliyunOSSSDK
//
// Created by ws on 2023/12/28.
// Copyright © 2023 aliyun. All rights reserved.
//

#import "NSSet+OSS.h"

@implementation NSSet (OSS)

- (NSString *)componentsJoinedByString:(NSString *)separator {
NSMutableString *builder = [NSMutableString new];
int i = 0;

for (NSObject *part in self) {
if ([part isKindOfClass:[NSString class]]) {
[builder appendString:(NSString *)part];
if (i < [self count] - 1) {
[builder appendString:separator];
}
}
i++;
}

return builder;
}

@end
3 changes: 2 additions & 1 deletion AliyunOSSSDK/OSSAllRequestNeededMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
@property (nonatomic, copy) NSDictionary *params;
@property (nonatomic, copy) NSString *contentSHA1;
@property (nonatomic, assign) BOOL isHostInCnameExcludeList;

@property (nonatomic, assign) BOOL isUseUrlSignature;
@property (nonatomic, copy) NSSet<NSString *> *additionalHeaderNames;

- (OSSTask *)validateRequestParamsInOperationType:(OSSOperationType)operType;

Expand Down
6 changes: 6 additions & 0 deletions AliyunOSSSDK/OSSClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, strong) OSSClientConfiguration * clientConfiguration;

/// OSS services Region
@property (nonatomic, copy) NSString *region;

/// cloudBoxId OSS cloud box id
@property (nonatomic, copy) NSString *cloudBoxId;

/**
oss operation task queue
*/
Expand Down
140 changes: 67 additions & 73 deletions AliyunOSSSDK/OSSClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#import "OSSNetworking.h"
#import "OSSXMLDictionary.h"
#import "OSSIPv6Adapter.h"
#import "OSSSignerParams.h"
#import "OSSSignerBase.h"

#import "OSSNetworkingRequestDelegate.h"
#import "OSSAllRequestNeededMessage.h"
Expand Down Expand Up @@ -146,9 +148,17 @@ - (OSSTask *)invokeRequest:(OSSNetworkingRequestDelegate *)request requireAuthen
id<OSSRequestInterceptor> uaSetting = [[OSSUASettingInterceptor alloc] initWithClientConfiguration:self.clientConfiguration];
[request.interceptors addObject:uaSetting];

/* check if the authentication is required */
if (requireAuthentication) {
id<OSSRequestInterceptor> signer = [[OSSSignerInterceptor alloc] initWithCredentialProvider:self.credentialProvider];
if (self.clientConfiguration.signVersion == OSSSignVersionV4 && self.region == nil) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeInvalidArgument
userInfo:@{OSSErrorMessageTOKEN: @"Region haven't been set!"}]];
}

OSSSignerInterceptor *signer = [[OSSSignerInterceptor alloc] initWithCredentialProvider:self.credentialProvider];
signer.version = self.clientConfiguration.signVersion;
signer.region = self.region;
signer.cloudBoxId = self.cloudBoxId;
[request.interceptors addObject:signer];
}

Expand Down Expand Up @@ -1990,93 +2000,53 @@ - (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withHeaders:header];
}

- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
httpMethod:(NSString *)method
withExpirationInterval:(NSTimeInterval)interval
withParameters:(NSDictionary *)parameters
withHeaders:(NSDictionary *)headers {
return [self presignConstrainURLWithBucketName:bucketName
withObjectKey:objectKey
httpMethod:method
withExpirationInterval:interval
withParameters:parameters
withHeaders:headers
withAdditionalHeaderNames:nil];
}

- (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
withObjectKey:(NSString *)objectKey
httpMethod:(NSString *)method
withExpirationInterval:(NSTimeInterval)interval
withParameters:(NSDictionary *)parameters
withHeaders:(NSDictionary *)headers
withAdditionalHeaderNames:(NSSet<NSString *> *)additionalHeaderNames
{
return [[OSSTask taskWithResult:nil] continueWithBlock:^id(OSSTask *task) {
NSString * resource = [NSString stringWithFormat:@"/%@/%@", bucketName, objectKey];
NSString * expires = [@((int64_t)[[NSDate oss_clockSkewFixedDate] timeIntervalSince1970] + interval) stringValue];
NSString * xossHeader = @"";

NSString *resource = @"/";
if (bucketName != nil) {
resource = [NSString stringWithFormat:@"/%@/", bucketName];
}
if (objectKey != nil) {
resource = [resource oss_stringByAppendingPathComponentForURL:objectKey];
}
NSString * contentType = headers[OSSHttpHeaderContentType];
NSString * contentMd5 = headers[OSSHttpHeaderContentMD5];
NSString * patchContentType = contentType == nil ? @"" : contentType;
NSString * patchContentMd5 = contentMd5 == nil ? @"" : contentMd5;

NSMutableDictionary * params = [NSMutableDictionary dictionary];
if (parameters.count > 0) {
[params addEntriesFromDictionary:parameters];
}

if (headers) {
NSMutableArray * params = [[NSMutableArray alloc] init];
NSArray * sortedKey = [[headers allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];
for (NSString * key in sortedKey) {
if ([key hasPrefix:@"x-oss-"]) {
[params addObject:[NSString stringWithFormat:@"%@:%@", key, [headers objectForKey:key]]];
}
}
if ([params count]) {
xossHeader = [NSString stringWithFormat:@"%@\n", [params componentsJoinedByString:@"\n"]];
}
}

NSString * wholeSign = nil;
OSSFederationToken *token = nil;
NSError *error = nil;

if ([self.credentialProvider isKindOfClass:[OSSFederationCredentialProvider class]]) {
token = [(OSSFederationCredentialProvider *)self.credentialProvider getToken:&error];
if (error) {
return [OSSTask taskWithError:error];
}
} else if ([self.credentialProvider isKindOfClass:[OSSStsTokenCredentialProvider class]]) {
token = [(OSSStsTokenCredentialProvider *)self.credentialProvider getToken];
}

if ([self.credentialProvider isKindOfClass:[OSSFederationCredentialProvider class]]
|| [self.credentialProvider isKindOfClass:[OSSStsTokenCredentialProvider class]])
{
[params oss_setObject:token.tToken forKey:@"security-token"];
resource = [NSString stringWithFormat:@"%@?%@", resource, [OSSUtil populateSubresourceStringFromParameter:params]];
NSString * stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%@%@", method, patchContentMd5, patchContentType, expires, xossHeader, resource];
wholeSign = [OSSUtil sign:stringToSign withToken:token];
} else {
NSString * subresource = [OSSUtil populateSubresourceStringFromParameter:params];
if ([subresource length] > 0) {
resource = [NSString stringWithFormat:@"%@?%@", resource, [OSSUtil populateSubresourceStringFromParameter:params]];
}
NSString * stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%@%@", method, patchContentMd5, patchContentType, expires, xossHeader, resource];
wholeSign = [self.credentialProvider sign:stringToSign error:&error];
if (error) {
return [OSSTask taskWithError:error];
}
}

NSArray * splitResult = [wholeSign componentsSeparatedByString:@":"];
if ([splitResult count] != 2
|| ![((NSString *)[splitResult objectAtIndex:0]) hasPrefix:@"OSS "]) {
return [OSSTask taskWithError:[NSError errorWithDomain:OSSClientErrorDomain
code:OSSClientErrorCodeSignFailed
userInfo:@{OSSErrorMessageTOKEN: @"the returned signature is invalid"}]];
}
NSString * accessKey = [(NSString *)[splitResult objectAtIndex:0] substringFromIndex:4];
NSString * signature = [splitResult objectAtIndex:1];

BOOL isPathStyle = false;
NSURL * endpointURL = [NSURL URLWithString:self.endpoint];
NSString * host = endpointURL.host;
BOOL isPathStyle = false;
NSString * port = @"";
NSString * path = @"";
NSString * pathStylePath = @"";
Boolean isHostInCnameExcludeList = [OSSUtil isIncludeCnameExcludeList:self.clientConfiguration.cnameExcludeList host:host];
if ([OSSUtil isOssOriginBucketHost:host]) {
host = [NSString stringWithFormat:@"%@.%@", bucketName, host];
} else if ([OSSUtil isIncludeCnameExcludeList:self.clientConfiguration.cnameExcludeList host:host]) {
} else if (isHostInCnameExcludeList) {
if (self.clientConfiguration.isPathStyleAccessEnable) {
isPathStyle = true;
} else {
Expand All @@ -2096,17 +2066,41 @@ - (OSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
pathStylePath = [@"/" stringByAppendingString:bucketName];
}

[params oss_setObject:signature forKey:@"Signature"];
[params oss_setObject:accessKey forKey:@"OSSAccessKeyId"];
[params oss_setObject:expires forKey:@"Expires"];
OSSAllRequestNeededMessage *message = [OSSAllRequestNeededMessage new];
message.bucketName = bucketName;
message.objectKey = objectKey;
message.httpMethod = method;
message.contentMd5 = contentMd5;
message.contentType = contentType;
message.headerParams = headers.mutableCopy;
message.params = parameters;
message.isHostInCnameExcludeList = isHostInCnameExcludeList;
message.isUseUrlSignature = true;
message.additionalHeaderNames = additionalHeaderNames;


OSSSignerParams *signerParams = [[OSSSignerParams alloc] init];
signerParams.region = self.region;
signerParams.cloudBoxId = self.cloudBoxId;
signerParams.resourcePath = resource;
signerParams.credentialProvider = self.credentialProvider;
signerParams.expiration = interval;

id<OSSRequestPresigner> requestSigner = [OSSSignerBase createRequestPresignerWithSignerVersion:self.clientConfiguration.signVersion
signerParams:signerParams];
OSSTask *signTask = [requestSigner presign:message];
if (signTask.error) {
return signTask;
}

NSString * stringURL = [NSString stringWithFormat:@"%@://%@%@%@%@/%@?%@",
endpointURL.scheme,
host,
port,
path,
pathStylePath,
[OSSUtil encodeURL:objectKey],
[OSSUtil populateQueryStringFromParameter:params]];
[OSSUtil populateQueryStringFromParameter:message.params]];
return [OSSTask taskWithResult:stringURL];
}];
}
Expand Down
6 changes: 6 additions & 0 deletions AliyunOSSSDK/OSSConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,10 @@ OBJC_EXTERN NSString * const OSSHTTPMethodPOST;
OBJC_EXTERN NSString * const OSSHTTPMethodDELETE;


typedef NS_ENUM(NSInteger, OSSSignVersion)
{
OSSSignVersionV1,
OSSSignVersionV4
};

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 1f0599d

Please sign in to comment.