lib/keycloak.rb in keycloak-1.2.0 vs lib/keycloak.rb in keycloak-2.0.0

- old
+ new

@@ -7,11 +7,11 @@ module Keycloak class << self attr_accessor :proxy, :generate_request_exception, :keycloak_controller, - :last_response + :proc_cookie_token, :proc_external_attributes end def self.explode_exception if Keycloak.generate_request_exception == nil @@ -21,55 +21,75 @@ end module Client class << self - attr_reader :user, :password, :realm, :url, :client_id, :auth_server_url, - :secret, :configuration, :public_key, :decoded_access_token, - :token, :token_introspection, :decoded_refresh_token, - :active, :decoded_id_token, :userinfo + attr_reader :realm, :url, :client_id, :auth_server_url, + :secret, :configuration, :public_key - attr_accessor :external_attributes end KEYCLOAK_JSON_FILE = 'keycloak.json' def self.get_token(user, password) setup_module - reset_active - @user, @password = user, password - payload = {'client_id' => @client_id, 'client_secret' => @secret, - 'username' => @user, - 'password' => @password, + 'username' => user, + 'password' => password, 'grant_type' => 'password' } mount_request_token(payload) end def self.get_token_by_code(code, redirect_uri) - reset_active + verify_setup payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'code' => code, - 'grant_type' => 'authorization_code', - 'redirect_uri' => redirect_uri - } + 'client_secret' => @secret, + 'code' => code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => redirect_uri + } mount_request_token(payload) end + def self.get_token_by_refresh_token(refreshToken = nil) + verify_setup + + refreshToken = self.token['refresh_token'] + + payload = {'client_id' => @client_id, + 'client_secret' => @secret, + 'refresh_token' => refreshToken, + 'grant_type' => 'refresh_token' + } + + mount_request_token(payload) + end + + def self.get_token_by_client_credentials + setup_module + + payload = {'client_id' => @client_id, + 'client_secret' => @secret, + 'grant_type' => 'client_credentials' + } + + mount_request_token(payload) + end + def self.get_token_introspection(refresh = false) - reset_active(false) + verify_setup + unless refresh - payload = {'token' => @token["access_token"]} + payload = {'token' => self.token["access_token"]} else - payload = {'token' => @token["refresh_token"]} + payload = {'token' => self.token["refresh_token"]} end authorization = Base64.strict_encode64("#{@client_id}:#{@secret}") authorization = "Basic #{authorization}" @@ -78,36 +98,36 @@ _request = -> do RestClient.post(@configuration['token_introspection_endpoint'], payload, header){|response, request, result| case response.code when 200..399 - @token_introspection = JSON response.body - @active = @token_introspection['active'] - @token_introspection + response.body + else response.return! end - if !@active - reset_active - end } end exec_request _request end def self.url_login_redirect(redirect_uri, response_type = 'code') + verify_setup + p = URI.encode_www_form({:response_type => response_type, :client_id => @client_id, :redirect_uri => redirect_uri}) "#{@configuration['authorization_endpoint']}?#{p}" end def self.logout(redirect_uri = '') - if @token + verify_setup + + if self.token payload = {'client_id' => @client_id, - 'client_secret' => @secret, - 'refresh_token' => @token["refresh_token"] - } + 'client_secret' => @secret, + 'refresh_token' => self.token["refresh_token"] + } header = {'Content-Type' => 'application/x-www-form-urlencoded'} if redirect_uri.empty? final_url = @configuration['end_session_endpoint'] @@ -117,11 +137,10 @@ _request = -> do RestClient.post(final_url, payload, header){|response, request, result| case response.code when 200..399 - reset_active true else response.return! end } @@ -132,30 +151,33 @@ true end end def self.get_userinfo - payload = {'access_token' => @token["access_token"]} + verify_setup + payload = {'access_token' => self.token["access_token"]} + header = {'Content-Type' => 'application/x-www-form-urlencoded'} _request = -> do RestClient.post(@configuration['userinfo_endpoint'], payload, header){|response, request, result| case response.code when 200 - @userinfo = JSON response.body - @userinfo + response.body else response.return! end } end exec_request _request end def self.url_user_account + verify_setup + "#{@url}/realms/#{@realm}/account" end def self.get_installation if File.exists?(KEYCLOAK_JSON_FILE) @@ -164,20 +186,21 @@ @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"] - reset_active(false) openid_configuration else raise "#{KEYCLOAK_JSON_FILE} not found." end end def self.has_role?(userRole) + verify_setup + if user_signed_in? - dt = @decoded_access_token[0] + dt = decoded_access_token[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 @@ -189,26 +212,54 @@ false end end def self.user_signed_in? + verify_setup + begin - get_token_introspection['active'] - rescue - @active + JSON(get_token_introspection)['active'] === true + rescue => e + if e.class < Keycloak::KeycloakException + raise + else + false + end end end def self.get_attribute(attributeName) - attr = @decoded_access_token[0] + verify_setup + + attr = decoded_access_token[0] attr[attributeName] end + def self.token + unless Keycloak.proc_cookie_token.nil? + JSON Keycloak.proc_cookie_token.call + else + raise Keycloak::ProcCookieTokenNotDefined + end + end + + def self.external_attributes + unless Keycloak.proc_external_attributes.nil? + Keycloak.proc_external_attributes.call + else + raise Keycloak::ProcExternalAttributesNotDefined + end + end + private KEYCLOACK_CONTROLLER_DEFAULT = 'session' + def self.verify_setup + get_installation if @configuration.nil? + end + def self.setup_module Keycloak.proxy ||= '' Keycloak.keycloak_controller ||= KEYCLOACK_CONTROLLER_DEFAULT get_installation end @@ -225,68 +276,61 @@ end end def self.openid_configuration RestClient.proxy = Keycloak.proxy unless Keycloak.proxy.empty? - full_url = "#{@url}/realms/#{@realm}/.well-known/openid-configuration" + configUrl = "#{@url}/realms/#{@realm}/.well-known/openid-configuration" _request = -> do - RestClient.get full_url + RestClient.get configUrl end response = exec_request _request if response.code == 200 @configuration = JSON response.body else response.return! end end - def self.reset_active(resetExternalAttributes = true) - @active = false - @userinfo = nil - if resetExternalAttributes - @external_attributes = nil - end - end - def self.mount_request_token(payload) header = {'Content-Type' => 'application/x-www-form-urlencoded'} _request = -> do RestClient.post(@configuration['token_endpoint'], payload, header){|response, request, result| case response.code when 200 - @active = true - @token = JSON response.body - @decoded_access_token = JWT.decode @token["access_token"], @public_key, false, { :algorithm => 'RS256' } - @decoded_refresh_token = JWT.decode @token["refresh_token"], @public_key, false, { :algorithm => 'RS256' } - if @token["id_token"] - @decoded_id_token = JWT.decode @token["id_token"], @public_key, false, { :algorithm => 'RS256' } - end - Keycloak::Admin.setup_admin(@auth_server_url, @realm, @token["access_token"]) - @token + response.body else response.return! end } end exec_request _request end + def self.decoded_access_token + JWT.decode self.token["access_token"], @public_key, false, { :algorithm => 'RS256' } + end + + def self.decoded_refresh_token + JWT.decode self.token["refresh_token"], @public_key, false, { :algorithm => 'RS256' } + end + + def self.decoded_id_token + tk = self.token + if tk["id_token"] + @decoded_id_token = JWT.decode tk["id_token"], @public_key, false, { :algorithm => 'RS256' } + end + end + 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 - attr_reader :access_token, :auth_server_url, :realm - end - def self.setup_admin(auth_server_url, realm, access_token) - @auth_server_url = auth_server_url - @access_token = access_token - @realm = realm end def self.get_users( queryParameters = nil) generic_get("users/", queryParameters) end @@ -405,29 +449,29 @@ end # Generics methods def self.generic_get(service, queryParameters = nil) - Keycloak.generic_request(@access_token, full_url(service), queryParameters, nil, 'GET') + Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, nil, 'GET') end def self.generic_post(service, queryParameters, bodyParameter) - Keycloak.generic_request(@access_token, full_url(service), queryParameters, bodyParameter, 'POST') + Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'POST') end def self.generic_put(service, queryParameters, bodyParameter) - Keycloak.generic_request(@access_token, full_url(service), queryParameters, bodyParameter, 'PUT') + Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'PUT') end def self.generic_delete(service, queryParameters = nil, bodyParameter = nil) - Keycloak.generic_request(@access_token, full_url(service), queryParameters, bodyParameter, 'DELETE') + Keycloak.generic_request(Keycloak::Client.token['access_token'], full_url(service), queryParameters, bodyParameter, 'DELETE') end private def self.base_url - @auth_server_url + "/admin/realms/#{@realm}/" + Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/" end def self.full_url(service) base_url + service end @@ -436,17 +480,17 @@ module Internal include Keycloak::Admin class << self - attr_accessor :admin_user, :admin_password + attr_accessor end def self.change_password(userID, redirectURI = '') proc = lambda {|token| Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/users/#{userID}/execute-actions-email", + Keycloak::Admin.full_url("users/#{userID}/execute-actions-email"), {:redirect_uri => redirectURI, :client_id => Keycloak::Client.client_id}, ['UPDATE_PASSWORD'], 'PUT') } @@ -458,13 +502,13 @@ change_password(user['id'], redirectURI) end def self.get_logged_user_info proc = lambda {|token| - userinfo = Keycloak::Client.get_userinfo + userinfo = JSON Keycloak::Client.get_userinfo Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/users/#{userinfo['sub']}", + Keycloak::Admin.full_url("users/#{userinfo['sub']}"), nil, nil, 'GET') } default_call(proc) end @@ -475,11 +519,11 @@ search = {:username => userLogin} else search = {:email => userLogin} end users = JSON Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/users/", + Keycloak::Admin.full_url("users/"), search, nil, 'GET') users[0] if users.count == 0 raise Keycloak::UserLoginNotFound else @@ -527,40 +571,40 @@ userRepresentation = {:username => userName, :email => email, :enabled => true} if !newUser || Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/users/", + Keycloak::Admin.full_url("users/"), nil, userRepresentation, 'POST') user = get_user_info(userName, true) if newUser credentialRepresentation = {:type => "password", :temporary => false, :value => password} if Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/users/#{user['id']}/reset-password", + Keycloak::Admin.full_url("users/#{user['id']}/reset-password"), nil, credentialRepresentation, 'PUT') client = JSON Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/clients/", + Keycloak::Admin.full_url("clients/"), {:clientId => Keycloak::Client.client_id}, nil, 'GET') roles = Array.new clientRolesNames.each do |r| if r && !r.empty? role = JSON Keycloak.generic_request(token["access_token"], - Keycloak::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/clients/#{client[0]['id']}/roles/#{r}", + 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::Client.auth_server_url + "/admin/realms/#{Keycloak::Client.realm}/users/#{user['id']}/role-mappings/clients/#{client[0]['id']}", + Keycloak::Admin.full_url("users/#{user['id']}/role-mappings/clients/#{client[0]['id']}"), nil, roles, 'POST') end end end @@ -582,15 +626,13 @@ resp = nil Keycloak::Client.get_installation payload = {'client_id' => Keycloak::Client.client_id, - 'client_secret' => Keycloak::Client.secret, - 'username' => @admin_user, - 'password' => @admin_password, - 'grant_type' => 'password' - } + 'client_secret' => Keycloak::Client.secret, + 'grant_type' => 'client_credentials' + } header = {'Content-Type' => 'application/x-www-form-urlencoded'} _request = -> do RestClient.post(Keycloak::Client.configuration['token_endpoint'], payload, header){|response, request, result| @@ -631,10 +673,11 @@ end private def self.generic_request(accessToken, uri, queryParameters, bodyParameter, method) + Keycloak::Client.verify_setup final_url = uri header = {'Content-Type' => 'application/x-www-form-urlencoded', 'Authorization' => "Bearer #{accessToken}"} @@ -687,23 +730,22 @@ _request.call end def self.rescue_response(response) - @last_response = response - case @last_response.code + case response.code when 200..399 - if @last_response.body.empty? + if response.body.empty? true else - @last_response.body + response.body end else if Keycloak.explode_exception - @last_response.return! + response.return! else begin - @last_response.return! + response.return! rescue RestClient::ExceptionWithResponse => err err.response rescue Exception => e e.message end \ No newline at end of file