doorkeeper 0.4.2 → 0.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (118) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +5 -1
  3. data/CHANGELOG.md +29 -0
  4. data/Gemfile +12 -4
  5. data/README.md +76 -7
  6. data/Rakefile +1 -25
  7. data/app/assets/javascripts/doorkeeper/application.js +0 -7
  8. data/app/controllers/doorkeeper/application_controller.rb +1 -27
  9. data/app/controllers/doorkeeper/applications_controller.rb +14 -6
  10. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  11. data/app/controllers/doorkeeper/token_info_controller.rb +11 -0
  12. data/app/controllers/doorkeeper/tokens_controller.rb +11 -8
  13. data/app/validators/redirect_uri_validator.rb +12 -0
  14. data/app/views/doorkeeper/applications/_form.html.erb +3 -3
  15. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  16. data/app/views/doorkeeper/applications/index.html.erb +4 -4
  17. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  18. data/app/views/doorkeeper/applications/show.html.erb +3 -3
  19. data/app/views/doorkeeper/authorizations/new.html.erb +2 -2
  20. data/app/views/doorkeeper/authorized_applications/index.html.erb +1 -1
  21. data/config/locales/en.yml +35 -0
  22. data/doorkeeper.gemspec +3 -3
  23. data/gemfiles/gemfile.rails-3.1.x +10 -0
  24. data/gemfiles/gemfile.rails-3.2.x +10 -0
  25. data/lib/doorkeeper.rb +10 -3
  26. data/lib/doorkeeper/config.rb +56 -38
  27. data/lib/doorkeeper/doorkeeper_for.rb +2 -0
  28. data/lib/doorkeeper/engine.rb +3 -32
  29. data/lib/doorkeeper/helpers/controller.rb +29 -0
  30. data/lib/doorkeeper/helpers/filter.rb +4 -18
  31. data/{app/models/doorkeeper → lib/doorkeeper/models}/access_grant.rb +7 -7
  32. data/{app/models/doorkeeper → lib/doorkeeper/models}/access_token.rb +27 -24
  33. data/lib/doorkeeper/models/accessible.rb +9 -0
  34. data/lib/doorkeeper/models/active_record/access_grant.rb +5 -0
  35. data/lib/doorkeeper/models/active_record/access_token.rb +15 -0
  36. data/lib/doorkeeper/models/active_record/application.rb +18 -0
  37. data/lib/doorkeeper/models/application.rb +38 -0
  38. data/lib/doorkeeper/models/expirable.rb +6 -4
  39. data/lib/doorkeeper/models/mongoid/access_grant.rb +22 -0
  40. data/lib/doorkeeper/models/mongoid/access_token.rb +35 -0
  41. data/lib/doorkeeper/models/mongoid/application.rb +22 -0
  42. data/lib/doorkeeper/models/mongoid/revocable.rb +15 -0
  43. data/lib/doorkeeper/models/mongoid/scopes.rb +15 -0
  44. data/lib/doorkeeper/models/ownership.rb +16 -0
  45. data/lib/doorkeeper/models/revocable.rb +1 -1
  46. data/lib/doorkeeper/models/scopes.rb +9 -5
  47. data/lib/doorkeeper/oauth/access_token_request.rb +2 -2
  48. data/lib/doorkeeper/oauth/authorization.rb +1 -0
  49. data/lib/doorkeeper/oauth/authorization/code.rb +5 -3
  50. data/lib/doorkeeper/oauth/client.rb +2 -2
  51. data/lib/doorkeeper/oauth/client_credentials_request.rb +4 -1
  52. data/lib/doorkeeper/oauth/helpers/unique_token.rb +2 -5
  53. data/lib/doorkeeper/oauth/password_access_token_request.rb +2 -5
  54. data/lib/doorkeeper/oauth/token.rb +36 -0
  55. data/lib/doorkeeper/rails/routes.rb +77 -0
  56. data/lib/doorkeeper/rails/routes/mapper.rb +28 -0
  57. data/lib/doorkeeper/rails/routes/mapping.rb +39 -0
  58. data/lib/doorkeeper/version.rb +1 -1
  59. data/lib/generators/doorkeeper/application_owner_generator.rb +15 -0
  60. data/lib/generators/doorkeeper/install_generator.rb +2 -9
  61. data/lib/generators/doorkeeper/migration_generator.rb +15 -0
  62. data/lib/generators/doorkeeper/templates/README +15 -1
  63. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +7 -0
  64. data/lib/generators/doorkeeper/templates/initializer.rb +31 -15
  65. data/lib/generators/doorkeeper/templates/migration.rb +7 -4
  66. data/lib/generators/doorkeeper/views_generator.rb +1 -1
  67. data/script/run_all +3 -0
  68. data/spec/controllers/applications_controller_spec.rb +1 -1
  69. data/spec/controllers/authorizations_controller_spec.rb +4 -4
  70. data/spec/controllers/protected_resources_controller_spec.rb +7 -7
  71. data/spec/controllers/token_info_controller_spec.rb +54 -0
  72. data/spec/controllers/tokens_controller_spec.rb +3 -2
  73. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +7 -0
  74. data/spec/dummy/app/models/user.rb +16 -5
  75. data/spec/dummy/config/application.rb +4 -7
  76. data/spec/dummy/config/boot.rb +3 -7
  77. data/spec/dummy/config/initializers/doorkeeper.rb +13 -0
  78. data/spec/dummy/config/mongoid.yml +7 -0
  79. data/spec/dummy/config/routes.rb +29 -1
  80. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +1 -1
  81. data/spec/dummy/db/migrate/20120524202412_create_doorkeeper_tables.rb +6 -4
  82. data/spec/dummy/db/schema.rb +5 -3
  83. data/spec/generators/application_owner_generator_spec.rb +23 -0
  84. data/spec/generators/install_generator_spec.rb +1 -6
  85. data/spec/generators/migration_generator_spec.rb +20 -0
  86. data/spec/lib/config_spec.rb +72 -4
  87. data/spec/lib/models/expirable_spec.rb +8 -11
  88. data/spec/lib/models/revocable_spec.rb +1 -1
  89. data/spec/lib/oauth/access_token_request_spec.rb +15 -9
  90. data/spec/lib/oauth/authorization_request_spec.rb +1 -0
  91. data/spec/lib/oauth/client_credentials_request_spec.rb +15 -9
  92. data/spec/lib/oauth/client_spec.rb +5 -8
  93. data/spec/lib/oauth/helpers/unique_token_spec.rb +2 -20
  94. data/spec/lib/oauth/password_access_token_request_spec.rb +16 -9
  95. data/spec/lib/oauth/token_spec.rb +83 -0
  96. data/spec/models/doorkeeper/access_token_spec.rb +41 -1
  97. data/spec/models/doorkeeper/application_spec.rb +53 -20
  98. data/spec/requests/flows/authorization_code_spec.rb +1 -1
  99. data/spec/requests/flows/client_credentials_spec.rb +2 -0
  100. data/spec/requests/flows/password_spec.rb +25 -0
  101. data/spec/requests/flows/refresh_token_spec.rb +5 -2
  102. data/spec/requests/protected_resources/private_api_spec.rb +10 -3
  103. data/spec/routing/custom_controller_routes_spec.rb +44 -0
  104. data/spec/routing/default_routes_spec.rb +32 -0
  105. data/spec/spec_helper.rb +1 -0
  106. data/spec/spec_helper_integration.rb +18 -8
  107. data/spec/support/dependencies/factory_girl.rb +0 -3
  108. data/spec/support/orm/active_record.rb +11 -0
  109. data/spec/support/orm/mongoid.rb +26 -0
  110. data/spec/support/shared/controllers_shared_context.rb +2 -2
  111. data/spec/support/shared/models_shared_examples.rb +16 -0
  112. data/spec/validators/redirect_uri_validator_spec.rb +40 -0
  113. metadata +61 -37
  114. data/app/helpers/doorkeeper/application_helper.rb +0 -4
  115. data/app/models/doorkeeper/application.rb +0 -54
  116. data/config/routes.rb +0 -9
  117. data/lib/tasks/doorkeeper_tasks.rake +0 -4
  118. data/spec/support/dependencies/database_cleaner.rb +0 -16
@@ -4,8 +4,8 @@ require 'doorkeeper/oauth/client/credentials'
4
4
  module Doorkeeper
5
5
  module OAuth
6
6
  class Client
7
- def self.find(uid)
8
- if application = Doorkeeper::Application.find_by_uid(uid)
7
+ def self.find(uid, method = Doorkeeper::Application.method(:by_uid))
8
+ if application = method.call(uid)
9
9
  new(application)
10
10
  end
11
11
  end
@@ -27,13 +27,16 @@ module Doorkeeper
27
27
  end
28
28
 
29
29
  def authorize
30
- @response = if issuer.create(client, scopes)
30
+ status = issuer.create(client, scopes)
31
+ @response = if status
31
32
  Response.new(issuer.token)
32
33
  else
33
34
  ErrorResponse.from_request(self)
34
35
  end
36
+ status
35
37
  end
36
38
 
39
+ # TODO: duplicated code in all flows
37
40
  def scopes
38
41
  @scopes ||= if @original_scopes.present?
39
42
  Doorkeeper::OAuth::Scopes.from_string(@original_scopes)
@@ -2,13 +2,10 @@ module Doorkeeper
2
2
  module OAuth
3
3
  module Helpers
4
4
  module UniqueToken
5
- def self.generate_for(attribute, klass, options = {})
5
+ def self.generate(options = {})
6
6
  generator_method = options.delete(:generator) || SecureRandom.method(:hex)
7
7
  token_size = options.delete(:size) || 32
8
- loop do
9
- token = generator_method.call(token_size)
10
- break token unless klass.send("find_by_#{attribute}", token)
11
- end
8
+ generator_method.call(token_size)
12
9
  end
13
10
  end
14
11
  end
@@ -51,7 +51,8 @@ module Doorkeeper::OAuth
51
51
  end
52
52
 
53
53
  def access_token
54
- @access_token
54
+ return unless client.present? && resource_owner.present?
55
+ @access_token ||= Doorkeeper::AccessToken.matching_token_for client, resource_owner.id, scopes
55
56
  end
56
57
 
57
58
  def token_type
@@ -85,10 +86,6 @@ module Doorkeeper::OAuth
85
86
  create_access_token
86
87
  end
87
88
 
88
- def revoke_base_token
89
- base_token.revoke
90
- end
91
-
92
89
  def create_access_token
93
90
  @access_token = Doorkeeper::AccessToken.create!({
94
91
  :application_id => client.id,
@@ -0,0 +1,36 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ class Token
4
+ module Methods
5
+ def from_access_token_param(request)
6
+ request.parameters[:access_token]
7
+ end
8
+
9
+ def from_bearer_param(request)
10
+ request.parameters[:bearer_token]
11
+ end
12
+
13
+ def from_bearer_authorization(request)
14
+ pattern = /^Bearer /
15
+ header = request.authorization
16
+ header.gsub pattern, '' if header && header.match(pattern)
17
+ end
18
+ end
19
+
20
+ extend Methods
21
+
22
+ def self.from_request(request, *methods)
23
+ methods.inject(nil) do |credentials, method|
24
+ method = self.method(method) if method.is_a?(Symbol)
25
+ credentials = method.call(request)
26
+ break credentials unless credentials.blank?
27
+ end
28
+ end
29
+
30
+ def self.authenticate(request, *methods)
31
+ token = from_request request, *methods
32
+ Doorkeeper::AccessToken.authenticate(token) if token
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,77 @@
1
+ require 'doorkeeper/rails/routes/mapping'
2
+ require 'doorkeeper/rails/routes/mapper'
3
+
4
+ module Doorkeeper
5
+ module Rails
6
+ class Routes
7
+ module Helper
8
+ # TODO: options hash is not being used
9
+ def use_doorkeeper(options = {}, &block)
10
+ Doorkeeper::Rails::Routes.new(self, &block).generate_routes!(options)
11
+ end
12
+ end
13
+
14
+ def self.install!
15
+ ActionDispatch::Routing::Mapper.send :include, Doorkeeper::Rails::Routes::Helper
16
+ end
17
+
18
+ def self.warn_if_using_mount_method!
19
+ if File.read(::Rails.root + 'config/routes.rb') =~ %r[mount Doorkeeper::Engine]
20
+ warn "\n[DOORKEEPER] `mount Doorkeeper::Engine` is not being used anymore. Please replace it with `use_doorkeeper` in your /config/routes.rb file\n"
21
+ end
22
+ end
23
+
24
+ attr_accessor :routes
25
+
26
+ def initialize(routes, &options)
27
+ @routes, @options = routes, options
28
+ end
29
+
30
+ def generate_routes!(options)
31
+ @mapping = Mapper.new.map(&@options)
32
+ routes.scope 'oauth', :as => 'oauth' do
33
+ map_route(:authorizations, :authorization_routes)
34
+ map_route(:tokens, :token_routes)
35
+ map_route(:applications, :application_routes)
36
+ map_route(:authorized_applications, :authorized_applications_routes)
37
+ map_route(:token_info, :token_info_routes)
38
+ end
39
+ end
40
+
41
+ private
42
+ def map_route(name, method)
43
+ unless @mapping.skipped?(name)
44
+ send method, @mapping[name]
45
+ end
46
+ end
47
+
48
+ def authorization_routes(mapping)
49
+ routes.scope :controller => mapping[:controllers] do
50
+ routes.match 'authorize', :via => :get, :action => :new, :as => mapping[:as]
51
+ routes.match 'authorize', :via => :post, :action => :create, :as => mapping[:as]
52
+ routes.match 'authorize', :via => :delete, :action => :destroy, :as => mapping[:as]
53
+ end
54
+ end
55
+
56
+ def token_routes(mapping)
57
+ routes.scope :controller => mapping[:controllers] do
58
+ routes.match 'token', :via => :post, :action => :create, :as => mapping[:as]
59
+ end
60
+ end
61
+
62
+ def token_info_routes(mapping)
63
+ routes.scope :controller => mapping[:controllers] do
64
+ routes.match 'token/info', :via => :get, :action => :show, :as => mapping[:as]
65
+ end
66
+ end
67
+
68
+ def application_routes(mapping)
69
+ routes.resources :applications, :controller => mapping[:controllers]
70
+ end
71
+
72
+ def authorized_applications_routes(mapping)
73
+ routes.resources :authorized_applications, :only => [:index, :destroy], :controller => mapping[:controllers]
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,28 @@
1
+ module Doorkeeper
2
+ module Rails
3
+ class Routes
4
+ class Mapper
5
+ def initialize(mapping = Mapping.new)
6
+ @mapping = mapping
7
+ end
8
+
9
+ def map(&block)
10
+ self.instance_eval(&block) if block
11
+ @mapping
12
+ end
13
+
14
+ def controllers(controller_names = {})
15
+ @mapping.controllers.merge!(controller_names)
16
+ end
17
+
18
+ def skip_controllers(*controller_names)
19
+ @mapping.skips = controller_names
20
+ end
21
+
22
+ def as(alias_names = {})
23
+ @mapping.as.merge!(alias_names)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module Doorkeeper
2
+ module Rails
3
+ class Routes
4
+ class Mapping
5
+ attr_accessor :controllers, :as, :skips
6
+
7
+ def initialize
8
+ @controllers = {
9
+ :authorizations => 'doorkeeper/authorizations',
10
+ :applications => 'doorkeeper/applications',
11
+ :authorized_applications => 'doorkeeper/authorized_applications',
12
+ :tokens => 'doorkeeper/tokens',
13
+ :token_info => 'doorkeeper/token_info'
14
+ }
15
+
16
+ @as = {
17
+ :authorizations => :authorization,
18
+ :tokens => :token,
19
+ :token_info => :token_info
20
+ }
21
+
22
+ @skips = []
23
+
24
+ end
25
+
26
+ def [](routes)
27
+ {
28
+ :controllers => @controllers[routes],
29
+ :as => @as[routes]
30
+ }
31
+ end
32
+
33
+ def skipped?(controller)
34
+ return @skips.include?(controller)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,3 @@
1
1
  module Doorkeeper
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0.rc1"
3
3
  end
@@ -0,0 +1,15 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ class Doorkeeper::ApplicationOwnerGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+ source_root File.expand_path('../templates', __FILE__)
6
+ desc "Provide support for client application ownership."
7
+
8
+ def application_owner
9
+ migration_template 'add_owner_to_application_migration.rb', 'db/migrate/add_owner_to_application.rb'
10
+ end
11
+
12
+ def self.next_migration_number(dirname)
13
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
14
+ end
15
+ end
@@ -1,19 +1,12 @@
1
- require 'rails/generators/active_record'
2
-
3
- class Doorkeeper::InstallGenerator < Rails::Generators::Base
1
+ class Doorkeeper::InstallGenerator < ::Rails::Generators::Base
4
2
  include Rails::Generators::Migration
5
3
  source_root File.expand_path('../templates', __FILE__)
6
4
  desc "Installs Doorkeeper."
7
5
 
8
6
  def install
9
- migration_template 'migration.rb', 'db/migrate/create_doorkeeper_tables.rb'
10
7
  template "initializer.rb", "config/initializers/doorkeeper.rb"
11
8
  copy_file "../../../../config/locales/en.yml", "config/locales/doorkeeper.en.yml"
12
- route "mount Doorkeeper::Engine => '/oauth'"
9
+ route "use_doorkeeper"
13
10
  readme "README"
14
11
  end
15
-
16
- def self.next_migration_number(dirname)
17
- ActiveRecord::Generators::Base.next_migration_number(dirname)
18
- end
19
12
  end
@@ -0,0 +1,15 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ class Doorkeeper::MigrationGenerator < ::Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+ source_root File.expand_path('../templates', __FILE__)
6
+ desc "Installs Doorkeeper migration file."
7
+
8
+ def install
9
+ migration_template 'migration.rb', 'db/migrate/create_doorkeeper_tables.rb'
10
+ end
11
+
12
+ def self.next_migration_number(dirname)
13
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
14
+ end
15
+ end
@@ -7,7 +7,21 @@ Go to config/initializers/doorkeeper.rb and configure
7
7
  resource_owner_authenticator block.
8
8
 
9
9
  Step 2.
10
- Migrate your database
10
+ Choose the ORM:
11
+
12
+ If you want to use ActiveRecord run:
13
+
14
+ rails generate doorkeeper:migration
15
+
16
+ And run
17
+
18
+ rake db:migrate
19
+
20
+ If you want to use Mongoid, configure the orm in initializers/doorkeeper.rb
21
+
22
+ Doorkeeper.configure do
23
+ orm :mongoid
24
+ end
11
25
 
12
26
  Step 3.
13
27
  That's it, that's all. Enjoy!
@@ -0,0 +1,7 @@
1
+ class AddOwnerToApplication < ActiveRecord::Migration
2
+ def change
3
+ add_column :oauth_applications, :owner_id, :integer, :null => true
4
+ add_column :oauth_applications, :owner_type, :string, :null => true
5
+ add_index :oauth_applications, [:owner_id, :owner_type]
6
+ end
7
+ end
@@ -1,26 +1,30 @@
1
1
  Doorkeeper.configure do
2
- # This block will be called to check whether the
3
- # resource owner is authenticated or not
2
+ # Change the ORM that doorkeeper will use.
3
+ # Currently supported options are :active_record and :mongoid
4
+ orm :active_record
5
+
6
+ # This block will be called to check whether the resource owner is authenticated or not.
4
7
  resource_owner_authenticator do |routes|
5
8
  raise "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
6
9
  # Put your resource owner authentication logic here.
7
- # If you want to use named routes from your app you need
8
- # to call them on routes object eg.
9
- # routes.new_user_session_path
10
- # e.g. User.find_by_id(session[:user_id]) || redirect_to(routes.new_user_session_url)
10
+ # If you want to use named routes from your app, you need to call them on the routes object.
11
+ # For example:
12
+ # routes.new_user_session_path
13
+ # Example implementation:
14
+ # User.find_by_id(session[:user_id]) || redirect_to(routes.new_user_session_url)
11
15
  end
12
16
 
13
- # If you want to restrict the access to the web interface for
14
- # adding oauth authorized applications you need to declare the
15
- # block below
17
+ # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
16
18
  # admin_authenticator do |routes|
17
19
  # # Put your admin authentication logic here.
18
- # # If you want to use named routes from your app you need
19
- # # to call them on routes object eg.
20
- # # routes.new_admin_session_path
20
+ # # If you want to use named routes from your app, you need to call them on routes object, e.g., routes.new_admin_session_path
21
+ # # Example implementation:
21
22
  # Admin.find_by_id(session[:admin_id]) || redirect_to(routes.new_admin_session_url)
22
23
  # end
23
24
 
25
+ # Authorization Code expiration time (default 10 minutes).
26
+ # authorization_code_expires_in 10.minutes
27
+
24
28
  # Access token expiration time (default 2 hours).
25
29
  # If you want to disable expiration, set this to nil.
26
30
  # access_token_expires_in 2.hours
@@ -28,14 +32,26 @@ Doorkeeper.configure do
28
32
  # Issue access tokens with refresh token (disabled by default)
29
33
  # use_refresh_token
30
34
 
35
+ # Provide support for an owner to be assigned to each registered application (disabled by default)
36
+ # Optional parameter :confirmation => true (default false) if you want to enforce ownership of
37
+ # a registered application
38
+ # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
39
+ # enable_application_owner :confirmation => false
40
+
31
41
  # Define access token scopes for your provider
32
42
  # For more information go to https://github.com/applicake/doorkeeper/wiki/Using-Scopes
33
43
  # default_scopes :public
34
44
  # optional_scopes :write, :update
35
45
 
36
46
  # Change the way client credentials are retrieved from the request object.
37
- # By default it retrieves first from `HTTP_AUTHORIZATION` header and
38
- # fallsback to `:client_id` and `:client_secret` from `params` object
39
- # Check out the wiki for mor information on customization
47
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
48
+ # falls back to the `:client_id` and `:client_secret` params from the `params` object.
49
+ # Check out the wiki for more information on customization
40
50
  # client_credentials :from_basic, :from_params
51
+
52
+ # Change the way access token is authenticated from the request object.
53
+ # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
54
+ # falls back to the `:access_token` or `:bearer_token` params from the `params` object.
55
+ # Check out the wiki for mor information on customization
56
+ # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
41
57
  end
@@ -1,14 +1,17 @@
1
1
  class CreateDoorkeeperTables < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :oauth_applications do |t|
4
- t.string :name, :null => false
5
- t.string :uid, :null => false
6
- t.string :secret, :null => false
7
- t.string :redirect_uri, :null => false
4
+ t.string :name, :null => false
5
+ t.string :uid, :null => false
6
+ t.string :secret, :null => false
7
+ t.string :redirect_uri, :null => false
8
+ t.integer :owner_id, :null => true
9
+ t.string :owner_type, :null => true
8
10
  t.timestamps
9
11
  end
10
12
 
11
13
  add_index :oauth_applications, :uid, :unique => true
14
+ add_index :oauth_applications, [:owner_id, :owner_type]
12
15
 
13
16
  create_table :oauth_access_grants do |t|
14
17
  t.integer :resource_owner_id, :null => false