gamora 0.7.0 → 0.9.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e164eceeb7c3a744ed43be46877cb904fff4add871d4a7b4fac25e4837f2f731
4
- data.tar.gz: cff5f7b7f3ffd07b13d6e6cc0e476ae86c87788bdf47a4e9c9ff4703dfe54d64
3
+ metadata.gz: 6fff76821e79e75149f4d407303a9b52dac3b68ac711ffc38ac4e8d517ab7225
4
+ data.tar.gz: 4f5d52c9ef04b8d1219ca84a28fe25d3bb0dad677d97edc7c863d3c039a9e8d4
5
5
  SHA512:
6
- metadata.gz: b5da9c118a7f13441147ded22bb7bc237e7b51cd583e7355fa65370ef4e71dfa5256150f6ff0b6aad0f0169a1113dc9a8af2514aecff33454bb571391dea74de
7
- data.tar.gz: ad67d0b0be691f544bd2ffcc277b6a70f036bd20ddbabfd9a48b1f92023f84023e8eaa715b6ccc82a9f8a90f4be975b0ac54a657bc18a14e6fd6e40f4bff6f23
6
+ metadata.gz: eaec688075667ad6184c0567aa2637480a1781e50e5a7bb9448ba27f0b39cc969f42d83374afb5c1c2a5ccc1a339cfc95c553e71492e1e0de65a836f247bde45
7
+ data.tar.gz: a7d1eadca9cd826bcb13f22c01e332324199877fd9e43285e3daae60a6b3ce29102f3beeccfb20db200563d7a6a90c8ae7dfe25d4097e9cb6fd8a2762ef9f0bb
@@ -5,6 +5,7 @@ module Gamora
5
5
  module Base
6
6
  CLAIMS = {
7
7
  sub: :id,
8
+ roles: :roles,
8
9
  email: :email,
9
10
  given_name: :first_name,
10
11
  family_name: :last_name,
@@ -14,9 +15,15 @@ module Gamora
14
15
  }.freeze
15
16
 
16
17
  def authenticate_user!
18
+ return authentication_failed! unless access_token.present?
19
+
20
+ token_data = introspect_access_token(access_token)
21
+ return authentication_failed! unless valid_token_data?(token_data)
22
+
17
23
  claims = resource_owner_claims(access_token)
18
- assign_current_user_from_claims(claims) if claims.present?
19
- validate_authentication!
24
+ return authentication_failed! unless claims.present?
25
+
26
+ assign_current_user_from_claims(claims)
20
27
  end
21
28
 
22
29
  def current_user
@@ -25,21 +32,29 @@ module Gamora
25
32
 
26
33
  private
27
34
 
28
- def validate_authentication!
35
+ def access_token
29
36
  raise NotImplementedError
30
37
  end
31
38
 
32
- def access_token
39
+ def authentication_failed!
33
40
  raise NotImplementedError
34
41
  end
35
42
 
36
- def user_authentication_failed!
37
- raise NotImplementedError
43
+ def valid_token_data?(token_data)
44
+ token_data[:active] && whitelisted_client?(token_data[:client_id])
45
+ end
46
+
47
+ def whitelisted_client?(client_id)
48
+ whitelisted_clients.include?(client_id)
49
+ end
50
+
51
+ def whitelisted_clients
52
+ Configuration.whitelisted_clients | [Configuration.client_id]
38
53
  end
39
54
 
40
55
  def assign_current_user_from_claims(claims)
41
- attrs = user_attributes_from_claims(claims)
42
- @current_user = User.new(attrs)
56
+ attributes = user_attributes_from_claims(claims)
57
+ @current_user = User.new(attributes)
43
58
  end
44
59
 
45
60
  def user_attributes_from_claims(claims)
@@ -47,27 +62,29 @@ module Gamora
47
62
  end
48
63
 
49
64
  def resource_owner_claims(access_token)
50
- return {} if access_token.blank?
51
-
52
- resource_owner_claims!(access_token)
53
- end
65
+ cache_key = cache_key(:userinfo, access_token)
66
+ expires_in = Configuration.userinfo_cache_expires_in
54
67
 
55
- def resource_owner_claims!(access_token)
56
- Rails.cache.fetch(cache_key(access_token), cache_options) do
68
+ Rails.cache.fetch(cache_key, { expires_in: expires_in }) do
57
69
  oauth_client.userinfo(access_token)
58
70
  end
59
71
  end
60
72
 
61
- def oauth_client
62
- Client.from_config
73
+ def introspect_access_token(access_token)
74
+ cache_key = cache_key(:introspect, access_token)
75
+ expires_in = Configuration.introspect_cache_expires_in
76
+
77
+ Rails.cache.fetch(cache_key, { expires_in: expires_in }) do
78
+ oauth_client.introspect(access_token)
79
+ end
63
80
  end
64
81
 
65
- def cache_options
66
- { expires_in: Configuration.userinfo_cache_expires_in }
82
+ def cache_key(context, access_token)
83
+ "gamora:#{context}:#{Digest::SHA256.hexdigest(access_token)}"
67
84
  end
68
85
 
69
- def cache_key(access_token)
70
- "userinfo:#{Digest::SHA256.hexdigest(access_token)}"
86
+ def oauth_client
87
+ Client.from_config
71
88
  end
72
89
  end
73
90
  end
@@ -7,12 +7,6 @@ module Gamora
7
7
 
8
8
  private
9
9
 
10
- def validate_authentication!
11
- return if current_user.present?
12
-
13
- user_authentication_failed!
14
- end
15
-
16
10
  def access_token
17
11
  pattern = /^Bearer /
18
12
  header = request.headers["Authorization"]
@@ -21,7 +15,7 @@ module Gamora
21
15
  header.gsub(pattern, "")
22
16
  end
23
17
 
24
- def user_authentication_failed!
18
+ def authentication_failed!
25
19
  render json: { error: "Access token invalid" }, status: :unauthorized
26
20
  end
27
21
  end
@@ -11,18 +11,12 @@ module Gamora
11
11
 
12
12
  private
13
13
 
14
- def validate_authentication!
15
- return if current_user.present?
16
-
17
- session["gamora.origin"] = request.original_url
18
- user_authentication_failed!
19
- end
20
-
21
14
  def access_token
22
15
  session[:access_token]
23
16
  end
24
17
 
25
- def user_authentication_failed!
18
+ def authentication_failed!
19
+ session["gamora.origin"] = request.original_url
26
20
  redirect_to gamora.authentication_path
27
21
  end
28
22
  end
data/lib/gamora/client.rb CHANGED
@@ -20,13 +20,25 @@ module Gamora
20
20
  token_method: Configuration.token_method,
21
21
  redirect_uri: Configuration.redirect_uri,
22
22
  userinfo_url: Configuration.userinfo_url,
23
- authorize_url: Configuration.authorize_url
23
+ authorize_url: Configuration.authorize_url,
24
+ introspect_url: Configuration.introspect_url
24
25
  }
25
26
  end
26
27
  end
27
28
 
28
29
  def userinfo(access_token)
29
- response = userinfo_request(access_token)
30
+ params = userinfo_params(access_token)
31
+ opts = request_options(params)
32
+ response = request(:post, options[:userinfo_url], opts)
33
+ JSON.parse(response.body).symbolize_keys
34
+ rescue OAuth2::Error
35
+ {}
36
+ end
37
+
38
+ def introspect(access_token)
39
+ params = introspect_params(access_token)
40
+ opts = request_options(params)
41
+ response = request(:post, options[:introspect_url], opts)
30
42
  JSON.parse(response.body).symbolize_keys
31
43
  rescue OAuth2::Error
32
44
  {}
@@ -34,15 +46,22 @@ module Gamora
34
46
 
35
47
  private
36
48
 
37
- def userinfo_request(access_token)
38
- opts = userinfo_request_options(access_token)
39
- request(:post, options[:userinfo_url], opts)
49
+ def request_options(params)
50
+ {
51
+ body: params.to_json,
52
+ headers: { "Content-Type": "application/json" }
53
+ }
40
54
  end
41
55
 
42
- def userinfo_request_options(access_token)
56
+ def userinfo_params(access_token)
57
+ { access_token: access_token }
58
+ end
59
+
60
+ def introspect_params(access_token)
43
61
  {
44
- body: { access_token: access_token }.to_json,
45
- headers: { "Content-Type": "application/json" }
62
+ token: access_token,
63
+ client_id: Configuration.client_id,
64
+ client_secret: Configuration.client_secret
46
65
  }
47
66
  end
48
67
  end
@@ -6,8 +6,9 @@ module Gamora
6
6
  mattr_accessor :client_secret, default: nil
7
7
  mattr_accessor :site, default: nil
8
8
  mattr_accessor :token_url, default: "/oauth2/token"
9
- mattr_accessor :authorize_url, default: "/oauth2/authorize"
10
9
  mattr_accessor :userinfo_url, default: "/oauth2/userinfo"
10
+ mattr_accessor :authorize_url, default: "/oauth2/authorize"
11
+ mattr_accessor :introspect_url, default: "/oauth2/introspect"
11
12
  mattr_accessor :token_method, default: :post
12
13
  mattr_accessor :redirect_uri, default: nil
13
14
  mattr_accessor :default_scope, default: "openid profile email"
@@ -16,7 +17,9 @@ module Gamora
16
17
  mattr_accessor :default_branding, default: "amco"
17
18
  mattr_accessor :default_theme, default: "default"
18
19
  mattr_accessor :ui_locales, default: -> { I18n.locale }
19
- mattr_accessor :userinfo_cache_expires_in, default: 0.seconds
20
+ mattr_accessor :userinfo_cache_expires_in, default: 1.minute
21
+ mattr_accessor :introspect_cache_expires_in, default: 0.seconds
22
+ mattr_accessor :whitelisted_clients, default: []
20
23
 
21
24
  def setup
22
25
  yield(self) if block_given?
data/lib/gamora/user.rb CHANGED
@@ -5,6 +5,7 @@ module Gamora
5
5
  include ActiveModel::Model
6
6
 
7
7
  attr_accessor :id,
8
+ :roles,
8
9
  :email,
9
10
  :last_name,
10
11
  :first_name,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gamora
4
- VERSION = "0.7.0"
4
+ VERSION = "0.9.0"
5
5
  end
@@ -8,8 +8,9 @@ Gamora.setup do |config|
8
8
 
9
9
  # ===> Optional OAuth2 configuration options and its defaults.
10
10
  # config.token_url = "/oauth2/token"
11
- # config.authorize_url = "/oauth2/authorize"
12
11
  # config.userinfo_url = "/oauth2/userinfo"
12
+ # config.authorize_url = "/oauth2/authorize"
13
+ # config.introspect_url = "/oauth2/introspect"
13
14
  # config.token_method = :post
14
15
  # config.redirect_uri = nil
15
16
  # config.default_scope = "openid profile email"
@@ -18,5 +19,7 @@ Gamora.setup do |config|
18
19
  # config.default_branding = "amco"
19
20
  # config.default_theme = "default"
20
21
  # config.ui_locales = -> { I18n.locale }
21
- # config.userinfo_cache_expires_in = 0.seconds
22
+ # config.userinfo_cache_expires_in = 1.minute
23
+ # config.introspect_cache_expires_in = 0.seconds
24
+ # config.whitelisted_clients = []
22
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gamora
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Gutiérrez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-02 00:00:00.000000000 Z
11
+ date: 2023-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth2