haveapi 0.17.0 → 0.18.1
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.
- checksums.yaml +4 -4
- data/haveapi.gemspec +2 -1
- data/lib/haveapi/authentication/base.rb +10 -0
- data/lib/haveapi/authentication/chain.rb +2 -0
- data/lib/haveapi/authentication/oauth2/config.rb +143 -0
- data/lib/haveapi/authentication/oauth2/provider.rb +231 -0
- data/lib/haveapi/authentication/oauth2.rb +9 -0
- data/lib/haveapi/client_examples/curl.rb +3 -0
- data/lib/haveapi/client_examples/fs_client.rb +3 -0
- data/lib/haveapi/client_examples/http.rb +19 -0
- data/lib/haveapi/client_examples/js_client.rb +3 -0
- data/lib/haveapi/client_examples/php_client.rb +3 -0
- data/lib/haveapi/client_examples/ruby_cli.rb +3 -0
- data/lib/haveapi/client_examples/ruby_client.rb +3 -0
- data/lib/haveapi/server.rb +7 -0
- data/lib/haveapi/version.rb +1 -1
- data/lib/haveapi/views/version_page/auth_body.erb +7 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a503deac250571b471c672f113a2470e24ebf575ec19b09d44d1d48c210bf50
|
4
|
+
data.tar.gz: 300d414e67b3d2083c0c6d352e1817274e7ed729d099b6f814aa5fd03bd81ce8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e7d0ecf8a43a49e8bf7dca76286f6dc43cb22c65794d080e2d74b7f5ba1e39ccb6d1d1800229f925b26df6dcbad8f8bb5eb74ac70c50741450c95a5ad9f893d
|
7
|
+
data.tar.gz: 10581d63837d9a8a2fb19625dc8b61b1217fe0c4fe55dac6376190e45e482d5786ca0b32cc7d5bcd6c100f16871a5f27c789bfcdd5ea4edc5c63cadec5ad03bb
|
data/haveapi.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_runtime_dependency 'rake'
|
24
24
|
s.add_runtime_dependency 'github-markdown'
|
25
25
|
s.add_runtime_dependency 'nesty', '~> 1.0'
|
26
|
-
s.add_runtime_dependency 'haveapi-client', '~> 0.
|
26
|
+
s.add_runtime_dependency 'haveapi-client', '~> 0.18.1'
|
27
27
|
s.add_runtime_dependency 'mail'
|
28
|
+
s.add_runtime_dependency 'rack-oauth2', '~> 2.2.0'
|
28
29
|
end
|
@@ -13,6 +13,10 @@ module HaveAPI
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.inherited(subclass)
|
17
|
+
subclass.send(:instance_variable_set, '@auth_method', @auth_method)
|
18
|
+
end
|
19
|
+
|
16
20
|
# @return [Symbol]
|
17
21
|
attr_reader :name
|
18
22
|
|
@@ -23,6 +27,12 @@ module HaveAPI
|
|
23
27
|
setup
|
24
28
|
end
|
25
29
|
|
30
|
+
# Register custom path handlers in sinatra
|
31
|
+
# @param sinatra [Sinatra::Base]
|
32
|
+
# @param prefix [String]
|
33
|
+
def register_routes(sinatra, prefix)
|
34
|
+
end
|
35
|
+
|
26
36
|
# @return [Module, nil]
|
27
37
|
def resource_module
|
28
38
|
nil
|
@@ -99,6 +99,8 @@ module HaveAPI::Authentication
|
|
99
99
|
instance = p.new(@server, v)
|
100
100
|
@instances[v] << instance
|
101
101
|
|
102
|
+
@server.add_auth_routes(v, instance, prefix: instance.name.to_s)
|
103
|
+
|
102
104
|
if resource_module = instance.resource_module
|
103
105
|
@server.add_auth_module(
|
104
106
|
v,
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module HaveAPI::Authentication
|
2
|
+
module OAuth2
|
3
|
+
# Config passed to the OAuth2 provider
|
4
|
+
#
|
5
|
+
# Create your own subclass and pass it to {HaveAPI::Authentication::OAuth2.with_config}.
|
6
|
+
# The created provider can then be added to authentication chain.
|
7
|
+
#
|
8
|
+
# In general, it is up to the implementation to provide the authentication flow
|
9
|
+
# -- render HTML page in {#render_authorize_page} and then process it in
|
10
|
+
# {#handle_post_authorize}. The implementation must also handle generation
|
11
|
+
# of all needed tokens, their persistence and validity checking.
|
12
|
+
class Config
|
13
|
+
def initialize(provider, server, v)
|
14
|
+
@provider = provider
|
15
|
+
@server = server
|
16
|
+
@version = v
|
17
|
+
end
|
18
|
+
|
19
|
+
# Render authorization page
|
20
|
+
#
|
21
|
+
# This method can be called on both GET and POST requests, e.g. if the user
|
22
|
+
# provided incorrect credentials or if there are multiple authentication
|
23
|
+
# steps.
|
24
|
+
#
|
25
|
+
# It should return full HTML page that will be sent to the user. The page
|
26
|
+
# usually contains a login form.
|
27
|
+
#
|
28
|
+
# @param oauth2_request [Rack::OAuth2::Server::Authorize::Request]
|
29
|
+
# @param sinatra_params [Hash] request params
|
30
|
+
# @param client [Client]
|
31
|
+
# @param auth_result [AuthResult, nil]
|
32
|
+
# @return [String] HTML
|
33
|
+
def render_authorize_page(oauth2_request, sinatra_params, client, auth_result: nil)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
# Handle POST requests made from {#render_authorize_page}
|
38
|
+
#
|
39
|
+
# Process form data and return {AuthResult} or nil. When nil is returned
|
40
|
+
# the authorization process is aborted and the user is redirected back
|
41
|
+
# to the client.
|
42
|
+
#
|
43
|
+
# @param sinatra_request [Sinatra::Request]
|
44
|
+
# @param sinatra_params [Hash] request params
|
45
|
+
# @param oauth2_request [Rack::OAuth2::Server::Authorize::Request]
|
46
|
+
# @param client [Client]
|
47
|
+
# @return [AuthResult, nil]
|
48
|
+
def handle_post_authorize(sinatra_request, sinatra_params, oauth2_request, client)
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get oauth2 authorization code
|
53
|
+
#
|
54
|
+
# Called when the authentication is successful and complete. This method
|
55
|
+
# must generate and return authorization_code which is then sent to the
|
56
|
+
# client. It is up to the API implementation to persist the code.
|
57
|
+
#
|
58
|
+
# @param auth_res [AuthResult] value returned by {#handle_post_authorize}
|
59
|
+
# @return [String]
|
60
|
+
def get_authorization_code(auth_res)
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
# Get access token, its expiration date and optionally a refresh token
|
65
|
+
#
|
66
|
+
# The client has used the authorization_code returned by {#get_authorization_code}
|
67
|
+
# and now requests its access token. It is up to the implementation to create
|
68
|
+
# and persist the tokens. The authorization code should be invalidated.
|
69
|
+
#
|
70
|
+
# @param authorization [Authorization]
|
71
|
+
# @param sinatra_request [Sinatra::Request]
|
72
|
+
# @return [Array] access token, expiration date and optional refresh token
|
73
|
+
def get_tokens(authorization, sinatra_request)
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
# Refresh access token and optionally generate new refresh token
|
78
|
+
#
|
79
|
+
# The implementation should invalidate the current tokens and generate
|
80
|
+
# and persist new ones.
|
81
|
+
#
|
82
|
+
# @param authorization [Authorization]
|
83
|
+
# @param sinatra_request [Sinatra::Request]
|
84
|
+
# @return [Array] access token, expiration date and optional refresh token
|
85
|
+
def refresh_tokens(authorization, sinatra_request)
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
# Find client by ID
|
90
|
+
# @param client_id [String]
|
91
|
+
# @return [Client, nil]
|
92
|
+
def find_client_by_id(client_id)
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
# Find authorization by code
|
97
|
+
# @param client [Client]
|
98
|
+
# @param code [String]
|
99
|
+
# @return [Authorization, nil]
|
100
|
+
def find_authorization_by_code(client, code)
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# Find authorization by refresh token
|
105
|
+
# @param client [Client]
|
106
|
+
# @param refresh_token [String]
|
107
|
+
# @return [Authorization, nil]
|
108
|
+
def find_authorization_by_refresh_token(client, refresh_token)
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
# Find user by the bearer token sent in HTTP header or as a query parameter
|
113
|
+
# @param sinatra_request [Sinatra::Request]
|
114
|
+
# @param access_token [String]
|
115
|
+
# @return [Object, nil] user
|
116
|
+
def find_user_by_access_token(request, access_token)
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
# Path to the authorization endpoint on this API
|
121
|
+
# @return [String]
|
122
|
+
def authorize_path
|
123
|
+
@provider.authorize_path
|
124
|
+
end
|
125
|
+
|
126
|
+
# Parameters needed for the authorization process
|
127
|
+
#
|
128
|
+
# Use these in {#render_authorization_page}, put them e.g. in hidden form
|
129
|
+
# fields.
|
130
|
+
#
|
131
|
+
# @return [Hash<String, String>]
|
132
|
+
def oauth2_params(req)
|
133
|
+
{
|
134
|
+
client_id: req.client_id,
|
135
|
+
response_type: req.response_type,
|
136
|
+
redirect_uri: req.redirect_uri,
|
137
|
+
scope: req.scope.join(' '),
|
138
|
+
state: req.state,
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'haveapi/authentication/base'
|
2
|
+
require 'rack/oauth2'
|
3
|
+
|
4
|
+
module HaveAPI::Authentication
|
5
|
+
module OAuth2
|
6
|
+
# Abstract class describing the client and what methods it must respond to
|
7
|
+
class Client
|
8
|
+
# @return [String]
|
9
|
+
attr_reader :client_id
|
10
|
+
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :redirect_uri
|
13
|
+
|
14
|
+
# @param client_secret [String]
|
15
|
+
# @return [Boolean]
|
16
|
+
def check_secret(client_secret)
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Abstract class describing the authentication result and what methods it must respond to
|
22
|
+
class AuthResult
|
23
|
+
# True of the user was authenticated
|
24
|
+
# @return [Boolean]
|
25
|
+
attr_reader :authenticated
|
26
|
+
|
27
|
+
# True if the authentication process is complete, false if other steps are needed
|
28
|
+
# @return [Boolean]
|
29
|
+
attr_reader :complete
|
30
|
+
|
31
|
+
# True if the user asked to cancel the authorization process
|
32
|
+
# @return [Boolean]
|
33
|
+
attr_reader :cancel
|
34
|
+
end
|
35
|
+
|
36
|
+
# Abstract class describing ongoing authorization and what methods it must respond to
|
37
|
+
class Authorization
|
38
|
+
# @return [String]
|
39
|
+
attr_reader :redirect_uri
|
40
|
+
|
41
|
+
# @param redirect_uri [String]
|
42
|
+
# @return [Boolean]
|
43
|
+
def check_code_validity(redirect_uri)
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# OAuth2 authentication and authorization provider
|
49
|
+
#
|
50
|
+
# Must be configured with {Config} using {OAuth2.with_config}.
|
51
|
+
class Provider < Base
|
52
|
+
auth_method :oauth2
|
53
|
+
|
54
|
+
# Configure the OAuth2 provider
|
55
|
+
# @param cfg [Config]
|
56
|
+
def self.with_config(cfg)
|
57
|
+
Module.new do
|
58
|
+
define_singleton_method(:new) do |*args|
|
59
|
+
Provider.new(*args, cfg)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [String]
|
65
|
+
attr_reader :authorize_path
|
66
|
+
|
67
|
+
# @return [Config]
|
68
|
+
attr_reader :config
|
69
|
+
|
70
|
+
def initialize(server, v, cfg)
|
71
|
+
@config = cfg.new(self, server, v)
|
72
|
+
super(server, v)
|
73
|
+
end
|
74
|
+
|
75
|
+
def register_routes(sinatra, prefix)
|
76
|
+
@authorize_path = File.join(prefix, 'authorize')
|
77
|
+
@token_path = File.join(prefix, 'token')
|
78
|
+
that = self
|
79
|
+
|
80
|
+
sinatra.get @authorize_path do
|
81
|
+
that.authorization_endpoint(self).call(request.env)
|
82
|
+
end
|
83
|
+
|
84
|
+
sinatra.post @authorize_path do
|
85
|
+
that.authorization_endpoint(self).call(request.env)
|
86
|
+
end
|
87
|
+
|
88
|
+
sinatra.post @token_path do
|
89
|
+
that.token_endpoint(self).call(request.env)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def authenticate(request)
|
94
|
+
tokens = [
|
95
|
+
request['access_token'],
|
96
|
+
token_from_header(request)
|
97
|
+
].compact
|
98
|
+
|
99
|
+
token =
|
100
|
+
case tokens.length
|
101
|
+
when 0
|
102
|
+
nil
|
103
|
+
when 1
|
104
|
+
tokens.first
|
105
|
+
else
|
106
|
+
fail 'Too many oauth2 tokens'
|
107
|
+
end
|
108
|
+
|
109
|
+
token && config.find_user_by_access_token(request, token)
|
110
|
+
end
|
111
|
+
|
112
|
+
def token_from_header(request)
|
113
|
+
auth_header = Rack::Auth::AbstractRequest.new(request.env)
|
114
|
+
|
115
|
+
if auth_header.provided? && !auth_header.parts.first.nil? && auth_header.scheme.to_s == 'bearer'
|
116
|
+
auth_header.params
|
117
|
+
else
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def describe
|
123
|
+
desc = <<-END
|
124
|
+
OAuth2 authorization provider. While OAuth2 is not supported by HaveAPI
|
125
|
+
clients, it is possible to use your API as an authentication source.
|
126
|
+
|
127
|
+
HaveAPI partially implements RFC 6749: authorization response type "code"
|
128
|
+
and token grant types "authorization_code" and "refresh_token". Other
|
129
|
+
response and grant types are not supported at this time.
|
130
|
+
|
131
|
+
The access token can be passed as bearer token according to RFC 6750.
|
132
|
+
END
|
133
|
+
|
134
|
+
{
|
135
|
+
description: desc,
|
136
|
+
authorize_path: @authorize_path,
|
137
|
+
token_path: @token_path,
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def authorization_endpoint(handler)
|
142
|
+
Rack::OAuth2::Server::Authorize.new do |req, res|
|
143
|
+
client = config.find_client_by_id(req.client_id)
|
144
|
+
req.bad_request! if client.nil?
|
145
|
+
|
146
|
+
res.redirect_uri = req.verify_redirect_uri!(client.redirect_uri)
|
147
|
+
|
148
|
+
if req.post?
|
149
|
+
auth_res = config.handle_post_authorize(handler.request, handler.params, req, client)
|
150
|
+
|
151
|
+
if auth_res.nil?
|
152
|
+
# Authentication failed
|
153
|
+
req.access_denied!
|
154
|
+
elsif auth_res.cancel
|
155
|
+
# Cancel the process
|
156
|
+
req.access_denied!
|
157
|
+
elsif auth_res.authenticated && auth_res.complete
|
158
|
+
# Authentication was successful
|
159
|
+
case req.response_type
|
160
|
+
when :code
|
161
|
+
res.code = config.get_authorization_code(auth_res)
|
162
|
+
when :token
|
163
|
+
req.unsupported_response_type!
|
164
|
+
end
|
165
|
+
|
166
|
+
res.approve!
|
167
|
+
elsif auth_res.authenticated && !auth_res.complete
|
168
|
+
# Continue with another authentication step
|
169
|
+
res.content_type = 'text/html'
|
170
|
+
res.write(config.render_authorize_page(req, handler.params, client, auth_result: auth_res))
|
171
|
+
else
|
172
|
+
# Authentication failed, report errors and let the user retry
|
173
|
+
res.content_type = 'text/html'
|
174
|
+
res.write(config.render_authorize_page(req, handler.params, client, auth_result: auth_res))
|
175
|
+
end
|
176
|
+
else
|
177
|
+
res.content_type = 'text/html'
|
178
|
+
res.write(config.render_authorize_page(req, handler.params, client))
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def token_endpoint(handler)
|
184
|
+
Rack::OAuth2::Server::Token.new do |req, res|
|
185
|
+
client = config.find_client_by_id(req.client_id)
|
186
|
+
req.invalid_client! if client.nil? || !client.check_secret(req.client_secret)
|
187
|
+
|
188
|
+
res.access_token =
|
189
|
+
case req.grant_type
|
190
|
+
when :authorization_code
|
191
|
+
authorization = config.find_authorization_by_code(client, req.code)
|
192
|
+
|
193
|
+
if authorization.nil? || !authorization.check_code_validity(req.redirect_uri)
|
194
|
+
req.invalid_grant!
|
195
|
+
end
|
196
|
+
|
197
|
+
access_token, expires_at, refresh_token = config.get_tokens(authorization, handler.request)
|
198
|
+
|
199
|
+
bearer_token = Rack::OAuth2::AccessToken::Bearer.new(
|
200
|
+
access_token: access_token,
|
201
|
+
expires_in: expires_at - Time.now,
|
202
|
+
)
|
203
|
+
bearer_token.refresh_token = refresh_token if refresh_token
|
204
|
+
bearer_token
|
205
|
+
|
206
|
+
when :password
|
207
|
+
req.unsupported_grant_type!
|
208
|
+
|
209
|
+
when :client_credentials
|
210
|
+
req.unsupported_grant_type!
|
211
|
+
|
212
|
+
when :refresh_token
|
213
|
+
config.find_authorization_by_refresh_token(client, req.refresh_token)
|
214
|
+
|
215
|
+
access_token, expires_at, refresh_token = config.refresh_tokens(authorization, handler.request)
|
216
|
+
|
217
|
+
bearer_token = Rack::OAuth2::AccessToken::Bearer.new(
|
218
|
+
access_token: access_token,
|
219
|
+
expires_in: expires_at - Time.now,
|
220
|
+
)
|
221
|
+
bearer_token.refresh_token = refresh_token if refresh_token
|
222
|
+
bearer_token
|
223
|
+
|
224
|
+
else
|
225
|
+
req.unsupported_grant_type!
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -36,6 +36,25 @@ Host: #{host}
|
|
36
36
|
Content-Type: application/json
|
37
37
|
|
38
38
|
#{JSON.pretty_generate({token: login})}
|
39
|
+
END
|
40
|
+
|
41
|
+
when :oauth2
|
42
|
+
<<END
|
43
|
+
# 1) Request authorization code
|
44
|
+
GET #{desc[:authorize_path]}?response_type=code&client_id=$client_id&state=$state&redirect_uri=$client_redirect_uri HTTP/1.1
|
45
|
+
Host: #{host}
|
46
|
+
|
47
|
+
# 2) The user logs in using this API
|
48
|
+
|
49
|
+
# 3) The API then redirects the user back to the client application
|
50
|
+
GET $client_redirect_uri?code=$authorization_code&state=$state
|
51
|
+
Host: client-application
|
52
|
+
|
53
|
+
# 4) The client application requests access token
|
54
|
+
POST #{desc[:token_path]}
|
55
|
+
Content-Type: application/x-www-form-urlencoded
|
56
|
+
|
57
|
+
grant_type=authorization_code&code=$authorization_code&redirect_uri=$client_redirect_uri&client_id=$client_id&client_secret=$client_secret
|
39
58
|
END
|
40
59
|
end
|
41
60
|
end
|
@@ -33,6 +33,9 @@ echo "Token = ".$api->getAuthenticationProvider()->getToken();
|
|
33
33
|
// Next time, the client can authenticate using the token directly
|
34
34
|
$api->authenticate("token", ["token" => $savedToken]);
|
35
35
|
END
|
36
|
+
|
37
|
+
when :oauth2
|
38
|
+
'// OAuth2 is not supported by HaveAPI PHP client.'
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
data/lib/haveapi/server.rb
CHANGED
@@ -576,6 +576,13 @@ module HaveAPI
|
|
576
576
|
"#{@root}v#{v}/"
|
577
577
|
end
|
578
578
|
|
579
|
+
# @param v [String] API version
|
580
|
+
# @param provider [Authentication::Base]
|
581
|
+
# @param prefix [String]
|
582
|
+
def add_auth_routes(v, provider, prefix: '')
|
583
|
+
provider.register_routes(@sinatra, "#{@root}_auth/#{prefix}")
|
584
|
+
end
|
585
|
+
|
579
586
|
def add_auth_module(v, name, mod, prefix: '')
|
580
587
|
@routes[v] ||= {authentication: {name => {resources: {}}}}
|
581
588
|
|
data/lib/haveapi/version.rb
CHANGED
@@ -10,6 +10,13 @@
|
|
10
10
|
<dt>Query parameter:</dt>
|
11
11
|
<dd><%= info[:query_parameter] %></dd>
|
12
12
|
</dl>
|
13
|
+
<% elsif name == :oauth2 %>
|
14
|
+
<dl>
|
15
|
+
<dt>Authorize path:</dt>
|
16
|
+
<dd><%= info[:authorize_path] %></dd>
|
17
|
+
<dt>Token path:</dt>
|
18
|
+
<dd><%= info[:token_path] %></dd>
|
19
|
+
</dl>
|
13
20
|
<% end %>
|
14
21
|
|
15
22
|
<% if info[:resources] %>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haveapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Skokan
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.
|
145
|
+
version: 0.18.1
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.
|
152
|
+
version: 0.18.1
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: mail
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rack-oauth2
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 2.2.0
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.2.0
|
167
181
|
description: Framework for creating self-describing APIs
|
168
182
|
email: jakub.skokan@vpsfree.cz
|
169
183
|
executables: []
|
@@ -193,6 +207,9 @@ files:
|
|
193
207
|
- lib/haveapi/authentication/base.rb
|
194
208
|
- lib/haveapi/authentication/basic/provider.rb
|
195
209
|
- lib/haveapi/authentication/chain.rb
|
210
|
+
- lib/haveapi/authentication/oauth2.rb
|
211
|
+
- lib/haveapi/authentication/oauth2/config.rb
|
212
|
+
- lib/haveapi/authentication/oauth2/provider.rb
|
196
213
|
- lib/haveapi/authentication/token.rb
|
197
214
|
- lib/haveapi/authentication/token/action_config.rb
|
198
215
|
- lib/haveapi/authentication/token/action_request.rb
|