The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Net::OAuth2::Scheme::Factory - the default factory for token schemes

VERSION

version 0.010004_004

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 and authcode 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 various http_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 or bearer_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 or allow_body is set and bearer_client_uses_param is set. This also serves as the default parameter name the resource server looks for if bearer_param_re is not set. Default is 'oauth_token'.

bearer_param_re

regexp; if allow_uri or allow_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 in accept_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, and token_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.

'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']).

http_hmac_hmac (format/http_hmac)

The HMAC algorithm to be used.

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:

'shared_cache'

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 and vtable_lookup translate directly to vtable_put and vtable_get (see vtable-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 just vtable_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 does vtable_enqueue, which just places the entry on an internal queue.

vtable_lookup, when called by the resource server, does the following

  • a call to vtable_get, which may succeed or fail. Failure is immediately followed by

  • a 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 point

  • vtable_load can then load the new entries into the resource server's cache and then

  • vtable_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 and vtable_put methods. The default implementation is

'object'

which requires cache to be set as described below.

(...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 functions vtable_enqueue, vtable_dump, vtable_query, and vtable_load).

Current choices are

'default'

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-argument set().

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 "vtab:"

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 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.

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.

v_id_random_length

integer; for when v_id => 'random', the number of random bytes to include (must be at least 8).

counter_tag

(default '') for when v_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 for when there are to be 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.