keycloak_ruby 0.1.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 +7 -0
- data/.rspec_status +68 -0
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE +674 -0
- data/README.md +157 -0
- data/Rakefile +14 -0
- data/lib/assets/.keep +0 -0
- data/lib/generators/keycloak_ruby/install_generator.rb +47 -0
- data/lib/keycloak_ruby/authentication.rb +25 -0
- data/lib/keycloak_ruby/client.rb +249 -0
- data/lib/keycloak_ruby/config.rb +118 -0
- data/lib/keycloak_ruby/errors.rb +73 -0
- data/lib/keycloak_ruby/request_params.rb +16 -0
- data/lib/keycloak_ruby/request_performer.rb +65 -0
- data/lib/keycloak_ruby/response_validator.rb +115 -0
- data/lib/keycloak_ruby/testing/keycloak_helpers.rb +125 -0
- data/lib/keycloak_ruby/testing.rb +13 -0
- data/lib/keycloak_ruby/token_refresher.rb +103 -0
- data/lib/keycloak_ruby/token_service.rb +108 -0
- data/lib/keycloak_ruby/user.rb +55 -0
- data/lib/keycloak_ruby/version.rb +62 -0
- data/lib/keycloak_ruby.rb +65 -0
- data/lib/templates/omniauth.rb +29 -0
- data/sig/keycloak_ruby.rbs +656 -0
- metadata +129 -0
@@ -0,0 +1,656 @@
|
|
1
|
+
# Module for interacting with Keycloak
|
2
|
+
module KeycloakRuby
|
3
|
+
self.@config: untyped
|
4
|
+
|
5
|
+
# Returns the singleton configuration object. The configuration is
|
6
|
+
# initialized on first access and validated immediately.
|
7
|
+
#
|
8
|
+
# @return [KeycloakRuby::Config] the configuration object
|
9
|
+
def self.config: () -> untyped
|
10
|
+
|
11
|
+
# Yields the configuration object for block-based configuration.
|
12
|
+
# Validates the configuration after the block executes.
|
13
|
+
#
|
14
|
+
# @yield [KeycloakRuby::Config] the configuration object
|
15
|
+
# @raise [ConfigurationError] if configuration is invalid
|
16
|
+
def self.configure: () { (untyped) -> untyped } -> untyped
|
17
|
+
|
18
|
+
VERSION: untyped
|
19
|
+
end
|
20
|
+
|
21
|
+
# lib/keycloak_ruby/user.rb
|
22
|
+
module KeycloakRuby
|
23
|
+
# User-related operations for interacting with Keycloak.
|
24
|
+
# This class provides a simple interface for creating, deleting, and finding users in Keycloak.
|
25
|
+
class User
|
26
|
+
self.@client: untyped
|
27
|
+
|
28
|
+
# Creates a new user in Keycloak.
|
29
|
+
#
|
30
|
+
# @param user_attrs [Hash] A hash of user attributes (e.g., :username, :email, :password, :temporary).
|
31
|
+
# @return [Hash] The created user's data.
|
32
|
+
# @raise [KeycloakRuby::Error] If the user creation fails.
|
33
|
+
def self.create: (?::Hash[untyped, untyped] user_attrs) -> untyped
|
34
|
+
|
35
|
+
# Deletes users from Keycloak based on a search string.
|
36
|
+
#
|
37
|
+
# @param search_string [String] A string to search for users (e.g., username, email, etc.).
|
38
|
+
# @return [void]
|
39
|
+
# @raise [KeycloakRuby::Error] If any user deletion fails.
|
40
|
+
def self.delete: (untyped search_string) -> untyped
|
41
|
+
|
42
|
+
# Deletes a user from Keycloak by ID.
|
43
|
+
#
|
44
|
+
# @param user_id [String] The ID of the user to delete.
|
45
|
+
# @return [void]
|
46
|
+
# @raise [KeycloakRuby::Error] If the deletion fails.
|
47
|
+
def self.delete_by_id: (untyped user_id) -> untyped
|
48
|
+
|
49
|
+
# Finds users in Keycloak based on a search string.
|
50
|
+
#
|
51
|
+
# @param search_string [String] A string to search for users (e.g., username, email, etc.).
|
52
|
+
# @return [Array<Hash>] An array of user objects (hashes) matching the search criteria.
|
53
|
+
# @raise [KeycloakRuby::Error] If the search fails.
|
54
|
+
def self.find: (untyped search_string) -> untyped
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Provides a singleton instance of the KeycloakRuby::Client.
|
59
|
+
#
|
60
|
+
# @return [KeycloakRuby::Client] The client instance used for making API requests.
|
61
|
+
def self.client: () -> untyped
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module KeycloakRuby
|
66
|
+
# Responsible for performing HTTP requests with HTTParty
|
67
|
+
# and validating the response. This class helps to reduce
|
68
|
+
# FeatureEnvy and keep the Client code cleaner.
|
69
|
+
# :reek:FeatureEnvy
|
70
|
+
class RequestPerformer
|
71
|
+
@config: untyped
|
72
|
+
|
73
|
+
def initialize: (untyped config) -> void
|
74
|
+
|
75
|
+
# Executes an HTTP request and verifies the response code.
|
76
|
+
#
|
77
|
+
# @param request_params [KeycloakRuby::RequestParams] - an object containing
|
78
|
+
# :http_method, :url, :headers, :body, :success_codes, :error_class, :error_message
|
79
|
+
#
|
80
|
+
# @return [HTTParty::Response] The HTTParty response object on success.
|
81
|
+
# @raise [request_params.error_class] If the response code is not in success_codes
|
82
|
+
# or HTTParty raises an error.
|
83
|
+
def call: (untyped request_params) -> untyped
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Safe validation: returns true/false
|
88
|
+
def verify_response: (untyped response, untyped request_params) -> untyped
|
89
|
+
|
90
|
+
# Bang version that raises an error on invalid response
|
91
|
+
def verify_response!: (untyped response, untyped request_params) -> (nil | untyped)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# keycloak_ruby/testing/keycloak_helpers.rb
|
96
|
+
# :reek:UtilityFunction :reek:ControlParameter :reek:ManualDispatch :reek:BooleanParameter :reek:LongParameterList
|
97
|
+
module KeycloakRuby
|
98
|
+
module Testing
|
99
|
+
# Helper module for tests with Keycloak
|
100
|
+
module KeycloakHelpers
|
101
|
+
self.@keycloak_users: untyped
|
102
|
+
|
103
|
+
# Combines both sign-in approaches with automatic detection of test type
|
104
|
+
def sign_in: (untyped user, ?test_type: untyped) -> untyped
|
105
|
+
|
106
|
+
# Мокирует авторизацию в request-тестах, подставляя указанного пользователя в current_user.
|
107
|
+
# Нужно, так как в request-тестах нет прямого доступа к сессиям и внешним сервисам авторизации.
|
108
|
+
def mock_token_service: (untyped user) -> untyped
|
109
|
+
|
110
|
+
def create_keycloak_user: (username: untyped, email: untyped, password: untyped, temporary: untyped) -> untyped
|
111
|
+
|
112
|
+
# Delete all users from Keycloak
|
113
|
+
def self.delete_all_keycloak_users: () -> untyped
|
114
|
+
|
115
|
+
def self.track_keycloak_user: (untyped user_id) -> untyped
|
116
|
+
|
117
|
+
def self.cleanup_keycloak_users: () -> (nil | untyped)
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def mock_keycloak_login: (untyped user, ?use_capybara: bool) -> untyped
|
122
|
+
|
123
|
+
def capybara_login: () -> untyped
|
124
|
+
|
125
|
+
def generate_fake_tokens: (untyped user) -> untyped
|
126
|
+
|
127
|
+
def store_session: (untyped credentials) -> untyped
|
128
|
+
|
129
|
+
def rspec_auto_detect_test_type: () -> (:request | :feature | :controller)
|
130
|
+
|
131
|
+
def auto_detect_test_type: () -> (untyped | :feature)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
module Minitest
|
137
|
+
class Test
|
138
|
+
include KeycloakRuby::Testing::KeycloakHelpers
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
module KeycloakRuby
|
143
|
+
# Validates Keycloak API responses with both safe and strict modes
|
144
|
+
#
|
145
|
+
# Provides two validation approaches:
|
146
|
+
# 1. Safe validation (#validate) - returns boolean
|
147
|
+
# 2. Strict validation (#validate!) - raises detailed exceptions
|
148
|
+
#
|
149
|
+
# @example Safe validation
|
150
|
+
# validator = ResponseValidator.new(response)
|
151
|
+
# if validator.validate
|
152
|
+
# # proceed with valid response
|
153
|
+
# else
|
154
|
+
# # handle invalid response
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# @example Strict validation
|
158
|
+
# begin
|
159
|
+
# data = ResponseValidator.new(response).validate!
|
160
|
+
# # use validated data
|
161
|
+
# rescue KeycloakRuby::Errors::TokenRefreshFailed => e
|
162
|
+
# # handle error
|
163
|
+
# end
|
164
|
+
class ResponseValidator
|
165
|
+
@response: untyped
|
166
|
+
|
167
|
+
@data: untyped
|
168
|
+
|
169
|
+
# Initialize with the HTTP response
|
170
|
+
# @param response [HTTP::Response] The raw HTTP response from Keycloak
|
171
|
+
def initialize: (untyped response) -> void
|
172
|
+
|
173
|
+
# Safe validation - returns boolean instead of raising exceptions
|
174
|
+
# @return [Boolean] true if response is valid, false otherwise
|
175
|
+
def validate: () -> (false | untyped)
|
176
|
+
|
177
|
+
# Strict validation - raises exceptions for invalid responses
|
178
|
+
# @return [Hash] Parsed response data if valid
|
179
|
+
# @raise [KeycloakRuby::Errors::TokenRefreshFailed] if validation fails
|
180
|
+
def validate!: () -> untyped
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# Parses JSON response body, returns empty hash on failure
|
185
|
+
# @return [Hash]
|
186
|
+
def parse_response_body: () -> untyped
|
187
|
+
|
188
|
+
# Checks if HTTP status indicates success
|
189
|
+
# @return [Boolean]
|
190
|
+
def valid_http_status?: () -> untyped
|
191
|
+
|
192
|
+
# Checks for OAuth2 "invalid_grant" error
|
193
|
+
# @return [Boolean]
|
194
|
+
def invalid_grant?: () -> untyped
|
195
|
+
|
196
|
+
# Checks for any error in response
|
197
|
+
# @return [Boolean]
|
198
|
+
def error_present?: () -> untyped
|
199
|
+
|
200
|
+
# Verifies access token presence
|
201
|
+
# @return [Boolean]
|
202
|
+
def access_token_present?: () -> untyped
|
203
|
+
|
204
|
+
# Raises appropriate validation error based on failure reason
|
205
|
+
# @raise [KeycloakRuby::Errors::TokenRefreshFailed]
|
206
|
+
def raise_validation_error: () -> untyped
|
207
|
+
|
208
|
+
# Extracts error message from response
|
209
|
+
# @return [String]
|
210
|
+
def extract_error_message: () -> (untyped | untyped | "See response body for details")
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# lib/keycloak_ruby/config.rb
|
215
|
+
module KeycloakRuby
|
216
|
+
# Configuration class for Keycloak Ruby gem.
|
217
|
+
#
|
218
|
+
# Handles loading and validation of Keycloak configuration from either:
|
219
|
+
# - A YAML file (default: config/keycloak.yml)
|
220
|
+
# - Direct attribute assignment
|
221
|
+
#
|
222
|
+
# == Example YAML Configuration
|
223
|
+
#
|
224
|
+
# development:
|
225
|
+
# keycloak_url: "https://keycloak.example.com"
|
226
|
+
# app_host: "http://localhost:3000"
|
227
|
+
# realm: "my-realm"
|
228
|
+
# oauth_client_id: "my-client"
|
229
|
+
# oauth_client_secret: "secret"
|
230
|
+
#
|
231
|
+
# == Example Programmatic Configuration
|
232
|
+
#
|
233
|
+
# config = KeycloakRuby::Config.new
|
234
|
+
# config.keycloak_url = "https://keycloak.example.com"
|
235
|
+
# config.realm = "my-realm"
|
236
|
+
# # ... etc
|
237
|
+
# :reek:MissingSafeMethod
|
238
|
+
class Config
|
239
|
+
@config_path: untyped
|
240
|
+
|
241
|
+
# Default path to configuration file (Rails.root/config/keycloak.yml)
|
242
|
+
DEFAULT_CONFIG_PATH: untyped
|
243
|
+
|
244
|
+
REQUIRED_ATTRIBUTES: ::Array[:keycloak_url | :app_host | :realm | :oauth_client_id | :oauth_client_secret]
|
245
|
+
|
246
|
+
# :reek:Attribute
|
247
|
+
attr_accessor keycloak_url: untyped
|
248
|
+
|
249
|
+
# :reek:Attribute
|
250
|
+
attr_accessor app_host: untyped
|
251
|
+
|
252
|
+
# :reek:Attribute
|
253
|
+
attr_accessor realm: untyped
|
254
|
+
|
255
|
+
# :reek:Attribute
|
256
|
+
attr_accessor admin_client_id: untyped
|
257
|
+
|
258
|
+
# :reek:Attribute
|
259
|
+
attr_accessor admin_client_secret: untyped
|
260
|
+
|
261
|
+
# :reek:Attribute
|
262
|
+
attr_accessor oauth_client_id: untyped
|
263
|
+
|
264
|
+
# :reek:Attribute
|
265
|
+
attr_accessor oauth_client_secret: untyped
|
266
|
+
|
267
|
+
attr_reader config_path: untyped
|
268
|
+
|
269
|
+
# Initialize configuration, optionally loading from YAML file
|
270
|
+
#
|
271
|
+
# @param config_path [String] Path to YAML config file (default: config/keycloak.yml)
|
272
|
+
#
|
273
|
+
#
|
274
|
+
def initialize: (?untyped config_path) -> void
|
275
|
+
|
276
|
+
def validate!: () -> untyped
|
277
|
+
|
278
|
+
def realm_url: () -> ::String
|
279
|
+
|
280
|
+
def redirect_url: () -> ::String
|
281
|
+
|
282
|
+
def logout_url: () -> ::String
|
283
|
+
|
284
|
+
def token_url: () -> ::String
|
285
|
+
|
286
|
+
private
|
287
|
+
|
288
|
+
# Loads configuration from YAML file if it exists
|
289
|
+
# :reek:ManualDispatch
|
290
|
+
def load_config: () -> (nil | untyped)
|
291
|
+
|
292
|
+
def load_yaml_file: () -> untyped
|
293
|
+
|
294
|
+
def current_env: () -> untyped
|
295
|
+
|
296
|
+
def apply_config: (untyped config_hash) -> untyped
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
module KeycloakRuby
|
301
|
+
# Include test methods
|
302
|
+
module Testing
|
303
|
+
def self.included: (untyped base) -> untyped
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# lib/keycloak_ruby/request_params.rb
|
308
|
+
module KeycloakRuby
|
309
|
+
# A small, typed struct for request parameters
|
310
|
+
RequestParams: untyped
|
311
|
+
end
|
312
|
+
|
313
|
+
# lib/keycloak_ruby/errors.rb
|
314
|
+
module KeycloakRuby
|
315
|
+
# Namespace for all KeycloakRuby specific errors
|
316
|
+
# Follows a hierarchical structure for better error handling
|
317
|
+
module Errors
|
318
|
+
# Base error class for all KeycloakRuby errors
|
319
|
+
# All custom errors inherit from this class
|
320
|
+
class Error < StandardError
|
321
|
+
end
|
322
|
+
|
323
|
+
# Raised when there's an issue with gem configuration
|
324
|
+
class ConfigurationError < Error
|
325
|
+
end
|
326
|
+
|
327
|
+
# Base class for authentication failures
|
328
|
+
class AuthenticationError < Error
|
329
|
+
end
|
330
|
+
|
331
|
+
# Raised when user credentials are invalid
|
332
|
+
class InvalidCredentials < AuthenticationError
|
333
|
+
end
|
334
|
+
|
335
|
+
# Raised when user account is not found
|
336
|
+
class UserNotFound < AuthenticationError
|
337
|
+
end
|
338
|
+
|
339
|
+
# Raised when account is temporarily locked
|
340
|
+
class AccountLocked < AuthenticationError
|
341
|
+
end
|
342
|
+
|
343
|
+
# Raised when user creation fails
|
344
|
+
class UserCreationError < Error
|
345
|
+
end
|
346
|
+
|
347
|
+
# Raised when user update fails
|
348
|
+
class UserUpdateError < Error
|
349
|
+
end
|
350
|
+
|
351
|
+
# Raised when user deletion fails
|
352
|
+
class UserDeletionError < Error
|
353
|
+
end
|
354
|
+
|
355
|
+
# Base class for all token-related errors
|
356
|
+
class TokenError < Error
|
357
|
+
end
|
358
|
+
|
359
|
+
# Raised when token has expired +
|
360
|
+
class TokenExpired < TokenError
|
361
|
+
end
|
362
|
+
|
363
|
+
# Raised when token is invalid (malformed, wrong signature, etc.)
|
364
|
+
class TokenInvalid < TokenError
|
365
|
+
end
|
366
|
+
|
367
|
+
# Raised when token refresh fails
|
368
|
+
class TokenRefreshFailed < TokenError
|
369
|
+
end
|
370
|
+
|
371
|
+
# Raised when token verification fails
|
372
|
+
class TokenVerificationFailed < TokenError
|
373
|
+
end
|
374
|
+
|
375
|
+
# Raised when API request fails
|
376
|
+
class APIError < Error
|
377
|
+
end
|
378
|
+
|
379
|
+
# Raised when receiving 4xx responses from Keycloak
|
380
|
+
class ClientError < APIError
|
381
|
+
end
|
382
|
+
|
383
|
+
# Raised when receiving 5xx responses from Keycloak
|
384
|
+
class ServerError < APIError
|
385
|
+
end
|
386
|
+
|
387
|
+
# Raised when connection to Keycloak fails
|
388
|
+
class ConnectionError < APIError
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
# lib/keycloak_ruby/token_service.rb
|
394
|
+
# :reek:FeatureEnvy
|
395
|
+
module KeycloakRuby
|
396
|
+
# Service for check and refresh jwt tokens
|
397
|
+
class TokenService
|
398
|
+
@session: untyped
|
399
|
+
|
400
|
+
@config: untyped
|
401
|
+
|
402
|
+
@refresh_mutex: untyped
|
403
|
+
|
404
|
+
@fetch_jwks: untyped
|
405
|
+
|
406
|
+
@issuer_url: untyped
|
407
|
+
|
408
|
+
def initialize: (untyped session, ?untyped config) -> void
|
409
|
+
|
410
|
+
# Finds user by token claims
|
411
|
+
# @return [User, nil]
|
412
|
+
def find_user: () -> (nil | untyped)
|
413
|
+
|
414
|
+
# Store token
|
415
|
+
def store_tokens: (untyped data) -> untyped
|
416
|
+
|
417
|
+
def clear_tokens: () -> untyped
|
418
|
+
|
419
|
+
private
|
420
|
+
|
421
|
+
# It's necessary, because omniauth return request.env["omniauth.auth"] as 'token', not 'access_token'
|
422
|
+
def extract_access_token: (untyped data) -> untyped
|
423
|
+
|
424
|
+
# Gets current token or attempts refresh if expired
|
425
|
+
# @return [Hash, nil] Decoded token claims
|
426
|
+
def current_token: () -> untyped
|
427
|
+
|
428
|
+
# Decodes JWT token
|
429
|
+
# @raise [Errors::TokenExpired, Errors::TokenInvalid]
|
430
|
+
def decode_token: (untyped token) -> untyped
|
431
|
+
|
432
|
+
def fetch_jwks: () -> untyped
|
433
|
+
|
434
|
+
# Attempts to refresh the current token
|
435
|
+
def refresh_current_token: () -> untyped
|
436
|
+
|
437
|
+
# JWT decoding options with JWKS
|
438
|
+
def jwt_decode_options: () -> { algorithms: ::Array["RS256"], verify_iss: true, iss: untyped, aud: untyped, verify_expiration: true, jwks: untyped }
|
439
|
+
|
440
|
+
# Constructs issuer URL from configuration
|
441
|
+
def issuer_url: () -> untyped
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
# lib/keycloak_ruby/token_refresher.rb`
|
446
|
+
module KeycloakRuby
|
447
|
+
# Handles OAuth2 refresh token flow with Keycloak
|
448
|
+
#
|
449
|
+
# Responsible for:
|
450
|
+
# - Executing refresh token requests
|
451
|
+
# - Validating responses
|
452
|
+
# - Managing refresh failures
|
453
|
+
#
|
454
|
+
# @example Basic usage
|
455
|
+
# refresher = TokenRefresher.new(session, config)
|
456
|
+
# new_tokens = refresher.call
|
457
|
+
#
|
458
|
+
# @example With error handling
|
459
|
+
# begin
|
460
|
+
# refresher.call
|
461
|
+
# rescue KeycloakRuby::Errors::TokenRefreshFailed => e
|
462
|
+
# # Handle token refresh failure (e.g., redirect to login)
|
463
|
+
# end
|
464
|
+
class TokenRefresher
|
465
|
+
@session: untyped
|
466
|
+
|
467
|
+
@config: untyped
|
468
|
+
|
469
|
+
def initialize: (untyped session, untyped config) -> void
|
470
|
+
|
471
|
+
# Main entry point - refreshes the token
|
472
|
+
# @return [Hash] New token data if successful
|
473
|
+
# @raise [KeycloakRuby::Errors::TokenRefreshFailed] if refresh fails
|
474
|
+
def call: () -> untyped
|
475
|
+
|
476
|
+
private
|
477
|
+
|
478
|
+
def refresh_token_flow: () -> untyped
|
479
|
+
|
480
|
+
def request_refresh: () -> untyped
|
481
|
+
|
482
|
+
def validate_response: (untyped response) -> untyped
|
483
|
+
|
484
|
+
def handle_http_error: (untyped exception) -> untyped
|
485
|
+
|
486
|
+
# :reek:FeatureEnvy
|
487
|
+
def handle_failed_validation: (untyped response) -> untyped
|
488
|
+
|
489
|
+
def refresh_params: () -> { grant_type: "refresh_token", client_id: untyped, client_secret: untyped, refresh_token: untyped }
|
490
|
+
|
491
|
+
def headers: () -> { "Content-Type" => "application/x-www-form-urlencoded", "Accept" => "application/json", "User-Agent" => ::String }
|
492
|
+
|
493
|
+
def log_refresh_attempt: () -> untyped
|
494
|
+
|
495
|
+
def log_successful_refresh: () -> untyped
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
# lib/keycloak_ruby/client.rb
|
500
|
+
module KeycloakRuby
|
501
|
+
# Client for interacting with Keycloak (create, delete, and find users, etc.).
|
502
|
+
# rubocop:disable Metrics/ClassLength
|
503
|
+
# rubocop:disable Metrics/MethodLength
|
504
|
+
# :reek:TooManyMethods
|
505
|
+
class Client
|
506
|
+
@config: untyped
|
507
|
+
|
508
|
+
@request_performer: untyped
|
509
|
+
|
510
|
+
def initialize: (?untyped config) -> void
|
511
|
+
|
512
|
+
# Authenticates a user with Keycloak and returns token data upon success.
|
513
|
+
#
|
514
|
+
# @param username [String] The user's username or email.
|
515
|
+
# @param password [String] The user's password.
|
516
|
+
# @return [Hash] The token data (access_token, refresh_token, id_token, etc.).
|
517
|
+
# @raise [KeycloakRuby::Errors::InvalidCredentials] If authentication fails.
|
518
|
+
def authenticate_user: (username: untyped, password: untyped) -> untyped
|
519
|
+
|
520
|
+
# Creates a user in Keycloak and returns the newly created user's data.
|
521
|
+
#
|
522
|
+
# @param user_attrs [Hash] A hash of user attributes. Must contain:
|
523
|
+
# :username, :email, :password, :temporary
|
524
|
+
# @option user_attrs [String] :username The username for the new user.
|
525
|
+
# @option user_attrs [String] :email The user's email.
|
526
|
+
# @option user_attrs [String] :password The initial password.
|
527
|
+
# @option user_attrs [Boolean] :temporary Whether to force a password update on first login.
|
528
|
+
#
|
529
|
+
# @raise [KeycloakRuby::Errors::UserCreationError] If user creation fails.
|
530
|
+
# @return [Hash] The newly created user's data.
|
531
|
+
def create_user: (?::Hash[untyped, untyped] user_attrs) -> untyped
|
532
|
+
|
533
|
+
# Deletes all users that match the provided search string (e.g., username, email).
|
534
|
+
#
|
535
|
+
# @param search_string [String] The search criteria for finding users in Keycloak.
|
536
|
+
# @raise [KeycloakRuby::Errors::UserDeletionError] If any user deletion fails.
|
537
|
+
def delete_users: (untyped search_string) -> untyped
|
538
|
+
|
539
|
+
# Deletes a single user by ID in Keycloak.
|
540
|
+
#
|
541
|
+
# @param user_id [String] The ID of the user to delete.
|
542
|
+
# @raise [KeycloakRuby::Errors::UserDeletionError] If the deletion fails.
|
543
|
+
def delete_user_by_id: (untyped user_id) -> untyped
|
544
|
+
|
545
|
+
# Finds all users in Keycloak that match the given search string.
|
546
|
+
#
|
547
|
+
# @param search [String] The search query (e.g., part of username or email).
|
548
|
+
# @return [Array<Hash>] An array of user objects.
|
549
|
+
# @raise [KeycloakRuby::Errors::APIError] If the request fails.
|
550
|
+
def find_users: (untyped search) -> untyped
|
551
|
+
|
552
|
+
# Updates the redirect URIs for a specific client in Keycloak.
|
553
|
+
#
|
554
|
+
# @param client_id [String] The client ID in Keycloak.
|
555
|
+
# @param redirect_uris [Array<String>] A list of valid redirect URIs for this client.
|
556
|
+
# @raise [KeycloakRuby::Errors::ConnectionError] If the update request fails.
|
557
|
+
def update_client_redirect_uris: (client_id: untyped, redirect_uris: untyped) -> untyped
|
558
|
+
|
559
|
+
private
|
560
|
+
|
561
|
+
def build_auth_body: (untyped username, untyped password) -> { client_id: untyped, client_secret: untyped, username: untyped, password: untyped, grant_type: "password" }
|
562
|
+
|
563
|
+
def build_user_data: (untyped attrs) -> { username: untyped, email: untyped, enabled: true, credentials: ::Array[{ type: "password", value: untyped, temporary: untyped }] }
|
564
|
+
|
565
|
+
# Builds RequestParams and passes them to the RequestPerformer.
|
566
|
+
def http_request: (?::Hash[untyped, untyped] options) -> untyped
|
567
|
+
|
568
|
+
def build_request_params: (untyped opts) -> untyped
|
569
|
+
|
570
|
+
# Retrieves client details by its "clientId".
|
571
|
+
#
|
572
|
+
# @param client_id [String] The "clientId" in Keycloak.
|
573
|
+
# @return [Hash] The client details.
|
574
|
+
# @raise [KeycloakRuby::Errors::ClientError] If no matching client is found or the request fails.
|
575
|
+
def find_client_by_id: (untyped client_id) -> untyped
|
576
|
+
|
577
|
+
# Performs a PUT request to update the redirect URIs for a given client in Keycloak.
|
578
|
+
#
|
579
|
+
# @param client_id [String] The internal Keycloak client ID.
|
580
|
+
# @param redirect_uris [Array<String>] List of valid redirect URIs for this client.
|
581
|
+
# @raise [KeycloakRuby::Errors::ConnectionError] If the update request fails.
|
582
|
+
def update_redirect_uris_for: (untyped client_id, untyped redirect_uris) -> untyped
|
583
|
+
|
584
|
+
# Fetches a user by ID from Keycloak.
|
585
|
+
#
|
586
|
+
# @param user_id [String] The user's ID in Keycloak.
|
587
|
+
# @return [Hash] The Keycloak user data.
|
588
|
+
# @raise [KeycloakRuby::Errors::UserNotFound] If the user cannot be found or the request fails.
|
589
|
+
def fetch_user: (untyped user_id) -> untyped
|
590
|
+
|
591
|
+
# Retrieves the admin token used to authenticate calls to the Keycloak Admin API.
|
592
|
+
#
|
593
|
+
# @return [String] The admin access token.
|
594
|
+
# @raise [KeycloakRuby::Errors::TokenVerificationFailed] If the token request fails.
|
595
|
+
def admin_token: () -> untyped
|
596
|
+
|
597
|
+
# Returns a set of default headers for requests requiring the admin token.
|
598
|
+
#
|
599
|
+
# @return [Hash] A headers Hash including Authorization and Content-Type.
|
600
|
+
def default_headers: () -> { "Authorization" => ::String, "Content-Type" => "application/json" }
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
# lib/keycloak_ruby/version.rb
|
605
|
+
# Module for interacting with Keycloak
|
606
|
+
module KeycloakRuby
|
607
|
+
# Version module following Semantic Versioning 2.0 guidelines
|
608
|
+
# Provides detailed version information and helper methods
|
609
|
+
#
|
610
|
+
# @example Getting version information
|
611
|
+
# KeycloakRuby::Version::VERSION # => "0.1.0"
|
612
|
+
# KeycloakRuby::Version.to_a # => [0, 1, 0]
|
613
|
+
# KeycloakRuby::Version.to_h # => { major: 0, minor: 1, patch: 0, pre: nil }
|
614
|
+
# KeycloakRuby.version # => "0.1.0"
|
615
|
+
#
|
616
|
+
# @example Checking version
|
617
|
+
# KeycloakRuby::Version >= '0.1.0' # => true
|
618
|
+
# Module for work with Version
|
619
|
+
module Version
|
620
|
+
# Major version number (incompatible API changes)
|
621
|
+
MAJOR: 0
|
622
|
+
|
623
|
+
# Minor version number (backwards-compatible functionality)
|
624
|
+
MINOR: 1
|
625
|
+
|
626
|
+
# Patch version number (backwards-compatible bug fixes)
|
627
|
+
PATCH: 0
|
628
|
+
|
629
|
+
# Pre-release version (nil for stable releases)
|
630
|
+
PRE: nil
|
631
|
+
|
632
|
+
# Full version string
|
633
|
+
VERSION: untyped
|
634
|
+
|
635
|
+
# Returns version components as an array
|
636
|
+
# @return [Array<Integer, Integer, Integer, String|nil>]
|
637
|
+
def self.to_a: () -> ::Array[untyped]
|
638
|
+
|
639
|
+
# Returns version components as a hash
|
640
|
+
# @return [Hash<Symbol, Integer|String|nil>]
|
641
|
+
def self.to_h: () -> { major: untyped, minor: untyped, patch: untyped, pre: untyped }
|
642
|
+
|
643
|
+
# Compares version with another version string
|
644
|
+
# @param version_string [String] version to compare with (e.g., "1.2.3")
|
645
|
+
# @return [Boolean]
|
646
|
+
def self.>=: (untyped version_string) -> untyped
|
647
|
+
|
648
|
+
# Returns the full version string
|
649
|
+
# @return [String]
|
650
|
+
def self.to_s: () -> untyped
|
651
|
+
end
|
652
|
+
|
653
|
+
# Returns the current gem version
|
654
|
+
# @return [String]
|
655
|
+
def self.version: () -> untyped
|
656
|
+
end
|