hadley 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ doc/*
6
+ .yardoc/*
@@ -0,0 +1 @@
1
+ --protected lib/**/*.rb ext/**/*.c README.rdoc
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2012 Sean M. Duncan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ == Welcome to Hadley
2
+
3
+ Hadley is rack middleware built on top of the excellent security authentication middleware warden. Hadley enables
4
+ Rack-based web applications to easily become AFID protected resource servers.
5
+
6
+
7
+ == Getting Started
8
+
9
+ Rails:
10
+
11
+ 1. Add <tt>gem 'hadley'</tt> to your Gemfile
12
+
13
+ 2. Run <tt>bundle</tt> from your project root
14
+
15
+ 3. Run <tt>touch config/initializers/hadley.rb</tt> from your project root
16
+
17
+ 4. Add warden and hadley to your middleware stack by opening <tt>config/initializers/hadlery.rb</tt> in your favorite text editor and adding the following:
18
+
19
+ token_store = Hadley::TokenStore.new(Rails.cache)
20
+
21
+ MyApp::Application.config.middleware.insert_after ActionDispatch::Session::CookieStore, Warden::Manager do |manager|
22
+ # setup authentication for the afid server to provision and revoke access tokens
23
+ manager.basic(:server) do |basic|
24
+ basic.hash_credentials true
25
+ basic.lookup do |id, secret|
26
+ [ id, secret ] == [ 'my_hashed_id', 'my_hashed_secret' ] ? id : nil
27
+ end
28
+ end
29
+ # setup authentication for afid clients to authenticate in anonymous mode (client_credentials grant type in OAuth2
30
+ # parlance)
31
+ manager.bearer(:client) do |bearer|
32
+ bearer.token_store token_store
33
+ bearer.anonymous_allowed true
34
+ end
35
+ # setup authentication for afid clients to access apis on behalf of a particular user (authorization_grant grant
36
+ # type in OAuth2 parlance)
37
+ manager.bearer(:user) do |bearer|
38
+ bearer.token_store token_store
39
+ bearer.anonymous_allowed false
40
+ end
41
+ end
42
+
43
+ MyApp::Application.config.middleware.insert_after Warden::Manager, Hadley::Middleware, token_store: token_store
44
+
45
+ 5. Run <tt>rake middleware</tt> from your project root and verify that <tt>Warden::Manager</tt> appears after <tt>ActionDispatch::Session::CookieStore</tt> and <tt>Hadley::Middleware</tt> appears after <tt>Warden::Manager</tt>
data/config.ru CHANGED
@@ -29,7 +29,7 @@ class ExampleResourceServer < Sinatra::Base
29
29
 
30
30
  use Warden::Manager do |manager|
31
31
  manager.basic(:server) do |basic|
32
- basic.hash_credentials = true
32
+ basic.hash_credentials true
33
33
  basic.lookup do |id, secret|
34
34
  [ id, secret] == [
35
35
  'a8ab10237100f16d12b6c8e574e84b92cc15aecaced04d47251a5f34ffaa0e60',
@@ -38,12 +38,12 @@ class ExampleResourceServer < Sinatra::Base
38
38
  end
39
39
  end
40
40
  manager.bearer(:client) do |bearer|
41
- bearer.token_store = token_store
42
- bearer.anonymous_allowed = true
41
+ bearer.token_store token_store
42
+ bearer.anonymous_allowed true
43
43
  end
44
44
  manager.bearer(:user) do |bearer|
45
- bearer.token_store = token_store
46
- bearer.anonymous_allowed = false
45
+ bearer.token_store token_store
46
+ bearer.anonymous_allowed false
47
47
  end
48
48
  end
49
49
 
@@ -17,6 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = [ 'lib' ]
19
19
 
20
+ s.add_development_dependency 'yard'
21
+ s.add_development_dependency 'yard-sinatra'
20
22
  s.add_development_dependency 'rspec'
21
23
  s.add_development_dependency 'active_support'
22
24
  s.add_development_dependency 'dalli'
@@ -2,6 +2,7 @@ autoload :Rack, 'rack'
2
2
  autoload :Sinatra, 'sinatra/base'
3
3
  autoload :Warden, 'warden'
4
4
 
5
+ # This module is a namespace for all modules and classes related to the AFID resource server rack middleware
5
6
  module Hadley
6
7
 
7
8
  autoload :Authz, 'hadley/authz'
@@ -10,8 +11,10 @@ module Hadley
10
11
  autoload :TokenStore, 'hadley/token_store'
11
12
  autoload :Utils, 'hadley/utils'
12
13
 
13
- VERSION = '0.0.2'
14
+ # The current version of this ruby gem
15
+ VERSION = '0.0.3'
14
16
 
17
+ # The identity key for the AFID anonymous identity
15
18
  ANONYMOUS_IDENTITY = '0' * 66
16
19
 
17
20
  end
@@ -1,53 +1,23 @@
1
+ # This module is both a namespace for modules and classes related to AFID authorization and a collection of useful
2
+ # helper methods that can be mixed in to application controllers / route handlers that need to interact with warden and
3
+ # AFID authorization details.
1
4
  module Hadley::Authz
2
5
 
6
+ autoload :StrategyBuilder, 'hadley/authz/strategy_builder'
7
+ autoload :Strategy, 'hadley/authz/strategy'
3
8
  autoload :Basic, 'hadley/authz/basic'
4
9
  autoload :Bearer, 'hadley/authz/bearer'
5
10
 
11
+ # A wrapper method that allows cleaner access to the warden proxy
12
+ #
13
+ # @return [Warden::Proxy] The warden lazy object equivalent to <tt>env['warden']</tt>.
6
14
  def warden
7
15
  env['warden']
8
16
  end
9
17
 
10
- module StrategyBuilder
11
-
12
- def build(name, config)
13
- strategy = self.create_strategy(name)
14
- self.register_strategy(name, strategy)
15
- self.set_config(strategy, config)
16
- end
17
-
18
- protected
19
-
20
- def create_strategy(name)
21
- class_name = Hadley::Utils.camelize(name.to_s)
22
- if self.const_defined?(class_name)
23
- self.const_get(class_name)
24
- else
25
- self.const_set(class_name, Class.new(self))
26
- end
27
- end
28
-
29
- def register_strategy(name, strategy)
30
- full_name = "afid_#{name}".to_sym
31
- if Warden::Strategies[full_name].nil?
32
- Warden::Strategies.add(full_name, strategy)
33
- end
34
- end
35
-
36
- def set_config(strategy, config)
37
- strategy.const_set("CONFIG", config) unless strategy.const_defined?("CONFIG")
38
- end
39
-
40
- end
41
-
42
- class Strategy < Warden::Strategies::Base
43
- extend StrategyBuilder
44
-
45
- def config
46
- self.class.const_get("CONFIG")
47
- end
48
- end
49
-
18
+ # Add the warden config extension for the Basic authorization strategy
50
19
  Warden::Config.send(:include, Hadley::Authz::Basic::ConfigExtension)
20
+ # Add the warden config extension for the Bearer authorization strategy
51
21
  Warden::Config.send(:include, Hadley::Authz::Bearer::ConfigExtension)
52
22
 
53
23
  end
@@ -1,56 +1,77 @@
1
- module Hadley
2
-
3
- module Authz
1
+ # This module is a namespace for modules and classes related to the HTTP Basic authorization strategy.
2
+ module Hadley::Authz::Basic
4
3
 
5
- module Basic
4
+ # This class is the prototype class for all HTTP Basic authorization strategies used by hadley.
5
+ class Strategy < Hadley::Authz::Strategy
6
6
 
7
- class Strategy < Hadley::Authz::Strategy
7
+ # Provides access to the HTTP Basic Auth information assiciated with the current request.
8
+ #
9
+ # @return [Rack::Aauth::Basic::Request] The HTTP Basic Auth information associated with the current request.
10
+ def auth
11
+ @auth ||= Rack::Auth::Basic::Request.new(env)
12
+ end
8
13
 
9
- def auth
10
- @auth ||= Rack::Auth::Basic::Request.new(env)
11
- end
14
+ # Identifies whether a login using this strategy should be persisted across multiple requests.
15
+ #
16
+ # @see Warden::Strategies::Base#store?
17
+ #
18
+ # @return [Boolean] true if and only if a login using this strategy should be persistent across multiple requests.
19
+ def store?
20
+ false
21
+ end
12
22
 
13
- def store?
14
- false
15
- end
23
+ # Authenticates the entity identified by the provided HTTP Basic Auth information
24
+ def authenticate!
25
+ return unauthorized unless auth.provided? and auth.basic? and auth.credentials
26
+ credentials = auth.credentials.map do |credential|
27
+ config.hash_credentials ? Digest::SHA2.new(256).update(credential).to_s : credential
28
+ end
29
+ user = config.lookup.call(credentials.first, credentials.last)
30
+ return user ? success!(auth.credentials.first) : unauthorized
31
+ end
16
32
 
17
- def authenticate!
18
- return unauthorized unless auth.provided? and auth.basic? and auth.credentials
19
- credentials = auth.credentials.map do |credential|
20
- config.hash_credentials ? Digest::SHA2.new(256).update(credential).to_s : credential
21
- end
22
- user = config.lookup.call(credentials.first, credentials.last)
23
- return user ? success!(auth.credentials.first) : unauthorized
24
- end
33
+ private
25
34
 
26
- def unauthorized
27
- custom!(Rack::Response.new([config.fail_message], 401, { 'WWW-Authenticate' => %Q{Basic realm="#{config.realm}"} }))
28
- end
35
+ # Renders a custom HTTP 401 Unauthorized response with the appropriate challenge.
36
+ def unauthorized
37
+ custom!(Rack::Response.new([config.fail_message], 401, { 'WWW-Authenticate' => %Q{Basic realm="#{config.realm}"} }))
38
+ end
29
39
 
30
- end
40
+ end
31
41
 
32
- module ConfigExtension
33
-
34
- def basic(name, &block)
35
- config = Hadley::Config.new(
36
- realm: 'Access Tokens',
37
- fail_message: 'Authorization Failed',
38
- hash_credentials: false
39
- )
40
- if block_given?
41
- if block.arity == 1
42
- yield config
43
- else
44
- config.instance_eval(&block)
45
- end
46
- end
47
- Hadley::Authz::Basic::Strategy.build(name, config) unless config.lookup.nil?
42
+ # This module provides the configuration extension to Warden allowing for ease of configuration for basic auth
43
+ # strategies via the following syntax:
44
+ #
45
+ # use Warden::Manager do |manager|
46
+ # manager.basic(:server) do |basic|
47
+ # basic.hash_credentials true
48
+ # basic.lookup do |id, secret|
49
+ # [ id, secret] == [ 'client_identity', 'client_secret' ] ? id : nil
50
+ # end
51
+ # end
52
+ # end
53
+ module ConfigExtension
54
+
55
+ # Configures and registers and new basic authorization strategy.
56
+ #
57
+ # @param [Symbol] name The unqualified name for the new basic authorization strategy.
58
+ # @param [Hadley::Config] config The configuration specific to the new basic authorization strategy.
59
+ def basic(name, &block)
60
+ config = Hadley::Config.new(
61
+ realm: 'Access Tokens',
62
+ fail_message: 'Authorization Failed',
63
+ hash_credentials: false
64
+ )
65
+ if block_given?
66
+ if block.arity == 1
67
+ yield config
68
+ else
69
+ config.instance_eval(&block)
48
70
  end
49
-
50
71
  end
51
-
72
+ Hadley::Authz::Basic::Strategy.build(name, config) unless config.lookup.nil?
52
73
  end
53
-
74
+
54
75
  end
55
76
 
56
77
  end
@@ -1,11 +1,19 @@
1
+ # This module is a namespace for modules and classes related to bearer token based custom rack authorization requests
1
2
  module Rack::Auth::Bearer
2
3
 
4
+ # This class represents a custom rack authorization request type for bearer token based authorization
3
5
  class Request < Rack::Auth::AbstractRequest
4
6
 
7
+ # Provides a means to determin if the current requests authorization type is 'Bearer'.
8
+ #
9
+ # @return [Boolean] true if and only if the current requests authorization type is 'Bearer'.
5
10
  def bearer?
6
11
  :bearer == scheme
7
12
  end
8
13
 
14
+ # Provides access to the bearer token associated with the current request.
15
+ #
16
+ # @return [String] The token assiciated with the current request.
9
17
  def token
10
18
  @token ||= params.split(' ', 2).first
11
19
  end
@@ -14,59 +22,76 @@ module Rack::Auth::Bearer
14
22
 
15
23
  end
16
24
 
17
- module Hadley
18
-
19
- module Authz
25
+ # This module is a namespace for modules and classes related to bearer token based authorization strategies.
26
+ module Hadley::Authz::Bearer
20
27
 
21
- module Bearer
28
+
29
+ class Strategy < Hadley::Authz::Strategy
22
30
 
23
- class Strategy < Hadley::Authz::Strategy
24
-
25
- def auth
26
- @auth ||= Rack::Auth::Bearer::Request.new(env)
27
- end
31
+ # Provides access to the bearer token based auth information assiciated with the current request.
32
+ #
33
+ # @return [Rack::Aauth::Bearer::Request] The bearer token based auth information assiciated with the current request.
34
+ def auth
35
+ @auth ||= Rack::Auth::Bearer::Request.new(env)
36
+ end
28
37
 
29
- def store?
30
- false
31
- end
38
+ # Identifies whether a login using this strategy should be persisted across multiple requests.
39
+ #
40
+ # @see Warden::Strategies::Base#store?
41
+ #
42
+ # @return [Boolean] true if and only if a login using this strategy should be persistent across multiple requests.
43
+ def store?
44
+ false
45
+ end
32
46
 
33
- def authenticate!(anonymous_allowed=false)
34
- return unauthorized unless auth.provided? and auth.bearer? and auth.token
35
- user = config.token_store.get(auth.token)
36
- return unauthorized unless user and (!user[:anonymous] or config.anonymous_allowed)
37
- success!(user)
38
- end
47
+ # Authenticates the entity identified by the provided bearer token.
48
+ def authenticate!(anonymous_allowed=false)
49
+ return unauthorized unless auth.provided? and auth.bearer? and auth.token
50
+ user = config.token_store.get(auth.token)
51
+ return unauthorized unless user and (!user[:anonymous] or config.anonymous_allowed)
52
+ success!(user)
53
+ end
39
54
 
40
- private
55
+ private
41
56
 
42
- def unauthorized
43
- custom!(Rack::Response.new([config.fail_message], 401, { 'WWW-Authenticate' => %Q{Bearer realm="#{config.realm}"} }))
44
- end
57
+ # Renders a custom HTTP 401 Unauthorized response with the appropriate challenge.
58
+ def unauthorized
59
+ custom!(Rack::Response.new([config.fail_message], 401, { 'WWW-Authenticate' => %Q{Bearer realm="#{config.realm}"} }))
60
+ end
45
61
 
46
- end
62
+ end
47
63
 
48
- module ConfigExtension
49
-
50
- def bearer(name, &block)
51
- config = Hadley::Config.new(
52
- realm: 'Access Tokens',
53
- fail_message: 'Authorization Failed',
54
- anonymous_allowed: false
55
- )
56
- if block_given?
57
- if block.arity == 1
58
- yield config
59
- else
60
- config.instance_eval(&block)
61
- end
62
- end
63
- Hadley::Authz::Bearer::Strategy.build(name, config) unless config.token_store.nil?
64
+ # This module provides the configuration extension to Warden allowing for ease of configuration for bearer token
65
+ # based authorization strategies via the following syntax:
66
+ #
67
+ # use Warden::Manager do |manager|
68
+ # manager.bearer(:server) do |bearer|
69
+ # bearer.token_store token_store
70
+ # bearer.anonymous_allowed true
71
+ # end
72
+ # end
73
+ module ConfigExtension
74
+
75
+ # Configures and registers and new bearer token based authorization strategy.
76
+ #
77
+ # @param [Symbol] name The unqualified name for the new bearer token based authorization strategy.
78
+ # @param [Hadley::Config] config The configuration specific to the new bearer token based authorization strategy.
79
+ def bearer(name, &block)
80
+ config = Hadley::Config.new(
81
+ realm: 'Access Tokens',
82
+ fail_message: 'Authorization Failed',
83
+ anonymous_allowed: false
84
+ )
85
+ if block_given?
86
+ if block.arity == 1
87
+ yield config
88
+ else
89
+ config.instance_eval(&block)
64
90
  end
65
-
66
91
  end
67
-
92
+ Hadley::Authz::Bearer::Strategy.build(name, config) unless config.token_store.nil?
68
93
  end
69
-
94
+
70
95
  end
71
96
 
72
97
  end
@@ -0,0 +1,11 @@
1
+ # This class is a base class for authorization strategies
2
+ class Hadley::Authz::Strategy < Warden::Strategies::Base
3
+ extend Hadley::Authz::StrategyBuilder
4
+
5
+ # Provides access to the configuration for this authorization strategy.
6
+ #
7
+ # @return [Hadley::Config] the configuration for this authorization strategy.
8
+ def config
9
+ self.class.const_get("CONFIG")
10
+ end
11
+ end
@@ -0,0 +1,51 @@
1
+ # This mixin module provides helpful utilties for generating new authorization strategies based on configuration
2
+ # provided when the strategy is being registered with Warden.
3
+ module Hadley::Authz::StrategyBuilder
4
+
5
+ # Builds a new authorization strategy class based on the provided configuration.
6
+ #
7
+ # @param [Symbol] name The unqualified name of the authorization strategy to be built.
8
+ # @param [Hadley::Config] config The configuration for the authorization strategy to be built.
9
+ def build(name, config)
10
+ strategy = self.create_strategy(name)
11
+ self.register_strategy(name, strategy)
12
+ self.set_config(strategy, config)
13
+ end
14
+
15
+ protected
16
+
17
+ # Creates the strategy class based on the provided name. The class will be namespaced under the class that
18
+ # these methods are mixed into.
19
+ #
20
+ # @param [Symbol] name The unqualified name of the authorization strategy to be built.
21
+ #
22
+ # @return [Class] The new strategy class.
23
+ def create_strategy(name)
24
+ class_name = Hadley::Utils.camelize(name.to_s)
25
+ if self.const_defined?(class_name)
26
+ self.const_get(class_name)
27
+ else
28
+ self.const_set(class_name, Class.new(self))
29
+ end
30
+ end
31
+
32
+ # Registers the new authorization strategy with Warden under the specified name prefixed by 'afid_'.
33
+ #
34
+ # @param [Symbol] name The unqualified name of the authorization strategy to be built.
35
+ # @param [Class] strategy The newly created strategy class.
36
+ def register_strategy(name, strategy)
37
+ full_name = "afid_#{name}".to_sym
38
+ if Warden::Strategies[full_name].nil?
39
+ Warden::Strategies.add(full_name, strategy)
40
+ end
41
+ end
42
+
43
+ # Binds the configuration information to the newly created strategy class.
44
+ #
45
+ # @param [Class] strategy The newly created strategy class.
46
+ # @param [Hadley::Config] config The configuration to be bound to the authorization strategy.
47
+ def set_config(strategy, config)
48
+ strategy.const_set("CONFIG", config) unless strategy.const_defined?("CONFIG")
49
+ end
50
+
51
+ end
@@ -1,28 +1,70 @@
1
+ # This class is a convenience wrapper around an Hash that provides a more expressive api for initial configuration and
2
+ # referencing the configuration information at runtime. For example:
3
+ # config.prop 'value' # --> config[:prop] = 'value'
4
+ # config.prop = 'value' # --> same as above
5
+ # config.props 'a', 'b', 'c' # --> config[:props] = [ 'a', 'b', 'c' ]
6
+ # config.props = 'a', 'b', 'c' # same as above
7
+ # config.callback { |it| puts it } # config[:callback] = { |it| puts it }
8
+ # config.prop # --> config[:prop]
1
9
  class Hadley::Config
2
10
 
3
- def initialize(config={})
4
- @config = config
11
+ # Initializes this Config with the specified defaults.
12
+ #
13
+ # @param [Hash] defaults The default configuration values for this Config instance.
14
+ def initialize(defaults={})
15
+ @config = defaults
5
16
  end
6
17
 
18
+ # Delegates to {#set}, {#get} or {#proc} depending on the nature of the given name, if a block is given or if the args
19
+ # array is not empty.
20
+ #
21
+ # @param [String] name The name of the property to be read or written. If the name ends with '=' it will be stripped
22
+ # from the name and the operation will be treated as a write.
23
+ # @param [*Object] args The optional array of property values to be assigned to the provided property name. If this
24
+ # array is not empty then {#set} will be called.
25
+ # @param [Proc] &block The optional block to be assigned to the provided property name. If the operation has a block
26
+ # given then {#proc} will be called.
27
+ #
28
+ # @return [Object,nil] The value ultimately written to or read from the given property name.
7
29
  def method_missing(name, *args, &block)
8
30
  if block_given?
9
31
  proc(name, &block)
10
32
  elsif name =~ /(.+)=$/
11
- set($1, *args, &block)
33
+ set($1, *args)
34
+ elsif not args.empty?
35
+ set(name, *args)
12
36
  else
13
- get(name, &block)
37
+ get(name)
14
38
  end
15
39
  end
16
40
 
41
+ # Stores the given block under the provided property name.
42
+ #
43
+ # @param [String] name The name of the property to be written.
44
+ # @param [Proc] &block The block to be assigned to the provided property name.
45
+ #
46
+ # @return [Proc] The block written to the provided name.
17
47
  def proc(name, &block)
18
48
  @config[name.to_sym] = block
19
49
  end
20
50
 
51
+ # Stores the value or values indicated by the args array under the provided property name.
52
+ #
53
+ # @param [String] name The name of the property to be written.
54
+ # @param [*Object] args The value or values to be assigned to the provided property name. If a single value is found
55
+ # a scalar will be written otherwise an array will be written.
56
+ #
57
+ # @return [Object,nil] The value written to the provided name.
21
58
  def set(name, *args)
22
59
  @config[name.to_sym] = args.size == 1 ? args.first : args
23
60
  end
24
61
 
25
- def get(name, &block)
62
+ # Retrieves the value stored under the provided name.
63
+ #
64
+ # @param [String] name The name of the property to be read.
65
+ #
66
+ # @return [Object,nil] The value stored under the provided name or nil if no such value exists.
67
+ def get(name)
26
68
  @config[name.to_sym]
27
69
  end
28
70
 
@@ -1,9 +1,15 @@
1
+ # This class provides the rack middleware that builds on top of warden to provide the necessary endpoints for a rack
2
+ # application to function as an AFID protected resource.
1
3
  class Hadley::Middleware < Sinatra::Base
2
4
 
3
5
  include Hadley::Authz
4
6
 
5
- attr_reader :confg
6
-
7
+ # Initializes the middleware with the provided application and options
8
+ #
9
+ # @param [Rack::Application] app The rack application that this middleware is participating in
10
+ # @param [Hash] options The Hash of keyword arguments
11
+ # @param [Hadley::TokenStore] options.store The token store to be used for persisting tokens provisioned by the AFID
12
+ # authorization server
7
13
  def initialize(app=nil, options={})
8
14
  super(app)
9
15
  @config ||= Hadley::Config.new(options)
@@ -12,10 +18,7 @@ class Hadley::Middleware < Sinatra::Base
12
18
  self
13
19
  end
14
20
 
15
- # ------------------------------------------
16
- # Routes
17
- # ------------------------------------------
18
-
21
+ # The required endpoint for provisioning AFID access tokens.
19
22
  put '/access/tokens/:token' do |token|
20
23
  warden.authenticate!(:afid_server)
21
24
  begin
@@ -30,6 +33,7 @@ class Hadley::Middleware < Sinatra::Base
30
33
  end
31
34
  end
32
35
 
36
+ # The required endpoint for invalidating AFID access tokens.
33
37
  delete '/access/tokens/:token' do |token|
34
38
  warden.authenticate!(:afid_server)
35
39
  begin
@@ -1,13 +1,23 @@
1
+ # This class handles the storage, retrieval and removal of OAuth 2 bearer tokens sent from the AFID authorization
2
+ # server. The TokenStore delegates most of the work to the delegate store, which must support the api set forth by
3
+ # ActiveSupport::Cache::Store.
1
4
  class Hadley::TokenStore
2
5
 
6
+ # This method initializes the TokenStore with the delegate store.
7
+ #
8
+ # @param [ActiveSupport::Cache::Store] store The TokenStore instance will delegate the heavy lifting to the provided
9
+ # store.
3
10
  def initialize(store)
4
11
  @store = store
5
12
  end
6
13
 
7
- def key_for(token)
8
- "afid-access-token:#{token}"
9
- end
10
-
14
+ # This method retrieves the AFID identity information associated with the provided token. If no such identity is
15
+ # found the result will be nil.
16
+ #
17
+ # @param [String] token The unique token provisioned by the AFID resource server.
18
+ #
19
+ # @return [Hash, nil] A Hash representation of the identity associated with the provided token or nil if no such identity
20
+ # exists.
11
21
  def get(token)
12
22
  access = @store.read(key_for(token))
13
23
  if access
@@ -16,12 +26,37 @@ class Hadley::TokenStore
16
26
  access
17
27
  end
18
28
 
29
+ # This method stores the provided AFID identity information under the given AFID token for the duration of time
30
+ # specified by the expires_in argument.
31
+ #
32
+ # @param [String] token The unique token provisioned by the AFID resource server.
33
+ # @param [Integer] expires_in The duration of time (in seconds) that the provided AFID identity information should be
34
+ # stored.
35
+ # @param [Hash] data The identity information to be assiciated with the given AFID token.
36
+ #
37
+ # @return [Boolean, nil] True if and only if the identity information was stored successfully.
19
38
  def put(token, expires_in, data={})
20
39
  @store.write(key_for(token), data, expires_in: expires_in)
21
40
  end
22
41
 
42
+ # This method removes the AFID identity information associated with the provided token.
43
+ #
44
+ # @param [String] token The token provisioned by the AFID resource server.
45
+ #
46
+ # @return [Boolean, nil] True if an only if the identity information was removed successfully.
23
47
  def delete(token)
24
48
  @store.delete(key_for(token))
25
49
  end
26
50
 
51
+ protected
52
+
53
+ # This method derives the appropriate datastore key from the given AFID token.
54
+ #
55
+ # @param [String] token The unique token provisioned by the AFID resource server.
56
+ #
57
+ # @return [Symbol] The appropriate datastore key for the given AFID token.
58
+ def key_for(token)
59
+ "afid-access-token:#{token}".to_sym
60
+ end
61
+
27
62
  end
@@ -1,8 +1,17 @@
1
+ # This module contains a collection of generally useful methods that (currently) have no better place to live. They can
2
+ # either be referenced directly as module methods or be mixed in.
1
3
  module Hadley::Utils
2
4
  extend self
3
5
 
4
- def camelize(word, uc_first=true)
5
- parts = word.split('_')
6
+ # This method will derive a camelized name from the provided underscored name.
7
+ #
8
+ # @param [#to_s] name The underscored name to be camelized.
9
+ # @param [Boolean] uc_first True if and only if the first letter of the resulting camelized name should be
10
+ # capitalized.
11
+ #
12
+ # @return [String] The camelized name corresponding to the provided underscored name.
13
+ def camelize(name, uc_first=true)
14
+ parts = name.to_s.split('_')
6
15
  assemble = lambda { |head, tail| head + tail.capitalize }
7
16
  uc_first ? parts.inject('', &assemble) : parts.inject(&assemble)
8
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hadley
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,33 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-12 00:00:00.000000000 Z
12
+ date: 2012-02-14 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: yard
16
+ requirement: &70230747821600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70230747821600
25
+ - !ruby/object:Gem::Dependency
26
+ name: yard-sinatra
27
+ requirement: &70230747821000 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70230747821000
14
36
  - !ruby/object:Gem::Dependency
15
37
  name: rspec
16
- requirement: &70308229014860 !ruby/object:Gem::Requirement
38
+ requirement: &70230747820200 !ruby/object:Gem::Requirement
17
39
  none: false
18
40
  requirements:
19
41
  - - ! '>='
@@ -21,10 +43,10 @@ dependencies:
21
43
  version: '0'
22
44
  type: :development
23
45
  prerelease: false
24
- version_requirements: *70308229014860
46
+ version_requirements: *70230747820200
25
47
  - !ruby/object:Gem::Dependency
26
48
  name: active_support
27
- requirement: &70308229014300 !ruby/object:Gem::Requirement
49
+ requirement: &70230747819480 !ruby/object:Gem::Requirement
28
50
  none: false
29
51
  requirements:
30
52
  - - ! '>='
@@ -32,10 +54,10 @@ dependencies:
32
54
  version: '0'
33
55
  type: :development
34
56
  prerelease: false
35
- version_requirements: *70308229014300
57
+ version_requirements: *70230747819480
36
58
  - !ruby/object:Gem::Dependency
37
59
  name: dalli
38
- requirement: &70308229030120 !ruby/object:Gem::Requirement
60
+ requirement: &70230747818780 !ruby/object:Gem::Requirement
39
61
  none: false
40
62
  requirements:
41
63
  - - ! '>='
@@ -43,10 +65,10 @@ dependencies:
43
65
  version: '0'
44
66
  type: :development
45
67
  prerelease: false
46
- version_requirements: *70308229030120
68
+ version_requirements: *70230747818780
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: sinatra
49
- requirement: &70308229029500 !ruby/object:Gem::Requirement
71
+ requirement: &70230747833560 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ! '>='
@@ -54,10 +76,10 @@ dependencies:
54
76
  version: '0'
55
77
  type: :runtime
56
78
  prerelease: false
57
- version_requirements: *70308229029500
79
+ version_requirements: *70230747833560
58
80
  - !ruby/object:Gem::Dependency
59
81
  name: warden
60
- requirement: &70308229028740 !ruby/object:Gem::Requirement
82
+ requirement: &70230747832820 !ruby/object:Gem::Requirement
61
83
  none: false
62
84
  requirements:
63
85
  - - ! '>='
@@ -65,7 +87,7 @@ dependencies:
65
87
  version: '0'
66
88
  type: :runtime
67
89
  prerelease: false
68
- version_requirements: *70308229028740
90
+ version_requirements: *70230747832820
69
91
  description:
70
92
  email:
71
93
  - bitbutcher@gmail.com
@@ -74,7 +96,10 @@ extensions: []
74
96
  extra_rdoc_files: []
75
97
  files:
76
98
  - .gitignore
99
+ - .yardopts
77
100
  - Gemfile
101
+ - LICENSE.txt
102
+ - README.rdoc
78
103
  - Rakefile
79
104
  - config.ru
80
105
  - hadley.gemspec
@@ -82,6 +107,8 @@ files:
82
107
  - lib/hadley/authz.rb
83
108
  - lib/hadley/authz/basic.rb
84
109
  - lib/hadley/authz/bearer.rb
110
+ - lib/hadley/authz/strategy.rb
111
+ - lib/hadley/authz/strategy_builder.rb
85
112
  - lib/hadley/config.rb
86
113
  - lib/hadley/middleware.rb
87
114
  - lib/hadley/token_store.rb
@@ -111,3 +138,4 @@ signing_key:
111
138
  specification_version: 3
112
139
  summary: Rack middleware for AFID(bby-id) resource server implementations
113
140
  test_files: []
141
+ has_rdoc: