Skip to content

Commit

Permalink
simplify using the :auth_header_format option by autogenerating a pro…
Browse files Browse the repository at this point in the history
…per :auth_header_parse expression that should cover pretty much all cases

simplifies usage of multiple authentication secrets with header-based authentication
  • Loading branch information
Xylakant committed Dec 14, 2011
1 parent 452ae66 commit a6a5db9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
10 changes: 5 additions & 5 deletions README.md
Expand Up @@ -120,9 +120,11 @@ No authentication attempt is made if the scheme name in the `Authorization` head
## Authentication Header Format

The format of the Authentication Header can be controlled using the `:auth_header_format` directive. The given format string will be interpolated
with all given options and the signature. The default value is `%{auth_scheme} %{signature}` which will result in an auth header with a format such as `HMAC 539263f4f83878a4917d2f9c1521320c28b926a9`.
with all given options and the signature. The default value is `%{scheme} %{signature}` which will result in an auth header with a format such as `HMAC 539263f4f83878a4917d2f9c1521320c28b926a9`. The format string must contain at least the `scheme` and `signature` components.

The `:auth_header_format` directive has a companion directive, `:auth_header_parse` which can be a proc or a regular expression. Any given regular expression will be evaluated against the string and any named capture pattern will be added to the parameters for the request. The regular expression must at least contain a pattern named `scheme` and pattern named `signature`. The default value is `/(?<scheme>\w+) (?<signature>\w+)/`
The `:auth_header_format` directive has a companion directive, `:auth_header_parse` which must be a regular expression. Any given regular expression will be evaluated against the authorization header. The results can be retrieved using the `parsed_auth_header` method. The regular expression must at least contain a pattern named `scheme` and pattern named `signature`. The default value for this directive is a regular expression that is auto-generated by translating the `:auth_header_format` setting to a regular expression that contains a named capture group for each named part of the format string. Each capture allows for word characters, plus, dash, underscore and dot. The default :auth_header_format `%{scheme} %{signature}` will be translated to `/(?<autschemeh_scheme>[-_+.\w]+) (?<signature>[-_+.\w]+)/`.

See the section about multiple authentication secrets for a use-case and a comprehensive example.

## Optional nonce

Expand Down Expand Up @@ -306,9 +308,7 @@ secrets allows us to implement multiple signing keys:
access_key_id = strategy.parsed_auth_header["access_key_id"]
keys[access_key_id]
},
:auth_header_format => '%{scheme} %{access_key_id} %{signature}',
:auth_header_parse => /(?<scheme>\w+) (?<access_key_id>\w+) (?<signature>\w+)/
}
:auth_header_format => '%{scheme} %{access_key_id} %{signature}' }
end

This combination of settings uses a slightly different Format for the authorization header and transports the secret keys ID in the header of the form `HMAC KEY2 a59456da1f61f86e96622e283780f58b7428c892`
Expand Down
34 changes: 33 additions & 1 deletion lib/hmac/strategies/base.rb
Expand Up @@ -119,8 +119,40 @@ def optional_headers
(config[:optional_headers] || []) + ["Content-MD5", "Content-Type"]
end

def auth_header_format
config[:auth_header_format] || '%{scheme} %{signature}'
end

def auth_header_parse
config[:auth_header_parse] || /(?<scheme>\w+) (?<signature>\w+)/
unless @auth_header_parse
r = config[:auth_header_parse]

if !r
# transforms the auth_header_format to a regular expression
# that allows [-_+.\w] for each of the segments in the format string
#
# '%{scheme} %{signature}' => /(?<scheme>[-_+.\w]+) (?<signature>[-_+.\w]+)/
#
split_re = /(?<!%)(%{[^}]+})/
replace_re = /(?<!%)%{([^}]+)}/

segments = auth_header_format.split split_re
segments.each_index do |i; md, key|
md = replace_re.match(segments[i])
if ! md.nil?
key = md.captures[0].to_sym
segments[i] = "(?<#{key}>[-_+.\\w]+)"
else
segments[i] = segments[i].gsub "%%", "%"
end
end
r = Regexp.new segments.join
end

@auth_header_parse = r
end

@auth_header_parse
end

def lowercase_headers
Expand Down
3 changes: 1 addition & 2 deletions test/hmac/strategies/header_test.rb
Expand Up @@ -30,8 +30,7 @@
access_key_id = strategy.parsed_auth_header["access_key_id"]
keys[access_key_id]
},
:auth_header_format => '%{scheme} %{access_key_id} %{signature}',
:auth_header_parse => /(?<scheme>\w+) (?<access_key_id>\w+) (?<signature>\w+)/
:auth_header_format => '%{scheme} %{access_key_id} %{signature}'
}
}
}
Expand Down

0 comments on commit a6a5db9

Please sign in to comment.