masks 0.6.0 → 0.8.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 +4 -4
- data/CHANGELOG.md +65 -0
- data/LICENSE +1 -1
- data/README.md +136 -32
- data/app/controllers/masks/rails/handshakes_controller.rb +13 -12
- data/app/controllers/masks/rails/logouts_controller.rb +32 -0
- data/app/controllers/masks/rails/sessions_controller.rb +3 -1
- data/app/views/masks/rails/handshakes/show.html.erb +17 -33
- data/config/routes.rb +1 -0
- data/lib/masks/client/claims.rb +69 -0
- data/lib/masks/client/delegations/fake.rb +91 -0
- data/lib/masks/client/delegations.rb +117 -0
- data/lib/masks/client/handshake.rb +7 -3
- data/lib/masks/client/introspection.rb +7 -1
- data/lib/masks/client/issuer.rb +4 -0
- data/lib/masks/client/logout.rb +60 -0
- data/lib/masks/client/registration.rb +2 -3
- data/lib/masks/client/resource.rb +3 -2
- data/lib/masks/client/session.rb +77 -10
- data/lib/masks/client/tokens.rb +4 -1
- data/lib/masks/client/verifier.rb +18 -3
- data/lib/masks/client.rb +46 -0
- data/lib/masks/rails/authentication.rb +78 -11
- data/lib/masks/rails/configuration.rb +36 -20
- data/lib/masks/rails/credentials.rb +0 -4
- data/lib/masks/rails/engine.rb +0 -5
- data/lib/masks/rails/protected_resource.rb +5 -4
- data/lib/masks/rails.rb +26 -0
- data/lib/masks/version.rb +1 -1
- data/lib/masks.rb +17 -0
- metadata +8 -3
data/lib/masks/client.rb
CHANGED
|
@@ -19,33 +19,79 @@ require_relative "client/claims"
|
|
|
19
19
|
require_relative "client/introspection"
|
|
20
20
|
require_relative "client/session"
|
|
21
21
|
require_relative "client/verifier"
|
|
22
|
+
require_relative "client/logout"
|
|
22
23
|
require_relative "client/resource"
|
|
23
24
|
require_relative "client/rack"
|
|
24
25
|
require_relative "client/registration"
|
|
25
26
|
require_relative "client/handshake"
|
|
27
|
+
require_relative "client/delegations"
|
|
26
28
|
|
|
27
29
|
module Masks
|
|
30
|
+
# = Masks::Client
|
|
31
|
+
#
|
|
32
|
+
# The protocol half of the gem: plain Ruby, no \Rails, no database. Every
|
|
33
|
+
# entry point here is a class method that builds one of the objects below.
|
|
34
|
+
#
|
|
35
|
+
# Which one you want depends on what the application is doing:
|
|
36
|
+
#
|
|
37
|
+
# [issuer] an app signing people in — discovery, PKCE, the code exchange
|
|
38
|
+
# [verifier] an API checking a bearer it was handed
|
|
39
|
+
# [resource] an API publishing what it is and which scopes it takes
|
|
40
|
+
# [handshake] an app registering itself, once, without a copied secret
|
|
41
|
+
#
|
|
42
|
+
# Everything reachable from here talks HTTP to a masks issuer and holds no
|
|
43
|
+
# state of its own beyond the discovery cache in ::registry.
|
|
28
44
|
module Client
|
|
29
45
|
class << self
|
|
46
|
+
# The process-wide cache of resolved issuers, so discovery is fetched
|
|
47
|
+
# once rather than per request.
|
|
48
|
+
#
|
|
49
|
+
# @return [Masks::Client::Registry]
|
|
30
50
|
def registry
|
|
31
51
|
@registry ||= Registry.new
|
|
32
52
|
end
|
|
33
53
|
|
|
54
|
+
# Resolves +url+ through its discovery document and returns the issuer
|
|
55
|
+
# it describes. Cached in ::registry, so calling this per request is
|
|
56
|
+
# cheap after the first.
|
|
57
|
+
#
|
|
58
|
+
# issuer = Masks::Client.issuer("https://auth.example")
|
|
59
|
+
# issuer.authorization_url(client_id: id, redirect_uri: uri)
|
|
60
|
+
#
|
|
61
|
+
# @return [Masks::Client::Issuer]
|
|
34
62
|
def issuer(url, **options)
|
|
35
63
|
Issuer.resolve(url, **options)
|
|
36
64
|
end
|
|
37
65
|
|
|
66
|
+
# Checks tokens minted by the issuer at +url+ against +audience+ — the
|
|
67
|
+
# API's own URL, which the token names in +aud+. A token issued for
|
|
68
|
+
# anything else is refused rather than merely noted.
|
|
69
|
+
#
|
|
70
|
+
# @return [Masks::Client::Verifier]
|
|
38
71
|
def verifier(url, audience:, **options)
|
|
39
72
|
Verifier.new(issuer(url), audience: audience, **options)
|
|
40
73
|
end
|
|
41
74
|
|
|
75
|
+
# Describes this API to callers: the scopes it accepts and the issuer
|
|
76
|
+
# that may mint tokens for it, served as RFC 9728 metadata.
|
|
77
|
+
#
|
|
78
|
+
# @return [Masks::Client::Resource]
|
|
42
79
|
def resource(url, issuer:, **options)
|
|
43
80
|
Resource.new(issuer: issuer, url: url, **options)
|
|
44
81
|
end
|
|
45
82
|
|
|
83
|
+
# Registers this application against a masks issuer. A person approves
|
|
84
|
+
# it in their browser and the credentials come back server to server, so
|
|
85
|
+
# no secret is pasted between the two.
|
|
86
|
+
#
|
|
87
|
+
# @return [Masks::Client::Handshake]
|
|
46
88
|
def handshake(url, **options)
|
|
47
89
|
Handshake.new(url, **options)
|
|
48
90
|
end
|
|
91
|
+
|
|
92
|
+
def delegations(issuer, **options)
|
|
93
|
+
Delegations.new(issuer: issuer, **options)
|
|
94
|
+
end
|
|
49
95
|
end
|
|
50
96
|
end
|
|
51
97
|
end
|
|
@@ -7,7 +7,15 @@ module Masks
|
|
|
7
7
|
included do
|
|
8
8
|
if respond_to?(:helper_method)
|
|
9
9
|
helper_method :masks_signed_in?, :masks_identity, :masks_tenant, :masks_scopes,
|
|
10
|
-
:masks_claims
|
|
10
|
+
:masks_claims, :masks_organization, :masks_organizations, :masks_role?,
|
|
11
|
+
:masks_login_url
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class_methods do
|
|
16
|
+
def masks_members_only!(role: nil, organization: nil, **options)
|
|
17
|
+
before_action(-> { authorize_masks_member!(*Array(role), organization: organization) },
|
|
18
|
+
**options.slice(:only, :except))
|
|
11
19
|
end
|
|
12
20
|
end
|
|
13
21
|
|
|
@@ -43,6 +51,7 @@ module Masks
|
|
|
43
51
|
session[masks_config.session_key] = held.compact
|
|
44
52
|
@masks_tokens = tokens
|
|
45
53
|
@masks_identity = held["identity"]
|
|
54
|
+
@masks_claims = nil
|
|
46
55
|
end
|
|
47
56
|
|
|
48
57
|
def masks_held
|
|
@@ -51,7 +60,8 @@ module Masks
|
|
|
51
60
|
|
|
52
61
|
IDENTITY = [
|
|
53
62
|
"sub", "name", "preferred_username", "email", "email_verified", "tenant",
|
|
54
|
-
"picture", Masks::Client::Claims::AVATARS
|
|
63
|
+
"picture", Masks::Client::Claims::AVATARS, Masks::Client::Claims::ORGANIZATION,
|
|
64
|
+
Masks::Client::Claims::ORGANIZATIONS
|
|
55
65
|
].freeze
|
|
56
66
|
|
|
57
67
|
def masks_identity_from(tokens)
|
|
@@ -64,6 +74,7 @@ module Masks
|
|
|
64
74
|
session.delete(masks_config.session_key)
|
|
65
75
|
@masks_tokens = nil
|
|
66
76
|
@masks_identity = nil
|
|
77
|
+
@masks_claims = nil
|
|
67
78
|
end
|
|
68
79
|
|
|
69
80
|
def masks_signed_in?
|
|
@@ -122,6 +133,20 @@ module Masks
|
|
|
122
133
|
@masks_claims ||= Masks::Client::Claims.new(masks_identity || {})
|
|
123
134
|
end
|
|
124
135
|
|
|
136
|
+
def masks_organization
|
|
137
|
+
held = masks_claims.organization
|
|
138
|
+
|
|
139
|
+
held.present? ? held : nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def masks_organizations
|
|
143
|
+
masks_claims.organizations
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def masks_role?(*roles)
|
|
147
|
+
masks_organization&.role?(*roles) || false
|
|
148
|
+
end
|
|
149
|
+
|
|
125
150
|
def masks_scopes
|
|
126
151
|
masks_tokens&.scopes || []
|
|
127
152
|
end
|
|
@@ -138,12 +163,12 @@ module Masks
|
|
|
138
163
|
return false unless masks_configured?
|
|
139
164
|
return false if masks_tokens&.refresh_token.nil?
|
|
140
165
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
resource: masks_config.resource_for(request)
|
|
145
|
-
)
|
|
166
|
+
refreshed = masks_session.refresh(
|
|
167
|
+
masks_tokens.refresh_token,
|
|
168
|
+
resource: masks_config.resource_for(request)
|
|
146
169
|
)
|
|
170
|
+
|
|
171
|
+
masks_store(refreshed, identity: masks_refreshed_identity(refreshed))
|
|
147
172
|
true
|
|
148
173
|
rescue Masks::Client::Unregistered
|
|
149
174
|
masks_disconnect!
|
|
@@ -153,6 +178,16 @@ module Masks
|
|
|
153
178
|
false
|
|
154
179
|
end
|
|
155
180
|
|
|
181
|
+
def masks_refreshed_identity(tokens)
|
|
182
|
+
held = masks_held["identity"]
|
|
183
|
+
|
|
184
|
+
return nil unless held.is_a?(Hash)
|
|
185
|
+
|
|
186
|
+
profile = masks_session.profile(tokens)
|
|
187
|
+
|
|
188
|
+
profile.empty? ? nil : held.merge(profile.slice(*IDENTITY))
|
|
189
|
+
end
|
|
190
|
+
|
|
156
191
|
def masks_logout_url(return_to: nil)
|
|
157
192
|
return nil unless masks_configured?
|
|
158
193
|
|
|
@@ -168,11 +203,14 @@ module Masks
|
|
|
168
203
|
"#{request.base_url}#{masks_local_path(masks_config.after_sign_out) || '/'}"
|
|
169
204
|
end
|
|
170
205
|
|
|
171
|
-
def masks_login_url(return_to: nil)
|
|
206
|
+
def masks_login_url(return_to: nil, organization: nil)
|
|
172
207
|
path = Masks::Rails::Engine.routes.url_helpers.start_path
|
|
173
|
-
|
|
208
|
+
query = {
|
|
209
|
+
"return_to" => masks_local_path(return_to),
|
|
210
|
+
"organization" => Masks::Client::Session.organization_key(organization)
|
|
211
|
+
}.compact
|
|
174
212
|
|
|
175
|
-
|
|
213
|
+
query.empty? ? path : "#{path}?#{URI.encode_www_form(query)}"
|
|
176
214
|
end
|
|
177
215
|
|
|
178
216
|
def masks_account
|
|
@@ -188,11 +226,20 @@ module Masks
|
|
|
188
226
|
"picture" => masks_claims.picture,
|
|
189
227
|
"avatars" => masks_claims.avatars.to_h.presence,
|
|
190
228
|
"tenant" => masks_tenant,
|
|
229
|
+
"organization" => masks_organization&.to_h,
|
|
230
|
+
"organizations" => masks_organizations.map(&:to_h).presence,
|
|
191
231
|
"scopes" => masks_scopes,
|
|
192
|
-
"expires_at" => masks_tokens&.expires_at
|
|
232
|
+
"expires_at" => masks_tokens&.expires_at,
|
|
233
|
+
"account_url" => masks_account_url
|
|
193
234
|
}.compact
|
|
194
235
|
end
|
|
195
236
|
|
|
237
|
+
def masks_account_url
|
|
238
|
+
"#{masks_config.issuer_for(request).to_s.chomp('/')}/"
|
|
239
|
+
rescue Masks::Rails::Configuration::Unconfigured
|
|
240
|
+
nil
|
|
241
|
+
end
|
|
242
|
+
|
|
196
243
|
def authenticate_masks!
|
|
197
244
|
return true if masks_configured? && (masks_signed_in? || (masks_tokens && masks_refresh!))
|
|
198
245
|
|
|
@@ -200,8 +247,28 @@ module Masks
|
|
|
200
247
|
false
|
|
201
248
|
end
|
|
202
249
|
|
|
250
|
+
def authorize_masks_member!(*roles, organization: nil)
|
|
251
|
+
return false unless authenticate_masks!
|
|
252
|
+
|
|
253
|
+
masks_claims.member!(*roles, organization: organization)
|
|
254
|
+
true
|
|
255
|
+
rescue Masks::Client::Forbidden => e
|
|
256
|
+
masks_forbid(e)
|
|
257
|
+
false
|
|
258
|
+
end
|
|
259
|
+
|
|
203
260
|
private
|
|
204
261
|
|
|
262
|
+
def masks_forbid(error)
|
|
263
|
+
response.headers["Cache-Control"] = "no-store"
|
|
264
|
+
|
|
265
|
+
if masks_wants_json?
|
|
266
|
+
render json: { "error" => error.code, "error_description" => error.description }, status: :forbidden
|
|
267
|
+
else
|
|
268
|
+
render plain: error.description, status: :forbidden
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
205
272
|
def masks_refuse
|
|
206
273
|
return masks_refuse_json if masks_wants_json?
|
|
207
274
|
return redirect_to(masks_handshake_path) unless masks_configured?
|
|
@@ -5,8 +5,9 @@ module Masks
|
|
|
5
5
|
|
|
6
6
|
attr_accessor :scope, :namespace, :resource, :resource_scopes, :after_sign_in,
|
|
7
7
|
:after_sign_out, :session_key, :sign_out_of_issuer, :parent_controller,
|
|
8
|
-
:credentials_path, :authenticate_everything
|
|
9
|
-
attr_writer :issuer, :redirect_uri, :name, :credentials, :store, :forget
|
|
8
|
+
:credentials_path, :authenticate_everything, :delegates
|
|
9
|
+
attr_writer :issuer, :redirect_uri, :name, :credentials, :store, :forget, :logged_out,
|
|
10
|
+
:delegation_redirect_uri, :organization
|
|
10
11
|
|
|
11
12
|
def initialize
|
|
12
13
|
@scope = Masks::Client::Session::DEFAULT_SCOPE
|
|
@@ -17,12 +18,9 @@ module Masks
|
|
|
17
18
|
@sign_out_of_issuer = false
|
|
18
19
|
@parent_controller = "ActionController::Base"
|
|
19
20
|
@authenticate_everything = false
|
|
21
|
+
@delegates = false
|
|
20
22
|
end
|
|
21
23
|
|
|
22
|
-
# An app that has not said where to keep its credentials gets one file
|
|
23
|
-
# under the Rails root, so the handshake works before anybody writes a
|
|
24
|
-
# `store` lambda. `things` overrides both because it is multi-tenant,
|
|
25
|
-
# which is the interesting case rather than the common one.
|
|
26
24
|
def default_credentials
|
|
27
25
|
@default_credentials ||= Credentials.new(
|
|
28
26
|
credentials_path || ::Rails.root.join("config", "masks.json")
|
|
@@ -43,10 +41,20 @@ module Masks
|
|
|
43
41
|
"#{request.base_url}#{routes.callback_path}"
|
|
44
42
|
end
|
|
45
43
|
|
|
44
|
+
def delegation_redirect_uri_for(request)
|
|
45
|
+
return nil unless delegates
|
|
46
|
+
|
|
47
|
+
resolve(@delegation_redirect_uri, request)
|
|
48
|
+
end
|
|
49
|
+
|
|
46
50
|
def resource_for(request)
|
|
47
51
|
resolve(@resource, request)
|
|
48
52
|
end
|
|
49
53
|
|
|
54
|
+
def organization_for(request)
|
|
55
|
+
resolve(@organization, request)
|
|
56
|
+
end
|
|
57
|
+
|
|
50
58
|
def credentials_for(request)
|
|
51
59
|
held = @credentials ? resolve(@credentials, request) : default_credentials.read
|
|
52
60
|
held ||= {}
|
|
@@ -66,8 +74,21 @@ module Masks
|
|
|
66
74
|
client_id_for(request).present?
|
|
67
75
|
end
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
def backchannel_logout_uri_for(request)
|
|
78
|
+
return nil unless @logged_out.respond_to?(:call)
|
|
79
|
+
return nil unless Masks::Client::Issuer.resolve(issuer_for(request)).backchannel_logout?
|
|
80
|
+
|
|
81
|
+
"#{request.base_url}#{routes.backchannel_logout_path}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def logged_out!(request, logout)
|
|
85
|
+
return false unless @logged_out.respond_to?(:call)
|
|
86
|
+
|
|
87
|
+
@logged_out.arity == 1 ? @logged_out.call(logout) : @logged_out.call(request, logout)
|
|
88
|
+
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
|
|
71
92
|
def can_forget?
|
|
72
93
|
@forget.respond_to?(:call) || !@store.respond_to?(:call)
|
|
73
94
|
end
|
|
@@ -85,10 +106,6 @@ module Masks
|
|
|
85
106
|
@store.call(request, registration)
|
|
86
107
|
end
|
|
87
108
|
|
|
88
|
-
# The engine depends on `handshake_endpoint` being in the discovery
|
|
89
|
-
# document, and on the approval flow behind it. An issuer that predates
|
|
90
|
-
# both should say so here rather than at the one screen that exists to
|
|
91
|
-
# be the first thing anybody touches.
|
|
92
109
|
MINIMUM_ISSUER = 1
|
|
93
110
|
|
|
94
111
|
def issuer_speaks!(request)
|
|
@@ -132,22 +149,21 @@ module Masks
|
|
|
132
149
|
name: name_for(request),
|
|
133
150
|
resource: Array(resource_for(request)).first ||
|
|
134
151
|
raise(Unconfigured, "Masks::Rails.config.resource is not set"),
|
|
135
|
-
redirect_uris: [ redirect_uri_for(request) ],
|
|
152
|
+
redirect_uris: [ redirect_uri_for(request), delegation_redirect_uri_for(request) ].compact.uniq,
|
|
136
153
|
return_to: return_to_for(request),
|
|
137
|
-
scope: approved_scope
|
|
154
|
+
scope: approved_scope,
|
|
155
|
+
backchannel_logout_uri: backchannel_logout_uri_for(request)
|
|
138
156
|
)
|
|
139
157
|
end
|
|
140
158
|
|
|
141
|
-
# What the handshake asks to be approved for, which is not what a sign-in
|
|
142
|
-
# requests. An app that owns a namespace asks for the namespace once, so
|
|
143
|
-
# that adding a capability later is a deployment rather than an approval
|
|
144
|
-
# round; the authorize request still names the scopes it actually wants.
|
|
145
159
|
def approved_scope
|
|
146
|
-
|
|
160
|
+
delegated = delegates ? [ Masks::Client::Delegations::SCOPE ] : []
|
|
161
|
+
|
|
162
|
+
return Array(scope) + delegated if namespace.blank?
|
|
147
163
|
|
|
148
164
|
outside = Array(scope).reject { |name| name.to_s.start_with?(namespace) }
|
|
149
165
|
|
|
150
|
-
outside + [ namespace ]
|
|
166
|
+
outside + [ namespace ] + delegated
|
|
151
167
|
end
|
|
152
168
|
|
|
153
169
|
def return_to_for(request)
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
module Masks
|
|
2
2
|
module Rails
|
|
3
|
-
# The default place a single-tenant app keeps what the handshake gives it,
|
|
4
|
-
# so `config.store` has something to be before a consumer writes one. An
|
|
5
|
-
# app with more than one issuer wants its own — `things` keeps these on
|
|
6
|
-
# `tenants`, because a handshake is per tenant there.
|
|
7
3
|
class Credentials
|
|
8
4
|
KEYS = %w[client_id client_secret registration_access_token registration_client_uri].freeze
|
|
9
5
|
|
data/lib/masks/rails/engine.rb
CHANGED
|
@@ -5,11 +5,6 @@ module Masks
|
|
|
5
5
|
|
|
6
6
|
config.masks = Masks::Rails.config
|
|
7
7
|
|
|
8
|
-
# Opt-in, not blanket. This used to `include Masks::Rails::Authentication`
|
|
9
|
-
# into every controller in the host app, which lands twenty-five `masks_*`
|
|
10
|
-
# methods and four helper_methods on code the consumer owns, with no way
|
|
11
|
-
# to say no — and a name collision found that way is the kind of thing
|
|
12
|
-
# `grants:` versus `scope:` already cost this project once.
|
|
13
8
|
initializer "masks.authentication" do
|
|
14
9
|
ActiveSupport.on_load(:action_controller) do
|
|
15
10
|
include Masks::Rails::Authentication if Masks::Rails.config.authenticate_everything
|
|
@@ -18,15 +18,16 @@ module Masks
|
|
|
18
18
|
@masks_claims if defined?(@masks_claims)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def masks_authenticate!(scope: nil, **)
|
|
22
|
-
@masks_claims = masks_resource.authenticate(request.authorization, scope: scope
|
|
21
|
+
def masks_authenticate!(scope: nil, role: nil, organization: nil, **)
|
|
22
|
+
@masks_claims = masks_resource.authenticate(request.authorization, scope: scope, role: role,
|
|
23
|
+
organization: organization)
|
|
23
24
|
rescue Masks::Client::Challenge => e
|
|
24
25
|
masks_challenge(e)
|
|
25
26
|
false
|
|
26
27
|
end
|
|
27
28
|
|
|
28
|
-
def masks_authenticate(scope: nil)
|
|
29
|
-
masks_resource.authenticate(request.authorization, scope: scope)
|
|
29
|
+
def masks_authenticate(scope: nil, role: nil, organization: nil)
|
|
30
|
+
masks_resource.authenticate(request.authorization, scope: scope, role: role, organization: organization)
|
|
30
31
|
rescue Masks::Client::Unauthenticated
|
|
31
32
|
nil
|
|
32
33
|
end
|
data/lib/masks/rails.rb
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
require "rails"
|
|
2
2
|
|
|
3
|
+
module Masks
|
|
4
|
+
# = Masks::Rails
|
|
5
|
+
#
|
|
6
|
+
# The consumer half: a \Rails engine that mounts the code flow into an
|
|
7
|
+
# application, so signing in against a masks issuer is configuration rather
|
|
8
|
+
# than a controller you write.
|
|
9
|
+
#
|
|
10
|
+
# It loads only when +Rails::Engine+ is already defined. Requiring the gem
|
|
11
|
+
# from a plain Ruby process gets Masks::Client and nothing else.
|
|
12
|
+
#
|
|
13
|
+
# Three pieces do the work:
|
|
14
|
+
#
|
|
15
|
+
# [Configuration] the issuer, credentials and routes, set once in an
|
|
16
|
+
# initializer and validated on boot rather than on the
|
|
17
|
+
# first request that needs them
|
|
18
|
+
# [Authentication] +masks_login_url+, the callback, and the session the
|
|
19
|
+
# app reads +current_actor+ from
|
|
20
|
+
# [ProtectedResource] the other direction — checking a bearer this app was
|
|
21
|
+
# handed, for an API rather than a browser
|
|
22
|
+
#
|
|
23
|
+
# This engine is the client. The provider is the masks-server gem, whether
|
|
24
|
+
# it runs elsewhere or is mounted on a subdomain of this app.
|
|
25
|
+
module Rails
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
3
29
|
require_relative "version"
|
|
4
30
|
require_relative "client"
|
|
5
31
|
require_relative "rails/credentials"
|
data/lib/masks/version.rb
CHANGED
data/lib/masks.rb
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# = \Masks
|
|
2
|
+
#
|
|
3
|
+
# Signs an application in against a masks issuer.
|
|
4
|
+
#
|
|
5
|
+
# The gem is two halves. Masks::Client is plain Ruby and speaks the protocol —
|
|
6
|
+
# discovery, PKCE, the code exchange, token verification. Masks::Rails mounts
|
|
7
|
+
# that flow into a \Rails app, and loads only when +Rails::Engine+ is already
|
|
8
|
+
# defined, so requiring this gem outside \Rails costs nothing.
|
|
9
|
+
#
|
|
10
|
+
# issuer = Masks::Client.issuer("https://auth.example")
|
|
11
|
+
# issuer.authorization_url(client_id: id, redirect_uri: uri)
|
|
12
|
+
#
|
|
13
|
+
# The provider itself is not in here. It is the masks-server gem, which runs
|
|
14
|
+
# as an app of its own or mounted inside another Rails app.
|
|
15
|
+
module Masks
|
|
16
|
+
end
|
|
17
|
+
|
|
1
18
|
require_relative "masks/version"
|
|
2
19
|
require_relative "masks/client"
|
|
3
20
|
|
metadata
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: masks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- the masks authors
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -25,7 +25,8 @@ dependencies:
|
|
|
25
25
|
version: '3.1'
|
|
26
26
|
description: Discovery, PKCE authorization, token exchange, and token verification
|
|
27
27
|
against a masks issuer, with Rack middleware for a resource server and a Rails engine
|
|
28
|
-
that mounts the consumer half of the code flow. The auth server itself
|
|
28
|
+
that mounts the consumer half of the code flow. The auth server itself is the masks-server
|
|
29
|
+
gem.
|
|
29
30
|
executables: []
|
|
30
31
|
extensions: []
|
|
31
32
|
extra_rdoc_files: []
|
|
@@ -36,6 +37,7 @@ files:
|
|
|
36
37
|
- app/controllers/masks/rails/avatars_controller.rb
|
|
37
38
|
- app/controllers/masks/rails/base_controller.rb
|
|
38
39
|
- app/controllers/masks/rails/handshakes_controller.rb
|
|
40
|
+
- app/controllers/masks/rails/logouts_controller.rb
|
|
39
41
|
- app/controllers/masks/rails/sessions_controller.rb
|
|
40
42
|
- app/views/layouts/masks/rails/plain.html.erb
|
|
41
43
|
- app/views/masks/rails/handshakes/refused.html.erb
|
|
@@ -46,11 +48,14 @@ files:
|
|
|
46
48
|
- lib/masks.rb
|
|
47
49
|
- lib/masks/client.rb
|
|
48
50
|
- lib/masks/client/claims.rb
|
|
51
|
+
- lib/masks/client/delegations.rb
|
|
52
|
+
- lib/masks/client/delegations/fake.rb
|
|
49
53
|
- lib/masks/client/errors.rb
|
|
50
54
|
- lib/masks/client/handshake.rb
|
|
51
55
|
- lib/masks/client/http.rb
|
|
52
56
|
- lib/masks/client/introspection.rb
|
|
53
57
|
- lib/masks/client/issuer.rb
|
|
58
|
+
- lib/masks/client/logout.rb
|
|
54
59
|
- lib/masks/client/pkce.rb
|
|
55
60
|
- lib/masks/client/rack.rb
|
|
56
61
|
- lib/masks/client/registration.rb
|