keycloak 1.2.0 → 2.0.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/lib/generators/initializer_generator.rb +1 -4
- data/lib/keycloak.rb +133 -91
- data/lib/keycloak/exceptions.rb +4 -1
- data/lib/keycloak/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16dc6ab9a33a507e177fc676f907c015291d0f70
|
4
|
+
data.tar.gz: 4c49fd2835f1ac1a39410c50f77b8fca4bdb791c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 813ec13535ea225feb0a42048169c6d62caa51ccc7b54aac269ce8beba2a5b63e2ee065163f0df196ec83aa0f74cfeb8fa363a3a64160a6bf249fbadbae487d0
|
7
|
+
data.tar.gz: 37d21da9cecd8a1f21a013b6afb8a35f99919654ca5957bedf4f86cd2a01ac2fd8d3620a82f7d115ffa5ae77bd9b9c283195981440a69611058a023844105b59
|
@@ -8,10 +8,7 @@ class InitializerGenerator < Rails::Generators::Base
|
|
8
8
|
# If true, then all request exception will explode in application (this is the default value)
|
9
9
|
Keycloak.generate_request_exception = #{generate_request_exception}
|
10
10
|
# controller that manage the user session
|
11
|
-
Keycloak.keycloak_controller = 'session'
|
12
|
-
# internal user for admin tasks
|
13
|
-
Keycloak::Internal.admin_user = ''
|
14
|
-
Keycloak::Internal.admin_password = ''"
|
11
|
+
Keycloak.keycloak_controller = 'session'"
|
15
12
|
end
|
16
13
|
end
|
17
14
|
end
|
data/lib/keycloak.rb
CHANGED
@@ -9,7 +9,7 @@ module Keycloak
|
|
9
9
|
|
10
10
|
class << self
|
11
11
|
attr_accessor :proxy, :generate_request_exception, :keycloak_controller,
|
12
|
-
:
|
12
|
+
:proc_cookie_token, :proc_external_attributes
|
13
13
|
end
|
14
14
|
|
15
15
|
|
@@ -23,26 +23,20 @@ module Keycloak
|
|
23
23
|
module Client
|
24
24
|
|
25
25
|
class << self
|
26
|
-
attr_reader :
|
27
|
-
|
28
|
-
:token, :token_introspection, :decoded_refresh_token,
|
29
|
-
:active, :decoded_id_token, :userinfo
|
26
|
+
attr_reader :realm, :url, :client_id, :auth_server_url,
|
27
|
+
:secret, :configuration, :public_key
|
30
28
|
|
31
|
-
attr_accessor :external_attributes
|
32
29
|
end
|
33
30
|
|
34
31
|
KEYCLOAK_JSON_FILE = 'keycloak.json'
|
35
32
|
|
36
33
|
def self.get_token(user, password)
|
37
34
|
setup_module
|
38
|
-
reset_active
|
39
|
-
|
40
|
-
@user, @password = user, password
|
41
35
|
|
42
36
|
payload = {'client_id' => @client_id,
|
43
37
|
'client_secret' => @secret,
|
44
|
-
'username' =>
|
45
|
-
'password' =>
|
38
|
+
'username' => user,
|
39
|
+
'password' => password,
|
46
40
|
'grant_type' => 'password'
|
47
41
|
}
|
48
42
|
|
@@ -50,24 +44,50 @@ module Keycloak
|
|
50
44
|
end
|
51
45
|
|
52
46
|
def self.get_token_by_code(code, redirect_uri)
|
53
|
-
|
47
|
+
verify_setup
|
48
|
+
|
49
|
+
payload = {'client_id' => @client_id,
|
50
|
+
'client_secret' => @secret,
|
51
|
+
'code' => code,
|
52
|
+
'grant_type' => 'authorization_code',
|
53
|
+
'redirect_uri' => redirect_uri
|
54
|
+
}
|
55
|
+
|
56
|
+
mount_request_token(payload)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.get_token_by_refresh_token(refreshToken = nil)
|
60
|
+
verify_setup
|
61
|
+
|
62
|
+
refreshToken = self.token['refresh_token']
|
63
|
+
|
64
|
+
payload = {'client_id' => @client_id,
|
65
|
+
'client_secret' => @secret,
|
66
|
+
'refresh_token' => refreshToken,
|
67
|
+
'grant_type' => 'refresh_token'
|
68
|
+
}
|
69
|
+
|
70
|
+
mount_request_token(payload)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.get_token_by_client_credentials
|
74
|
+
setup_module
|
54
75
|
|
55
76
|
payload = {'client_id' => @client_id,
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
'redirect_uri' => redirect_uri
|
60
|
-
}
|
77
|
+
'client_secret' => @secret,
|
78
|
+
'grant_type' => 'client_credentials'
|
79
|
+
}
|
61
80
|
|
62
81
|
mount_request_token(payload)
|
63
82
|
end
|
64
83
|
|
65
84
|
def self.get_token_introspection(refresh = false)
|
66
|
-
|
85
|
+
verify_setup
|
86
|
+
|
67
87
|
unless refresh
|
68
|
-
payload = {'token' =>
|
88
|
+
payload = {'token' => self.token["access_token"]}
|
69
89
|
else
|
70
|
-
payload = {'token' =>
|
90
|
+
payload = {'token' => self.token["refresh_token"]}
|
71
91
|
end
|
72
92
|
|
73
93
|
authorization = Base64.strict_encode64("#{@client_id}:#{@secret}")
|
@@ -80,15 +100,11 @@ module Keycloak
|
|
80
100
|
RestClient.post(@configuration['token_introspection_endpoint'], payload, header){|response, request, result|
|
81
101
|
case response.code
|
82
102
|
when 200..399
|
83
|
-
|
84
|
-
|
85
|
-
@token_introspection
|
103
|
+
response.body
|
104
|
+
|
86
105
|
else
|
87
106
|
response.return!
|
88
107
|
end
|
89
|
-
if !@active
|
90
|
-
reset_active
|
91
|
-
end
|
92
108
|
}
|
93
109
|
end
|
94
110
|
|
@@ -96,16 +112,20 @@ module Keycloak
|
|
96
112
|
end
|
97
113
|
|
98
114
|
def self.url_login_redirect(redirect_uri, response_type = 'code')
|
115
|
+
verify_setup
|
116
|
+
|
99
117
|
p = URI.encode_www_form({:response_type => response_type, :client_id => @client_id, :redirect_uri => redirect_uri})
|
100
118
|
"#{@configuration['authorization_endpoint']}?#{p}"
|
101
119
|
end
|
102
120
|
|
103
121
|
def self.logout(redirect_uri = '')
|
104
|
-
|
122
|
+
verify_setup
|
123
|
+
|
124
|
+
if self.token
|
105
125
|
payload = {'client_id' => @client_id,
|
106
|
-
|
107
|
-
|
108
|
-
|
126
|
+
'client_secret' => @secret,
|
127
|
+
'refresh_token' => self.token["refresh_token"]
|
128
|
+
}
|
109
129
|
|
110
130
|
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
111
131
|
|
@@ -119,7 +139,6 @@ module Keycloak
|
|
119
139
|
RestClient.post(final_url, payload, header){|response, request, result|
|
120
140
|
case response.code
|
121
141
|
when 200..399
|
122
|
-
reset_active
|
123
142
|
true
|
124
143
|
else
|
125
144
|
response.return!
|
@@ -134,7 +153,9 @@ module Keycloak
|
|
134
153
|
end
|
135
154
|
|
136
155
|
def self.get_userinfo
|
137
|
-
|
156
|
+
verify_setup
|
157
|
+
|
158
|
+
payload = {'access_token' => self.token["access_token"]}
|
138
159
|
|
139
160
|
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
140
161
|
|
@@ -142,8 +163,7 @@ module Keycloak
|
|
142
163
|
RestClient.post(@configuration['userinfo_endpoint'], payload, header){|response, request, result|
|
143
164
|
case response.code
|
144
165
|
when 200
|
145
|
-
|
146
|
-
@userinfo
|
166
|
+
response.body
|
147
167
|
else
|
148
168
|
response.return!
|
149
169
|
end
|
@@ -154,6 +174,8 @@ module Keycloak
|
|
154
174
|
end
|
155
175
|
|
156
176
|
def self.url_user_account
|
177
|
+
verify_setup
|
178
|
+
|
157
179
|
"#{@url}/realms/#{@realm}/account"
|
158
180
|
end
|
159
181
|
|
@@ -166,7 +188,6 @@ module Keycloak
|
|
166
188
|
@secret = installation["credentials"]["secret"]
|
167
189
|
@public_key = installation["realm-public-key"]
|
168
190
|
@auth_server_url = installation["auth-server-url"]
|
169
|
-
reset_active(false)
|
170
191
|
openid_configuration
|
171
192
|
else
|
172
193
|
raise "#{KEYCLOAK_JSON_FILE} not found."
|
@@ -174,8 +195,10 @@ module Keycloak
|
|
174
195
|
end
|
175
196
|
|
176
197
|
def self.has_role?(userRole)
|
198
|
+
verify_setup
|
199
|
+
|
177
200
|
if user_signed_in?
|
178
|
-
dt =
|
201
|
+
dt = decoded_access_token[0]
|
179
202
|
dt = dt["resource_access"][@client_id]
|
180
203
|
if dt != nil
|
181
204
|
dt["roles"].each do |role|
|
@@ -191,22 +214,50 @@ module Keycloak
|
|
191
214
|
end
|
192
215
|
|
193
216
|
def self.user_signed_in?
|
217
|
+
verify_setup
|
218
|
+
|
194
219
|
begin
|
195
|
-
get_token_introspection['active']
|
196
|
-
rescue
|
197
|
-
|
220
|
+
JSON(get_token_introspection)['active'] === true
|
221
|
+
rescue => e
|
222
|
+
if e.class < Keycloak::KeycloakException
|
223
|
+
raise
|
224
|
+
else
|
225
|
+
false
|
226
|
+
end
|
198
227
|
end
|
199
228
|
end
|
200
229
|
|
201
230
|
def self.get_attribute(attributeName)
|
202
|
-
|
231
|
+
verify_setup
|
232
|
+
|
233
|
+
attr = decoded_access_token[0]
|
203
234
|
attr[attributeName]
|
204
235
|
end
|
205
236
|
|
237
|
+
def self.token
|
238
|
+
unless Keycloak.proc_cookie_token.nil?
|
239
|
+
JSON Keycloak.proc_cookie_token.call
|
240
|
+
else
|
241
|
+
raise Keycloak::ProcCookieTokenNotDefined
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.external_attributes
|
246
|
+
unless Keycloak.proc_external_attributes.nil?
|
247
|
+
Keycloak.proc_external_attributes.call
|
248
|
+
else
|
249
|
+
raise Keycloak::ProcExternalAttributesNotDefined
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
206
253
|
private
|
207
254
|
|
208
255
|
KEYCLOACK_CONTROLLER_DEFAULT = 'session'
|
209
256
|
|
257
|
+
def self.verify_setup
|
258
|
+
get_installation if @configuration.nil?
|
259
|
+
end
|
260
|
+
|
210
261
|
def self.setup_module
|
211
262
|
Keycloak.proxy ||= ''
|
212
263
|
Keycloak.keycloak_controller ||= KEYCLOACK_CONTROLLER_DEFAULT
|
@@ -227,9 +278,9 @@ module Keycloak
|
|
227
278
|
|
228
279
|
def self.openid_configuration
|
229
280
|
RestClient.proxy = Keycloak.proxy unless Keycloak.proxy.empty?
|
230
|
-
|
281
|
+
configUrl = "#{@url}/realms/#{@realm}/.well-known/openid-configuration"
|
231
282
|
_request = -> do
|
232
|
-
RestClient.get
|
283
|
+
RestClient.get configUrl
|
233
284
|
end
|
234
285
|
response = exec_request _request
|
235
286
|
if response.code == 200
|
@@ -239,14 +290,6 @@ module Keycloak
|
|
239
290
|
end
|
240
291
|
end
|
241
292
|
|
242
|
-
def self.reset_active(resetExternalAttributes = true)
|
243
|
-
@active = false
|
244
|
-
@userinfo = nil
|
245
|
-
if resetExternalAttributes
|
246
|
-
@external_attributes = nil
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
293
|
def self.mount_request_token(payload)
|
251
294
|
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
252
295
|
|
@@ -254,15 +297,7 @@ module Keycloak
|
|
254
297
|
RestClient.post(@configuration['token_endpoint'], payload, header){|response, request, result|
|
255
298
|
case response.code
|
256
299
|
when 200
|
257
|
-
|
258
|
-
@token = JSON response.body
|
259
|
-
@decoded_access_token = JWT.decode @token["access_token"], @public_key, false, { :algorithm => 'RS256' }
|
260
|
-
@decoded_refresh_token = JWT.decode @token["refresh_token"], @public_key, false, { :algorithm => 'RS256' }
|
261
|
-
if @token["id_token"]
|
262
|
-
@decoded_id_token = JWT.decode @token["id_token"], @public_key, false, { :algorithm => 'RS256' }
|
263
|
-
end
|
264
|
-
Keycloak::Admin.setup_admin(@auth_server_url, @realm, @token["access_token"])
|
265
|
-
@token
|
300
|
+
response.body
|
266
301
|
else
|
267
302
|
response.return!
|
268
303
|
end
|
@@ -272,19 +307,28 @@ module Keycloak
|
|
272
307
|
exec_request _request
|
273
308
|
end
|
274
309
|
|
310
|
+
def self.decoded_access_token
|
311
|
+
JWT.decode self.token["access_token"], @public_key, false, { :algorithm => 'RS256' }
|
312
|
+
end
|
313
|
+
|
314
|
+
def self.decoded_refresh_token
|
315
|
+
JWT.decode self.token["refresh_token"], @public_key, false, { :algorithm => 'RS256' }
|
316
|
+
end
|
317
|
+
|
318
|
+
def self.decoded_id_token
|
319
|
+
tk = self.token
|
320
|
+
if tk["id_token"]
|
321
|
+
@decoded_id_token = JWT.decode tk["id_token"], @public_key, false, { :algorithm => 'RS256' }
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
275
325
|
end
|
276
326
|
|
277
327
|
# Os recursos desse module (admin) serão utilizadas apenas por usuários que possuem as roles do client realm-management
|
278
328
|
module Admin
|
279
329
|
|
280
330
|
class << self
|
281
|
-
attr_reader :access_token, :auth_server_url, :realm
|
282
|
-
end
|
283
331
|
|
284
|
-
def self.setup_admin(auth_server_url, realm, access_token)
|
285
|
-
@auth_server_url = auth_server_url
|
286
|
-
@access_token = access_token
|
287
|
-
@realm = realm
|
288
332
|
end
|
289
333
|
|
290
334
|
def self.get_users( queryParameters = nil)
|
@@ -407,25 +451,25 @@ module Keycloak
|
|
407
451
|
# Generics methods
|
408
452
|
|
409
453
|
def self.generic_get(service, queryParameters = nil)
|
410
|
-
Keycloak.generic_request(
|
454
|
+
Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, nil, 'GET')
|
411
455
|
end
|
412
456
|
|
413
457
|
def self.generic_post(service, queryParameters, bodyParameter)
|
414
|
-
Keycloak.generic_request(
|
458
|
+
Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'POST')
|
415
459
|
end
|
416
460
|
|
417
461
|
def self.generic_put(service, queryParameters, bodyParameter)
|
418
|
-
Keycloak.generic_request(
|
462
|
+
Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'PUT')
|
419
463
|
end
|
420
464
|
|
421
465
|
def self.generic_delete(service, queryParameters = nil, bodyParameter = nil)
|
422
|
-
Keycloak.generic_request(
|
466
|
+
Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'DELETE')
|
423
467
|
end
|
424
468
|
|
425
469
|
private
|
426
470
|
|
427
471
|
def self.base_url
|
428
|
-
|
472
|
+
Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/"
|
429
473
|
end
|
430
474
|
|
431
475
|
def self.full_url(service)
|
@@ -438,13 +482,13 @@ module Keycloak
|
|
438
482
|
include Keycloak::Admin
|
439
483
|
|
440
484
|
class << self
|
441
|
-
attr_accessor
|
485
|
+
attr_accessor
|
442
486
|
end
|
443
487
|
|
444
488
|
def self.change_password(userID, redirectURI = '')
|
445
489
|
proc = lambda {|token|
|
446
490
|
Keycloak.generic_request(token["access_token"],
|
447
|
-
Keycloak::
|
491
|
+
Keycloak::Admin.full_url("users/#{userID}/execute-actions-email"),
|
448
492
|
{:redirect_uri => redirectURI, :client_id => Keycloak::Client.client_id},
|
449
493
|
['UPDATE_PASSWORD'],
|
450
494
|
'PUT')
|
@@ -460,9 +504,9 @@ module Keycloak
|
|
460
504
|
|
461
505
|
def self.get_logged_user_info
|
462
506
|
proc = lambda {|token|
|
463
|
-
userinfo = Keycloak::Client.get_userinfo
|
507
|
+
userinfo = JSON Keycloak::Client.get_userinfo
|
464
508
|
Keycloak.generic_request(token["access_token"],
|
465
|
-
Keycloak::
|
509
|
+
Keycloak::Admin.full_url("users/#{userinfo['sub']}"),
|
466
510
|
nil, nil, 'GET')
|
467
511
|
}
|
468
512
|
|
@@ -477,7 +521,7 @@ module Keycloak
|
|
477
521
|
search = {:email => userLogin}
|
478
522
|
end
|
479
523
|
users = JSON Keycloak.generic_request(token["access_token"],
|
480
|
-
Keycloak::
|
524
|
+
Keycloak::Admin.full_url("users/"),
|
481
525
|
search, nil, 'GET')
|
482
526
|
users[0]
|
483
527
|
if users.count == 0
|
@@ -529,7 +573,7 @@ module Keycloak
|
|
529
573
|
:enabled => true}
|
530
574
|
|
531
575
|
if !newUser || Keycloak.generic_request(token["access_token"],
|
532
|
-
Keycloak::
|
576
|
+
Keycloak::Admin.full_url("users/"),
|
533
577
|
nil, userRepresentation, 'POST')
|
534
578
|
|
535
579
|
user = get_user_info(userName, true) if newUser
|
@@ -539,18 +583,18 @@ module Keycloak
|
|
539
583
|
:value => password}
|
540
584
|
|
541
585
|
if Keycloak.generic_request(token["access_token"],
|
542
|
-
Keycloak::
|
586
|
+
Keycloak::Admin.full_url("users/#{user['id']}/reset-password"),
|
543
587
|
nil, credentialRepresentation, 'PUT')
|
544
588
|
|
545
589
|
client = JSON Keycloak.generic_request(token["access_token"],
|
546
|
-
Keycloak::
|
590
|
+
Keycloak::Admin.full_url("clients/"),
|
547
591
|
{:clientId => Keycloak::Client.client_id}, nil, 'GET')
|
548
592
|
|
549
593
|
roles = Array.new
|
550
594
|
clientRolesNames.each do |r|
|
551
595
|
if r && !r.empty?
|
552
596
|
role = JSON Keycloak.generic_request(token["access_token"],
|
553
|
-
Keycloak::
|
597
|
+
Keycloak::Admin.full_url("clients/#{client[0]['id']}/roles/#{r}"),
|
554
598
|
nil, nil, 'GET')
|
555
599
|
roles.push(role)
|
556
600
|
end
|
@@ -558,7 +602,7 @@ module Keycloak
|
|
558
602
|
|
559
603
|
if roles.count > 0
|
560
604
|
Keycloak.generic_request(token["access_token"],
|
561
|
-
Keycloak::
|
605
|
+
Keycloak::Admin.full_url("users/#{user['id']}/role-mappings/clients/#{client[0]['id']}"),
|
562
606
|
nil, roles, 'POST')
|
563
607
|
end
|
564
608
|
end
|
@@ -584,11 +628,9 @@ module Keycloak
|
|
584
628
|
Keycloak::Client.get_installation
|
585
629
|
|
586
630
|
payload = {'client_id' => Keycloak::Client.client_id,
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
'grant_type' => 'password'
|
591
|
-
}
|
631
|
+
'client_secret' => Keycloak::Client.secret,
|
632
|
+
'grant_type' => 'client_credentials'
|
633
|
+
}
|
592
634
|
|
593
635
|
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
594
636
|
|
@@ -633,6 +675,7 @@ module Keycloak
|
|
633
675
|
private
|
634
676
|
|
635
677
|
def self.generic_request(accessToken, uri, queryParameters, bodyParameter, method)
|
678
|
+
Keycloak::Client.verify_setup
|
636
679
|
final_url = uri
|
637
680
|
|
638
681
|
header = {'Content-Type' => 'application/x-www-form-urlencoded',
|
@@ -689,20 +732,19 @@ module Keycloak
|
|
689
732
|
end
|
690
733
|
|
691
734
|
def self.rescue_response(response)
|
692
|
-
|
693
|
-
case @last_response.code
|
735
|
+
case response.code
|
694
736
|
when 200..399
|
695
|
-
if
|
737
|
+
if response.body.empty?
|
696
738
|
true
|
697
739
|
else
|
698
|
-
|
740
|
+
response.body
|
699
741
|
end
|
700
742
|
else
|
701
743
|
if Keycloak.explode_exception
|
702
|
-
|
744
|
+
response.return!
|
703
745
|
else
|
704
746
|
begin
|
705
|
-
|
747
|
+
response.return!
|
706
748
|
rescue RestClient::ExceptionWithResponse => err
|
707
749
|
err.response
|
708
750
|
rescue Exception => e
|
data/lib/keycloak/exceptions.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
1
|
module Keycloak
|
2
|
-
class
|
2
|
+
class KeycloakException < StandardError; end
|
3
|
+
class UserLoginNotFound < KeycloakException; end
|
4
|
+
class ProcCookieTokenNotDefined < KeycloakException; end
|
5
|
+
class ProcExternalAttributesNotDefined < KeycloakException; end
|
3
6
|
end
|
data/lib/keycloak/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keycloak
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guilherme Portugues
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|