Class: TOS::Signer
- Inherits:
-
Object
- Object
- TOS::Signer
- Defined in:
- lib/tos/signer.rb
Overview
Signs HTTP requests for the TOS object service using the TOS4-HMAC-SHA256 scheme (analogous to AWS SigV4, but with the “tos” service name and a slightly different signed-header policy: by default only ‘content-type` and any `x-tos-*` headers are signed).
Constant Summary collapse
- ALGORITHM =
"TOS4-HMAC-SHA256"- SERVICE =
"tos"- REQUEST =
"request"- EMPTY_SHA256 =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"- UNSIGNED_PAYLOAD =
"UNSIGNED-PAYLOAD"
Instance Attribute Summary collapse
-
#credentials ⇒ Object
readonly
Returns the value of attribute credentials.
-
#region ⇒ Object
readonly
Returns the value of attribute region.
Instance Method Summary collapse
-
#initialize(credentials:, region:) ⇒ Signer
constructor
A new instance of Signer.
-
#presign(method:, host:, path:, query: {}, expires_in: 3600, now: Time.now.utc) ⇒ Object
Build a presigned URL with all signing material in the query string.
-
#sign_headers(method:, path:, query: {}, headers: {}, body: nil, now: Time.now.utc) ⇒ Object
Sign a request and return a Hash of headers to add (Authorization, X-Tos-Date, X-Tos-Content-Sha256, plus X-Tos-Security-Token when STS credentials are used).
Constructor Details
#initialize(credentials:, region:) ⇒ Signer
Returns a new instance of Signer.
22 23 24 25 26 27 28 |
# File 'lib/tos/signer.rb', line 22 def initialize(credentials:, region:) @credentials = Credentials.from(credentials) raise ConfigError, "TOS credentials are missing access_key_id/secret_access_key" unless @credentials.valid? raise ConfigError, "TOS region is required" if region.to_s.empty? @region = region.to_s end |
Instance Attribute Details
#credentials ⇒ Object (readonly)
Returns the value of attribute credentials.
20 21 22 |
# File 'lib/tos/signer.rb', line 20 def credentials @credentials end |
#region ⇒ Object (readonly)
Returns the value of attribute region.
20 21 22 |
# File 'lib/tos/signer.rb', line 20 def region @region end |
Instance Method Details
#presign(method:, host:, path:, query: {}, expires_in: 3600, now: Time.now.utc) ⇒ Object
Build a presigned URL with all signing material in the query string. Returns a fully-qualified URL.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/tos/signer.rb', line 74 def presign(method:, host:, path:, query: {}, expires_in: 3600, now: Time.now.utc) datetime = now.strftime("%Y%m%dT%H%M%SZ") date = datetime[0, 8] credential_scope = "#{date}/#{@region}/#{SERVICE}/#{REQUEST}" query_with_sig = query.dup query_with_sig["X-Tos-Algorithm"] = ALGORITHM query_with_sig["X-Tos-Credential"] = "#{@credentials.access_key_id}/#{credential_scope}" query_with_sig["X-Tos-Date"] = datetime query_with_sig["X-Tos-Expires"] = expires_in.to_s query_with_sig["X-Tos-SignedHeaders"] = "" query_with_sig["X-Tos-Security-Token"] = @credentials.security_token if @credentials.security_token canonical_request = build_canonical_request( method: method.to_s.upcase, path: path, query: query_with_sig, signed_headers: [], content_sha: UNSIGNED_PAYLOAD ) string_to_sign = [ALGORITHM, datetime, credential_scope, sha256_hex(canonical_request)].join("\n") signing_key = derive_signing_key(date) query_with_sig["X-Tos-Signature"] = hmac_hex(signing_key, string_to_sign) "https://#{host}#{path}?#{encode_query(query_with_sig)}" end |
#sign_headers(method:, path:, query: {}, headers: {}, body: nil, now: Time.now.utc) ⇒ Object
Sign a request and return a Hash of headers to add (Authorization, X-Tos-Date, X-Tos-Content-Sha256, plus X-Tos-Security-Token when STS credentials are used).
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/tos/signer.rb', line 40 def sign_headers(method:, path:, query: {}, headers: {}, body: nil, now: Time.now.utc) datetime = now.strftime("%Y%m%dT%H%M%SZ") date = datetime[0, 8] content_sha = body ? sha256_hex(body) : EMPTY_SHA256 working_headers = headers.dup working_headers["X-Tos-Date"] = datetime working_headers["X-Tos-Content-Sha256"] = content_sha working_headers["X-Tos-Security-Token"] = @credentials.security_token if @credentials.security_token signed_headers = filter_signed_headers(working_headers) canonical_request = build_canonical_request( method: method.to_s.upcase, path: path, query: query, signed_headers: signed_headers, content_sha: content_sha ) credential_scope = "#{date}/#{@region}/#{SERVICE}/#{REQUEST}" string_to_sign = [ALGORITHM, datetime, credential_scope, sha256_hex(canonical_request)].join("\n") signing_key = derive_signing_key(date) signature = hmac_hex(signing_key, string_to_sign) = (signed_headers, credential_scope, signature) working_headers["Authorization"] = working_headers end |