hadley 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hadley.gemspec
4
+ gemspec
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,52 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+ require 'rubygems'
3
+ require 'hadley'
4
+ require 'dalli'
5
+ require 'sinatra/base'
6
+ require 'json'
7
+
8
+ class ExampleResourceServer < Sinatra::Base
9
+ include Hadley::Authz
10
+
11
+ get '/' do
12
+ body 'afid-resource-server'
13
+ end
14
+
15
+ get '/v1/current_time' do
16
+ warden.authenticate!(:afid_user)
17
+ body({current_time: Time.now.strftime('%Y-%m-%dT%H:%M:%SZ')}.to_json)
18
+ end
19
+
20
+ get '/v1/anonymous_time' do
21
+ warden.authenticate!(:afid_client)
22
+ body({current_time: Time.now.strftime('%s')}.to_json)
23
+ end
24
+
25
+ token_store = Hadley::TokenAccess.new(Dalli::Client.new)
26
+
27
+ use Rack::Session::Cookie, :secret => 'a8ab10237100f16d12b6c8e574e84b92cc15aecaced04d47251a5f34ffaa0e60'
28
+
29
+ use Warden::Manager do |manager|
30
+ manager.basic(:server) do |basic|
31
+ basic.hash_credentials = true
32
+ basic.lookup do |id, secret|
33
+ [ id, secret] == [
34
+ 'a8ab10237100f16d12b6c8e574e84b92cc15aecaced04d47251a5f34ffaa0e60',
35
+ '29cd5d3e8f481821422f886055d536c8e395a8aa123700eec74f045b0144e986'
36
+ ] ? id : nil
37
+ end
38
+ end
39
+ manager.bearer(:client) do |bearer|
40
+ bearer.token_store = token_store
41
+ bearer.anonymous_allowed = true
42
+ end
43
+ manager.bearer(:user) do |bearer|
44
+ bearer.token_store = token_store
45
+ bearer.anonymous_allowed = false
46
+ end
47
+ end
48
+
49
+ use Hadley::Middleware, token_store: token_store
50
+ end
51
+
52
+ run ExampleResourceServer
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'hadley'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'hadley'
7
+ s.version = Hadley::VERSION
8
+ s.authors = ['Sean M. Duncan']
9
+ s.email = ['bitbutcher@gmail.com']
10
+ s.homepage = 'https://github.com/bitbutcher/hadley'
11
+ s.summary = 'Rack middleware for AFID(bby-id) resource server implementations'
12
+
13
+ s.rubyforge_project = 'hadley'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = [ 'lib' ]
19
+
20
+ s.add_development_dependency 'rspec'
21
+ s.add_development_dependency 'dalli'
22
+ s.add_runtime_dependency 'sinatra'
23
+ s.add_runtime_dependency 'warden'
24
+ end
@@ -0,0 +1,17 @@
1
+ autoload :Rack, 'rack'
2
+ autoload :Sinatra, 'sinatra/base'
3
+ autoload :Warden, 'warden'
4
+
5
+ module Hadley
6
+
7
+ autoload :Authz, 'hadley/authz'
8
+ autoload :Config, 'hadley/config'
9
+ autoload :Middleware, 'hadley/middleware'
10
+ autoload :TokenAccess, 'hadley/token_access'
11
+ autoload :Utils, 'hadley/utils'
12
+
13
+ VERSION = '0.0.1'
14
+
15
+ ANONYMOUS_IDENTITY = '0' * 66
16
+
17
+ end
@@ -0,0 +1,53 @@
1
+ module Hadley::Authz
2
+
3
+ autoload :Basic, 'hadley/authz/basic'
4
+ autoload :Bearer, 'hadley/authz/bearer'
5
+
6
+ def warden
7
+ env['warden']
8
+ end
9
+
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
+
50
+ Warden::Config.send(:include, Hadley::Authz::Basic::ConfigExtension)
51
+ Warden::Config.send(:include, Hadley::Authz::Bearer::ConfigExtension)
52
+
53
+ end
@@ -0,0 +1,56 @@
1
+ module Hadley
2
+
3
+ module Authz
4
+
5
+ module Basic
6
+
7
+ class Strategy < Hadley::Authz::Strategy
8
+
9
+ def auth
10
+ @auth ||= Rack::Auth::Basic::Request.new(env)
11
+ end
12
+
13
+ def store?
14
+ false
15
+ end
16
+
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
25
+
26
+ def unauthorized
27
+ custom!(Rack::Response.new([config.fail_message], 401, { 'WWW-Authenticate' => %Q{Basic realm="#{config.realm}"} }))
28
+ end
29
+
30
+ end
31
+
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?
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,72 @@
1
+ module Rack::Auth::Bearer
2
+
3
+ class Request < Rack::Auth::AbstractRequest
4
+
5
+ def bearer?
6
+ :bearer == scheme
7
+ end
8
+
9
+ def token
10
+ @token ||= params.split(' ', 2).first
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ module Hadley
18
+
19
+ module Authz
20
+
21
+ module Bearer
22
+
23
+ class Strategy < Hadley::Authz::Strategy
24
+
25
+ def auth
26
+ @auth ||= Rack::Auth::Bearer::Request.new(env)
27
+ end
28
+
29
+ def store?
30
+ false
31
+ end
32
+
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
39
+
40
+ private
41
+
42
+ def unauthorized
43
+ custom!(Rack::Response.new([config.fail_message], 401, { 'WWW-Authenticate' => %Q{Bearer realm="#{config.realm}"} }))
44
+ end
45
+
46
+ end
47
+
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
+ end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,29 @@
1
+ class Hadley::Config
2
+
3
+ def initialize(config={})
4
+ @config = config
5
+ end
6
+
7
+ def method_missing(name, *args, &block)
8
+ if block_given?
9
+ proc(name, &block)
10
+ elsif name =~ /(.+)=$/
11
+ set($1, *args, &block)
12
+ else
13
+ get(name, &block)
14
+ end
15
+ end
16
+
17
+ def proc(name, &block)
18
+ @config[name.to_sym] = block
19
+ end
20
+
21
+ def set(name, *args)
22
+ @config[name.to_sym] = args.size == 1 ? args.first : args
23
+ end
24
+
25
+ def get(name, &block)
26
+ @config[name.to_sym]
27
+ end
28
+
29
+ end
@@ -0,0 +1,52 @@
1
+ class Hadley::Middleware < Sinatra::Base
2
+
3
+ include Hadley::Authz
4
+
5
+ attr_reader :confg
6
+
7
+ def initialize(app=nil, options={})
8
+ super(app)
9
+ @config ||= Hadley::Config.new(options)
10
+ yield @config if block_given?
11
+ @tokens = @config.token_store
12
+ self
13
+ end
14
+
15
+ # ------------------------------------------
16
+ # Routes
17
+ # ------------------------------------------
18
+
19
+ put '/access/tokens/:token' do |token|
20
+ warden.authenticate!(:afid_server)
21
+ begin
22
+ @tokens.put(token, Integer(params.fetch('expires_in')),
23
+ identity: params.fetch('identity'),
24
+ client: params.fetch('client')
25
+ )
26
+ body 'Token Accepted'
27
+ rescue => e
28
+ status 400
29
+ body e.to_s
30
+ end
31
+ end
32
+
33
+ delete '/access/tokens/:token' do |token|
34
+ warden.authenticate!(:afid_server)
35
+ begin
36
+ @tokens.delete(token)
37
+ body 'Token Deleted'
38
+ rescue => e
39
+ status 400
40
+ body e.to_s
41
+ end
42
+ end
43
+
44
+ # ------------------------------------------
45
+ # Config
46
+ # ------------------------------------------
47
+
48
+ disable :show_exceptions
49
+ enable :raise_errors
50
+ enable :logging
51
+
52
+ end
@@ -0,0 +1,27 @@
1
+ class Hadley::TokenAccess
2
+
3
+ def initialize(store)
4
+ @store = store
5
+ end
6
+
7
+ def key_for(token)
8
+ "afid-access-token:#{token}"
9
+ end
10
+
11
+ def get(token)
12
+ access = @store.get(key_for(token))
13
+ if access
14
+ access[:anonymous] = access[:identity] == Hadley::ANONYMOUS_IDENTITY
15
+ end
16
+ access
17
+ end
18
+
19
+ def put(token, expires_in, data={})
20
+ @store.set(key_for(token), data, expires_in)
21
+ end
22
+
23
+ def delete(token)
24
+ @store.delete(key_for(token))
25
+ end
26
+
27
+ end
@@ -0,0 +1,10 @@
1
+ module Hadley::Utils
2
+ extend self
3
+
4
+ def camelize(word, uc_first=true)
5
+ parts = word.split('_')
6
+ assemble = lambda { |head, tail| head + tail.capitalize }
7
+ uc_first ? parts.inject('', &assemble) : parts.inject(&assemble)
8
+ end
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hadley
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sean M. Duncan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70184778050660 !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: *70184778050660
25
+ - !ruby/object:Gem::Dependency
26
+ name: dalli
27
+ requirement: &70184778049880 !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: *70184778049880
36
+ - !ruby/object:Gem::Dependency
37
+ name: sinatra
38
+ requirement: &70184778065160 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70184778065160
47
+ - !ruby/object:Gem::Dependency
48
+ name: warden
49
+ requirement: &70184778064540 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70184778064540
58
+ description:
59
+ email:
60
+ - bitbutcher@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - Gemfile
67
+ - Rakefile
68
+ - config.ru
69
+ - hadley.gemspec
70
+ - lib/hadley.rb
71
+ - lib/hadley/authz.rb
72
+ - lib/hadley/authz/basic.rb
73
+ - lib/hadley/authz/bearer.rb
74
+ - lib/hadley/config.rb
75
+ - lib/hadley/middleware.rb
76
+ - lib/hadley/token_access.rb
77
+ - lib/hadley/utils.rb
78
+ homepage: https://github.com/bitbutcher/hadley
79
+ licenses: []
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project: hadley
98
+ rubygems_version: 1.8.15
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Rack middleware for AFID(bby-id) resource server implementations
102
+ test_files: []