simple_oauth2 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +25 -0
  3. data/.coveralls.yml +1 -0
  4. data/.gitignore +26 -0
  5. data/.hound.yml +4 -0
  6. data/.rubocop.yml +5 -0
  7. data/.rubocop_todo.yml +12 -0
  8. data/.travis.yml +31 -0
  9. data/Gemfile +18 -0
  10. data/LICENSE +21 -0
  11. data/README.md +11 -0
  12. data/Rakefile +11 -0
  13. data/gemfiles/nobrainer.rb +15 -0
  14. data/lib/simple_oauth2/configuration/class_accessors.rb +36 -0
  15. data/lib/simple_oauth2/configuration/constants.rb +36 -0
  16. data/lib/simple_oauth2/configuration.rb +169 -0
  17. data/lib/simple_oauth2/generators/authorization.rb +64 -0
  18. data/lib/simple_oauth2/generators/base.rb +31 -0
  19. data/lib/simple_oauth2/generators/token.rb +71 -0
  20. data/lib/simple_oauth2/helpers.rb +40 -0
  21. data/lib/simple_oauth2/mixins/nobrainer/access_grant.rb +62 -0
  22. data/lib/simple_oauth2/mixins/nobrainer/access_token.rb +98 -0
  23. data/lib/simple_oauth2/mixins/nobrainer/client.rb +43 -0
  24. data/lib/simple_oauth2/resource/bearer.rb +20 -0
  25. data/lib/simple_oauth2/responses.rb +62 -0
  26. data/lib/simple_oauth2/scopes.rb +59 -0
  27. data/lib/simple_oauth2/strategies/authorization_code.rb +22 -0
  28. data/lib/simple_oauth2/strategies/base.rb +61 -0
  29. data/lib/simple_oauth2/strategies/client_credentials.rb +21 -0
  30. data/lib/simple_oauth2/strategies/code.rb +25 -0
  31. data/lib/simple_oauth2/strategies/password.rb +21 -0
  32. data/lib/simple_oauth2/strategies/refresh_token.rb +53 -0
  33. data/lib/simple_oauth2/strategies/token.rb +24 -0
  34. data/lib/simple_oauth2/uniq_token.rb +20 -0
  35. data/lib/simple_oauth2/version.rb +26 -0
  36. data/lib/simple_oauth2.rb +62 -0
  37. data/logo.png +0 -0
  38. data/simple_oauth2.gemspec +22 -0
  39. data/spec/configuration/config_spec.rb +181 -0
  40. data/spec/configuration/version_spec.rb +11 -0
  41. data/spec/dummy/endpoints/authorization.rb +15 -0
  42. data/spec/dummy/endpoints/custom_authorization.rb +21 -0
  43. data/spec/dummy/endpoints/custom_token.rb +21 -0
  44. data/spec/dummy/endpoints/status.rb +51 -0
  45. data/spec/dummy/endpoints/token.rb +22 -0
  46. data/spec/dummy/orm/nobrainer/app/config/db.rb +8 -0
  47. data/spec/dummy/orm/nobrainer/app/models/access_grant.rb +3 -0
  48. data/spec/dummy/orm/nobrainer/app/models/access_token.rb +3 -0
  49. data/spec/dummy/orm/nobrainer/app/models/client.rb +3 -0
  50. data/spec/dummy/orm/nobrainer/app/models/user.rb +11 -0
  51. data/spec/dummy/orm/nobrainer/app/twitter.rb +51 -0
  52. data/spec/dummy/orm/nobrainer/config.ru +37 -0
  53. data/spec/dummy/simple_oauth2_config.rb +7 -0
  54. data/spec/requests/flows/authorization_code_spec.rb +177 -0
  55. data/spec/requests/flows/client_credentials_spec.rb +163 -0
  56. data/spec/requests/flows/code_spec.rb +98 -0
  57. data/spec/requests/flows/password_spec.rb +183 -0
  58. data/spec/requests/flows/refresh_token_spec.rb +282 -0
  59. data/spec/requests/flows/token_spec.rb +113 -0
  60. data/spec/requests/protected_resources_spec.rb +65 -0
  61. data/spec/requests/revoke_token_spec.rb +90 -0
  62. data/spec/spec_helper.rb +51 -0
  63. data/spec/support/helper.rb +11 -0
  64. metadata +125 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7457463729d7d0b17d67f13e8f0865f8340d8e59
4
+ data.tar.gz: 85c2c6a42f9085f0636c4fca5e72339b542c7a48
5
+ SHA512:
6
+ metadata.gz: 5e0ff90478bd45cd417ef769086b492252375fcefdea551d7f853df51096c3513be1b399322f70ade0392a7a3c9cd9acc3ff05a969b9fc647acc15d859a47b0c
7
+ data.tar.gz: 4575200800986eac07b0bae126b44a144cbd5ebc5ff7a2cecec0da2eedba32b055e1f62445c90b3b79bd7fe16c76ad24df83190924ef9a04b86587ef45c09b14
data/.codeclimate.yml ADDED
@@ -0,0 +1,25 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ - javascript
9
+ - python
10
+ - php
11
+ fixme:
12
+ enabled: true
13
+ rubocop:
14
+ enabled: true
15
+ ratings:
16
+ paths:
17
+ - "**.inc"
18
+ - "**.js"
19
+ - "**.jsx"
20
+ - "**.module"
21
+ - "**.php"
22
+ - "**.py"
23
+ - "**.rb"
24
+ exclude_paths:
25
+ - spec/
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,26 @@
1
+ *.gem
2
+ *.rbc
3
+ .rbx
4
+ /coverage/
5
+ Gemfile.lock
6
+ gemfiles/*.lock
7
+
8
+ ## Documentation cache and generated files:
9
+ /.yardoc/
10
+ /_yardoc/
11
+ /doc/
12
+ /rdoc/
13
+
14
+ ## Environment normalization:
15
+ .bundle/
16
+
17
+ rethinkdb_data
18
+
19
+ # for a library or gem, you might want to ignore these files since the code is
20
+ # intended to run in multiple environments; otherwise, check them in:
21
+ # Gemfile.lock
22
+ # .ruby-version
23
+ # .ruby-gemset
24
+
25
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
26
+ .rvmrc
data/.hound.yml ADDED
@@ -0,0 +1,4 @@
1
+ ruby:
2
+ config_file: .rubocop_todo.yml
3
+
4
+ fail_on_violations: true
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ AllCops:
2
+ Exclude:
3
+ - rethinkdb_data
4
+
5
+ inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,12 @@
1
+ Style/FrozenStringLiteralComment:
2
+ Enabled: false
3
+ Style/StringLiterals:
4
+ EnforcedStyle: single_quotes
5
+ Metrics/MethodLength:
6
+ Max: 15
7
+ Metrics/LineLength:
8
+ Max: 120
9
+ Style/Lambda:
10
+ Enabled: false
11
+ Style/DotPosition:
12
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,31 @@
1
+ language: ruby
2
+ cache: bundler
3
+ bundler_args: --without yard guard benchmarks
4
+ notifications:
5
+ email: false
6
+ addons:
7
+ code_climate:
8
+ repo_token: b06efdea32dd6768ddb83b21e07f85d439a6c725eaa97c8981324a14cbcbee17
9
+
10
+ before_install:
11
+ - source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list
12
+ - wget -qO- http://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add -
13
+ - sudo apt-get update -q
14
+ - sudo apt-get install rethinkdb
15
+ - sudo cp /etc/rethinkdb/default.conf.sample /etc/rethinkdb/instances.d/instance1.conf
16
+ - sudo service rethinkdb restart
17
+ - gem install bundler -v '~> 1.10'
18
+
19
+ matrix:
20
+ allow_failures:
21
+ - rvm: ruby-head
22
+ include:
23
+ - rvm: 2.2.6
24
+ gemfile: gemfiles/nobrainer.rb
25
+ env: ORM=nobrainer
26
+ - rvm: 2.3.3
27
+ gemfile: gemfiles/nobrainer.rb
28
+ env: ORM=nobrainer
29
+ - rvm: ruby-head
30
+ gemfile: gemfiles/nobrainer.rb
31
+ env: ORM=nobrainer
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rack-oauth2'
6
+
7
+ group :test do
8
+ gem 'nobrainer'
9
+
10
+ gem 'coveralls', require: false
11
+ gem 'ffaker'
12
+ gem 'rack-test', require: 'rack/test'
13
+ gem 'rspec-rails', '~> 3.4'
14
+ gem 'rubocop', '~> 0.46.0', require: false
15
+ gem 'simplecov', require: false
16
+ end
17
+
18
+ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Volodimir Partytskyi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ ![Simple OAuth2 Logo](https://raw.github.com/simple-oauth2/simple_oauth2/master/logo.png)
2
+
3
+ [![Build Status](https://travis-ci.org/simple-oauth2/simple_oauth2.svg?branch=master)](https://travis-ci.org/simple-oauth2/simple_oauth2)
4
+ [![Dependency Status](https://gemnasium.com/badges/github.com/simple-oauth2/simple_oauth2.svg)](https://gemnasium.com/github.com/simple-oauth2/simple_oauth2)
5
+ [![Coverage Status](https://coveralls.io/repos/github/simple-oauth2/simple_oauth2/badge.svg?branch=master)](https://coveralls.io/github/simple-oauth2/simple_oauth2?branch=master)
6
+ [![Code Climate](https://codeclimate.com/github/simple-oauth2/simple_oauth2/badges/gpa.svg)](https://codeclimate.com/github/simple-oauth2/simple_oauth2)
7
+ [![Inline docs](http://inch-ci.org/github/simple-oauth2/simple_oauth2.svg?branch=master)](http://inch-ci.org/github/simple-oauth2/simple_oauth2)
8
+ [![security](https://hakiri.io/github/simple-oauth2/simple_oauth2/master.svg)](https://hakiri.io/github/simple-oauth2/simple_oauth2/master)
9
+ [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/simple-oauth2/simple_oauth2/blob/master/LICENSE)
10
+
11
+ A flexible OAuth2 server authorization and endpoints protection to your API
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc 'Default: run specs.'
5
+ task default: :spec
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |config|
8
+ config.verbose = false
9
+ end
10
+
11
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'nobrainer'
6
+
7
+ group :test do
8
+ gem 'coveralls', require: false
9
+ gem 'factory_girl', '~> 4.0'
10
+ gem 'ffaker'
11
+ gem 'rack-test', require: 'rack/test'
12
+ gem 'rspec-rails', '~> 3.4'
13
+ end
14
+
15
+ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
@@ -0,0 +1,36 @@
1
+ module Simple
2
+ module OAuth2
3
+ # Simple::OAuth2 accessors for configured classes.
4
+ module ClassAccessors
5
+ # Returns Access Token class by configured name
6
+ def access_token_class
7
+ @access_token_class ||= access_token_class_name.constantize
8
+ end
9
+
10
+ # Returns Resource Owner class by configured name
11
+ def resource_owner_class
12
+ @resource_owner_class ||= resource_owner_class_name.constantize
13
+ end
14
+
15
+ # Returns Client class by configured name
16
+ def client_class
17
+ @client_class ||= client_class_name.constantize
18
+ end
19
+
20
+ # Returns Access Grant class by configured name
21
+ def access_grant_class
22
+ @access_grant_class ||= access_grant_class_name.constantize
23
+ end
24
+
25
+ # Returns Token Generator class by configured name
26
+ def token_generator
27
+ token_generator_class_name.constantize
28
+ end
29
+
30
+ # Returns Scopes Validator class by configured name
31
+ def scopes_validator
32
+ scopes_validator_class_name.constantize
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ module Simple
2
+ module OAuth2
3
+ # Simple::OAuth2 default constants
4
+ module Constants
5
+ # Currently supported (by the gem) OAuth2 grant types
6
+ SUPPORTED_GRANT_TYPES = %w(password authorization_code refresh_token client_credentials).freeze
7
+
8
+ # Default OAuth2 response types
9
+ SUPPORTED_RESPONSE_TYPES = %w(code token).freeze
10
+
11
+ # Default Access Token TTL (in seconds)
12
+ DEFAULT_TOKEN_LIFETIME = 7200
13
+
14
+ # Default Authorization Code TTL (in seconds)
15
+ DEFAULT_CODE_LIFETIME = 1800
16
+
17
+ # Default realm value
18
+ DEFAULT_REALM = 'OAuth 2.0'.freeze
19
+
20
+ # Default Client class value
21
+ DEFAULT_CLIENT_CLASS = 'Client'.freeze
22
+
23
+ # Default Access Token class value
24
+ DEFAULT_ACCESS_TOKEN_CLASS = 'AccessToken'.freeze
25
+
26
+ # Default Resource Owner class value
27
+ DEFAULT_RESOURCE_OWNER_CLASS = 'User'.freeze
28
+
29
+ # Default Access Grant class value
30
+ DEFAULT_ACCESS_GRANT_CLASS = 'AccessGrant'.freeze
31
+
32
+ # Default option for generate refresh token
33
+ DEFAULT_ISSUE_REFRESH_TOKEN = false
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,169 @@
1
+ module Simple
2
+ module OAuth2
3
+ # Simple::OAuth2 configuration class.
4
+ # Contains default or customized options that would be used in OAuth2 endpoints and helpers
5
+ class Configuration
6
+ include ClassAccessors
7
+ include Constants
8
+
9
+ # The names of the classes that represents OAuth2 roles
10
+ #
11
+ # @return [String] class name
12
+ #
13
+ attr_accessor :access_token_class_name, :access_grant_class_name,
14
+ :client_class_name, :resource_owner_class_name
15
+
16
+ # Class name for the OAuth2 helper class that generates unique token values
17
+ #
18
+ # @return [String] token generator class name
19
+ #
20
+ attr_accessor :token_generator_class_name
21
+
22
+ # Class name for the OAuth2 helper class that validates requested scopes against Access Token scopes
23
+ #
24
+ # @return [String] scope validator class name
25
+ #
26
+ attr_accessor :scopes_validator_class_name
27
+
28
+ # Access Token and Authorization Code lifetime in seconds
29
+ #
30
+ # @return [Integer] lifetime in seconds
31
+ #
32
+ attr_accessor :authorization_code_lifetime, :access_token_lifetime
33
+
34
+ # OAuth2 grant types (flows) allowed to be processed
35
+ #
36
+ # @return [Array<String>] grant types
37
+ #
38
+ attr_accessor :allowed_grant_types
39
+
40
+ # OAuth2 response types (flows) allowed to be processed
41
+ #
42
+ # @return [Array<String>] response types
43
+ #
44
+ attr_accessor :allowed_response_types
45
+
46
+ # Realm value
47
+ #
48
+ # @return [String] realm
49
+ #
50
+ attr_accessor :realm
51
+
52
+ # Access Token authenticator block option for customization
53
+ attr_accessor :token_authenticator
54
+
55
+ # Resource Owner authenticator block option for customization
56
+ attr_accessor :resource_owner_authenticator
57
+
58
+ # Specifies whether to generate a Refresh Token when creating an Access Token
59
+ #
60
+ # @return [Boolean] true if need to generate refresh token
61
+ #
62
+ attr_accessor :issue_refresh_token
63
+
64
+ # Callback that would be invoked during processing of Refresh Token request for
65
+ # the original Access Token found by token value
66
+ attr_accessor :on_refresh
67
+
68
+ # Return a new instance of Configuration with default options
69
+ def initialize
70
+ setup!
71
+ end
72
+
73
+ # Accessor for Access Token authenticator block. Set it to proc
74
+ # if called with block or returns current value of the accessor.
75
+ def token_authenticator(&block)
76
+ if block_given?
77
+ instance_variable_set(:'@token_authenticator', block)
78
+ else
79
+ instance_variable_get(:'@token_authenticator')
80
+ end
81
+ end
82
+
83
+ # Accessor for Resource Owner authenticator block. Set it to proc
84
+ # if called with block or returns current value of the accessor.
85
+ def resource_owner_authenticator(&block)
86
+ if block_given?
87
+ instance_variable_set(:'@resource_owner_authenticator', block)
88
+ else
89
+ instance_variable_get(:'@resource_owner_authenticator')
90
+ end
91
+ end
92
+
93
+ # Indicates if on_refresh callback can be invoked.
94
+ #
95
+ # @return [Boolean]
96
+ # true if callback can be invoked and false in other cases
97
+ #
98
+ def on_refresh_runnable?
99
+ !on_refresh.nil? && on_refresh != :nothing
100
+ end
101
+
102
+ # Accessor for on_refresh callback. Set callback proc
103
+ # if called with block or returns current value of the accessor.
104
+ def on_refresh(&block)
105
+ if block_given?
106
+ instance_variable_set(:'@on_refresh', block)
107
+ else
108
+ instance_variable_get(:'@on_refresh')
109
+ end
110
+ end
111
+
112
+ # Default Access Token authenticator block.
113
+ # Validates token value passed with the request params
114
+ def default_token_authenticator
115
+ lambda do |request|
116
+ access_token_class.authenticate(request.access_token) || request.invalid_token!
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ # Setup configuration to default options values
123
+ def setup!
124
+ init_classes
125
+ init_authenticators
126
+ init_represents_roles
127
+
128
+ self.access_token_lifetime = DEFAULT_TOKEN_LIFETIME
129
+ self.authorization_code_lifetime = DEFAULT_CODE_LIFETIME
130
+ self.allowed_grant_types = SUPPORTED_GRANT_TYPES
131
+ self.allowed_response_types = SUPPORTED_RESPONSE_TYPES
132
+ self.issue_refresh_token = DEFAULT_ISSUE_REFRESH_TOKEN
133
+ self.on_refresh = :nothing
134
+
135
+ self.realm = DEFAULT_REALM
136
+ end
137
+
138
+ # Default Resource Owner authenticator block
139
+ def default_resource_owner_authenticator
140
+ lambda do |_request|
141
+ raise(
142
+ 'Resource Owner find failed due to '\
143
+ 'Simple::OAuth2.configure.resource_owner_authenticator being unconfigured.'
144
+ )
145
+ end
146
+ end
147
+
148
+ # Sets OAuth2 helpers classes to gem defaults
149
+ def init_classes
150
+ self.token_generator_class_name = Simple::OAuth2::UniqToken.name
151
+ self.scopes_validator_class_name = Simple::OAuth2::Scopes.name
152
+ end
153
+
154
+ # Sets authenticators to gem defaults
155
+ def init_authenticators
156
+ self.token_authenticator = default_token_authenticator
157
+ self.resource_owner_authenticator = default_resource_owner_authenticator
158
+ end
159
+
160
+ # Sets OAuth2 represents roles
161
+ def init_represents_roles
162
+ self.access_token_class_name = DEFAULT_ACCESS_TOKEN_CLASS
163
+ self.resource_owner_class_name = DEFAULT_RESOURCE_OWNER_CLASS
164
+ self.client_class_name = DEFAULT_CLIENT_CLASS
165
+ self.access_grant_class_name = DEFAULT_ACCESS_GRANT_CLASS
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,64 @@
1
+ module Simple
2
+ module OAuth2
3
+ module Generators
4
+ # Authorization generator class
5
+ # Processes the request by required Response Type and builds the response
6
+ class Authorization < Base
7
+ class << self
8
+ # Generates Authorization Response based on the request
9
+ #
10
+ # @return [Simple::OAuth2::Responses] response
11
+ #
12
+ def generate_for(env, &_block)
13
+ authorization = Rack::OAuth2::Server::Authorize.new do |request, response|
14
+ request.unsupported_response_type! unless allowed_types.include?(request.response_type.to_s)
15
+
16
+ if block_given?
17
+ yield request, response
18
+ else
19
+ execute_default(request, response)
20
+ end
21
+ end
22
+
23
+ Simple::OAuth2::Responses.new(authorization.call(env))
24
+ rescue Rack::OAuth2::Server::Authorize::BadRequest => error
25
+ error_response(error)
26
+ end
27
+
28
+ private
29
+
30
+ # Returns error Rack::Response
31
+ def error_response(error)
32
+ response = Rack::Response.new
33
+ response.status = error.status
34
+ response.header['Content-Type'] = 'application/json'
35
+ response.write(JSON.dump(Rack::OAuth2::Util.compact_hash(error.protocol_params)))
36
+
37
+ Simple::OAuth2::Responses.new(response.finish)
38
+ end
39
+
40
+ # Runs default Simple::OAuth2 functionality for Authorization endpoint
41
+ #
42
+ # @param request [Rack::Request] request object
43
+ # @param response [Rack::Response] response object
44
+ #
45
+ def execute_default(request, response)
46
+ find_strategy(request.response_type).process(request, response)
47
+ response.approve!
48
+ response
49
+ end
50
+
51
+ # Returns Simple::OAuth2 strategy class by Response Type
52
+ #
53
+ # @param response_type [Symbol] response type value
54
+ #
55
+ # @return [Code, Token] strategy class
56
+ #
57
+ def find_strategy(response_type)
58
+ "Simple::OAuth2::Strategies::#{response_type.to_s.classify}".constantize
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,31 @@
1
+ module Simple
2
+ module OAuth2
3
+ module Generators
4
+ # Base class for Simple::OAuth2 generators
5
+ class Base
6
+ class << self
7
+ # Allowed grant types from the Simple::OAuth2 configuration
8
+ #
9
+ # @return [Array] allowed grant types
10
+ #
11
+ def allowed_grants
12
+ config.allowed_grant_types
13
+ end
14
+
15
+ # Allowed response types from the Simple::OAuth2 configuration
16
+ #
17
+ # @return [Array] allowed response types
18
+ #
19
+ def allowed_types
20
+ config.allowed_response_types
21
+ end
22
+
23
+ # Short getter for Simple::OAuth2 configuration.
24
+ def config
25
+ Simple::OAuth2.config
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,71 @@
1
+ module Simple
2
+ module OAuth2
3
+ module Generators
4
+ # Token generator class.
5
+ # Processes the request by required Grant Type and builds the response
6
+ class Token < Base
7
+ class << self
8
+ # Generates Token Response based on the request
9
+ #
10
+ # @return [Simple::OAuth2::Responses] response
11
+ #
12
+ def generate_for(env, &_block)
13
+ token = Rack::OAuth2::Server::Token.new do |request, response|
14
+ request.unsupported_grant_type! unless allowed_grants.include?(request.grant_type.to_s)
15
+
16
+ if block_given?
17
+ yield(request, response)
18
+ else
19
+ execute_default(request, response)
20
+ end
21
+ end
22
+
23
+ Simple::OAuth2::Responses.new(token.call(env))
24
+ end
25
+
26
+ # OAuth 2.0 Token Revocation - http://tools.ietf.org/html/rfc7009
27
+ #
28
+ # @return [Response] with HTTP status code 200
29
+ #
30
+ def revoke(token, env)
31
+ access_token = config.access_token_class.authenticate(token, 'refresh_token')
32
+
33
+ if access_token
34
+ request = Rack::OAuth2::Server::Token::Request.new(env)
35
+
36
+ # The authorization server, if applicable, first authenticates the client
37
+ # and checks its ownership of the provided token.
38
+ client = Simple::OAuth2::Strategies::Base.authenticate_client(request) || request.invalid_client!
39
+ client.id == access_token.client.id && access_token.revoke!
40
+ end
41
+ # The authorization server responds with HTTP status code 200 if the token
42
+ # has been revoked successfully or if the client submitted an invalid token
43
+ [200, {}, []]
44
+ end
45
+
46
+ private
47
+
48
+ # Runs default Simple::OAuth2 functionality for Token endpoint.
49
+ #
50
+ # @param request [Rack::Request] request object
51
+ # @param response [Rack::Response] response object
52
+ #
53
+ def execute_default(request, response)
54
+ strategy = find_strategy(request.grant_type) || request.invalid_grant!
55
+ response.access_token = strategy.process(request)
56
+ end
57
+
58
+ # Returns Simple::OAuth2 strategy class by Grant Type
59
+ #
60
+ # @param grant_type [Symbol] grant type value
61
+ #
62
+ # @return [Password, RefreshToken, AuthorizationCode] strategy class
63
+ #
64
+ def find_strategy(grant_type)
65
+ "Simple::OAuth2::Strategies::#{grant_type.to_s.camelize}".constantize
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,40 @@
1
+ module Simple
2
+ module OAuth2
3
+ # Set of Simple::OAuth2 helpers
4
+ module Helpers
5
+ # Adds OAuth2 AccessToken protection for routes
6
+ #
7
+ # @param scopes [Array<String, Symbol>] set of scopes required to access the endpoint
8
+ #
9
+ # @raise [Rack::OAuth2::Server::Resource::Bearer::Unauthorized] invalid AccessToken value
10
+ # @raise [Rack::OAuth2::Server::Resource::Bearer::Forbidden]
11
+ # AccessToken expired, revoked or does't have required scopes
12
+ #
13
+ def access_token_required!(*scopes)
14
+ raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized if current_access_token.nil?
15
+ raise Rack::OAuth2::Server::Resource::Bearer::Forbidden unless valid_access_token?(scopes)
16
+ end
17
+
18
+ # Returns ResourceOwner from the AccessToken found by access_token value passed with the request
19
+ def current_resource_owner
20
+ @current_resource_owner ||= instance_eval(&Simple::OAuth2.config.resource_owner_authenticator)
21
+ end
22
+
23
+ # Returns AccessToken instance found by access_token value passed with the request
24
+ def current_access_token
25
+ @current_access_token ||= request.env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
26
+ end
27
+
28
+ private
29
+
30
+ # Validate current access token not to be expired or revoked and has all the requested scopes
31
+ #
32
+ # @return [Boolean] true if current_access_token not expired, not revoked and scopes match
33
+ #
34
+ def valid_access_token?(scopes)
35
+ !current_access_token.revoked? && !current_access_token.expired? &&
36
+ Simple::OAuth2.config.scopes_validator.valid?(current_access_token.scopes, scopes)
37
+ end
38
+ end
39
+ end
40
+ end