NAME
Net::OAuth2::Scheme::Factory - the default factory for token schemes
VERSION
version 0.03
SYNOPSIS
# The recipes;
#
# can be hardcoded, initialized from config files, etc...
my %recipe_client = (
context => 'client',
transport => 'bearer'
... or ...
transport => 'hmac_http',
)
# more stuff for authorization servers and resource servers
my %recipe_common = (
%recipe_client,
format => 'bearer_handle', # or 'bearer_signed'
... or ...
format => 'hmac_http',
vtable => 'shared_cache', # default
cache => $cache_object # shared cache for authservers + resources
...or...
vtable => 'authserv_push',
...or...
vtable => 'resource_pull',
);
# the completely specialized versions:
my %recipe_auth = (
%recipe_common,
context => 'auth_server',
# if authserv_push
vtable_push => \&my_push_method,
);
my %recipe_resource = (
%recipe_common,
context => 'resource_server',
# if authserv_push or resource_pull
cache => $private_cache_object, # only accessible to resource server
# if resource_pull
vtable_pull => \&my_pull_method,
},
);
# for refresh tokens
my %recipe_refresh = (
usage => 'refresh',
format => 'bearer_handle', # or 'bearer_signed'
vtable => 'shared_cache',
cache => $private_cache_object, # only accessible to authserver(s)
);
######
# client code
my $access_scheme = Net::OAuth2::Scheme->new(%recipe_client);
######
# authserver code
my $access_scheme = Net::OAuth2::Scheme->new(%recipe_auth);
my $refresh_scheme = Net::OAuth2::Scheme->new(%recipe_refresh);
my $authcode_scheme = Net::OAuth2::Scheme->new(%recipe_authcode);
######
# resource code
my $access_scheme = Net::OAuth2::Scheme->new(%recipe_resource);
DESCRIPTION
A token scheme factory object parses a collection of option settings (normally given as the arguments for Net::OAuth2::Scheme->new()), and then exports a set of specialized methods (closures) that a corresponding scheme object will need. The implementation context and intended usage determine which option values are referenced/needed and which methods will ultimately be produced.
The factory object is ephemeral and intended to be able to self-destruct as soon as the exported methods are installed on the scheme object being created.
One should generally not need to create factory objects directly, though it is intended for one to be able to design customized factory classes with their own option group definitions and implementation methods to, say, accomodate new token formats or transport schemes. See Net::OAuth2::Scheme::Option::Builder and Net::OAuth2::Scheme::Option::Defines and the various mixins Net::OAuth2::Scheme::Mixin::* for a sense of how this works [... since we're still in alpha release here, be aware that this particular part of our world may be in a bit of flux for a while...]
KINDS OF OPTIONS
There will generally be two kinds of option settings
- option_name
=>
value -
which directly sets the value of the specified option.
- group_name
=>
implementation -
which has the effect of setting an entire group of options. (Options that are members of a group can be set individually, but in most cases you shouldn't, and if you do, you need to be sure you set all of them).
implementation is either a string naming the implementation choice that this group represents or an arrayref whose first element is said implementation choice and the remaining elements are alternating keyword-value pairs, e.g.,
transport => ['bearer', param => 'oauth_second', allow_uri => 1]
which specify the settings of related options that the implementation directly depends on. Generally each keyword here will be the name of some option with some prefix stripped. E.g., the previous example is equivalent to specifying
transport => 'bearer', bearer_param => 'oauth_second', bearer_allow_uri => 1,
Group settings and single-option settings can be given in any order; nothing is executed until the context/usage is determined and a scheme object needs to be produced.
Note, however, that the usual rules for initializing perl hashes still apply here, e.g., if you specify an option setting twice in the same parameter list, the first will be silently ignored.
An option setting is regarded as constant, i.e., once an option value is actually set, it is an error to attempt to set it a different value later.
You can use the defaults
option (or defaults_all
if you are completely crazy) to change the defaults for certain options without actually setting them (if say, one of the existing defaults turns out to be stupid, or you are building a scheme template into which Other People will be inserting Actual Settings later...).
OPTIONS
Generally you will have to set one of usage
or context
to determine how/where the scheme object will be used.
For client implementations, specifying transport
should suffice. Authorization and resource servers will also need specifications for at least format
and vtable
.
Specifying option settings often entails the presence of others (e.g., once you decide on a vtable
implementation, a setting for cache
will be required, at least in all of the current implementations) which will be noted below.
Usage and Implementation Context
usage
-
This specifies the intended use of the token, one of the following
'access'
-
(Default.) An access token for use by a client to make use of a particular API at a resource server.
'refresh'
-
A refresh token for use by a client at an authorization server's token endpoint to obtain replacement access tokens.
'authcode'
-
An authorization code for use by a client at an authorization server's token endpoint to obtain access and refresh tokens.
(Strictly speaking, authorization codes are not regarded as tokens by the OAuth 2 specification, however they require the same methods as refresh tokens, i.e., they need to be created and validated. Currently authcode schemes differ from refresh token schemes only in choice of binding information, which is outside the scope of these modules, so
refresh
andauthcode
schemes are functionally identical, for now...)
Note that in OAuth2, client and resource server implementations do not, in fact, (currently) need to use scheme objects other than
usage => 'access'
ones.While client implementations do in fact see refresh tokens and authorization codes, in that context they are simply passed through as opaque strings and all questions of transport that would normally be of interest are already completely determined by the OAuth2 protocol itself, so there are no actual methods that need to be made available.
context
-
For access-token schemes, this specifies the implementation context, one or more of the following:
'client'
-
This scheme object is for use in a client implementation. The methods token_accept and http_insert will be provided.
'resource_server'
-
This scheme object is for use in a resource server implementation. The methods psgi_extract and token_validate will be provided.
'auth_server'
-
This scheme object is for use in an authorization server implementation. The token_create method will be provided.
Here, the option value can either be as single string or a listref in the case of combined implementations where the same process is serving multiple roles for whatever reason.
Note that while refresh token and authorization code schemes are only needed within an authorization server implementation, since the same server also has to be able to receive these tokens/codes, the resource-side methods need to be enabled. Thus the scheme object is produced (mostly) as if
context => [qw(auth_server, resource_server)]
were specified, meaning that any option settings that would otherwise only be necessary for a resource server implementation will be required in these cases as well.
Transport Options
The transport options determines how psgi_extract and http_insert are implemented. They concern where the token appears in a given HTTP message, the usual choices being a header field, a (POST or other) body parameter, or a URI parameter. In the event that a header field is used, the header in question will generally be "authorization-formatted", i.e., formatted as per rfc2617 and successor specifications, in which case an authorization scheme name will also need to be specified.
transport
-
The specific transport scheme to use; current available choices are:
'bearer'
-
Bearer token (draft-ietf-oauth-v2-bearer) consisting of a single (secret, unpredictable) string. The various
bearer_
options below apply and 'http_hmac'
-
HTTP-HMAC token (draft-ietf-oauth-v2-http-mac), a "proof-style" token in which the token is a string (key identifier) and two additional parameters (
nonce
,mac
) placed in an Authorization header constituting proof that the client possesses the token secret without having to actually send the secret. The varioushttp_hmac_
options below apply.
The following generic transport options are applicable to all choices of transport
implementation.
transport_header
-
if this is a transport scheme that allows the use of headers, indicates the header to be used by clients and also as the header where tokens will be recognized by resource servers if
transport_header_re
has not been set.Default is
"Authorization"
. transport_header_re
-
regexp; if this is a transport scheme that allows the use of headers, the resource server will recognize tokens in headers whose names match this pattern.
transport_auth_scheme
-
if this is a transport scheme that calls for an Authorization-formatted header, indicates the authorization scheme to be used by clients and also the scheme that will be recognized by resource servers if
transport_auth_scheme_re
has not been set. transport_auth_scheme_re
-
regexp; if this is a transport scheme that calls for an authorization-formatted header, the resource server will recognize tokens in headers whose authorization scheme matches this pattern.
The following options apply when transport => 'bearer'
is selected and can be included with the bearer_
prefix omitted, e.g.,
transport => ['bearer', allow_body => 1],
bearer_allow_body
-
boolean; if true, (default) resource server will recognize tokens located in the request body, otherwise, request body will be ignored when searching for tokens.
bearer_allow_uri
-
boolean; if true, resource server will recognize tokens located in the request URI, otherwise, (default) request URI will be ignored when searching for tokens.
bearer_client_uses_param
-
boolean; if true, client send the token as a body or URI parameter (use whichever is available as per
bearer_allow_body
orbearer_allow_uri
, preferring body), rather than a header, otherwise, (default) client will send the token in an authorization-formatted header. bearer_header
-
clients place tokens in this (authorization-formatted) header. This also serves as the default header where resource servers look for tokens if
bearer_header_re
is not set. Default is'Authorization'
. bearer_header_re
-
regexp; resource server looks for tokens in headers whose names match this
bearer_param
-
name of body or URI parameter for client to use if either
allow_uri
orallow_body
is set andbearer_client_uses_param
is set. This also serves as the default parameter name the resource server looks for ifbearer_param_re
is not set. Default is'oauth_token'
. bearer_param_re
-
regexp; if
allow_uri
orallow_body
is set, resource server should look for tokens in parameters with matching names. bearer_scheme
-
if authorization-formatted headers are called for, client will use this authorization scheme. This also serves as the default pattern for the scheme that resource servers will recognize if
bearer_scheme_re
is not set. Default is'Bearer'
. bearer_scheme_re
-
regexp; resource server recognizes tokens in authorization-formatted headers whose scheme matches this pattern.
bearer_token_type
-
authorization server sets and client should expect this value of
token_type
in @token_as_issued. Default is'Bearer'
.
The following options apply when transport => 'http_hmac'
is selected and can be included with the http_hmac_
prefix omitted (e.g., transport => ['http_hmac', header => 'X-HTTP-HMAC']
):
http_hmac_header
-
clients place tokens in this header field. This also serves as the default header where resource servers look for tokens if
http_hmac_header_re
is not set. Default is'Authorization'
. http_hmac_header_re
-
regexp; resource server looks for tokens in headers whose names match this pattern.
http_hmac_scheme
-
client will use this authorization scheme. This also serves as the default pattern for the scheme that resource servers will recognize if
http_hmac_scheme_re
is not set. Default is'MAC'
. http_hmac_scheme_re
-
regexp; resource server will recognize tokens in authorization-formatted headers whose scheme matches this pattern.
http_hmac_nonce_length
-
length of nonce that clients should generate
http_hmac_token_type
-
authorization server sets and client should expect this value of
token_type
in @token_as_issued. Default is'mac'
.
Acceptance Options
The following options customize the behavior of token_accept:
accept_keep
-
listref of keywords or
'everything'
; indicating which values should be included in @token_as_saved.'everything'
indicates that all available keywords should be included except for those specified inaccept_remove
. Default is'everything'
accept_remove
-
listref of keywords; indicates which values token_accept should exclude from @token_as_saved in the case where
accept_keep
is indicating that everything should be kept by default; this option is ignored, otherwise. Default is['expires_in', 'scope', 'refresh_token']
Format Options
The following options determine the format/encoding of a token and the binding information that it includes, if there is a choice about this.
format
-
This is an option group, providing
token_create
,token_parse
, andtoken_finish
. Choices are'bearer_handle'
-
Use a "handle-style" bearer token where the token string is a random base64url string with no actual content. Expiration information and all binding values must live in the vtable and need to be communicated out of band to the resource server. Implies
v_id => 'random'
. 'bearer_signed'
-
Use a "assertion-style" bearer token where the token string includes some or all of the binding values, a nonce, and a hash value keyed on a shared secret that effectively signs everything. Only the shared secret and remaining binding values needs to be kept in the vtable and communicated out of band to the resource server.
'hmac_http'
-
Implements the formatting portion of draft-ietf-oauth-v2-http-mac (see description under
transport_hmac_http
). Expiration information and all binding data live in the vtable and must be communicated out of band to the resource server, as for'bearer_handle'
formatted tokens.
The following options apply when format => bearer_signed
is selected and can be included with the bearer_signed_
prefix omitted (e.g., transport => ['bearer_signed', hmac => 'hmac_sha256']
).
(bearer_signed_)hmac
-
HMAC algorithm to use for signing tokens. Default is
'hmac_sha224'
. (bearer_signed_)nonce_length
-
integer; length (bytes) of random nonce/salt material to be included in the token. Default is half of the keylength of the chosen HMAC algorithm.
(bearer_signed_)fixed
-
listref; initial sequence of bound values that must always be the same (and are thus never included with the token). Setting this to a nonempty list causes token_create to fail when @bindings does not begin with these values in the specified order, and causes token_validate to always return a @bindings list beginning with these values. Default is an empty list.
The following options apply when format => http_hmac
is selected and can be included with the http_hmac_
prefix omitted (e.g., transport => ['http_hmac', hmac => 'hmac_sha256']
).
Validator Table (vtable) Options
The validator table or "vtable" is the mechanism via which secrets are communicated from the authorization server to the resource server.
Conceptually, it is a shared cache, for which two functions are exposed to the formatting group: vtable_insert
, which the authorization server uses to write new secrets and binding values to the cache, and vtable_lookup
, which the resource server uses to obtain these values as needed to validate a given token and return the bindings and expiration data associated with it.
vtable
-
Determines which vtable implementation paradigm to use, one of:
-
The cache is an actual (secure) shared cache, accessible to both the authorization server and the resource server, whether this be, say,
a memcached server (or a farm thereof) mutually accessible to authorization and resource servers, which can then live on entirely different hosts or even distinct network sites
a file-based cache (e.g., Cache::File), which requires authorization and resource servers to either be on the same host or have access to the same file server
a shared-memory-segment cache (e.g., Cache::Memory), which requires authorization and resource servers to either be on the same host.
some kind of shared internal reference in the case where the authorization and resource requests are handled by the same process.
vtable_insert
andvtable_lookup
translate directly tovtable_put
andvtable_get
(seevtable-cache
below) with no additional machinery. Secrets inserted by the authorization server just become automatically available immediately on the resource server, and we don't have to know exactly how the communication happens because the cache implementer already took care of that for us. 'authserv_push'
-
There is a cache, but it is local/private to the resource server.
vtable_insert
by the authorization server is actually vtable_push which sends the new entry to the resource server by some means. A push-handler in the resource server receives the entry and calls vtable_pushed to insert it into the actual cache, and either token_create blocks until the push response is received or (if you care about speed and can tolerate the occasional race condition failure) we just assume the resource server has enough of a head start that the insertion will be completed by the time the client gets around to actually using the token.vtable_lookup
by the resource server is then justvtable_get
.The function vtable_push must be supplied in the authorization server implementation. There must also be a resource server push endpoint with a handler that calls the the scheme object's vtable_pushed method on whatever (opaque list) value receives, sending back as a response whatever return value (null or error code) it gets.
'resource_pull'
-
There is a cache, but it is (again) local/private to the resource server.
vtable_insert
by the authorization server doesvtable_enqueue
, which just places the entry on an internal queue.vtable_lookup
, when called by the resource server, does the followinga call to
vtable_get
, which may succeed or fail. Failure is immediately followed bya call to
vtable_pull
which is expected to send a query to the authorization server.A pull handler on the authorization server then calls
vtable_dump
to flush the contents of the internal queue and incorporate this list value into a response back to the resource server.vtable_pull
then receives that response, extracts the reply list value and returns it, at which pointvtable_load
can then load the new entries into the resource server's cache and thenvtable_get
can be retried.
The function vtable_pull must be supplied.
The function vtable_dump is available on the scheme object to the authorization server implementation. Its argument is expected to be the query value received by the pull-handler, and its return value is to be included in the response to the pull request.
-
vtable_pull
-
coderef; implementation for vtable_pull as used/required by
vtable => resource_pull
in a resource server implementation. It takes an arbitrary opaque list of arguments, sends them to the authorization server's resource_pull endpoint, collects the (opaque list) response it receives and returns it, or returns a one-element error-code list if the send fails. vtable_push
-
coderef; implementation for vtable_push as used/required by
vtable => authserv_push
in an authorization server implementation. It takes an arbitrary opaque list of arguments, sends them to the resource server's authserv_push endpoint, collects the success or error-code response that it receives, and returns null or the error code accordingly. vtable_cache
-
The low-level cache interface; provides
vtable_get
andvtable_put
methods. The default implementation is(...some day there may also be a straight hash-reference implementation for those cases where response and authorization server are the same process and somebody wants to be ultra-secure by not even allowing the cache into shared memory... but I'm not going to worry about this for now...)
vtable_pull_queue
-
Determines how the queue for
vtable => resource_pull
, is implemented. (implementation is a matter of supplying four functionsvtable_enqueue
,vtable_dump
,vtable_query
, andvtable_load
).Current choices are
Current Secret Options
For format => bearer_signed
(and possibly other uses later), there is a shared secret that needs to be communicated out of band to the resource server and that needs to be expired and regenerated every so often. Generally, there will be two secrets active at any given time (since after regeneration, we keep the old one around and continue to honor tokens generated from it until it expires).
current_secret_length
-
integer; number of bytes in the share secret
current_secret_rekey_interval
-
integer; number of seconds before expiration that the current secret gets regenerated.
current_secret_lifetime
-
integer (default is twice
current_secret_rekey_interval
); secrets are to expire this many seconds after being regenerated.
Cache Options
The following options apply when vtable_cache => object
is chosen
cache
-
The actual cache object to use, some object that implements the Cache interface, specifically
get()
and the 3-argumentset()
. cache_grace
-
integer; setting this causes actual expiration times for items in the cache to be set this many seconds beyond the stated expiration time, i.e., so that the cache retains expired entries this much longer. This also similarly extends the time that items are kept in the queue for
vtable_pull_queue => default
. cache_prefix
-
a string that is prefixed to all vtable cache keys. If you are using this same cache for other purposes than holding vtable entries, make sure that said other purposes use different prefixes or at least that this prefix is chosen so that no vtable entry will be confused with an entry made for some other purpose. Default is
"vtab:"
.
Vtable ID Generation Options
The following options govern the generation of keys for vtable entries.
v_id
-
one of
'counter'
['counter', tag ]
-
generate sequential IDs using a counter. Providing tag sets
counter_tag
(which see). 'random'
['random', n ]
-
generate random IDs using the random number generator. Providing n sets
v_id_random_length
, which needs to be large enough so as to make collisions between random IDs as unlikely as feasible over the lifetime of the tokens produced by this scheme.
The default is
'counter'
unless the scheme is one (e.g.,'bearer_handle'
) that explicitly requires unpredictable IDs.Note that random IDs currently begin with a 0-127 byte while counter IDs begin with a 128-255 byte, so no random ID should ever collide with a counter ID. Likewise, counter IDs generated from the same
counter_tag
are guaranteed not to collide. v_id_random_length
-
integer; for when
v_id => 'random'
, the number of random bytes to use when creating the ID (must be at least 8). Note that the ID ultimately created will generally be longer than this, both due to the possible inclusion ofv_id_suffix
and any encoding (e.g., base64url) that may be needed. counter_tag
-
(default
''
) for whenv_id => 'counter'
, a string tag identifying which counter to use. A fresh counter will be initialized if the specified tag has not been seen before. v_id_suffix
-
(default
''
) is added to the end of every ID generated in this scheme. The main use of this is to distinguish (and thus prevent collisions between) IDs generated by multiple hosts in the situation where there are multiple authorization servers issuing tokens for the same resource.
Note that the counter associated with a given tag is guaranteed to produce distinct IDs on each invocation during an arbitrary 194-day (2^24 second) window around the time of invocation, regardless of which process or thread/PerlInterpreter it is invoked from.
Therefore all schemes using the same cache object with the same cache_tag
and the same v_id_suffix
should be sure to use the same counter tag in order not to have ID collisions when v_id => 'counter'
(For v_id => 'random'
, one has to rely that the ID is sufficiently long to make collisions extremely unlikely.)
Random Number Generator Options
The random number generator is used for generation of vtable IDs, nonces, secrets, and other unpredictable artifacts that need to be created.
random_class
-
package name; currently
'Math::Random::ISAAC'
and'Math::Random::MT::Auto'
(Mersenne Twister) are supported. random
-
coderef; takes an integer and returns a string of that many random bytes
AUTHOR
Roger Crew <crew@cs.stanford.edu>
COPYRIGHT AND LICENSE
This software is copyright (c) 2012 by Roger Crew.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.