rack-couchdb-oauth2 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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