Class: Clonk::Connection
- Inherits:
-
Object
- Object
- Clonk::Connection
- Defined in:
- lib/clonk/role.rb,
lib/clonk/user.rb,
lib/clonk/group.rb,
lib/clonk/realm.rb,
lib/clonk/client.rb,
lib/clonk/policy.rb,
lib/clonk/connection.rb,
lib/clonk/permission.rb
Overview
Defines a connection to SSO.
Instance Attribute Summary collapse
-
#realm ⇒ Object
writeonly
Sets the attribute realm.
Class Method Summary collapse
-
.create(data) ⇒ Object
Creates a policy in SSO.
Instance Method Summary collapse
-
#add_to_group(user:, group:) ⇒ Object
Adds a user to a group.
- #clients ⇒ Object
-
#config(object) ⇒ Object
Returns the config in SSO for an object.
-
#connection(raise_error: false, json: true, token: @access_token) ⇒ Object
Defines a Faraday::Connection object linked to the SSO instance.
- #create_client(**data) ⇒ Object
-
#create_group(**data) ⇒ Object
Creates a group in SSO and returns its representation as a Clonk::Group.
- #create_instance_of(class_name, response) ⇒ Object
-
#create_object(type:, path: "/#{type.downcase}s", root: realm_admin_root, data: {}) ⇒ Object
Creates an object and returns an instance of it in SSO.
-
#create_realm(**data) ⇒ Object
Creates a new realm with the given data.
-
#create_role(client:, **data) ⇒ Object
Creates a role within the given client.
-
#create_subgroup(group:, **data) ⇒ Object
Creates a subgroup in SSO and returns its representation as a Clonk::Group.
-
#create_user(**data) ⇒ Object
Creates a new user in SSO and returns its representation as a Clonk::User.
-
#define_policy(type: :role, name: nil, objects: [], description: nil, groups_claim: nil) ⇒ Object
Returns a policy definition that can then be used to create a policy in SSO.
- #delete(object) ⇒ Object
-
#get_policy_config(id) ⇒ Object
Gets config inside SSO for policy with ID in realm.
-
#groups(user: nil) ⇒ Object
Lists groups in the realm.
-
#initial_access_token(username: @username, password: @password, client_id: @client_id, realm_id: @realm.name) ⇒ Object
Retrieves an initial access token for the user in the given realm.
-
#initialize(base_url:, realm_id:, username:, password:, client_id: nil) ⇒ Connection
constructor
A new instance of Connection.
- #login_url(realm_id: @realm.name, redirect_uri:, client_id: @client_id) ⇒ Object
- #logout_url(realm_id: @realm.name, client_id: @client_id, redirect_uri:) ⇒ Object
-
#map_role(role:, target:) ⇒ Object
Map a role to another object.
-
#map_scope(client:, role:) ⇒ Object
Maps the given role into the scope of the client.
-
#objects(type:, path: "/#{type.downcase}s", root: realm_admin_root) ⇒ Object
Returns all objects in the realm of that type.
-
#parsed_response(method: :get, path: '/', data: nil, connection_params: {}) ⇒ Object
Returns a parsed JSON response for an API call via the given method.
-
#permissions(object: nil) ⇒ Object
Lists the permissions associated with an object.
- #policies ⇒ Object
-
#policies_for(permission) ⇒ Object
Returns the policy IDs associated with a permission.
-
#realm_admin_root(realm = @realm) ⇒ Object
Returns the admin API root for the realm.
-
#realms ⇒ Object
Lists all realms in SSO.
-
#resources_for(permission) ⇒ Object
Returns the resource IDs associated with this permission.
-
#response(method: :get, path: '/', data: nil, connection_params: {}) ⇒ Object
Returns a Faraday::Response for an API call via the given method.
- #roles(client:) ⇒ Object
-
#scopes_for(permission) ⇒ Object
Returns the scope IDs associated with this permission.
-
#secret(client:) ⇒ Object
Returns the client’s secret FIXME: Write test!.
-
#set_password_for(user:, password: nil, temporary: false) ⇒ Object
Sets the password for a user.
-
#set_permissions(object:, enabled: true) ⇒ Object
Enables or disables permissions for some object FIXME: Write test!.
-
#subgroups(group) ⇒ Object
Lists subgroups of a given group.
-
#update_permission(permission:, policies: [], resources: [], scopes: []) ⇒ Object
Adds the given policy/resource/scope IDs to this permission in SSO.
-
#url_for(target, prefix: 'permision/scope') ⇒ Object
Returns the URL for the given object.
- #url_for_permission(permission, prefix: 'permission/scope') ⇒ Object
-
#users ⇒ Object
Lists all users in the realm.
Constructor Details
#initialize(base_url:, realm_id:, username:, password:, client_id: nil) ⇒ Connection
Returns a new instance of Connection.
11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/clonk/connection.rb', line 11 def initialize(base_url:, realm_id:, username:, password:, client_id: nil) @base_url = base_url @client_id = client_id initial_access_token( username: username, password: password, realm_id: realm_id, client_id: client_id ) @realm = create_instance_of( 'Realm', parsed_response(path: "/auth/realms/#{realm_id}") ) end |
Instance Attribute Details
#realm=(value) ⇒ Object (writeonly)
Sets the attribute realm
9 10 11 |
# File 'lib/clonk/connection.rb', line 9 def realm=(value) @realm = value end |
Class Method Details
.create(data) ⇒ Object
Creates a policy in SSO. You should do this after defining a policy with define_policy. FIXME: move to connection class
85 86 87 88 89 90 91 92 |
# File 'lib/clonk/policy.rb', line 85 def self.create(data) realm_management_url = url_for(clients.find { |c| c.name == 'realm-management' }) parsed_response( method: :post, path: "#{realm_management_url}/authz/resource-server/policy/#{data['type']}", data: data ) end |
Instance Method Details
#add_to_group(user:, group:) ⇒ Object
Adds a user to a group.
48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/clonk/group.rb', line 48 def add_to_group(user:, group:) response( method: :put, path: "#{realm_admin_root}/users/#{user.id}/groups/#{group.id}", data: { userId: user.id, groupId: group.id, realm: @realm.name } ) end |
#clients ⇒ Object
19 20 21 |
# File 'lib/clonk/client.rb', line 19 def clients objects(type: 'Client') end |
#config(object) ⇒ Object
Returns the config in SSO for an object. – FIXME: Does not work for policies or permissions ++
64 65 66 67 68 69 70 |
# File 'lib/clonk/connection.rb', line 64 def config(object) class_name = object.class.name.split('::').last.downcase + 's' class_name = 'roles-by-id' if class_name == 'roles' route = realm_admin_root + "/#{class_name}/#{object.id}" return parsed_response(path: url_fo(object)) if class_name == 'realm' parsed_response(path: route) end |
#connection(raise_error: false, json: true, token: @access_token) ⇒ Object
Defines a Faraday::Connection object linked to the SSO instance.
110 111 112 113 114 115 116 117 |
# File 'lib/clonk/connection.rb', line 110 def connection(raise_error: false, json: true, token: @access_token) Faraday.new(url: @base_url) do |faraday| faraday.request(json ? :json : :url_encoded) faraday.use Faraday::Response::RaiseError if raise_error faraday.adapter Faraday.default_adapter faraday.headers['Authorization'] = "Bearer #{token}" unless token.nil? end end |
#create_client(**data) ⇒ Object
23 24 25 26 27 28 |
# File 'lib/clonk/client.rb', line 23 def create_client(**data) create_object( type: 'Client', data: { fullScopeAllowed: false }.merge(data) ) end |
#create_group(**data) ⇒ Object
Creates a group in SSO and returns its representation as a Clonk::Group.
33 34 35 36 37 |
# File 'lib/clonk/group.rb', line 33 def create_group(**data) return if data[:name].nil? # Breaks things in SSO! create_object(type: 'Group', data: data) end |
#create_instance_of(class_name, response) ⇒ Object
51 52 53 |
# File 'lib/clonk/connection.rb', line 51 def create_instance_of(class_name, response) Object.const_get('Clonk').const_get(class_name).new(response) || response end |
#create_object(type:, path: "/#{type.downcase}s", root: realm_admin_root, data: {}) ⇒ Object
Creates an object and returns an instance of it in SSO. Wrapped for each type.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/clonk/connection.rb', line 29 def create_object( type:, path: "/#{type.downcase}s", root: realm_admin_root, data: {} ) creation_response = response( method: :post, path: root + path, data: data ) create_instance_of( type, parsed_response( path: creation_response.headers[:location] ) ) end |
#create_realm(**data) ⇒ Object
Creates a new realm with the given data.
25 26 27 28 29 30 31 32 |
# File 'lib/clonk/realm.rb', line 25 def create_realm(**data) create_object( type: 'Realm', path: '', root: realm_admin_root(nil), data: { enabled: true, id: data['realm'] }.merge(data) ) end |
#create_role(client:, **data) ⇒ Object
Creates a role within the given client. it will be visible in tokens given by this client during authentication, as it is already in scope.
28 29 30 |
# File 'lib/clonk/role.rb', line 28 def create_role(client:, **data) create_object(type: 'Role', root: url_for(client), data: data) end |
#create_subgroup(group:, **data) ⇒ Object
Creates a subgroup in SSO and returns its representation as a Clonk::Group.
41 42 43 44 45 |
# File 'lib/clonk/group.rb', line 41 def create_subgroup(group:, **data) create_object( type: 'Group', path: "/groups/#{group.id}/children", data: data ) end |
#create_user(**data) ⇒ Object
Creates a new user in SSO and returns its representation as a Clonk::User.
24 25 26 |
# File 'lib/clonk/user.rb', line 24 def create_user(**data) create_object(type: 'User', data: { enabled: true }.merge(data)) end |
#define_policy(type: :role, name: nil, objects: [], description: nil, groups_claim: nil) ⇒ Object
Returns a policy definition that can then be used to create a policy in SSO. Only defines role, group and client policies – TODO: Expand to allow for other policy types TODO: Don’t assume role as default type FIXME: give objects a type method, split this into two functions ++
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/clonk/policy.rb', line 58 def define_policy(type: :role, name: nil, objects: [], description: nil, groups_claim: nil) objects = if type == :role { roles: objects.map do |role| { id: role.id, required: true } end } elsif type == :group { groups: objects.map do |group| { id: group.id, extendChildren: false } end } end defaults.merge(objects).merge( type: type, name: name, groupsClaim: (groups_claim if type == :group), clients: (objects.map(&:id) if type == :client), description: description ).delete_if { |_k, v| v.nil? } end |
#delete(object) ⇒ Object
55 56 57 |
# File 'lib/clonk/connection.rb', line 55 def delete(object) response(path: url_for(object), method: :delete) end |
#get_policy_config(id) ⇒ Object
Gets config inside SSO for policy with ID in realm. – FIXME: bring in line with existing config method ++
41 42 43 44 45 46 47 |
# File 'lib/clonk/policy.rb', line 41 def get_policy_config(id) parsed_response( path: "#{realm_admin_root(realm)}/clients/#{clients.find { |client| client.name == 'realm-management' }.id}/authz/resource-server/policy/role/#{id}" ) end |
#groups(user: nil) ⇒ Object
Lists groups in the realm.
18 19 20 21 22 |
# File 'lib/clonk/group.rb', line 18 def groups(user: nil) return objects(type: 'Group') unless user objects(type: 'Group', path: "/users/#{user.id}/groups") end |
#initial_access_token(username: @username, password: @password, client_id: @client_id, realm_id: @realm.name) ⇒ Object
Retrieves an initial access token for the user in the given realm.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/clonk/connection.rb', line 93 def initial_access_token( username: @username, password: @password, client_id: @client_id, realm_id: @realm.name ) @access_token = parsed_response( method: :post, path: "/auth/realms/#{realm_id}/protocol/openid-connect/token", connection_params: { json: false, raise_error: true }, data: { username: username, password: password, grant_type: 'password', client_id: client_id } )['access_token'] end |
#login_url(realm_id: @realm.name, redirect_uri:, client_id: @client_id) ⇒ Object
174 175 176 |
# File 'lib/clonk/connection.rb', line 174 def login_url(realm_id: @realm.name, redirect_uri:, client_id: @client_id) "#{@base_url}/auth/realms/#{realm_id}/protocol/openid-connect/auth?response_type=code&client_id=#{client_id}&redirect_uri=#{CGI.escape(redirect_uri)}" end |
#logout_url(realm_id: @realm.name, client_id: @client_id, redirect_uri:) ⇒ Object
170 171 172 |
# File 'lib/clonk/connection.rb', line 170 def logout_url(realm_id: @realm.name, client_id: @client_id, redirect_uri:) "#{@base_url}/auth/realms/#{realm_id}/protocol/openid-connect/logout?redirect_uri=#{CGI.escape(redirect_uri)}" end |
#map_role(role:, target:) ⇒ Object
Map a role to another object. Common to groups and users
75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/clonk/connection.rb', line 75 def map_role(role:, target:) client_path = case role.container_id when @realm 'realm' else "clients/#{role.container_id}" end parsed_response( method: :post, data: [config(role)], path: "#{url_for(target)}/role-mappings/#{client_path}" ) end |
#map_scope(client:, role:) ⇒ Object
Maps the given role into the scope of the client. If a user has that role, it will be visible in tokens given by this client during authentication. FIXME: Write test!
35 36 37 38 39 40 41 |
# File 'lib/clonk/client.rb', line 35 def map_scope(client:, role:) response( method: :post, data: [config(role)], path: "#{url_for(client)}/scope-mappings/clients/#{role.container_id}" ) end |
#objects(type:, path: "/#{type.downcase}s", root: realm_admin_root) ⇒ Object
Returns all objects in the realm of that type. Wrapped for each type.
45 46 47 48 49 |
# File 'lib/clonk/connection.rb', line 45 def objects(type:, path: "/#{type.downcase}s", root: realm_admin_root) parsed_response(path: root + path).map do |object_response| create_instance_of(type, object_response) end end |
#parsed_response(method: :get, path: '/', data: nil, connection_params: {}) ⇒ Object
Returns a parsed JSON response for an API call via the given method. Useful in instances where only the data is necessary, and not HTTP status confirmation that the desired effect was caused.
131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/clonk/connection.rb', line 131 def parsed_response( method: :get, path: '/', data: nil, connection_params: {} ) resp = response( method: method, path: path, data: data, connection_params: connection_params ) JSON.parse(resp.body) rescue JSON::ParserError resp.body end |
#permissions(object: nil) ⇒ Object
Lists the permissions associated with an object. If an object is not provided, all permissions in the realm-management client are returned.
50 51 52 53 54 |
# File 'lib/clonk/client.rb', line 50 def (client:) parsed_response( path: "#{url_for(client)}/management/permissions" )['scopePermissions'] || false end |
#policies ⇒ Object
28 29 30 31 32 33 |
# File 'lib/clonk/policy.rb', line 28 def policies realm_management = clients.find { |client| client.name == 'realm-management' } objects(type: 'Policy', path: "/clients/#{realm_management.id}/authz/resource-server/policy" ) end |
#policies_for(permission) ⇒ Object
Returns the policy IDs associated with a permission. FIXME: untested!
40 41 42 43 44 |
# File 'lib/clonk/permission.rb', line 40 def policies_for() parsed_response( path: "#{url_for(, prefix: 'policy')}/associatedPolicies" ) end |
#realm_admin_root(realm = @realm) ⇒ Object
Returns the admin API root for the realm.
146 147 148 |
# File 'lib/clonk/connection.rb', line 146 def realm_admin_root(realm = @realm) "#{@base_url}/auth/admin/realms/#{realm&.name}" end |
#realms ⇒ Object
Lists all realms in SSO.
20 21 22 |
# File 'lib/clonk/realm.rb', line 20 def realms objects(type: 'Realm', path: '', root: realm_admin_root(nil)) end |
#resources_for(permission) ⇒ Object
Returns the resource IDs associated with this permission. FIXME: untested!
49 50 51 52 53 |
# File 'lib/clonk/permission.rb', line 49 def resources_for() parsed_response( path: "#{url_for(, prefix: 'policy')}/resources" ) end |
#response(method: :get, path: '/', data: nil, connection_params: {}) ⇒ Object
Returns a Faraday::Response for an API call via the given method.
121 122 123 124 125 |
# File 'lib/clonk/connection.rb', line 121 def response(method: :get, path: '/', data: nil, connection_params: {}) return unless %i[get post put delete].include?(method) connection(connection_params).public_send(method, path, data) end |
#roles(client:) ⇒ Object
19 20 21 |
# File 'lib/clonk/role.rb', line 19 def roles(client:) objects(type: 'Role', root: url_for(client)) end |
#scopes_for(permission) ⇒ Object
Returns the scope IDs associated with this permission. FIXME: untested
58 59 60 61 62 |
# File 'lib/clonk/permission.rb', line 58 def scopes_for() parsed_response( path: "#{url_for(, prefix: 'policy')}/scopes" ) end |
#secret(client:) ⇒ Object
Returns the client’s secret FIXME: Write test!
74 75 76 77 78 |
# File 'lib/clonk/client.rb', line 74 def secret(client:) parsed_response( path: "#{url_for(client)}/client-secret" )['value'] end |
#set_password_for(user:, password: nil, temporary: false) ⇒ Object
Sets the password for a user.
29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/clonk/user.rb', line 29 def set_password_for(user:, password: nil, temporary: false) response( method: :put, data: { type: 'password', value: password, temporary: temporary }, path: "#{url_for(user)}/reset-password" ) end |
#set_permissions(object:, enabled: true) ⇒ Object
Enables or disables permissions for some object FIXME: Write test!
60 61 62 63 64 65 66 67 68 |
# File 'lib/clonk/client.rb', line 60 def (object:, enabled: true) parsed_response( method: :put, path: "#{url_for(object)}/management/permissions", data: { enabled: enabled } ) end |
#subgroups(group) ⇒ Object
Lists subgroups of a given group.
25 26 27 28 29 30 |
# File 'lib/clonk/group.rb', line 25 def subgroups(group) subgroups = config(group)['subGroups'] return [] if subgroups.nil? subgroups.map { |subgroup| create_instance_of('Group', subgroup) } end |
#update_permission(permission:, policies: [], resources: [], scopes: []) ⇒ Object
Adds the given policy/resource/scope IDs to this permission in SSO. FIXME: untested
67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/clonk/permission.rb', line 67 def ( permission:, policies: [], resources: [], scopes: [] ) data = config().merge( policies: policies() + policies, resources: resources() + resources, scopes: scopes() + scopes ) parsed_response( path: url_for(), data: data, method: :put ) end |
#url_for(target, prefix: 'permision/scope') ⇒ Object
Returns the URL for the given object. Argument is necessary as permissions are sometimes treated as policies within SSO for some reason, especially when fetching scopes, resources and policies. FIXME: Does not work with realms - realm_admin_root does, though.
156 157 158 159 160 161 |
# File 'lib/clonk/connection.rb', line 156 def url_for(target, prefix: 'permision/scope') class_name = target.class.name.split('::').last.downcase (target, prefix: prefix) if class_name == 'permission' return "#{realm_admin_root(target)}" if class_name == 'realm' "#{realm_admin_root}/#{class_name}s/#{target.id}" end |
#url_for_permission(permission, prefix: 'permission/scope') ⇒ Object
163 164 165 166 167 168 |
# File 'lib/clonk/connection.rb', line 163 def (, prefix: 'permission/scope') client_url = url_for( clients.find { |client| client.name == 'realm-management' } ) "#{client_url}/authz/resource-server/#{prefix}/#{.id}" end |
#users ⇒ Object
Lists all users in the realm.
19 20 21 |
# File 'lib/clonk/user.rb', line 19 def users objects(type: 'User') end |