1
+ # frozen_string_literal: true
2
+
1
3
module OIDCProvider
2
4
class Authorization < ApplicationRecord
3
5
belongs_to :account , class_name : OIDCProvider . account_class
@@ -10,25 +12,72 @@ class Authorization < ApplicationRecord
10
12
attribute :expires_at , :datetime , default : -> { 5 . minutes . from_now }
11
13
12
14
serialize :scopes , JSON
15
+ serialize :claims , JSON
16
+
17
+ def access_token
18
+ super || ( expire! && generate_access_token! )
19
+ end
20
+
21
+ def scope_configs_for ( type )
22
+ if claims_request_for? ( type )
23
+ build_scope_configs_from_claims_request_for ( type )
24
+ else
25
+ type == :id_token ? [ open_id_scope_config ] : user_info_scope_configs
26
+ end
27
+ end
13
28
14
29
def expire!
15
30
self . expires_at = Time . now
16
- self . save!
17
- end
18
31
19
- def access_token
20
- super || expire! && generate_access_token!
32
+ save!
21
33
end
22
34
23
35
def id_token
24
36
super || generate_id_token!
25
37
end
26
38
39
+ def user_info_scopes
40
+ scopes - [ 'openid' ]
41
+ end
42
+
27
43
private
28
44
45
+ def build_scope_config_for ( scope , type , key )
46
+ ScopeConfig . new ( scope , [ key . to_sym ] ) . tap do |scope_config |
47
+ scope_config . add_force_claim ( key . to_sym => claims [ type . to_s ] [ key ] )
48
+ end
49
+ end
50
+
51
+ def build_scope_configs_from_claims_request_for ( type )
52
+ # No matter the `claims` config, when we are about to create an IdToken
53
+ # response, we need the OpenID scope claims since there's mandatory ones
54
+ scope_configs = type == :id_token ? [ open_id_scope_config ] : [ ]
55
+
56
+ claims [ type . to_s ] . each_key do |key |
57
+ scopes_with_claim = OIDCProvider . find_all_scopes_with_claim ( key )
58
+
59
+ next unless scope_found? ( scopes_with_claim , key )
60
+
61
+ warn_when_many_scopes_found_in ( scopes_with_claim , key , type )
62
+
63
+ scope = scopes_with_claim . first
64
+
65
+ next unless scope_has_been_requested? ( scope )
66
+
67
+ scope_configs << build_scope_config_for ( scope , type , key )
68
+ end
69
+
70
+ scope_configs
71
+ end
72
+
73
+ def claims_request_for? ( type )
74
+ return false unless claims
75
+
76
+ claims . keys . include? ( type . to_s )
77
+ end
78
+
29
79
def generate_access_token!
30
- token = create_access_token!
31
- token
80
+ create_access_token!
32
81
end
33
82
34
83
def generate_id_token!
@@ -37,5 +86,51 @@ def generate_id_token!
37
86
token . save!
38
87
token
39
88
end
89
+
90
+ def open_id_scope_config
91
+ scope = OIDCProvider . find_scope ( OIDCProvider ::Scopes ::OpenID )
92
+
93
+ ScopeConfig . new ( scope , scope . claims )
94
+ end
95
+
96
+ def scope_found? ( scopes_with_claim , key )
97
+ return true unless scopes_with_claim . empty?
98
+
99
+ Rails . logger . warn (
100
+ "WARNING: No scope found providing the '#{ key } ' claim. " \
101
+ 'OIDCProvider will skip it.'
102
+ )
103
+
104
+ false
105
+ end
106
+
107
+ def scope_has_been_requested? ( scope )
108
+ return true if scopes . include? ( scope . name )
109
+
110
+ Rails . logger . warn (
111
+ "WARNING: The scope #{ scope . name } has not being requested " \
112
+ 'on authorization creation, there fore OIDCProvider will skip it.'
113
+ )
114
+
115
+ false
116
+ end
117
+
118
+ def user_info_scope_configs
119
+ user_info_scopes . map do |scope_name |
120
+ scope = OIDCProvider . find_scope ( scope_name )
121
+
122
+ ScopeConfig . new ( scope , scope . claims )
123
+ end
124
+ end
125
+
126
+ def warn_when_many_scopes_found_in ( scopes_with_claim , key , type )
127
+ return unless scopes_with_claim . size > 1
128
+
129
+ Rails . logger . warn (
130
+ "WARNING: Scopes #{ scopes_with_claim . map ( &:name ) . to_sentence } " \
131
+ "have the #{ key } claim declared. OIDCProvider will use the first " \
132
+ "one to populate the #{ type } response."
133
+ )
134
+ end
40
135
end
41
136
end
0 commit comments