zaikio-oauth_client 0.18.0 → 0.19.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f6d99b08d0e3fc512ce6a4bf8184be7c7d95144f3798062756f8f8159f86655
4
- data.tar.gz: 4ed2286c417bdac976e6ad1f26c4ec84fc8d18b52312b082fd548800edfbec9b
3
+ metadata.gz: fd5390d254c886ad8c082def82463c6653bdb91b4f08433bf138b872e9fb54ff
4
+ data.tar.gz: b9bca34becf29861bd4e5f57d88492a9dfb7aecb8ad6ed2306c2007ee75740e5
5
5
  SHA512:
6
- metadata.gz: fb66005f53cbb480678247a36aa77af00c32fb93cdf4ca9615aa3bf51efa82e83e60fdf4f61d68123e331a369451db548b40a8cc0f8e57cec3d6cd686872918f
7
- data.tar.gz: 63e5d71e4025046ef18c1759d582262f319581a8462092026b7f21e19640250ce94f6caefe5a6365e823c910eb4d8a390cb3a65a328a579739b06387e2732141
6
+ metadata.gz: 61f6e1657014daa3b0cc5efb2e5a0ac97c0d81708d68ad7a98b030e24ce5fd2e3918c2613371dc7f9ed64f5546dad84e8f189e996fe1db113a5a295137cba74c
7
+ data.tar.gz: 38e9e845d6bae276a28ef32d6fab275ae0539598c1f7c85680ba87554e3ac0f5619261cb9346435b787c06526d0a87ca2ddfbb502a299027d1b81ea75bc424af
data/README.md CHANGED
@@ -145,12 +145,19 @@ redirect_to zaikio_oauth_client.new_subscription_path(plan: "free")
145
145
 
146
146
  #### Session handling
147
147
 
148
- The Zaikio gem engine will set a cookie for the user after a successful OAuth flow: `session[:zaikio_person_id]`.
148
+ The Zaikio gem engine will set a cookie for the access token after a successful OAuth flow: `session[:zaikio_access_token_id]`.
149
149
 
150
150
  If you are using for example `Zaikio::Hub::Models`, you can use this snippet to set the current user:
151
151
 
152
152
  ```ruby
153
- Current.user ||= Zaikio::Hub::Models::Person.find_by(id: session[:zaikio_person_id])
153
+ access_token = Zaikio::OAuthClient.find_active_access_token(session[:zaikio_access_token_id])
154
+ session[:zaikio_access_token_id] = access_token&.id
155
+ Current.user = Zaikio::Hub::Models::Person.find_by(id: access_token&.bearer_id)
156
+
157
+ unless Current.user
158
+ session[:origin] = request.fullpath
159
+ redirect_to zaikio_oauth_client.new_session_path
160
+ end
154
161
  ````
155
162
 
156
163
  You can then use `Current.user` anywhere.
@@ -9,7 +9,7 @@ module Zaikio
9
9
  encrypts :token
10
10
  encrypts :refresh_token
11
11
 
12
- def self.build_from_access_token(access_token, requested_scopes: nil)
12
+ def self.build_from_access_token(access_token, requested_scopes: nil, include_refresh_token: true)
13
13
  payload = JWT.decode(access_token.token, nil, false).first rescue {} # rubocop:disable Style/RescueModifier
14
14
  scopes = access_token.params["scope"].split(",")
15
15
  new(
@@ -18,7 +18,7 @@ module Zaikio
18
18
  bearer_id: access_token.params["bearer"]["id"],
19
19
  audience: access_token.params["audiences"].first,
20
20
  token: access_token.token,
21
- refresh_token: access_token.refresh_token,
21
+ refresh_token: (access_token.refresh_token if include_refresh_token),
22
22
  expires_at: Time.strptime(access_token.expires_at.to_s, "%s"),
23
23
  scopes: scopes,
24
24
  requested_scopes: requested_scopes || scopes
@@ -67,7 +67,7 @@ module Zaikio
67
67
  end
68
68
 
69
69
  def bearer_klass
70
- return unless Zaikio.const_defined?("Hub::Models", false) # rubocop:disable Performance/StringIdentifierArgument
70
+ return unless Zaikio.const_defined?("Hub::Models", false)
71
71
 
72
72
  if Zaikio::Hub::Models.configuration.respond_to?(:"#{bearer_type.underscore}_class_name")
73
73
  Zaikio::Hub::Models.configuration.public_send(:"#{bearer_type.underscore}_class_name").constantize
@@ -95,5 +95,15 @@ module Zaikio
95
95
  destroy
96
96
  nil
97
97
  end
98
+
99
+ def revoke!
100
+ return unless Zaikio.const_defined?("Hub::RevokedAccessToken", false)
101
+
102
+ Zaikio::Hub.with_token(token) do
103
+ Zaikio::Hub::RevokedAccessToken.create
104
+ end
105
+ rescue Zaikio::ConnectionError => e
106
+ Zaikio::OAuthClient.configuration.logger.warn "Access Token #{id} could not be revoked: #{e.message}"
107
+ end
98
108
  end
99
109
  end
@@ -55,13 +55,16 @@ module Zaikio
55
55
  end
56
56
 
57
57
  def destroy
58
- access_token_id = session[:zaikio_access_token_id]
58
+ if (access_token = Zaikio::AccessToken.valid.or(Zaikio::AccessToken.valid_refresh)
59
+ .find_by(id: session[:zaikio_access_token_id]))
60
+ access_token.revoke!
61
+ end
59
62
  session.delete(:zaikio_access_token_id)
60
63
  session.delete(:origin)
61
64
 
62
65
  redirect_to send(
63
66
  respond_to?(:after_destroy_path_for) ? :after_destroy_path_for : :default_after_destroy_path_for,
64
- access_token_id
67
+ access_token.id
65
68
  )
66
69
  end
67
70
 
@@ -3,6 +3,23 @@ module Zaikio
3
3
  module TestHelper
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ VirtualAccessToken = Struct.new(:bearer_id, :bearer_type, :audience, :expired?, keyword_init: true)
7
+
8
+ class << self
9
+ def find_active_access_token(id)
10
+ return unless id.to_s.starts_with?("AT:")
11
+
12
+ _, audience, person_id = id.split(":")
13
+
14
+ VirtualAccessToken.new(
15
+ bearer_id: person_id,
16
+ audience: audience,
17
+ bearer_type: "Person",
18
+ expired?: false
19
+ )
20
+ end
21
+ end
22
+
6
23
  class TestSessionController < ActionController::Base # rubocop:disable Rails/ApplicationController
7
24
  def show
8
25
  if session[params[:key]].nil?
@@ -43,7 +60,15 @@ module Zaikio
43
60
  get "/zaikio/oauth_client/test_helper/session", params: { id: value, key: key }
44
61
  end
45
62
 
46
- def logged_in_as(person)
63
+ def logged_in_as(person, access_token: nil, client_name: nil)
64
+ client_name ||= Zaikio::OAuthClient.client_name ||
65
+ Zaikio::OAuthClient.configuration.all_client_names.first
66
+ set_session(
67
+ :zaikio_access_token_id,
68
+ access_token&.id || "AT:#{client_name}:#{person.id}"
69
+ )
70
+
71
+ # Deprecated please use zaikio_access_token_id
47
72
  set_session(:zaikio_person_id, person.id)
48
73
  end
49
74
  end
@@ -1,5 +1,5 @@
1
1
  module Zaikio
2
2
  module OAuthClient
3
- VERSION = "0.18.0".freeze
3
+ VERSION = "0.19.1".freeze
4
4
  end
5
5
  end
@@ -6,7 +6,7 @@ require "zaikio/oauth_client/configuration"
6
6
  require "zaikio/oauth_client/authenticatable"
7
7
 
8
8
  module Zaikio
9
- module OAuthClient
9
+ module OAuthClient # rubocop:disable Metrics/ModuleLength
10
10
  class << self
11
11
  attr_reader :client_name
12
12
 
@@ -58,9 +58,8 @@ module Zaikio
58
58
  end
59
59
  end
60
60
 
61
- # Finds the best possible access token, using the DB or an API call
62
- # * If the token has expired, it will be refreshed using the refresh_token flow
63
- # (if this fails, we fallback to getting a new token using client_credentials)
61
+ # Finds active access token, using the DB or Client Credentials flow
62
+ # * It searches in the DB for an active access token
64
63
  # * If the token does not exist, we'll get a new one using the client_credentials flow
65
64
  def get_access_token(bearer_id:, client_name: nil, bearer_type: "Person", scopes: nil, valid_for: 30.seconds)
66
65
  client_config = client_config_for(client_name || self.client_name)
@@ -72,8 +71,6 @@ module Zaikio
72
71
  requested_scopes: scopes,
73
72
  valid_for: valid_for)
74
73
 
75
- token = token.refresh! if token&.expired?
76
-
77
74
  token ||= fetch_new_token(client_config: client_config,
78
75
  bearer_type: bearer_type,
79
76
  bearer_id: bearer_id,
@@ -81,21 +78,36 @@ module Zaikio
81
78
  token
82
79
  end
83
80
 
84
- # Finds the best usable access token. Note that this token may have expired and
85
- # would require refreshing.
86
- def find_usable_access_token(client_name:, bearer_type:, bearer_id:, requested_scopes:, valid_for: 30.seconds) # rubocop:disable Metrics/MethodLength
87
- configuration.logger.debug "Try to fetch token for client_name: #{client_name}, "\
81
+ # This method can be used to find an active access token by id.
82
+ # It might refresh the access token to get an active one.
83
+ def find_active_access_token(id)
84
+ return unless id
85
+
86
+ if Rails.env.test?
87
+ access_token = TestHelper.find_active_access_token(id)
88
+ return access_token if access_token
89
+ end
90
+
91
+ access_token = Zaikio::AccessToken.find_by(id: id)
92
+ access_token = access_token.refresh! if access_token&.expired?
93
+
94
+ access_token
95
+ end
96
+
97
+ # Finds active access token with matching criteria for bearer and scopes.
98
+ def find_usable_access_token(client_name:, bearer_type:, bearer_id:, requested_scopes:, valid_for: 30.seconds) # rubocop:disable Metrics/MethodLength
99
+ configuration.logger.debug "Try to fetch token for client_name: #{client_name}, " \
88
100
  "bearer #{bearer_type}/#{bearer_id}, requested_scopes: #{requested_scopes}"
89
101
 
90
102
  fetch_access_token = lambda {
91
103
  Zaikio::AccessToken
92
104
  .where(audience: client_name)
93
- .usable(
105
+ .by_bearer(
94
106
  bearer_type: bearer_type,
95
107
  bearer_id: bearer_id,
96
- requested_scopes: requested_scopes,
97
- valid_until: valid_for.from_now
108
+ requested_scopes: requested_scopes
98
109
  )
110
+ .valid(valid_for.from_now)
99
111
  .first
100
112
  }
101
113
 
@@ -113,7 +125,10 @@ module Zaikio
113
125
  bearer_id: bearer_id,
114
126
  scopes: scopes
115
127
  ),
116
- requested_scopes: scopes
128
+ requested_scopes: scopes,
129
+ include_refresh_token: false
130
+ # Do not store refresh token on client credentials flow
131
+ # https://docs.zaikio.com/changelog/2022-08-09_client-credentials-drop-refresh-token.html
117
132
  ).tap(&:save!)
118
133
  end
119
134
 
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.18.0
4
+ version: 0.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zaikio GmbH
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-26 00:00:00.000000000 Z
11
+ date: 2022-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -89,7 +89,7 @@ dependencies:
89
89
  version: '0.5'
90
90
  - - "<"
91
91
  - !ruby/object:Gem::Version
92
- version: '2.0'
92
+ version: '3.0'
93
93
  type: :runtime
94
94
  prerelease: false
95
95
  version_requirements: !ruby/object:Gem::Requirement
@@ -99,7 +99,7 @@ dependencies:
99
99
  version: '0.5'
100
100
  - - "<"
101
101
  - !ruby/object:Gem::Version
102
- version: '2.0'
102
+ version: '3.0'
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: pg
105
105
  requirement: !ruby/object:Gem::Requirement