@@ -6,6 +6,7 @@ import Core
6
6
public class S3SignerAWS {
7
7
private let accessKey : String
8
8
private let secretKey : String
9
+ private let securityToken : String ? // Used to validate temporary credentials, such as those from an EC2 Instance's IAM role
9
10
private let _region : Region
10
11
private let dateFormatter : DateFormatter
11
12
@@ -14,14 +15,22 @@ public class S3SignerAWS {
14
15
return self . _region
15
16
}
16
17
}
17
-
18
- required public init ( accessKey: String , secretKey: String , region: Region ) {
18
+
19
+ /// Initializes a signer which works for either permanent credentials or temporary secrets
20
+ ///
21
+ /// - Parameters:
22
+ /// - accessKey: Main token to identify the credential
23
+ /// - secretKey: Password to validate access
24
+ /// - region: Which AWS region to sign against
25
+ /// - securityToken: Optional token used only with temporary credentials
26
+ public init ( accessKey: String , secretKey: String , region: Region , securityToken: String ? = nil ) {
19
27
self . accessKey = accessKey
20
28
self . secretKey = secretKey
21
29
self . _region = region
30
+ self . securityToken = securityToken
22
31
self . dateFormatter = DateFormatter ( )
23
32
}
24
-
33
+
25
34
public func authHeaderV4( httpMethod: HTTPMethod , urlString: String , pathPercentEncoding: CharacterSet = CharacterSet . urlPathAllowed, queryPercentEncoding: CharacterSet = CharacterSet . urlQueryAllowed, headers: [ String : String ] , payload: Payload , mimeType: String ? = nil ) throws -> [ String : String ] {
26
35
27
36
guard let url = URL ( string: urlString) else { throw S3SignerError . badURL }
@@ -34,7 +43,7 @@ public class S3SignerAWS {
34
43
35
44
if httpMethod == . put {
36
45
if payload. isBytes {
37
- let MD5Digest = try Hash . make ( . md5, payload. bytes) . base64String
46
+ let MD5Digest = try Hash . make ( . md5, payload. bytes) . base64Encoded . string
38
47
updatedHeaders [ " content-md5 " ] = MD5Digest
39
48
}
40
49
}
@@ -79,7 +88,7 @@ public class S3SignerAWS {
79
88
guard let stringToSign = [ " GET " , " " , " " , " \( expirationTime) " , path ( url: url) ] . joined ( separator: " \n " ) . data ( using: String . Encoding. utf8) else { throw S3SignerError . unableToEncodeStringToSign }
80
89
81
90
let stringToSignBytes = try stringToSign. makeBytes ( )
82
- let signature = try HMAC . make ( . sha1, stringToSignBytes, key: secretKey. bytes) . base64String . addingPercentEncoding ( withAllowedCharacters: . urlHostAllowed)
91
+ let signature = try HMAC . make ( . sha1, stringToSignBytes, key: secretKey. bytes) . base64Encoded . string . addingPercentEncoding ( withAllowedCharacters: . urlHostAllowed)
83
92
guard let sig = signature else { throw S3SignerError . unableToEncodeSignature }
84
93
85
94
let finalURLString = " \( urlString) ?AWSAccessKeyId= \( accessKey) &Signature= \( sig) &Expires= \( expirationTime) "
@@ -113,6 +122,10 @@ public class S3SignerAWS {
113
122
if bodyDigest != " UNSIGNED-PAYLOAD " {
114
123
headersCopy [ " x-amz-content-sha256 " ] = bodyDigest
115
124
}
125
+ // According to http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html#RequestWithSTS
126
+ if let token = securityToken {
127
+ headersCopy [ " X-Amz-Security-Token " ] = token
128
+ }
116
129
return headersCopy
117
130
}
118
131
0 commit comments