rack-couchdb-oauth2 0.1.0 → 0.2.0

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.
data/Gemfile.lock CHANGED
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: git://github.com/couchrest/couchrest_model.git
3
- revision: 98772ae98a4685d6a69a77a50d30bd2118cc3aad
3
+ revision: dca47ac3b2b6fd5a4f3ee131083dde4a5cd2b8db
4
4
  specs:
5
5
  couchrest_model (1.1.0.rc1)
6
6
  activemodel (~> 3.0)
@@ -11,11 +11,11 @@ GIT
11
11
  GEM
12
12
  remote: http://rubygems.org/
13
13
  specs:
14
- activemodel (3.0.8)
15
- activesupport (= 3.0.8)
14
+ activemodel (3.0.9)
15
+ activesupport (= 3.0.9)
16
16
  builder (~> 2.1.2)
17
17
  i18n (~> 0.5.0)
18
- activesupport (3.0.8)
18
+ activesupport (3.0.9)
19
19
  attr_required (0.0.3)
20
20
  bcrypt-ruby (2.1.4)
21
21
  builder (2.1.2)
@@ -30,11 +30,11 @@ GEM
30
30
  bundler (~> 1.0)
31
31
  git (>= 1.2.5)
32
32
  rake
33
- json (1.5.2)
33
+ json (1.5.3)
34
34
  mime-types (1.16)
35
35
  multi_json (1.0.3)
36
36
  rack (1.3.0)
37
- rack-oauth2 (0.8.1)
37
+ rack-oauth2 (0.8.2)
38
38
  activesupport (>= 2.3)
39
39
  attr_required (>= 0.0.3)
40
40
  httpclient (>= 2.2.0.2)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -0,0 +1,28 @@
1
+ module Rack
2
+ module CouchdbOAuth2
3
+ class Configuration
4
+ def self.add_config(name)
5
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
6
+ def self.#{name}(value=nil)
7
+ @#{name} = value if value
8
+ return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
9
+ name = superclass.#{name}
10
+ return nil if name.nil? && !instance_variable_defined?("@#{name}")
11
+ @#{name} = name && !name.is_a?(Module) && !name.is_a?(Symbol) && !name.is_a?(Numeric) && !name.is_a?(TrueClass) && !name.is_a?(FalseClass) ? name.dup : name
12
+ end
13
+
14
+ def self.#{name}=(value)
15
+ @#{name} = value
16
+ end
17
+
18
+ def #{name}
19
+ self.class.#{name}
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ add_config :account_class
25
+
26
+ end
27
+ end
28
+ end
@@ -1,11 +1,9 @@
1
1
  class AccessToken < CouchRest::Model::Base
2
- include CouchdbOAuth2::Model::Base
2
+ include Rack::CouchdbOAuth2::Model::Base
3
3
  include Oauth2Token
4
4
  self.default_lifetime = 15.minutes
5
5
 
6
6
  belongs_to :refresh_token
7
- property :token, String
8
- property :expires_at, Time
9
7
  timestamps!
10
8
 
11
9
  def to_bearer_token(with_refresh_token = false)
@@ -1,74 +1,92 @@
1
1
  require 'bcrypt'
2
2
 
3
- class Account < CouchRest::Model::Base
4
- include CouchdbOAuth2::Model::Base
5
-
6
- property :email, String
7
- property :encrypted_password, String
8
- timestamps!
9
-
10
- view_by :email
11
-
12
- validates_uniqueness_of :email
13
-
14
- attr_reader :password
15
-
16
- def password=(new_password)
17
- @password = new_password
18
- self.encrypted_password = password_digest(@password) if @password.present?
19
- end
20
-
21
- def valid_password?(password)
22
- return false if encrypted_password.blank?
23
- bcrypt = ::BCrypt::Password.new(self.encrypted_password)
24
- password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
25
- Account.secure_compare(password, self.encrypted_password)
26
- end
27
-
28
- def clean_up_passwords
29
- self.password = self.password_confirmation = ""
30
- end
31
-
32
- # A reliable way to expose the salt regardless of the implementation.
33
- def authenticatable_salt
34
- self.encrypted_password[0,29] if self.encrypted_password
35
- end
36
-
37
- def access_tokens
38
- AccessToken.view(:by_account_id, :key => self['_id'])
39
- end
40
-
41
- def refresh_tokens
42
- RefreshToken.view(:by_account_id, :key => self['_id'])
43
- end
44
-
45
- protected
46
-
47
- # Downcase case-insensitive keys
48
- def downcase_keys
49
- (self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
50
- end
3
+ module Rack
4
+ module CouchdbOAuth2
5
+ module Model
6
+ module Account
7
+ def self.included(klass)
8
+ klass.class_eval do
51
9
 
52
- # Digests the password using bcrypt.
53
- def password_digest(password)
54
- ::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
55
- end
56
-
57
- def self.stretches
58
- 5
59
- end
60
-
61
- def self.pepper
62
- '5ad96cc293abadd5322908c597a363205b909c99fab13b59895b6e3fc93540f2f276800d6718fa174c9a9720e1148b4da19ee58c779078efe98ca2c76c8cdd40'
63
- end
64
-
65
- def self.secure_compare(a, b)
66
- return false if a.blank? || b.blank? || a.bytesize != b.bytesize
67
- l = a.unpack "C#{a.bytesize}"
68
-
69
- res = 0
70
- b.each_byte { |byte| res |= byte ^ l.shift }
71
- res == 0
10
+ property :email, String
11
+ property :encrypted_password, String, :protected => true
12
+ property :pepper, String, :protected => true
13
+
14
+ view_by :email
15
+
16
+ validates_presence_of :email
17
+ validates_uniqueness_of :email
18
+ validates_confirmation_of :password
19
+ validates_presence_of :encrypted_password, :message => 'password should not be empty'
20
+ validates_presence_of :password_confirmation, :if => :password_changed?
21
+
22
+ attr_reader :password
23
+
24
+ def self.stretches
25
+ 5
26
+ end
27
+
28
+ def self.secure_compare(a, b)
29
+ return false if a.blank? || b.blank? || a.bytesize != b.bytesize
30
+ l = a.unpack "C#{a.bytesize}"
31
+
32
+ res = 0
33
+ b.each_byte { |byte| res |= byte ^ l.shift }
34
+ res == 0
35
+ end
36
+
37
+ def self.find_account(identity)
38
+ raise 'implement me'
39
+ end
40
+ end
41
+ end
42
+
43
+ def password=(new_password)
44
+ @password = new_password
45
+ self.pepper = BCrypt::Engine.generate_salt
46
+ self.encrypted_password = password_digest(@password) if @password.present?
47
+ end
48
+
49
+ def password_changed?
50
+ self.encrypted_password_changed?
51
+ end
52
+
53
+ def valid_password?(password)
54
+ return false if encrypted_password.blank?
55
+ bcrypt = ::BCrypt::Password.new(self.encrypted_password)
56
+ password = ::BCrypt::Engine.hash_secret("#{password}#{self.pepper}", bcrypt.salt)
57
+ self.class.secure_compare(password, self.encrypted_password)
58
+ end
59
+
60
+ def clean_up_passwords
61
+ self.password = self.password_confirmation = ""
62
+ end
63
+
64
+ # A reliable way to expose the salt regardless of the implementation.
65
+ def authenticatable_salt
66
+ self.encrypted_password[0,29] if self.encrypted_password
67
+ end
68
+
69
+ def access_tokens
70
+ AccessToken.view(:by_account_id, :key => self['_id'])
71
+ end
72
+
73
+ def refresh_tokens
74
+ RefreshToken.view(:by_account_id, :key => self['_id'])
75
+ end
76
+
77
+ protected
78
+
79
+ # Downcase case-insensitive keys
80
+ def downcase_keys
81
+ (self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
82
+ end
83
+
84
+ # Digests the password using bcrypt.
85
+ def password_digest(password)
86
+ ::BCrypt::Password.create("#{password}#{self.pepper}", :cost => self.class.stretches).to_s
87
+ end
88
+
89
+ end
90
+ end
72
91
  end
73
-
74
92
  end
@@ -1,12 +1,13 @@
1
- module CouchdbOAuth2
2
- module Model
3
- module Base
4
- def self.included(klass)
5
- klass.class_eval do
6
- use_database klass.name.tableize
7
- end
8
- end
1
+ module Rack
2
+ module CouchdbOAuth2
3
+ module Model
4
+ module Base
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ use_database klass.name.tableize
8
+ end
9
+ end
10
+ end
9
11
  end
10
- end
11
-
12
- end
12
+ end
13
+ end
@@ -1,13 +1,16 @@
1
1
  class Client < CouchRest::Model::Base
2
- include CouchdbOAuth2::Model::Base
2
+ include Rack::CouchdbOAuth2::Model::Base
3
3
 
4
4
  property :name, String
5
5
  property :redirect_url, String
6
6
  property :website, String
7
- property :secret, String
7
+ property :secret, String, :protected => true
8
8
  timestamps!
9
9
 
10
10
  before_validation :setup, :on => :create
11
+ validates_uniqueness_of :name
12
+ validates_presence_of :name
13
+ validates_presence_of :secret
11
14
 
12
15
  def setup
13
16
  if self.secret.nil?
@@ -18,4 +21,10 @@ class Client < CouchRest::Model::Base
18
21
  def identity
19
22
  self['_id']
20
23
  end
24
+
25
+ def self.find_by_env(env)
26
+ request = Rack::OAuth2::Server::Token::Request.new(env)
27
+ client = Client.find(request.client_id)
28
+ client if client && client.secret == request.client_secret
29
+ end
21
30
  end
@@ -4,9 +4,12 @@ module Oauth2Token
4
4
  cattr_accessor :default_lifetime
5
5
  self.default_lifetime = 1.minute
6
6
 
7
- belongs_to :account
7
+ belongs_to :account, :class_name => Rack::CouchdbOAuth2::Configuration.account_class.to_s
8
8
  belongs_to :client
9
9
 
10
+ property :token, String
11
+ property :expires_at, Time
12
+
10
13
  view_by :expires_at
11
14
  view_by :account_id
12
15
  view_by :client_id
@@ -15,6 +18,25 @@ module Oauth2Token
15
18
  before_validation :setup, :on => :create
16
19
  validates :client, :expires_at, :account, :presence => true
17
20
  validates :token, :presence => true, :uniqueness => true
21
+
22
+ def self.find_by_env(env)
23
+ token = find_by_token(env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN])
24
+ if token.nil? || token.expired?
25
+ nil
26
+ else
27
+ token
28
+ end
29
+ end
30
+
31
+ def self.valid
32
+ view(:by_expires_at, :startkey => Time.now.utc)
33
+ end
34
+
35
+ def self.find_by_token(token)
36
+ return nil if token.nil? || token.empty?
37
+ self.first_from_view(:by_token, token)
38
+ end
39
+
18
40
  end
19
41
  end
20
42
 
@@ -29,16 +51,8 @@ module Oauth2Token
29
51
 
30
52
  def expired?
31
53
  self.expires_at < Time.now.utc
32
- end
33
-
34
- def self.valid
35
- view(:by_expires_at, :startkey => Time.now.utc)
36
- end
54
+ end
37
55
 
38
- def self.find_by_token(token)
39
- return nil if token.nil? || token.empty?
40
- self.first_from_view(:by_token, token)
41
- end
42
56
  private
43
57
 
44
58
  def self.generate(bytes = 64)
@@ -1,10 +1,6 @@
1
1
  class RefreshToken < CouchRest::Model::Base
2
- include CouchdbOAuth2::Model::Base
2
+ include Rack::CouchdbOAuth2::Model::Base
3
3
  include Oauth2Token
4
- belongs_to :account
5
- belongs_to :client
6
- property :token, String
7
- property :expires_at, Time
8
4
  timestamps!
9
5
 
10
6
  self.default_lifetime = 1.month
@@ -22,7 +22,7 @@ module Rack
22
22
  client = request.client
23
23
  request.unauthorized!(:invalid_token) unless client
24
24
  if @authenticator
25
- request.unauthorized! unless @authenticator.call(request)
25
+ request.unauthorized!(:invalid_token) unless @authenticator.call(request)
26
26
  end
27
27
  env[CLIENT] = client
28
28
  end
@@ -17,7 +17,8 @@ module Rack
17
17
  req.unsupported_grant_type!
18
18
  when :password
19
19
  # NOTE: password is not hashed in this sample app. Don't do the same on your app.
20
- account = req.username.nil? ? nil : Account.first_from_view(:by_email, req.username)
20
+ account_class = Rack::CouchdbOAuth2::Configuration.account_class
21
+ account = req.username.nil? ? nil : account_class.find_account(req.username)
21
22
  req.invalid_grant! unless account && account.valid_password?(req.password)
22
23
  res.access_token = AccessToken.create(:client => client, :account => account).to_bearer_token(:with_refresh_token)
23
24
  when :client_credentials
@@ -2,13 +2,23 @@ require 'rack/oauth2'
2
2
  require 'couchrest'
3
3
  require 'couchrest_model'
4
4
  require 'active_support'
5
- require 'couchdb_oauth2/model/base'
6
- require 'couchdb_oauth2/model/oauth2_token'
7
- require 'couchdb_oauth2/model/access_token'
8
- require 'couchdb_oauth2/model/account'
9
- require 'couchdb_oauth2/model/client'
10
- require 'couchdb_oauth2/model/refresh_token'
11
5
 
12
- require 'couchdb_oauth2/token_endpoint'
13
- require 'couchdb_oauth2/resource/require_bearer_token'
14
- require 'couchdb_oauth2/resource/require_client'
6
+ module Rack
7
+ module CouchdbOAuth2
8
+ autoload :Configuration, 'couchdb_oauth2/configuration'
9
+ autoload :TokenEndpoint, 'couchdb_oauth2/token_endpoint'
10
+
11
+ autoload :RequireBearerToken, 'couchdb_oauth2/resource/require_bearer_token'
12
+ autoload :RequireClient, 'couchdb_oauth2/resource/require_client'
13
+
14
+ module Model
15
+ autoload :Base, 'couchdb_oauth2/model/base'
16
+ autoload :Account, 'couchdb_oauth2/model/account'
17
+ end
18
+ end
19
+ end
20
+ autoload :Oauth2Token, 'couchdb_oauth2/model/oauth2_token'
21
+ autoload :AccessToken, 'couchdb_oauth2/model/access_token'
22
+ autoload :Client, 'couchdb_oauth2/model/client'
23
+ autoload :RefreshToken, 'couchdb_oauth2/model/refresh_token'
24
+
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rack-couchdb-oauth2}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Robin Lu"]
12
- s.date = %q{2011-06-15}
12
+ s.date = %q{2011-06-27}
13
13
  s.description = %q{Rack middleware for OAuth2 Provider Server Based on Couchdb}
14
14
  s.email = %q{iamawalrus@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
24
24
  "README.rdoc",
25
25
  "Rakefile",
26
26
  "VERSION",
27
+ "lib/couchdb_oauth2/configuration.rb",
27
28
  "lib/couchdb_oauth2/model/access_token.rb",
28
29
  "lib/couchdb_oauth2/model/account.rb",
29
30
  "lib/couchdb_oauth2/model/base.rb",
@@ -36,12 +37,16 @@ Gem::Specification.new do |s|
36
37
  "lib/rack-couchdb-oauth2.rb",
37
38
  "rack-couchdb-oauth2.gemspec",
38
39
  "test/helper.rb",
39
- "test/test_rack-couchdb-oauth2.rb"
40
+ "test/test_account.rb",
41
+ "test/test_client.rb",
42
+ "test/test_rack-couchdb-oauth2.rb",
43
+ "test/test_require_client.rb",
44
+ "test/test_token.rb"
40
45
  ]
41
46
  s.homepage = %q{http://github.com/robin/rack-couchdb-oauth2}
42
47
  s.licenses = ["MIT"]
43
48
  s.require_paths = ["lib"]
44
- s.rubygems_version = %q{1.4.2}
49
+ s.rubygems_version = %q{1.6.2}
45
50
  s.summary = %q{Rack middleware for OAuth2 Provider Server Based on Couchdb}
46
51
 
47
52
  if s.respond_to? :specification_version then
data/test/helper.rb CHANGED
@@ -14,6 +14,21 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
14
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
15
  require 'rack-couchdb-oauth2'
16
16
 
17
+ class User < CouchRest::Model::Base
18
+ use_database 'users'
19
+ include Rack::CouchdbOAuth2::Model::Account
20
+
21
+ def self.pepper
22
+ 'pepper'
23
+ end
24
+
25
+ def self.find_account(identity)
26
+ first_from_view(:by_email, identity)
27
+ end
28
+ end
29
+
30
+ Rack::CouchdbOAuth2::Configuration.account_class = ::User
31
+
17
32
  class Test::Unit::TestCase
18
33
  def assert_error_response(response)
19
34
  assert !response.ok?
@@ -21,6 +36,22 @@ class Test::Unit::TestCase
21
36
  assert_not_nil(body['error'])
22
37
  assert_nil(body['access_token'])
23
38
  end
39
+
40
+ def create_client
41
+ @client = Client.create(:name => 'test client')
42
+ end
43
+
44
+ def create_account
45
+ @account = User.create(:email => 'test@example.com', :password => 'abc123', :password_confirmation => 'abc123' )
46
+ end
47
+
48
+ def destroy_client
49
+ @client.destroy
50
+ end
51
+
52
+ def destroy_account
53
+ @account.destroy
54
+ end
24
55
  end
25
56
 
26
57
  class TestApp
@@ -0,0 +1,26 @@
1
+ require "helper"
2
+
3
+ class TestRequireClient < Test::Unit::TestCase
4
+ include Rack::Test::Methods
5
+
6
+ def test_presents
7
+ a = User.new()
8
+ assert(!a.save, "Failure message.")
9
+ a.email = 'abc@example.com'
10
+ assert(!a.save, "Failure message.")
11
+ a.password = 'abcdef'
12
+ assert(!a.save, "Failure message.")
13
+ a.password_confirmation = 'wrong'
14
+ assert(!a.save, "Failure message.")
15
+ a.password_confirmation = 'abcdef'
16
+ assert(a.save, "Failure message.")
17
+ a.destroy
18
+ end
19
+
20
+ def test_attr_protected
21
+ a = User.new(:email => 'aaa@example.com', :encrypted_password => "pwd", :pepper => "pepper")
22
+ assert_equal('aaa@example.com', a.email)
23
+ assert_nil(a.encrypted_password)
24
+ assert_nil(a.pepper)
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ require "helper"
2
+
3
+ class TestClient < Test::Unit::TestCase
4
+ include Rack::Test::Methods
5
+
6
+ def setup
7
+ create_client
8
+ end
9
+
10
+ def teardown
11
+ destroy_client
12
+ end
13
+
14
+ def app
15
+ Rack::Builder.new do
16
+ run proc {|env|
17
+ client = Client.find_by_env(env)
18
+ raise 'no client' if client.nil?
19
+ [200, {}, 'OK']
20
+ }
21
+ end
22
+ end
23
+
24
+ def test_presents
25
+ c = Client.new()
26
+ assert(!c.save, "Failure message.")
27
+ c.name = 'abc'
28
+ assert(c.save, "Failure message.")
29
+
30
+ c2 = Client.new :name => 'abc', :secret => 's'
31
+ assert_nil(c2.secret)
32
+ assert(!c2.save, "Failure message.")
33
+ c.destroy
34
+ end
35
+
36
+ def test_find_by_env
37
+ assert_raise(RuntimeError) {
38
+ get '/'
39
+ }
40
+ assert_raise(RuntimeError) {
41
+ get '/', :client_id => @client.identity, :client_secret =>'wrong secret'
42
+ }
43
+ assert_nothing_raised(RuntimeError) {
44
+ get '/', :client_id => @client.identity, :client_secret =>@client.secret
45
+ }
46
+ assert_raise(RuntimeError) {
47
+ get '/', :client_id => "wrong identity", :client_secret =>'wrong secret'
48
+ }
49
+ end
50
+ end
@@ -4,20 +4,19 @@ class TestRackCouchdbOauth2 < Test::Unit::TestCase
4
4
  include Rack::Test::Methods
5
5
 
6
6
  def setup
7
- @client = Client.create(:name => 'test client')
8
- @account = Account.create(:email => 'test@example.com', :password => 'abc123' )
7
+ create_client
8
+ create_account
9
9
  end
10
10
 
11
11
  def teardown
12
- @client.destroy
13
- @account.destroy
12
+ destroy_client
13
+ destroy_account
14
14
  end
15
15
 
16
16
  def app
17
17
  Rack::Builder.new do
18
18
  map '/db' do
19
19
  use Rack::CouchdbOAuth2::RequireBearerToken
20
- use Rack::CouchdbOAuth2::RequireClient
21
20
  run TestApp.new
22
21
  end
23
22
 
@@ -0,0 +1,130 @@
1
+ require "helper"
2
+
3
+ class TestRequireClient < Test::Unit::TestCase
4
+ include Rack::Test::Methods
5
+
6
+ def setup
7
+ create_client
8
+ create_account
9
+ end
10
+
11
+ def teardown
12
+ destroy_client
13
+ destroy_account
14
+ end
15
+
16
+ def app
17
+ @app ||= Rack::Builder.new do
18
+ map '/db' do
19
+ use Rack::CouchdbOAuth2::RequireBearerToken
20
+ use Rack::CouchdbOAuth2::RequireClient
21
+ run TestApp.new
22
+ end
23
+
24
+ map '/oauth2' do
25
+ map '/token' do
26
+ run Rack::CouchdbOAuth2::TokenEndpoint.new
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def change_to_false_client_id
33
+ @app ||= Rack::Builder.new do
34
+ map '/db' do
35
+ use Rack::CouchdbOAuth2::RequireBearerToken
36
+ use Rack::CouchdbOAuth2::RequireClient do |req|
37
+ req.client.identity == 'false id'
38
+ end
39
+ run TestApp.new
40
+ end
41
+
42
+ map '/oauth2' do
43
+ map '/token' do
44
+ run Rack::CouchdbOAuth2::TokenEndpoint.new
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def change_to_use_client_id
51
+ identity = @client.identity
52
+ @app ||= Rack::Builder.new do
53
+ map '/db' do
54
+ use Rack::CouchdbOAuth2::RequireBearerToken
55
+ use Rack::CouchdbOAuth2::RequireClient do |req|
56
+ req.client.identity == identity
57
+ end
58
+ run TestApp.new
59
+ end
60
+
61
+ map '/oauth2' do
62
+ map '/token' do
63
+ run Rack::CouchdbOAuth2::TokenEndpoint.new
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def test_require_client
70
+ header 'AUTHORIZATION', nil
71
+ get 'db'
72
+ assert_error_response last_response
73
+
74
+ post 'oauth2/token', :grant_type => 'password', :client_id => @client.identity, :client_secret => @client.secret, :username => @account.email, :password => 'abc123'
75
+ assert last_response.ok?
76
+ body = ActiveSupport::JSON.decode(last_response.body)
77
+ access_token = body['access_token']
78
+ refresh_token = body['refresh_token']
79
+ assert_not_nil(access_token)
80
+ assert_not_nil(refresh_token)
81
+ assert_equal('bearer', body['token_type'])
82
+
83
+ header 'AUTHORIZATION', "Bearer #{access_token}"
84
+ get 'db'
85
+ assert last_response.ok?
86
+ assert_equal(TestApp::BODY, last_response.body)
87
+ end
88
+
89
+ def test_require_client_with_wrong_id
90
+ change_to_false_client_id
91
+ header 'AUTHORIZATION', nil
92
+ get 'db'
93
+ assert_error_response last_response
94
+
95
+ post 'oauth2/token', :grant_type => 'password', :client_id => @client.identity, :client_secret => @client.secret, :username => @account.email, :password => 'abc123'
96
+ assert last_response.ok?
97
+ body = ActiveSupport::JSON.decode(last_response.body)
98
+ access_token = body['access_token']
99
+ refresh_token = body['refresh_token']
100
+ assert_not_nil(access_token)
101
+ assert_not_nil(refresh_token)
102
+ assert_equal('bearer', body['token_type'])
103
+
104
+ header 'AUTHORIZATION', "Bearer #{access_token}"
105
+ get 'db'
106
+ assert_error_response last_response
107
+ end
108
+
109
+ def test_require_client_with_correct_id
110
+ change_to_use_client_id
111
+ header 'AUTHORIZATION', nil
112
+ get 'db'
113
+ assert_error_response last_response
114
+
115
+ post 'oauth2/token', :grant_type => 'password', :client_id => @client.identity, :client_secret => @client.secret, :username => @account.email, :password => 'abc123'
116
+ assert last_response.ok?
117
+ body = ActiveSupport::JSON.decode(last_response.body)
118
+ access_token = body['access_token']
119
+ refresh_token = body['refresh_token']
120
+ assert_not_nil(access_token)
121
+ assert_not_nil(refresh_token)
122
+ assert_equal('bearer', body['token_type'])
123
+
124
+ header 'AUTHORIZATION', "Bearer #{access_token}"
125
+ get 'db'
126
+ assert last_response.ok?
127
+ assert_equal(TestApp::BODY, last_response.body)
128
+
129
+ end
130
+ end
@@ -0,0 +1,62 @@
1
+ require 'helper'
2
+
3
+ class TestToken < Test::Unit::TestCase
4
+ include Rack::Test::Methods
5
+
6
+ def setup
7
+ create_client
8
+ create_account
9
+ end
10
+
11
+ def teardown
12
+ destroy_client
13
+ destroy_account
14
+ end
15
+
16
+ def app
17
+ Rack::Builder.new do
18
+ map '/oauth2' do
19
+ map '/token' do
20
+ run Rack::CouchdbOAuth2::TokenEndpoint.new
21
+ end
22
+ end
23
+
24
+ map '/db' do
25
+ use Rack::OAuth2::Server::Resource::Bearer, 'test' do |req|
26
+
27
+ end
28
+ run proc {|env|
29
+ token = AccessToken.find_by_env(env)
30
+ raise 'no client' if token.nil?
31
+ [200, {}, 'OK']
32
+ }
33
+ end
34
+ end
35
+ end
36
+
37
+ def test_find_by_env
38
+ post 'oauth2/token', :grant_type => 'password', :client_id => @client.identity, :client_secret => @client.secret, :username => @account.email, :password => 'abc123'
39
+ assert last_response.ok?
40
+ body = ActiveSupport::JSON.decode(last_response.body)
41
+ access_token = body['access_token']
42
+ refresh_token = body['refresh_token']
43
+ assert_not_nil(access_token)
44
+ assert_not_nil(refresh_token)
45
+ assert_equal('bearer', body['token_type'])
46
+
47
+ assert_raise(RuntimeError) {
48
+ header 'AUTHORIZATION', nil
49
+ get 'db'
50
+ }
51
+
52
+ assert_nothing_raised(RuntimeError) {
53
+ header 'AUTHORIZATION', "Bearer #{access_token}"
54
+ get 'db'
55
+ }
56
+
57
+ assert_raise(RuntimeError) {
58
+ header 'AUTHORIZATION', nil
59
+ get 'db'
60
+ }
61
+ end
62
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-couchdb-oauth2
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Robin Lu
@@ -15,14 +15,13 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-15 00:00:00 +08:00
18
+ date: 2011-06-27 00:00:00 +08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  prerelease: false
23
- name: rack
24
23
  type: :runtime
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
26
25
  none: false
27
26
  requirements:
28
27
  - - ">="
@@ -31,12 +30,12 @@ dependencies:
31
30
  segments:
32
31
  - 0
33
32
  version: "0"
34
- requirement: *id001
33
+ name: rack
34
+ version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
36
36
  prerelease: false
37
- name: couchrest
38
37
  type: :runtime
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
40
39
  none: false
41
40
  requirements:
42
41
  - - ">="
@@ -45,12 +44,12 @@ dependencies:
45
44
  segments:
46
45
  - 0
47
46
  version: "0"
48
- requirement: *id002
47
+ name: couchrest
48
+ version_requirements: *id002
49
49
  - !ruby/object:Gem::Dependency
50
50
  prerelease: false
51
- name: couchrest_model
52
51
  type: :runtime
53
- version_requirements: &id003 !ruby/object:Gem::Requirement
52
+ requirement: &id003 !ruby/object:Gem::Requirement
54
53
  none: false
55
54
  requirements:
56
55
  - - ">="
@@ -59,12 +58,12 @@ dependencies:
59
58
  segments:
60
59
  - 0
61
60
  version: "0"
62
- requirement: *id003
61
+ name: couchrest_model
62
+ version_requirements: *id003
63
63
  - !ruby/object:Gem::Dependency
64
64
  prerelease: false
65
- name: activesupport
66
65
  type: :runtime
67
- version_requirements: &id004 !ruby/object:Gem::Requirement
66
+ requirement: &id004 !ruby/object:Gem::Requirement
68
67
  none: false
69
68
  requirements:
70
69
  - - ">="
@@ -73,12 +72,12 @@ dependencies:
73
72
  segments:
74
73
  - 0
75
74
  version: "0"
76
- requirement: *id004
75
+ name: activesupport
76
+ version_requirements: *id004
77
77
  - !ruby/object:Gem::Dependency
78
78
  prerelease: false
79
- name: rack-oauth2
80
79
  type: :runtime
81
- version_requirements: &id005 !ruby/object:Gem::Requirement
80
+ requirement: &id005 !ruby/object:Gem::Requirement
82
81
  none: false
83
82
  requirements:
84
83
  - - ">="
@@ -87,12 +86,12 @@ dependencies:
87
86
  segments:
88
87
  - 0
89
88
  version: "0"
90
- requirement: *id005
89
+ name: rack-oauth2
90
+ version_requirements: *id005
91
91
  - !ruby/object:Gem::Dependency
92
92
  prerelease: false
93
- name: bcrypt-ruby
94
93
  type: :runtime
95
- version_requirements: &id006 !ruby/object:Gem::Requirement
94
+ requirement: &id006 !ruby/object:Gem::Requirement
96
95
  none: false
97
96
  requirements:
98
97
  - - ">="
@@ -101,12 +100,12 @@ dependencies:
101
100
  segments:
102
101
  - 0
103
102
  version: "0"
104
- requirement: *id006
103
+ name: bcrypt-ruby
104
+ version_requirements: *id006
105
105
  - !ruby/object:Gem::Dependency
106
106
  prerelease: false
107
- name: bundler
108
107
  type: :development
109
- version_requirements: &id007 !ruby/object:Gem::Requirement
108
+ requirement: &id007 !ruby/object:Gem::Requirement
110
109
  none: false
111
110
  requirements:
112
111
  - - ~>
@@ -117,12 +116,12 @@ dependencies:
117
116
  - 0
118
117
  - 0
119
118
  version: 1.0.0
120
- requirement: *id007
119
+ name: bundler
120
+ version_requirements: *id007
121
121
  - !ruby/object:Gem::Dependency
122
122
  prerelease: false
123
- name: jeweler
124
123
  type: :development
125
- version_requirements: &id008 !ruby/object:Gem::Requirement
124
+ requirement: &id008 !ruby/object:Gem::Requirement
126
125
  none: false
127
126
  requirements:
128
127
  - - ~>
@@ -133,12 +132,12 @@ dependencies:
133
132
  - 6
134
133
  - 2
135
134
  version: 1.6.2
136
- requirement: *id008
135
+ name: jeweler
136
+ version_requirements: *id008
137
137
  - !ruby/object:Gem::Dependency
138
138
  prerelease: false
139
- name: rcov
140
139
  type: :development
141
- version_requirements: &id009 !ruby/object:Gem::Requirement
140
+ requirement: &id009 !ruby/object:Gem::Requirement
142
141
  none: false
143
142
  requirements:
144
143
  - - ">="
@@ -147,12 +146,12 @@ dependencies:
147
146
  segments:
148
147
  - 0
149
148
  version: "0"
150
- requirement: *id009
149
+ name: rcov
150
+ version_requirements: *id009
151
151
  - !ruby/object:Gem::Dependency
152
152
  prerelease: false
153
- name: rack-test
154
153
  type: :development
155
- version_requirements: &id010 !ruby/object:Gem::Requirement
154
+ requirement: &id010 !ruby/object:Gem::Requirement
156
155
  none: false
157
156
  requirements:
158
157
  - - ">="
@@ -161,7 +160,8 @@ dependencies:
161
160
  segments:
162
161
  - 0
163
162
  version: "0"
164
- requirement: *id010
163
+ name: rack-test
164
+ version_requirements: *id010
165
165
  description: Rack middleware for OAuth2 Provider Server Based on Couchdb
166
166
  email: iamawalrus@gmail.com
167
167
  executables: []
@@ -179,6 +179,7 @@ files:
179
179
  - README.rdoc
180
180
  - Rakefile
181
181
  - VERSION
182
+ - lib/couchdb_oauth2/configuration.rb
182
183
  - lib/couchdb_oauth2/model/access_token.rb
183
184
  - lib/couchdb_oauth2/model/account.rb
184
185
  - lib/couchdb_oauth2/model/base.rb
@@ -191,7 +192,11 @@ files:
191
192
  - lib/rack-couchdb-oauth2.rb
192
193
  - rack-couchdb-oauth2.gemspec
193
194
  - test/helper.rb
195
+ - test/test_account.rb
196
+ - test/test_client.rb
194
197
  - test/test_rack-couchdb-oauth2.rb
198
+ - test/test_require_client.rb
199
+ - test/test_token.rb
195
200
  has_rdoc: true
196
201
  homepage: http://github.com/robin/rack-couchdb-oauth2
197
202
  licenses:
@@ -222,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
227
  requirements: []
223
228
 
224
229
  rubyforge_project:
225
- rubygems_version: 1.4.2
230
+ rubygems_version: 1.6.2
226
231
  signing_key:
227
232
  specification_version: 3
228
233
  summary: Rack middleware for OAuth2 Provider Server Based on Couchdb