class OCI::BaseSigner
The base class for other classes which are meant to generate a signature
Constants
- BODY_HEADERS
- GENERIC_HEADERS
- SIGNATURE_VERSION
The Oracle Cloud Infrastructure API signature version
- SIGNING_STRATEGY_ENUM
enum to define the signing strategy
Public Class Methods
Creates a BaseSigner
@param [String] api_key The API key needed when making calls. For token-based signing this should be ST$<token> but for calling as a user it will be tenancy/user/fingerprint @param [String] private_key_content The private key as a PEM-formatted string @param [String] pass_phrase Optional the pass phrase for the private key (if any) @param [SIGNING_STRATEGY_ENUM] signing_strategy Optional signing for standard service or object storage service @param [Array<String>] headers_to_sign_in_all_requests Optional headers which should be signed on each request @param [Array<String>] body_headers_to_sign Optional headers which should be signed on requests with bodies
# File lib/oci/base_signer.rb, line 31 def initialize( api_key, private_key_content, pass_phrase: nil, signing_strategy: STANDARD, headers_to_sign_in_all_requests: GENERIC_HEADERS, body_headers_to_sign: BODY_HEADERS ) raise 'Missing required parameter api_key.' unless api_key raise 'Missing required parameter private_key_content.' unless private_key_content @key_id = api_key @private_key_content = private_key_content @pass_phrase = pass_phrase @signing_strategy = signing_strategy @headers_to_sign_all_requests = headers_to_sign_in_all_requests @body_headers_to_sign = body_headers_to_sign @operation_header_mapping = { options: [], get: headers_to_sign_in_all_requests, head: headers_to_sign_in_all_requests, delete: headers_to_sign_in_all_requests, put: headers_to_sign_in_all_requests + body_headers_to_sign, post: headers_to_sign_in_all_requests + body_headers_to_sign, patch: headers_to_sign_in_all_requests + body_headers_to_sign } end
Public Instance Methods
Generates the correct signature and adds it to the headers that are passed in. Also injects any required headers that might be missing.
@param [Symbol] method The HTTP method, such as :get or :post. @param [String] uri The URI, such as 'iaas.us-phoenix-1.oraclecloud.com/20160918/volumeAttachments/' @param [Hash] headers A hash of headers @param [String] body The request body @param [String] operation_signing_strategy the signing strategy for the operation. Default is :standard
# File lib/oci/base_signer.rb, line 69 def sign(method, uri, headers, body, operation_signing_strategy = :standard) method = method.to_sym.downcase uri = URI(uri) path = uri.query.nil? ? uri.path : "#{uri.path}?#{uri.query}" inject_missing_headers(method, headers, body, uri, operation_signing_strategy) signature = compute_signature(headers, method, path, operation_signing_strategy) inject_authorization_header(headers, method, signature, operation_signing_strategy) unless signature.nil? end
Private Instance Methods
# File lib/oci/base_signer.rb, line 121 def compute_signature(headers, method, path, operation_signing_strategy) header_mapping = fetch_header_mapping(method, operation_signing_strategy) return if header_mapping.empty? signing_string = header_mapping.map do |header| if header == :'(request-target)' "#{header}: #{method.downcase} #{path}" else "#{header}: #{headers[header]}" end end.join("\n") signature = private_key.sign(OpenSSL::Digest::SHA256.new, signing_string.encode('ascii')) Base64.strict_encode64(signature) end
# File lib/oci/base_signer.rb, line 102 def fetch_header_mapping(method, operation_signing_strategy) return @headers_to_sign_all_requests if operation_signing_strategy == :exclude_body @operation_header_mapping[method] end
# File lib/oci/base_signer.rb, line 80 def inject_missing_headers(method, headers, body, uri, operation_signing_strategy) headers[:date] ||= Time.now.utc.httpdate headers[:accept] ||= '*/*' headers[:host] ||= uri.host if @headers_to_sign_all_requests.include?(:host) return unless %i[put post patch].include?(method) body ||= '' # For object storage service's put method, we don't need to set content length and x-content sha256 if operation_signing_strategy == :exclude_body headers[:'content-length'] ||= if body.respond_to?(:read) && body.respond_to?(:write) body.respond_to?('size') ? body.size : body.stat.size else body.bytes.length.to_s end else headers[:'content-length'] ||= body.bytes.length.to_s headers[:'x-content-sha256'] ||= OpenSSL::Digest::SHA256.new.update(body).base64digest end end
# File lib/oci/base_signer.rb, line 137 def private_key # If a pass_phase was not provided and the key is in fact encrypted, then passing in # nil for the passphrase here will show a user prompt and block until there is a response. # Passing in an empty string will work for some versions of Ruby's openssl wrapper, but # other versions will enforce the 4 character password minimum at this point. Passing in # a dummy password that's greater than 4 characters avoids both problems, and will # always succeed if the file is not encrypted. @private_key ||= OpenSSL::PKey::RSA.new( @private_key_content, @pass_phrase || SecureRandom.uuid ) end