Skip to content

Commit bd5d3e0

Browse files
committed
Update MAC to draft 05
1 parent 81bd411 commit bd5d3e0

File tree

2 files changed

+21
-21
lines changed

2 files changed

+21
-21
lines changed

lib/oauth2/mac_token.rb

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def self.from_access_token(token, secret, options = {})
2929
# @option opts [FixNum, String] :algorithm (hmac-sha-256) the algorithm to use for the HMAC digest (one of 'hmac-sha-256', 'hmac-sha-1')
3030
def initialize(client, token, secret, opts = {})
3131
@secret = secret
32+
@seq_nr = SecureRandom.random_number(2 ** 64 - 1)
33+
@kid = opts.delete(:kid) || strict_encode64(Digest::SHA1.digest(token))
3234
self.algorithm = opts.delete(:algorithm) || 'hmac-sha-256'
3335

3436
super(client, token, opts)
@@ -59,33 +61,30 @@ def headers
5961
# @param [Symbol] verb the HTTP request method
6062
# @param [String] url the HTTP URL path of the request
6163
def header(verb, url)
62-
timestamp = Time.now.utc.to_i
63-
nonce = Digest::MD5.hexdigest([timestamp, SecureRandom.hex].join(':'))
64+
timestamp = (Time.now.to_f * 1000).floor
65+
@seq_nr = (@seq_nr + 1) % (2 ** 64 - 1)
6466

65-
uri = URI.parse(url)
67+
uri = URI(url)
6668

6769
fail(ArgumentError, "could not parse \"#{url}\" into URI") unless uri.is_a?(URI::HTTP)
6870

69-
mac = signature(timestamp, nonce, verb, uri)
71+
mac = signature(timestamp, @seq_nr, verb, uri)
7072

71-
"MAC id=\"#{token}\", ts=\"#{timestamp}\", nonce=\"#{nonce}\", mac=\"#{mac}\""
73+
"MAC kid=\"#{@kid}\", ts=\"#{timestamp}\", seq-nr=\"#{@seq_nr}\", mac=\"#{mac}\""
7274
end
7375

7476
# Generate the Base64-encoded HMAC digest signature
7577
#
76-
# @param [Fixnum] timestamp the timestamp of the request in seconds since epoch
77-
# @param [String] nonce the MAC header nonce
78+
# @param [Fixnum] timestamp the timestamp of the request in milliseconds since epoch
79+
# @param [Fixnum] seq_nr the MAC header sequence number
7880
# @param [Symbol] verb the HTTP request method
7981
# @param [String] url the HTTP URL path of the request
80-
def signature(timestamp, nonce, verb, uri)
82+
def signature(timestamp, seq_nr, verb, uri)
8183
signature = [
84+
"#{verb.to_s.upcase} #{uri.request_uri} HTTP/1.1",
8285
timestamp,
83-
nonce,
84-
verb.to_s.upcase,
85-
uri.request_uri,
86-
uri.host,
87-
uri.port,
88-
'', nil
86+
seq_nr,
87+
''
8988
].join("\n")
9089

9190
strict_encode64(OpenSSL::HMAC.digest(@algorithm, secret, signature))

spec/oauth2/mac_token_spec.rb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'helper'
22

33
describe MACToken do
4+
let(:kid) { 'this-token' }
45
let(:token) { 'monkey' }
56
let(:client) do
67
Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
@@ -13,7 +14,7 @@
1314
end
1415
end
1516

16-
subject { MACToken.new(client, token, 'abc123') }
17+
subject { MACToken.new(client, token, 'abc123', kid: kid) }
1718

1819
describe '#initialize' do
1920
it 'assigns client and token' do
@@ -46,8 +47,8 @@
4647

4748
describe '#request' do
4849
VERBS.each do |verb|
49-
it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
50-
expect(subject.post('/token/header').body).to include("MAC id=\"#{token}\"")
50+
it "sends the kid in the Authorization header for a #{verb.to_s.upcase} request" do
51+
expect(subject.post('/token/header').body).to include("MAC kid=\"#{kid}\"")
5152
end
5253
end
5354
end
@@ -62,22 +63,22 @@
6263

6364
it 'generates the proper format' do
6465
header = subject.header('get', 'https://www.example.com/hello?a=1')
65-
expect(header).to match(/MAC id="#{token}", ts="[0-9]+", nonce="[^"]+", mac="[^"]+"/)
66+
expect(header).to match(/MAC kid="#{kid}", ts="[0-9]+", seq-nr="[0-9]+", mac="[^"]+"/)
6667
end
6768

6869
it 'passes ArgumentError with an invalid url' do
6970
expect { subject.header('get', 'this-is-not-valid') }.to raise_error(ArgumentError)
7071
end
7172

7273
it 'passes URI::InvalidURIError through' do
73-
expect { subject.header('get', nil) }.to raise_error(URI::InvalidURIError)
74+
expect { subject.header('get', '\\') }.to raise_error(URI::InvalidURIError)
7475
end
7576
end
7677

7778
describe '#signature' do
7879
it 'generates properly' do
79-
signature = subject.signature(0, 'random-string', 'get', URI('https://www.google.com'))
80-
expect(signature).to eq('rMDjVA3VJj3v1OmxM29QQljKia6msl5rjN83x3bZmi8=')
80+
signature = subject.signature(0, 'random-string', 'get', URI('https://www.google.com/hai?this=1'))
81+
expect(signature).to eq('13wqHvYkM7uDKpT9Yc8HnDLxa+4yjv2G1qV1kkqpbdc=')
8182
end
8283
end
8384

0 commit comments

Comments
 (0)