keycloak 2.3.2 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +6 -6
- data/README.md +60 -40
- data/README.pt-BR.md +36 -28
- data/lib/keycloak.rb +184 -114
- data/lib/keycloak/exceptions.rb +1 -0
- data/lib/keycloak/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d419a683b8c5acc4e90870947280ad4953e44ffe3a91fc231afc9ed8665226d1
|
4
|
+
data.tar.gz: 523aa9997cbacb76ef37a2617b685cc9a919219b2511cd79bd38da0114ca1ccb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5776f216a4ef94247922c5b4837785ab71bb6611fe0bf6cc9f86f30847ae140f6d10634e969e7e3c682d1c87598077a54c387ae6a7f52dbd5582e3d2c17775e
|
7
|
+
data.tar.gz: 93d76cc19f4d93efe21bf7697a4f345818f22faaead39ad8376bca6d953dd173781b04877e8f2b32485673195aefeb710cd7a986ce655bf26a754915e75b6247
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
keycloak (2.
|
4
|
+
keycloak (2.4.0)
|
5
5
|
json
|
6
6
|
jwt
|
7
7
|
rest-client
|
@@ -10,15 +10,15 @@ GEM
|
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
12
|
diff-lcs (1.3)
|
13
|
-
domain_name (0.5.
|
13
|
+
domain_name (0.5.20180417)
|
14
14
|
unf (>= 0.0.5, < 1.0.0)
|
15
15
|
http-cookie (1.0.3)
|
16
16
|
domain_name (~> 0.5)
|
17
17
|
json (2.1.0)
|
18
18
|
jwt (2.1.0)
|
19
|
-
mime-types (3.
|
19
|
+
mime-types (3.2.2)
|
20
20
|
mime-types-data (~> 3.2015)
|
21
|
-
mime-types-data (3.
|
21
|
+
mime-types-data (3.2018.0812)
|
22
22
|
netrc (0.11.0)
|
23
23
|
rake (10.5.0)
|
24
24
|
rest-client (2.0.2)
|
@@ -40,7 +40,7 @@ GEM
|
|
40
40
|
rspec-support (3.7.1)
|
41
41
|
unf (0.1.4)
|
42
42
|
unf_ext
|
43
|
-
unf_ext (0.0.7.
|
43
|
+
unf_ext (0.0.7.5)
|
44
44
|
|
45
45
|
PLATFORMS
|
46
46
|
ruby
|
@@ -52,4 +52,4 @@ DEPENDENCIES
|
|
52
52
|
rspec (~> 3.0)
|
53
53
|
|
54
54
|
BUNDLED WITH
|
55
|
-
1.16.
|
55
|
+
1.16.2
|
data/README.md
CHANGED
@@ -8,6 +8,8 @@ Its development was based on version 3.2 of Keycloak, whose documentation can be
|
|
8
8
|
|
9
9
|
Publication of gem: https://rubygems.org/gems/keycloak
|
10
10
|
|
11
|
+
Exemple: https://github.com/imagov/example-gem-keycloak
|
12
|
+
|
11
13
|
## Installation
|
12
14
|
|
13
15
|
Add this line in your application's <b>gemfile</b>:
|
@@ -33,7 +35,7 @@ To add the configuration file:
|
|
33
35
|
|
34
36
|
Since you already have a Keycloak environment configured and the gem already installed, the next step is to define how the application will authenticate. Keycloak works with key authentication protocols, such as OpenID Connect, Oauth 2.0 and SAML 2.0, integrating system access through Single-Sign On, and can also provide access to <b>LDAP</b> or <b>Active Directory</b> users.
|
35
37
|
|
36
|
-
When you register a realm and also a Client in your Keycloak environment, you can download the Client installation file into the
|
38
|
+
When you register a realm and also a Client in your Keycloak environment, you can download the Client installation file into the `config` folder of the application so that gem gets the information it needs to interact with Keycloak. To download this, simply access your Client's registry, click the <b>Installation</b> tab, select <b>Keycloak OIDC JSON</b> in the <b>Format option</b> field and click <b>Download</b>. If your application does not only work with a specific client (application server for APIs, for example), then you can tell what is the realm that gem will interact in the `keycloak.rb` configuration file.
|
37
39
|
|
38
40
|
Gem has a main module called <b>Keycloak</b>. Within this module there are three other modules: <b>Client</b>, <b>Admin</b> and <b>Internal</b>.
|
39
41
|
|
@@ -41,6 +43,12 @@ Gem has a main module called <b>Keycloak</b>. Within this module there are three
|
|
41
43
|
|
42
44
|
The Keycloak module has some attributes and its definitions are fundamental for the perfect functioning of the gem in the application.
|
43
45
|
|
46
|
+
```ruby
|
47
|
+
Keycloak.installation_file = 'path/to/file.json'
|
48
|
+
```
|
49
|
+
|
50
|
+
Allows you to set the location of installation file if you have one. If not set, it will default to `keycloak.json` in the `config` folder of your repository. In any case, it will use installation file only if it's present.
|
51
|
+
|
44
52
|
```ruby
|
45
53
|
Keycloak.realm
|
46
54
|
```
|
@@ -122,7 +130,7 @@ The `Keycloak::Client` module has the methods that represent the <b>endpoint</b>
|
|
122
130
|
We will detail each of these methods:
|
123
131
|
|
124
132
|
```ruby
|
125
|
-
Keycloak::Client.get_token(user, password)
|
133
|
+
Keycloak::Client.get_token(user, password, client_id = '', secret = '')
|
126
134
|
```
|
127
135
|
|
128
136
|
If you choose to authenticate users using the screen of your own application, then use this method. Simply invoke it in the method of login in the `controller` defined with the session controller of your application, passing as parameter the <b>user</b> and the <b>password</b> informed by the user. If the authentication is valid, then a JSON containing the `access_token` and the `refresh_token` is returned.
|
@@ -136,21 +144,35 @@ To authenticate the users of your application using a template configured in Key
|
|
136
144
|
|
137
145
|
|
138
146
|
```ruby
|
139
|
-
Keycloak::Client.get_token_by_code(code, redirect_uri)
|
147
|
+
Keycloak::Client.get_token_by_code(code, redirect_uri, client_id = '', secret = '')
|
140
148
|
```
|
141
149
|
|
142
150
|
When using the `Keycloak::Client.url_login_redirect` method to get a `code`, pass it as a parameter in this method so that Keycloak returns a token, thus logging the user in the application. The second parameter (`redirect_uri`) must be passed so that when a token is made available, Keycloak redirects to the url informed.
|
143
151
|
|
144
152
|
|
145
153
|
```ruby
|
146
|
-
Keycloak::Client.
|
154
|
+
Keycloak::Client.get_token_by_exchange(issuer, issuer_token, client_id = '', secret = '')
|
155
|
+
```
|
156
|
+
|
157
|
+
To get a token through a token previously obtained from a trusted provider (OpenID standard), such as Facebook, Gooble, Twitter, or even another realm configured in the keycloak, simply invoke this method, passing in the `issuer` parameter the provider alias configured in the realm, and in the `issuer_token` parameter the token obtained by that provider. This will return a token authenticated by your realm.
|
158
|
+
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
Keycloak::Client.get_userinfo_issuer(access_token = '', userinfo_endpoint = '')
|
162
|
+
```
|
163
|
+
|
164
|
+
This method returns the user information of a provider (`issuer` of the `get_token_by_exchange` method represented by the `access_token` passed as parameter. If the `access_token` parameter is not informed, then the gem will get this information in the cookie.
|
165
|
+
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
Keycloak::Client.get_token_by_refresh_token(refresh_token = '', client_id = '', secret = '')
|
147
169
|
```
|
148
170
|
|
149
171
|
When the user is already logged in and your application internally tracks the token expiration time provided by Keycloak, then this method can be used to renew that token if it is still valid. To do this, simply pass the `refresh_token` as a parameter. If you do not inform `refresh_token`, gem will use the `refresh_token` stored in the cookie.
|
150
172
|
|
151
173
|
|
152
174
|
```ruby
|
153
|
-
Keycloak::Client.get_token_introspection(token = '')
|
175
|
+
Keycloak::Client.get_token_introspection(token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
154
176
|
```
|
155
177
|
|
156
178
|
This method returns the information from the `token` session passed as parameter. Among the information returned, the most important is the `active` field, since it informs whether the token session passed in the parameter is active or not. This will help your application control whether the logged-in user session has expired or not. If no token is passed as a parameter, gem will use the last `access_token` stored in the application's cookie.
|
@@ -164,14 +186,14 @@ There are some Keycloak services like <b>password reset</b>, <b>user registratio
|
|
164
186
|
|
165
187
|
|
166
188
|
```ruby
|
167
|
-
Keycloak::Client.logout(redirect_uri = '', refresh_token = '')
|
189
|
+
Keycloak::Client.logout(redirect_uri = '', refresh_token = '', client_id = '', secret = '', end_session_endpoint = '')
|
168
190
|
```
|
169
191
|
|
170
192
|
When used before the expiration of the logged on user's session, this method terminates the session. If the `redirect_uri` parameter is fed, then Keycloak will redirect your application to the url informed after logout. The second parameter is `refresh_token`, obtained at the time of authentication or session update. If the latter is not informed, then the gem will use the `refresh_token` of the cookie
|
171
193
|
|
172
194
|
|
173
195
|
```ruby
|
174
|
-
Keycloak::Client.get_userinfo(access_token = '')
|
196
|
+
Keycloak::Client.get_userinfo(access_token = '', userinfo_endpoint = '')
|
175
197
|
```
|
176
198
|
|
177
199
|
This method returns synthetic information from the user represented by the `access_token` passed as a parameter, such as `sub` - which is the authenticated user id -, `preferred_username` - which is the authenticated user name - and `email` - which is the user's email address. If the `access_token` parameter is not informed, then the gem will get this information in the cookie.
|
@@ -185,14 +207,14 @@ Returns the <b>url</b> for access to the realm user registry of the installation
|
|
185
207
|
|
186
208
|
|
187
209
|
```ruby
|
188
|
-
Keycloak::Client.has_role?(user_role, access_token = '')
|
210
|
+
Keycloak::Client.has_role?(user_role, access_token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
189
211
|
```
|
190
212
|
|
191
213
|
The `has_role?` method decodes the JWT `access_token` and verifies that the user who owns the token has the <b>role</b> informed in the `user_role` parameter. If `access_token` is not informed then gem will use the `access_token` of the cookie.
|
192
214
|
|
193
215
|
|
194
216
|
```ruby
|
195
|
-
Keycloak::Client.user_signed_in?(access_token = '')
|
217
|
+
Keycloak::Client.user_signed_in?(access_token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
196
218
|
```
|
197
219
|
|
198
220
|
This method checks whether the `access_token` passed in the parameter is still active. To check whether the user is active or not, the gem invokes the `get_token_introspection` method internally. If `access_token` is not informed then gem will use the `access_token` of the cookie.
|
@@ -376,8 +398,8 @@ The following are the <b>Generics Methods</b>:
|
|
376
398
|
Keycloak::Admin.generic_get(service, query_parameters = nil, access_token = nil)
|
377
399
|
```
|
378
400
|
|
379
|
-
`generic_get`
|
380
|
-
|
401
|
+
`generic_get` allows you to make <b>Keycloak</b> `GET` service requests. The part of the URI that identifies the service must be passed in the `service` parameter, already with the route parameters (such as `{client}`, for example) properly replaced. In the `query_parameters` parameter you can pass a `hash` containing the <b>Queries Parameters</b> of the request.<br>
|
402
|
+
Example:
|
381
403
|
```ruby
|
382
404
|
Keycloak::Admin.generic_get("users/", {email: 'admin@test.com'}, "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU...")
|
383
405
|
```
|
@@ -387,107 +409,105 @@ Exemplo:
|
|
387
409
|
Keycloak::Admin.generic_post(service, query_parameters, body_parameter, access_token = nil)
|
388
410
|
```
|
389
411
|
|
390
|
-
`generic_post`
|
391
|
-
|
412
|
+
`generic_post` allows you to make <b>Keycloak</b> `POST` service requests. The part of the URI that identifies the service must be passed in the `service` parameter, already with the route parameters (such as `{client}`, for example) properly replaced. In the `query_parameters` parameter you can pass a `hash` containing the <b>Query Parameters</b> of the request. In the `body_parameter` parameter you can pass a `hash` containing the <b>Body Parameters</b> of the request.<br>
|
413
|
+
Example:
|
392
414
|
```ruby
|
393
415
|
Keycloak::Admin.generic_post("users/", nil, { username: "admin", email: "admin@test.com", enabled: true }, "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU...")
|
394
416
|
```
|
395
417
|
|
396
|
-
|
397
418
|
```ruby
|
398
419
|
Keycloak::Admin.generic_put(service, query_parameters, body_parameter, access_token = nil)
|
399
420
|
```
|
400
421
|
|
401
|
-
`generic_put`
|
422
|
+
`generic_put` allows you to make <b>Keycloak</b> `PUT` service requests. The part of the URI that identifies the service must be passed in the `service` parameter, already with the route parameters (such as `{client}`, for example) properly replaced. In the `query_parameters` parameter you can pass a `hash` containing the <b>Query Parameters</b> of the request. In the `body_parameter` parameter you can pass a `hash` containing the <b>Body Parameters</b> of the request.
|
402
423
|
|
403
424
|
|
404
425
|
```ruby
|
405
426
|
Keycloak::Admin.generic_delete(service, query_parameters = nil, body_parameter = nil, access_token = nil)
|
406
427
|
```
|
407
428
|
|
408
|
-
`generic_delete`
|
409
|
-
|
429
|
+
`generic_delete` allows you to make <b>Keycloak</b> `DELETE` service requests. The part of the URI that identifies the service must be passed in the `service` parameter, already with the route parameters (such as `{client}`, for example) properly replaced. In the `query_parameters` parameter you can pass a `hash` containing the <b>Query Parameters</b> of the request. In the `body_parameter` parameter you can pass a `hash` containing the <b>Body Parameters</b> of the request.
|
410
430
|
|
411
431
|
|
412
432
|
### Keycloak::Internal
|
413
433
|
|
414
|
-
|
434
|
+
The `Keycloak::internal` module provides methods designed to facilitate interaction between the application and <b>Keycloak</b>. From the information found in the `keycloak.json` installation file, all invoked methods will be authenticated automatically, using the application credentials (`grant_type = client_credentials`), depending on the assigned roles assigned to it. request is authorized.
|
415
435
|
|
416
436
|
|
417
437
|
```ruby
|
418
|
-
Keycloak::Internal.get_users(query_parameters = nil)
|
438
|
+
Keycloak::Internal.get_users(query_parameters = nil, client_id = '', secret = '')
|
419
439
|
```
|
420
440
|
|
421
|
-
`get_users`
|
441
|
+
`get_users` invokes the `Keycloak::Admin.get_users` method that returns a list of users, filtered according to the parameters hash passed in `query_parameters`.
|
422
442
|
|
423
443
|
|
424
444
|
```ruby
|
425
|
-
Keycloak::Internal.change_password(user_id, redirect_uri = '')
|
445
|
+
Keycloak::Internal.change_password(user_id, redirect_uri = '', client_id = '', secret = '')
|
426
446
|
```
|
427
447
|
|
428
|
-
`change_password`
|
448
|
+
`change_password` will invoke the Keycloak `PUT /admin/realms/{realm}/users/{id}/execute-actions-email` API requesting the `UPDATE_PASSWORD` action. This will cause Keycloak to trigger an email to the user represented by the `user_id` parameter. The `redirect_uri` parameter is optional. If it is not filled, then there will be no link to click after the password reset action has been completed.
|
429
449
|
|
430
450
|
|
431
451
|
```ruby
|
432
|
-
Keycloak::Internal.get_user_info(user_login, whole_word = false)
|
452
|
+
Keycloak::Internal.get_user_info(user_login, whole_word = false, client_id = '', secret = ''))
|
433
453
|
```
|
434
454
|
|
435
|
-
`get_user_info`,
|
455
|
+
`get_user_info`, based on the `user_login` parameter, which will be able to receive the `username` or the `email` of the user, will return an array of [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) in the case where the `whole_word` parameter is `false`, or it will return a [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) when the `whole_word` parameter is `true`. The `whole_word` parameter indicates whether the method should consider users that have `username` or `email` part of the expression passed in the `user_login` parameter - for the cases of `whole_word = false` - or that has exactly the last expression in this parameter - for the cases of `whole_word = true`.
|
436
456
|
|
437
457
|
|
438
458
|
```ruby
|
439
|
-
Keycloak::Internal.forgot_password(user_login, redirect_uri = '')
|
459
|
+
Keycloak::Internal.forgot_password(user_login, redirect_uri = '', client_id = '', secret = '')
|
440
460
|
```
|
441
461
|
|
442
|
-
`forgot_password`
|
462
|
+
`forgot_password` will invoke the `Keycloak::Internal.change_password` method after invoking the `Keycloak::Internal.get_user_info` method - passing in the `user_login` parameter of the described method the `user_login` parameter of this topic and passing `true` in the parameter `whole_word`. The use of this method is indicated for the cases of applications allow the reset of the password of the users without it is logged in.
|
443
463
|
|
444
464
|
|
445
465
|
```ruby
|
446
|
-
Keycloak::Internal.exists_name_or_email(value, user_id = '')
|
466
|
+
Keycloak::Internal.exists_name_or_email(value, user_id = '', client_id = '', secret = '')
|
447
467
|
```
|
448
468
|
|
449
|
-
`exists_name_or_email`
|
469
|
+
`exists_name_or_email` checks whether a user with `username` or `email` already exists in the `value` parameter in the realm. The `user_id` parameter is used to pass the `ID` of a user in cases where it is desired to change the `username` or `email` of the same, so that they are considered in the `username` and `email verification` different users of the user with the `ID` informed in `user_id`.
|
450
470
|
|
451
471
|
|
452
472
|
```ruby
|
453
|
-
Keycloak::Internal.get_logged_user_info
|
473
|
+
Keycloak::Internal.get_logged_user_info(client_id = '', secret = '')
|
454
474
|
```
|
455
475
|
|
456
|
-
`get_logged_user_info`
|
476
|
+
`get_logged_user_info` returns the [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) of the user logged into the application.
|
457
477
|
|
458
478
|
|
459
479
|
```ruby
|
460
480
|
# GET /admin/realms/{realm}/users
|
461
|
-
Keycloak::Internal.logged_federation_user?
|
481
|
+
Keycloak::Internal.logged_federation_user?(client_id = '', secret = '')
|
462
482
|
```
|
463
483
|
|
464
|
-
`logged_federation_user?`
|
484
|
+
`logged_federation_user?` method invokes the `Keycloak::Internal.get_logged_user_info` method and checks to see if it is an <b>Federation User</b> (an LDAP user for example).
|
465
485
|
|
466
486
|
|
467
487
|
```ruby
|
468
488
|
# GET /admin/realms/{realm}/users
|
469
|
-
Keycloak::Internal.create_starter_user(username, password, email, client_roles_names, proc = nil)
|
489
|
+
Keycloak::Internal.create_starter_user(username, password, email, client_roles_names, proc = nil, client_id = '', secret = '')
|
470
490
|
```
|
471
491
|
|
472
|
-
`create_starter_user`
|
492
|
+
`create_starter_user` is suitable for applications that allow the creation of new users without a user being logged in or even to create new users from `rake db: seed`. In the `username`, `password` and `email` parameters, the user name, password, and email, respectively, must be passed. In the `client_roles_names` parameter, a list (array) with the name of the `roles` of the Client that will be assigned to the user must be passed. The `proc` parameter is a <b>lambda</b> method that will make available the [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) of the created user as a parameter, so that actions should be defined by the application. This method returns the same return of the `proc` parameter method if it is set, otherwise it will return to [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) of the created user.
|
473
493
|
|
474
494
|
|
475
495
|
```ruby
|
476
|
-
Keycloak::Internal.get_client_roles
|
496
|
+
Keycloak::Internal.get_client_roles(client_id = '', secret = '')
|
477
497
|
```
|
478
498
|
|
479
|
-
`get_client_roles`
|
499
|
+
`get_client_roles` will return an array of [RoleRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_rolerepresentation) from the Client indicated in the `client_id` parameter or, in the absence of this, by the client of the `keycloak.json` installation file.
|
480
500
|
|
481
501
|
|
482
502
|
```ruby
|
483
|
-
Keycloak::Internal.get_client_user_roles(user_id)
|
503
|
+
Keycloak::Internal.get_client_user_roles(user_id, client_id = '', secret = '')
|
484
504
|
```
|
485
505
|
|
486
|
-
`get_client_user_roles`
|
506
|
+
`get_client_user_roles` will invoke the `Keycloak::Admin.get_effective_client_level_role_composite_user` method by considering the Client indicated in the `client_id` parameter or, if not, by the client of the `keycloak.json` installation file and the user represented by the `user_id` parameter.
|
487
507
|
|
488
508
|
|
489
509
|
```ruby
|
490
|
-
Keycloak::Internal.has_role?(user_id, user_role)
|
510
|
+
Keycloak::Internal.has_role?(user_id, user_role, client_id = '', secret = '')
|
491
511
|
```
|
492
512
|
|
493
|
-
`has_role?`
|
513
|
+
`has_role?` informing the user represented by the `user_id` parameter has <b>role</b> with the name represented by the `user_role` parameter.
|
data/README.pt-BR.md
CHANGED
@@ -5,6 +5,8 @@ O seu desenvolvimento foi baseado na versão 3.2 do Keycloak, cuja documentaçã
|
|
5
5
|
|
6
6
|
Publicação da gem: https://rubygems.org/gems/keycloak
|
7
7
|
|
8
|
+
Exemplo: https://github.com/imagov/example-gem-keycloak
|
9
|
+
|
8
10
|
## Instalação
|
9
11
|
|
10
12
|
Adicione esta linha no <b>Gemfile</b> de sua aplicação:
|
@@ -29,7 +31,7 @@ Para adicionar o arquivo de configuração:
|
|
29
31
|
|
30
32
|
Considerando que você já possua um ambiente do Keycloak configurado e a gem já instalada, o próximo passo é definir como será a autenticação da aplicação. O Keycloak trabalha com os principais protocolos de autenticação, tais como o OpenID Connect, Oauth 2.0 e SAML 2.0, integrando acesso a sistemas via Single-Sign On, podendo inclusive disponibilizar acessos a usuários LDAP ou Active Directory.
|
31
33
|
|
32
|
-
Ao cadastrar um Reino e também um Client no seu ambiente Keycloak, você poderá fazer o download do arquivo de instalação do Client para dentro da pasta
|
34
|
+
Ao cadastrar um Reino e também um Client no seu ambiente Keycloak, você poderá fazer o download do arquivo de instalação do Client para dentro da pasta `config` da aplicação, para que a gem obtenha as informações necessárias para interagir com o Keycloak. Para fazer esse download, basta acessar o cadastro de seu Client, clicar na aba <b>Installation</b>, selecionar <b>Keycloak OIDC JSON</b> no campo <b>Format option</b> e clicar em <b>Download</b>. Caso a sua aplicação não trabalhe apenas com um client específico (aplicação servidora de APIs, por exemplo), então você poderá informar o reino que a gem irá interagir no arquivo de configuração `keycloak.rb`.
|
33
35
|
|
34
36
|
A gem possui um módulo principal chamado <b>Keycloak</b>. Dentro desse módulo há três outros módulos: <b>Client</b>, <b>Admin</b> e <b>Internal</b>.
|
35
37
|
|
@@ -37,6 +39,12 @@ A gem possui um módulo principal chamado <b>Keycloak</b>. Dentro desse módulo
|
|
37
39
|
|
38
40
|
O módulo Keycloak possui alguns atributos e suas definições são fundamentais para o perfeito funcionamento da gem na aplicação.
|
39
41
|
|
42
|
+
```ruby
|
43
|
+
Keycloak.installation_file = 'path/to/file.json'
|
44
|
+
```
|
45
|
+
|
46
|
+
Permite você determinar o local do arquivo de instalação do Keycloak, caso você esteja utilizando um. Se não for informado, o caminho default será `config/Keycloak.json`.
|
47
|
+
|
40
48
|
```ruby
|
41
49
|
Keycloak.realm
|
42
50
|
```
|
@@ -116,7 +124,7 @@ Vamos ao detalhamento de cada um desses métodos:
|
|
116
124
|
|
117
125
|
|
118
126
|
```ruby
|
119
|
-
Keycloak::Client.get_token(user, password)
|
127
|
+
Keycloak::Client.get_token(user, password, client_id = '', secret = '')
|
120
128
|
```
|
121
129
|
|
122
130
|
Caso você opte por efetuar a autenticação dos usuários utilizando a tela da sua própria aplicação, então utilize esse método. Basta invocá-lo no método de login no `controller` definido com o controlador de sessão de sua aplicação, passando como parâmetro o <b>usuário</b> e a <b>senha</b> informados pelo usuário. Caso a autenticação seja válida, então será retornado um JSON contendo entre as informações principais o `access_token` e o `refresh_token`.
|
@@ -130,35 +138,35 @@ Para efetuar a autenticação dos usuários de sua aplicação utilizando um tem
|
|
130
138
|
|
131
139
|
|
132
140
|
```ruby
|
133
|
-
Keycloak::Client.get_token_by_code(code, redirect_uri)
|
141
|
+
Keycloak::Client.get_token_by_code(code, redirect_uri, client_id = '', secret = '')
|
134
142
|
```
|
135
143
|
|
136
144
|
Ao utilizar o método `Keycloak::Client.url_login_redirect` para obter um `code`, passe-o como parâmetro neste método para que o Keycloak retorne um token, efetuando assim o login do usuário na aplicação. O segundo parâmetro (`redirect_uri`) deve ser passado para que, ao disponibilizar um token, o Keycloak redirecione para a url informada.
|
137
145
|
|
138
146
|
|
139
147
|
```ruby
|
140
|
-
Keycloak::Client.get_token_by_exchange(issuer, issuer_token)
|
148
|
+
Keycloak::Client.get_token_by_exchange(issuer, issuer_token, client_id = '', secret = '')
|
141
149
|
```
|
142
150
|
|
143
151
|
Para obter um token através de um token obtido anteriormente de um provedor confiável (padrão OpenID), como Facebook, Gooble, Twitter, ou até mesmo outro reino configurado no keycloak, basta invocar este método, passando no parâmetro `issuer` o alias do provedor configurado no reino, e, no parâmetro `issuer_token` o token obtido por esse provedor. Com isso, será retornado um token autenticado pelo teu reino.
|
144
152
|
|
145
153
|
|
146
154
|
```ruby
|
147
|
-
Keycloak::Client.get_userinfo_issuer(access_token = '')
|
155
|
+
Keycloak::Client.get_userinfo_issuer(access_token = '', userinfo_endpoint = '')
|
148
156
|
```
|
149
157
|
|
150
158
|
Esse método retorna as informações do usuário de um provevedor (`issuer` do método `get_token_by_exchange`) representado pelo `access_token` passado como parâmetro. Caso o parâmetro `access_token` não seja informado, então a gem obterá essa informação no cookie.
|
151
159
|
|
152
160
|
|
153
161
|
```ruby
|
154
|
-
Keycloak::Client.get_token_by_refresh_token(refresh_token = '')
|
162
|
+
Keycloak::Client.get_token_by_refresh_token(refresh_token = '', client_id = '', secret = '')
|
155
163
|
```
|
156
164
|
|
157
165
|
Quando o usuário já estiver logado e a sua aplicação acompanhar internamente o tempo de expiração do token fornecido pelo Keycloak, então esse método poderá ser utilizado para a renovação desse token, caso o mesmo ainda seja válido. Para isso, basta passar como parãmetro o `refresh_token`. Caso não seja informado o `refresh_token`, a gem utilizará o `refresh_token` armazenado no cookie.
|
158
166
|
|
159
167
|
|
160
168
|
```ruby
|
161
|
-
Keycloak::Client.get_token_introspection(token = '')
|
169
|
+
Keycloak::Client.get_token_introspection(token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
162
170
|
```
|
163
171
|
|
164
172
|
Esse método retorna a as informações da sessão do `token` passado como parâmetro. Entre as informações retornadas, a mais importante é o campo `active`, pois ele informa se a sessão do token passado no parâmetro é ativo ou não. Isso auxiliará a sua aplicação a controlar se a sessão do usuário logado expirou ou não. Caso nenhum token seja passado como parâmetro, a gem utilizará o último `access_token` armazenado no cookie da aplicação.
|
@@ -172,14 +180,14 @@ Há alguns serviços do Keycloak como <b>reset de senha</b>, <b>cadastro de usu
|
|
172
180
|
|
173
181
|
|
174
182
|
```ruby
|
175
|
-
Keycloak::Client.logout(redirect_uri = '', refresh_token = '')
|
183
|
+
Keycloak::Client.logout(redirect_uri = '', refresh_token = '', client_id = '', secret = '', end_session_endpoint = '')
|
176
184
|
```
|
177
185
|
|
178
186
|
Quando utilizado antes da expiração da sessão do usuário logado, esse método encerra a sessão. Se o parâmetro `redirect_uri` for alimentado, então o Keycloak redirecionará a sua aplicação para a url informada após a efetuação do logout. O segundo parâmetro é o `refresh_token` obtido no momento da autenticação ou da atualização da sessão. Caso este último não seja informado, então a gem utilizará o `refresh_token` do cookie.
|
179
187
|
|
180
188
|
|
181
189
|
```ruby
|
182
|
-
Keycloak::Client.get_userinfo(access_token = '')
|
190
|
+
Keycloak::Client.get_userinfo(access_token = '', userinfo_endpoint = '')
|
183
191
|
```
|
184
192
|
|
185
193
|
Esse método retorna informações sintéticas do usuário representado pelo `access_token` passado como parâmetro, tais como `sub` - que é o Id do usuário autenticado -, `preferred_username` - que é o nome do usuário autenticado - e `email` - que é o e-mail do usuário. Caso o parâmetro `access_token` não seja informado, então a gem obterá essa informação no cookie.
|
@@ -193,14 +201,14 @@ Retorna a <b>url</b> para acesso ao cadastro de usuários do Reino do arquivo de
|
|
193
201
|
|
194
202
|
|
195
203
|
```ruby
|
196
|
-
Keycloak::Client.has_role?(user_role, access_token = '')
|
204
|
+
Keycloak::Client.has_role?(user_role, access_token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
197
205
|
```
|
198
206
|
|
199
207
|
O método `has_role?` decodifica o JWT `access_token` e verifica se o usuário dono do token possui o <b>role</b> informado no parâmetro `user_role`. Caso o `access_token` não seja informado, então a gem utilizará o `access_token` do cookie.
|
200
208
|
|
201
209
|
|
202
210
|
```ruby
|
203
|
-
Keycloak::Client.user_signed_in?(access_token = '')
|
211
|
+
Keycloak::Client.user_signed_in?(access_token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
204
212
|
```
|
205
213
|
|
206
214
|
Esse método verifica se o `access_token` passado no parâmetro ainda está ativo. Para verificar se o usuário está ativo ou não, internamente a gem invoca o método `get_token_introspection`. Caso o `access_token` não seja informado, então a gem utilizará o `access_token` do cookie.
|
@@ -422,46 +430,46 @@ Keycloak::Admin.generic_delete(service, query_parameters = nil, body_parameter =
|
|
422
430
|
|
423
431
|
### Keycloak::Internal
|
424
432
|
|
425
|
-
O módulo `Keycloak::internal`disponibiliza métodos criados para facilitar a interação entre a aplicação e o <b>Keycloak</b>. Partindo das informações encontradas no arquivo de instalação `keycloak.json`, todos os métodos invocados serão autenticados automaticamente, utilizando as credências da aplicação (`grant_type = client_credentials`), dependendo assim dos <b>roles</b> atribuídos a mesma para que o retorno da requisição seja autorizado.
|
433
|
+
O módulo `Keycloak::internal` disponibiliza métodos criados para facilitar a interação entre a aplicação e o <b>Keycloak</b>. Partindo das informações encontradas no arquivo de instalação `keycloak.json`, todos os métodos invocados serão autenticados automaticamente, utilizando as credências da aplicação (`grant_type = client_credentials`), dependendo assim dos <b>roles</b> atribuídos a mesma para que o retorno da requisição seja autorizado.
|
426
434
|
|
427
435
|
|
428
436
|
```ruby
|
429
|
-
Keycloak::Internal.get_users(query_parameters = nil)
|
437
|
+
Keycloak::Internal.get_users(query_parameters = nil, client_id = '', secret = '')
|
430
438
|
```
|
431
439
|
|
432
440
|
`get_users` invoca o método `Keycloak::Admin.get_users` que, por sua vez, retorna uma lista de usuários, filtrada de acordo com o hash de parâmetros passado em `query_parameters`.
|
433
441
|
|
434
442
|
|
435
443
|
```ruby
|
436
|
-
Keycloak::Internal.change_password(user_id, redirect_uri = '')
|
444
|
+
Keycloak::Internal.change_password(user_id, redirect_uri = '', client_id = '', secret = '')
|
437
445
|
```
|
438
446
|
|
439
447
|
`change_password` invocará a API `PUT /admin/realms/{realm}/users/{id}/execute-actions-email` do Keycloak requisitando a action `UPDATE_PASSWORD`. Isso fará com que o Keycloak dispare um e-mail para o usuário representado pelo parâmetro `user_id`. O parâmetro `redirect_uri` é opcional. Se não for preenchido, então não haverá nenhum link para clicar após a ação de reset de senha ter sido concluída.
|
440
448
|
|
441
449
|
|
442
450
|
```ruby
|
443
|
-
Keycloak::Internal.get_user_info(user_login, whole_word = false)
|
451
|
+
Keycloak::Internal.get_user_info(user_login, whole_word = false, client_id = '', secret = ''))
|
444
452
|
```
|
445
453
|
|
446
454
|
`get_user_info`, baseado no parâmetro `user_login`, que poderá recepcionar o `username` ou o `email` do usuário, retornará uma lista (array) de [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) no caso em que o parâmetro `whole_word` for `false`, ou retornará um [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) quando o parâmetro `whole_word` for `true`. O parâmetro `whole_word` indica se o método deverá considerar usuários que tenham no `username` ou `email` parte da expressão passada no parâmetro `user_login` - para os casos de `whole_word = false` -, ou que tenha exatamente a expressão passada nesse parâmetro - para os casos de `whole_word = true`.
|
447
455
|
|
448
456
|
|
449
457
|
```ruby
|
450
|
-
Keycloak::Internal.forgot_password(user_login, redirect_uri = '')
|
458
|
+
Keycloak::Internal.forgot_password(user_login, redirect_uri = '', client_id = '', secret = '')
|
451
459
|
```
|
452
460
|
|
453
|
-
`forgot_password` invocará o método `Keycloak::Internal.change_password` após invocar o método `Keycloak::Internal.get_user_info` - passando no parâmetro `user_login` do método descrito o parâmetro `user_login`deste tópico e passando `true` no parâmetro `whole_word
|
461
|
+
`forgot_password` invocará o método `Keycloak::Internal.change_password` após invocar o método `Keycloak::Internal.get_user_info` - passando no parâmetro `user_login` do método descrito o parâmetro `user_login`deste tópico e passando `true` no parâmetro `whole_word`. A utilização deste método é indicado para os casos de aplicações permitam o reset da senha dos usuários sem que o mesmo esteja logado.
|
454
462
|
|
455
463
|
|
456
464
|
```ruby
|
457
|
-
Keycloak::Internal.exists_name_or_email(value, user_id = '')
|
465
|
+
Keycloak::Internal.exists_name_or_email(value, user_id = '', client_id = '', secret = '')
|
458
466
|
```
|
459
467
|
|
460
468
|
`exists_name_or_email` verifica se no reino já existe algum usuário com `username` ou o `email` passado no parâmetro `value`. O parâmetro `user_id` serve para passar o `ID` de um usuário nos casos em que deseja-se alterar o `username` ou o `email` do mesmo, para que assim sejam considerados na verificação do `username` e do `email` usuários diferentes do usuário com o `ID` informado em `user_id`.
|
461
469
|
|
462
470
|
|
463
471
|
```ruby
|
464
|
-
Keycloak::Internal.get_logged_user_info
|
472
|
+
Keycloak::Internal.get_logged_user_info(client_id = '', secret = '')
|
465
473
|
```
|
466
474
|
|
467
475
|
`get_logged_user_info` retorna o [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) do usuário logado na aplicação.
|
@@ -469,36 +477,36 @@ Keycloak::Internal.get_logged_user_info
|
|
469
477
|
|
470
478
|
```ruby
|
471
479
|
# GET /admin/realms/{realm}/users
|
472
|
-
Keycloak::Internal.logged_federation_user?
|
480
|
+
Keycloak::Internal.logged_federation_user?(client_id = '', secret = '')
|
473
481
|
```
|
474
482
|
|
475
|
-
`logged_federation_user?` incova o método `Keycloak::Internal.get_logged_user_info` e verifica se o mesmo é um <b>Federation User</b> (um usuário do
|
483
|
+
`logged_federation_user?` incova o método `Keycloak::Internal.get_logged_user_info` e verifica se o mesmo é um <b>Federation User</b> (um usuário do LDAP por exemplo).
|
476
484
|
|
477
485
|
|
478
486
|
```ruby
|
479
487
|
# GET /admin/realms/{realm}/users
|
480
|
-
Keycloak::Internal.create_starter_user(username, password, email, client_roles_names, proc = nil)
|
488
|
+
Keycloak::Internal.create_starter_user(username, password, email, client_roles_names, proc = nil, client_id = '', secret = '')
|
481
489
|
```
|
482
490
|
|
483
|
-
`create_starter_user` é indicado para aplicações que permitam a criação de novos usuários sem que um usuário esteja logado ou até mesmo para criar novos usuários a partir do `rake db:seed`. Nos parâmetros `username`, `password` e `email` devem ser passados o nome
|
491
|
+
`create_starter_user` é indicado para aplicações que permitam a criação de novos usuários sem que um usuário esteja logado ou até mesmo para criar novos usuários a partir do `rake db:seed`. Nos parâmetros `username`, `password` e `email` devem ser passados o nome, a senha, e o e-mail do usuário, respectivamente. No parâmetro `client_roles_names`deve ser passado uma lista (array) com o nome dos `roles` do Client que serão atribuídos ao usuário. O parâmetro `proc` trata-se de um método <b>lambda</b> que disponibilizará como parâmetro a [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) do usuário criado para que sejam definidas ações por parte da aplicação. Esse método terá como retorno o mesmo retorno do método do parâmetro `proc` se o mesmo for definido, caso contrário retornará a [UserRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_userrepresentation) do usuário criado.
|
484
492
|
|
485
493
|
|
486
494
|
```ruby
|
487
|
-
Keycloak::Internal.get_client_roles
|
495
|
+
Keycloak::Internal.get_client_roles(client_id = '', secret = '')
|
488
496
|
```
|
489
497
|
|
490
|
-
`get_client_roles` retornará uma lista (array) de [RoleRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_rolerepresentation) do Client indicado pelo arquivo de instalação `keycloak.json`.
|
498
|
+
`get_client_roles` retornará uma lista (array) de [RoleRepresentation](http://www.keycloak.org/docs-api/3.2/rest-api/index.html#_rolerepresentation) do Client indicado no parâmetro `client_id` ou, na falta desse, pelo Client do arquivo de instalação `keycloak.json`.
|
491
499
|
|
492
500
|
|
493
501
|
```ruby
|
494
|
-
Keycloak::Internal.get_client_user_roles(user_id)
|
502
|
+
Keycloak::Internal.get_client_user_roles(user_id, client_id = '', secret = '')
|
495
503
|
```
|
496
504
|
|
497
|
-
`get_client_user_roles` invocará o método `Keycloak::Admin.get_effective_client_level_role_composite_user` considerando o Client indicado pelo arquivo de instalação `keycloak.json` e o usuário representado pelo parâmetro `user_id`.
|
505
|
+
`get_client_user_roles` invocará o método `Keycloak::Admin.get_effective_client_level_role_composite_user` considerando o Client indicado no parâmetro `client_id` ou, na falta desse, pelo Client do arquivo de instalação `keycloak.json` e o usuário representado pelo parâmetro `user_id`.
|
498
506
|
|
499
507
|
|
500
508
|
```ruby
|
501
|
-
Keycloak::Internal.has_role?(user_id, user_role)
|
509
|
+
Keycloak::Internal.has_role?(user_id, user_role, client_id = '', secret = '')
|
502
510
|
```
|
503
511
|
|
504
512
|
`has_role?` informará se o usuário representado pelo parâmetro `user_id` possui o <b>role</b> com o nome representado pelo parâmetro `user_role`.
|
data/lib/keycloak.rb
CHANGED
@@ -6,33 +6,47 @@ require 'base64'
|
|
6
6
|
require 'uri'
|
7
7
|
|
8
8
|
module Keycloak
|
9
|
+
OLD_KEYCLOAK_JSON_FILE = 'keycloak.json'
|
10
|
+
KEYCLOAK_JSON_FILE = 'config/keycloak.json'
|
11
|
+
|
9
12
|
class << self
|
10
13
|
attr_accessor :proxy, :generate_request_exception, :keycloak_controller,
|
11
14
|
:proc_cookie_token, :proc_external_attributes,
|
12
15
|
:realm, :auth_server_url
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
18
|
def self.explode_exception
|
17
|
-
if Keycloak.generate_request_exception
|
18
|
-
Keycloak.generate_request_exception = true
|
19
|
-
end
|
19
|
+
Keycloak.generate_request_exception = true if Keycloak.generate_request_exception.nil?
|
20
20
|
Keycloak.generate_request_exception
|
21
21
|
end
|
22
22
|
|
23
|
+
def self.installation_file
|
24
|
+
if File.exists?(KEYCLOAK_JSON_FILE)
|
25
|
+
@installation_file ||= KEYCLOAK_JSON_FILE
|
26
|
+
else
|
27
|
+
@installation_file ||= OLD_KEYCLOAK_JSON_FILE
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.installation_file=(file = nil)
|
32
|
+
raise InstallationFileNotFound unless file.instance_of?(String) && File.exists?(file)
|
33
|
+
@installation_file = file || KEYCLOAK_JSON_FILE
|
34
|
+
end
|
35
|
+
|
23
36
|
module Client
|
24
37
|
class << self
|
25
38
|
attr_accessor :realm, :auth_server_url
|
26
39
|
attr_reader :client_id, :secret, :configuration, :public_key
|
27
40
|
end
|
28
41
|
|
29
|
-
|
30
|
-
|
31
|
-
def self.get_token(user, password)
|
42
|
+
def self.get_token(user, password, client_id = '', secret = '')
|
32
43
|
setup_module
|
33
44
|
|
34
|
-
|
35
|
-
|
45
|
+
client_id = @client_id if client_id.blank?
|
46
|
+
secret = @secret if secret.blank?
|
47
|
+
|
48
|
+
payload = { 'client_id' => client_id,
|
49
|
+
'client_secret' => secret,
|
36
50
|
'username' => user,
|
37
51
|
'password' => password,
|
38
52
|
'grant_type' => 'password' }
|
@@ -40,11 +54,14 @@ module Keycloak
|
|
40
54
|
mount_request_token(payload)
|
41
55
|
end
|
42
56
|
|
43
|
-
def self.get_token_by_code(code, redirect_uri)
|
57
|
+
def self.get_token_by_code(code, redirect_uri, client_id = '', secret = '')
|
44
58
|
verify_setup
|
45
59
|
|
46
|
-
|
47
|
-
|
60
|
+
client_id = @client_id if client_id.blank?
|
61
|
+
secret = @secret if secret.blank?
|
62
|
+
|
63
|
+
payload = { 'client_id' => client_id,
|
64
|
+
'client_secret' => secret,
|
48
65
|
'code' => code,
|
49
66
|
'grant_type' => 'authorization_code',
|
50
67
|
'redirect_uri' => redirect_uri }
|
@@ -52,48 +69,55 @@ module Keycloak
|
|
52
69
|
mount_request_token(payload)
|
53
70
|
end
|
54
71
|
|
55
|
-
def self.get_token_by_exchange(issuer, issuer_token)
|
56
|
-
setup_module
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
# response.
|
67
|
-
#
|
68
|
-
response.body
|
69
|
-
|
72
|
+
def self.get_token_by_exchange(issuer, issuer_token, client_id = '', secret = '', token_endpoint = '')
|
73
|
+
setup_module
|
74
|
+
|
75
|
+
client_id = @client_id if client_id.blank?
|
76
|
+
secret = @secret if secret.blank?
|
77
|
+
token_endpoint = @configuration['token_endpoint'] if token_endpoint.blank?
|
78
|
+
|
79
|
+
payload = { 'client_id' => client_id, 'client_secret' => secret, 'audience' => client_id, 'grant_type' => 'urn:ietf:params:oauth:grant-type:token-exchange', 'subject_token_type' => 'urn:ietf:params:oauth:token-type:access_token', 'subject_issuer' => issuer, 'subject_token' => issuer_token }
|
80
|
+
header = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
81
|
+
_request = -> do
|
82
|
+
RestClient.post(token_endpoint, payload, header){|response, request, result|
|
83
|
+
# case response.code
|
84
|
+
# when 200
|
85
|
+
# response.body
|
86
|
+
# else
|
87
|
+
# response.return!
|
88
|
+
# end
|
89
|
+
response.body
|
90
|
+
}
|
70
91
|
end
|
71
|
-
|
72
|
-
exec_request _request
|
92
|
+
exec_request _request
|
73
93
|
end
|
74
94
|
|
75
|
-
def self.get_userinfo_issuer(access_token = '')
|
95
|
+
def self.get_userinfo_issuer(access_token = '', userinfo_endpoint = '')
|
76
96
|
verify_setup
|
77
|
-
|
97
|
+
|
98
|
+
userinfo_endpoint = @configuration['userinfo_endpoint'] if userinfo_endpoint.blank?
|
99
|
+
|
78
100
|
access_token = self.token["access_token"] if access_token.empty?
|
79
101
|
payload = { 'access_token' => access_token }
|
80
102
|
header = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
81
103
|
_request = -> do
|
82
|
-
RestClient.post(
|
83
|
-
response.body
|
84
|
-
}
|
104
|
+
RestClient.post(userinfo_endpoint, payload, header){ |response, request, result|
|
105
|
+
response.body
|
106
|
+
}
|
85
107
|
end
|
86
|
-
|
87
|
-
exec_request _request
|
108
|
+
|
109
|
+
exec_request _request
|
88
110
|
end
|
89
111
|
|
90
|
-
def self.get_token_by_refresh_token(refresh_token = '')
|
112
|
+
def self.get_token_by_refresh_token(refresh_token = '', client_id = '', secret = '')
|
91
113
|
verify_setup
|
92
114
|
|
115
|
+
client_id = @client_id if client_id.blank?
|
116
|
+
secret = @secret if secret.blank?
|
93
117
|
refresh_token = self.token['refresh_token'] if refresh_token.empty?
|
94
118
|
|
95
|
-
payload = { 'client_id' =>
|
96
|
-
'client_secret' =>
|
119
|
+
payload = { 'client_id' => client_id,
|
120
|
+
'client_secret' => secret,
|
97
121
|
'refresh_token' => refresh_token,
|
98
122
|
'grant_type' => 'refresh_token' }
|
99
123
|
|
@@ -103,8 +127,8 @@ module Keycloak
|
|
103
127
|
def self.get_token_by_client_credentials(client_id = '', secret = '')
|
104
128
|
setup_module
|
105
129
|
|
106
|
-
client_id = @client_id if client_id.
|
107
|
-
secret = @secret if secret.
|
130
|
+
client_id = @client_id if client_id.blank?
|
131
|
+
secret = @secret if secret.blank?
|
108
132
|
|
109
133
|
payload = { 'client_id' => client_id,
|
110
134
|
'client_secret' => secret,
|
@@ -113,23 +137,24 @@ module Keycloak
|
|
113
137
|
mount_request_token(payload)
|
114
138
|
end
|
115
139
|
|
116
|
-
def self.get_token_introspection(token = '', client_id = '', secret = '')
|
140
|
+
def self.get_token_introspection(token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
117
141
|
verify_setup
|
118
142
|
|
119
|
-
|
120
|
-
|
143
|
+
client_id = @client_id if client_id.blank?
|
144
|
+
secret = @secret if secret.blank?
|
145
|
+
token = self.token["access_token"] if token.blank?
|
146
|
+
token_introspection_endpoint = @configuration['token_introspection_endpoint'] if token_introspection_endpoint.blank?
|
121
147
|
|
122
|
-
|
123
|
-
secret = @secret if secret.empty?
|
148
|
+
payload = { 'token' => token }
|
124
149
|
|
125
150
|
authorization = Base64.strict_encode64("#{client_id}:#{secret}")
|
126
151
|
authorization = "Basic #{authorization}"
|
127
152
|
|
128
|
-
header = {'Content-Type' => 'application/x-www-form-urlencoded',
|
129
|
-
|
153
|
+
header = { 'Content-Type' => 'application/x-www-form-urlencoded',
|
154
|
+
'authorization' => authorization }
|
130
155
|
|
131
156
|
_request = -> do
|
132
|
-
RestClient.post(
|
157
|
+
RestClient.post(token_introspection_endpoint, payload, header){|response, request, result|
|
133
158
|
case response.code
|
134
159
|
when 200..399
|
135
160
|
response.body
|
@@ -142,31 +167,36 @@ module Keycloak
|
|
142
167
|
exec_request _request
|
143
168
|
end
|
144
169
|
|
145
|
-
def self.url_login_redirect(redirect_uri, response_type = 'code')
|
170
|
+
def self.url_login_redirect(redirect_uri, response_type = 'code', client_id = '', authorization_endpoint = '')
|
146
171
|
verify_setup
|
147
172
|
|
148
|
-
|
149
|
-
|
173
|
+
client_id = @client_id if client_id.blank?
|
174
|
+
authorization_endpoint = @configuration['authorization_endpoint'] if authorization_endpoint.blank?
|
175
|
+
|
176
|
+
p = URI.encode_www_form({ response_type: response_type, client_id: client_id, redirect_uri: redirect_uri })
|
177
|
+
"#{authorization_endpoint}?#{p}"
|
150
178
|
end
|
151
179
|
|
152
|
-
def self.logout(redirect_uri = '', refresh_token = '')
|
180
|
+
def self.logout(redirect_uri = '', refresh_token = '', client_id = '', secret = '', end_session_endpoint = '')
|
153
181
|
verify_setup
|
154
182
|
|
155
183
|
if self.token || !refresh_token.empty?
|
156
184
|
|
157
185
|
refresh_token = self.token['refresh_token'] if refresh_token.empty?
|
186
|
+
client_id = @client_id if client_id.blank?
|
187
|
+
secret = @secret if secret.blank?
|
188
|
+
end_session_endpoint = @configuration['end_session_endpoint'] if end_session_endpoint.blank?
|
158
189
|
|
159
|
-
payload = { 'client_id' =>
|
160
|
-
'client_secret' =>
|
161
|
-
'refresh_token' => refresh_token
|
162
|
-
}
|
190
|
+
payload = { 'client_id' => client_id,
|
191
|
+
'client_secret' => secret,
|
192
|
+
'refresh_token' => refresh_token }
|
163
193
|
|
164
|
-
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
194
|
+
header = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
165
195
|
|
166
196
|
if redirect_uri.empty?
|
167
|
-
final_url =
|
197
|
+
final_url = end_session_endpoint
|
168
198
|
else
|
169
|
-
final_url = "#{
|
199
|
+
final_url = "#{end_session_endpoint}?#{URI.encode_www_form({ redirect_uri: redirect_uri })}"
|
170
200
|
end
|
171
201
|
|
172
202
|
_request = -> do
|
@@ -186,17 +216,18 @@ module Keycloak
|
|
186
216
|
end
|
187
217
|
end
|
188
218
|
|
189
|
-
def self.get_userinfo(access_token = '')
|
219
|
+
def self.get_userinfo(access_token = '', userinfo_endpoint = '')
|
190
220
|
verify_setup
|
191
221
|
|
192
222
|
access_token = self.token["access_token"] if access_token.empty?
|
223
|
+
userinfo_endpoint = @configuration['userinfo_endpoint'] if userinfo_endpoint.blank?
|
193
224
|
|
194
225
|
payload = { 'access_token' => access_token }
|
195
226
|
|
196
227
|
header = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
197
228
|
|
198
229
|
_request = -> do
|
199
|
-
RestClient.post(
|
230
|
+
RestClient.post(userinfo_endpoint, payload, header){ |response, request, result|
|
200
231
|
case response.code
|
201
232
|
when 200
|
202
233
|
response.body
|
@@ -215,12 +246,16 @@ module Keycloak
|
|
215
246
|
"#{@auth_server_url}/realms/#{@realm}/account"
|
216
247
|
end
|
217
248
|
|
218
|
-
def self.has_role?(user_role, access_token = '')
|
249
|
+
def self.has_role?(user_role, access_token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
219
250
|
verify_setup
|
220
251
|
|
221
|
-
if
|
252
|
+
client_id = @client_id if client_id.blank?
|
253
|
+
secret = @secret if secret.blank?
|
254
|
+
token_introspection_endpoint = @configuration['token_introspection_endpoint'] if token_introspection_endpoint.blank?
|
255
|
+
|
256
|
+
if user_signed_in?(access_token, client_id, secret, token_introspection_endpoint)
|
222
257
|
dt = decoded_access_token(access_token)[0]
|
223
|
-
dt = dt["resource_access"][
|
258
|
+
dt = dt["resource_access"][client_id]
|
224
259
|
if dt != nil
|
225
260
|
dt["roles"].each do |role|
|
226
261
|
return true if role.to_s == user_role.to_s
|
@@ -234,11 +269,15 @@ module Keycloak
|
|
234
269
|
end
|
235
270
|
end
|
236
271
|
|
237
|
-
def self.user_signed_in?(access_token = '')
|
272
|
+
def self.user_signed_in?(access_token = '', client_id = '', secret = '', token_introspection_endpoint = '')
|
238
273
|
verify_setup
|
239
274
|
|
275
|
+
client_id = @client_id if client_id.blank?
|
276
|
+
secret = @secret if secret.blank?
|
277
|
+
token_introspection_endpoint = @configuration['token_introspection_endpoint'] if token_introspection_endpoint.blank?
|
278
|
+
|
240
279
|
begin
|
241
|
-
JSON(get_token_introspection(access_token))['active'] === true
|
280
|
+
JSON(get_token_introspection(access_token, client_id, secret, token_introspection_endpoint))['active'] === true
|
242
281
|
rescue => e
|
243
282
|
if e.class < Keycloak::KeycloakException
|
244
283
|
raise
|
@@ -286,8 +325,8 @@ module Keycloak
|
|
286
325
|
KEYCLOACK_CONTROLLER_DEFAULT = 'session'
|
287
326
|
|
288
327
|
def self.get_installation
|
289
|
-
if File.exists?(
|
290
|
-
installation = JSON File.read(
|
328
|
+
if File.exists?(Keycloak.installation_file)
|
329
|
+
installation = JSON File.read(Keycloak.installation_file)
|
291
330
|
@realm = installation["realm"]
|
292
331
|
@client_id = installation["resource"]
|
293
332
|
@secret = installation["credentials"]["secret"]
|
@@ -296,7 +335,7 @@ module Keycloak
|
|
296
335
|
openid_configuration
|
297
336
|
else
|
298
337
|
if Keycloak.realm.blank? || Keycloak.auth_server_url.blank?
|
299
|
-
raise "#{
|
338
|
+
raise "#{Keycloak.installation_file} and relm settings not found."
|
300
339
|
else
|
301
340
|
@realm = Keycloak.realm
|
302
341
|
@auth_server_url = Keycloak.auth_server_url
|
@@ -328,7 +367,7 @@ module Keycloak
|
|
328
367
|
end
|
329
368
|
|
330
369
|
def self.openid_configuration
|
331
|
-
RestClient.proxy = Keycloak.proxy
|
370
|
+
RestClient.proxy = Keycloak.proxy if Keycloak.proxy.present?
|
332
371
|
config_url = "#{@auth_server_url}/realms/#{@realm}/.well-known/openid-configuration"
|
333
372
|
_request = -> do
|
334
373
|
RestClient.get config_url
|
@@ -398,16 +437,12 @@ module Keycloak
|
|
398
437
|
end
|
399
438
|
|
400
439
|
def self.revoke_consent_user(id, client_id = nil, access_token = nil)
|
401
|
-
if client_id.
|
402
|
-
client_id = Keycloak::Client.client_id
|
403
|
-
end
|
440
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
404
441
|
generic_delete("users/#{id}/consents/#{client_id}", nil, nil, access_token)
|
405
442
|
end
|
406
443
|
|
407
444
|
def self.update_account_email(id, actions, redirect_uri = '', client_id = nil, access_token = nil)
|
408
|
-
if client_id.
|
409
|
-
client_id = Keycloak::Client.client_id
|
410
|
-
end
|
445
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
411
446
|
generic_put("users/#{id}/execute-actions-email", {:redirect_uri => redirect_uri, :client_id => client_id}, actions, access_token)
|
412
447
|
end
|
413
448
|
|
@@ -529,7 +564,6 @@ module Keycloak
|
|
529
564
|
def self.full_url(service)
|
530
565
|
base_url + service
|
531
566
|
end
|
532
|
-
|
533
567
|
end
|
534
568
|
|
535
569
|
module Internal
|
@@ -538,32 +572,44 @@ module Keycloak
|
|
538
572
|
class << self
|
539
573
|
end
|
540
574
|
|
541
|
-
def self.get_users(query_parameters = nil)
|
575
|
+
def self.get_users(query_parameters = nil, client_id = '', secret = '')
|
576
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
577
|
+
secret = Keycloak::Client.secret if secret.blank?
|
578
|
+
|
542
579
|
proc = lambda {|token|
|
543
580
|
Keycloak::Admin.get_users(query_parameters, token["access_token"])
|
544
581
|
}
|
545
582
|
|
546
|
-
default_call(proc)
|
583
|
+
default_call(proc, client_id, secret)
|
547
584
|
end
|
548
585
|
|
549
|
-
def self.change_password(user_id, redirect_uri = '')
|
586
|
+
def self.change_password(user_id, redirect_uri = '', client_id = '', secret = '')
|
587
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
588
|
+
secret = Keycloak::Client.secret if secret.blank?
|
589
|
+
|
550
590
|
proc = lambda {|token|
|
551
591
|
Keycloak.generic_request(token["access_token"],
|
552
592
|
Keycloak::Admin.full_url("users/#{user_id}/execute-actions-email"),
|
553
|
-
{:redirect_uri => redirect_uri, :client_id =>
|
593
|
+
{:redirect_uri => redirect_uri, :client_id => client_id},
|
554
594
|
['UPDATE_PASSWORD'],
|
555
595
|
'PUT')
|
556
596
|
}
|
557
597
|
|
558
|
-
default_call(proc)
|
598
|
+
default_call(proc, client_id, secret)
|
559
599
|
end
|
560
600
|
|
561
|
-
def self.forgot_password(user_login, redirect_uri = '')
|
562
|
-
|
563
|
-
|
601
|
+
def self.forgot_password(user_login, redirect_uri = '', client_id = '', secret = '')
|
602
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
603
|
+
secret = Keycloak::Client.secret if secret.blank?
|
604
|
+
|
605
|
+
user = get_user_info(user_login, true, client_id, secret)
|
606
|
+
change_password(user['id'], redirect_uri, client_id, secret)
|
564
607
|
end
|
565
608
|
|
566
|
-
def self.get_logged_user_info
|
609
|
+
def self.get_logged_user_info(client_id = '', secret = '')
|
610
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
611
|
+
secret = Keycloak::Client.secret if secret.blank?
|
612
|
+
|
567
613
|
proc = lambda {|token|
|
568
614
|
userinfo = JSON Keycloak::Client.get_userinfo
|
569
615
|
Keycloak.generic_request(token["access_token"],
|
@@ -571,10 +617,13 @@ module Keycloak
|
|
571
617
|
nil, nil, 'GET')
|
572
618
|
}
|
573
619
|
|
574
|
-
default_call(proc)
|
620
|
+
default_call(proc, client_id, secret)
|
575
621
|
end
|
576
622
|
|
577
|
-
def self.get_user_info(user_login, whole_word = false)
|
623
|
+
def self.get_user_info(user_login, whole_word = false, client_id = '', secret = '')
|
624
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
625
|
+
secret = Keycloak::Client.secret if secret.blank?
|
626
|
+
|
578
627
|
proc = lambda { |token|
|
579
628
|
if user_login.index('@').nil?
|
580
629
|
search = {:username => user_login}
|
@@ -610,12 +659,15 @@ module Keycloak
|
|
610
659
|
end
|
611
660
|
}
|
612
661
|
|
613
|
-
default_call(proc)
|
662
|
+
default_call(proc, client_id, secret)
|
614
663
|
end
|
615
664
|
|
616
|
-
def self.exists_name_or_email(value, user_id = '')
|
665
|
+
def self.exists_name_or_email(value, user_id = '', client_id = '', secret = '')
|
666
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
667
|
+
secret = Keycloak::Client.secret if secret.blank?
|
668
|
+
|
617
669
|
begin
|
618
|
-
usuario = Keycloak::Internal.get_user_info(value, true)
|
670
|
+
usuario = Keycloak::Internal.get_user_info(value, true, client_id, secret)
|
619
671
|
if user_id.empty? || user_id != usuario['id']
|
620
672
|
usuario.present?
|
621
673
|
else
|
@@ -626,15 +678,20 @@ module Keycloak
|
|
626
678
|
end
|
627
679
|
end
|
628
680
|
|
629
|
-
def self.logged_federation_user?
|
630
|
-
|
681
|
+
def self.logged_federation_user?(client_id = '', secret = '')
|
682
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
683
|
+
secret = Keycloak::Client.secret if secret.blank?
|
684
|
+
info = get_logged_user_info(client_id, secret)
|
631
685
|
info['federationLink'] != nil
|
632
686
|
end
|
633
687
|
|
634
|
-
def self.create_simple_user(username, password, email, first_name, last_name, realm_roles_names, client_roles_names, proc = nil)
|
688
|
+
def self.create_simple_user(username, password, email, first_name, last_name, realm_roles_names, client_roles_names, proc = nil, client_id = '', secret = '')
|
689
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
690
|
+
secret = Keycloak::Client.secret if secret.blank?
|
691
|
+
|
635
692
|
begin
|
636
693
|
username.downcase!
|
637
|
-
user = get_user_info(username, true)
|
694
|
+
user = get_user_info(username, true, client_id, secret)
|
638
695
|
newUser = false
|
639
696
|
rescue Keycloak::UserLoginNotFound
|
640
697
|
newUser = true
|
@@ -653,7 +710,7 @@ module Keycloak
|
|
653
710
|
Keycloak::Admin.full_url("users/"),
|
654
711
|
nil, user_representation, 'POST')
|
655
712
|
|
656
|
-
user = get_user_info(username, true) if newUser
|
713
|
+
user = get_user_info(username, true, client_id, secret) if newUser
|
657
714
|
|
658
715
|
credential_representation = { type: "password",
|
659
716
|
temporary: false,
|
@@ -665,7 +722,7 @@ module Keycloak
|
|
665
722
|
|
666
723
|
client = JSON Keycloak.generic_request(token["access_token"],
|
667
724
|
Keycloak::Admin.full_url("clients/"),
|
668
|
-
{ clientId:
|
725
|
+
{ clientId: client_id }, nil, 'GET')
|
669
726
|
|
670
727
|
if client_roles_names.count > 0
|
671
728
|
roles = []
|
@@ -708,38 +765,49 @@ module Keycloak
|
|
708
765
|
end
|
709
766
|
}
|
710
767
|
|
711
|
-
if default_call(proc_default)
|
768
|
+
if default_call(proc_default, client_id, secret)
|
712
769
|
proc.call user unless proc.nil?
|
713
770
|
end
|
714
771
|
end
|
715
772
|
|
716
|
-
def self.create_starter_user(username, password, email, client_roles_names, proc = nil)
|
717
|
-
Keycloak::
|
773
|
+
def self.create_starter_user(username, password, email, client_roles_names, proc = nil, client_id = '', secret = '')
|
774
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
775
|
+
secret = Keycloak::Client.secret if secret.blank?
|
776
|
+
Keycloak::Internal.create_simple_user(username, password, email, '', '', [], client_roles_names, proc, client_id, secret)
|
718
777
|
end
|
719
778
|
|
720
|
-
def self.get_client_roles
|
779
|
+
def self.get_client_roles(client_id = '', secret = '')
|
780
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
781
|
+
secret = Keycloak::Client.secret if secret.blank?
|
782
|
+
|
721
783
|
proc = lambda {|token|
|
722
|
-
client = JSON Keycloak::Admin.get_clients({ clientId:
|
784
|
+
client = JSON Keycloak::Admin.get_clients({ clientId: client_id }, token["access_token"])
|
723
785
|
|
724
786
|
Keycloak.generic_request(token["access_token"],
|
725
787
|
Keycloak::Admin.full_url("clients/#{client[0]['id']}/roles"),
|
726
788
|
nil, nil, 'GET')
|
727
789
|
}
|
728
790
|
|
729
|
-
default_call(proc)
|
791
|
+
default_call(proc, client_id, secret)
|
730
792
|
end
|
731
793
|
|
732
|
-
def self.get_client_user_roles(user_id)
|
794
|
+
def self.get_client_user_roles(user_id, client_id = '', secret = '')
|
795
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
796
|
+
secret = Keycloak::Client.secret if secret.blank?
|
797
|
+
|
733
798
|
proc = lambda {|token|
|
734
|
-
client = JSON Keycloak::Admin.get_clients({ clientId:
|
799
|
+
client = JSON Keycloak::Admin.get_clients({ clientId: client_id }, token["access_token"])
|
735
800
|
Keycloak::Admin.get_effective_client_level_role_composite_user(user_id, client[0]['id'], token["access_token"])
|
736
801
|
}
|
737
802
|
|
738
|
-
default_call(proc)
|
803
|
+
default_call(proc, client_id, secret)
|
739
804
|
end
|
740
805
|
|
741
|
-
def self.has_role?(user_id, user_role)
|
742
|
-
|
806
|
+
def self.has_role?(user_id, user_role, client_id = '', secret = '')
|
807
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
808
|
+
secret = Keycloak::Client.secret if secret.blank?
|
809
|
+
|
810
|
+
roles = JSON get_client_user_roles(user_id, client_id, secret)
|
743
811
|
if !roles.nil?
|
744
812
|
roles.each do |role|
|
745
813
|
return true if role['name'].to_s == user_role.to_s
|
@@ -752,15 +820,17 @@ module Keycloak
|
|
752
820
|
|
753
821
|
protected
|
754
822
|
|
755
|
-
def self.default_call(proc)
|
823
|
+
def self.default_call(proc, client_id = '', secret = '')
|
824
|
+
client_id = Keycloak::Client.client_id if client_id.blank?
|
825
|
+
secret = Keycloak::Client.secret if secret.blank?
|
756
826
|
begin
|
757
827
|
tk = nil
|
758
828
|
resp = nil
|
759
829
|
|
760
830
|
Keycloak::Client.get_installation
|
761
831
|
|
762
|
-
payload = { 'client_id' =>
|
763
|
-
'client_secret' =>
|
832
|
+
payload = { 'client_id' => client_id,
|
833
|
+
'client_secret' => secret,
|
764
834
|
'grant_type' => 'client_credentials' }
|
765
835
|
|
766
836
|
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
@@ -780,8 +850,8 @@ module Keycloak
|
|
780
850
|
Keycloak::Client.exec_request _request
|
781
851
|
ensure
|
782
852
|
if tk
|
783
|
-
payload = { 'client_id' =>
|
784
|
-
'client_secret' =>
|
853
|
+
payload = { 'client_id' => client_id,
|
854
|
+
'client_secret' => secret,
|
785
855
|
'refresh_token' => tk["refresh_token"] }
|
786
856
|
|
787
857
|
header = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
data/lib/keycloak/exceptions.rb
CHANGED
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: 2.
|
4
|
+
version: 2.4.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: 2018-
|
11
|
+
date: 2018-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -140,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
140
|
version: '0'
|
141
141
|
requirements: []
|
142
142
|
rubyforge_project:
|
143
|
-
rubygems_version: 2.7.
|
143
|
+
rubygems_version: 2.7.7
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
146
|
summary: Add authentication to applications and secure services with Keycloak
|