lib/keycloak.rb in keycloak-2.1.0 vs lib/keycloak.rb in keycloak-2.2.0

- old
+ new

@@ -4,762 +4,799 @@ require 'jwt' require 'base64' require 'uri' module Keycloak + class << self + attr_accessor :proxy, :generate_request_exception, :keycloak_controller, + :proc_cookie_token, :proc_external_attributes + end - class << self - attr_accessor :proxy, :generate_request_exception, :keycloak_controller, - :proc_cookie_token, :proc_external_attributes - end + def self.explode_exception + if Keycloak.generate_request_exception == nil + Keycloak.generate_request_exception = true + end + Keycloak.generate_request_exception + end - def self.explode_exception - if Keycloak.generate_request_exception == nil - Keycloak.generate_request_exception = true - end - Keycloak.generate_request_exception - end + module Client + class << self + attr_reader :realm, :url, :client_id, :auth_server_url, + :secret, :configuration, :public_key + end - module Client + KEYCLOAK_JSON_FILE = 'keycloak.json' - class << self - attr_reader :realm, :url, :client_id, :auth_server_url, - :secret, :configuration, :public_key + def self.get_token(user, password) + setup_module - end + payload = { 'client_id' => @client_id, + 'client_secret' => @secret, + 'username' => user, + 'password' => password, + 'grant_type' => 'password' } - KEYCLOAK_JSON_FILE = 'keycloak.json' + mount_request_token(payload) + end - def self.get_token(user, password) - setup_module + def self.get_token_by_code(code, redirect_uri) + verify_setup - payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'username' => user, - 'password' => password, - 'grant_type' => 'password' - } + payload = { 'client_id' => @client_id, + 'client_secret' => @secret, + 'code' => code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => redirect_uri } - mount_request_token(payload) - end + mount_request_token(payload) + end - def self.get_token_by_code(code, redirect_uri) - verify_setup + def self.get_token_by_refresh_token(refreshToken = '') + verify_setup - payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'code' => code, - 'grant_type' => 'authorization_code', - 'redirect_uri' => redirect_uri - } + refreshToken = self.token['refresh_token'] if refreshToken.empty? - mount_request_token(payload) - end + payload = { 'client_id' => @client_id, + 'client_secret' => @secret, + 'refresh_token' => refreshToken, + 'grant_type' => 'refresh_token' } - def self.get_token_by_refresh_token(refreshToken = '') - verify_setup + mount_request_token(payload) + end - refreshToken = self.token['refresh_token'] if refreshToken.empty? + def self.get_token_by_client_credentials + setup_module - payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'refresh_token' => refreshToken, - 'grant_type' => 'refresh_token' - } + payload = { 'client_id' => @client_id, + 'client_secret' => @secret, + 'grant_type' => 'client_credentials' } - mount_request_token(payload) - end + mount_request_token(payload) + end - def self.get_token_by_client_credentials - setup_module + def self.get_token_introspection(token = '') + verify_setup - payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'grant_type' => 'client_credentials' - } + token = self.token["access_token"] if token.empty? - mount_request_token(payload) - end + payload = { 'token' => token } - def self.get_token_introspection(token = '') - verify_setup + authorization = Base64.strict_encode64("#{@client_id}:#{@secret}") + authorization = "Basic #{authorization}" - token = self.token["access_token"] if token.empty? + header = {'Content-Type' => 'application/x-www-form-urlencoded', + 'authorization' => authorization} - payload = {'token' => token} + _request = -> do + RestClient.post(@configuration['token_introspection_endpoint'], payload, header){|response, request, result| + case response.code + when 200..399 + response.body - authorization = Base64.strict_encode64("#{@client_id}:#{@secret}") - authorization = "Basic #{authorization}" + else + response.return! + end + } + end - header = {'Content-Type' => 'application/x-www-form-urlencoded', - 'authorization' => authorization} + exec_request _request + end - _request = -> do - RestClient.post(@configuration['token_introspection_endpoint'], payload, header){|response, request, result| - case response.code - when 200..399 - response.body + def self.url_login_redirect(redirect_uri, response_type = 'code') + verify_setup - else - response.return! - end - } - end + p = URI.encode_www_form({ response_type: response_type, client_id: @client_id, redirect_uri: redirect_uri }) + "#{@configuration['authorization_endpoint']}?#{p}" + end - exec_request _request - end + def self.logout(redirect_uri = '', refresh_token = '') + verify_setup - def self.url_login_redirect(redirect_uri, response_type = 'code') - verify_setup + if self.token || !refresh_token.empty? - p = URI.encode_www_form({:response_type => response_type, :client_id => @client_id, :redirect_uri => redirect_uri}) - "#{@configuration['authorization_endpoint']}?#{p}" - end + refresh_token = self.token['refresh_token'] if refresh_token.empty? - def self.logout(redirect_uri = '', refresh_token = '') - verify_setup + payload = { 'client_id' => @client_id, + 'client_secret' => @secret, + 'refresh_token' => refresh_token + } - if self.token || !refresh_token.empty? + header = {'Content-Type' => 'application/x-www-form-urlencoded'} - refresh_token = self.token['refresh_token'] if refresh_token.empty? + if redirect_uri.empty? + final_url = @configuration['end_session_endpoint'] + else + final_url = "#{@configuration['end_session_endpoint']}?#{URI.encode_www_form({ redirect_uri: redirect_uri })}" + end - payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'refresh_token' => refresh_token - } + _request = -> do + RestClient.post(final_url, payload, header){ |response, request, result| + case response.code + when 200..399 + true + else + response.return! + end + } + end - header = {'Content-Type' => 'application/x-www-form-urlencoded'} + exec_request _request + else + true + end + end - if redirect_uri.empty? - final_url = @configuration['end_session_endpoint'] - else - final_url = "#{@configuration['end_session_endpoint']}?#{URI.encode_www_form({:redirect_uri => redirect_uri})}" - end + def self.get_userinfo(accessToken = '') + verify_setup - _request = -> do - RestClient.post(final_url, payload, header){|response, request, result| - case response.code - when 200..399 - true - else - response.return! - end - } - end + accessToken = self.token["access_token"] if accessToken.empty? - exec_request _request - else - true - end - end + payload = { 'access_token' => accessToken } - def self.get_userinfo(accessToken = '') - verify_setup + header = { 'Content-Type' => 'application/x-www-form-urlencoded' } - accessToken = self.token["access_token"] if accessToken.empty? + _request = -> do + RestClient.post(@configuration['userinfo_endpoint'], payload, header){ |response, request, result| + case response.code + when 200 + response.body + else + response.return! + end + } + end - payload = {'access_token' => accessToken} + exec_request _request + end - header = {'Content-Type' => 'application/x-www-form-urlencoded'} + def self.url_user_account + verify_setup - _request = -> do - RestClient.post(@configuration['userinfo_endpoint'], payload, header){|response, request, result| - case response.code - when 200 - response.body - else - response.return! - end - } - end + "#{@url}/realms/#{@realm}/account" + end - exec_request _request - end + def self.has_role?(userRole, accessToken = '') + verify_setup - def self.url_user_account - verify_setup + if user_signed_in?(accessToken) + dt = decoded_access_token(accessToken)[0] + dt = dt["resource_access"][@client_id] + if dt != nil + dt["roles"].each do |role| + return true if role.to_s == userRole.to_s + end + false + else + false + end + else + false + end + end - "#{@url}/realms/#{@realm}/account" - end + def self.user_signed_in?(accessToken = '') + verify_setup - def self.has_role?(userRole, accessToken = '') - verify_setup + begin + JSON(get_token_introspection(accessToken))['active'] === true + rescue => e + if e.class < Keycloak::KeycloakException + raise + else + false + end + end + end - if user_signed_in?(accessToken) - dt = decoded_access_token(accessToken)[0] - dt = dt["resource_access"][@client_id] - if dt != nil - dt["roles"].each do |role| - return true if role.to_s == userRole.to_s - end - false - else - false - end - else - false - end - end + def self.get_attribute(attributeName, accessToken = '') + verify_setup - def self.user_signed_in?(accessToken = '') - verify_setup + attr = decoded_access_token(accessToken)[0] + attr[attributeName] + end - begin - JSON(get_token_introspection(accessToken))['active'] === true - rescue => e - if e.class < Keycloak::KeycloakException - raise - else - false - end - end - end + def self.token + if !Keycloak.proc_cookie_token.nil? + JSON Keycloak.proc_cookie_token.call + else + raise Keycloak::ProcCookieTokenNotDefined + end + end - def self.get_attribute(attributeName, accessToken = '') - verify_setup + def self.external_attributes + if !Keycloak.proc_external_attributes.nil? + Keycloak.proc_external_attributes.call + else + raise Keycloak::ProcExternalAttributesNotDefined + end + end - attr = decoded_access_token(accessToken)[0] - attr[attributeName] - end + private - def self.token - unless Keycloak.proc_cookie_token.nil? - JSON Keycloak.proc_cookie_token.call - else - raise Keycloak::ProcCookieTokenNotDefined - end - end + KEYCLOACK_CONTROLLER_DEFAULT = 'session' - def self.external_attributes - unless Keycloak.proc_external_attributes.nil? - Keycloak.proc_external_attributes.call - else - raise Keycloak::ProcExternalAttributesNotDefined - end - end + def self.get_installation + if File.exists?(KEYCLOAK_JSON_FILE) + installation = JSON File.read(KEYCLOAK_JSON_FILE) + @realm = installation["realm"] + @url = installation["auth-server-url"] + @client_id = installation["resource"] + @secret = installation["credentials"]["secret"] + @public_key = installation["realm-public-key"] + @auth_server_url = installation["auth-server-url"] + openid_configuration + else + raise "#{KEYCLOAK_JSON_FILE} not found." + end + end - private + def self.verify_setup + get_installation if @configuration.nil? + end - KEYCLOACK_CONTROLLER_DEFAULT = 'session' + def self.setup_module + Keycloak.proxy ||= '' + Keycloak.keycloak_controller ||= KEYCLOACK_CONTROLLER_DEFAULT + get_installation + end - def self.get_installation - if File.exists?(KEYCLOAK_JSON_FILE) - installation = JSON File.read(KEYCLOAK_JSON_FILE) - @realm = installation["realm"] - @url = installation["auth-server-url"] - @client_id = installation["resource"] - @secret = installation["credentials"]["secret"] - @public_key = installation["realm-public-key"] - @auth_server_url = installation["auth-server-url"] - openid_configuration - else - raise "#{KEYCLOAK_JSON_FILE} not found." - end - end + def self.exec_request(proc_request) + if Keycloak.explode_exception + proc_request.call + else + begin + proc_request.call + rescue RestClient::ExceptionWithResponse => err + err.response + end + end + end - def self.verify_setup - get_installation if @configuration.nil? - end + def self.openid_configuration + RestClient.proxy = Keycloak.proxy unless Keycloak.proxy.empty? + config_url = "#{@url}/realms/#{@realm}/.well-known/openid-configuration" + _request = -> do + RestClient.get config_url + end + response = exec_request _request + if response.code == 200 + @configuration = JSON response.body + else + response.return! + end + end - def self.setup_module - Keycloak.proxy ||= '' - Keycloak.keycloak_controller ||= KEYCLOACK_CONTROLLER_DEFAULT - get_installation - end + def self.mount_request_token(payload) + header = {'Content-Type' => 'application/x-www-form-urlencoded'} - def self.exec_request(proc_request) - if Keycloak.explode_exception - proc_request.call - else - begin - proc_request.call - rescue RestClient::ExceptionWithResponse => err - err.response - end - end - end + _request = -> do + RestClient.post(@configuration['token_endpoint'], payload, header){|response, request, result| + case response.code + when 200 + response.body + else + response.return! + end + } + end - def self.openid_configuration - RestClient.proxy = Keycloak.proxy unless Keycloak.proxy.empty? - configUrl = "#{@url}/realms/#{@realm}/.well-known/openid-configuration" - _request = -> do - RestClient.get configUrl - end - response = exec_request _request - if response.code == 200 - @configuration = JSON response.body - else - response.return! - end - end + exec_request _request + end - def self.mount_request_token(payload) - header = {'Content-Type' => 'application/x-www-form-urlencoded'} + def self.decoded_access_token(accessToken = '') + accessToken = self.token["access_token"] if accessToken.empty? + JWT.decode accessToken, @public_key, false, { :algorithm => 'RS256' } + end - _request = -> do - RestClient.post(@configuration['token_endpoint'], payload, header){|response, request, result| - case response.code - when 200 - response.body - else - response.return! - end - } - end + def self.decoded_refresh_token(refreshToken = '') + refreshToken = self.token["access_token"] if refreshToken.empty? + JWT.decode refreshToken, @public_key, false, { :algorithm => 'RS256' } + end - exec_request _request - end + def self.decoded_id_token(idToken = '') + tk = self.token + idToken = tk["id_token"] if idToken.empty? + if idToken + @decoded_id_token = JWT.decode idToken, @public_key, false, { :algorithm => 'RS256' } + end + end - def self.decoded_access_token(accessToken = '') - accessToken = self.token["access_token"] if accessToken.empty? - JWT.decode accessToken, @public_key, false, { :algorithm => 'RS256' } - end + end - def self.decoded_refresh_token(refreshToken = '') - refreshToken = self.token["access_token"] if refreshToken.empty? - JWT.decode refreshToken, @public_key, false, { :algorithm => 'RS256' } - end + # Os recursos desse module (admin) serão utilizadas apenas por usuários que possuem as roles do client realm-management + module Admin + class << self + end - def self.decoded_id_token(idToken = '') - tk = self.token - idToken = tk["id_token"] if idToken.empty? - if idToken - @decoded_id_token = JWT.decode idToken, @public_key, false, { :algorithm => 'RS256' } - end - end + def self.get_users(queryParameters = nil, accessToken = nil) + generic_get("users/", queryParameters, accessToken) + end - end + def self.create_user(userRepresentation, accessToken = nil) + generic_post("users/", nil, userRepresentation, accessToken) + end - # Os recursos desse module (admin) serão utilizadas apenas por usuários que possuem as roles do client realm-management - module Admin + def self.count_users(accessToken = nil) + generic_get("users/count/", nil, accessToken) + end - class << self + def self.get_user(id, accessToken = nil) + generic_get("users/#{id}", nil, accessToken) + end - end + def self.update_user(id, userRepresentation, accessToken = nil) + generic_put("users/#{id}", nil, userRepresentation, accessToken) + end - def self.get_users( queryParameters = nil) - generic_get("users/", queryParameters) - end + def self.delete_user(id, accessToken = nil) + generic_delete("users/#{id}", nil, nil, accessToken) + end - def self.create_user(userRepresentation) - generic_post("users/", nil, userRepresentation) - end + def self.revoke_consent_user(id, clientID = nil, accessToken = nil) + if clientID.nil? + clientID = Keycloak::Client.client_id + end + generic_delete("users/#{id}/consents/#{clientID}", nil, nil, accessToken) + end - def self.count_users - generic_get("users/count/") - end + def self.update_account_email(id, actions, redirectUri = '', clientID = nil, accessToken = nil) + if clientID.nil? + clientID = Keycloak::Client.client_id + end + generic_put("users/#{id}/execute-actions-email", {:redirect_uri => redirectUri, :client_id => clientID}, actions, accessToken) + end - def self.get_user(id) - generic_get("users/#{id}") - end + def self.get_role_mappings(id, accessToken = nil) + generic_get("users/#{id}/role-mappings", nil, accessToken) + end - def self.update_user(id, userRepresentation) - generic_put("users/#{id}", nil, userRepresentation) - end + def self.get_clients(queryParameters = nil, accessToken = nil) + generic_get("clients/", queryParameters, accessToken) + end - def self.delete_user(id) - generic_delete("users/#{id}") - end + def self.get_all_roles_client(id, accessToken = nil) + generic_get("clients/#{id}/roles", nil, accessToken) + end - def self.revoke_consent_user(id, clientID = nil) - if clientID.nil? - clientID = Keycloak::Client.client_id - end - generic_delete("users/#{id}/consents/#{clientID}") - end + def self.get_roles_client_by_name(id, roleName, accessToken = nil) + generic_get("clients/#{id}/roles/#{roleName}", nil, accessToken) + end - def self.update_account_email(id, actions, redirectUri = '', clientID = nil) - if clientID.nil? - clientID = Keycloak::Client.client_id - end - generic_put("users/#{id}/execute-actions-email", {:redirect_uri => redirectUri, :client_id => clientID}, actions) - end + def self.add_client_level_roles_to_user(id, client, roleRepresentation, accessToken = nil) + generic_post("users/#{id}/role-mappings/clients/#{client}", nil, roleRepresentation, accessToken) + end - def self.get_role_mappings(id) - generic_get("users/#{id}/role-mappings") - end + def self.delete_client_level_roles_from_user(id, client, roleRepresentation, accessToken = nil) + generic_delete("users/#{id}/role-mappings/clients/#{client}", nil, roleRepresentation, accessToken) + end - def self.get_clients(queryParameters = nil) - generic_get("clients/", queryParameters) - end + def self.get_client_level_role_for_user_and_app(id, client, accessToken = nil) + generic_get("users/#{id}/role-mappings/clients/#{client}", nil, accessToken) + end - def self.get_all_roles_client(id) - generic_get("clients/#{id}/roles") - end + def self.update_effective_user_roles(id, clientID, rolesNames, accessToken = nil) + client = JSON get_clients({ clientId: clientID }) - def self.get_roles_client_by_name(id, roleName) - generic_get("clients/#{id}/roles/#{roleName}") - end + userRoles = JSON get_client_level_role_for_user_and_app(id, client[0]['id'], accessToken) - def self.add_client_level_roles_to_user(id, client, roleRepresentation) - generic_post("users/#{id}/role-mappings/clients/#{client}", nil, roleRepresentation) - end + roles = Array.new + # Include new role + rolesNames.each do |r| + if r && !r.empty? + found = false + userRoles.each do |ur| + found = ur['name'] == r + break if found + found = false + end + if !found + role = JSON get_roles_client_by_name(client[0]['id'], r, accessToken) + roles.push(role) + end + end + end - def self.delete_client_level_roles_fom_user(id, client, roleRepresentation) - generic_delete("users/#{id}/role-mappings/clients/#{client}", nil, roleRepresentation) - end + garbageRoles = Array.new + # Exclude old role + userRoles.each do |ur| + found = false + rolesNames.each do |r| + if r && !r.empty? + found = ur['name'] == r + break if found + found = false + end + end + if !found + garbageRoles.push(ur) + end + end - def self.get_client_level_role_for_user_and_app(id, client) - generic_get("users/#{id}/role-mappings/clients/#{client}") - end + if garbageRoles.count > 0 + delete_client_level_roles_from_user(id, client[0]['id'], garbageRoles, accessToken) + end - def self.update_effective_user_roles(id, clientID, rolesNames) - client = JSON get_clients({:clientId => clientID}) + if roles.count > 0 + add_client_level_roles_to_user(id, client[0]['id'], roles, accessToken) + end + end - userRoles = JSON get_client_level_role_for_user_and_app(id, client[0]['id']) + def self.reset_password(id, credentialRepresentation, accessToken = nil) + generic_put("users/#{id}/reset-password", nil, credentialRepresentation, accessToken) + end - roles = Array.new - # Include new role - rolesNames.each do |r| - if r && !r.empty? - found = false - userRoles.each do |ur| - found = ur['name'] == r - break if found - found = false - end - if !found - role = JSON get_roles_client_by_name(client[0]['id'], r) - roles.push(role) - end - end - end + def self.get_effective_client_level_role_composite_user(id, client, accessToken = nil) + generic_get("users/#{id}/role-mappings/clients/#{client}/composite", nil, accessToken) + end - garbageRoles = Array.new - # Exclude old role - userRoles.each do |ur| - found = false - rolesNames.each do |r| - if r && !r.empty? - found = ur['name'] == r - break if found - found = false - end - end - if !found - garbageRoles.push(ur) - end - end + # Generics methods - if garbageRoles.count > 0 - delete_client_level_roles_fom_user(id, client[0]['id'], garbageRoles) - end + def self.generic_get(service, queryParameters = nil, accessToken = nil) + Keycloak.generic_request(effective_access_token(accessToken), full_url(service), queryParameters, nil, 'GET') + end - if roles.count > 0 - add_client_level_roles_to_user(id, client[0]['id'], roles) - end - end + def self.generic_post(service, queryParameters, bodyParameter, accessToken = nil) + Keycloak.generic_request(effective_access_token(accessToken), full_url(service), queryParameters, bodyParameter, 'POST') + end - def self.reset_password(id, credentialRepresentation) - generic_put("users/#{id}/reset-password", nil, credentialRepresentation) - end + def self.generic_put(service, queryParameters, bodyParameter, accessToken = nil) + Keycloak.generic_request(effective_access_token(accessToken), full_url(service), queryParameters, bodyParameter, 'PUT') + end - # Generics methods + def self.generic_delete(service, queryParameters = nil, bodyParameter = nil, accessToken = nil) + Keycloak.generic_request(effective_access_token(accessToken), full_url(service), queryParameters, bodyParameter, 'DELETE') + end - def self.generic_get(service, queryParameters = nil) - Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, nil, 'GET') - end + private - def self.generic_post(service, queryParameters, bodyParameter) - Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'POST') - end + def self.effective_access_token(access_token) + if access_token.blank? + Keycloak::Client.token['access_token'] + else + access_token + end + end - def self.generic_put(service, queryParameters, bodyParameter) - Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'PUT') - end + def self.base_url + Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/" + end - def self.generic_delete(service, queryParameters = nil, bodyParameter = nil) - Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'DELETE') - end + def self.full_url(service) + base_url + service + end - private + end - def self.base_url - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/" - end + module Internal + include Keycloak::Admin - def self.full_url(service) - base_url + service - end + class << self + end - end + def self.get_users(queryParameters = nil) + proc = lambda {|token| + Keycloak::Admin.get_users(queryParameters, token["access_token"]) + } - module Internal - include Keycloak::Admin + default_call(proc) + end - class << self - attr_accessor - end + def self.change_password(userID, redirectURI = '') + proc = lambda {|token| + Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("users/#{userID}/execute-actions-email"), + {:redirect_uri => redirectURI, :client_id => Keycloak::Client.client_id}, + ['UPDATE_PASSWORD'], + 'PUT') + } - def self.change_password(userID, redirectURI = '') - proc = lambda {|token| - Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("users/#{userID}/execute-actions-email"), - {:redirect_uri => redirectURI, :client_id => Keycloak::Client.client_id}, - ['UPDATE_PASSWORD'], - 'PUT') - } + default_call(proc) + end - default_call(proc) - end + def self.forgot_password(userLogin, redirectURI = '') + user = get_user_info(userLogin, true) + change_password(user['id'], redirectURI) + end - def self.forgot_password(userLogin, redirectURI = '') - user = get_user_info(userLogin, true) - change_password(user['id'], redirectURI) - end + def self.get_logged_user_info + proc = lambda {|token| + userinfo = JSON Keycloak::Client.get_userinfo + Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("users/#{userinfo['sub']}"), + nil, nil, 'GET') + } - def self.get_logged_user_info - proc = lambda {|token| - userinfo = JSON Keycloak::Client.get_userinfo - Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("users/#{userinfo['sub']}"), - nil, nil, 'GET') - } + default_call(proc) + end - default_call(proc) - end + def self.get_user_info(userLogin, wholeWord = false) + proc = lambda { |token| + if userLogin.index('@').nil? + search = {:username => userLogin} + else + search = {:email => userLogin} + end + users = JSON Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("users/"), + search, nil, 'GET') + users[0] + if users.count.zero? + raise Keycloak::UserLoginNotFound + else + efective_index = -1 + users.each_with_index do |user, i| + if wholeWord + efective_index = i if userLogin == user['username'] || userLogin == user['email'] + else + efective_index = 0 + end + break if efective_index >= 0 + end - def self.get_user_info(userLogin, wholeWord = false) - proc = lambda {|token| - if userLogin.index('@').nil? - search = {:username => userLogin} - else - search = {:email => userLogin} - end - users = JSON Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("users/"), - search, nil, 'GET') - users[0] - if users.count == 0 - raise Keycloak::UserLoginNotFound - else - efectiveIndex = -1 - users.each_with_index do |user, i| - if wholeWord - efectiveIndex = i if userLogin == user['username'] || userLogin == user['email'] - else - efectiveIndex = 0 - end - break if efectiveIndex >= 0 - end + if efective_index >= 0 + if wholeWord + users[efective_index] + else + users + end + else + raise Keycloak::UserLoginNotFound + end + end + } - if efectiveIndex >= 0 - if wholeWord - users[efectiveIndex] - else - users - end - else - raise Keycloak::UserLoginNotFound - end - end - } + default_call(proc) + end - default_call(proc) - end + def self.logged_federation_user? + info = get_logged_user_info + info['federationLink'] != nil + end - def self.is_logged_federation_user? - info = get_logged_user_info - info['federationLink'] != nil - end + def self.create_starter_user(userName, password, email, clientRolesNames, proc = nil) + begin + user = get_user_info(userName, true) + newUser = false + rescue Keycloak::UserLoginNotFound + newUser = true + rescue + raise + end - def self.create_starter_user(userName, password, email, clientRolesNames, proc = nil) - begin - user = get_user_info(userName, true) - newUser = false - rescue Keycloak::UserLoginNotFound - newUser = true - rescue - raise - end + proc_default = lambda { |token| + user_representation = { username: userName, + email: email, + enabled: true } - procDefault = lambda {|token| - userRepresentation = {:username => userName, - :email => email, - :enabled => true} + if !newUser || Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("users/"), + nil, user_representation, 'POST') - if !newUser || Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("users/"), - nil, userRepresentation, 'POST') + user = get_user_info(userName, true) if newUser - user = get_user_info(userName, true) if newUser + credential_representation = { type: "password", + temporary: false, + value: password } - credentialRepresentation = {:type => "password", - :temporary => false, - :value => password} + if Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("users/#{user['id']}/reset-password"), + nil, credential_representation, 'PUT') - if Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("users/#{user['id']}/reset-password"), - nil, credentialRepresentation, 'PUT') + client = JSON Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("clients/"), + { clientId: Keycloak::Client.client_id }, nil, 'GET') - client = JSON Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("clients/"), - {:clientId => Keycloak::Client.client_id}, nil, 'GET') + roles = [] + clientRolesNames.each do |r| + if r.present? + role = JSON Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("clients/#{client[0]['id']}/roles/#{r}"), + nil, nil, 'GET') + roles.push(role) + end + end - roles = Array.new - clientRolesNames.each do |r| - if r && !r.empty? - role = JSON Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("clients/#{client[0]['id']}/roles/#{r}"), - nil, nil, 'GET') - roles.push(role) - end - end + if roles.count > 0 + Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("users/#{user['id']}/role-mappings/clients/#{client[0]['id']}"), + nil, roles, 'POST') + end + end - if roles.count > 0 - Keycloak.generic_request(token["access_token"], - Keycloak::Admin.full_url("users/#{user['id']}/role-mappings/clients/#{client[0]['id']}"), - nil, roles, 'POST') - end - end + end + } - end - } + if default_call(proc_default) + proc.call user unless proc.nil? + end + end - if default_call(procDefault) - if !proc.nil? - proc.call user - end - end + def self.get_client_roles + proc = lambda {|token| + client = JSON Keycloak::Admin.get_clients({ clientId: Keycloak::Client.client_id }, token["access_token"]) - end + Keycloak.generic_request(token["access_token"], + Keycloak::Admin.full_url("clients/#{client[0]['id']}/roles"), + nil, nil, 'GET') + } - protected + default_call(proc) + end - def self.default_call(proc) - begin - tk = nil - resp = nil + def self.get_client_user_roles(userID) + proc = lambda {|token| + client = JSON Keycloak::Admin.get_clients({ clientId: Keycloak::Client.client_id }, token["access_token"]) + Keycloak::Admin.get_effective_client_level_role_composite_user(userID, client[0]['id'], token["access_token"]) + } - Keycloak::Client.get_installation + default_call(proc) + end - payload = {'client_id' => Keycloak::Client.client_id, - 'client_secret' => Keycloak::Client.secret, - 'grant_type' => 'client_credentials' - } + def self.has_role?(userID, userRole) + roles = JSON get_client_user_roles(userID) + if !roles.nil? + roles.each do |role| + return true if role['name'].to_s == userRole.to_s + end + false + else + false + end + end - header = {'Content-Type' => 'application/x-www-form-urlencoded'} + protected - _request = -> do - RestClient.post(Keycloak::Client.configuration['token_endpoint'], payload, header){|response, request, result| - case response.code - when 200..399 - tk = JSON response.body - resp = proc.call(tk) - else - response.return! - end - } - end + def self.default_call(proc) + begin + tk = nil + resp = nil - Keycloak::Client.exec_request _request - ensure - if tk - payload = {'client_id' => Keycloak::Client.client_id, - 'client_secret' => Keycloak::Client.secret, - 'refresh_token' => tk["refresh_token"] - } + Keycloak::Client.get_installation - header = {'Content-Type' => 'application/x-www-form-urlencoded'} - _request = -> do - RestClient.post(Keycloak::Client.configuration['end_session_endpoint'], payload, header){|response, request, result| - case response.code - when 200..399 - resp if resp.nil? - else - response.return! - end - } - end - Keycloak::Client.exec_request _request - end - end - end + payload = { 'client_id' => Keycloak::Client.client_id, + 'client_secret' => Keycloak::Client.secret, + 'grant_type' => 'client_credentials' } - end + header = {'Content-Type' => 'application/x-www-form-urlencoded'} - private + _request = -> do + RestClient.post(Keycloak::Client.configuration['token_endpoint'], payload, header){|response, request, result| + case response.code + when 200..399 + tk = JSON response.body + resp = proc.call(tk) + else + response.return! + end + } + end - def self.generic_request(accessToken, uri, queryParameters, bodyParameter, method) - Keycloak::Client.verify_setup - final_url = uri + Keycloak::Client.exec_request _request + ensure + if tk + payload = { 'client_id' => Keycloak::Client.client_id, + 'client_secret' => Keycloak::Client.secret, + 'refresh_token' => tk["refresh_token"] } - header = {'Content-Type' => 'application/x-www-form-urlencoded', - 'Authorization' => "Bearer #{accessToken}"} + header = {'Content-Type' => 'application/x-www-form-urlencoded'} + _request = -> do + RestClient.post(Keycloak::Client.configuration['end_session_endpoint'], payload, header){|response, request, result| + case response.code + when 200..399 + resp if resp.nil? + else + response.return! + end + } + end + Keycloak::Client.exec_request _request + end + end + end - if queryParameters - parameters = URI.encode_www_form(queryParameters) - final_url = final_url << '?' << parameters - end + end - case method.upcase - when 'GET' - _request = -> do - RestClient.get(final_url, header){|response, request, result| - rescue_response(response) - } - end - when 'POST', 'PUT' - header["Content-Type"] = 'application/json' - parameters = JSON.generate bodyParameter - _request = -> do - case method.upcase - when 'POST' - RestClient.post(final_url, parameters, header){|response, request, result| - rescue_response(response) - } - else - RestClient.put(final_url, parameters, header){|response, request, result| - rescue_response(response) - } - end - end - when 'DELETE' - _request = -> do - if bodyParameter - header["Content-Type"] = 'application/json' - parameters = JSON.generate bodyParameter - RestClient::Request.execute(method: :delete, url: final_url, - payload: parameters, headers: header){|response, request, result| - rescue_response(response) - } - else - RestClient.delete(final_url, header){|response, request, result| - rescue_response(response) - } - end - end - else - raise - end + private - _request.call + def self.generic_request(accessToken, uri, queryParameters, bodyParameter, method) + Keycloak::Client.verify_setup + final_url = uri - end + header = {'Content-Type' => 'application/x-www-form-urlencoded', + 'Authorization' => "Bearer #{accessToken}"} - def self.rescue_response(response) - case response.code - when 200..399 - if response.body.empty? - true - else - response.body - end - else - if Keycloak.explode_exception - response.return! - else - begin - response.return! - rescue RestClient::ExceptionWithResponse => err - err.response - rescue Exception => e - e.message - end - end - end - end + if queryParameters + parameters = URI.encode_www_form(queryParameters) + final_url = final_url << '?' << parameters + end + case method.upcase + when 'GET' + _request = -> do + RestClient.get(final_url, header){|response, request, result| + rescue_response(response) + } + end + when 'POST', 'PUT' + header["Content-Type"] = 'application/json' + parameters = JSON.generate bodyParameter + _request = -> do + case method.upcase + when 'POST' + RestClient.post(final_url, parameters, header){|response, request, result| + rescue_response(response) + } + else + RestClient.put(final_url, parameters, header){|response, request, result| + rescue_response(response) + } + end + end + when 'DELETE' + _request = -> do + if bodyParameter + header["Content-Type"] = 'application/json' + parameters = JSON.generate bodyParameter + RestClient::Request.execute(method: :delete, url: final_url, + payload: parameters, headers: header) { |response, request, result| + rescue_response(response) + } + else + RestClient.delete(final_url, header) { |response, request, result| + rescue_response(response) + } + end + end + else + raise + end + + _request.call + + end + + def self.rescue_response(response) + case response.code + when 200..399 + if response.body.empty? + true + else + response.body + end + else + if Keycloak.explode_exception + response.return! + else + begin + response.return! + rescue RestClient::ExceptionWithResponse => err + err.response + rescue StandardError => e + e.message + end + end + end + end end require 'keycloak/exceptions' \ No newline at end of file