zaikio-oauth_client 0.12.1 → 0.15.1.beta1
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/README.md +35 -21
- data/Rakefile +1 -3
- data/app/controllers/zaikio/oauth_client/subscriptions_controller.rb +0 -1
- data/app/models/zaikio/access_token.rb +15 -16
- data/lib/zaikio/oauth_client.rb +10 -8
- data/lib/zaikio/oauth_client/authenticatable.rb +4 -4
- data/lib/zaikio/oauth_client/client_configuration.rb +1 -1
- data/lib/zaikio/oauth_client/test_helper.rb +1 -1
- data/lib/zaikio/oauth_client/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5695820de8df28288feb3794016c0288e2dce2d7890a8c3bd9b11685fc39c32f
|
4
|
+
data.tar.gz: 2616666c8df490d153339d6953f6066a46f00669dfd037dcc2faf62873b44e9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd7d9785f60d8c025ec461d6ab006f714f7f9abfd83ebffcfcf261c17a386903a6d9a42eb57708fd23b23662060190be1b5fd3089f03c10e0459a5106bcf4268
|
7
|
+
data.tar.gz: 1a554847284740a40cd231681572c30a0ae32c441a3da4de9feafdc36ea9057ff66ec93281be4108e4e1e7683c8f550a4bdf4b63153292f295295b29d0007a3f
|
data/README.md
CHANGED
@@ -36,32 +36,34 @@ mount Zaikio::OAuthClient::Engine => "/zaikio"
|
|
36
36
|
|
37
37
|
```rb
|
38
38
|
# config/initializers/zaikio_oauth_client.rb
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
39
|
+
Rails.application.reloader.to_prepare do
|
40
|
+
Zaikio::OAuthClient.configure do |config|
|
41
|
+
config.environment = :sandbox
|
42
|
+
|
43
|
+
config.register_client :warehouse do |warehouse|
|
44
|
+
warehouse.client_id = "52022d7a-7ba2-41ed-8890-97d88e6472f6"
|
45
|
+
warehouse.client_secret = "ShiKTnHqEf3M8nyHQPyZgbz7"
|
46
|
+
warehouse.default_scopes = %w[directory.person.r]
|
47
|
+
|
48
|
+
warehouse.register_organization_connection do |org|
|
49
|
+
org.default_scopes = %w[directory.organization.r]
|
50
|
+
end
|
49
51
|
end
|
50
|
-
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
config.register_client :warehouse_goods_call_of do |warehouse_goods_call_of|
|
54
|
+
warehouse_goods_call_of.client_id = "12345-7ba2-41ed-8890-97d88e6472f6"
|
55
|
+
warehouse_goods_call_of.client_secret = "secret"
|
56
|
+
warehouse_goods_call_of.default_scopes = %w[directory.person.r]
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
warehouse_goods_call_of.register_organization_connection do |org|
|
59
|
+
org.default_scopes = %w[directory.organization.r]
|
60
|
+
end
|
59
61
|
end
|
60
|
-
end
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
config.around_auth do |access_token, block|
|
64
|
+
Zaikio::Hub.with_token(access_token.token) do
|
65
|
+
block.call(access_token)
|
66
|
+
end
|
65
67
|
end
|
66
68
|
end
|
67
69
|
end
|
@@ -264,6 +266,18 @@ Zaikio::OAuthClient.with_auth(bearer_type: "Organization", bearer_id: "fd61f5f5-
|
|
264
266
|
end
|
265
267
|
```
|
266
268
|
|
269
|
+
If you need the token for a certain period (e.g. a long-running job which makes many
|
270
|
+
requests in sequence), you can specify the `valid_for` interval when requesting the token.
|
271
|
+
By default, it won't return an access token which was due to expire in less than 30
|
272
|
+
seconds from now. If there is an existing token, but it was due to expire before the end
|
273
|
+
of the validity period, this will go and get a fresh token anyway:
|
274
|
+
|
275
|
+
```rb
|
276
|
+
Zaikio::OAuthClient.with_auth(..., valid_for: 10.minutes) do |access_token|
|
277
|
+
# ...
|
278
|
+
end
|
279
|
+
```
|
280
|
+
|
267
281
|
## Use of dummy app
|
268
282
|
|
269
283
|
You can use the included dummy app as a showcase for the workflow and to adjust your own application. To set up the dummy application properly, go into `test/dummy` and use [puma-dev](https://github.com/puma/puma-dev) like this:
|
data/Rakefile
CHANGED
@@ -35,9 +35,7 @@ require 'rubocop/rake_task'
|
|
35
35
|
|
36
36
|
namespace :test do
|
37
37
|
desc 'Runs RuboCop on specified directories'
|
38
|
-
RuboCop::RakeTask.new(:rubocop)
|
39
|
-
task.fail_on_error = false
|
40
|
-
end
|
38
|
+
RuboCop::RakeTask.new(:rubocop)
|
41
39
|
end
|
42
40
|
|
43
41
|
Rake::Task[:test].enhance ['test:rubocop']
|
@@ -3,7 +3,6 @@ module Zaikio
|
|
3
3
|
class SubscriptionsController < ConnectionsController
|
4
4
|
def new
|
5
5
|
opts = params.permit(:client_name, :state, :plan, :organization_id)
|
6
|
-
opts[:redirect_with_error] = 1
|
7
6
|
opts[:state] ||= session[:state] = SecureRandom.urlsafe_base64(32)
|
8
7
|
|
9
8
|
plan = opts.delete(:plan)
|
@@ -5,7 +5,7 @@ module Zaikio
|
|
5
5
|
class AccessToken < ApplicationRecord
|
6
6
|
self.table_name = "zaikio_access_tokens"
|
7
7
|
|
8
|
-
def self.build_from_access_token(access_token, requested_scopes: nil)
|
8
|
+
def self.build_from_access_token(access_token, requested_scopes: nil)
|
9
9
|
payload = JWT.decode(access_token.token, nil, false).first rescue {} # rubocop:disable Style/RescueModifier
|
10
10
|
scopes = access_token.params["scope"].split(",")
|
11
11
|
new(
|
@@ -26,27 +26,28 @@ module Zaikio
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Scopes
|
29
|
-
scope :valid, lambda {
|
30
|
-
where("expires_at > :
|
29
|
+
scope :valid, lambda { |valid_until = Time.current|
|
30
|
+
where("expires_at > :valid_until", valid_until: valid_until)
|
31
31
|
.where.not(id: Zaikio::JWTAuth.revoked_token_ids)
|
32
32
|
}
|
33
33
|
scope :with_invalid_refresh_token, lambda {
|
34
34
|
where("created_at <= ?", Time.current - Zaikio::AccessToken.refresh_token_valid_for)
|
35
35
|
}
|
36
|
-
scope :valid_refresh, lambda {
|
37
|
-
where("expires_at <= :
|
38
|
-
|
39
|
-
created_at_max:
|
40
|
-
.where(
|
36
|
+
scope :valid_refresh, lambda { |valid_until = Time.current|
|
37
|
+
where("expires_at <= :valid_until AND created_at > :created_at_max",
|
38
|
+
valid_until: valid_until,
|
39
|
+
created_at_max: valid_until - refresh_token_valid_for)
|
40
|
+
.where.not(refresh_token: nil)
|
41
41
|
.where.not(id: Zaikio::JWTAuth.revoked_token_ids)
|
42
42
|
}
|
43
43
|
scope :by_bearer, lambda { |bearer_id:, requested_scopes: [], bearer_type: "Person"|
|
44
44
|
where(bearer_type: bearer_type, bearer_id: bearer_id)
|
45
45
|
.where("requested_scopes @> ARRAY[?]::varchar[]", requested_scopes)
|
46
46
|
}
|
47
|
-
scope :usable, lambda { |options|
|
48
|
-
by_bearer(**options).valid.or(
|
49
|
-
|
47
|
+
scope :usable, lambda { |valid_until: Time.current, **options|
|
48
|
+
by_bearer(**options).valid(valid_until).or(
|
49
|
+
by_bearer(**options).valid_refresh
|
50
|
+
).order(expires_at: :desc)
|
50
51
|
}
|
51
52
|
|
52
53
|
def expired?
|
@@ -72,6 +73,8 @@ module Zaikio
|
|
72
73
|
end
|
73
74
|
|
74
75
|
def refresh!
|
76
|
+
return unless refresh_token?
|
77
|
+
|
75
78
|
Zaikio::OAuthClient.with_oauth_scheme(:basic_auth) do
|
76
79
|
refreshed_token = OAuth2::AccessToken.from_hash(
|
77
80
|
Zaikio::OAuthClient.for(audience),
|
@@ -80,16 +83,12 @@ module Zaikio
|
|
80
83
|
|
81
84
|
destroy
|
82
85
|
|
83
|
-
self.class.build_from_access_token(
|
84
|
-
refreshed_token,
|
85
|
-
requested_scopes: requested_scopes
|
86
|
-
).tap(&:save!)
|
86
|
+
self.class.build_from_access_token(refreshed_token, requested_scopes: requested_scopes).tap(&:save!)
|
87
87
|
end
|
88
88
|
rescue OAuth2::Error => e
|
89
89
|
raise unless e.code == "invalid_grant"
|
90
90
|
|
91
91
|
destroy
|
92
|
-
|
93
92
|
nil
|
94
93
|
end
|
95
94
|
end
|
data/lib/zaikio/oauth_client.rb
CHANGED
@@ -49,7 +49,7 @@ module Zaikio
|
|
49
49
|
get_access_token(**options_or_access_token)
|
50
50
|
end
|
51
51
|
|
52
|
-
return unless
|
52
|
+
return unless block
|
53
53
|
|
54
54
|
if configuration.around_auth_block
|
55
55
|
configuration.around_auth_block.call(access_token, block)
|
@@ -62,14 +62,15 @@ module Zaikio
|
|
62
62
|
# * If the token has expired, it will be refreshed using the refresh_token flow
|
63
63
|
# (if this fails, we fallback to getting a new token using client_credentials)
|
64
64
|
# * If the token does not exist, we'll get a new one using the client_credentials flow
|
65
|
-
def get_access_token(bearer_id:, client_name: nil, bearer_type: "Person", scopes: nil)
|
65
|
+
def get_access_token(bearer_id:, client_name: nil, bearer_type: "Person", scopes: nil, valid_for: 30.seconds)
|
66
66
|
client_config = client_config_for(client_name || self.client_name)
|
67
67
|
scopes ||= client_config.default_scopes_for(bearer_type)
|
68
68
|
|
69
69
|
token = find_usable_access_token(client_name: client_config.client_name,
|
70
70
|
bearer_type: bearer_type,
|
71
71
|
bearer_id: bearer_id,
|
72
|
-
requested_scopes: scopes
|
72
|
+
requested_scopes: scopes,
|
73
|
+
valid_for: valid_for)
|
73
74
|
|
74
75
|
token = token.refresh! if token&.expired?
|
75
76
|
|
@@ -82,9 +83,9 @@ module Zaikio
|
|
82
83
|
|
83
84
|
# Finds the best usable access token. Note that this token may have expired and
|
84
85
|
# would require refreshing.
|
85
|
-
def find_usable_access_token(client_name:, bearer_type:, bearer_id:, requested_scopes:)
|
86
|
+
def find_usable_access_token(client_name:, bearer_type:, bearer_id:, requested_scopes:, valid_for: 30.seconds) # rubocop:disable Metrics/MethodLength
|
86
87
|
configuration.logger.debug "Try to fetch token for client_name: #{client_name}, "\
|
87
|
-
|
88
|
+
"bearer #{bearer_type}/#{bearer_id}, requested_scopes: #{requested_scopes}"
|
88
89
|
|
89
90
|
fetch_access_token = lambda {
|
90
91
|
Zaikio::AccessToken
|
@@ -92,7 +93,8 @@ module Zaikio
|
|
92
93
|
.usable(
|
93
94
|
bearer_type: bearer_type,
|
94
95
|
bearer_id: bearer_id,
|
95
|
-
requested_scopes: requested_scopes
|
96
|
+
requested_scopes: requested_scopes,
|
97
|
+
valid_until: valid_for.from_now
|
96
98
|
)
|
97
99
|
.first
|
98
100
|
}
|
@@ -117,9 +119,9 @@ module Zaikio
|
|
117
119
|
|
118
120
|
def get_plain_scopes(scopes)
|
119
121
|
regex = /^((Org|Per)\.)?(.*)$/
|
120
|
-
scopes.
|
122
|
+
scopes.filter_map do |scope|
|
121
123
|
(regex.match(scope) || [])[3]
|
122
|
-
end
|
124
|
+
end
|
123
125
|
end
|
124
126
|
|
125
127
|
private
|
@@ -4,8 +4,8 @@ module Zaikio
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
def new
|
7
|
-
opts = params.permit(:client_name, :show_signup, :force_login, :state)
|
8
|
-
opts[:
|
7
|
+
opts = params.permit(:client_name, :show_signup, :prompt, :force_login, :state, :lang)
|
8
|
+
opts[:lang] ||= I18n.locale if defined?(I18n)
|
9
9
|
client_name = opts.delete(:client_name)
|
10
10
|
opts[:state] ||= session[:state] = SecureRandom.urlsafe_base64(32)
|
11
11
|
|
@@ -16,7 +16,7 @@ module Zaikio
|
|
16
16
|
)
|
17
17
|
end
|
18
18
|
|
19
|
-
def approve
|
19
|
+
def approve # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
20
20
|
if params[:error].present?
|
21
21
|
redirect_to send(
|
22
22
|
respond_to?(:error_path_for) ? :error_path_for : :default_error_path_for,
|
@@ -81,7 +81,7 @@ module Zaikio
|
|
81
81
|
|
82
82
|
def client_config
|
83
83
|
client_config = Zaikio::OAuthClient.configuration.find!(client_name)
|
84
|
-
client_config =
|
84
|
+
client_config = client_config.org_config if use_org_config?
|
85
85
|
|
86
86
|
client_config or raise ActiveRecord::RecordNotFound
|
87
87
|
end
|
@@ -20,7 +20,7 @@ module Zaikio
|
|
20
20
|
client_secret,
|
21
21
|
authorize_url: "oauth/authorize",
|
22
22
|
token_url: "oauth/access_token",
|
23
|
-
connection_opts: { headers: {
|
23
|
+
connection_opts: { headers: { Accept: "application/json" } },
|
24
24
|
site: Zaikio::OAuthClient.configuration.host
|
25
25
|
)
|
26
26
|
|
@@ -3,7 +3,7 @@ module Zaikio
|
|
3
3
|
module TestHelper
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
class TestSessionController < ActionController::Base
|
6
|
+
class TestSessionController < ActionController::Base # rubocop:disable Rails/ApplicationController
|
7
7
|
def show
|
8
8
|
if session[params[:key]].nil?
|
9
9
|
head :no_content
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zaikio-oauth_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.1.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zaikio GmbH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -183,9 +183,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
183
|
version: '0'
|
184
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
185
|
requirements:
|
186
|
-
- - "
|
186
|
+
- - ">"
|
187
187
|
- !ruby/object:Gem::Version
|
188
|
-
version:
|
188
|
+
version: 1.3.1
|
189
189
|
requirements: []
|
190
190
|
rubygems_version: 3.2.3
|
191
191
|
signing_key:
|