brycesch-devise_oauth2_providable 1.1.7

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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.ruby_gemset +1 -0
  4. data/.ruby_version +1 -0
  5. data/CONTRIBUTORS.txt +6 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +160 -0
  9. data/Rakefile +8 -0
  10. data/app/controllers/devise/oauth2_providable/authorizations_controller.rb +59 -0
  11. data/app/controllers/devise/oauth2_providable/tokens_controller.rb +35 -0
  12. data/app/models/devise/oauth2_providable/access_token.rb +25 -0
  13. data/app/models/devise/oauth2_providable/authorization_code.rb +3 -0
  14. data/app/models/devise/oauth2_providable/client.rb +26 -0
  15. data/app/models/devise/oauth2_providable/refresh_token.rb +6 -0
  16. data/app/views/devise/oauth2_providable/authorizations/_form.html.erb +7 -0
  17. data/app/views/devise/oauth2_providable/authorizations/error.html.erb +4 -0
  18. data/app/views/devise/oauth2_providable/authorizations/new.html.erb +4 -0
  19. data/config/routes.rb +6 -0
  20. data/db/migrate/20111014160714_create_devise_oauth2_providable_schema.rb +58 -0
  21. data/devise_oauth2_providable.gemspec +33 -0
  22. data/lib/devise/oauth2_providable/engine.rb +16 -0
  23. data/lib/devise/oauth2_providable/expirable_token.rb +56 -0
  24. data/lib/devise/oauth2_providable/models/oauth2_authorization_code_grantable.rb +6 -0
  25. data/lib/devise/oauth2_providable/models/oauth2_password_grantable.rb +6 -0
  26. data/lib/devise/oauth2_providable/models/oauth2_providable.rb +13 -0
  27. data/lib/devise/oauth2_providable/models/oauth2_refresh_token_grantable.rb +6 -0
  28. data/lib/devise/oauth2_providable/strategies/oauth2_authorization_code_grant_type_strategy.rb +21 -0
  29. data/lib/devise/oauth2_providable/strategies/oauth2_grant_type_strategy.rb +44 -0
  30. data/lib/devise/oauth2_providable/strategies/oauth2_password_grant_type_strategy.rb +22 -0
  31. data/lib/devise/oauth2_providable/strategies/oauth2_providable_strategy.rb +31 -0
  32. data/lib/devise/oauth2_providable/strategies/oauth2_refresh_token_grant_type_strategy.rb +22 -0
  33. data/lib/devise/oauth2_providable/version.rb +5 -0
  34. data/lib/devise_oauth2_providable.rb +41 -0
  35. data/script/rails +6 -0
  36. data/spec/controllers/authorizations_controller_spec.rb +32 -0
  37. data/spec/controllers/protected_controller_spec.rb +43 -0
  38. data/spec/controllers/tokens_controller_spec.rb +50 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +7 -0
  41. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  42. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  43. data/spec/dummy/app/controllers/protected_controller.rb +7 -0
  44. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy/app/mailers/.gitkeep +0 -0
  46. data/spec/dummy/app/models/.gitkeep +0 -0
  47. data/spec/dummy/app/models/user.rb +3 -0
  48. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  49. data/spec/dummy/config.ru +4 -0
  50. data/spec/dummy/config/application.rb +51 -0
  51. data/spec/dummy/config/boot.rb +10 -0
  52. data/spec/dummy/config/database.yml +25 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +32 -0
  55. data/spec/dummy/config/environments/production.rb +62 -0
  56. data/spec/dummy/config/environments/test.rb +42 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/devise.rb +259 -0
  59. data/spec/dummy/config/initializers/inflections.rb +10 -0
  60. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  61. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  62. data/spec/dummy/config/initializers/session_store.rb +8 -0
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  64. data/spec/dummy/config/locales/devise.en.yml +58 -0
  65. data/spec/dummy/config/locales/en.yml +5 -0
  66. data/spec/dummy/config/routes.rb +7 -0
  67. data/spec/dummy/db/migrate/20111014142838_create_users.rb +9 -0
  68. data/spec/dummy/db/migrate/20111014161437_create_devise_oauth2_providable_schema.rb +55 -0
  69. data/spec/dummy/db/schema.rb +78 -0
  70. data/spec/dummy/lib/assets/.gitkeep +0 -0
  71. data/spec/dummy/public/404.html +26 -0
  72. data/spec/dummy/public/422.html +26 -0
  73. data/spec/dummy/public/500.html +26 -0
  74. data/spec/dummy/public/favicon.ico +0 -0
  75. data/spec/dummy/script/rails +6 -0
  76. data/spec/factories/client_factory.rb +7 -0
  77. data/spec/factories/user_factory.rb +6 -0
  78. data/spec/integration/oauth2_authorization_token_grant_type_strategy_spec.rb +137 -0
  79. data/spec/integration/oauth2_password_grant_type_strategy_spec.rb +174 -0
  80. data/spec/integration/oauth2_refresh_token_grant_type_strategy_spec.rb +138 -0
  81. data/spec/lib/devise_oauth2_providable_spec.rb +7 -0
  82. data/spec/models/access_token_spec.rb +50 -0
  83. data/spec/models/authorization_code_spec.rb +21 -0
  84. data/spec/models/client_spec.rb +17 -0
  85. data/spec/models/refresh_token_spec.rb +23 -0
  86. data/spec/models/user_spec.rb +6 -0
  87. data/spec/routing/authorizations_routing_spec.rb +16 -0
  88. data/spec/routing/tokens_routing_spec.rb +9 -0
  89. data/spec/spec_helper.rb +33 -0
  90. data/spec/support/match_json.rb +6 -0
  91. metadata +330 -0
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ Devise::Oauth2Providable::Engine.routes.draw do
2
+ root :to => "authorizations#new"
3
+ resources :authorizations, :only => :create
4
+ match 'authorize' => 'authorizations#new', via: [:get, :post]
5
+ resource :token, :only => [:create, :destroy]
6
+ end
@@ -0,0 +1,58 @@
1
+ class CreateDeviseOauth2ProvidableSchema < ActiveRecord::Migration
2
+ def change
3
+ create_table :oauth2_clients do |t|
4
+ t.string :name
5
+ t.string :redirect_uri
6
+ t.string :website
7
+ t.string :identifier
8
+ t.string :secret
9
+ t.timestamps
10
+ end
11
+
12
+ change_table :oauth2_clients do |t|
13
+ t.index :identifier, :unique => true
14
+ end
15
+
16
+ create_table :oauth2_access_tokens do |t|
17
+ t.belongs_to :user, :client, :refresh_token
18
+ t.string :token
19
+ t.datetime :expires_at
20
+ t.timestamps
21
+ end
22
+
23
+ change_table :oauth2_access_tokens do |t|
24
+ t.index :token, :unique => true
25
+ t.index :expires_at
26
+ t.index :user_id
27
+ t.index :client_id
28
+ end
29
+
30
+ create_table :oauth2_refresh_tokens do |t|
31
+ t.belongs_to :user, :client
32
+ t.string :token
33
+ t.datetime :expires_at
34
+ t.timestamps
35
+ end
36
+
37
+ change_table :oauth2_refresh_tokens do |t|
38
+ t.index :token, :unique => true
39
+ t.index :expires_at
40
+ t.index :user_id
41
+ t.index :client_id
42
+ end
43
+
44
+ create_table :oauth2_authorization_codes do |t|
45
+ t.belongs_to :user, :client
46
+ t.string :token
47
+ t.datetime :expires_at
48
+ t.timestamps
49
+ end
50
+
51
+ change_table :oauth2_authorization_codes do |t|
52
+ t.index :token, :unique => true
53
+ t.index :expires_at
54
+ t.index :user_id
55
+ t.index :client_id
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "devise/oauth2_providable/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "brycesch-devise_oauth2_providable"
8
+ spec.version = Devise::Oauth2Providable::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.authors = ["Ryan Sonnek"]
11
+ spec.email = ["ryan@socialcast.com"]
12
+ spec.homepage = ""
13
+ spec.summary = %q{OAuth2 Provider for Rails applications}
14
+ spec.description = %q{Rails3 engine that adds OAuth2 Provider support to any application built with Devise authentication}
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rails", "> 4.0.0"
22
+ spec.add_dependency "devise"
23
+ spec.add_dependency "rack-oauth2"
24
+
25
+ spec.add_development_dependency 'rspec-rails', "~> 2.14.2"
26
+ # spec.add_development_dependency 'minitest'
27
+ spec.add_development_dependency 'shoulda-matchers'
28
+ spec.add_development_dependency 'shoulda-kept-assign-to'
29
+ spec.add_development_dependency "database_cleaner", "~> 1.3.0"
30
+ spec.add_development_dependency "sqlite3"
31
+ spec.add_development_dependency "pry"
32
+ spec.add_development_dependency "factory_girl_rails"
33
+ end
@@ -0,0 +1,16 @@
1
+ module Devise
2
+ module Oauth2Providable
3
+ class Engine < Rails::Engine
4
+ config.devise_oauth2_providable = ActiveSupport::OrderedOptions.new
5
+ config.devise_oauth2_providable.access_token_expires_in = 15.minutes
6
+ config.devise_oauth2_providable.refresh_token_expires_in = 1.month
7
+ config.devise_oauth2_providable.authorization_code_expires_in = 1.minute
8
+
9
+ engine_name 'oauth2'
10
+ isolate_namespace Devise::Oauth2Providable
11
+ initializer "devise_oauth2_providable.initialize_application", :before=> :load_config_initializers do |app|
12
+ app.config.filter_parameters << :client_secret
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,56 @@
1
+ require 'active_support/concern'
2
+ require 'active_record'
3
+
4
+ module Devise
5
+ module Oauth2Providable
6
+ module ExpirableToken
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def expires_according_to(config_name)
11
+ cattr_accessor :default_lifetime
12
+ self.default_lifetime = Rails.application.config.devise_oauth2_providable[config_name]
13
+
14
+ belongs_to :user
15
+ belongs_to :client
16
+
17
+ after_initialize :init_token, :on => :create, :unless => :token?
18
+ after_initialize :init_expires_at, :on => :create, :unless => :expires_at?
19
+ validates :expires_at, :presence => true
20
+ validates :client, :presence => true
21
+ validates :token, :presence => true, :uniqueness => true
22
+
23
+ default_scope lambda {
24
+ where(self.arel_table[:expires_at].gteq(Time.now.utc))
25
+ }
26
+
27
+ include LocalInstanceMethods
28
+ end
29
+ end
30
+
31
+ module LocalInstanceMethods
32
+ # number of seconds until the token expires
33
+ def expires_in
34
+ (expires_at - Time.now.utc).to_i
35
+ end
36
+
37
+ # forcefully expire the token
38
+ def expired!
39
+ self.expires_at = Time.now.utc
40
+ self.save!
41
+ end
42
+
43
+ private
44
+
45
+ def init_token
46
+ self.token = Devise::Oauth2Providable.random_id
47
+ end
48
+ def init_expires_at
49
+ self.expires_at = self.default_lifetime.from_now
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ ActiveRecord::Base.send :include, Devise::Oauth2Providable::ExpirableToken
@@ -0,0 +1,6 @@
1
+ module Devise
2
+ module Models
3
+ module Oauth2AuthorizationCodeGrantable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Devise
2
+ module Models
3
+ module Oauth2PasswordGrantable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ require 'devise/models'
2
+
3
+ module Devise
4
+ module Models
5
+ module Oauth2Providable
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ has_many :access_tokens, :class_name => 'Devise::Oauth2Providable::AccessToken'
9
+ has_many :authorization_codes, :class_name => 'Devise::Oauth2Providable::AuthorizationCode'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module Devise
2
+ module Models
3
+ module Oauth2RefreshTokenGrantable
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ require 'devise/oauth2_providable/strategies/oauth2_grant_type_strategy'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2AuthorizationCodeGrantTypeStrategy < Oauth2GrantTypeStrategy
6
+ def grant_type
7
+ 'authorization_code'
8
+ end
9
+
10
+ def authenticate_grant_type(client)
11
+ if code = client.authorization_codes.find_by_token(params[:code])
12
+ success! code.user
13
+ else
14
+ oauth_error! :invalid_grant, 'invalid authorization code request'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ Warden::Strategies.add(:oauth2_authorization_code_grantable, Devise::Strategies::Oauth2AuthorizationCodeGrantTypeStrategy)
@@ -0,0 +1,44 @@
1
+ require 'devise/strategies/base'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2GrantTypeStrategy < Authenticatable
6
+
7
+ def store?
8
+ false
9
+ end
10
+
11
+ def valid?
12
+ params[:controller] == 'devise/oauth2_providable/tokens' && request.post? && params[:grant_type] == grant_type
13
+ end
14
+
15
+ # defined by subclass
16
+ def grant_type
17
+ end
18
+
19
+ # defined by subclass
20
+ def authenticate_grant_type(client)
21
+ end
22
+
23
+ def authenticate!
24
+ client_id, client_secret = request.authorization ? decode_credentials : [params[:client_id], params[:client_secret]]
25
+ client = Devise::Oauth2Providable::Client.find_by_identifier client_id
26
+ if client && client.secret == client_secret
27
+ env[Devise::Oauth2Providable::CLIENT_ENV_REF] = client
28
+ authenticate_grant_type(client)
29
+ else
30
+ oauth_error! :invalid_client, 'invalid client credentials'
31
+ end
32
+ end
33
+
34
+ # return custom error response in accordance with the oauth spec
35
+ # see http://tools.ietf.org/html/draft-ietf-oauth-v2-16#section-4.3
36
+ def oauth_error!(error_code = :invalid_request, description = nil)
37
+ body = {:error => error_code}
38
+ body[:error_description] = description if description
39
+ custom! [400, {'Content-Type' => 'application/json'}, [body.to_json]]
40
+ throw :warden
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,22 @@
1
+ require 'devise/oauth2_providable/strategies/oauth2_grant_type_strategy'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2PasswordGrantTypeStrategy < Oauth2GrantTypeStrategy
6
+ def grant_type
7
+ 'password'
8
+ end
9
+
10
+ def authenticate_grant_type(client)
11
+ resource = mapping.to.find_for_database_authentication(mapping.to.authentication_keys.first => params[:username])
12
+ if validate(resource) { resource.valid_password?(params[:password]) }
13
+ success! resource
14
+ else
15
+ oauth_error! :invalid_grant, 'invalid password authentication request'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Warden::Strategies.add(:oauth2_password_grantable, Devise::Strategies::Oauth2PasswordGrantTypeStrategy)
@@ -0,0 +1,31 @@
1
+ require 'devise/strategies/base'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2Providable < Authenticatable
6
+
7
+ def store?
8
+ false
9
+ end
10
+
11
+ def valid?
12
+ @req = Rack::OAuth2::Server::Resource::Bearer::Request.new(env)
13
+ @req.oauth2?
14
+ end
15
+
16
+ def authenticate!
17
+ @req.setup!
18
+ token = Devise::Oauth2Providable::AccessToken.find_by_token @req.access_token
19
+ env[Devise::Oauth2Providable::CLIENT_ENV_REF] = token.client if token
20
+ resource = token ? token.user : nil
21
+ if validate(resource)
22
+ success! resource
23
+ else
24
+ fail(:invalid_token)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ Warden::Strategies.add(:oauth2_providable, Devise::Strategies::Oauth2Providable)
@@ -0,0 +1,22 @@
1
+ require 'devise/oauth2_providable/strategies/oauth2_grant_type_strategy'
2
+
3
+ module Devise
4
+ module Strategies
5
+ class Oauth2RefreshTokenGrantTypeStrategy < Oauth2GrantTypeStrategy
6
+ def grant_type
7
+ 'refresh_token'
8
+ end
9
+
10
+ def authenticate_grant_type(client)
11
+ if refresh_token = client.refresh_tokens.find_by_token(params[:refresh_token])
12
+ env[Devise::Oauth2Providable::REFRESH_TOKEN_ENV_REF] = refresh_token
13
+ success! refresh_token.user
14
+ else
15
+ oauth_error! :invalid_grant, 'invalid refresh token'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Warden::Strategies.add(:oauth2_refresh_token_grantable, Devise::Strategies::Oauth2RefreshTokenGrantTypeStrategy)
@@ -0,0 +1,5 @@
1
+ module Devise
2
+ module Oauth2Providable
3
+ VERSION = "1.1.7"
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ require 'devise'
2
+ require 'rack/oauth2'
3
+ require 'devise/oauth2_providable/engine'
4
+ require 'devise/oauth2_providable/expirable_token'
5
+ require 'devise/oauth2_providable/strategies/oauth2_providable_strategy'
6
+ require 'devise/oauth2_providable/strategies/oauth2_password_grant_type_strategy'
7
+ require 'devise/oauth2_providable/strategies/oauth2_refresh_token_grant_type_strategy'
8
+ require 'devise/oauth2_providable/strategies/oauth2_authorization_code_grant_type_strategy'
9
+ require 'devise/oauth2_providable/models/oauth2_providable'
10
+ require 'devise/oauth2_providable/models/oauth2_password_grantable'
11
+ require 'devise/oauth2_providable/models/oauth2_refresh_token_grantable'
12
+ require 'devise/oauth2_providable/models/oauth2_authorization_code_grantable'
13
+
14
+ module Devise
15
+ module Oauth2Providable
16
+ CLIENT_ENV_REF = 'oauth2.client'
17
+ REFRESH_TOKEN_ENV_REF = "oauth2.refresh_token"
18
+
19
+ class << self
20
+ def random_id
21
+ SecureRandom.hex
22
+ end
23
+ def table_name_prefix
24
+ 'oauth2_'
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ Devise.add_module(:oauth2_providable,
31
+ :strategy => true,
32
+ :model => 'devise/oauth2_providable/models/oauth2_providable')
33
+ Devise.add_module(:oauth2_password_grantable,
34
+ :strategy => true,
35
+ :model => 'devise/oauth2_providable/models/oauth2_password_grantable')
36
+ Devise.add_module(:oauth2_refresh_token_grantable,
37
+ :strategy => true,
38
+ :model => 'devise/oauth2_providable/models/oauth2_refresh_token_grantable')
39
+ Devise.add_module(:oauth2_authorization_code_grantable,
40
+ :strategy => true,
41
+ :model => 'devise/oauth2_providable/models/oauth2_authorization_code_grantable')
data/script/rails ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ #!/usr/bin/env ruby
3
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
4
+
5
+ ENGINE_PATH = File.expand_path('../..', __FILE__)
6
+ load File.expand_path('../../spec/dummy/script/rails', __FILE__)
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Devise::Oauth2Providable::AuthorizationsController do
4
+ routes { Devise::Oauth2Providable::Engine.routes }
5
+ describe 'GET #new' do
6
+ context 'with valid redirect_uri' do
7
+ let(:user) { FactoryGirl.create :user }
8
+ let(:client) { FactoryGirl.create :client }
9
+ let(:redirect_uri) { client.redirect_uri }
10
+ before do
11
+ sign_in user
12
+ get :new, :client_id => client.identifier, :redirect_uri => redirect_uri, response_type: 'code'
13
+ end
14
+ it { should respond_with :success }
15
+ # it { should respond_with_content_type :html }
16
+ it { should assign_to(:redirect_uri).with(redirect_uri) }
17
+ it { should assign_to(:response_type) }
18
+ it { should render_template 'devise/oauth2_providable/authorizations/new' }
19
+ end
20
+ context 'with invalid redirect_uri' do
21
+ let(:user) { FactoryGirl.create :user }
22
+ let(:client) { FactoryGirl.create :client }
23
+ let(:redirect_uri) { 'http://example.com/foo/bar' }
24
+ before do
25
+ sign_in user
26
+ get :new, :client_id => client.identifier, :redirect_uri => redirect_uri, response_type: 'code'
27
+ end
28
+ it { should respond_with :bad_request }
29
+ # it { should respond_with_content_type :html }
30
+ end
31
+ end
32
+ end