I'm attempting to implement some basic integration with CloudKit web services, following Apple's guide for authenticating requests. I've followed some help from this and this question as to how to properly authorize requests, and seem to be following all steps correctly, but I'm still getting a 401 AUTHENTICATION_FAILED
error from Apple.
The endpoint I'm targeting is a POST endpoint for retrieving a record, given a record name.
I've added comments to my code to show the outputs i get at various stages, and I've used an alternative certificate so i'm not providing my genuine private key:
def self.signature(parameters, date, image_id)
#date: 2016-08-14T14:32:20Z
#parameters: {"records":[{"recordName":"7DBC4FAD-D18C-476A-89FB-14A515098F34"}]}
encoded_parameters = Digest::SHA256.base64digest(parameters)
#encoded_parameters: 6gmJ4AvmJgkNY4SJm6ImOxZaZ07J7cih/tRXI0zkRjQ=
url_subpath = CloudKit.url_subpath
#url_subpath: /database/1/iCloud.ProjectDent.TwIM/development/public/records/lookup
message = date + ':' + encoded_parameters + ':' + url_subpath
#message: 2016-08-14T14:23:35Z:6gmJ4AvmJgkNY4SJm6ImOxZaZ07J7cih/tRXI0zkRjQ=:/database/1/iCloud.ProjectDent.TwIM/development/public/records/lookup
private_key = OpenSSL::PKey.read(File.read('altkey.pem'))
signature = private_key.dsa_sign_asn1(OpenSSL::Digest::SHA256.digest(message))
#signature: -? WX?xfc???ɔ???,?Ț?Փv?3+Xt!?$R?_Y?×*?,?3??Z-\#?ŭ?Ƿh
encoded_signature = Base64.strict_encode64(signature)
#encoded_signature: MEUCIFdYlHhmrxoIY8KW1tT6yZT17bYsP8ia09WTdpEzK1h0AiEA0yRSh39fWYHDlyqJLNgzhr9aLVwj2cWtkse3aA0tGZI=
return encoded_signature
end
def self.headers(parameters, image_id)
date = Time.now.utc.iso8601
signature = self.signature(parameters, date, image_id)
headers = {
'X-Apple-CloudKit-Request-KeyID' => CloudKit.key_id,
'X-Apple-CloudKit-Request-ISO8601Date' => date,
'X-Apple-CloudKit-Request-SignatureV1' => signature
}
#headers (key id masked): {"X-Apple-CloudKit-Request-KeyID"=>"123456", "X-Apple-CloudKit-Request-ISO8601Date"=>"2016-08-14T14:32:20Z", "X-Apple-CloudKit-Request-SignatureV1"=>"MEUCIFdYlHhmrxoIY8KW1tT6yZT17bYsP8ia09WTdpEzK1h0AiEA0yRSh39fWYHDlyqJLNgzhr9aLVwj2cWtkse3aA0tGZI="}
return headers
end
def self.fetch_image(image_id)
url = CloudKit.url
parameters = CloudKit.parameters(image_id).to_json
headers = CloudKit.headers(parameters, image_id)
begin
response = RestClient.post(url, parameters, headers)
puts 'response'
puts response.code
puts response.to_str
rescue => e
puts 'rescued: ' + e.to_s
end
end
The end result is:
rescued: 401 Unauthorized
I'm not sure what I'm doing wrong here - I do seem to be following all steps correctly. Hopefully the logs can help someone understand where this might be going wrong.