grape_oauth2 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +18 -0
  5. data/.travis.yml +42 -0
  6. data/Gemfile +23 -0
  7. data/README.md +820 -0
  8. data/Rakefile +11 -0
  9. data/gemfiles/active_record.rb +25 -0
  10. data/gemfiles/mongoid.rb +14 -0
  11. data/gemfiles/sequel.rb +24 -0
  12. data/grape_oauth2.gemspec +27 -0
  13. data/grape_oauth2.png +0 -0
  14. data/lib/grape_oauth2.rb +129 -0
  15. data/lib/grape_oauth2/configuration.rb +143 -0
  16. data/lib/grape_oauth2/configuration/class_accessors.rb +36 -0
  17. data/lib/grape_oauth2/configuration/validation.rb +71 -0
  18. data/lib/grape_oauth2/endpoints/authorize.rb +34 -0
  19. data/lib/grape_oauth2/endpoints/token.rb +72 -0
  20. data/lib/grape_oauth2/gem_version.rb +24 -0
  21. data/lib/grape_oauth2/generators/authorization.rb +44 -0
  22. data/lib/grape_oauth2/generators/base.rb +26 -0
  23. data/lib/grape_oauth2/generators/token.rb +62 -0
  24. data/lib/grape_oauth2/helpers/access_token_helpers.rb +54 -0
  25. data/lib/grape_oauth2/helpers/oauth_params.rb +41 -0
  26. data/lib/grape_oauth2/mixins/active_record/access_grant.rb +47 -0
  27. data/lib/grape_oauth2/mixins/active_record/access_token.rb +75 -0
  28. data/lib/grape_oauth2/mixins/active_record/client.rb +35 -0
  29. data/lib/grape_oauth2/mixins/mongoid/access_grant.rb +58 -0
  30. data/lib/grape_oauth2/mixins/mongoid/access_token.rb +88 -0
  31. data/lib/grape_oauth2/mixins/mongoid/client.rb +41 -0
  32. data/lib/grape_oauth2/mixins/sequel/access_grant.rb +68 -0
  33. data/lib/grape_oauth2/mixins/sequel/access_token.rb +86 -0
  34. data/lib/grape_oauth2/mixins/sequel/client.rb +46 -0
  35. data/lib/grape_oauth2/responses/authorization.rb +10 -0
  36. data/lib/grape_oauth2/responses/base.rb +56 -0
  37. data/lib/grape_oauth2/responses/token.rb +10 -0
  38. data/lib/grape_oauth2/scopes.rb +74 -0
  39. data/lib/grape_oauth2/strategies/authorization_code.rb +38 -0
  40. data/lib/grape_oauth2/strategies/base.rb +47 -0
  41. data/lib/grape_oauth2/strategies/client_credentials.rb +20 -0
  42. data/lib/grape_oauth2/strategies/password.rb +22 -0
  43. data/lib/grape_oauth2/strategies/refresh_token.rb +47 -0
  44. data/lib/grape_oauth2/unique_token.rb +20 -0
  45. data/lib/grape_oauth2/version.rb +14 -0
  46. data/spec/configuration/config_spec.rb +231 -0
  47. data/spec/configuration/version_spec.rb +12 -0
  48. data/spec/dummy/endpoints/custom_authorization.rb +25 -0
  49. data/spec/dummy/endpoints/custom_token.rb +35 -0
  50. data/spec/dummy/endpoints/status.rb +25 -0
  51. data/spec/dummy/grape_oauth2_config.rb +11 -0
  52. data/spec/dummy/orm/active_record/app/config/db.rb +7 -0
  53. data/spec/dummy/orm/active_record/app/models/access_code.rb +3 -0
  54. data/spec/dummy/orm/active_record/app/models/access_token.rb +3 -0
  55. data/spec/dummy/orm/active_record/app/models/application.rb +3 -0
  56. data/spec/dummy/orm/active_record/app/models/application_record.rb +3 -0
  57. data/spec/dummy/orm/active_record/app/models/user.rb +10 -0
  58. data/spec/dummy/orm/active_record/app/twitter.rb +36 -0
  59. data/spec/dummy/orm/active_record/config.ru +7 -0
  60. data/spec/dummy/orm/active_record/db/schema.rb +53 -0
  61. data/spec/dummy/orm/mongoid/app/config/db.rb +6 -0
  62. data/spec/dummy/orm/mongoid/app/config/mongoid.yml +21 -0
  63. data/spec/dummy/orm/mongoid/app/models/access_code.rb +3 -0
  64. data/spec/dummy/orm/mongoid/app/models/access_token.rb +3 -0
  65. data/spec/dummy/orm/mongoid/app/models/application.rb +3 -0
  66. data/spec/dummy/orm/mongoid/app/models/user.rb +11 -0
  67. data/spec/dummy/orm/mongoid/app/twitter.rb +34 -0
  68. data/spec/dummy/orm/mongoid/config.ru +5 -0
  69. data/spec/dummy/orm/sequel/app/config/db.rb +1 -0
  70. data/spec/dummy/orm/sequel/app/models/access_code.rb +4 -0
  71. data/spec/dummy/orm/sequel/app/models/access_token.rb +4 -0
  72. data/spec/dummy/orm/sequel/app/models/application.rb +4 -0
  73. data/spec/dummy/orm/sequel/app/models/application_record.rb +2 -0
  74. data/spec/dummy/orm/sequel/app/models/user.rb +11 -0
  75. data/spec/dummy/orm/sequel/app/twitter.rb +47 -0
  76. data/spec/dummy/orm/sequel/config.ru +5 -0
  77. data/spec/dummy/orm/sequel/db/schema.rb +50 -0
  78. data/spec/lib/scopes_spec.rb +50 -0
  79. data/spec/mixins/active_record/access_token_spec.rb +185 -0
  80. data/spec/mixins/active_record/client_spec.rb +95 -0
  81. data/spec/mixins/mongoid/access_token_spec.rb +185 -0
  82. data/spec/mixins/mongoid/client_spec.rb +95 -0
  83. data/spec/mixins/sequel/access_token_spec.rb +185 -0
  84. data/spec/mixins/sequel/client_spec.rb +96 -0
  85. data/spec/requests/flows/authorization_code_spec.rb +67 -0
  86. data/spec/requests/flows/client_credentials_spec.rb +101 -0
  87. data/spec/requests/flows/password_spec.rb +210 -0
  88. data/spec/requests/flows/refresh_token_spec.rb +222 -0
  89. data/spec/requests/flows/revoke_token_spec.rb +103 -0
  90. data/spec/requests/protected_resources_spec.rb +64 -0
  91. data/spec/spec_helper.rb +60 -0
  92. data/spec/support/api_helper.rb +11 -0
  93. metadata +257 -0
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Grape::OAuth2 Version' do
4
+ it 'has a version string' do
5
+ expect(Grape::OAuth2::VERSION::STRING).to be_present
6
+ end
7
+
8
+ it 'returns version as an instance of Gem::Version' do
9
+ expect(Grape::OAuth2.gem_version).to be_an_instance_of(Gem::Version)
10
+ expect(Grape::OAuth2.version).to be_an_instance_of(Gem::Version)
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ module Twitter
2
+ module Endpoints
3
+ class CustomAuthorization < ::Grape::API
4
+ helpers Grape::OAuth2::Helpers::OAuthParams
5
+
6
+ namespace :oauth do
7
+ params do
8
+ use :oauth_authorization_params
9
+ end
10
+
11
+ post :custom_authorize do
12
+ response = Grape::OAuth2::Generators::Authorization.generate_for(env) do |request, response|
13
+ request.unsupported_response_type!
14
+ end
15
+
16
+ # Status
17
+ status response.status
18
+
19
+ # Body
20
+ body response.body
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ module Twitter
2
+ module Endpoints
3
+ class CustomToken < ::Grape::API
4
+ helpers Grape::OAuth2::Helpers::OAuthParams
5
+
6
+ namespace :oauth do
7
+ params do
8
+ use :oauth_token_params
9
+ end
10
+
11
+ post :custom_token do
12
+ token_response = Grape::OAuth2::Generators::Token.generate_for(env) do |request, response|
13
+ # Custom client authentication:
14
+ client = Grape::OAuth2::Strategies::Base.authenticate_client(request)
15
+ request.invalid_client! if client.nil? || client.name != 'Admin'
16
+
17
+ resource_owner = Grape::OAuth2::Strategies::Base.authenticate_resource_owner(client, request)
18
+ request.invalid_grant! if resource_owner.nil?
19
+
20
+ token = AccessToken.create_for(client, resource_owner, request.scope.join(' '))
21
+ response.access_token = Grape::OAuth2::Strategies::Base.expose_to_bearer_token(token)
22
+ end
23
+
24
+ status token_response.status
25
+
26
+ token_response.headers.each do |key, value|
27
+ header key, value
28
+ end
29
+
30
+ body token_response.body
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module Twitter
2
+ module Endpoints
3
+ class Status < Grape::API
4
+ before do
5
+ access_token_required!
6
+ end
7
+
8
+ resources :status do
9
+ get do
10
+ { value: 'Nice day!', current_user: current_resource_owner.username }
11
+ end
12
+
13
+ get :single_scope, scopes: [:read] do
14
+ { value: 'Access granted' }
15
+ end
16
+
17
+ get :multiple_scopes, scopes: [:read, :write] do
18
+ access_token_required!
19
+
20
+ { value: 'Access granted' }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ # Common config across all the ORMs
2
+ Grape::OAuth2.configure do |config|
3
+ config.client_class_name = 'Application'
4
+ config.access_token_class_name = 'AccessToken'
5
+ config.resource_owner_class_name = 'User'
6
+ config.access_grant_class_name = 'AccessCode'
7
+
8
+ config.realm = 'Custom Realm'
9
+
10
+ config.allowed_grant_types << 'refresh_token'
11
+ end
@@ -0,0 +1,7 @@
1
+ OTR::ActiveRecord.configure_from_hash!(adapter: 'sqlite3', database: ':memory:')
2
+
3
+ ::ActiveRecord::Base.default_timezone = :utc
4
+ ::ActiveRecord::Base.logger = ENV['RAILS_ENV'] == 'test' ? nil : Logger.new(STDOUT)
5
+
6
+ ::ActiveRecord::Migration.verbose = false
7
+ load File.expand_path('../../../db/schema.rb', __FILE__)
@@ -0,0 +1,3 @@
1
+ class AccessCode < ApplicationRecord
2
+ include Grape::OAuth2::ActiveRecord::AccessGrant
3
+ end
@@ -0,0 +1,3 @@
1
+ class AccessToken < ApplicationRecord
2
+ include Grape::OAuth2::ActiveRecord::AccessToken
3
+ end
@@ -0,0 +1,3 @@
1
+ class Application < ApplicationRecord
2
+ include Grape::OAuth2::ActiveRecord::Client
3
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ::ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -0,0 +1,10 @@
1
+ class User < ApplicationRecord
2
+ has_secure_password
3
+
4
+ def self.oauth_authenticate(_client, username, password)
5
+ user = find_by(username: username)
6
+ return if user.nil?
7
+
8
+ user.authenticate(password)
9
+ end
10
+ end
@@ -0,0 +1,36 @@
1
+ require 'otr-activerecord'
2
+ require 'grape'
3
+
4
+ require File.expand_path('../../../../../../lib/grape_oauth2', __FILE__)
5
+
6
+ # Database
7
+ load File.expand_path('../config/db.rb', __FILE__)
8
+
9
+ # Grape::OAuth2 config
10
+ load File.expand_path('../../../../grape_oauth2_config.rb', __FILE__)
11
+
12
+ # Models
13
+ require_relative 'models/application_record'
14
+ require_relative 'models/access_token'
15
+ require_relative 'models/access_code'
16
+ require_relative 'models/application'
17
+ require_relative 'models/user'
18
+
19
+ # Twitter Endpoints
20
+ require_relative '../../../endpoints/custom_token'
21
+ require_relative '../../../endpoints/custom_authorization'
22
+ require_relative '../../../endpoints/status'
23
+
24
+ module Twitter
25
+ class API < Grape::API
26
+ version 'v1', using: :path
27
+ format :json
28
+ prefix :api
29
+
30
+ include Grape::OAuth2.api
31
+
32
+ mount Twitter::Endpoints::Status
33
+ mount Twitter::Endpoints::CustomToken
34
+ mount Twitter::Endpoints::CustomAuthorization
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'app/twitter'
4
+
5
+ use OTR::ActiveRecord::ConnectionManagement
6
+
7
+ run Twitter::API
@@ -0,0 +1,53 @@
1
+ ActiveRecord::Schema.define(version: 3) do
2
+ create_table :users do |t|
3
+ t.string :name
4
+ t.string :username
5
+ t.string :password_digest
6
+ end
7
+
8
+ create_table :applications do |t|
9
+ t.string :name
10
+ t.string :key
11
+ t.string :secret
12
+ t.string :redirect_uri
13
+
14
+ t.timestamps null: false
15
+ end
16
+
17
+ add_index :applications, :key, unique: true
18
+
19
+ create_table :access_tokens do |t|
20
+ t.integer :resource_owner_id
21
+ t.integer :client_id
22
+
23
+ t.string :token, null: false
24
+ t.string :refresh_token
25
+ t.string :scopes
26
+
27
+ t.datetime :expires_at
28
+ t.datetime :revoked_at
29
+ t.datetime :created_at, null: false
30
+ end
31
+
32
+ create_table :access_codes do |t|
33
+ t.integer :resource_owner_id
34
+ t.integer :client_id
35
+
36
+ t.string :token, null: false
37
+ t.string :redirect_uri
38
+ t.string :scopes
39
+
40
+ t.datetime :expires_at
41
+ t.datetime :revoked_at
42
+ t.datetime :created_at, null: false
43
+ end
44
+
45
+ add_index :access_tokens, :token, unique: true
46
+ add_index :access_tokens, :resource_owner_id
47
+ add_index :access_tokens, :client_id
48
+ add_index :access_tokens, :refresh_token, unique: true
49
+
50
+ add_index :access_codes, :token, unique: true
51
+ add_index :access_codes, :resource_owner_id
52
+ add_index :access_codes, :client_id
53
+ end
@@ -0,0 +1,6 @@
1
+ Mongoid.load!(File.expand_path('../mongoid.yml', __FILE__), :test)
2
+
3
+ Mongoid.raise_not_found_error = false
4
+
5
+ Mongoid.logger.level = Logger::ERROR
6
+ Mongo::Logger.logger.level = Logger::ERROR
@@ -0,0 +1,21 @@
1
+ development:
2
+ clients:
3
+ default:
4
+ database: mongoid-dev
5
+ hosts:
6
+ - localhost:27017
7
+ options:
8
+ raise_not_found_error: false
9
+ write:
10
+ w: 1
11
+
12
+ test:
13
+ clients:
14
+ default:
15
+ database: mongoid-test
16
+ hosts:
17
+ - localhost:27017
18
+ options:
19
+ raise_not_found_error: false
20
+ write:
21
+ w: 1
@@ -0,0 +1,3 @@
1
+ class AccessCode
2
+ include Grape::OAuth2::Mongoid::AccessGrant
3
+ end
@@ -0,0 +1,3 @@
1
+ class AccessToken
2
+ include Grape::OAuth2::Mongoid::AccessToken
3
+ end
@@ -0,0 +1,3 @@
1
+ class Application
2
+ include Grape::OAuth2::Mongoid::Client
3
+ end
@@ -0,0 +1,11 @@
1
+ class User
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+
5
+ field :username, type: String
6
+ field :password, type: String
7
+
8
+ def self.oauth_authenticate(_client, username, password)
9
+ find_by(username: username, password: password)
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ require 'grape'
2
+
3
+ require File.expand_path('../../../../../../lib/grape_oauth2', __FILE__)
4
+
5
+ # Database
6
+ load File.expand_path('../config/db.rb', __FILE__)
7
+
8
+ # Grape::OAuth2 config
9
+ load File.expand_path('../../../../grape_oauth2_config.rb', __FILE__)
10
+
11
+ # Models
12
+ require_relative 'models/access_token'
13
+ require_relative 'models/access_code'
14
+ require_relative 'models/application'
15
+ require_relative 'models/user'
16
+
17
+ # Twitter Endpoints
18
+ require_relative '../../../endpoints/custom_token'
19
+ require_relative '../../../endpoints/custom_authorization'
20
+ require_relative '../../../endpoints/status'
21
+
22
+ module Twitter
23
+ class API < Grape::API
24
+ version 'v1', using: :path
25
+ format :json
26
+ prefix :api
27
+
28
+ include Grape::OAuth2.api
29
+
30
+ mount Twitter::Endpoints::Status
31
+ mount Twitter::Endpoints::CustomToken
32
+ mount Twitter::Endpoints::CustomAuthorization
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'app/twitter'
4
+
5
+ run Twitter::API
@@ -0,0 +1 @@
1
+ load File.expand_path('../../../db/schema.rb', __FILE__)
@@ -0,0 +1,4 @@
1
+ class AccessCode < ApplicationRecord
2
+ set_dataset :access_codes
3
+ include Grape::OAuth2::Sequel::AccessGrant
4
+ end
@@ -0,0 +1,4 @@
1
+ class AccessToken < ApplicationRecord
2
+ set_dataset :access_tokens
3
+ include Grape::OAuth2::Sequel::AccessToken
4
+ end
@@ -0,0 +1,4 @@
1
+ class Application < ApplicationRecord
2
+ set_dataset :applications
3
+ include Grape::OAuth2::Sequel::Client
4
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationRecord < ::Sequel::Model
2
+ end
@@ -0,0 +1,11 @@
1
+ class User < ApplicationRecord
2
+ set_dataset :users
3
+ plugin :secure_password, include_validations: false
4
+
5
+ def self.oauth_authenticate(_client, username, password)
6
+ user = find(username: username)
7
+ return if user.nil?
8
+
9
+ user.authenticate(password)
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ require 'grape'
2
+
3
+ require File.expand_path('../../../../../../lib/grape_oauth2', __FILE__)
4
+
5
+ # SQLite memory database
6
+ DB = if defined?(JRUBY_VERSION)
7
+ Sequel.connect('jdbc:sqlite::memory:')
8
+ else
9
+ Sequel.sqlite
10
+ end
11
+
12
+ # Database
13
+ load File.expand_path('../config/db.rb', __FILE__)
14
+
15
+ # Grape::OAuth2 config
16
+ load File.expand_path('../../../../grape_oauth2_config.rb', __FILE__)
17
+
18
+ # Models
19
+ require_relative 'models/application_record'
20
+ require_relative 'models/access_token'
21
+ require_relative 'models/access_code'
22
+ require_relative 'models/application'
23
+ require_relative 'models/user'
24
+
25
+ # Twitter Endpoints
26
+ require_relative '../../../endpoints/custom_token'
27
+ require_relative '../../../endpoints/custom_authorization'
28
+ require_relative '../../../endpoints/status'
29
+
30
+ module Twitter
31
+ class API < Grape::API
32
+ version 'v1', using: :path
33
+ format :json
34
+ prefix :api
35
+
36
+ use *Grape::OAuth2.middleware
37
+
38
+ helpers Grape::OAuth2::Helpers::AccessTokenHelpers
39
+
40
+ mount Grape::OAuth2::Endpoints::Token
41
+ mount Grape::OAuth2::Endpoints::Authorize
42
+
43
+ mount Twitter::Endpoints::Status
44
+ mount Twitter::Endpoints::CustomToken
45
+ mount Twitter::Endpoints::CustomAuthorization
46
+ end
47
+ end