From e72f88febff5766345fa4a8f9086639ea997a2e9 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 2 Mar 2018 14:45:33 -0800 Subject: [PATCH 01/32] GUACAMOLE-220: Define base schema for user groups. --- .../schema/001-create-schema.sql | 233 +++++++++--- .../schema/002-create-admin-user.sql | 27 +- .../schema/upgrade/upgrade-pre-1.0.0.sql | 357 ++++++++++++++++++ 3 files changed, 558 insertions(+), 59 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql index ddd3566c2..9bcf1c51f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql @@ -26,6 +26,15 @@ CREATE TYPE guacamole_connection_group_type AS ENUM( 'BALANCING' ); +-- +-- Entity types +-- + +CREATE TYPE guacamole_entity_type AS ENUM( + 'USER', + 'USER_GROUP' +); + -- -- Object permission types -- @@ -46,6 +55,7 @@ CREATE TYPE guacamole_system_permission_type AS ENUM( 'CREATE_CONNECTION_GROUP', 'CREATE_SHARING_PROFILE', 'CREATE_USER', + 'CREATE_USER_GROUP', 'ADMINISTER' ); @@ -131,6 +141,26 @@ CREATE TABLE guacamole_connection ( CREATE INDEX guacamole_connection_parent_id ON guacamole_connection(parent_id); +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE guacamole_entity ( + + entity_id serial NOT NULL, + name varchar(128) NOT NULL, + type guacamole_entity_type NOT NULL, + + PRIMARY KEY (entity_id), + + CONSTRAINT guacamole_entity_name_scope + UNIQUE (type, name) + +); + -- -- Table of users. Each user has a unique username and a hashed password -- with corresponding salt. Although the authentication system will always set @@ -141,9 +171,9 @@ CREATE INDEX guacamole_connection_parent_id CREATE TABLE guacamole_user ( user_id serial NOT NULL, + entity_id integer NOT NULL, - -- Username and optionally-salted password - username varchar(128) NOT NULL, + -- Optionally-salted password password_hash bytea NOT NULL, password_salt bytea, password_date timestamptz NOT NULL, @@ -171,8 +201,62 @@ CREATE TABLE guacamole_user ( PRIMARY KEY (user_id), - CONSTRAINT username - UNIQUE (username) + CONSTRAINT guacamole_user_single_entity + UNIQUE (entity_id), + + CONSTRAINT guacamole_user_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE + +); + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE guacamole_user_group ( + + user_group_id serial NOT NULL, + entity_id integer NOT NULL, + + -- Group disabled status + disabled boolean NOT NULL DEFAULT FALSE, + + PRIMARY KEY (user_group_id), + + CONSTRAINT guacamole_user_group_single_entity + UNIQUE (entity_id), + + CONSTRAINT guacamole_user_group_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE + +); + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE guacamole_user_group_member ( + + user_group_id integer NOT NULL, + member_entity_id integer NOT NULL, + + PRIMARY KEY (user_group_id, member_entity_id), + + -- Parent must be a user group + CONSTRAINT guacamole_user_group_member_parent + FOREIGN KEY (user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT guacamole_user_group_member_entity + FOREIGN KEY (member_entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE ); @@ -275,6 +359,30 @@ CREATE TABLE guacamole_user_attribute ( CREATE INDEX guacamole_user_attribute_user_id ON guacamole_user_attribute(user_id); +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_user_group_attribute ( + + user_group_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (user_group_id, attribute_name), + + CONSTRAINT guacamole_user_group_attribute_ibfk_1 + FOREIGN KEY (user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_group_attribute_user_group_id + ON guacamole_user_group_attribute(user_group_id); + -- -- Table of arbitrary connection attributes. Each attribute is simply a -- name/value pair associated with a connection. Arbitrary attributes are @@ -348,141 +456,172 @@ CREATE INDEX guacamole_sharing_profile_attribute_sharing_profile_id ON guacamole_sharing_profile_attribute(sharing_profile_id); -- --- Table of connection permissions. Each connection permission grants a user --- specific access to a connection. +-- Table of connection permissions. Each connection permission grants a user or +-- user group specific access to a connection. -- CREATE TABLE guacamole_connection_permission ( - user_id integer NOT NULL, + entity_id integer NOT NULL, connection_id integer NOT NULL, permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (user_id,connection_id,permission), + PRIMARY KEY (entity_id, connection_id, permission), CONSTRAINT guacamole_connection_permission_ibfk_1 FOREIGN KEY (connection_id) REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE, - CONSTRAINT guacamole_connection_permission_ibfk_2 - FOREIGN KEY (user_id) - REFERENCES guacamole_user (user_id) ON DELETE CASCADE + CONSTRAINT guacamole_connection_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE ); CREATE INDEX guacamole_connection_permission_connection_id ON guacamole_connection_permission(connection_id); -CREATE INDEX guacamole_connection_permission_user_id - ON guacamole_connection_permission(user_id); +CREATE INDEX guacamole_connection_permission_entity_id + ON guacamole_connection_permission(entity_id); -- -- Table of connection group permissions. Each group permission grants a user --- specific access to a connection group. +-- or user group specific access to a connection group. -- CREATE TABLE guacamole_connection_group_permission ( - user_id integer NOT NULL, + entity_id integer NOT NULL, connection_group_id integer NOT NULL, permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (user_id,connection_group_id,permission), + PRIMARY KEY (entity_id, connection_group_id, permission), CONSTRAINT guacamole_connection_group_permission_ibfk_1 FOREIGN KEY (connection_group_id) REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE, - CONSTRAINT guacamole_connection_group_permission_ibfk_2 - FOREIGN KEY (user_id) - REFERENCES guacamole_user (user_id) ON DELETE CASCADE + CONSTRAINT guacamole_connection_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE ); CREATE INDEX guacamole_connection_group_permission_connection_group_id ON guacamole_connection_group_permission(connection_group_id); -CREATE INDEX guacamole_connection_group_permission_user_id - ON guacamole_connection_group_permission(user_id); +CREATE INDEX guacamole_connection_group_permission_entity_id + ON guacamole_connection_group_permission(entity_id); -- -- Table of sharing profile permissions. Each sharing profile permission grants --- a user specific access to a sharing profile. +-- a user or user group specific access to a sharing profile. -- CREATE TABLE guacamole_sharing_profile_permission ( - user_id integer NOT NULL, + entity_id integer NOT NULL, sharing_profile_id integer NOT NULL, permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (user_id,sharing_profile_id,permission), + PRIMARY KEY (entity_id, sharing_profile_id, permission), CONSTRAINT guacamole_sharing_profile_permission_ibfk_1 FOREIGN KEY (sharing_profile_id) REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE, - CONSTRAINT guacamole_sharing_profile_permission_ibfk_2 - FOREIGN KEY (user_id) - REFERENCES guacamole_user (user_id) ON DELETE CASCADE + CONSTRAINT guacamole_sharing_profile_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE ); CREATE INDEX guacamole_sharing_profile_permission_sharing_profile_id ON guacamole_sharing_profile_permission(sharing_profile_id); -CREATE INDEX guacamole_sharing_profile_permission_user_id - ON guacamole_sharing_profile_permission(user_id); +CREATE INDEX guacamole_sharing_profile_permission_entity_id + ON guacamole_sharing_profile_permission(entity_id); -- --- Table of system permissions. Each system permission grants a user a --- system-level privilege of some kind. +-- Table of system permissions. Each system permission grants a user or user +-- group a system-level privilege of some kind. -- CREATE TABLE guacamole_system_permission ( - user_id integer NOT NULL, + entity_id integer NOT NULL, permission guacamole_system_permission_type NOT NULL, - PRIMARY KEY (user_id,permission), + PRIMARY KEY (entity_id, permission), - CONSTRAINT guacamole_system_permission_ibfk_1 - FOREIGN KEY (user_id) - REFERENCES guacamole_user (user_id) ON DELETE CASCADE + CONSTRAINT guacamole_system_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE ); -CREATE INDEX guacamole_system_permission_user_id - ON guacamole_system_permission(user_id); +CREATE INDEX guacamole_system_permission_entity_id + ON guacamole_system_permission(entity_id); -- --- Table of user permissions. Each user permission grants a user access to --- another user (the "affected" user) for a specific type of operation. +-- Table of user permissions. Each user permission grants a user or user group +-- access to another user (the "affected" user) for a specific type of +-- operation. -- CREATE TABLE guacamole_user_permission ( - user_id integer NOT NULL, + entity_id integer NOT NULL, affected_user_id integer NOT NULL, permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (user_id,affected_user_id,permission), + PRIMARY KEY (entity_id, affected_user_id, permission), CONSTRAINT guacamole_user_permission_ibfk_1 FOREIGN KEY (affected_user_id) REFERENCES guacamole_user (user_id) ON DELETE CASCADE, - CONSTRAINT guacamole_user_permission_ibfk_2 - FOREIGN KEY (user_id) - REFERENCES guacamole_user (user_id) ON DELETE CASCADE + CONSTRAINT guacamole_user_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE ); CREATE INDEX guacamole_user_permission_affected_user_id ON guacamole_user_permission(affected_user_id); -CREATE INDEX guacamole_user_permission_user_id - ON guacamole_user_permission(user_id); +CREATE INDEX guacamole_user_permission_entity_id + ON guacamole_user_permission(entity_id); + +-- +-- Table of user group permissions. Each user group permission grants a user +-- or user group access to a another user group (the "affected" user group) for +-- a specific type of operation. +-- + +CREATE TABLE guacamole_user_group_permission ( + + entity_id integer NOT NULL, + affected_user_group_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, affected_user_group_id, permission), + + CONSTRAINT guacamole_user_group_permission_affected_user_group + FOREIGN KEY (affected_user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_user_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_group_permission_affected_user_group_id + ON guacamole_user_group_permission(affected_user_group_id); + +CREATE INDEX guacamole_user_group_permission_entity_id + ON guacamole_user_group_permission(entity_id); -- -- Table of connection history records. Each record defines a specific user's diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql index 47eebd248..c7cd7c910 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql @@ -17,36 +17,39 @@ -- under the License. -- - -- Create default user "guacadmin" with password "guacadmin" -INSERT INTO guacamole_user (username, password_hash, password_salt, password_date) -VALUES ('guacadmin', +INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER'); +INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date) +SELECT + entity_id, decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'), -- 'guacadmin' decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'), - CURRENT_TIMESTAMP); + CURRENT_TIMESTAMP +FROM guacamole_entity WHERE name = 'guacadmin' AND guacamole_entity.type = 'USER'; -- Grant this user all system permissions -INSERT INTO guacamole_system_permission -SELECT user_id, permission::guacamole_system_permission_type +INSERT INTO guacamole_system_permission (entity_id, permission) +SELECT entity_id, permission::guacamole_system_permission_type FROM ( VALUES ('guacadmin', 'CREATE_CONNECTION'), ('guacadmin', 'CREATE_CONNECTION_GROUP'), ('guacadmin', 'CREATE_SHARING_PROFILE'), ('guacadmin', 'CREATE_USER'), + ('guacadmin', 'CREATE_USER_GROUP'), ('guacadmin', 'ADMINISTER') ) permissions (username, permission) -JOIN guacamole_user ON permissions.username = guacamole_user.username; +JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'; -- Grant admin permission to read/update/administer self -INSERT INTO guacamole_user_permission -SELECT guacamole_user.user_id, affected.user_id, permission::guacamole_object_permission_type +INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission) +SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission::guacamole_object_permission_type FROM ( VALUES ('guacadmin', 'guacadmin', 'READ'), ('guacadmin', 'guacadmin', 'UPDATE'), ('guacadmin', 'guacadmin', 'ADMINISTER') ) permissions (username, affected_username, permission) -JOIN guacamole_user ON permissions.username = guacamole_user.username -JOIN guacamole_user affected ON permissions.affected_username = affected.username; - +JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER' +JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER' +JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql index db115c230..dd341dccd 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql @@ -17,6 +17,339 @@ -- under the License. -- +-- +-- Add new system-level permission +-- + +ALTER TYPE guacamole_system_permission_type + ADD VALUE 'CREATE_USER_GROUP' + AFTER 'CREATE_USER'; + +-- +-- Entity types +-- + +CREATE TYPE guacamole_entity_type AS ENUM( + 'USER', + 'USER_GROUP' +); + +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE guacamole_entity ( + + entity_id serial NOT NULL, + name varchar(128) NOT NULL, + type guacamole_entity_type NOT NULL, + + PRIMARY KEY (entity_id), + + CONSTRAINT guacamole_entity_name_scope + UNIQUE (type, name) + +); + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE guacamole_user_group ( + + user_group_id serial NOT NULL, + entity_id integer NOT NULL, + + -- Group disabled status + disabled boolean NOT NULL DEFAULT FALSE, + + PRIMARY KEY (user_group_id), + + CONSTRAINT guacamole_user_group_single_entity + UNIQUE (entity_id), + + CONSTRAINT guacamole_user_group_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE + +); + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE guacamole_user_group_member ( + + user_group_id integer NOT NULL, + member_entity_id integer NOT NULL, + + PRIMARY KEY (user_group_id, member_entity_id), + + -- Parent must be a user group + CONSTRAINT guacamole_user_group_member_parent + FOREIGN KEY (user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT guacamole_user_group_member_entity + FOREIGN KEY (member_entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +-- +-- Table of user group permissions. Each user group permission grants a user +-- access to a particular user group for a specific type of operation. +-- + +CREATE TABLE guacamole_user_group_permission ( + + entity_id integer NOT NULL, + affected_user_group_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, affected_user_group_id, permission), + + CONSTRAINT guacamole_user_group_permission_affected_user_group + FOREIGN KEY (affected_user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_user_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_group_permission_affected_user_group_id + ON guacamole_user_group_permission(affected_user_group_id); + +CREATE INDEX guacamole_user_group_permission_entity_id + ON guacamole_user_group_permission(entity_id); + +-- +-- Modify guacamole_user table to use guacamole_entity as a base +-- + +-- Add new entity_id column +ALTER TABLE guacamole_user ADD COLUMN entity_id integer; + +-- Create user entities for each guacamole_user entry +INSERT INTO guacamole_entity (name, type) +SELECT username, 'USER' FROM guacamole_user; + +-- Update guacamole_user to point to corresponding guacamole_entity +UPDATE guacamole_user SET entity_id = ( + SELECT entity_id FROM guacamole_entity + WHERE + username = guacamole_entity.name + AND type = 'USER' +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_user + ALTER COLUMN entity_id SET NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_user + ADD CONSTRAINT guacamole_user_single_entity + UNIQUE (entity_id); + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_user + ADD CONSTRAINT guacamole_user_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- The username column can now safely be removed +ALTER TABLE guacamole_user DROP COLUMN username; + +-- +-- Modify guacamole_connection_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_connection_permission ADD COLUMN entity_id integer; + +-- Update guacamole_connection_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_connection_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_connection_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_connection_permission + ALTER COLUMN entity_id SET NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_connection_permission + ADD CONSTRAINT guacamole_connection_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +CREATE INDEX guacamole_connection_permission_entity_id + ON guacamole_connection_permission(entity_id); + +-- Remove user_id column (implicitly drops associated contraints/keys) +ALTER TABLE guacamole_connection_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_connection_permission + ADD PRIMARY KEY (entity_id, connection_id, permission); + +-- +-- Modify guacamole_connection_group_permission to use guacamole_entity instead +-- of guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_connection_group_permission ADD COLUMN entity_id integer; + +-- Update guacamole_connection_group_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_connection_group_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_connection_group_permission + ALTER COLUMN entity_id SET NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_connection_group_permission + ADD CONSTRAINT guacamole_connection_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +CREATE INDEX guacamole_connection_group_permission_entity_id + ON guacamole_connection_group_permission(entity_id); + +-- Remove user_id column (implicitly drops associated contraints/keys) +ALTER TABLE guacamole_connection_group_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_connection_group_permission + ADD PRIMARY KEY (entity_id, connection_group_id, permission); + +-- +-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead +-- of guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_sharing_profile_permission ADD COLUMN entity_id integer; + +-- Update guacamole_sharing_profile_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_sharing_profile_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_sharing_profile_permission + ALTER COLUMN entity_id SET NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_sharing_profile_permission + ADD CONSTRAINT guacamole_sharing_profile_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +CREATE INDEX guacamole_sharing_profile_permission_entity_id + ON guacamole_sharing_profile_permission(entity_id); + +-- Remove user_id column (implicitly drops associated contraints/keys) +ALTER TABLE guacamole_sharing_profile_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_sharing_profile_permission + ADD PRIMARY KEY (entity_id, sharing_profile_id, permission); + +-- +-- Modify guacamole_user_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_user_permission ADD COLUMN entity_id integer; + +-- Update guacamole_user_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_user_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_user_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_user_permission + ALTER COLUMN entity_id SET NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_user_permission + ADD CONSTRAINT guacamole_user_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +CREATE INDEX guacamole_user_permission_entity_id + ON guacamole_user_permission(entity_id); + +-- Remove user_id column (implicitly drops associated contraints/keys) +ALTER TABLE guacamole_user_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_user_permission + ADD PRIMARY KEY (entity_id, affected_user_id, permission); + +-- +-- Modify guacamole_system_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_system_permission ADD COLUMN entity_id integer; + +-- Update guacamole_system_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_system_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_system_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_system_permission + ALTER COLUMN entity_id SET NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_system_permission + ADD CONSTRAINT guacamole_system_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +CREATE INDEX guacamole_system_permission_entity_id + ON guacamole_system_permission(entity_id); + +-- Remove user_id column (implicitly drops associated contraints/keys) +ALTER TABLE guacamole_system_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_system_permission + ADD PRIMARY KEY (entity_id, permission); + -- -- Table of arbitrary user attributes. Each attribute is simply a name/value -- pair associated with a user. Arbitrary attributes are defined by other @@ -41,6 +374,30 @@ CREATE TABLE guacamole_user_attribute ( CREATE INDEX guacamole_user_attribute_user_id ON guacamole_user_attribute(user_id); +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_user_group_attribute ( + + user_group_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (user_group_id, attribute_name), + + CONSTRAINT guacamole_user_group_attribute_ibfk_1 + FOREIGN KEY (user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_group_attribute_user_group_id + ON guacamole_user_group_attribute(user_group_id); + -- -- Table of arbitrary connection attributes. Each attribute is simply a -- name/value pair associated with a connection. Arbitrary attributes are From d95e05961275a773aa689adac6dae7d204426201 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Apr 2018 11:17:31 -0700 Subject: [PATCH 02/32] GUACAMOLE-220: Refactor user-related model objects and services to leverage the base "entity" model. --- .../guacamole/auth/jdbc/base/EntityModel.java | 113 ++++++++++++++++++ .../guacamole/auth/jdbc/base/EntityType.java | 38 ++++++ .../base/ModeledDirectoryObjectService.java | 3 +- .../ModeledObjectPermissionService.java | 3 +- .../permission/ObjectPermissionMapper.java | 20 ++-- .../jdbc/permission/PermissionMapper.java | 13 +- .../auth/jdbc/permission/PermissionModel.java | 50 ++------ .../permission/SystemPermissionMapper.java | 12 +- .../permission/SystemPermissionService.java | 3 +- .../guacamole/auth/jdbc/user/UserModel.java | 6 +- .../guacamole/auth/jdbc/user/UserService.java | 5 +- 11 files changed, 195 insertions(+), 71 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java new file mode 100644 index 000000000..c42db16b9 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +/** + * Base representation of a Guacamole object that can be granted permissions + * (an "entity"), such as a user or user group, as represented in the database. + * Each entity has three base properties: + * + * 1. The "entityID", which points to the common entry in the + * guacamole_entity table and is common to any type of entity. + * + * 2. The "objectID", which points to the type-specific entry for the object + * in question (ie: an entry in guacamole_user or guacamole_user_group). + * + * 3. The "identifier", which contains the unique "name" value defined for + * the entity within the guacamole_entity table. + */ +public abstract class EntityModel extends ObjectModel { + + /** + * The ID of the entity entry which corresponds to this object in the + * database, if any. Note that this is distinct from the objectID, + * inherited from ObjectModel, which is specific to the actual type of + * object represented by the entity. + */ + private Integer entityID; + + /** + * The type of object represented by the entity (user or user group). + */ + private EntityType type; + + /** + * Creates a new, empty entity. + */ + public EntityModel() { + } + + /** + * Creates a new entity of the given type which is otherwise empty. + * + * @param type + * The type to assign to the new entity. + */ + public EntityModel(EntityType type) { + this.type = type; + } + + /** + * Returns the ID of the entity entry which corresponds to this object in + * the database, if it exists. Note that this is distinct from the objectID, + * inherited from ObjectModel, which is specific to the actual type of + * object represented by the entity. + * + * @return + * The ID of this entity in the database, or null if this entity was + * not retrieved from the database. + */ + public Integer getEntityID() { + return entityID; + } + + /** + * Sets the ID of this entity to the given value. + * + * @param entityID + * The ID to assign to this entity. + */ + public void setEntityID(Integer entityID) { + this.entityID = entityID; + } + + /** + * Returns the type of object represented by the entity. Each entity may be + * either a user or a user group. + * + * @return + * The type of object represented by the entity. + */ + public EntityType getEntityType() { + return type; + } + + /** + * Sets the type of object represented by the entity. Each entity may be + * either a user or a user group. + * + * @param type + * The type of object represented by the entity. + */ + public void setEntityType(EntityType type) { + this.type = type; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java new file mode 100644 index 000000000..9b1f1edc9 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +/** + * The type of object represented by an entity. Each entity may represent + * either a user or a user group. + */ +public enum EntityType { + + /** + * An individual user. + */ + USER, + + /** + * A group of users and/or other groups. + */ + USER_GROUP + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java index 21508c471..3e3e707d5 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java @@ -432,8 +432,7 @@ public abstract class ModeledDirectoryObjectService selectAccessibleIdentifiers(@Param("user") UserModel user, + Collection selectAccessibleIdentifiers(@Param("entity") EntityModel entity, @Param("permissions") Collection permissions, @Param("identifiers") Collection identifiers); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java index d49dc30c3..7b476b362 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java @@ -20,7 +20,7 @@ package org.apache.guacamole.auth.jdbc.permission; import java.util.Collection; -import org.apache.guacamole.auth.jdbc.user.UserModel; +import org.apache.guacamole.auth.jdbc.base.EntityModel; import org.apache.ibatis.annotations.Param; /** @@ -32,15 +32,16 @@ import org.apache.ibatis.annotations.Param; public interface PermissionMapper { /** - * Retrieves all permissions associated with the given user. + * Retrieves all permissions associated with the given entity (user or user + * group). * - * @param user - * The user to retrieve permissions for. + * @param entity + * The entity to retrieve permissions for. * * @return - * All permissions associated with the given user. + * All permissions associated with the given entity. */ - Collection select(@Param("user") UserModel user); + Collection select(@Param("entity") EntityModel entity); /** * Inserts the given permissions into the database. If any permissions diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java index fbc3e8de4..da1ec2d28 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java @@ -21,7 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission; /** * Generic base permission model which grants a permission of a particular type - * to a specific user. + * to a specific entity (user or user group). * * @param * The type of permissions allowed within this model. @@ -29,14 +29,9 @@ package org.apache.guacamole.auth.jdbc.permission; public abstract class PermissionModel { /** - * The database ID of the user to whom this permission is granted. + * The database ID of the entity to whom this permission is granted. */ - private Integer userID; - - /** - * The username of the user to whom this permission is granted. - */ - private String username; + private Integer entityID; /** * The type of action granted by this permission. @@ -44,43 +39,24 @@ public abstract class PermissionModel { private PermissionType type; /** - * Returns the database ID of the user to whom this permission is granted. + * Returns the database ID of the entity to whom this permission is + * granted. * * @return - * The database ID of the user to whom this permission is granted. + * The database ID of the entity to whom this permission is granted. */ - public Integer getUserID() { - return userID; + public Integer getEntityID() { + return entityID; } /** - * Sets the database ID of the user to whom this permission is granted. + * Sets the database ID of the entity to whom this permission is granted. * - * @param userID - * The database ID of the user to whom this permission is granted. + * @param entityID + * The database ID of the entity to whom this permission is granted. */ - public void setUserID(Integer userID) { - this.userID = userID; - } - - /** - * Returns the username of the user to whom this permission is granted. - * - * @return - * The username of the user to whom this permission is granted. - */ - public String getUsername() { - return username; - } - - /** - * Sets the username of the user to whom this permission is granted. - * - * @param username - * The username of the user to whom this permission is granted. - */ - public void setUsername(String username) { - this.username = username; + public void setEntityID(Integer entityID) { + this.entityID = entityID; } /** diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java index 929d6e9aa..738062c2a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java @@ -19,7 +19,7 @@ package org.apache.guacamole.auth.jdbc.permission; -import org.apache.guacamole.auth.jdbc.user.UserModel; +import org.apache.guacamole.auth.jdbc.base.EntityModel; import org.apache.ibatis.annotations.Param; import org.apache.guacamole.net.auth.permission.SystemPermission; @@ -30,19 +30,19 @@ public interface SystemPermissionMapper extends PermissionMapper Date: Tue, 3 Apr 2018 14:23:56 -0700 Subject: [PATCH 03/32] GUACAMOLE-220: Update SQL queries to use guacamole_entity table where applicable. --- .../auth/jdbc/connection/ConnectionMapper.xml | 10 +-- .../connection/ConnectionRecordMapper.xml | 10 ++- .../connectiongroup/ConnectionGroupMapper.xml | 12 +-- .../ConnectionGroupPermissionMapper.xml | 35 ++++----- .../permission/ConnectionPermissionMapper.xml | 35 ++++----- .../SharingProfilePermissionMapper.xml | 35 ++++----- .../permission/SystemPermissionMapper.xml | 31 ++++---- .../jdbc/permission/UserPermissionMapper.xml | 77 ++++++++++--------- .../sharingprofile/SharingProfileMapper.xml | 6 +- .../auth/jdbc/user/PasswordRecordMapper.xml | 3 +- .../guacamole/auth/jdbc/user/UserMapper.xml | 70 +++++++++++------ .../auth/jdbc/user/UserRecordMapper.xml | 23 ++++-- 12 files changed, 188 insertions(+), 159 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index 0b109f6ba..c238c78e7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -68,7 +68,7 @@ SELECT connection_id FROM guacamole_connection_permission WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' @@ -89,7 +89,7 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' @@ -165,7 +165,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_connection_permission.entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' GROUP BY guacamole_connection.connection_id; @@ -177,7 +177,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; SELECT @@ -191,7 +191,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index 4545332b5..b4407bd08 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -79,7 +79,10 @@ #{record.sharingProfileIdentifier,jdbcType=INTEGER}::integer, #{record.sharingProfileName,jdbcType=VARCHAR}, (SELECT user_id FROM guacamole_user - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{record.username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'::guacamole_entity_type), #{record.username,jdbcType=VARCHAR}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} @@ -180,7 +183,10 @@ guacamole_connection_history.user_id IN ( SELECT user_id FROM guacamole_user - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 + AND guacamole_entity.type = 'USER'::guacamole_entity_type ) OR guacamole_connection_history.connection_id IN ( diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 7cc4ac7fa..7e0b1883e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -69,7 +69,7 @@ SELECT connection_group_id FROM guacamole_connection_group_permission WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' @@ -90,7 +90,7 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' @@ -161,7 +161,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id @@ -172,7 +172,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id @@ -183,7 +183,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; SELECT @@ -197,7 +197,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index 5ab114a43..c8ec936fc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -25,24 +25,21 @@ - - + - + @@ -50,26 +47,24 @@ - + SELECT - guacamole_connection_permission.user_id, - username, + entity_id, permission, connection_id FROM guacamole_connection_permission - JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id - WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} + WHERE entity_id = #{entity.entityID,jdbcType=INTEGER} @@ -50,26 +47,24 @@ - + SELECT - guacamole_sharing_profile_permission.user_id, - username, + entity_id, permission, sharing_profile_id FROM guacamole_sharing_profile_permission - JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id - WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER} + WHERE entity_id = #{entity.entityID,jdbcType=INTEGER} @@ -50,26 +47,24 @@ - + SELECT - guacamole_system_permission.user_id, - username, + entity_id, permission FROM guacamole_system_permission - JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id - WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} + WHERE entity_id = #{entity.entityID,jdbcType=INTEGER} @@ -48,13 +45,11 @@ @@ -63,10 +58,10 @@ DELETE FROM guacamole_system_permission - WHERE (user_id, permission) IN + WHERE (entity_id, permission) IN - (#{permission.userID,jdbcType=INTEGER}, + (#{permission.entityID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type) @@ -76,22 +71,22 @@ INSERT INTO guacamole_system_permission ( - user_id, + entity_id, permission ) SELECT DISTINCT - permissions.user_id, + permissions.entity_id, permissions.permission FROM - SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type AS permission AS permissions - WHERE (user_id, permission) NOT IN ( + WHERE (entity_id, permission) NOT IN ( SELECT - guacamole_system_permission.user_id, + guacamole_system_permission.entity_id, guacamole_system_permission.permission FROM guacamole_system_permission ); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index 0126ae570..d6680ea98 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -25,25 +25,25 @@ - - + - + - + @@ -51,38 +51,40 @@ - + @@ -90,16 +92,18 @@ DELETE FROM guacamole_user_permission - USING guacamole_user affected + USING guacamole_user affected_user, guacamole_entity affected_entity WHERE - guacamole_user_permission.affected_user_id = affected.user_id - AND (guacamole_user_permission.user_id, permission, affected.username) IN + guacamole_user_permission.affected_user_id = affected_user.user_id + AND affected_user.entity_id = affected_entity.entity_id + AND (guacamole_user_permission.entity_id, permission, affected_entity.name) IN - (#{permission.userID,jdbcType=INTEGER}, + (#{permission.entityID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.objectIdentifier,jdbcType=INTEGER}) + AND affected_entity.type = 'USER'::guacamole_entity_type @@ -107,26 +111,29 @@ INSERT INTO guacamole_user_permission ( - user_id, + entity_id, permission, affected_user_id ) SELECT DISTINCT - permissions.user_id, + permissions.entity_id, permissions.permission, - guacamole_user.user_id + affected_user.user_id FROM - SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, - #{permission.objectIdentifier,jdbcType=INTEGER} AS username + #{permission.objectIdentifier,jdbcType=VARCHAR}::text AS affected_name AS permissions - JOIN guacamole_user ON guacamole_user.username = permissions.username - WHERE (permissions.user_id, permissions.permission, guacamole_user.user_id) NOT IN ( + JOIN guacamole_entity affected_entity ON + affected_entity.name = permissions.affected_name + AND affected_entity.type = 'USER'::guacamole_entity_type + JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id + WHERE (permissions.entity_id, permissions.permission, affected_user.user_id) NOT IN ( SELECT - guacamole_user_permission.user_id, + guacamole_user_permission.entity_id, guacamole_user_permission.permission, guacamole_user_permission.affected_user_id FROM guacamole_user_permission diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index 801d6e363..66bd7019d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -52,7 +52,7 @@ SELECT sharing_profile_id FROM guacamole_sharing_profile_permission WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' @@ -99,7 +99,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; SELECT @@ -113,7 +113,7 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml index 41591fada..e9c857afd 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml @@ -41,8 +41,9 @@ guacamole_user_password_history.password_date FROM guacamole_user_password_history JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id WHERE - guacamole_user.username = #{username,jdbcType=VARCHAR} + guacamole_entity.name = #{username,jdbcType=VARCHAR} ORDER BY guacamole_user_password_history.password_date DESC LIMIT #{maxHistorySize} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index e183fe295..796962d69 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -28,7 +28,8 @@ - + + @@ -57,17 +58,20 @@ @@ -77,7 +81,8 @@ SELECT guacamole_user.user_id, - guacamole_user.username, + guacamole_entity.entity_id, + guacamole_entity.name, password_hash, password_salt, password_date, @@ -94,13 +99,15 @@ organizational_role, MAX(start_date) AS last_active FROM guacamole_user + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id - WHERE guacamole_user.username IN + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - GROUP BY guacamole_user.user_id; + AND guacamole_entity.type = 'USER'::guacamole_entity_type + GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; SELECT guacamole_user_attribute.user_id, @@ -108,11 +115,13 @@ guacamole_user_attribute.attribute_value FROM guacamole_user_attribute JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id - WHERE username IN + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - ; + + AND guacamole_entity.type = 'USER'::guacamole_entity_type; @@ -122,7 +131,8 @@ SELECT guacamole_user.user_id, - guacamole_user.username, + guacamole_entity.entity_id, + guacamole_entity.name, password_hash, password_salt, password_date, @@ -139,16 +149,18 @@ organizational_role, MAX(start_date) AS last_active FROM guacamole_user + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id - WHERE guacamole_user.username IN + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER'::guacamole_entity_type + AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ' - GROUP BY guacamole_user.user_id; + GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; SELECT guacamole_user_attribute.user_id, @@ -156,13 +168,15 @@ guacamole_user_attribute.attribute_value FROM guacamole_user_attribute JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id - WHERE username IN + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER'::guacamole_entity_type + AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER} AND permission = 'READ'; @@ -173,7 +187,8 @@ SELECT guacamole_user.user_id, - guacamole_user.username, + guacamole_entity.entity_id, + guacamole_entity.name, password_hash, password_salt, password_date, @@ -190,10 +205,12 @@ organizational_role, MAX(start_date) AS last_active FROM guacamole_user + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id WHERE - guacamole_user.username = #{username,jdbcType=VARCHAR} - GROUP BY guacamole_user.user_id; + guacamole_entity.name = #{username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'::guacamole_entity_type + GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; SELECT guacamole_user_attribute.user_id, @@ -201,14 +218,19 @@ guacamole_user_attribute.attribute_value FROM guacamole_user_attribute JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id - WHERE username = #{username,jdbcType=VARCHAR}; + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'::guacamole_entity_type - DELETE FROM guacamole_user - WHERE username = #{identifier,jdbcType=VARCHAR} + DELETE FROM guacamole_entity + WHERE + name = #{identifier,jdbcType=VARCHAR} + AND type = 'USER'::guacamole_entity_type @@ -216,7 +238,7 @@ parameterType="org.apache.guacamole.auth.jdbc.user.UserModel"> INSERT INTO guacamole_user ( - username, + entity_id, password_hash, password_salt, password_date, @@ -233,7 +255,7 @@ organizational_role ) VALUES ( - #{object.identifier,jdbcType=VARCHAR}, + #{object.entityID,jdbcType=VARCHAR}, #{object.passwordHash,jdbcType=BINARY}, #{object.passwordSalt,jdbcType=BINARY}, #{object.passwordDate,jdbcType=TIMESTAMP}, diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml index 014b38aca..20cb2a809 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml @@ -44,8 +44,9 @@ guacamole_user_history.end_date FROM guacamole_user_history JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id WHERE - guacamole_user.username = #{username,jdbcType=VARCHAR} + guacamole_entity.name = #{username,jdbcType=VARCHAR} ORDER BY guacamole_user_history.start_date DESC, guacamole_user_history.end_date DESC @@ -66,7 +67,10 @@ VALUES ( #{record.remoteHost,jdbcType=VARCHAR}, (SELECT user_id FROM guacamole_user - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{record.username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'::guacamole_entity_type), #{record.username,jdbcType=VARCHAR}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} @@ -79,7 +83,10 @@ UPDATE guacamole_user_history SET remote_host = #{record.remoteHost,jdbcType=VARCHAR}, user_id = (SELECT user_id FROM guacamole_user - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{record.username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'::guacamole_entity_type), username = #{record.username,jdbcType=VARCHAR}, start_date = #{record.startDate,jdbcType=TIMESTAMP}, end_date = #{record.endDate,jdbcType=TIMESTAMP} @@ -105,7 +112,10 @@ guacamole_user_history.user_id IN ( SELECT user_id FROM guacamole_user - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 + AND guacamole_entity.type = 'USER'::guacamole_entity_type), ) @@ -157,7 +167,10 @@ guacamole_user_history.user_id IN ( SELECT user_id FROM guacamole_user - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 + AND guacamole_entity.type = 'USER'::guacamole_entity_type ) From 72bac09f433de23654b66dbee0f2d5fd6a55e48c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Apr 2018 17:53:26 -0700 Subject: [PATCH 04/32] GUACAMOLE-220: Add explicit mapper for entities (the basis for users and groups). --- .../JDBCAuthenticationProviderModule.java | 2 + .../auth/jdbc/base/EntityMapper.java | 43 +++++++++++++++++++ .../guacamole/auth/jdbc/user/UserService.java | 10 +++++ .../guacamole/auth/jdbc/base/EntityMapper.xml | 41 ++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 0f72559e2..17dfc5db0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -59,6 +59,7 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet; import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; +import org.apache.guacamole.auth.jdbc.base.EntityMapper; import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService; @@ -120,6 +121,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { addMapperClass(ConnectionPermissionMapper.class); addMapperClass(ConnectionRecordMapper.class); addMapperClass(ConnectionParameterMapper.class); + addMapperClass(EntityMapper.class); addMapperClass(PasswordRecordMapper.class); addMapperClass(SystemPermissionMapper.class); addMapperClass(SharingProfileMapper.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java new file mode 100644 index 000000000..14657ce26 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +import org.apache.ibatis.annotations.Param; + +/** + * Mapper for entities. An entity is the base concept behind a user or user + * group, and serves as a common point for granting permissions and defining + * group membership. + */ +public interface EntityMapper { + + /** + * Inserts the given entity into the database. If the entity already + * exists, this will result in an error. + * + * @param entity + * The entity to insert. + * + * @return + * The number of rows inserted. + */ + int insert(@Param("entity") EntityModel entity); + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java index e4bb738d8..9f7fb8761 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java @@ -37,6 +37,7 @@ import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate; +import org.apache.guacamole.auth.jdbc.base.EntityMapper; import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel; @@ -113,6 +114,12 @@ public class UserService extends ModeledDirectoryObjectService + + + + + + + + + + INSERT INTO guacamole_entity ( + name, + type + ) + VALUES ( + #{entity.identifier,jdbcType=VARCHAR}, + #{entity.entityType,jdbcType=VARCHAR}::guacamole_entity_type + ) + + + + From 0a69630cbb0f80cd819136dce4127dfa6366e1a2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 3 Apr 2018 21:32:38 -0700 Subject: [PATCH 05/32] GUACAMOLE-220: Implement base API changes within database auth allowing for permission inheritance. --- .../ActiveConnectionPermissionService.java | 26 ++++---- .../ConnectionGroupPermissionService.java | 4 +- .../ConnectionPermissionService.java | 4 +- .../ModeledObjectPermissionService.java | 23 +++----- .../permission/ModeledPermissionService.java | 12 ++-- .../permission/ObjectPermissionMapper.java | 20 +++++-- .../permission/ObjectPermissionService.java | 27 ++++++--- .../jdbc/permission/ObjectPermissionSet.java | 23 ++++++-- .../jdbc/permission/PermissionMapper.java | 8 ++- .../jdbc/permission/PermissionService.java | 19 +++--- .../SharingProfilePermissionService.java | 4 +- .../permission/SystemPermissionMapper.java | 10 +++- .../permission/SystemPermissionService.java | 35 ++++++----- .../jdbc/permission/SystemPermissionSet.java | 19 +++++- .../permission/UserPermissionService.java | 4 +- .../guacamole/auth/jdbc/user/ModeledUser.java | 59 ++++++++++++++++--- 16 files changed, 198 insertions(+), 99 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java index 91ad11d7e..405b23761 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java @@ -23,7 +23,6 @@ import com.google.inject.Inject; import com.google.inject.Provider; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.guacamole.GuacamoleException; @@ -58,26 +57,23 @@ public class ActiveConnectionPermissionService private Provider activeConnectionPermissionSetProvider; @Override - public ObjectPermission retrievePermission(ModeledAuthenticatedUser user, + public boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, ObjectPermission.Type type, - String identifier) throws GuacamoleException { + String identifier, boolean inherit) throws GuacamoleException { // Retrieve permissions - Set permissions = retrievePermissions(user, targetUser); + Set permissions = retrievePermissions(user, targetUser, inherit); - // If retrieved permissions contains the requested permission, return it + // Permission is granted if retrieved permissions contains the + // requested permission ObjectPermission permission = new ObjectPermission(type, identifier); - if (permissions.contains(permission)) - return permission; - - // Otherwise, no such permission - return null; + return permissions.contains(permission); } @Override public Set retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Retrieve permissions only if allowed if (canReadPermissions(user, targetUser)) { @@ -113,9 +109,9 @@ public class ActiveConnectionPermissionService @Override public Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, ModeledUser targetUser, Collection permissionTypes, - Collection identifiers) throws GuacamoleException { + Collection identifiers, boolean inherit) throws GuacamoleException { - Set permissions = retrievePermissions(user, targetUser); + Set permissions = retrievePermissions(user, targetUser, inherit); Collection accessibleObjects = new ArrayList(permissions.size()); // For each identifier/permission combination @@ -138,11 +134,11 @@ public class ActiveConnectionPermissionService @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Create permission set for requested user ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get(); - permissionSet.init(user, targetUser); + permissionSet.init(user, targetUser, inherit); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java index 68fc3ed4b..3027d8123 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java @@ -51,11 +51,11 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get(); - permissionSet.init(user, targetUser); + permissionSet.init(user, targetUser, inherit); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java index 80c4b0b43..19c30c0be 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java @@ -51,11 +51,11 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get(); - permissionSet.init(user, targetUser); + permissionSet.init(user, targetUser, inherit); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java index 9197217bc..30ea5d78a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java @@ -105,7 +105,7 @@ public abstract class ModeledObjectPermissionService affectedIdentifiers.add(permission.getObjectIdentifier()); // Determine subset of affected identifiers that we have admin access to - ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser()); + ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), true); Collection allowedSubset = affectedPermissionSet.getAccessibleObjects( Collections.singleton(ObjectPermission.Type.ADMINISTER), affectedIdentifiers @@ -154,21 +154,13 @@ public abstract class ModeledObjectPermissionService } @Override - public ObjectPermission retrievePermission(ModeledAuthenticatedUser user, + public boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, ObjectPermission.Type type, - String identifier) throws GuacamoleException { + String identifier, boolean inherit) throws GuacamoleException { // Retrieve permissions only if allowed - if (canReadPermissions(user, targetUser)) { - - // Read permission from database, return null if not found - ObjectPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type, identifier); - if (model == null) - return null; - - return getPermissionInstance(model); - - } + if (canReadPermissions(user, targetUser)) + return getPermissionMapper().selectOne(targetUser.getModel(), type, identifier, inherit) != null; // User cannot read this user's permissions throw new GuacamoleSecurityException("Permission denied."); @@ -178,7 +170,8 @@ public abstract class ModeledObjectPermissionService @Override public Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, ModeledUser targetUser, Collection permissions, - Collection identifiers) throws GuacamoleException { + Collection identifiers, boolean inherit) + throws GuacamoleException { // Nothing is always accessible if (identifiers.isEmpty()) @@ -192,7 +185,7 @@ public abstract class ModeledObjectPermissionService return identifiers; // Otherwise, return explicitly-retrievable identifiers - return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers); + return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers, inherit); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java index 28008451f..4d0fcf61f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java @@ -92,7 +92,7 @@ public abstract class ModeledPermissionService getModelInstances(ModeledUser targetUser, Collection permissions) { - // Create new collection of models by manually converting each permission + // Create new collection of models by manually converting each permission Collection models = new ArrayList(permissions.size()); for (PermissionType permission : permissions) models.add(getModelInstance(targetUser, permission)); @@ -140,15 +140,15 @@ public abstract class ModeledPermissionService retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Retrieve permissions only if allowed if (canReadPermissions(user, targetUser)) - return getPermissionInstances(getPermissionMapper().select(targetUser.getModel())); + return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), inherit)); // User cannot read this user's permissions throw new GuacamoleSecurityException("Permission denied."); - + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java index f744fbf89..e5efad09c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java @@ -36,20 +36,26 @@ public interface ObjectPermissionMapper extends PermissionMapper selectAccessibleIdentifiers(@Param("entity") EntityModel entity, @Param("permissions") Collection permissions, - @Param("identifiers") Collection identifiers); + @Param("identifiers") Collection identifiers, + @Param("inherit") boolean inherit); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java index 5eead24e1..fa1ee2d76 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java @@ -35,31 +35,36 @@ public interface ObjectPermissionService extends PermissionService { /** - * Retrieves the permission of the given type associated with the given - * user and object, if it exists. If no such permission exists, null is + * Returns whether the permission of the given type and associated with the + * given object has been granted to the given user. * * @param user * The user retrieving the permission. * * @param targetUser * The user associated with the permission to be retrieved. - * + * * @param type * The type of permission to retrieve. * * @param identifier * The identifier of the object affected by the permission to return. * + * @param inherit + * Whether permissions inherited through user groups should be taken + * into account. If false, only permissions granted directly will be + * included. + * * @return - * The permission of the given type associated with the given user and - * object, or null if no such permission exists. + * true if permission of the given type and associated with the given + * object has been granted to the given user, false otherwise. * * @throws GuacamoleException * If an error occurs while retrieving the requested permission. */ - ObjectPermission retrievePermission(ModeledAuthenticatedUser user, + boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, ObjectPermission.Type type, - String identifier) throws GuacamoleException; + String identifier, boolean inherit) throws GuacamoleException; /** * Retrieves the subset of the given identifiers for which the given user @@ -80,6 +85,11 @@ public interface ObjectPermissionService * The identifiers of the objects affected by the permissions being * checked. * + * @param inherit + * Whether permissions inherited through user groups should be taken + * into account. If false, only permissions granted directly will be + * included. + * * @return * A collection containing the subset of identifiers for which at least * one of the specified permissions is granted. @@ -89,6 +99,7 @@ public interface ObjectPermissionService */ Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, ModeledUser targetUser, Collection permissions, - Collection identifiers) throws GuacamoleException; + Collection identifiers, boolean inherit) + throws GuacamoleException; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java index 712a42242..cedb45dd3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java @@ -42,6 +42,12 @@ public abstract class ObjectPermissionSet extends RestrictedObject */ private ModeledUser user; + /** + * Whether permissions inherited through user groups should be taken into + * account. If false, only permissions granted directly will be included. + */ + boolean inherit; + /** * Creates a new ObjectPermissionSet. The resulting permission set * must still be initialized by a call to init(), or the information @@ -60,10 +66,17 @@ public abstract class ObjectPermissionSet extends RestrictedObject * * @param user * The user to whom the permissions in this set are granted. + * + * @param inherit + * Whether permissions inherited through user groups should be taken + * into account. If false, only permissions granted directly will be + * included. */ - public void init(ModeledAuthenticatedUser currentUser, ModeledUser user) { + public void init(ModeledAuthenticatedUser currentUser, ModeledUser user, + boolean inherit) { super.init(currentUser); this.user = user; + this.inherit = inherit; } /** @@ -75,16 +88,16 @@ public abstract class ObjectPermissionSet extends RestrictedObject * permissions contained within this permission set. */ protected abstract ObjectPermissionService getObjectPermissionService(); - + @Override public Set getPermissions() throws GuacamoleException { - return getObjectPermissionService().retrievePermissions(getCurrentUser(), user); + return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, inherit); } @Override public boolean hasPermission(ObjectPermission.Type permission, String identifier) throws GuacamoleException { - return getObjectPermissionService().retrievePermission(getCurrentUser(), user, permission, identifier) != null; + return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, inherit); } @Override @@ -102,7 +115,7 @@ public abstract class ObjectPermissionSet extends RestrictedObject @Override public Collection getAccessibleObjects(Collection permissions, Collection identifiers) throws GuacamoleException { - return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers); + return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, inherit); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java index 7b476b362..1c2d23b76 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java @@ -38,10 +38,16 @@ public interface PermissionMapper { * @param entity * The entity to retrieve permissions for. * + * @param inherit + * Whether permissions inherited through user groups should be taken + * into account. If false, only permissions granted directly will be + * included. + * * @return * All permissions associated with the given entity. */ - Collection select(@Param("entity") EntityModel entity); + Collection select(@Param("entity") EntityModel entity, + @Param("inherit") boolean inherit); /** * Inserts the given permissions into the database. If any permissions diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java index 12b046b4d..6e596346e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java @@ -19,16 +19,11 @@ package org.apache.guacamole.auth.jdbc.permission; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleSecurityException; -import org.apache.guacamole.net.auth.permission.ObjectPermission; -import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.PermissionSet; @@ -59,6 +54,11 @@ public interface PermissionService retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException; + ModeledUser targetUser, boolean inherit) throws GuacamoleException; /** * Creates the given permissions within the database. If any permissions diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java index ac16fc2c7..3cdf9d160 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java @@ -51,11 +51,11 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get(); - permissionSet.init(user, targetUser); + permissionSet.init(user, targetUser, inherit); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java index 738062c2a..c05f4053a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java @@ -34,15 +34,21 @@ public interface SystemPermissionMapper extends PermissionMapper getPermissions() throws GuacamoleException { - return systemPermissionService.retrievePermissions(getCurrentUser(), user); + return systemPermissionService.retrievePermissions(getCurrentUser(), user, inherit); } @Override public boolean hasPermission(SystemPermission.Type permission) throws GuacamoleException { - return systemPermissionService.retrievePermission(getCurrentUser(), user, permission) != null; + return systemPermissionService.hasPermission(getCurrentUser(), user, permission, inherit); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java index d56ed28bc..8e6586257 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java @@ -51,11 +51,11 @@ public class UserPermissionService extends ModeledObjectPermissionService { @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser) throws GuacamoleException { + ModeledUser targetUser, boolean inherit) throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = userPermissionSetProvider.get(); - permissionSet.init(user, targetUser); + permissionSet.init(user, targetUser, inherit); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 583aa7fc1..39f163621 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -350,37 +350,37 @@ public class ModeledUser extends ModeledDirectoryObject implements Us @Override public SystemPermissionSet getSystemPermissions() throws GuacamoleException { - return systemPermissionService.getPermissionSet(getCurrentUser(), this); + return systemPermissionService.getPermissionSet(getCurrentUser(), this, false); } @Override public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException { - return connectionPermissionService.getPermissionSet(getCurrentUser(), this); + return connectionPermissionService.getPermissionSet(getCurrentUser(), this, false); } @Override public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException { - return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this); + return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this, false); } @Override public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException { - return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this); + return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this, false); } @Override public ObjectPermissionSet getActiveConnectionPermissions() throws GuacamoleException { - return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this); + return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this, false); } @Override public ObjectPermissionSet getUserPermissions() throws GuacamoleException { - return userPermissionService.getPermissionSet(getCurrentUser(), this); + return userPermissionService.getPermissionSet(getCurrentUser(), this, false); } @Override @@ -855,7 +855,52 @@ public class ModeledUser extends ModeledDirectoryObject implements Us @Override public Permissions getEffectivePermissions() throws GuacamoleException { - return this; + return new Permissions() { + + @Override + public ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException { + return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + } + + @Override + public ObjectPermissionSet getConnectionGroupPermissions() + throws GuacamoleException { + return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + } + + @Override + public ObjectPermissionSet getConnectionPermissions() + throws GuacamoleException { + return connectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + } + + @Override + public ObjectPermissionSet getSharingProfilePermissions() + throws GuacamoleException { + return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + } + + @Override + public SystemPermissionSet getSystemPermissions() + throws GuacamoleException { + return systemPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + } + + @Override + public ObjectPermissionSet getUserPermissions() + throws GuacamoleException { + return userPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + } + + @Override + public ObjectPermissionSet getUserGroupPermissions() + throws GuacamoleException { + // FIXME: STUB + return new SimpleObjectPermissionSet(); + } + + }; } } From 199f518cdb7e888de1f574d871e5f3847041a327 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 8 Apr 2018 00:16:12 -0700 Subject: [PATCH 06/32] GUACAMOLE-220: Use effective permissions when deciding whether a user has permission to perform an action. --- .../base/ModeledChildDirectoryObjectService.java | 7 ++++--- .../jdbc/base/ModeledDirectoryObjectService.java | 13 ++++++++----- .../auth/jdbc/connection/ConnectionService.java | 10 +++++----- .../connectiongroup/ConnectionGroupService.java | 10 +++++----- .../jdbc/permission/AbstractPermissionService.java | 4 ++-- .../permission/ModeledObjectPermissionService.java | 3 ++- .../jdbc/sharingprofile/SharingProfileService.java | 10 +++++----- .../guacamole/auth/jdbc/user/ModeledUser.java | 5 +++-- .../guacamole/auth/jdbc/user/UserService.java | 6 +++--- 9 files changed, 37 insertions(+), 31 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java index 74ca5bb34..f517e2788 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java @@ -53,7 +53,8 @@ public abstract class ModeledChildDirectoryObjectService modifiedParents = getModifiedParents(user, identifier, model); if (!modifiedParents.isEmpty()) { - ObjectPermissionSet permissionSet = getParentPermissionSet(user); + ObjectPermissionSet permissionSet = getParentEffectivePermissionSet(user); Collection updateableParents = permissionSet.getAccessibleObjects( Collections.singleton(ObjectPermission.Type.UPDATE), modifiedParents diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java index 3e3e707d5..e87d6649f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java @@ -126,7 +126,8 @@ public abstract class ModeledDirectoryObjectService implements Us /** * Returns whether this user is a system administrator, and thus is not - * restricted by permissions. + * restricted by permissions, taking into account permission inheritance + * via user groups. * * @return * true if this user is a system administrator, false otherwise. @@ -343,7 +344,7 @@ public class ModeledUser extends ModeledDirectoryObject implements Us * status. */ public boolean isAdministrator() throws GuacamoleException { - SystemPermissionSet systemPermissionSet = getSystemPermissions(); + SystemPermissionSet systemPermissionSet = getEffectivePermissions().getSystemPermissions(); return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java index 9f7fb8761..2c70e2201 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java @@ -216,17 +216,17 @@ public class UserService extends ModeledDirectoryObjectService Date: Wed, 4 Apr 2018 21:07:49 -0700 Subject: [PATCH 07/32] GUACAMOLE-220: Implement permission inheritance within SQL queries. --- .../modules/guacamole-auth-jdbc-base/pom.xml | 10 ++--- .../guacamole/auth/jdbc/base/EntityMapper.xml | 17 ++++++++ .../auth/jdbc/connection/ConnectionMapper.xml | 35 +++++++++++++--- .../connection/ConnectionRecordMapper.xml | 14 ++++++- .../connectiongroup/ConnectionGroupMapper.xml | 42 ++++++++++++++++--- .../ConnectionGroupPermissionMapper.xml | 26 +++++++++--- .../permission/ConnectionPermissionMapper.xml | 26 +++++++++--- .../SharingProfilePermissionMapper.xml | 27 +++++++++--- .../permission/SystemPermissionMapper.xml | 23 +++++++--- .../jdbc/permission/UserPermissionMapper.xml | 25 ++++++++--- .../sharingprofile/SharingProfileMapper.xml | 21 ++++++++-- .../guacamole/auth/jdbc/user/UserMapper.xml | 21 ++++++++-- .../auth/jdbc/user/UserRecordMapper.xml | 7 +++- 13 files changed, 243 insertions(+), 51 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml index d99534c91..ab56499c2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml @@ -109,33 +109,33 @@ org.mybatis mybatis - 3.2.8 + 3.4.6 org.mybatis mybatis-guice - 3.6 + 3.10 com.google.inject guice - 3.0 + 4.1.0 com.google.inject.extensions guice-multibindings - 3.0 + 4.1.0 com.google.guava guava - 18.0 + 19.0 diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml index f05c2875b..dd262d1e9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -23,6 +23,23 @@ + + + ${entityID} + + WITH RECURSIVE related_entity(entity_id) AS ( + VALUES (${entityID}) + UNION + SELECT guacamole_user_group.entity_id + FROM related_entity + JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id + JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id + ) + SELECT entity_id FROM related_entity + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index c238c78e7..94855e168 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -68,7 +68,12 @@ SELECT connection_id FROM guacamole_connection_permission WHERE - entity_id = #{user.entityID,jdbcType=INTEGER} + entity_id IN ( + + + + + ) AND permission = 'READ' @@ -89,7 +94,12 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ' @@ -165,7 +175,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND guacamole_connection_permission.entity_id = #{user.entityID,jdbcType=INTEGER} + AND guacamole_connection_permission.entity_id IN ( + + + + + ) AND permission = 'READ' GROUP BY guacamole_connection.connection_id; @@ -177,7 +192,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; SELECT @@ -191,7 +211,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index b4407bd08..b04c9ca6f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -166,13 +166,23 @@ JOIN guacamole_connection_permission ON guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id - AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_connection_permission.entity_id IN ( + + + + + ) AND guacamole_connection_permission.permission = 'READ' JOIN guacamole_user_permission ON guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_user_permission.entity_id IN ( + + + + + ) AND guacamole_user_permission.permission = 'READ' diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 7e0b1883e..ffca72d25 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -69,7 +69,12 @@ SELECT connection_group_id FROM guacamole_connection_group_permission WHERE - entity_id = #{user.entityID,jdbcType=INTEGER} + entity_id IN ( + + + + + ) AND permission = 'READ' @@ -90,7 +95,12 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ' @@ -161,7 +171,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id @@ -172,7 +187,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id @@ -183,7 +203,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; SELECT @@ -197,7 +222,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index c8ec936fc..a21b7d5b7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -35,11 +35,17 @@ @@ -47,12 +53,17 @@ SELECT - entity_id, + #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, connection_id FROM guacamole_connection_permission - WHERE entity_id = #{entity.entityID,jdbcType=INTEGER} + WHERE + entity_id IN ( + + + + + ) @@ -47,12 +53,17 @@ SELECT - entity_id, + #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, sharing_profile_id FROM guacamole_sharing_profile_permission - WHERE entity_id = #{entity.entityID,jdbcType=INTEGER} + WHERE + entity_id IN ( + + + + + ) + @@ -47,12 +54,17 @@ - SELECT - entity_id, + SELECT DISTINCT + #{entity.entityID} AS entity_id, permission FROM guacamole_system_permission - WHERE entity_id = #{entity.entityID,jdbcType=INTEGER} + WHERE + entity_id IN ( + + + + + ) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index d6680ea98..e5a844afb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -35,14 +35,19 @@ @@ -51,14 +56,19 @@ @@ -99,7 +104,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; SELECT @@ -113,7 +123,12 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id = #{user.entityID,jdbcType=INTEGER} + AND entity_id IN ( + + + + + ) AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index 796962d69..654351fe5 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -70,7 +70,12 @@ JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id WHERE - guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER} + guacamole_user_permission.entity_id IN ( + + + + + ) AND guacamole_entity.type = 'USER'::guacamole_entity_type AND permission = 'READ' @@ -158,7 +163,12 @@ #{identifier,jdbcType=VARCHAR} AND guacamole_entity.type = 'USER'::guacamole_entity_type - AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER} + AND guacamole_user_permission.entity_id IN ( + + + + + ) AND permission = 'READ' GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; @@ -176,7 +186,12 @@ #{identifier,jdbcType=VARCHAR} AND guacamole_entity.type = 'USER'::guacamole_entity_type - AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER} + AND guacamole_user_permission.entity_id IN ( + + + + + ) AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml index 20cb2a809..862e2d719 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml @@ -156,7 +156,12 @@ JOIN guacamole_user_permission ON guacamole_user_history.user_id = guacamole_user_permission.affected_user_id - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_user_permission.entity_id IN ( + + + + + ) AND guacamole_user_permission.permission = 'READ' From 6e71f330b8f8108751fa2fee2b5adea1ae6aecae Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 6 Apr 2018 13:46:36 -0700 Subject: [PATCH 08/32] GUACAMOLE-220: Move JDBC handling of effective groups to RemoteAuthenticatedUser level. Stub out retrieval of effective groups. --- .../sharing/user/SharedAuthenticatedUser.java | 11 +++------- .../jdbc/user/ModeledAuthenticatedUser.java | 9 ++------- .../guacamole/auth/jdbc/user/ModeledUser.java | 16 +++++++++++++++ .../jdbc/user/RemoteAuthenticatedUser.java | 20 ++++++++++++++++++- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java index 958213cbc..96c6a9e31 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java @@ -20,7 +20,6 @@ package org.apache.guacamole.auth.jdbc.sharing.user; import java.util.Collections; -import java.util.Set; import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; @@ -52,7 +51,8 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser { * The AuthenticatedUser to copy. */ public SharedAuthenticatedUser(AuthenticatedUser authenticatedUser) { - super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials()); + super(authenticatedUser.getAuthenticationProvider(), + authenticatedUser.getCredentials(), Collections.emptySet()); this.shareKey = null; this.identifier = authenticatedUser.getIdentifier(); } @@ -75,7 +75,7 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser { */ public SharedAuthenticatedUser(AuthenticationProvider authenticationProvider, Credentials credentials, String shareKey) { - super(authenticationProvider, credentials); + super(authenticationProvider, credentials, Collections.emptySet()); this.shareKey = shareKey; this.identifier = AuthenticatedUser.ANONYMOUS_IDENTIFIER; } @@ -102,9 +102,4 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser { throw new UnsupportedOperationException("Users authenticated via share keys are immutable."); } - @Override - public Set getEffectiveUserGroups() { - return Collections.emptySet(); - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java index 8c201d004..e756374cb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java @@ -76,7 +76,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser { */ public ModeledAuthenticatedUser(AuthenticatedUser authenticatedUser, AuthenticationProvider modelAuthenticationProvider, ModeledUser user) { - super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials()); + super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials(), authenticatedUser.getEffectiveUserGroups()); this.modelAuthenticationProvider = modelAuthenticationProvider; this.user = user; } @@ -98,7 +98,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser { */ public ModeledAuthenticatedUser(AuthenticationProvider authenticationProvider, ModeledUser user, Credentials credentials) { - super(authenticationProvider, credentials); + super(authenticationProvider, credentials, user.getEffectiveUserGroups()); this.modelAuthenticationProvider = authenticationProvider; this.user = user; } @@ -169,9 +169,4 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser { user.setIdentifier(identifier); } - @Override - public Set getEffectiveUserGroups() { - return Collections.emptySet(); - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 737aec860..0628d7499 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -854,6 +854,22 @@ public class ModeledUser extends ModeledDirectoryObject implements Us return new SimpleRelatedObjectSet(); } + /** + * Returns the identifiers of all user groups defined within the database + * which apply to this user, including any groups inherited through + * membership in yet more groups. + * + * @return + * The identifiers of all user groups defined within the database which + * apply to this user. + */ + public Set getEffectiveUserGroups() { + + // FIXME: STUB + return /*retrieveEffectiveIdentifiers(this, */Collections.emptySet()/*)*/; + + } + @Override public Permissions getEffectivePermissions() throws GuacamoleException { return new Permissions() { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java index d68d9a96e..324892e4d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java @@ -19,6 +19,8 @@ package org.apache.guacamole.auth.jdbc.user; +import java.util.Collections; +import java.util.Set; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -43,6 +45,12 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser { */ private final String remoteHost; + /** + * The identifiers of any groups of which this user is a member, including + * groups inherited through membership in other groups. + */ + private final Set effectiveGroups; + /** * Creates a new RemoteAuthenticatedUser, deriving the associated remote * host from the given credentials. @@ -52,12 +60,17 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser { * * @param credentials * The credentials given by the user when they authenticated. + * + * @param effectiveGroups + * The identifiers of any groups of which this user is a member, + * including groups inherited through membership in other groups. */ public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider, - Credentials credentials) { + Credentials credentials, Set effectiveGroups) { this.authenticationProvider = authenticationProvider; this.credentials = credentials; this.remoteHost = credentials.getRemoteAddress(); + this.effectiveGroups = Collections.unmodifiableSet(effectiveGroups); } @Override @@ -75,6 +88,11 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser { return remoteHost; } + @Override + public Set getEffectiveUserGroups() { + return effectiveGroups; + } + @Override public AuthenticationProvider getAuthenticationProvider() { return authenticationProvider; From 14d10fb42abb59515bd58ce04245bd655be3b056 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 6 Apr 2018 14:10:52 -0700 Subject: [PATCH 09/32] GUACAMOLE-220: Inherit from groups even if not determined by database. --- .../ActiveConnectionPermissionService.java | 18 +++-- .../base/ModeledDirectoryObjectMapper.java | 14 +++- .../base/ModeledDirectoryObjectService.java | 6 +- .../jdbc/connection/ConnectionMapper.java | 10 ++- .../connection/ConnectionRecordMapper.java | 9 ++- .../jdbc/connection/ConnectionService.java | 9 ++- .../ConnectionGroupMapper.java | 10 ++- .../ConnectionGroupService.java | 4 +- .../ConnectionGroupPermissionService.java | 6 +- .../ConnectionPermissionService.java | 6 +- .../ModeledObjectPermissionService.java | 15 ++-- .../permission/ModeledPermissionService.java | 5 +- .../permission/ObjectPermissionMapper.java | 22 +++--- .../permission/ObjectPermissionService.java | 23 +++--- .../jdbc/permission/ObjectPermissionSet.java | 25 +++---- .../jdbc/permission/PermissionMapper.java | 11 +-- .../jdbc/permission/PermissionService.java | 24 ++++--- .../SharingProfilePermissionService.java | 6 +- .../permission/SystemPermissionMapper.java | 12 ++-- .../permission/SystemPermissionService.java | 18 ++--- .../jdbc/permission/SystemPermissionSet.java | 23 +++--- .../permission/UserPermissionService.java | 6 +- .../AbstractGuacamoleTunnelService.java | 4 +- .../guacamole/auth/jdbc/user/ModeledUser.java | 52 +++++++++----- .../guacamole/auth/jdbc/user/UserMapper.java | 24 ++++++- .../auth/jdbc/user/UserRecordMapper.java | 9 ++- .../guacamole/auth/jdbc/user/UserService.java | 29 +++++++- .../guacamole/auth/jdbc/base/EntityMapper.xml | 49 +++++++++---- .../auth/jdbc/connection/ConnectionMapper.xml | 55 +++++++------- .../connection/ConnectionRecordMapper.xml | 22 +++--- .../connectiongroup/ConnectionGroupMapper.xml | 66 ++++++++--------- .../ConnectionGroupPermissionMapper.xml | 33 ++++----- .../permission/ConnectionPermissionMapper.xml | 33 ++++----- .../SharingProfilePermissionMapper.xml | 34 ++++----- .../permission/SystemPermissionMapper.xml | 22 +++--- .../jdbc/permission/UserPermissionMapper.xml | 33 ++++----- .../sharingprofile/SharingProfileMapper.xml | 33 ++++----- .../guacamole/auth/jdbc/user/UserMapper.xml | 71 ++++++++++++++----- .../auth/jdbc/user/UserRecordMapper.xml | 11 ++- 39 files changed, 514 insertions(+), 348 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java index 405b23761..a0511b8f8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java @@ -59,10 +59,11 @@ public class ActiveConnectionPermissionService @Override public boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, ObjectPermission.Type type, - String identifier, boolean inherit) throws GuacamoleException { + String identifier, Set effectiveGroups) throws GuacamoleException { // Retrieve permissions - Set permissions = retrievePermissions(user, targetUser, inherit); + Set permissions = retrievePermissions(user, + targetUser, effectiveGroups); // Permission is granted if retrieved permissions contains the // requested permission @@ -73,7 +74,8 @@ public class ActiveConnectionPermissionService @Override public Set retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException { // Retrieve permissions only if allowed if (canReadPermissions(user, targetUser)) { @@ -109,9 +111,10 @@ public class ActiveConnectionPermissionService @Override public Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, ModeledUser targetUser, Collection permissionTypes, - Collection identifiers, boolean inherit) throws GuacamoleException { + Collection identifiers, Set effectiveGroups) + throws GuacamoleException { - Set permissions = retrievePermissions(user, targetUser, inherit); + Set permissions = retrievePermissions(user, targetUser, effectiveGroups); Collection accessibleObjects = new ArrayList(permissions.size()); // For each identifier/permission combination @@ -134,11 +137,12 @@ public class ActiveConnectionPermissionService @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException { // Create permission set for requested user ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get(); - permissionSet.init(user, targetUser, inherit); + permissionSet.init(user, targetUser, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java index 4431e8f42..8ff0cc1c7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java @@ -57,10 +57,15 @@ public interface ModeledDirectoryObjectMapper { * The user whose permissions should determine whether an identifier * is returned. * + * @param effectiveGroups + * The identifiers of any known effective groups that should be taken + * into account, such as those defined externally to the database. + * * @return * A Set containing all identifiers of all readable objects. */ - Set selectReadableIdentifiers(@Param("user") UserModel user); + Set selectReadableIdentifiers(@Param("user") UserModel user, + @Param("effectiveGroups") Collection effectiveGroups); /** * Selects all objects which have the given identifiers. If an identifier @@ -91,11 +96,16 @@ public interface ModeledDirectoryObjectMapper { * @param identifiers * The identifiers of the objects to return. * + * @param effectiveGroups + * The identifiers of any known effective groups that should be taken + * into account, such as those defined externally to the database. + * * @return * A Collection of all objects having the given identifiers. */ Collection selectReadable(@Param("user") UserModel user, - @Param("identifiers") Collection identifiers); + @Param("identifiers") Collection identifiers, + @Param("effectiveGroups") Collection effectiveGroups); /** * Inserts the given object into the database. If the object already diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java index e87d6649f..edbb67e3e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java @@ -401,7 +401,8 @@ public abstract class ModeledDirectoryObjectService selectReadableIdentifiersWithin(@Param("user") UserModel user, - @Param("parentIdentifier") String parentIdentifier); + @Param("parentIdentifier") String parentIdentifier, + @Param("effectiveGroups") Collection effectiveGroups); /** * Selects the connection within the given parent group and having the diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java index 637fd0fed..7380b213b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java @@ -102,12 +102,19 @@ public interface ConnectionRecordMapper { * @param limit * The maximum number of records that should be returned. * + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. + * * @return * The results of the search performed with the given parameters. */ List searchReadable(@Param("user") UserModel user, @Param("terms") Collection terms, @Param("sortPredicates") List sortPredicates, - @Param("limit") int limit); + @Param("limit") int limit, + @Param("effectiveGroups") Collection effectiveGroups); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java index 11e37923a..8dcf6f59a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java @@ -303,7 +303,9 @@ public class ConnectionService extends ModeledChildDirectoryObjectService selectReadableIdentifiersWithin(@Param("user") UserModel user, - @Param("parentIdentifier") String parentIdentifier); + @Param("parentIdentifier") String parentIdentifier, + @Param("effectiveGroups") Collection effectiveGroups); /** * Selects the connection group within the given parent group and having diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java index 34d039cca..01119b92e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java @@ -223,7 +223,9 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService effectiveGroups) + throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get(); - permissionSet.init(user, targetUser, inherit); + permissionSet.init(user, targetUser, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java index 19c30c0be..0cc69df17 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java @@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission; import com.google.inject.Inject; import com.google.inject.Provider; +import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.jdbc.user.ModeledUser; @@ -51,11 +52,12 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get(); - permissionSet.init(user, targetUser, inherit); + permissionSet.init(user, targetUser, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java index b1229ae04..f1105ed60 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc.permission; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; @@ -106,7 +107,7 @@ public abstract class ModeledObjectPermissionService affectedIdentifiers.add(permission.getObjectIdentifier()); // Determine subset of affected identifiers that we have admin access to - ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), true); + ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), user.getEffectiveUserGroups()); Collection allowedSubset = affectedPermissionSet.getAccessibleObjects( Collections.singleton(ObjectPermission.Type.ADMINISTER), affectedIdentifiers @@ -157,11 +158,13 @@ public abstract class ModeledObjectPermissionService @Override public boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, ObjectPermission.Type type, - String identifier, boolean inherit) throws GuacamoleException { + String identifier, Set effectiveGroups) + throws GuacamoleException { // Retrieve permissions only if allowed if (canReadPermissions(user, targetUser)) - return getPermissionMapper().selectOne(targetUser.getModel(), type, identifier, inherit) != null; + return getPermissionMapper().selectOne(targetUser.getModel(), type, + identifier, effectiveGroups) != null; // User cannot read this user's permissions throw new GuacamoleSecurityException("Permission denied."); @@ -171,7 +174,7 @@ public abstract class ModeledObjectPermissionService @Override public Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, ModeledUser targetUser, Collection permissions, - Collection identifiers, boolean inherit) + Collection identifiers, Set effectiveGroups) throws GuacamoleException { // Nothing is always accessible @@ -186,7 +189,9 @@ public abstract class ModeledObjectPermissionService return identifiers; // Otherwise, return explicitly-retrievable identifiers - return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers, inherit); + return getPermissionMapper().selectAccessibleIdentifiers( + targetUser.getModel(), permissions, identifiers, + effectiveGroups); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java index 4d0fcf61f..dadaea619 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java @@ -140,11 +140,12 @@ public abstract class ModeledPermissionService retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException { // Retrieve permissions only if allowed if (canReadPermissions(user, targetUser)) - return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), inherit)); + return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), effectiveGroups)); // User cannot read this user's permissions throw new GuacamoleSecurityException("Permission denied."); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java index e5efad09c..b6f9801d2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java @@ -43,10 +43,11 @@ public interface ObjectPermissionMapper extends PermissionMapper effectiveGroups); /** * Retrieves the subset of the given identifiers for which the given entity @@ -73,10 +74,11 @@ public interface ObjectPermissionMapper extends PermissionMapper selectAccessibleIdentifiers(@Param("entity") EntityModel entity, @Param("permissions") Collection permissions, @Param("identifiers") Collection identifiers, - @Param("inherit") boolean inherit); + @Param("effectiveGroups") Collection effectiveGroups); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java index fa1ee2d76..3f39881cb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java @@ -20,6 +20,7 @@ package org.apache.guacamole.auth.jdbc.permission; import java.util.Collection; +import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; @@ -50,10 +51,11 @@ public interface ObjectPermissionService * @param identifier * The identifier of the object affected by the permission to return. * - * @param inherit - * Whether permissions inherited through user groups should be taken - * into account. If false, only permissions granted directly will be - * included. + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. * * @return * true if permission of the given type and associated with the given @@ -64,7 +66,7 @@ public interface ObjectPermissionService */ boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, ObjectPermission.Type type, - String identifier, boolean inherit) throws GuacamoleException; + String identifier, Set effectiveGroups) throws GuacamoleException; /** * Retrieves the subset of the given identifiers for which the given user @@ -85,10 +87,11 @@ public interface ObjectPermissionService * The identifiers of the objects affected by the permissions being * checked. * - * @param inherit - * Whether permissions inherited through user groups should be taken - * into account. If false, only permissions granted directly will be - * included. + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. * * @return * A collection containing the subset of identifiers for which at least @@ -99,7 +102,7 @@ public interface ObjectPermissionService */ Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, ModeledUser targetUser, Collection permissions, - Collection identifiers, boolean inherit) + Collection identifiers, Set effectiveGroups) throws GuacamoleException; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java index cedb45dd3..c15b1af5b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java @@ -42,11 +42,7 @@ public abstract class ObjectPermissionSet extends RestrictedObject */ private ModeledUser user; - /** - * Whether permissions inherited through user groups should be taken into - * account. If false, only permissions granted directly will be included. - */ - boolean inherit; + private Set effectiveGroups; /** * Creates a new ObjectPermissionSet. The resulting permission set @@ -67,16 +63,17 @@ public abstract class ObjectPermissionSet extends RestrictedObject * @param user * The user to whom the permissions in this set are granted. * - * @param inherit - * Whether permissions inherited through user groups should be taken - * into account. If false, only permissions granted directly will be - * included. + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. */ public void init(ModeledAuthenticatedUser currentUser, ModeledUser user, - boolean inherit) { + Set effectiveGroups) { super.init(currentUser); this.user = user; - this.inherit = inherit; + this.effectiveGroups = effectiveGroups; } /** @@ -91,13 +88,13 @@ public abstract class ObjectPermissionSet extends RestrictedObject @Override public Set getPermissions() throws GuacamoleException { - return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, inherit); + return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, effectiveGroups); } @Override public boolean hasPermission(ObjectPermission.Type permission, String identifier) throws GuacamoleException { - return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, inherit); + return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, effectiveGroups); } @Override @@ -115,7 +112,7 @@ public abstract class ObjectPermissionSet extends RestrictedObject @Override public Collection getAccessibleObjects(Collection permissions, Collection identifiers) throws GuacamoleException { - return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, inherit); + return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, effectiveGroups); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java index 1c2d23b76..edd66f494 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java @@ -38,16 +38,17 @@ public interface PermissionMapper { * @param entity * The entity to retrieve permissions for. * - * @param inherit - * Whether permissions inherited through user groups should be taken - * into account. If false, only permissions granted directly will be - * included. + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. * * @return * All permissions associated with the given entity. */ Collection select(@Param("entity") EntityModel entity, - @Param("inherit") boolean inherit); + @Param("effectiveGroups") Collection effectiveGroups); /** * Inserts the given permissions into the database. If any permissions diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java index 6e596346e..3caa5874c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java @@ -54,10 +54,11 @@ public interface PermissionService effectiveGroups) + throws GuacamoleException; /** * Retrieves all permissions associated with the given user. @@ -80,10 +82,11 @@ public interface PermissionService retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException; + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException; /** * Creates the given permissions within the database. If any permissions diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java index 3cdf9d160..3018b290d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java @@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission; import com.google.inject.Inject; import com.google.inject.Provider; +import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.jdbc.user.ModeledUser; @@ -51,11 +52,12 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get(); - permissionSet.init(user, targetUser, inherit); + permissionSet.init(user, targetUser, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java index c05f4053a..c676b72b1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java @@ -19,6 +19,7 @@ package org.apache.guacamole.auth.jdbc.permission; +import java.util.Collection; import org.apache.guacamole.auth.jdbc.base.EntityModel; import org.apache.ibatis.annotations.Param; import org.apache.guacamole.net.auth.permission.SystemPermission; @@ -38,10 +39,11 @@ public interface SystemPermissionMapper extends PermissionMapper effectiveGroups); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java index 59095690f..b534ad3fa 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc.permission; import com.google.inject.Inject; import com.google.inject.Provider; import java.util.Collection; +import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; @@ -75,11 +76,11 @@ public class SystemPermissionService @Override public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) throws GuacamoleException { // Create permission set for requested user SystemPermissionSet permissionSet = systemPermissionSetProvider.get(); - permissionSet.init(user, targetUser, inherit); + permissionSet.init(user, targetUser, effectiveGroups); return permissionSet; @@ -136,10 +137,11 @@ public class SystemPermissionService * @param type * The type of permission to retrieve. * - * @param inherit - * Whether permissions inherited through user groups should be taken - * into account. If false, only permissions granted directly will be - * included. + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. * * @return * true if permission of the given type has been granted to the given @@ -150,11 +152,11 @@ public class SystemPermissionService */ public boolean hasPermission(ModeledAuthenticatedUser user, ModeledUser targetUser, SystemPermission.Type type, - boolean inherit) throws GuacamoleException { + Set effectiveGroups) throws GuacamoleException { // Retrieve permissions only if allowed if (canReadPermissions(user, targetUser)) - return getPermissionMapper().selectOne(targetUser.getModel(), type, inherit) != null; + return getPermissionMapper().selectOne(targetUser.getModel(), type, effectiveGroups) != null; // User cannot read this user's permissions throw new GuacamoleSecurityException("Permission denied."); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java index bb5af1185..dd8887901 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java @@ -42,11 +42,7 @@ public class SystemPermissionSet extends RestrictedObject */ private ModeledUser user; - /** - * Whether permissions inherited through user groups should be taken into - * account. If false, only permissions granted directly will be included. - */ - private boolean inherit; + private Set effectiveGroups; /** * Service for reading and manipulating system permissions. @@ -73,27 +69,28 @@ public class SystemPermissionSet extends RestrictedObject * @param user * The user to whom the permissions in this set are granted. * - * @param inherit - * Whether permissions inherited through user groups should be taken - * into account. If false, only permissions granted directly will be - * included. + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. */ public void init(ModeledAuthenticatedUser currentUser, ModeledUser user, - boolean inherit) { + Set effectiveGroups) { super.init(currentUser); this.user = user; - this.inherit = inherit; + this.effectiveGroups = effectiveGroups; } @Override public Set getPermissions() throws GuacamoleException { - return systemPermissionService.retrievePermissions(getCurrentUser(), user, inherit); + return systemPermissionService.retrievePermissions(getCurrentUser(), user, effectiveGroups); } @Override public boolean hasPermission(SystemPermission.Type permission) throws GuacamoleException { - return systemPermissionService.hasPermission(getCurrentUser(), user, permission, inherit); + return systemPermissionService.hasPermission(getCurrentUser(), user, permission, effectiveGroups); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java index 8e6586257..fabbf72fd 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java @@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission; import com.google.inject.Inject; import com.google.inject.Provider; +import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.jdbc.user.ModeledUser; @@ -51,11 +52,12 @@ public class UserPermissionService extends ModeledObjectPermissionService { @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, boolean inherit) throws GuacamoleException { + ModeledUser targetUser, Set effectiveGroups) + throws GuacamoleException { // Create permission set for requested user ObjectPermissionSet permissionSet = userPermissionSetProvider.get(); - permissionSet.init(user, targetUser, inherit); + permissionSet.init(user, targetUser, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index fe3a45b2f..5f7fc1ba3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -628,7 +628,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS identifiers.add(record.getConnection().getIdentifier()); // Produce collection of readable connection identifiers - Collection connections = connectionMapper.selectReadable(user.getUser().getModel(), identifiers); + Collection connections = + connectionMapper.selectReadable(user.getUser().getModel(), + identifiers, user.getEffectiveUserGroups()); // Ensure set contains only identifiers of readable connections identifiers.clear(); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 0628d7499..0bb199e23 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -351,37 +351,43 @@ public class ModeledUser extends ModeledDirectoryObject implements Us @Override public SystemPermissionSet getSystemPermissions() throws GuacamoleException { - return systemPermissionService.getPermissionSet(getCurrentUser(), this, false); + return systemPermissionService.getPermissionSet(getCurrentUser(), this, + Collections.emptySet()); } @Override public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException { - return connectionPermissionService.getPermissionSet(getCurrentUser(), this, false); + return connectionPermissionService.getPermissionSet(getCurrentUser(), + this, Collections.emptySet()); } @Override public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException { - return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this, false); + return connectionGroupPermissionService.getPermissionSet( + getCurrentUser(), this, Collections.emptySet()); } @Override public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException { - return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this, false); + return sharingProfilePermissionService.getPermissionSet( + getCurrentUser(), this, Collections.emptySet()); } @Override public ObjectPermissionSet getActiveConnectionPermissions() throws GuacamoleException { - return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this, false); + return activeConnectionPermissionService.getPermissionSet( + getCurrentUser(), this, Collections.emptySet()); } @Override public ObjectPermissionSet getUserPermissions() throws GuacamoleException { - return userPermissionService.getPermissionSet(getCurrentUser(), this, false); + return userPermissionService.getPermissionSet(getCurrentUser(), this, + Collections.emptySet()); } @Override @@ -864,50 +870,64 @@ public class ModeledUser extends ModeledDirectoryObject implements Us * apply to this user. */ public Set getEffectiveUserGroups() { - - // FIXME: STUB - return /*retrieveEffectiveIdentifiers(this, */Collections.emptySet()/*)*/; - + return userService.retrieveEffectiveGroups(this, + Collections.emptySet()); } @Override public Permissions getEffectivePermissions() throws GuacamoleException { + + final ModeledAuthenticatedUser authenticatedUser = getCurrentUser(); + final Set effectiveGroups; + + // If this user is the currently-authenticated user, include any + // additional effective groups declared by the authentication system + if (authenticatedUser.getIdentifier().equals(getIdentifier())) + effectiveGroups = userService.retrieveEffectiveGroups(this, + authenticatedUser.getEffectiveUserGroups()); + + // Otherwise, just include effective groups from the database + else + effectiveGroups = getEffectiveUserGroups(); + + // Return a permissions object which describes all effective + // permissions, including any permissions inherited via user groups return new Permissions() { @Override public ObjectPermissionSet getActiveConnectionPermissions() throws GuacamoleException { - return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); } @Override public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException { - return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); } @Override public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException { - return connectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); } @Override public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException { - return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); } @Override public SystemPermissionSet getSystemPermissions() throws GuacamoleException { - return systemPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + return systemPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); } @Override public ObjectPermissionSet getUserPermissions() throws GuacamoleException { - return userPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true); + return userPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java index 251445b62..6b5110560 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java @@ -19,6 +19,8 @@ package org.apache.guacamole.auth.jdbc.user; +import java.util.Collection; +import java.util.Set; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; import org.apache.ibatis.annotations.Param; @@ -38,5 +40,25 @@ public interface UserMapper extends ModeledDirectoryObjectMapper { * The user having the given username, or null if no such user exists. */ UserModel selectOne(@Param("username") String username); - + + /** + * Returns the set of all group identifiers of which the given user is a + * member, taking into account the given collection of known group + * memberships which are not necessarily defined within the database. + * + * @param user + * The user whose effective groups should be returned. + * + * @param effectiveGroups + * The identifiers of any known effective groups that should be taken + * into account, such as those defined externally to the database. + * + * @return + * The set of identifiers of all groups that the given user is a + * member of, including those where membership is inherited through + * membership in other groups. + */ + Set selectEffectiveGroupIdentifiers(@Param("user") UserModel user, + @Param("effectiveGroups") Collection effectiveGroups); + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java index b2177bf1f..92501ab0b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java @@ -113,12 +113,19 @@ public interface UserRecordMapper { * @param limit * The maximum number of records that should be returned. * + * @param effectiveGroups + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the user. If + * no groups are given, only permissions directly granted to the user + * will be used. + * * @return * The results of the search performed with the given parameters. */ List searchReadable(@Param("user") UserModel user, @Param("terms") Collection terms, @Param("sortPredicates") List sortPredicates, - @Param("limit") int limit); + @Param("limit") int limit, + @Param("effectiveGroups") Collection effectiveGroups); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java index 2c70e2201..6d89125a9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; @@ -591,11 +592,37 @@ public class UserService extends ModeledDirectoryObjectService retrieveEffectiveGroups(ModeledUser user, + Collection effectiveGroups) { + return userMapper.selectEffectiveGroupIdentifiers(user.getModel(), effectiveGroups); + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml index dd262d1e9..01830d759 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -23,21 +23,40 @@ - - - ${entityID} - - WITH RECURSIVE related_entity(entity_id) AS ( - VALUES (${entityID}) - UNION - SELECT guacamole_user_group.entity_id - FROM related_entity - JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id - JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id - ) - SELECT entity_id FROM related_entity - + + + ( + ${column} = ${entityID} + + OR ${column} IN ( + SELECT entity_id + FROM guacamole_entity + WHERE + type = 'USER_GROUP'::guacamole_entity_type + AND name IN + + #{effectiveGroup,jdbcType=VARCHAR} + + ) + + ) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index 94855e168..859cec53e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -68,12 +68,11 @@ SELECT connection_id FROM guacamole_connection_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = 'READ' @@ -94,12 +93,11 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ' @@ -175,12 +173,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND guacamole_connection_permission.entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ' GROUP BY guacamole_connection.connection_id; @@ -192,12 +189,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; SELECT @@ -211,12 +207,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index b04c9ca6f..e8e88764b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -166,23 +166,21 @@ JOIN guacamole_connection_permission ON guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id - AND guacamole_connection_permission.entity_id IN ( - - - - - ) + AND + + + + AND guacamole_connection_permission.permission = 'READ' JOIN guacamole_user_permission ON guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id - AND guacamole_user_permission.entity_id IN ( - - - - - ) + AND + + + + AND guacamole_user_permission.permission = 'READ' diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index ffca72d25..37841dee2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -69,12 +69,11 @@ SELECT connection_group_id FROM guacamole_connection_group_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = 'READ' @@ -95,12 +94,11 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ' @@ -171,12 +169,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id @@ -187,12 +184,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id @@ -203,12 +199,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; SELECT @@ -222,12 +217,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index a21b7d5b7..4ce168d4d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -40,12 +40,11 @@ connection_group_id FROM guacamole_connection_group_permission WHERE - entity_id IN ( - - - - - ) + + + + + @@ -58,12 +57,11 @@ connection_group_id FROM guacamole_connection_group_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer @@ -75,12 +73,11 @@ SELECT DISTINCT connection_group_id FROM guacamole_connection_group_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND connection_group_id IN diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml index 5d911de4e..68968d744 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml @@ -40,12 +40,11 @@ connection_id FROM guacamole_connection_permission WHERE - entity_id IN ( - - - - - ) + + + + + @@ -58,12 +57,11 @@ connection_id FROM guacamole_connection_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND connection_id = #{identifier,jdbcType=INTEGER}::integer @@ -75,12 +73,11 @@ SELECT DISTINCT connection_id FROM guacamole_connection_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND connection_id IN diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml index 68b3032f7..4594c05eb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml @@ -40,13 +40,11 @@ sharing_profile_id FROM guacamole_sharing_profile_permission WHERE - entity_id IN ( - - - - - ) - + + + + + @@ -59,12 +57,11 @@ sharing_profile_id FROM guacamole_sharing_profile_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer @@ -76,12 +73,11 @@ SELECT DISTINCT sharing_profile_id FROM guacamole_sharing_profile_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND sharing_profile_id IN diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml index 25ebf97ff..ae86302ed 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml @@ -38,12 +38,11 @@ permission FROM guacamole_system_permission WHERE - entity_id IN ( - - - - - ) + + + + + @@ -55,12 +54,11 @@ permission FROM guacamole_system_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index e5a844afb..bd3ff934e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -42,12 +42,11 @@ JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id WHERE - guacamole_user_permission.entity_id IN ( - - - - - ) + + + + + AND affected_entity.type = 'USER'::guacamole_entity_type @@ -63,12 +62,11 @@ JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id WHERE - guacamole_user_permission.entity_id IN ( - - - - - ) + + + + + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND affected_entity.name = #{identifier,jdbcType=VARCHAR} AND affected_entity.type = 'USER'::guacamole_entity_type @@ -83,12 +81,11 @@ JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id WHERE - guacamole_user_permission.entity_id IN ( - - - - - ) + + + + + AND affected_entity.name IN diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index febf54078..62548d7ce 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -52,12 +52,11 @@ SELECT sharing_profile_id FROM guacamole_sharing_profile_permission WHERE - entity_id IN ( - - - - - ) + + + + + AND permission = 'READ' @@ -104,12 +103,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; SELECT @@ -123,12 +121,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER}::integer - AND entity_id IN ( - - - - - ) + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index 654351fe5..25d7659a2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -70,16 +70,53 @@ JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id WHERE - guacamole_user_permission.entity_id IN ( - - - - - ) + + + + + AND guacamole_entity.type = 'USER'::guacamole_entity_type AND permission = 'READ' + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml index 862e2d719..6311a2546 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml @@ -156,12 +156,11 @@ JOIN guacamole_user_permission ON guacamole_user_history.user_id = guacamole_user_permission.affected_user_id - AND guacamole_user_permission.entity_id IN ( - - - - - ) + AND + + + + AND guacamole_user_permission.permission = 'READ' From 69f58c8ca314c44822e0eaab354b5f722a01ac89 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 7 Apr 2018 19:10:38 -0700 Subject: [PATCH 10/32] GUACAMOLE-220: Refactor handling of JDBC permissions to abstract away users vs. user groups. --- .../JDBCAuthenticationProviderModule.java | 2 + .../ActiveConnectionPermissionService.java | 37 +-- .../auth/jdbc/base/EntityMapper.java | 22 ++ .../auth/jdbc/base/EntityService.java | 65 +++++ .../auth/jdbc/base/ModeledPermissions.java | 266 ++++++++++++++++++ .../permission/AbstractPermissionService.java | 59 +++- .../ConnectionGroupPermissionService.java | 11 +- .../ConnectionPermissionService.java | 11 +- .../ModeledObjectPermissionService.java | 68 +++-- .../permission/ModeledPermissionService.java | 37 +-- .../permission/ObjectPermissionService.java | 37 +-- .../jdbc/permission/ObjectPermissionSet.java | 42 +-- .../jdbc/permission/PermissionService.java | 66 +++-- .../SharingProfilePermissionService.java | 11 +- .../permission/SystemPermissionService.java | 42 +-- .../jdbc/permission/SystemPermissionSet.java | 40 +-- .../permission/UserPermissionService.java | 11 +- .../guacamole/auth/jdbc/user/ModeledUser.java | 191 +------------ .../guacamole/auth/jdbc/user/UserMapper.java | 22 -- .../guacamole/auth/jdbc/user/UserService.java | 28 -- .../guacamole/auth/jdbc/base/EntityMapper.xml | 38 +++ .../guacamole/auth/jdbc/user/UserMapper.xml | 38 --- 22 files changed, 673 insertions(+), 471 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 17dfc5db0..48c95c77b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -60,6 +60,7 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; import org.apache.guacamole.auth.jdbc.base.EntityMapper; +import org.apache.guacamole.auth.jdbc.base.EntityService; import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService; @@ -161,6 +162,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(ConnectionPermissionService.class); bind(ConnectionSharingService.class); bind(ConnectionService.class); + bind(EntityService.class); bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class); bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class); bind(PasswordPolicyService.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java index a0511b8f8..e7cbd5db5 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java @@ -27,12 +27,13 @@ import java.util.HashSet; import java.util.Set; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.auth.jdbc.permission.AbstractPermissionService; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionService; import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord; import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; @@ -58,12 +59,13 @@ public class ActiveConnectionPermissionService @Override public boolean hasPermission(ModeledAuthenticatedUser user, - ModeledUser targetUser, ObjectPermission.Type type, - String identifier, Set effectiveGroups) throws GuacamoleException { + ModeledPermissions targetEntity, + ObjectPermission.Type type, String identifier, + Set effectiveGroups) throws GuacamoleException { // Retrieve permissions Set permissions = retrievePermissions(user, - targetUser, effectiveGroups); + targetEntity, effectiveGroups); // Permission is granted if retrieved permissions contains the // requested permission @@ -74,14 +76,14 @@ public class ActiveConnectionPermissionService @Override public Set retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { // Retrieve permissions only if allowed - if (canReadPermissions(user, targetUser)) { + if (canReadPermissions(user, targetEntity)) { // Only administrators may access active connections - boolean isAdmin = targetUser.isAdministrator(); + boolean isAdmin = targetEntity.isAdministrator(); // Get all active connections Collection records = tunnelService.getActiveConnections(user); @@ -110,11 +112,12 @@ public class ActiveConnectionPermissionService @Override public Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, - ModeledUser targetUser, Collection permissionTypes, + ModeledPermissions targetEntity, + Collection permissionTypes, Collection identifiers, Set effectiveGroups) throws GuacamoleException { - Set permissions = retrievePermissions(user, targetUser, effectiveGroups); + Set permissions = retrievePermissions(user, targetEntity, effectiveGroups); Collection accessibleObjects = new ArrayList(permissions.size()); // For each identifier/permission combination @@ -137,12 +140,12 @@ public class ActiveConnectionPermissionService @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { - // Create permission set for requested user + // Create permission set for requested entity ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get(); - permissionSet.init(user, targetUser, effectiveGroups); + permissionSet.init(user, targetEntity, effectiveGroups); return permissionSet; @@ -150,7 +153,8 @@ public class ActiveConnectionPermissionService @Override public void createPermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, Collection permissions) + ModeledPermissions targetEntity, + Collection permissions) throws GuacamoleException { // Creating active connection permissions is not implemented @@ -160,7 +164,8 @@ public class ActiveConnectionPermissionService @Override public void deletePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, Collection permissions) + ModeledPermissions targetEntity, + Collection permissions) throws GuacamoleException { // Deleting active connection permissions is not implemented diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java index 14657ce26..31efad5fc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java @@ -19,6 +19,8 @@ package org.apache.guacamole.auth.jdbc.base; +import java.util.Collection; +import java.util.Set; import org.apache.ibatis.annotations.Param; /** @@ -40,4 +42,24 @@ public interface EntityMapper { */ int insert(@Param("entity") EntityModel entity); + /** + * Returns the set of all group identifiers of which the given entity is a + * member, taking into account the given collection of known group + * memberships which are not necessarily defined within the database. + * + * @param entity + * The entity whose effective groups should be returned. + * + * @param effectiveGroups + * The identifiers of any known effective groups that should be taken + * into account, such as those defined externally to the database. + * + * @return + * The set of identifiers of all groups that the given entity is a + * member of, including those where membership is inherited through + * membership in other groups. + */ + Set selectEffectiveGroupIdentifiers(@Param("entity") EntityModel entity, + @Param("effectiveGroups") Collection effectiveGroups); + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java new file mode 100644 index 000000000..fa71feee0 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +import com.google.inject.Inject; +import java.util.Collection; +import java.util.Set; + +/** + * Service which provides convenience methods for creating, retrieving, and + * manipulating entities. + */ +public class EntityService { + + /** + * Mapper for Entity model objects. + */ + @Inject + private EntityMapper entityMapper; + + /** + * Returns the set of all group identifiers of which the given entity is a + * member, taking into account the given collection of known group + * memberships which are not necessarily defined within the database. + * + * Note that group visibility with respect to the queried entity is NOT + * taken into account. If the entity is a member of a group, the identifier + * of that group will be included in the returned set even if the current + * user lacks "READ" permission for that group. + * + * @param entity + * The entity whose effective groups should be returned. + * + * @param effectiveGroups + * The identifiers of any known effective groups that should be taken + * into account, such as those defined externally to the database. + * + * @return + * The set of identifiers of all groups that the given entity is a + * member of, including those where membership is inherited through + * membership in other groups. + */ + public Set retrieveEffectiveGroups(ModeledPermissions entity, + Collection effectiveGroups) { + return entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java new file mode 100644 index 000000000..2f7808d2c --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +import com.google.inject.Inject; +import java.util.Collections; +import java.util.Set; +import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService; +import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService; +import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService; +import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService; +import org.apache.guacamole.auth.jdbc.permission.UserPermissionService; +import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; +import org.apache.guacamole.net.auth.Permissions; +import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; +import org.apache.guacamole.net.auth.permission.SystemPermission; +import org.apache.guacamole.net.auth.permission.SystemPermissionSet; +import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet; + +/** + * An implementation of the base Permissions interface which is common to both + * Users and UserGroups, backed by a database model. + * + * @param + * The type of model object that corresponds to this object. + */ +public abstract class ModeledPermissions + extends ModeledDirectoryObject implements Permissions { + + /** + * Service for retrieving entity details. + */ + @Inject + private EntityService entityService; + + /** + * Service for retrieving system permissions. + */ + @Inject + private SystemPermissionService systemPermissionService; + + /** + * Service for retrieving connection permissions. + */ + @Inject + private ConnectionPermissionService connectionPermissionService; + + /** + * Service for retrieving connection group permissions. + */ + @Inject + private ConnectionGroupPermissionService connectionGroupPermissionService; + + /** + * Service for retrieving sharing profile permissions. + */ + @Inject + private SharingProfilePermissionService sharingProfilePermissionService; + + /** + * Service for retrieving active connection permissions. + */ + @Inject + private ActiveConnectionPermissionService activeConnectionPermissionService; + + /** + * Service for retrieving user permissions. + */ + @Inject + private UserPermissionService userPermissionService; + + /** + * Returns whether the underlying entity is a user. Entities may be either + * users or user groups. + * + * @return + * true if the underlying entity is a user, false otherwise. + */ + public boolean isUser() { + return getModel().getEntityType() == EntityType.USER; + } + + /** + * Returns whether the underlying entity is a user group. Entities may be + * either users or user groups. + * + * @return + * true if the underlying entity is a user group, false otherwise. + */ + public boolean isUserGroup() { + return getModel().getEntityType() == EntityType.USER_GROUP; + } + + /** + * Returns whether this entity is a system administrator, and thus is not + * restricted by permissions, taking into account permission inheritance + * via user groups. + * + * @return + * true if this entity is a system administrator, false otherwise. + * + * @throws GuacamoleException + * If an error occurs while determining the entity's system administrator + * status. + */ + public boolean isAdministrator() throws GuacamoleException { + SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions(); + return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER); + } + + @Override + public SystemPermissionSet getSystemPermissions() + throws GuacamoleException { + return systemPermissionService.getPermissionSet(getCurrentUser(), this, + Collections.emptySet()); + } + + @Override + public ObjectPermissionSet getConnectionPermissions() + throws GuacamoleException { + return connectionPermissionService.getPermissionSet(getCurrentUser(), + this, Collections.emptySet()); + } + + @Override + public ObjectPermissionSet getConnectionGroupPermissions() + throws GuacamoleException { + return connectionGroupPermissionService.getPermissionSet( + getCurrentUser(), this, Collections.emptySet()); + } + + @Override + public ObjectPermissionSet getSharingProfilePermissions() + throws GuacamoleException { + return sharingProfilePermissionService.getPermissionSet( + getCurrentUser(), this, Collections.emptySet()); + } + + @Override + public ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException { + return activeConnectionPermissionService.getPermissionSet( + getCurrentUser(), this, Collections.emptySet()); + } + + @Override + public ObjectPermissionSet getUserPermissions() + throws GuacamoleException { + return userPermissionService.getPermissionSet(getCurrentUser(), this, + Collections.emptySet()); + } + + @Override + public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException { + // FIXME: STUB + return new SimpleObjectPermissionSet(); + } + + /** + * Returns the identifiers of all user groups defined within the database + * which apply to this user, including any groups inherited through + * membership in yet more groups. + * + * @return + * The identifiers of all user groups defined within the database which + * apply to this user. + */ + public Set getEffectiveUserGroups() { + return entityService.retrieveEffectiveGroups(this, + Collections.emptySet()); + } + + /** + * Returns a Permissions object which represents all permissions granted to + * this entity, including any permissions inherited through group + * membership. + * + * @return + * A Permissions object which represents all permissions granted to + * this entity. + */ + public Permissions getEffective() { + + final ModeledAuthenticatedUser authenticatedUser = getCurrentUser(); + final Set effectiveGroups; + + // If this user is the currently-authenticated user, include any + // additional effective groups declared by the authentication system + if (authenticatedUser.getIdentifier().equals(getIdentifier())) + effectiveGroups = entityService.retrieveEffectiveGroups(this, + authenticatedUser.getEffectiveUserGroups()); + + // Otherwise, just include effective groups from the database + else + effectiveGroups = getEffectiveUserGroups(); + + // Return a permissions object which describes all effective + // permissions, including any permissions inherited via user groups + return new Permissions() { + + @Override + public ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException { + return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups); + } + + @Override + public ObjectPermissionSet getConnectionGroupPermissions() + throws GuacamoleException { + return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups); + } + + @Override + public ObjectPermissionSet getConnectionPermissions() + throws GuacamoleException { + return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups); + } + + @Override + public ObjectPermissionSet getSharingProfilePermissions() + throws GuacamoleException { + return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups); + } + + @Override + public SystemPermissionSet getSystemPermissions() + throws GuacamoleException { + return systemPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups); + } + + @Override + public ObjectPermissionSet getUserPermissions() + throws GuacamoleException { + return userPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups); + } + + @Override + public ObjectPermissionSet getUserGroupPermissions() + throws GuacamoleException { + // FIXME: STUB + return new SimpleObjectPermissionSet(); + } + + }; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java index 74f35fb58..6e4ddfab3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java @@ -20,8 +20,10 @@ package org.apache.guacamole.auth.jdbc.permission; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; +import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.Permission; @@ -41,17 +43,51 @@ public abstract class AbstractPermissionService implements PermissionService { + /** + * Returns the ObjectPermissionSet related to the type of the given entity. + * If the given entity represents a user, then the ObjectPermissionSet + * containing user permissions is returned. If the given entity represents + * a user group, then the ObjectPermissionSet containing user group + * permissions is returned. + * + * @param user + * The user to retrieve the ObjectPermissionSet from. + * + * @param targetEntity + * The entity whose type dictates the ObjectPermissionSet returned. + * + * @return + * The ObjectPermissionSet related to the type of the given entity. + * + * @throws GuacamoleException + * If the relevant ObjectPermissionSet cannot be retrieved. + */ + protected ObjectPermissionSet getRelevantPermissionSet(ModeledUser user, + ModeledPermissions targetEntity) + throws GuacamoleException { + + if (targetEntity.isUser()) + return user.getUserPermissions(); + + if (targetEntity.isUserGroup()) + return user.getUserGroupPermissions(); + + // Entities should be only users or groups + throw new UnsupportedOperationException("Unexpected entity type."); + + } + /** * Determines whether the given user can read the permissions currently - * granted to the given target user. If the reading user and the target - * user are not the same, then explicit READ or SYSTEM_ADMINISTER access is - * required. Permission inheritance via user groups is taken into account. + * granted to the given target entity. If the reading user and the target + * entity are not the same, then explicit READ or SYSTEM_ADMINISTER access + * is required. Permission inheritance via user groups is taken into account. * * @param user * The user attempting to read permissions. * - * @param targetUser - * The user whose permissions are being read. + * @param targetEntity + * The entity whose permissions are being read. * * @return * true if permission is granted, false otherwise. @@ -61,19 +97,20 @@ public abstract class AbstractPermissionService targetEntity) + throws GuacamoleException { // A user can always read their own permissions - if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())) + if (targetEntity.isUser() && user.getUser().getIdentifier().equals(targetEntity.getIdentifier())) return true; // A system adminstrator can do anything if (user.getUser().isAdministrator()) return true; - // Can read permissions on target user if explicit READ is granted - ObjectPermissionSet userPermissionSet = user.getUser().getEffectivePermissions().getUserPermissions(); - return userPermissionSet.hasPermission(ObjectPermission.Type.READ, targetUser.getIdentifier()); + // Can read permissions on target entity if explicit READ is granted + ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity); + return permissionSet.hasPermission(ObjectPermission.Type.READ, targetEntity.getIdentifier()); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java index afabbc735..d0f1f0b98 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java @@ -24,7 +24,8 @@ import com.google.inject.Provider; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; /** * Service which provides convenience methods for creating, retrieving, and @@ -52,12 +53,12 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { - // Create permission set for requested user + // Create permission set for requested entity ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get(); - permissionSet.init(user, targetUser, effectiveGroups); + permissionSet.init(user, targetEntity, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java index 0cc69df17..1dc70ad7b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java @@ -24,7 +24,8 @@ import com.google.inject.Provider; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; /** * Service which provides convenience methods for creating, retrieving, and @@ -52,12 +53,12 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { - // Create permission set for requested user + // Create permission set for requested entity ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get(); - permissionSet.init(user, targetUser, effectiveGroups); + permissionSet.init(user, targetEntity, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java index f1105ed60..d9bb6bc28 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java @@ -24,9 +24,10 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; @@ -48,13 +49,14 @@ public abstract class ModeledObjectPermissionService } @Override - protected ObjectPermissionModel getModelInstance(ModeledUser targetUser, + protected ObjectPermissionModel getModelInstance( + ModeledPermissions targetEntity, ObjectPermission permission) { ObjectPermissionModel model = new ObjectPermissionModel(); - // Populate model object with data from user and permission - model.setEntityID(targetUser.getModel().getEntityID()); + // Populate model object with data from entity and permission + model.setEntityID(targetEntity.getModel().getEntityID()); model.setType(permission.getType()); model.setObjectIdentifier(permission.getObjectIdentifier()); @@ -64,31 +66,32 @@ public abstract class ModeledObjectPermissionService /** * Determines whether the current user has permission to update the given - * target user, adding or removing the given permissions. Such permission + * target entity, adding or removing the given permissions. Such permission * depends on whether the current user is a system administrator, whether - * they have explicit UPDATE permission on the target user, and whether + * they have explicit UPDATE permission on the target entity, and whether * they have explicit ADMINISTER permission on all affected objects. * Permission inheritance via user groups is taken into account. * * @param user * The user who is changing permissions. * - * @param targetUser - * The user whose permissions are being changed. + * @param targetEntity + * The entity whose permissions are being changed. * * @param permissions * The permissions that are being added or removed from the target - * user. + * entity. * * @return - * true if the user has permission to change the target users + * true if the user has permission to change the target entity's * permissions as specified, false otherwise. * * @throws GuacamoleException * If an error occurs while checking permission status, or if * permission is denied to read the current user's permissions. */ - protected boolean canAlterPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, + protected boolean canAlterPermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { @@ -96,9 +99,9 @@ public abstract class ModeledObjectPermissionService if (user.getUser().isAdministrator()) return true; - // Verify user has update permission on the target user - ObjectPermissionSet userPermissionSet = user.getUser().getEffectivePermissions().getUserPermissions(); - if (!userPermissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetUser.getIdentifier())) + // Verify user has update permission on the target entity + ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity); + if (!permissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetEntity.getIdentifier())) return false; // Produce collection of affected identifiers @@ -122,13 +125,14 @@ public abstract class ModeledObjectPermissionService } @Override - public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, + public void createPermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { // Create permissions only if user has permission to do so - if (canAlterPermissions(user, targetUser, permissions)) { - Collection models = getModelInstances(targetUser, permissions); + if (canAlterPermissions(user, targetEntity, permissions)) { + Collection models = getModelInstances(targetEntity, permissions); getPermissionMapper().insert(models); return; } @@ -139,13 +143,14 @@ public abstract class ModeledObjectPermissionService } @Override - public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, + public void deletePermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { // Delete permissions only if user has permission to do so - if (canAlterPermissions(user, targetUser, permissions)) { - Collection models = getModelInstances(targetUser, permissions); + if (canAlterPermissions(user, targetEntity, permissions)) { + Collection models = getModelInstances(targetEntity, permissions); getPermissionMapper().delete(models); return; } @@ -157,23 +162,24 @@ public abstract class ModeledObjectPermissionService @Override public boolean hasPermission(ModeledAuthenticatedUser user, - ModeledUser targetUser, ObjectPermission.Type type, - String identifier, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + ObjectPermission.Type type, String identifier, + Set effectiveGroups) throws GuacamoleException { // Retrieve permissions only if allowed - if (canReadPermissions(user, targetUser)) - return getPermissionMapper().selectOne(targetUser.getModel(), type, - identifier, effectiveGroups) != null; + if (canReadPermissions(user, targetEntity)) + return getPermissionMapper().selectOne(targetEntity.getModel(), + type, identifier, effectiveGroups) != null; - // User cannot read this user's permissions + // User cannot read this entity's permissions throw new GuacamoleSecurityException("Permission denied."); } @Override public Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, - ModeledUser targetUser, Collection permissions, + ModeledPermissions targetEntity, + Collection permissions, Collection identifiers, Set effectiveGroups) throws GuacamoleException { @@ -182,7 +188,7 @@ public abstract class ModeledObjectPermissionService return identifiers; // Retrieve permissions only if allowed - if (canReadPermissions(user, targetUser)) { + if (canReadPermissions(user, targetEntity)) { // If user is an admin, everything is accessible if (user.getUser().isAdministrator()) @@ -190,12 +196,12 @@ public abstract class ModeledObjectPermissionService // Otherwise, return explicitly-retrievable identifiers return getPermissionMapper().selectAccessibleIdentifiers( - targetUser.getModel(), permissions, identifiers, + targetEntity.getModel(), permissions, identifiers, effectiveGroups); } - // User cannot read this user's permissions + // User cannot read this entity's permissions throw new GuacamoleSecurityException("Permission denied."); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java index dadaea619..a102f3434 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java @@ -24,9 +24,10 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.PermissionSet; @@ -97,42 +98,44 @@ public abstract class ModeledPermissionService targetEntity, PermissionType permission); /** * Returns a collection of model objects which are based on the given - * permissions and target user. + * permissions and target entity. * - * @param targetUser - * The user to whom this permission is granted. + * @param targetEntity + * The entity to whom this permission is granted. * * @param permissions * The permissions to use to produce the returned model objects. * * @return * A collection of model objects which are based on the given - * permissions and target user. + * permissions and target entity. */ - protected Collection getModelInstances(ModeledUser targetUser, + protected Collection getModelInstances( + ModeledPermissions targetEntity, Collection permissions) { // Create new collection of models by manually converting each permission Collection models = new ArrayList(permissions.size()); for (PermissionType permission : permissions) - models.add(getModelInstance(targetUser, permission)); + models.add(getModelInstance(targetEntity, permission)); return models; @@ -140,14 +143,14 @@ public abstract class ModeledPermissionService retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { // Retrieve permissions only if allowed - if (canReadPermissions(user, targetUser)) - return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), effectiveGroups)); + if (canReadPermissions(user, targetEntity)) + return getPermissionInstances(getPermissionMapper().select(targetEntity.getModel(), effectiveGroups)); - // User cannot read this user's permissions + // User cannot read this entity's permissions throw new GuacamoleSecurityException("Permission denied."); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java index 3f39881cb..a841c96c3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java @@ -22,8 +22,9 @@ package org.apache.guacamole.auth.jdbc.permission; import java.util.Collection; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; @@ -37,13 +38,13 @@ public interface ObjectPermissionService /** * Returns whether the permission of the given type and associated with the - * given object has been granted to the given user. + * given object has been granted to the given entity. * * @param user * The user retrieving the permission. * - * @param targetUser - * The user associated with the permission to be retrieved. + * @param targetEntity + * The entity associated with the permission to be retrieved. * * @param type * The type of permission to retrieve. @@ -53,30 +54,31 @@ public interface ObjectPermissionService * * @param effectiveGroups * The identifiers of all groups that should be taken into account - * when determining the permissions effectively granted to the user. If - * no groups are given, only permissions directly granted to the user - * will be used. + * when determining the permissions effectively granted to the entity. + * If no groups are given, only permissions directly granted to the + * entity will be used. * * @return * true if permission of the given type and associated with the given - * object has been granted to the given user, false otherwise. + * object has been granted to the given entity, false otherwise. * * @throws GuacamoleException * If an error occurs while retrieving the requested permission. */ boolean hasPermission(ModeledAuthenticatedUser user, - ModeledUser targetUser, ObjectPermission.Type type, - String identifier, Set effectiveGroups) throws GuacamoleException; + ModeledPermissions targetEntity, + ObjectPermission.Type type, String identifier, + Set effectiveGroups) throws GuacamoleException; /** - * Retrieves the subset of the given identifiers for which the given user + * Retrieves the subset of the given identifiers for which the given entity * has at least one of the given permissions. * * @param user * The user checking the permissions. * - * @param targetUser - * The user to check permissions of. + * @param targetEntity + * The entity to check permissions of. * * @param permissions * The permissions to check. An identifier will be included in the @@ -89,9 +91,9 @@ public interface ObjectPermissionService * * @param effectiveGroups * The identifiers of all groups that should be taken into account - * when determining the permissions effectively granted to the user. If - * no groups are given, only permissions directly granted to the user - * will be used. + * when determining the permissions effectively granted to the entity. + * If no groups are given, only permissions directly granted to the + * entity will be used. * * @return * A collection containing the subset of identifiers for which at least @@ -101,7 +103,8 @@ public interface ObjectPermissionService * If an error occurs while retrieving permissions. */ Collection retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, - ModeledUser targetUser, Collection permissions, + ModeledPermissions targetEntity, + Collection permissions, Collection identifiers, Set effectiveGroups) throws GuacamoleException; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java index c15b1af5b..d179c686a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java @@ -19,29 +19,34 @@ package org.apache.guacamole.auth.jdbc.permission; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import java.util.Collection; import java.util.Collections; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.net.auth.permission.ObjectPermission; /** * A database implementation of ObjectPermissionSet which uses an injected * service to query and manipulate the object-level permissions associated with - * a particular user. + * a particular entity. */ public abstract class ObjectPermissionSet extends RestrictedObject implements org.apache.guacamole.net.auth.permission.ObjectPermissionSet { /** - * The user associated with this permission set. Each of the permissions in - * this permission set is granted to this user. + * The entity associated with this permission set. Each of the permissions + * in this permission set is granted to this entity. */ - private ModeledUser user; + private ModeledPermissions entity; + /** + * The identifiers of all groups that should be taken into account + * when determining the permissions effectively granted to the entity. + */ private Set effectiveGroups; /** @@ -53,26 +58,27 @@ public abstract class ObjectPermissionSet extends RestrictedObject } /** - * Initializes this permission set with the current user and the user + * Initializes this permission set with the current user and the entity * to whom the permissions in this set are granted. * * @param currentUser * The user who queried this permission set, and whose permissions * dictate the access level of all operations performed on this set. * - * @param user - * The user to whom the permissions in this set are granted. + * @param entity + * The entity to whom the permissions in this set are granted. * * @param effectiveGroups * The identifiers of all groups that should be taken into account - * when determining the permissions effectively granted to the user. If - * no groups are given, only permissions directly granted to the user - * will be used. + * when determining the permissions effectively granted to the entity. + * If no groups are given, only permissions directly granted to the + * entity will be used. */ - public void init(ModeledAuthenticatedUser currentUser, ModeledUser user, + public void init(ModeledAuthenticatedUser currentUser, + ModeledPermissions entity, Set effectiveGroups) { super.init(currentUser); - this.user = user; + this.entity = entity; this.effectiveGroups = effectiveGroups; } @@ -88,13 +94,13 @@ public abstract class ObjectPermissionSet extends RestrictedObject @Override public Set getPermissions() throws GuacamoleException { - return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, effectiveGroups); + return getObjectPermissionService().retrievePermissions(getCurrentUser(), entity, effectiveGroups); } @Override public boolean hasPermission(ObjectPermission.Type permission, String identifier) throws GuacamoleException { - return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, effectiveGroups); + return getObjectPermissionService().hasPermission(getCurrentUser(), entity, permission, identifier, effectiveGroups); } @Override @@ -112,19 +118,19 @@ public abstract class ObjectPermissionSet extends RestrictedObject @Override public Collection getAccessibleObjects(Collection permissions, Collection identifiers) throws GuacamoleException { - return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, effectiveGroups); + return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), entity, permissions, identifiers, effectiveGroups); } @Override public void addPermissions(Set permissions) throws GuacamoleException { - getObjectPermissionService().createPermissions(getCurrentUser(), user, permissions); + getObjectPermissionService().createPermissions(getCurrentUser(), entity, permissions); } @Override public void removePermissions(Set permissions) throws GuacamoleException { - getObjectPermissionService().deletePermissions(getCurrentUser(), user, permissions); + getObjectPermissionService().deletePermissions(getCurrentUser(), entity, permissions); } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java index 3caa5874c..5d88887e7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java @@ -22,8 +22,9 @@ package org.apache.guacamole.auth.jdbc.permission; import java.util.Collection; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.PermissionSet; @@ -44,59 +45,60 @@ public interface PermissionService effectiveGroups) - throws GuacamoleException; + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException; /** - * Retrieves all permissions associated with the given user. + * Retrieves all permissions associated with the given entity. * * @param user * The user retrieving the permissions. * - * @param targetUser - * The user associated with the permissions to be retrieved. + * @param targetEntity + * The entity associated with the permissions to be retrieved. * * @param effectiveGroups * The identifiers of all groups that should be taken into account - * when determining the permissions effectively granted to the user. If - * no groups are given, only permissions directly granted to the user - * will be used. + * when determining the permissions effectively granted to the entity. + * If no groups are given, only permissions directly granted to the + * entity will be used. * * @return - * The permissions associated with the given user. + * The permissions associated with the given entity. * * @throws GuacamoleException * If an error occurs while retrieving the requested permissions. */ Set retrievePermissions(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException; + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException; /** * Creates the given permissions within the database. If any permissions @@ -105,8 +107,8 @@ public interface PermissionService permissions) throws GuacamoleException; + void createPermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, + Collection permissions) + throws GuacamoleException; /** * Deletes the given permissions. If any permissions do not exist, they @@ -125,17 +129,19 @@ public interface PermissionService permissions) throws GuacamoleException; + void deletePermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, + Collection permissions) + throws GuacamoleException; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java index 3018b290d..c30ff73b6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java @@ -24,7 +24,8 @@ import com.google.inject.Provider; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; /** * Service which provides convenience methods for creating, retrieving, and @@ -52,12 +53,12 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { - // Create permission set for requested user + // Create permission set for requested entity ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get(); - permissionSet.init(user, targetUser, effectiveGroups); + permissionSet.init(user, targetEntity, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java index b534ad3fa..c94a260c6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java @@ -24,10 +24,11 @@ import com.google.inject.Provider; import java.util.Collection; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleUnsupportedException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.net.auth.permission.SystemPermission; /** @@ -61,13 +62,14 @@ public class SystemPermissionService } @Override - protected SystemPermissionModel getModelInstance(final ModeledUser targetUser, + protected SystemPermissionModel getModelInstance( + final ModeledPermissions targetEntity, final SystemPermission permission) { SystemPermissionModel model = new SystemPermissionModel(); // Populate model object with data from user and permission - model.setEntityID(targetUser.getModel().getEntityID()); + model.setEntityID(targetEntity.getModel().getEntityID()); model.setType(permission.getType()); return model; @@ -76,23 +78,25 @@ public class SystemPermissionService @Override public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { // Create permission set for requested user SystemPermissionSet permissionSet = systemPermissionSetProvider.get(); - permissionSet.init(user, targetUser, effectiveGroups); + permissionSet.init(user, targetEntity, effectiveGroups); return permissionSet; } @Override - public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, + public void createPermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { // Only an admin can create system permissions if (user.getUser().isAdministrator()) { - Collection models = getModelInstances(targetUser, permissions); + Collection models = getModelInstances(targetEntity, permissions); systemPermissionMapper.insert(models); return; } @@ -103,17 +107,18 @@ public class SystemPermissionService } @Override - public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, + public void deletePermissions(ModeledAuthenticatedUser user, + ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { // Only an admin can delete system permissions if (user.getUser().isAdministrator()) { // Do not allow users to remove their own admin powers - if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())) + if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier())) throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed."); - Collection models = getModelInstances(targetUser, permissions); + Collection models = getModelInstances(targetEntity, permissions); systemPermissionMapper.delete(models); return; } @@ -125,14 +130,14 @@ public class SystemPermissionService /** * Retrieves whether the permission of the given type has been granted to - * the given user. Permission inheritance through group membership is taken - * into account. + * the given entity. Permission inheritance through group membership is + * taken into account. * * @param user * The user retrieving the permission. * - * @param targetUser - * The user associated with the permission to be retrieved. + * @param targetEntity + * The entity associated with the permission to be retrieved. * * @param type * The type of permission to retrieve. @@ -151,12 +156,13 @@ public class SystemPermissionService * If an error occurs while retrieving the requested permission. */ public boolean hasPermission(ModeledAuthenticatedUser user, - ModeledUser targetUser, SystemPermission.Type type, - Set effectiveGroups) throws GuacamoleException { + ModeledPermissions targetEntity, + SystemPermission.Type type, Set effectiveGroups) + throws GuacamoleException { // Retrieve permissions only if allowed - if (canReadPermissions(user, targetUser)) - return getPermissionMapper().selectOne(targetUser.getModel(), type, effectiveGroups) != null; + if (canReadPermissions(user, targetEntity)) + return getPermissionMapper().selectOne(targetEntity.getModel(), type, effectiveGroups) != null; // User cannot read this user's permissions throw new GuacamoleSecurityException("Permission denied."); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java index dd8887901..1948facaa 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java @@ -19,29 +19,34 @@ package org.apache.guacamole.auth.jdbc.permission; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; import com.google.inject.Inject; import java.util.Collections; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.net.auth.permission.SystemPermission; /** * A database implementation of SystemPermissionSet which uses an injected * service to query and manipulate the system permissions associated with a - * particular user. + * particular entity. */ public class SystemPermissionSet extends RestrictedObject implements org.apache.guacamole.net.auth.permission.SystemPermissionSet { /** - * The user associated with this permission set. Each of the permissions in - * this permission set is granted to this user. + * The entity associated with this permission set. Each of the permissions + * in this permission set is granted to this entity. */ - private ModeledUser user; + private ModeledPermissions entity; + /** + * The identifiers of all groups that should be taken into account when + * determining the permissions effectively granted to the entity. + */ private Set effectiveGroups; /** @@ -59,38 +64,39 @@ public class SystemPermissionSet extends RestrictedObject } /** - * Initializes this permission set with the current user and the user + * Initializes this permission set with the current user and the entity * to whom the permissions in this set are granted. * * @param currentUser * The user who queried this permission set, and whose permissions * dictate the access level of all operations performed on this set. * - * @param user - * The user to whom the permissions in this set are granted. + * @param entity + * The entity to whom the permissions in this set are granted. * * @param effectiveGroups * The identifiers of all groups that should be taken into account - * when determining the permissions effectively granted to the user. If - * no groups are given, only permissions directly granted to the user - * will be used. + * when determining the permissions effectively granted to the entity. + * If no groups are given, only permissions directly granted to the + * entity will be used. */ - public void init(ModeledAuthenticatedUser currentUser, ModeledUser user, + public void init(ModeledAuthenticatedUser currentUser, + ModeledPermissions entity, Set effectiveGroups) { super.init(currentUser); - this.user = user; + this.entity = entity; this.effectiveGroups = effectiveGroups; } @Override public Set getPermissions() throws GuacamoleException { - return systemPermissionService.retrievePermissions(getCurrentUser(), user, effectiveGroups); + return systemPermissionService.retrievePermissions(getCurrentUser(), entity, effectiveGroups); } @Override public boolean hasPermission(SystemPermission.Type permission) throws GuacamoleException { - return systemPermissionService.hasPermission(getCurrentUser(), user, permission, effectiveGroups); + return systemPermissionService.hasPermission(getCurrentUser(), entity, permission, effectiveGroups); } @Override @@ -108,13 +114,13 @@ public class SystemPermissionSet extends RestrictedObject @Override public void addPermissions(Set permissions) throws GuacamoleException { - systemPermissionService.createPermissions(getCurrentUser(), user, permissions); + systemPermissionService.createPermissions(getCurrentUser(), entity, permissions); } @Override public void removePermissions(Set permissions) throws GuacamoleException { - systemPermissionService.deletePermissions(getCurrentUser(), user, permissions); + systemPermissionService.deletePermissions(getCurrentUser(), entity, permissions); } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java index fabbf72fd..ed8689a7f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java @@ -24,7 +24,8 @@ import com.google.inject.Provider; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.auth.jdbc.user.ModeledUser; +import org.apache.guacamole.auth.jdbc.base.EntityModel; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; /** * Service which provides convenience methods for creating, retrieving, and @@ -52,12 +53,12 @@ public class UserPermissionService extends ModeledObjectPermissionService { @Override public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, - ModeledUser targetUser, Set effectiveGroups) - throws GuacamoleException { + ModeledPermissions targetEntity, + Set effectiveGroups) throws GuacamoleException { - // Create permission set for requested user + // Create permission set for requested entity ObjectPermissionSet permissionSet = userPermissionSetProvider.get(); - permissionSet.init(user, targetUser, effectiveGroups); + permissionSet.init(user, targetEntity, effectiveGroups); return permissionSet; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 0bb199e23..9b6547139 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -33,16 +33,10 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; -import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObject; import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService; import org.apache.guacamole.auth.jdbc.security.SaltService; -import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService; -import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService; -import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService; -import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService; -import org.apache.guacamole.auth.jdbc.permission.UserPermissionService; +import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.form.BooleanField; import org.apache.guacamole.form.DateField; import org.apache.guacamole.form.EmailField; @@ -55,10 +49,6 @@ import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.RelatedObjectSet; import org.apache.guacamole.net.auth.User; -import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; -import org.apache.guacamole.net.auth.permission.SystemPermission; -import org.apache.guacamole.net.auth.permission.SystemPermissionSet; -import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet; import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +56,7 @@ import org.slf4j.LoggerFactory; /** * An implementation of the User object which is backed by a database model. */ -public class ModeledUser extends ModeledDirectoryObject implements User { +public class ModeledUser extends ModeledPermissions implements User { /** * Logger for this class. @@ -186,42 +176,6 @@ public class ModeledUser extends ModeledDirectoryObject implements Us @Inject private SaltService saltService; - /** - * Service for retrieving system permissions. - */ - @Inject - private SystemPermissionService systemPermissionService; - - /** - * Service for retrieving connection permissions. - */ - @Inject - private ConnectionPermissionService connectionPermissionService; - - /** - * Service for retrieving connection group permissions. - */ - @Inject - private ConnectionGroupPermissionService connectionGroupPermissionService; - - /** - * Service for retrieving sharing profile permissions. - */ - @Inject - private SharingProfilePermissionService sharingProfilePermissionService; - - /** - * Service for retrieving active connection permissions. - */ - @Inject - private ActiveConnectionPermissionService activeConnectionPermissionService; - - /** - * Service for retrieving user permissions. - */ - @Inject - private UserPermissionService userPermissionService; - /** * Whether attributes which control access restrictions should be exposed * via getAttributes() or allowed to be set via setAttributes(). @@ -331,70 +285,6 @@ public class ModeledUser extends ModeledDirectoryObject implements Us return passwordRecord; } - /** - * Returns whether this user is a system administrator, and thus is not - * restricted by permissions, taking into account permission inheritance - * via user groups. - * - * @return - * true if this user is a system administrator, false otherwise. - * - * @throws GuacamoleException - * If an error occurs while determining the user's system administrator - * status. - */ - public boolean isAdministrator() throws GuacamoleException { - SystemPermissionSet systemPermissionSet = getEffectivePermissions().getSystemPermissions(); - return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER); - } - - @Override - public SystemPermissionSet getSystemPermissions() - throws GuacamoleException { - return systemPermissionService.getPermissionSet(getCurrentUser(), this, - Collections.emptySet()); - } - - @Override - public ObjectPermissionSet getConnectionPermissions() - throws GuacamoleException { - return connectionPermissionService.getPermissionSet(getCurrentUser(), - this, Collections.emptySet()); - } - - @Override - public ObjectPermissionSet getConnectionGroupPermissions() - throws GuacamoleException { - return connectionGroupPermissionService.getPermissionSet( - getCurrentUser(), this, Collections.emptySet()); - } - - @Override - public ObjectPermissionSet getSharingProfilePermissions() - throws GuacamoleException { - return sharingProfilePermissionService.getPermissionSet( - getCurrentUser(), this, Collections.emptySet()); - } - - @Override - public ObjectPermissionSet getActiveConnectionPermissions() - throws GuacamoleException { - return activeConnectionPermissionService.getPermissionSet( - getCurrentUser(), this, Collections.emptySet()); - } - - @Override - public ObjectPermissionSet getUserPermissions() - throws GuacamoleException { - return userPermissionService.getPermissionSet(getCurrentUser(), this, - Collections.emptySet()); - } - - @Override - public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(); - } - /** * Stores all restricted (privileged) attributes within the given Map, * pulling the values of those attributes from the underlying user model. @@ -860,84 +750,9 @@ public class ModeledUser extends ModeledDirectoryObject implements Us return new SimpleRelatedObjectSet(); } - /** - * Returns the identifiers of all user groups defined within the database - * which apply to this user, including any groups inherited through - * membership in yet more groups. - * - * @return - * The identifiers of all user groups defined within the database which - * apply to this user. - */ - public Set getEffectiveUserGroups() { - return userService.retrieveEffectiveGroups(this, - Collections.emptySet()); - } - @Override public Permissions getEffectivePermissions() throws GuacamoleException { - - final ModeledAuthenticatedUser authenticatedUser = getCurrentUser(); - final Set effectiveGroups; - - // If this user is the currently-authenticated user, include any - // additional effective groups declared by the authentication system - if (authenticatedUser.getIdentifier().equals(getIdentifier())) - effectiveGroups = userService.retrieveEffectiveGroups(this, - authenticatedUser.getEffectiveUserGroups()); - - // Otherwise, just include effective groups from the database - else - effectiveGroups = getEffectiveUserGroups(); - - // Return a permissions object which describes all effective - // permissions, including any permissions inherited via user groups - return new Permissions() { - - @Override - public ObjectPermissionSet getActiveConnectionPermissions() - throws GuacamoleException { - return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); - } - - @Override - public ObjectPermissionSet getConnectionGroupPermissions() - throws GuacamoleException { - return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); - } - - @Override - public ObjectPermissionSet getConnectionPermissions() - throws GuacamoleException { - return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); - } - - @Override - public ObjectPermissionSet getSharingProfilePermissions() - throws GuacamoleException { - return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); - } - - @Override - public SystemPermissionSet getSystemPermissions() - throws GuacamoleException { - return systemPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); - } - - @Override - public ObjectPermissionSet getUserPermissions() - throws GuacamoleException { - return userPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups); - } - - @Override - public ObjectPermissionSet getUserGroupPermissions() - throws GuacamoleException { - // FIXME: STUB - return new SimpleObjectPermissionSet(); - } - - }; + return super.getEffective(); } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java index 6b5110560..cf829be58 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java @@ -19,8 +19,6 @@ package org.apache.guacamole.auth.jdbc.user; -import java.util.Collection; -import java.util.Set; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; import org.apache.ibatis.annotations.Param; @@ -41,24 +39,4 @@ public interface UserMapper extends ModeledDirectoryObjectMapper { */ UserModel selectOne(@Param("username") String username); - /** - * Returns the set of all group identifiers of which the given user is a - * member, taking into account the given collection of known group - * memberships which are not necessarily defined within the database. - * - * @param user - * The user whose effective groups should be returned. - * - * @param effectiveGroups - * The identifiers of any known effective groups that should be taken - * into account, such as those defined externally to the database. - * - * @return - * The set of identifiers of all groups that the given user is a - * member of, including those where membership is inherited through - * membership in other groups. - */ - Set selectEffectiveGroupIdentifiers(@Param("user") UserModel user, - @Param("effectiveGroups") Collection effectiveGroups); - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java index 6d89125a9..60bd1e146 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java @@ -26,7 +26,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; @@ -598,31 +597,4 @@ public class UserService extends ModeledDirectoryObjectService retrieveEffectiveGroups(ModeledUser user, - Collection effectiveGroups) { - return userMapper.selectEffectiveGroupIdentifiers(user.getModel(), effectiveGroups); - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml index 01830d759..b2ae26c35 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -59,6 +59,44 @@ ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index 25d7659a2..1181b3774 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -79,44 +79,6 @@ AND permission = 'READ' - - - + + SELECT + #{entity.entityID,jdbcType=INTEGER} AS entity_id, + permission, + affected_entity.name AS affected_name + FROM guacamole_user_group_permission + JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id + JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id + WHERE + + + + + + AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type + + + + + + + + + + + + + DELETE FROM guacamole_user_group_permission + USING guacamole_user_group affected_group, guacamole_entity affected_entity + WHERE + guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id + AND affected_group.entity_id = affected_entity.entity_id + AND (guacamole_user_group_permission.entity_id, permission, affected_entity.name) IN + + (#{permission.entityID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, + #{permission.objectIdentifier,jdbcType=INTEGER}) + + AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type + + + + + + + INSERT INTO guacamole_user_group_permission ( + entity_id, + permission, + affected_user_group_id + ) + SELECT DISTINCT + permissions.entity_id, + permissions.permission, + affected_group.user_group_id + FROM + + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, + #{permission.objectIdentifier,jdbcType=VARCHAR}::text AS affected_name + + AS permissions + JOIN guacamole_entity affected_entity ON + affected_entity.name = permissions.affected_name + AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type + JOIN guacamole_user_group affected_group ON affected_group.entity_id = affected_entity.entity_id + WHERE (permissions.entity_id, permissions.permission, affected_group.user_group_id) NOT IN ( + SELECT + guacamole_user_group_permission.entity_id, + guacamole_user_group_permission.permission, + guacamole_user_group_permission.affected_user_group_id + FROM guacamole_user_group_permission + ); + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml new file mode 100644 index 000000000..0006d4267 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_entity + WHERE + name = #{identifier,jdbcType=VARCHAR} + AND type = 'USER_GROUP'::guacamole_entity_type + + + + + + INSERT INTO guacamole_user_group ( + entity_id, + disabled + ) + VALUES ( + #{object.entityID,jdbcType=VARCHAR}, + #{object.disabled,jdbcType=BOOLEAN} + ) + + + + + + UPDATE guacamole_user_group + SET disabled = #{object.disabled,jdbcType=BOOLEAN} + WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR} + + + + + DELETE FROM guacamole_user_group_attribute + WHERE user_group_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_user_group_attribute ( + user_group_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + + From a39d86379730f5a163e8a2c96ac5f9ecaeefa4ec Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 8 Apr 2018 00:27:16 -0700 Subject: [PATCH 12/32] GUACAMOLE-220: Take group "disabled" flag into account when determining effective groups. Do not inherit from nor apply disabled groups. --- .../apache/guacamole/auth/jdbc/base/EntityMapper.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml index b2ae26c35..ca779a218 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -27,6 +27,7 @@ * SQL fragment which tests whether the value of the given column matches * the given entity ID. If group identifiers are provided, the IDs of the * entities for all groups having those identifiers are tested, as well. + * Disabled groups are ignored. * * @param column * The name of the column to test. This column MUST contain an entity @@ -45,8 +46,9 @@ ${column} = ${entityID} OR ${column} IN ( - SELECT entity_id + SELECT guacamole_entity.entity_id FROM guacamole_entity + JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id WHERE type = 'USER_GROUP'::guacamole_entity_type AND name IN @@ -54,6 +56,7 @@ open="(" separator="," close=")"> #{effectiveGroup,jdbcType=VARCHAR} + AND disabled = false ) ) @@ -69,11 +72,13 @@ JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id WHERE guacamole_user_group_member.member_entity_id = #{entity.entityID} + AND guacamole_user_group.disabled = false UNION SELECT guacamole_entity.entity_id FROM guacamole_entity + JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id WHERE type = 'USER_GROUP'::guacamole_entity_type AND name IN @@ -81,6 +86,7 @@ open="(" separator="," close=")"> #{effectiveGroup,jdbcType=VARCHAR} + AND guacamole_user_group.disabled = false UNION SELECT @@ -88,6 +94,8 @@ FROM related_entity JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id + WHERE + guacamole_user_group.disabled = false ) SELECT name FROM related_entity From 8f06b7a3f9293254a546914dd403e322546fe03b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2018 12:16:11 -0700 Subject: [PATCH 13/32] GUACAMOLE-220: Define base interfaces for mapping RelatedObjectSets to the database. --- .../auth/jdbc/base/ObjectRelationMapper.java | 126 +++++++++++ .../auth/jdbc/base/RelatedObjectSet.java | 211 ++++++++++++++++++ 2 files changed, 337 insertions(+) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java new file mode 100644 index 000000000..082db0fe2 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +import java.util.Collection; +import java.util.Set; +import org.apache.guacamole.auth.jdbc.user.UserModel; +import org.apache.ibatis.annotations.Param; + +/** + * Mapper for the relations represented by a particular RelatedObjectSet + * implementation. + * + * @param + * The underlying database model of the object on the parent side of the + * one-to-many relationship represented by the RelatedObjectSet mapped by + * this ObjectRelationMapper. + */ +public interface ObjectRelationMapper { + + /** + * Inserts rows as necessary to establish the one-to-many relationship + * represented by the RelatedObjectSet between the given parent and + * children. If the relation for any parent/child pair is already present, + * no attempt is made to insert a new row for that relation. + * + * @param parent + * The model of the object on the parent side of the one-to-many + * relationship represented by the RelatedObjectSet. + * + * @param children + * The identifiers of the objects on the child side of the one-to-many + * relationship represented by the RelatedObjectSet. + * + * @return + * The number of rows inserted. + */ + int insert(@Param("parent") ParentModelType parent, + @Param("children") Collection children); + + /** + * Deletes rows as necessary to establish the one-to-many relationship + * represented by the RelatedObjectSet between the given parent and + * children. If the relation for any parent/child pair does not exist, + * that specific relation is ignored, and deletion proceeds with the + * remaining relations. + * + * @param parent + * The model of the object on the parent side of the one-to-many + * relationship represented by the RelatedObjectSet. + * + * @param children + * The identifiers of the objects on the child side of the one-to-many + * relationship represented by the RelatedObjectSet. + * + * @return + * The number of rows deleted. + */ + int delete(@Param("parent") ParentModelType parent, + @Param("children") Collection children); + + /** + * Retrieves the identifiers of all objects on the child side of the + * one-to-many relationship represented by the RelatedObjectSet mapped by + * this ObjectRelationMapper. This should only be called on behalf of a + * system administrator. If identifiers are needed by a non-administrative + * user who must have explicit read rights, use + * selectReadableChildIdentifiers() instead. + * + * @param parent + * The model of the object on the parent side of the one-to-many + * relationship represented by the RelatedObjectSet. + * + * @return + * A Set containing the identifiers of all objects on the child side + * of the one-to-many relationship. + */ + Set selectChildIdentifiers(@Param("parent") ParentModelType parent); + + /** + * Retrieves the identifiers of all objects on the child side of the + * one-to-many relationship represented by the RelatedObjectSet mapped by + * this ObjectRelationMapper, including only those objects which are + * explicitly readable by the given user. If identifiers are needed by a + * system administrator (who, by definition, does not need explicit read + * rights), use selectChildIdentifiers() instead. + + * + * @param user + * The user whose permissions should determine whether an identifier + * is returned. + * + * @param effectiveGroups + * The identifiers of any known effective groups that should be taken + * into account, such as those defined externally to the database. + * + * @param parent + * The model of the object on the parent side of the one-to-many + * relationship represented by the RelatedObjectSet. + * + * @return + * A Set containing the identifiers of all readable objects on the + * child side of the one-to-many relationship. + */ + Set selectReadableChildIdentifiers(@Param("user") UserModel user, + @Param("effectiveGroups") Collection effectiveGroups, + @Param("parent") ParentModelType parent); + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java new file mode 100644 index 000000000..a46cb2763 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.base; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.net.auth.permission.ObjectPermission; +import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; + +/** + * A database implementation of RelatedObjectSet which provides access to a + * parent object and corresponding set of objects related to the parent, subject + * to object-level permissions. Though the parent and child objects have + * specific types, only the parent object's type is enforced through type + * parameters, as child objects are represented by identifiers only. + * + * @param + * The type of object that represents the parent side of the relation. + * + * @param + * The underlying database model of the parent object. + */ +public abstract class RelatedObjectSet, ParentModelType extends ObjectModel> + extends RestrictedObject implements org.apache.guacamole.net.auth.RelatedObjectSet { + + /** + * The parent object which shares some arbitrary relation with the objects + * within this set. + */ + private ParentObjectType parent; + + /** + * Creates a new RelatedObjectSet. The resulting object set must still be + * initialized by a call to init(). + */ + public RelatedObjectSet() { + } + + /** + * Initializes this RelatedObjectSet with the current user and the single + * object on the parent side of the one-to-many relation represented by the + * set. + * + * @param currentUser + * The user who queried this RelatedObjectSet, and whose permissions + * dictate the access level of all operations performed on this set. + * + * @param parent + * The parent object which shares some arbitrary relation with the + * objects within this set. + */ + public void init(ModeledAuthenticatedUser currentUser, ParentObjectType parent) { + super.init(currentUser); + this.parent = parent; + } + + /** + * Returns the mapper which provides low-level access to the the database + * models which drive the relation represented by this RelatedObjectSet. + * + * @return + * The mapper which provides low-level access to the the database + * models which drive the relation represented by this + * RelatedObjectSet. + */ + protected abstract ObjectRelationMapper getObjectRelationMapper(); + + /** + * Returns the permission set which exposes the effective permissions + * available to the current user regarding the objects on the parent side + * of the one-to-many relationship represented by this RelatedObjectSet. + * Permission inheritance through user groups is taken into account. + * + * @return + * The permission set which exposes the effective permissions + * available to the current user regarding the objects on the parent + * side of the one-to-many relationship represented by this + * RelatedObjectSet. + * + * @throws GuacamoleException + * If permission to query permission status is denied. + */ + protected abstract ObjectPermissionSet getParentObjectEffectivePermissionSet() + throws GuacamoleException; + + /** + * Returns the permission set which exposes the effective permissions + * available to the current user regarding the objects on the child side + * of the one-to-many relationship represented by this RelatedObjectSet. + * Permission inheritance through user groups is taken into account. + * + * @return + * The permission set which exposes the effective permissions + * available to the current user regarding the objects on the child + * side of the one-to-many relationship represented by this + * RelatedObjectSet. + * + * @throws GuacamoleException + * If permission to query permission status is denied. + */ + protected abstract ObjectPermissionSet getChildObjectEffectivePermissionSet() + throws GuacamoleException; + + /** + * Returns whether the current user has permission to alter that status of + * the relation between the parent object and the given child objects. + * + * @param identifiers + * The identifiers of all objects on the child side of the one-to-many + * relation being changed. + * + * @return + * true if the user has permission to make the described changes, + * false otherwise. + * + * @throws GuacamoleException + * If permission to query permission status is denied. + */ + private boolean canAlterRelation(Collection identifiers) + throws GuacamoleException { + + // System administrators may alter any relations + if (getCurrentUser().getUser().isAdministrator()) + return true; + + // Non-admin users require UPDATE permission on the parent object ... + if (!getParentObjectEffectivePermissionSet().hasPermission( + ObjectPermission.Type.UPDATE, parent.getIdentifier())) + return false; + + // ... as well as UPDATE permission on all child objects being changed + Collection accessibleIdentifiers = + getChildObjectEffectivePermissionSet().getAccessibleObjects( + Collections.singleton(ObjectPermission.Type.UPDATE), + identifiers); + + return accessibleIdentifiers.size() == identifiers.size(); + + } + + @Override + public Set getObjects() throws GuacamoleException { + + // Bypass permission checks if the user is a system admin + ModeledAuthenticatedUser user = getCurrentUser(); + if (user.getUser().isAdministrator()) + return getObjectRelationMapper().selectChildIdentifiers(parent.getModel()); + + // Otherwise only return explicitly readable identifiers + return getObjectRelationMapper().selectReadableChildIdentifiers( + user.getUser().getModel(), user.getEffectiveUserGroups(), + parent.getModel()); + + } + + @Override + public void addObjects(Set identifiers) throws GuacamoleException { + + // Nothing to do if nothing provided + if (identifiers.isEmpty()) + return; + + // Create relations only if permission is granted + if (canAlterRelation(identifiers)) + getObjectRelationMapper().insert(parent.getModel(), identifiers); + + // User lacks permission to add user groups + else + throw new GuacamoleSecurityException("Permission denied."); + + } + + @Override + public void removeObjects(Set identifiers) throws GuacamoleException { + + // Nothing to do if nothing provided + if (identifiers.isEmpty()) + return; + + // Delete relations only if permission is granted + if (canAlterRelation(identifiers)) + getObjectRelationMapper().delete(parent.getModel(), identifiers); + + // User lacks permission to remove user groups + else + throw new GuacamoleSecurityException("Permission denied."); + + } + +} From ccd7920b2238de6d634336c3c6e2a8b13fa7d2f8 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2018 13:16:34 -0700 Subject: [PATCH 14/32] GUACAMOLE-220: Map and allow manipulation of the user members of user groups. --- .../JDBCAuthenticationProviderModule.java | 2 + .../auth/jdbc/usergroup/ModeledUserGroup.java | 10 +- .../usergroup/UserGroupMemberUserMapper.java | 28 ++++++ .../usergroup/UserGroupMemberUserSet.java | 57 ++++++++++++ .../usergroup/UserGroupMemberUserMapper.xml | 93 +++++++++++++++++++ 5 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index b97e7e459..0750b109f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -85,6 +85,7 @@ import org.apache.guacamole.auth.jdbc.user.UserRecordMapper; import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper; +import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; @@ -136,6 +137,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { addMapperClass(SharingProfileParameterMapper.class); addMapperClass(SharingProfilePermissionMapper.class); addMapperClass(UserGroupMapper.class); + addMapperClass(UserGroupMemberUserMapper.class); addMapperClass(UserGroupPermissionMapper.class); addMapperClass(UserMapper.class); addMapperClass(UserPermissionMapper.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java index 470bfab54..3612eead2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java @@ -20,6 +20,7 @@ package org.apache.guacamole.auth.jdbc.usergroup; import com.google.inject.Inject; +import com.google.inject.Provider; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -74,10 +75,11 @@ public class ModeledUserGroup extends ModeledPermissions ))); /** - * Service for managing user groups. + * Provider for RelatedObjectSets containing the users that are members of + * this user group. */ @Inject - private UserGroupService userGroupService; + private Provider memberUserSetProvider; /** * Whether attributes which control access restrictions should be exposed @@ -180,7 +182,9 @@ public class ModeledUserGroup extends ModeledPermissions @Override public RelatedObjectSet getMemberUsers() throws GuacamoleException { - return new SimpleRelatedObjectSet(); + UserGroupMemberUserSet memberUserSet = memberUserSetProvider.get(); + memberUserSet.init(getCurrentUser(), this); + return memberUserSet; } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java new file mode 100644 index 000000000..b668d07fe --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.usergroup; + +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; + +/** + * Mapper for the one-to-many relationship between a user group and its user + * members. + */ +public interface UserGroupMemberUserMapper extends ObjectRelationMapper {} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java new file mode 100644 index 000000000..989df551f --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.usergroup; + +import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; +import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet; +import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; + +/** + * RelatedObjectSet implementation which represents the one-to-many + * relationship between a particular user group and its user members. + */ +public class UserGroupMemberUserSet extends RelatedObjectSet { + + /** + * Mapper for the relation between user groups and their user members. + */ + @Inject + private UserGroupMemberUserMapper userGroupMemberUserMapper; + + @Override + protected ObjectRelationMapper getObjectRelationMapper() { + return userGroupMemberUserMapper; + } + + @Override + protected ObjectPermissionSet + getParentObjectEffectivePermissionSet() throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions(); + } + + @Override + protected ObjectPermissionSet getChildObjectEffectivePermissionSet() + throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserPermissions(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml new file mode 100644 index 000000000..562b1ad47 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_entity + WHERE + user_group_id = #{parent.objectID,jdbcType=INTEGER} + AND guacamole_entity.entity_id = member_entity_id + AND guacamole_entity.type = 'USER'::guacamole_entity_type + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + #{parent.objectID,jdbcType=INTEGER}, + guacamole_entity.entity_id + FROM guacamole_entity + WHERE + guacamole_entity.name IN + + #{identifier} + + AND guacamole_entity.type = 'USER'::guacamole_entity_type + AND guacamole_entity.entity_id NOT IN ( + SELECT guacamole_user_group_member.member_entity_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER} + ) + + + From 63be247db6ca3292afec9ecc532c3bd88d3a7ed0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2018 13:39:16 -0700 Subject: [PATCH 15/32] GUACAMOLE-220: Map and allow manipulation of the user group members of user groups. --- .../JDBCAuthenticationProviderModule.java | 2 + .../auth/jdbc/usergroup/ModeledUserGroup.java | 11 ++- .../UserGroupMemberUserGroupMapper.java | 28 ++++++ .../UserGroupMemberUserGroupSet.java | 57 ++++++++++++ .../UserGroupMemberUserGroupMapper.xml | 93 +++++++++++++++++++ 5 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 0750b109f..ab7547f2c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -85,6 +85,7 @@ import org.apache.guacamole.auth.jdbc.user.UserRecordMapper; import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper; +import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService; import org.mybatis.guice.MyBatisModule; @@ -137,6 +138,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { addMapperClass(SharingProfileParameterMapper.class); addMapperClass(SharingProfilePermissionMapper.class); addMapperClass(UserGroupMapper.class); + addMapperClass(UserGroupMemberUserGroupMapper.class); addMapperClass(UserGroupMemberUserMapper.class); addMapperClass(UserGroupPermissionMapper.class); addMapperClass(UserMapper.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java index 3612eead2..fcf12508c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java @@ -81,6 +81,13 @@ public class ModeledUserGroup extends ModeledPermissions @Inject private Provider memberUserSetProvider; + /** + * Provider for RelatedObjectSets containing the user groups that are + * members of this user group. + */ + @Inject + private Provider memberUserGroupSetProvider; + /** * Whether attributes which control access restrictions should be exposed * via getAttributes() or allowed to be set via setAttributes(). @@ -189,7 +196,9 @@ public class ModeledUserGroup extends ModeledPermissions @Override public RelatedObjectSet getMemberUserGroups() throws GuacamoleException { - return new SimpleRelatedObjectSet(); + UserGroupMemberUserGroupSet memberUserGroupSet = memberUserGroupSetProvider.get(); + memberUserGroupSet.init(getCurrentUser(), this); + return memberUserGroupSet; } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java new file mode 100644 index 000000000..70baef713 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.usergroup; + +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; + +/** + * Mapper for the one-to-many relationship between a user group and its user + * group members. + */ +public interface UserGroupMemberUserGroupMapper extends ObjectRelationMapper {} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java new file mode 100644 index 000000000..9684a47b6 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.usergroup; + +import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; +import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet; +import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; + +/** + * RelatedObjectSet implementation which represents the one-to-many + * relationship between a particular user group and its user group members. + */ +public class UserGroupMemberUserGroupSet extends RelatedObjectSet { + + /** + * Mapper for the relation between user groups and their user group members. + */ + @Inject + private UserGroupMemberUserGroupMapper userGroupMemberUserGroupMapper; + + @Override + protected ObjectRelationMapper getObjectRelationMapper() { + return userGroupMemberUserGroupMapper; + } + + @Override + protected ObjectPermissionSet + getParentObjectEffectivePermissionSet() throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions(); + } + + @Override + protected ObjectPermissionSet getChildObjectEffectivePermissionSet() + throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml new file mode 100644 index 000000000..13f4d71a9 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_entity + WHERE + user_group_id = #{parent.objectID,jdbcType=INTEGER} + AND guacamole_entity.entity_id = member_entity_id + AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + #{parent.objectID,jdbcType=INTEGER}, + guacamole_entity.entity_id + FROM guacamole_entity + WHERE + guacamole_entity.name IN + + #{identifier} + + AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type + AND guacamole_entity.entity_id NOT IN ( + SELECT guacamole_user_group_member.member_entity_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER} + ) + + + From 856ab44373df4e6b458c3c9c63536afb17af265e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2018 14:31:13 -0700 Subject: [PATCH 16/32] GUACAMOLE-220: Map and allow manipulation of the user group parents of user groups. --- .../JDBCAuthenticationProviderModule.java | 2 + .../auth/jdbc/usergroup/ModeledUserGroup.java | 12 ++- .../UserGroupParentUserGroupMapper.java | 28 ++++++ .../UserGroupParentUserGroupSet.java | 58 +++++++++++ .../UserGroupParentUserGroupMapper.xml | 96 +++++++++++++++++++ 5 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index ab7547f2c..2d4c67a09 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -87,6 +87,7 @@ import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper; +import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; @@ -140,6 +141,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { addMapperClass(UserGroupMapper.class); addMapperClass(UserGroupMemberUserGroupMapper.class); addMapperClass(UserGroupMemberUserMapper.class); + addMapperClass(UserGroupParentUserGroupMapper.class); addMapperClass(UserGroupPermissionMapper.class); addMapperClass(UserMapper.class); addMapperClass(UserPermissionMapper.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java index fcf12508c..914a29246 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java @@ -35,7 +35,6 @@ import org.apache.guacamole.form.Field; import org.apache.guacamole.form.Form; import org.apache.guacamole.net.auth.RelatedObjectSet; import org.apache.guacamole.net.auth.UserGroup; -import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet; /** * An implementation of the UserGroup object which is backed by a database model. @@ -74,6 +73,13 @@ public class ModeledUserGroup extends ModeledPermissions DISABLED_ATTRIBUTE_NAME ))); + /** + * Provider for RelatedObjectSets containing the user groups of which this + * user group is a member. + */ + @Inject + private Provider parentUserGroupSetProvider; + /** * Provider for RelatedObjectSets containing the users that are members of * this user group. @@ -184,7 +190,9 @@ public class ModeledUserGroup extends ModeledPermissions @Override public RelatedObjectSet getUserGroups() throws GuacamoleException { - return new SimpleRelatedObjectSet(); + UserGroupParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get(); + parentUserGroupSet.init(getCurrentUser(), this); + return parentUserGroupSet; } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java new file mode 100644 index 000000000..37433cc8c --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.usergroup; + +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; + +/** + * Mapper for the one-to-many relationship between a user group and its + * containing user groups. + */ +public interface UserGroupParentUserGroupMapper extends ObjectRelationMapper {} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java new file mode 100644 index 000000000..ee1f8efad --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.usergroup; + +import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; +import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet; +import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; + +/** + * RelatedObjectSet implementation which represents the one-to-many + * relationship between a particular user group and its containing user groups. + */ +public class UserGroupParentUserGroupSet extends RelatedObjectSet { + + /** + * Mapper for the relation between user groups and their containing user + * groups. + */ + @Inject + private UserGroupParentUserGroupMapper userGroupParentUserGroupMapper; + + @Override + protected ObjectRelationMapper getObjectRelationMapper() { + return userGroupParentUserGroupMapper; + } + + @Override + protected ObjectPermissionSet + getParentObjectEffectivePermissionSet() throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions(); + } + + @Override + protected ObjectPermissionSet getChildObjectEffectivePermissionSet() + throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml new file mode 100644 index 000000000..035211c97 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_user_group, guacamole_entity + WHERE + member_entity_id = #{parent.entityID,jdbcType=INTEGER} + AND guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id + AND guacamole_entity.entity_id = guacamole_user_group.entity_id + AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + guacamole_user_group.user_group_id, + #{parent.entityID,jdbcType=INTEGER} + FROM guacamole_user_group + JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type + AND guacamole_user_group.user_group_id NOT IN ( + SELECT guacamole_user_group_member.user_group_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER} + ) + + + From 2999c560980d48bcf58befebbc6d9dde98db3a36 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Apr 2018 15:18:38 -0700 Subject: [PATCH 17/32] GUACAMOLE-220: Map and allow manipulation of the user group parents of users. --- .../JDBCAuthenticationProviderModule.java | 2 + .../guacamole/auth/jdbc/user/ModeledUser.java | 13 ++- .../jdbc/user/UserParentUserGroupMapper.java | 28 ++++++ .../jdbc/user/UserParentUserGroupSet.java | 59 ++++++++++++ .../jdbc/user/UserParentUserGroupMapper.xml | 96 +++++++++++++++++++ 5 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 2d4c67a09..5203cfee7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -91,6 +91,7 @@ import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; +import org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper; /** * Guice module which configures the injections used by the JDBC authentication @@ -144,6 +145,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { addMapperClass(UserGroupParentUserGroupMapper.class); addMapperClass(UserGroupPermissionMapper.class); addMapperClass(UserMapper.class); + addMapperClass(UserParentUserGroupMapper.class); addMapperClass(UserPermissionMapper.class); addMapperClass(UserRecordMapper.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 9b6547139..b7924edd9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -20,6 +20,7 @@ package org.apache.guacamole.auth.jdbc.user; import com.google.inject.Inject; +import com.google.inject.Provider; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; @@ -49,7 +50,6 @@ import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.RelatedObjectSet; import org.apache.guacamole.net.auth.User; -import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -176,6 +176,13 @@ public class ModeledUser extends ModeledPermissions implements User { @Inject private SaltService saltService; + /** + * Provider for RelatedObjectSets containing the user groups of which this + * user is a member. + */ + @Inject + private Provider parentUserGroupSetProvider; + /** * Whether attributes which control access restrictions should be exposed * via getAttributes() or allowed to be set via setAttributes(). @@ -747,7 +754,9 @@ public class ModeledUser extends ModeledPermissions implements User { @Override public RelatedObjectSet getUserGroups() throws GuacamoleException { - return new SimpleRelatedObjectSet(); + UserParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get(); + parentUserGroupSet.init(getCurrentUser(), this); + return parentUserGroupSet; } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java new file mode 100644 index 000000000..ee3d6a8dd --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.user; + +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; + +/** + * Mapper for the one-to-many relationship between a user and the user groups + * of which it is a member. + */ +public interface UserParentUserGroupMapper extends ObjectRelationMapper {} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java new file mode 100644 index 000000000..f88872962 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.user; + +import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; +import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet; +import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; + +/** + * RelatedObjectSet implementation which represents the one-to-many + * relationship between a particular user and the user groups of which it is a + * member. + */ +public class UserParentUserGroupSet extends RelatedObjectSet { + + /** + * Mapper for the relations between users and the user groups of which they + * are members. + */ + @Inject + private UserParentUserGroupMapper userParentUserGroupMapper; + + @Override + protected ObjectRelationMapper getObjectRelationMapper() { + return userParentUserGroupMapper; + } + + @Override + protected ObjectPermissionSet + getParentObjectEffectivePermissionSet() throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserPermissions(); + } + + @Override + protected ObjectPermissionSet getChildObjectEffectivePermissionSet() + throws GuacamoleException { + return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml new file mode 100644 index 000000000..bcff7a259 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_user_group, guacamole_entity + WHERE + member_entity_id = #{parent.entityID,jdbcType=INTEGER} + AND guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id + AND guacamole_entity.entity_id = guacamole_user_group.entity_id + AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + guacamole_user_group.user_group_id, + #{parent.entityID,jdbcType=INTEGER} + FROM guacamole_user_group + JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type + AND guacamole_user_group.user_group_id NOT IN ( + SELECT guacamole_user_group_member.user_group_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER} + ) + + + From 48948fc24565f28ba4c98974332364022576f538 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 19 Apr 2018 23:50:19 -0700 Subject: [PATCH 18/32] GUACAMOLE-220: Add missing JDBC-specific USER_GROUP_ATTRIBUTES translation strings. --- .../src/main/resources/translations/en.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json index ff1484230..5520a81d4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json @@ -100,6 +100,14 @@ "SECTION_HEADER_RESTRICTIONS" : "Account Restrictions", "SECTION_HEADER_PROFILE" : "Profile" + }, + + "USER_GROUP_ATTRIBUTES" : { + + "FIELD_HEADER_DISABLED" : "@:USER_ATTRIBUTES.FIELD_HEADER_DISABLED", + + "SECTION_HEADER_RESTRICTIONS" : "@:USER_ATTRIBUTES.SECTION_HEADER_RESTRICTIONS" + } } From 78d5e3b9d746f9f5994d59c46d3d7f953c61a5be Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 8 Sep 2018 01:13:36 -0700 Subject: [PATCH 19/32] GUACAMOLE-220: Manually recurse through the group membership graph if the database engine does not support recursive queries. --- .../guacamole/auth/jdbc/JDBCEnvironment.java | 11 ++++++++ .../auth/jdbc/base/EntityMapper.java | 6 +++++ .../auth/jdbc/base/EntityService.java | 25 ++++++++++++++++++- .../auth/mysql/MySQLEnvironment.java | 7 +++++- .../postgresql/PostgreSQLEnvironment.java | 5 ++++ .../auth/sqlserver/SQLServerEnvironment.java | 7 +++++- 6 files changed, 58 insertions(+), 3 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java index 53935e62f..93cc7f7a3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java @@ -137,4 +137,15 @@ public abstract class JDBCEnvironment extends LocalEnvironment { */ public abstract PasswordPolicy getPasswordPolicy(); + /** + * Returns whether the database supports recursive queries. Many database + * engines support recursive queries through CTEs. If recursive queries are + * not supported, queries that are intended to be recursive may need to be + * invoked multiple times to retrieve the same data. + * + * @return + * true if the database supports recursive queries, false otherwise. + */ + public abstract boolean isRecursiveQuerySupported(); + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java index 31efad5fc..53b029091 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java @@ -47,6 +47,12 @@ public interface EntityMapper { * member, taking into account the given collection of known group * memberships which are not necessarily defined within the database. * + * NOTE: This query is expected to handle recursion through the membership + * graph on its own. If the database engine does not support recursive + * queries (isRecursiveQuerySupported() of JDBCEnvironment returns false), + * then this query will only return one level of depth past the effective + * groups given and will need to be invoked multiple times. + * * @param entity * The entity whose effective groups should be returned. * diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java index fa71feee0..1e40bb0ae 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc.base; import com.google.inject.Inject; import java.util.Collection; import java.util.Set; +import org.apache.guacamole.auth.jdbc.JDBCEnvironment; /** * Service which provides convenience methods for creating, retrieving, and @@ -29,6 +30,12 @@ import java.util.Set; */ public class EntityService { + /** + * The Guacamole server environment. + */ + @Inject + private JDBCEnvironment environment; + /** * Mapper for Entity model objects. */ @@ -59,7 +66,23 @@ public class EntityService { */ public Set retrieveEffectiveGroups(ModeledPermissions entity, Collection effectiveGroups) { - return entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups); + + // Retrieve the effective user groups of the given entity, recursively if possible + Set identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups); + + // If the set of user groups retrieved was not produced recursively, + // manually repeat the query to expand the set until all effective + // groups have been found + if (!environment.isRecursiveQuerySupported() && !identifiers.isEmpty()) { + Set previousIdentifiers; + do { + previousIdentifiers = identifiers; + identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers); + } while (identifiers.size() > previousIdentifiers.size()); + } + + return identifiers; + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java index dc676db89..062d6dfa4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java @@ -225,5 +225,10 @@ public class MySQLEnvironment extends JDBCEnvironment { public String getMySQLPassword() throws GuacamoleException { return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD); } - + + @Override + public boolean isRecursiveQuerySupported() { + return false; // Only very recent versions of MySQL / MariaDB support recursive queries through CTEs + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java index da0caead2..d5d259e6f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java @@ -242,5 +242,10 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { public String getPostgreSQLPassword() throws GuacamoleException { return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD); } + + @Override + public boolean isRecursiveQuerySupported() { + return true; // All versions of PostgreSQL support recursive queries through CTEs + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java index 20361e630..03f2cf865 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java @@ -250,5 +250,10 @@ public class SQLServerEnvironment extends JDBCEnvironment { SQLSERVER_DEFAULT_DRIVER ); } - + + @Override + public boolean isRecursiveQuerySupported() { + return true; // All versions of SQL Server support recursive queries through CTEs + } + } From 1d0fcc1732fded614707b0e425af89eca0526e6a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 7 Sep 2018 20:49:13 -0700 Subject: [PATCH 20/32] GUACAMOLE-220: Add MySQL and SQL Server versions of user group schema. --- .../schema/001-create-schema.sql | 196 +++++-- .../schema/002-create-admin-user.sql | 26 +- .../schema/upgrade/upgrade-pre-1.0.0.sql | 335 +++++++++++ .../schema/001-create-schema.sql | 303 +++++++--- .../schema/002-create-admin-user.sql | 21 +- .../schema/upgrade/upgrade-pre-1.0.0.sql | 532 ++++++++++++++++++ 6 files changed, 1294 insertions(+), 119 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql index 76711f118..1606af1f3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql @@ -78,6 +78,25 @@ CREATE TABLE `guacamole_connection` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE `guacamole_entity` ( + + `entity_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `type` enum('USER', + 'USER_GROUP') NOT NULL, + + PRIMARY KEY (`entity_id`), + UNIQUE KEY `guacamole_entity_name_scope` (`type`, `name`) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- -- Table of users. Each user has a unique username and a hashed password -- with corresponding salt. Although the authentication system will always set @@ -88,9 +107,9 @@ CREATE TABLE `guacamole_connection` ( CREATE TABLE `guacamole_user` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, + `entity_id` int(11) NOT NULL, - -- Username and optionally-salted password - `username` varchar(128) NOT NULL, + -- Optionally-salted password `password_hash` binary(32) NOT NULL, `password_salt` binary(32), `password_date` datetime NOT NULL, @@ -117,7 +136,61 @@ CREATE TABLE `guacamole_user` ( `organizational_role` VARCHAR(256), PRIMARY KEY (`user_id`), - UNIQUE KEY `username` (`username`) + + UNIQUE KEY `guacamole_user_single_entity` (`entity_id`), + + CONSTRAINT `guacamole_user_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) + ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE `guacamole_user_group` ( + + `user_group_id` int(11) NOT NULL AUTO_INCREMENT, + `entity_id` int(11) NOT NULL, + + -- Group disabled status + `disabled` boolean NOT NULL DEFAULT 0, + + PRIMARY KEY (`user_group_id`), + + UNIQUE KEY `guacamole_user_group_single_entity` (`entity_id`), + + CONSTRAINT `guacamole_user_group_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) + ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE `guacamole_user_group_member` ( + + `user_group_id` int(11) NOT NULL, + `member_entity_id` int(11) NOT NULL, + + PRIMARY KEY (`user_group_id`, `member_entity_id`), + + -- Parent must be a user group + CONSTRAINT `guacamole_user_group_member_parent_id` + FOREIGN KEY (`user_group_id`) + REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT `guacamole_user_group_member_entity_id` + FOREIGN KEY (`member_entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -207,6 +280,28 @@ CREATE TABLE guacamole_user_attribute ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_user_group_attribute ( + + `user_group_id` int(11) NOT NULL, + `attribute_name` varchar(128) NOT NULL, + `attribute_value` varchar(4096) NOT NULL, + + PRIMARY KEY (`user_group_id`, `attribute_name`), + KEY `user_group_id` (`user_group_id`), + + CONSTRAINT `guacamole_user_group_attribute_ibfk_1` + FOREIGN KEY (`user_group_id`) + REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- -- Table of arbitrary connection attributes. Each attribute is simply a -- name/value pair associated with a connection. Arbitrary attributes are @@ -274,128 +369,157 @@ CREATE TABLE guacamole_sharing_profile_attribute ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- --- Table of connection permissions. Each connection permission grants a user --- specific access to a connection. +-- Table of connection permissions. Each connection permission grants a user or +-- user group specific access to a connection. -- CREATE TABLE `guacamole_connection_permission` ( - `user_id` int(11) NOT NULL, + `entity_id` int(11) NOT NULL, `connection_id` int(11) NOT NULL, `permission` enum('READ', 'UPDATE', 'DELETE', 'ADMINISTER') NOT NULL, - PRIMARY KEY (`user_id`,`connection_id`,`permission`), + PRIMARY KEY (`entity_id`,`connection_id`,`permission`), CONSTRAINT `guacamole_connection_permission_ibfk_1` FOREIGN KEY (`connection_id`) REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE, - CONSTRAINT `guacamole_connection_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT `guacamole_connection_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Table of connection group permissions. Each group permission grants a user --- specific access to a connection group. +-- or user group specific access to a connection group. -- CREATE TABLE `guacamole_connection_group_permission` ( - `user_id` int(11) NOT NULL, + `entity_id` int(11) NOT NULL, `connection_group_id` int(11) NOT NULL, `permission` enum('READ', 'UPDATE', 'DELETE', 'ADMINISTER') NOT NULL, - PRIMARY KEY (`user_id`,`connection_group_id`,`permission`), + PRIMARY KEY (`entity_id`,`connection_group_id`,`permission`), CONSTRAINT `guacamole_connection_group_permission_ibfk_1` FOREIGN KEY (`connection_group_id`) REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE, - CONSTRAINT `guacamole_connection_group_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT `guacamole_connection_group_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Table of sharing profile permissions. Each sharing profile permission grants --- a user specific access to a sharing profile. +-- a user or user group specific access to a sharing profile. -- CREATE TABLE guacamole_sharing_profile_permission ( - `user_id` integer NOT NULL, + `entity_id` integer NOT NULL, `sharing_profile_id` integer NOT NULL, `permission` enum('READ', 'UPDATE', 'DELETE', 'ADMINISTER') NOT NULL, - PRIMARY KEY (`user_id`, `sharing_profile_id`, `permission`), + PRIMARY KEY (`entity_id`, `sharing_profile_id`, `permission`), CONSTRAINT `guacamole_sharing_profile_permission_ibfk_1` FOREIGN KEY (`sharing_profile_id`) REFERENCES `guacamole_sharing_profile` (`sharing_profile_id`) ON DELETE CASCADE, - CONSTRAINT `guacamole_sharing_profile_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT `guacamole_sharing_profile_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- --- Table of system permissions. Each system permission grants a user a --- system-level privilege of some kind. +-- Table of system permissions. Each system permission grants a user or user +-- group a system-level privilege of some kind. -- CREATE TABLE `guacamole_system_permission` ( - `user_id` int(11) NOT NULL, + `entity_id` int(11) NOT NULL, `permission` enum('CREATE_CONNECTION', 'CREATE_CONNECTION_GROUP', 'CREATE_SHARING_PROFILE', 'CREATE_USER', + 'CREATE_USER_GROUP', 'ADMINISTER') NOT NULL, - PRIMARY KEY (`user_id`,`permission`), + PRIMARY KEY (`entity_id`,`permission`), - CONSTRAINT `guacamole_system_permission_ibfk_1` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT `guacamole_system_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- --- Table of user permissions. Each user permission grants a user access to --- another user (the "affected" user) for a specific type of operation. +-- Table of user permissions. Each user permission grants a user or user group +-- access to another user (the "affected" user) for a specific type of +-- operation. -- CREATE TABLE `guacamole_user_permission` ( - `user_id` int(11) NOT NULL, + `entity_id` int(11) NOT NULL, `affected_user_id` int(11) NOT NULL, `permission` enum('READ', 'UPDATE', 'DELETE', 'ADMINISTER') NOT NULL, - PRIMARY KEY (`user_id`,`affected_user_id`,`permission`), + PRIMARY KEY (`entity_id`,`affected_user_id`,`permission`), CONSTRAINT `guacamole_user_permission_ibfk_1` FOREIGN KEY (`affected_user_id`) REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE, - CONSTRAINT `guacamole_user_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT `guacamole_user_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of user group permissions. Each user group permission grants a user +-- or user group access to a another user group (the "affected" user group) for +-- a specific type of operation. +-- + +CREATE TABLE `guacamole_user_group_permission` ( + + `entity_id` int(11) NOT NULL, + `affected_user_group_id` int(11) NOT NULL, + `permission` enum('READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER') NOT NULL, + + PRIMARY KEY (`entity_id`, `affected_user_group_id`, `permission`), + + CONSTRAINT `guacamole_user_group_permission_affected_user_group` + FOREIGN KEY (`affected_user_group_id`) + REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE, + + CONSTRAINT `guacamole_user_group_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql index cfc831361..f62d6d1d2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql @@ -18,32 +18,36 @@ -- -- Create default user "guacadmin" with password "guacadmin" -INSERT INTO guacamole_user (username, password_hash, password_salt, password_date) -VALUES ('guacadmin', +INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER'); +INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date) +SELECT + entity_id, x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin' x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', - NOW()); + NOW() +FROM guacamole_entity WHERE name = 'guacadmin'; -- Grant this user all system permissions -INSERT INTO guacamole_system_permission -SELECT user_id, permission +INSERT INTO guacamole_system_permission (entity_id, permission) +SELECT entity_id, permission FROM ( SELECT 'guacadmin' AS username, 'CREATE_CONNECTION' AS permission UNION SELECT 'guacadmin' AS username, 'CREATE_CONNECTION_GROUP' AS permission UNION SELECT 'guacadmin' AS username, 'CREATE_SHARING_PROFILE' AS permission UNION SELECT 'guacadmin' AS username, 'CREATE_USER' AS permission + UNION SELECT 'guacadmin' AS username, 'CREATE_USER_GROUP' AS permission UNION SELECT 'guacadmin' AS username, 'ADMINISTER' AS permission ) permissions -JOIN guacamole_user ON permissions.username = guacamole_user.username; +JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'; -- Grant admin permission to read/update/administer self -INSERT INTO guacamole_user_permission -SELECT guacamole_user.user_id, affected.user_id, permission +INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission) +SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission FROM ( SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'READ' AS permission UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'UPDATE' AS permission UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'ADMINISTER' AS permission ) permissions -JOIN guacamole_user ON permissions.username = guacamole_user.username -JOIN guacamole_user affected ON permissions.affected_username = affected.username; - +JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER' +JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER' +JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql index 2979f533e..8332d7ff7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql @@ -17,6 +17,319 @@ -- under the License. -- +-- +-- Add new system-level permission +-- + +ALTER TABLE `guacamole_system_permission` + MODIFY `permission` enum('CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_SHARING_PROFILE', + 'CREATE_USER', + 'CREATE_USER_GROUP', + 'ADMINISTER') NOT NULL; + +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE `guacamole_entity` ( + + `entity_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `type` enum('USER', + 'USER_GROUP') NOT NULL, + + PRIMARY KEY (`entity_id`), + UNIQUE KEY `guacamole_entity_name_scope` (`type`, `name`) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE `guacamole_user_group` ( + + `user_group_id` int(11) NOT NULL AUTO_INCREMENT, + `entity_id` int(11) NOT NULL, + + -- Group disabled status + `disabled` boolean NOT NULL DEFAULT 0, + + PRIMARY KEY (`user_group_id`), + + UNIQUE KEY `guacamole_user_group_single_entity` (`entity_id`), + + CONSTRAINT `guacamole_user_group_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) + ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE `guacamole_user_group_member` ( + + `user_group_id` int(11) NOT NULL, + `member_entity_id` int(11) NOT NULL, + + PRIMARY KEY (`user_group_id`, `member_entity_id`), + + -- Parent must be a user group + CONSTRAINT `guacamole_user_group_member_parent_id` + FOREIGN KEY (`user_group_id`) + REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT `guacamole_user_group_member_entity_id` + FOREIGN KEY (`member_entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of user group permissions. Each user group permission grants a user +-- or user group access to a another user group (the "affected" user group) for +-- a specific type of operation. +-- + +CREATE TABLE `guacamole_user_group_permission` ( + + `entity_id` int(11) NOT NULL, + `affected_user_group_id` int(11) NOT NULL, + `permission` enum('READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER') NOT NULL, + + PRIMARY KEY (`entity_id`, `affected_user_group_id`, `permission`), + + CONSTRAINT `guacamole_user_group_permission_affected_user_group` + FOREIGN KEY (`affected_user_group_id`) + REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE, + + CONSTRAINT `guacamole_user_group_permission_entity` + FOREIGN KEY (`entity_id`) + REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Modify guacamole_user table to use guacamole_entity as a base +-- + +-- Add new entity_id column +ALTER TABLE guacamole_user ADD COLUMN entity_id int(11); + +-- Create user entities for each guacamole_user entry +INSERT INTO guacamole_entity (name, type) +SELECT username, 'USER' FROM guacamole_user; + +-- Update guacamole_user to point to corresponding guacamole_entity +UPDATE guacamole_user SET entity_id = ( + SELECT entity_id FROM guacamole_entity + WHERE + username = guacamole_entity.name + AND type = 'USER' +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_user MODIFY entity_id int(11) NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_user + ADD CONSTRAINT guacamole_user_single_entity + UNIQUE (entity_id); + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_user + ADD CONSTRAINT guacamole_user_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- The username column can now safely be removed +ALTER TABLE guacamole_user DROP COLUMN username; + +-- +-- Modify guacamole_connection_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_connection_permission ADD COLUMN entity_id int(11); + +-- Update guacamole_connection_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_connection_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_connection_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_connection_permission MODIFY entity_id int(11) NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_connection_permission + ADD CONSTRAINT guacamole_connection_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- Remove user_id column +ALTER TABLE guacamole_connection_permission DROP FOREIGN KEY guacamole_connection_permission_ibfk_2; +ALTER TABLE guacamole_connection_permission DROP PRIMARY KEY; +ALTER TABLE guacamole_connection_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_connection_permission + ADD PRIMARY KEY (entity_id, connection_id, permission); + +-- +-- Modify guacamole_connection_group_permission to use guacamole_entity instead +-- of guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_connection_group_permission ADD COLUMN entity_id int(11); + +-- Update guacamole_connection_group_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_connection_group_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_connection_group_permission MODIFY entity_id int(11) NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_connection_group_permission + ADD CONSTRAINT guacamole_connection_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- Remove user_id column +ALTER TABLE guacamole_connection_group_permission DROP FOREIGN KEY guacamole_connection_group_permission_ibfk_2; +ALTER TABLE guacamole_connection_group_permission DROP PRIMARY KEY; +ALTER TABLE guacamole_connection_group_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_connection_group_permission + ADD PRIMARY KEY (entity_id, connection_group_id, permission); + +-- +-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead +-- of guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_sharing_profile_permission ADD COLUMN entity_id int(11); + +-- Update guacamole_sharing_profile_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_sharing_profile_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_sharing_profile_permission MODIFY entity_id int(11) NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_sharing_profile_permission + ADD CONSTRAINT guacamole_sharing_profile_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- Remove user_id column +ALTER TABLE guacamole_sharing_profile_permission DROP FOREIGN KEY guacamole_sharing_profile_permission_ibfk_2; +ALTER TABLE guacamole_sharing_profile_permission DROP PRIMARY KEY; +ALTER TABLE guacamole_sharing_profile_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_sharing_profile_permission + ADD PRIMARY KEY (entity_id, sharing_profile_id, permission); + +-- +-- Modify guacamole_user_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_user_permission ADD COLUMN entity_id int(11); + +-- Update guacamole_user_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_user_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_user_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_user_permission MODIFY entity_id int(11) NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_user_permission + ADD CONSTRAINT guacamole_user_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- Remove user_id column +ALTER TABLE guacamole_user_permission DROP FOREIGN KEY guacamole_user_permission_ibfk_2; +ALTER TABLE guacamole_user_permission DROP PRIMARY KEY; +ALTER TABLE guacamole_user_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_user_permission + ADD PRIMARY KEY (entity_id, affected_user_id, permission); + +-- +-- Modify guacamole_system_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE guacamole_system_permission ADD COLUMN entity_id int(11); + +-- Update guacamole_system_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_system_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_system_permission.user_id +); + +-- The entity_id column should now be safely non-NULL +ALTER TABLE guacamole_system_permission MODIFY entity_id int(11) NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE guacamole_system_permission + ADD CONSTRAINT guacamole_system_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE; + +-- Remove user_id column +ALTER TABLE guacamole_system_permission DROP FOREIGN KEY guacamole_system_permission_ibfk_1; +ALTER TABLE guacamole_system_permission DROP PRIMARY KEY; +ALTER TABLE guacamole_system_permission DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE guacamole_system_permission + ADD PRIMARY KEY (entity_id, permission); + -- -- Table of arbitrary user attributes. Each attribute is simply a name/value -- pair associated with a user. Arbitrary attributes are defined by other @@ -39,6 +352,28 @@ CREATE TABLE guacamole_user_attribute ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_user_group_attribute ( + + `user_group_id` int(11) NOT NULL, + `attribute_name` varchar(128) NOT NULL, + `attribute_value` varchar(4096) NOT NULL, + + PRIMARY KEY (`user_group_id`, `attribute_name`), + KEY `user_group_id` (`user_group_id`), + + CONSTRAINT `guacamole_user_group_attribute_ibfk_1` + FOREIGN KEY (`user_group_id`) + REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- -- Table of arbitrary connection attributes. Each attribute is simply a -- name/value pair associated with a connection. Arbitrary attributes are diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql index ee10ddaec..54be792ba 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql @@ -33,6 +33,22 @@ EXEC sp_bindrule 'guacamole_connection_group_type'; GO +-- +-- Entity types +-- + +CREATE RULE [guacamole_entity_type_list] AS @list IN ( + 'USER', + 'USER_GROUP' +); +GO + +CREATE TYPE [guacamole_entity_type] FROM [nvarchar](16); +EXEC sp_bindrule + 'guacamole_entity_type_list', + 'guacamole_entity_type'; +GO + -- -- Object permission types -- @@ -60,6 +76,7 @@ CREATE RULE [guacamole_system_permission_list] AS @list IN ( 'CREATE_CONNECTION_GROUP', 'CREATE_SHARING_PROFILE', 'CREATE_USER', + 'CREATE_USER_GROUP', 'ADMINISTER' ); GO @@ -163,6 +180,28 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_connection_parent_id] ON [guacamole_connection] ([parent_id]); GO +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE [guacamole_entity] ( + + [entity_id] [int] IDENTITY(1,1) NOT NULL, + [name] [nvarchar](128) NOT NULL, + [type] [guacamole_entity_type] NOT NULL, + + CONSTRAINT [PK_guacamole_entity] + PRIMARY KEY CLUSTERED ([entity_id]), + + CONSTRAINT [AK_guacamole_entity_name_scope] + UNIQUE ([type], [name]) + +); +GO + -- -- Table of users. Each user has a unique username and a hashed password -- with corresponding salt. Although the authentication system will always set @@ -172,10 +211,10 @@ GO CREATE TABLE [guacamole_user] ( - [user_id] [int] IDENTITY(1,1) NOT NULL, + [user_id] [int] IDENTITY(1,1) NOT NULL, + [entity_id] [int] NOT NULL, - -- Username and optionally-salted password - [username] [nvarchar](128) NOT NULL, + -- Optionally-salted password [password_hash] [binary](32) NOT NULL, [password_salt] [binary](32), [password_date] [datetime] NOT NULL, @@ -204,8 +243,68 @@ CREATE TABLE [guacamole_user] ( CONSTRAINT [PK_guacamole_user] PRIMARY KEY CLUSTERED ([user_id]), - CONSTRAINT [AK_guacamole_user_username] - UNIQUE ([username]) + CONSTRAINT [AK_guacamole_user_single_entity] + UNIQUE ([entity_id]), + + CONSTRAINT [FK_guacamole_user_entity] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE + +); +GO + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE [guacamole_user_group] ( + + [user_group_id] [int] IDENTITY(1,1) NOT NULL, + [entity_id] [int] NOT NULL, + + -- Group disabled status + [disabled] [bit] NOT NULL DEFAULT 0, + + CONSTRAINT [PK_guacamole_user_group] + PRIMARY KEY CLUSTERED ([user_group_id]), + + CONSTRAINT [guacamole_user_group_single_entity] + UNIQUE ([entity_id]), + + CONSTRAINT [guacamole_user_group_entity] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE + +); +GO + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE [guacamole_user_group_member] ( + + [user_group_id] [int] NOT NULL, + [member_entity_id] [int] NOT NULL, + + CONSTRAINT [PK_guacamole_user_group_member] + PRIMARY KEY CLUSTERED ([user_group_id], [member_entity_id]), + + -- Parent must be a user group + CONSTRAINT [guacamole_user_group_member_parent_id] + FOREIGN KEY ([user_group_id]) + REFERENCES [guacamole_user_group] ([user_group_id]) + ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT [guacamole_user_group_member_entity_id] + FOREIGN KEY ([member_entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + -- ON DELETE CASCADE handled by guacamole_delete_entity trigger ); GO @@ -269,6 +368,34 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_user_attribute_user_id] INCLUDE ([attribute_name], [attribute_value]); GO +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE [guacamole_user_group_attribute] ( + + [user_group_id] [int] NOT NULL, + [attribute_name] [nvarchar](128) NOT NULL, + [attribute_value] [nvarchar](4000) NOT NULL, + + CONSTRAINT [PK_guacamole_user_group_attribute] + PRIMARY KEY CLUSTERED ([user_group_id], [attribute_name]), + + CONSTRAINT [FK_guacamole_user_attribute_user_group_id] + FOREIGN KEY ([user_group_id]) + REFERENCES [guacamole_user_group] ([user_group_id]) + ON DELETE CASCADE + +); + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_attribute_user_id] + ON [guacamole_user_group_attribute] ([user_group_id]) + INCLUDE ([attribute_name], [attribute_value]); +GO + -- -- Table of arbitrary connection attributes. Each attribute is simply a -- name/value pair associated with a connection. Arbitrary attributes are @@ -403,27 +530,27 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_parameter_sharing_profil GO -- --- Table of connection permissions. Each connection permission grants a user --- specific access to a connection. +-- Table of connection permissions. Each connection permission grants a user or +-- user group specific access to a connection. -- CREATE TABLE [guacamole_connection_permission] ( - [user_id] [int] NOT NULL, + [entity_id] [int] NOT NULL, [connection_id] [int] NOT NULL, [permission] [guacamole_object_permission] NOT NULL, CONSTRAINT [PK_guacamole_connection_permission] - PRIMARY KEY CLUSTERED ([user_id], [connection_id], [permission]), + PRIMARY KEY CLUSTERED ([entity_id], [connection_id], [permission]), CONSTRAINT [FK_guacamole_connection_permission_connection_id] FOREIGN KEY ([connection_id]) REFERENCES [guacamole_connection] ([connection_id]) ON DELETE CASCADE, - CONSTRAINT [FK_guacamole_connection_permission_user_id] - FOREIGN KEY ([user_id]) - REFERENCES [guacamole_user] ([user_id]) + CONSTRAINT [FK_guacamole_connection_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) ON DELETE CASCADE ); @@ -431,32 +558,32 @@ CREATE TABLE [guacamole_connection_permission] ( CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_connection_id] ON [guacamole_connection_permission] ([connection_id]); -CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_user_id] - ON [guacamole_connection_permission] ([user_id]); +CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_entity_id] + ON [guacamole_connection_permission] ([entity_id]); GO -- -- Table of connection group permissions. Each group permission grants a user --- specific access to a connection group. +-- or user group specific access to a connection group. -- CREATE TABLE [guacamole_connection_group_permission] ( - [user_id] [int] NOT NULL, + [entity_id] [int] NOT NULL, [connection_group_id] [int] NOT NULL, [permission] [guacamole_object_permission] NOT NULL, CONSTRAINT [PK_guacamole_connection_group_permission] - PRIMARY KEY CLUSTERED ([user_id], [connection_group_id], [permission]), + PRIMARY KEY CLUSTERED ([entity_id], [connection_group_id], [permission]), CONSTRAINT [FK_guacamole_connection_group_permission_connection_group_id] FOREIGN KEY ([connection_group_id]) REFERENCES [guacamole_connection_group] ([connection_group_id]) ON DELETE CASCADE, - CONSTRAINT [FK_guacamole_connection_group_permission_user_id] - FOREIGN KEY ([user_id]) - REFERENCES [guacamole_user] ([user_id]) + CONSTRAINT [FK_guacamole_connection_group_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) ON DELETE CASCADE ); @@ -464,32 +591,32 @@ CREATE TABLE [guacamole_connection_group_permission] ( CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_connection_group_id] ON [guacamole_connection_group_permission] ([connection_group_id]); -CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_user_id] - ON [guacamole_connection_group_permission] ([user_id]); +CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_entity_id] + ON [guacamole_connection_group_permission] ([entity_id]); GO -- -- Table of sharing profile permissions. Each sharing profile permission grants --- a user specific access to a sharing profile. +-- a user or user group specific access to a sharing profile. -- CREATE TABLE [guacamole_sharing_profile_permission] ( - [user_id] [int] NOT NULL, + [entity_id] [int] NOT NULL, [sharing_profile_id] [int] NOT NULL, [permission] [guacamole_object_permission] NOT NULL, CONSTRAINT [PK_guacamole_sharing_profile_permission] - PRIMARY KEY CLUSTERED ([user_id], [sharing_profile_id], [permission]), + PRIMARY KEY CLUSTERED ([entity_id], [sharing_profile_id], [permission]), CONSTRAINT [FK_guacamole_sharing_profile_permission_sharing_profile_id] FOREIGN KEY ([sharing_profile_id]) REFERENCES [guacamole_sharing_profile] ([sharing_profile_id]) ON DELETE CASCADE, - CONSTRAINT [FK_guacamole_sharing_profile_permission_user_id] - FOREIGN KEY ([user_id]) - REFERENCES [guacamole_user] ([user_id]) + CONSTRAINT [FK_guacamole_sharing_profile_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) ON DELETE CASCADE ); @@ -497,67 +624,102 @@ CREATE TABLE [guacamole_sharing_profile_permission] ( CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_sharing_profile_id] ON [guacamole_sharing_profile_permission] ([sharing_profile_id]); -CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_user_id] - ON [guacamole_sharing_profile_permission] ([user_id]); +CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_entity_id] + ON [guacamole_sharing_profile_permission] ([entity_id]); GO -- --- Table of system permissions. Each system permission grants a user a --- system-level privilege of some kind. +-- Table of system permissions. Each system permission grants a user or user +-- group a system-level privilege of some kind. -- CREATE TABLE [guacamole_system_permission] ( - [user_id] [int] NOT NULL, + [entity_id] [int] NOT NULL, [permission] [guacamole_system_permission] NOT NULL, CONSTRAINT [PK_guacamole_system_permission] - PRIMARY KEY CLUSTERED ([user_id], [permission]), + PRIMARY KEY CLUSTERED ([entity_id], [permission]), - CONSTRAINT [FK_guacamole_system_permission_user_id] - FOREIGN KEY ([user_id]) - REFERENCES [guacamole_user] ([user_id]) + CONSTRAINT [FK_guacamole_system_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) ON DELETE CASCADE ); -CREATE NONCLUSTERED INDEX [IX_guacamole_system_permission_user_id] - ON [guacamole_system_permission] ([user_id]); +CREATE NONCLUSTERED INDEX [IX_guacamole_system_permission_entity_id] + ON [guacamole_system_permission] ([entity_id]); GO -- --- Table of user permissions. Each user permission grants a user access to --- another user (the "affected" user) for a specific type of operation. +-- Table of user permissions. Each user permission grants a user or user group +-- access to another user (the "affected" user) for a specific type of +-- operation. -- CREATE TABLE [guacamole_user_permission] ( - [user_id] [int] NOT NULL, + [entity_id] [int] NOT NULL, [affected_user_id] [int] NOT NULL, [permission] [guacamole_object_permission] NOT NULL, CONSTRAINT [PK_guacamole_user_permission] - PRIMARY KEY CLUSTERED ([user_id], [affected_user_id], [permission]), + PRIMARY KEY CLUSTERED ([entity_id], [affected_user_id], [permission]), CONSTRAINT [FK_guacamole_user_permission_affected_user_id] FOREIGN KEY ([affected_user_id]) - REFERENCES [guacamole_user] ([user_id]), - -- ON DELETE CASCADE handled by guacamole_delete_user trigger - - CONSTRAINT [FK_guacamole_user_permission_user_id] - FOREIGN KEY ([user_id]) REFERENCES [guacamole_user] ([user_id]) - -- ON DELETE CASCADE handled by guacamole_delete_user trigger + ON DELETE CASCADE, + + CONSTRAINT [FK_guacamole_user_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + -- ON DELETE CASCADE handled by guacamole_delete_entity trigger ); -CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_user_id] - ON [guacamole_user_permission] ([user_id]); +CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_entity_id] + ON [guacamole_user_permission] ([entity_id]); CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_affected_user_id] ON [guacamole_user_permission] ([affected_user_id]); GO +-- +-- Table of user group permissions. Each user group permission grants a user +-- or user group access to a another user group (the "affected" user group) for +-- a specific type of operation. +-- + +CREATE TABLE [guacamole_user_group_permission] ( + + [entity_id] [int] NOT NULL, + [affected_user_group_id] [int] NOT NULL, + [permission] [guacamole_object_permission] NOT NULL, + + CONSTRAINT [PK_guacamole_user_group_permission] + PRIMARY KEY CLUSTERED ([entity_id], [affected_user_group_id], [permission]), + + CONSTRAINT [FK_guacamole_user_group_permission_affected_user_group_id] + FOREIGN KEY ([affected_user_group_id]) + REFERENCES [guacamole_user_group] ([user_group_id]) + ON DELETE CASCADE, + + CONSTRAINT [FK_guacamole_user_group_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + -- ON DELETE CASCADE handled by guacamole_delete_entity trigger + +); + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_entity_id] + ON [guacamole_user_group_permission] ([entity_id]); + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_affected_user_group_id] + ON [guacamole_user_group_permission] ([affected_user_group_id]); +GO + -- -- Table of connection history records. Each record defines a specific user's -- session, including the connection used, the start time, and the end time @@ -682,12 +844,12 @@ GO -- -- Handle cascading deletion/updates of records in response to deletion of --- guacamole_user records, where such deletion is not already covered by +-- guacamole_entity records, where such deletion is not already covered by -- ON DELETE CASCADE or ON DELETE SET NULL. -- -CREATE TRIGGER [guacamole_delete_user] - ON [guacamole_user] +CREATE TRIGGER [guacamole_delete_entity] + ON [guacamole_entity] INSTEAD OF DELETE AS BEGIN @@ -696,13 +858,18 @@ AS BEGIN -- Delete all associated permissions not covered by ON DELETE CASCADE DELETE FROM [guacamole_user_permission] - WHERE - [user_id] IN (SELECT [user_id] FROM DELETED) - OR [user_id] IN (SELECT [user_id] FROM DELETED); + WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED); + + DELETE FROM [guacamole_user_group_permission] + WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED); + + -- Delete all associated group memberships not covered by ON DELETE CASCADE + DELETE FROM [guacamole_user_group_member] + WHERE [member_entity_id] IN (SELECT [entity_id] FROM DELETED); -- Perform original deletion - DELETE FROM [guacamole_user] - WHERE [user_id] IN (SELECT [user_id] FROM DELETED); + DELETE FROM [guacamole_entity] + WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED); END GO @@ -746,6 +913,20 @@ AS BEGIN -- Do not take trigger into account when producing row counts for the DELETE SET NOCOUNT ON; + -- Delete all descendant connections + WITH [connection_groups] ([connection_group_id]) AS ( + SELECT [connection_group_id] FROM DELETED + UNION ALL + SELECT [guacamole_connection_group].[connection_group_id] + FROM [guacamole_connection_group] + JOIN [connection_groups] ON [connection_groups].[connection_group_id] = [guacamole_connection_group].[parent_id] + ) + DELETE FROM [guacamole_connection] + WHERE [parent_id] IN ( + SELECT [connection_group_id] + FROM [connection_groups] + ); + -- Delete all requested connection groups, including descendants WITH [connection_groups] ([connection_group_id]) AS ( SELECT [connection_group_id] FROM DELETED @@ -760,10 +941,6 @@ AS BEGIN FROM [connection_groups] ); - -- Delete all child connections - DELETE FROM [guacamole_connection] - WHERE [parent_id] IN (SELECT [connection_group_id] FROM DELETED); - END GO diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql index 5b14651ee..dcb4257d6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql @@ -18,43 +18,46 @@ -- -- Create default user "guacadmin" with password "guacadmin" +INSERT INTO [guacamole_entity] ([name], [type]) VALUES ('guacadmin', 'USER'); INSERT INTO [guacamole_user] ( - [username], + [entity_id], [password_hash], [password_salt], [password_date] ) -VALUES ( - 'guacadmin', +SELECT + [entity_id], 0xCA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960, 0xFE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264, getdate() -); +FROM [guacamole_entity] WHERE [name] = 'guacadmin'; -- Grant this user all system permissions INSERT INTO [guacamole_system_permission] SELECT - [user_id], + [entity_id], [permission] FROM ( SELECT 'guacadmin', 'CREATE_CONNECTION' UNION SELECT 'guacadmin', 'CREATE_CONNECTION_GROUP' UNION SELECT 'guacadmin', 'CREATE_SHARING_PROFILE' UNION SELECT 'guacadmin', 'CREATE_USER' + UNION SELECT 'guacadmin', 'CREATE_USER_GROUP' UNION SELECT 'guacadmin', 'ADMINISTER' ) [permissions] ([username], [permission]) -JOIN [guacamole_user] ON [permissions].[username] = [guacamole_user].[username]; +JOIN [guacamole_entity] ON [permissions].[username] = [guacamole_entity].[name] AND [guacamole_entity].[type] = 'USER'; INSERT INTO [guacamole_user_permission] SELECT + [guacamole_entity].[entity_id], [guacamole_user].[user_id], - [affected].[user_id], [permission] FROM ( SELECT 'guacadmin', 'guacadmin', 'READ' UNION SELECT 'guacadmin', 'guacadmin', 'UPDATE' UNION SELECT 'guacadmin', 'guacadmin', 'ADMINISTER' ) [permissions] ([username], [affected_username], [permission]) -JOIN [guacamole_user] ON permissions.username = [guacamole_user].[username] -JOIN [guacamole_user] [affected] ON permissions.affected_username = affected.username; +JOIN [guacamole_entity] ON [permissions].[username] = [guacamole_entity].[name] AND [guacamole_entity].[type] = 'USER' +JOIN [guacamole_entity] [affected] ON [permissions].[affected_username] = [affected].[name] AND [guacamole_entity].[type] = 'USER' +JOIN [guacamole_user] ON [guacamole_user].[entity_id] = [affected].[entity_id]; GO diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql index cb02dd5fa..6e9133a59 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql @@ -17,6 +17,510 @@ -- under the License. -- +-- +-- Add new system-level permission +-- + +EXEC sp_unbindrule 'guacamole_system_permission'; +DROP RULE [guacamole_system_permission_list]; +GO + +CREATE RULE [guacamole_system_permission_list] AS @list IN ( + 'CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_SHARING_PROFILE', + 'CREATE_USER', + 'CREATE_USER_GROUP', + 'ADMINISTER' +); +GO + +EXEC sp_bindrule + 'guacamole_system_permission_list', + 'guacamole_system_permission'; +GO + +-- +-- Entity types +-- + +CREATE RULE [guacamole_entity_type_list] AS @list IN ( + 'USER', + 'USER_GROUP' +); +GO + +CREATE TYPE [guacamole_entity_type] FROM [nvarchar](16); +EXEC sp_bindrule + 'guacamole_entity_type_list', + 'guacamole_entity_type'; +GO + +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE [guacamole_entity] ( + + [entity_id] [int] IDENTITY(1,1) NOT NULL, + [name] [nvarchar](128) NOT NULL, + [type] [guacamole_entity_type] NOT NULL, + + CONSTRAINT [PK_guacamole_entity] + PRIMARY KEY CLUSTERED ([entity_id]), + + CONSTRAINT [AK_guacamole_entity_name_scope] + UNIQUE ([type], [name]) + +); +GO + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE [guacamole_user_group] ( + + [user_group_id] [int] IDENTITY(1,1) NOT NULL, + [entity_id] [int] NOT NULL, + + -- Group disabled status + [disabled] [bit] NOT NULL DEFAULT 0, + + CONSTRAINT [PK_guacamole_user_group] + PRIMARY KEY CLUSTERED ([user_group_id]), + + CONSTRAINT [guacamole_user_group_single_entity] + UNIQUE ([entity_id]), + + CONSTRAINT [guacamole_user_group_entity] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE + +); +GO + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE [guacamole_user_group_member] ( + + [user_group_id] [int] NOT NULL, + [member_entity_id] [int] NOT NULL, + + CONSTRAINT [PK_guacamole_user_group_member] + PRIMARY KEY CLUSTERED ([user_group_id], [member_entity_id]), + + -- Parent must be a user group + CONSTRAINT [guacamole_user_group_member_parent_id] + FOREIGN KEY ([user_group_id]) + REFERENCES [guacamole_user_group] ([user_group_id]) + ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT [guacamole_user_group_member_entity_id] + FOREIGN KEY ([member_entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + -- ON DELETE CASCADE handled by guacamole_delete_entity trigger + +); +GO + +-- +-- Table of user group permissions. Each user group permission grants a user +-- or user group access to a another user group (the "affected" user group) for +-- a specific type of operation. +-- + +CREATE TABLE [guacamole_user_group_permission] ( + + [entity_id] [int] NOT NULL, + [affected_user_group_id] [int] NOT NULL, + [permission] [guacamole_object_permission] NOT NULL, + + CONSTRAINT [PK_guacamole_user_group_permission] + PRIMARY KEY CLUSTERED ([entity_id], [affected_user_group_id], [permission]), + + CONSTRAINT [FK_guacamole_user_group_permission_affected_user_group_id] + FOREIGN KEY ([affected_user_group_id]) + REFERENCES [guacamole_user_group] ([user_group_id]) + ON DELETE CASCADE, + + CONSTRAINT [FK_guacamole_user_group_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + -- ON DELETE CASCADE handled by guacamole_delete_entity trigger + +); + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_entity_id] + ON [guacamole_user_group_permission] ([entity_id]); + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_affected_user_group_id] + ON [guacamole_user_group_permission] ([affected_user_group_id]); +GO + +-- +-- The guacamole_delete_entity trigger effectively replaces the +-- guacamole_delete_user trigger, which is no longer necessary and will cease +-- being correct after the columns of existing tables are updated. +-- + +DROP TRIGGER [guacamole_delete_user]; +GO + +-- +-- Modify guacamole_user table to use guacamole_entity as a base +-- + +-- Add new entity_id column +ALTER TABLE [guacamole_user] ADD [entity_id] [int]; +GO + +-- Create user entities for each guacamole_user entry +INSERT INTO [guacamole_entity] ([name], [type]) +SELECT [username], 'USER' FROM [guacamole_user]; +GO + +-- Update guacamole_user to point to corresponding guacamole_entity +UPDATE [guacamole_user] SET [entity_id] = ( + SELECT [entity_id] FROM [guacamole_entity] + WHERE + [username] = [guacamole_entity].[name] + AND type = 'USER' +); +GO + +-- The entity_id column should now be safely non-NULL +ALTER TABLE [guacamole_user] + ALTER COLUMN [entity_id] [int] NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_user] + ADD CONSTRAINT [AK_guacamole_user_single_entity] + UNIQUE ([entity_id]); + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_user] + ADD CONSTRAINT [FK_guacamole_user_entity] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE; + +-- The username column can now safely be removed +ALTER TABLE [guacamole_user] DROP [AK_guacamole_user_username]; +ALTER TABLE [guacamole_user] DROP COLUMN [username]; +GO + +-- +-- Modify guacamole_connection_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE [guacamole_connection_permission] ADD [entity_id] [int]; +GO + +-- Update guacamole_connection_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE [guacamole_connection_permission] SET [entity_id] = ( + SELECT [entity_id] FROM [guacamole_user] + WHERE [guacamole_user].[user_id] = [guacamole_connection_permission].[user_id] +); +GO + +-- The entity_id column should now be safely non-NULL +ALTER TABLE [guacamole_connection_permission] + ALTER COLUMN [entity_id] [int] NOT NULL; + +-- Remove user_id column +DROP INDEX [IX_guacamole_connection_permission_user_id] ON [guacamole_connection_permission]; +ALTER TABLE [guacamole_connection_permission] DROP [PK_guacamole_connection_permission]; +ALTER TABLE [guacamole_connection_permission] DROP [FK_guacamole_connection_permission_user_id]; +ALTER TABLE [guacamole_connection_permission] DROP COLUMN [user_id]; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_connection_permission] + ADD CONSTRAINT [FK_guacamole_connection_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE; + +CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_entity_id] + ON [guacamole_connection_permission] ([entity_id]); + +-- Add new primary key which uses entity_id +ALTER TABLE [guacamole_connection_permission] + ADD CONSTRAINT [PK_guacamole_connection_permission] + PRIMARY KEY CLUSTERED ([entity_id], [connection_id], [permission]); +GO + +-- +-- Modify guacamole_connection_group_permission to use guacamole_entity instead +-- of guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE [guacamole_connection_group_permission] ADD [entity_id] [int]; +GO + +-- Update guacamole_connection_group_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_connection_group_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id +); +GO + +-- The entity_id column should now be safely non-NULL +ALTER TABLE [guacamole_connection_group_permission] + ALTER COLUMN [entity_id] [int] NOT NULL; + +-- Remove user_id column +DROP INDEX [IX_guacamole_connection_group_permission_user_id] ON [guacamole_connection_group_permission]; +ALTER TABLE [guacamole_connection_group_permission] DROP [PK_guacamole_connection_group_permission]; +ALTER TABLE [guacamole_connection_group_permission] DROP [FK_guacamole_connection_group_permission_user_id]; +ALTER TABLE [guacamole_connection_group_permission] DROP COLUMN user_id; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_connection_group_permission] + ADD CONSTRAINT [FK_guacamole_connection_group_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE; + +CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_entity_id] + ON [guacamole_connection_group_permission] ([entity_id]); + +-- Add new primary key which uses entity_id +ALTER TABLE [guacamole_connection_group_permission] + ADD CONSTRAINT [PK_guacamole_connection_group_permission] + PRIMARY KEY CLUSTERED ([entity_id], [connection_group_id], [permission]); +GO + +-- +-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead +-- of guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE [guacamole_sharing_profile_permission] ADD [entity_id] [int]; +GO + +-- Update guacamole_sharing_profile_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_sharing_profile_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id +); +GO + +-- The entity_id column should now be safely non-NULL +ALTER TABLE [guacamole_sharing_profile_permission] + ALTER COLUMN [entity_id] [int] NOT NULL; + +-- Remove user_id column +DROP INDEX [IX_guacamole_sharing_profile_permission_user_id] ON [guacamole_sharing_profile_permission]; +ALTER TABLE [guacamole_sharing_profile_permission] DROP [PK_guacamole_sharing_profile_permission]; +ALTER TABLE [guacamole_sharing_profile_permission] DROP [FK_guacamole_sharing_profile_permission_user_id]; +ALTER TABLE [guacamole_sharing_profile_permission] DROP COLUMN user_id; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_sharing_profile_permission] + ADD CONSTRAINT [FK_guacamole_sharing_profile_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE; + +CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_entity_id] + ON [guacamole_sharing_profile_permission] ([entity_id]); + +-- Add new primary key which uses entity_id +ALTER TABLE [guacamole_sharing_profile_permission] + ADD CONSTRAINT [PK_guacamole_sharing_profile_permission] + PRIMARY KEY CLUSTERED ([entity_id], [sharing_profile_id], [permission]); +GO + +-- +-- Modify guacamole_user_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE [guacamole_user_permission] ADD [entity_id] [int]; +GO + +-- Update guacamole_user_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE guacamole_user_permission SET entity_id = ( + SELECT entity_id FROM guacamole_user + WHERE guacamole_user.user_id = guacamole_user_permission.user_id +); +GO + +-- The entity_id column should now be safely non-NULL +ALTER TABLE [guacamole_user_permission] + ALTER COLUMN [entity_id] [int] NOT NULL; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_user_permission] + ADD CONSTRAINT [FK_guacamole_user_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]); + -- ON DELETE CASCADE handled by guacamole_delete_entity trigger + +-- The affected_user_id column now has ON DELETE CASCADE +ALTER TABLE [guacamole_user_permission] DROP [FK_guacamole_user_permission_affected_user_id]; +ALTER TABLE [guacamole_user_permission] + ADD CONSTRAINT [FK_guacamole_user_permission_affected_user_id] + FOREIGN KEY ([affected_user_id]) + REFERENCES [guacamole_user] ([user_id]) + ON DELETE CASCADE; + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_entity_id] + ON [guacamole_user_permission] ([entity_id]); + +-- Remove user_id column +DROP INDEX [IX_guacamole_user_permission_user_id] ON [guacamole_user_permission]; +ALTER TABLE [guacamole_user_permission] DROP [PK_guacamole_user_permission]; +ALTER TABLE [guacamole_user_permission] DROP [FK_guacamole_user_permission_user_id]; +ALTER TABLE [guacamole_user_permission] DROP COLUMN user_id; + +-- Add new primary key which uses entity_id +ALTER TABLE [guacamole_user_permission] + ADD CONSTRAINT [PK_guacamole_user_permission] + PRIMARY KEY CLUSTERED ([entity_id], [affected_user_id], [permission]); +GO + +-- +-- Modify guacamole_system_permission to use guacamole_entity instead of +-- guacamole_user +-- + +-- Add new entity_id column +ALTER TABLE [guacamole_system_permission] ADD [entity_id] [int]; +GO + +-- Update guacamole_system_permission to point to the guacamole_entity +-- that has been granted the permission +UPDATE [guacamole_system_permission] SET [entity_id] = ( + SELECT [entity_id] FROM [guacamole_user] + WHERE [guacamole_user].[user_id] = [guacamole_system_permission].[user_id] +); +GO + +-- The entity_id column should now be safely non-NULL +ALTER TABLE [guacamole_system_permission] + ALTER COLUMN [entity_id] [int] NOT NULL; + +-- Remove user_id column +DROP INDEX [IX_guacamole_system_permission_user_id] ON [guacamole_system_permission]; +ALTER TABLE [guacamole_system_permission] DROP [PK_guacamole_system_permission]; +ALTER TABLE [guacamole_system_permission] DROP [FK_guacamole_system_permission_user_id]; +ALTER TABLE [guacamole_system_permission] DROP COLUMN [user_id]; + +-- The entity_id column should now safely point to guacamole_entity entries +ALTER TABLE [guacamole_system_permission] + ADD CONSTRAINT [FK_guacamole_system_permission_entity_id] + FOREIGN KEY ([entity_id]) + REFERENCES [guacamole_entity] ([entity_id]) + ON DELETE CASCADE; + +CREATE NONCLUSTERED INDEX [IX_guacamole_system_permission_entity_id] + ON [guacamole_system_permission] ([entity_id]); + +-- Add new primary key which uses entity_id +ALTER TABLE [guacamole_system_permission] + ADD CONSTRAINT [PK_guacamole_system_permission] + PRIMARY KEY CLUSTERED ([entity_id], [permission]); +GO + +-- +-- Handle cascading deletion/updates of records in response to deletion of +-- guacamole_entity records, where such deletion is not already covered by +-- ON DELETE CASCADE or ON DELETE SET NULL. +-- + +CREATE TRIGGER [guacamole_delete_entity] + ON [guacamole_entity] + INSTEAD OF DELETE +AS BEGIN + + -- Do not take trigger into account when producing row counts for the DELETE + SET NOCOUNT ON; + + -- Delete all associated permissions not covered by ON DELETE CASCADE + DELETE FROM [guacamole_user_permission] + WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED); + + DELETE FROM [guacamole_user_group_permission] + WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED); + + -- Delete all associated group memberships not covered by ON DELETE CASCADE + DELETE FROM [guacamole_user_group_member] + WHERE [member_entity_id] IN (SELECT [entity_id] FROM DELETED); + + -- Perform original deletion + DELETE FROM [guacamole_entity] + WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED); + +END +GO + +-- +-- Update guacamole_delete_connection_group trigger to remove descendant +-- connections first. +-- + +DROP TRIGGER [guacamole_delete_connection_group]; +GO + +CREATE TRIGGER [guacamole_delete_connection_group] + ON [guacamole_connection_group] + INSTEAD OF DELETE +AS BEGIN + + -- Do not take trigger into account when producing row counts for the DELETE + SET NOCOUNT ON; + + -- Delete all descendant connections + WITH [connection_groups] ([connection_group_id]) AS ( + SELECT [connection_group_id] FROM DELETED + UNION ALL + SELECT [guacamole_connection_group].[connection_group_id] + FROM [guacamole_connection_group] + JOIN [connection_groups] ON [connection_groups].[connection_group_id] = [guacamole_connection_group].[parent_id] + ) + DELETE FROM [guacamole_connection] + WHERE [parent_id] IN ( + SELECT [connection_group_id] + FROM [connection_groups] + ); + + -- Delete all requested connection groups, including descendants + WITH [connection_groups] ([connection_group_id]) AS ( + SELECT [connection_group_id] FROM DELETED + UNION ALL + SELECT [guacamole_connection_group].[connection_group_id] + FROM [guacamole_connection_group] + JOIN [connection_groups] ON [connection_groups].[connection_group_id] = [guacamole_connection_group].[parent_id] + ) + DELETE FROM [guacamole_connection_group] + WHERE [connection_group_id] IN ( + SELECT [connection_group_id] + FROM [connection_groups] + ); + +END +GO + -- -- Table of arbitrary user attributes. Each attribute is simply a name/value -- pair associated with a user. Arbitrary attributes are defined by other @@ -45,6 +549,34 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_user_attribute_user_id] INCLUDE ([attribute_name], [attribute_value]); GO +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE [guacamole_user_group_attribute] ( + + [user_group_id] [int] NOT NULL, + [attribute_name] [nvarchar](128) NOT NULL, + [attribute_value] [nvarchar](4000) NOT NULL, + + CONSTRAINT [PK_guacamole_user_group_attribute] + PRIMARY KEY CLUSTERED ([user_group_id], [attribute_name]), + + CONSTRAINT [FK_guacamole_user_attribute_user_group_id] + FOREIGN KEY ([user_group_id]) + REFERENCES [guacamole_user_group] ([user_group_id]) + ON DELETE CASCADE + +); + +CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_attribute_user_id] + ON [guacamole_user_group_attribute] ([user_group_id]) + INCLUDE ([attribute_name], [attribute_value]); +GO + -- -- Table of arbitrary connection attributes. Each attribute is simply a -- name/value pair associated with a connection. Arbitrary attributes are From 204b6a4b2478eccec7e502fef517c80f87d146c9 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 8 Sep 2018 11:36:54 -0700 Subject: [PATCH 21/32] GUACAMOLE-220: Update MySQL mapping with respect to user group support. --- .../guacamole/auth/jdbc/base/EntityMapper.xml | 123 ++++++++++ .../auth/jdbc/connection/ConnectionMapper.xml | 30 ++- .../connection/ConnectionRecordMapper.xml | 22 +- .../connectiongroup/ConnectionGroupMapper.xml | 36 ++- .../ConnectionGroupPermissionMapper.xml | 44 ++-- .../permission/ConnectionPermissionMapper.xml | 44 ++-- .../SharingProfilePermissionMapper.xml | 46 ++-- .../permission/SystemPermissionMapper.xml | 40 +-- .../permission/UserGroupPermissionMapper.xml | 149 ++++++++++++ .../jdbc/permission/UserPermissionMapper.xml | 85 ++++--- .../sharingprofile/SharingProfileMapper.xml | 18 +- .../auth/jdbc/user/PasswordRecordMapper.xml | 3 +- .../guacamole/auth/jdbc/user/UserMapper.xml | 82 +++++-- .../jdbc/user/UserParentUserGroupMapper.xml | 96 ++++++++ .../auth/jdbc/user/UserRecordMapper.xml | 29 ++- .../auth/jdbc/usergroup/UserGroupMapper.xml | 229 ++++++++++++++++++ .../UserGroupMemberUserGroupMapper.xml | 93 +++++++ .../usergroup/UserGroupMemberUserMapper.xml | 93 +++++++ .../UserGroupParentUserGroupMapper.xml | 96 ++++++++ 19 files changed, 1205 insertions(+), 153 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml new file mode 100644 index 000000000..eb7a7714a --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -0,0 +1,123 @@ + + + + + + + + + + ( + ${column} = ${entityID} + + OR ${column} IN ( + SELECT guacamole_entity.entity_id + FROM guacamole_entity + JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id + WHERE + type = 'USER_GROUP' + AND name IN + + #{effectiveGroup,jdbcType=VARCHAR} + + AND disabled = false + ) + + ) + + + + + + + + + INSERT INTO guacamole_entity ( + name, + type + ) + VALUES ( + #{entity.identifier,jdbcType=VARCHAR}, + #{entity.entityType,jdbcType=VARCHAR} + ) + + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index e5fd2f03f..391e90d30 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -68,7 +68,11 @@ SELECT connection_id FROM guacamole_connection_permission WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + + + + + AND permission = 'READ' @@ -89,7 +93,11 @@ WHERE parent_id = #{parentIdentifier,jdbcType=VARCHAR} parent_id IS NULL - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ' @@ -165,7 +173,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ' GROUP BY guacamole_connection.connection_id; @@ -177,7 +189,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT @@ -191,7 +207,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index 287ca02fa..d74d4c4cb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -79,7 +79,10 @@ #{record.sharingProfileIdentifier,jdbcType=VARCHAR}, #{record.sharingProfileName,jdbcType=VARCHAR}, (SELECT user_id FROM guacamole_user - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{record.username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'), #{record.username,jdbcType=VARCHAR}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} @@ -165,13 +168,21 @@ JOIN guacamole_connection_permission ON guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id - AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND guacamole_connection_permission.permission = 'READ' JOIN guacamole_user_permission ON guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND guacamole_user_permission.permission = 'READ' @@ -182,7 +193,10 @@ guacamole_connection_history.user_id IN ( SELECT user_id FROM guacamole_user - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 + AND guacamole_entity.type = 'USER' ) OR guacamole_connection_history.connection_id IN ( diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index e02a04640..9addd3c10 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -69,7 +69,11 @@ SELECT connection_group_id FROM guacamole_connection_group_permission WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + + + + + AND permission = 'READ' @@ -90,7 +94,11 @@ WHERE parent_id = #{parentIdentifier,jdbcType=VARCHAR} parent_id IS NULL - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ' @@ -161,7 +169,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id @@ -172,7 +184,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id @@ -183,7 +199,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT @@ -197,7 +217,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index 972a71d20..adb961820 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -25,24 +25,26 @@ - - + - + @@ -50,26 +52,32 @@ - + SELECT - guacamole_connection_permission.user_id, - username, + #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, connection_id FROM guacamole_connection_permission - JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id - WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} + WHERE + + + + + @@ -50,26 +52,32 @@ - + SELECT - guacamole_sharing_profile_permission.user_id, - username, + #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, sharing_profile_id FROM guacamole_sharing_profile_permission - JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id - WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER} + WHERE + + + + + @@ -50,26 +52,32 @@ - + - SELECT - guacamole_system_permission.user_id, - username, + SELECT DISTINCT + #{entity.entityID} AS entity_id, permission FROM guacamole_system_permission - JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id - WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} + WHERE + + + + + @@ -63,10 +67,10 @@ DELETE FROM guacamole_system_permission - WHERE (user_id, permission) IN + WHERE (entity_id, permission) IN - (#{permission.userID,jdbcType=INTEGER}, + (#{permission.entityID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}) @@ -76,15 +80,15 @@ INSERT IGNORE INTO guacamole_system_permission ( - user_id, + entity_id, permission ) VALUES - (#{permission.userID,jdbcType=INTEGER}, + (#{permission.entityID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}) - \ No newline at end of file + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml new file mode 100644 index 000000000..d8af2bcd2 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_permission + USING guacamole_user_group_permission + JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id + JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id + WHERE + (guacamole_user_group_permission.entity_id, permission, affected_entity.name) IN + + (#{permission.entityID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}, + #{permission.objectIdentifier,jdbcType=VARCHAR}) + + AND affected_entity.type = 'USER_GROUP' + + + + + + + INSERT IGNORE INTO guacamole_user_group_permission ( + entity_id, + permission, + affected_user_group_id + ) + SELECT DISTINCT + permissions.entity_id, + permissions.permission, + affected_group.user_group_id + FROM + + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, + #{permission.type,jdbcType=VARCHAR} AS permission, + #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name + + AS permissions + JOIN guacamole_entity affected_entity ON + affected_entity.name = permissions.affected_name + AND affected_entity.type = 'USER_GROUP' + JOIN guacamole_user_group affected_group ON affected_group.entity_id = affected_entity.entity_id + + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index 3b837de21..4470aa353 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -25,25 +25,29 @@ - - + - + - + @@ -51,29 +55,38 @@ - + @@ -91,15 +105,17 @@ DELETE FROM guacamole_user_permission USING guacamole_user_permission - JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id + JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id + JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id WHERE - (guacamole_user_permission.user_id, permission, affected.username) IN + (guacamole_user_permission.entity_id, permission, affected_entity.name) IN - (#{permission.userID,jdbcType=INTEGER}, + (#{permission.entityID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}, #{permission.objectIdentifier,jdbcType=VARCHAR}) + AND affected_entity.type = 'USER' @@ -107,20 +123,27 @@ INSERT IGNORE INTO guacamole_user_permission ( - user_id, + entity_id, permission, affected_user_id ) - SELECT permissions.user_id, permissions.permission, guacamole_user.user_id FROM + SELECT DISTINCT + permissions.entity_id, + permissions.permission, + affected_user.user_id + FROM - SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, #{permission.type,jdbcType=VARCHAR} AS permission, - #{permission.objectIdentifier,jdbcType=VARCHAR} AS username + #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name AS permissions - JOIN guacamole_user ON guacamole_user.username = permissions.username; + JOIN guacamole_entity affected_entity ON + affected_entity.name = permissions.affected_name + AND affected_entity.type = 'USER' + JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id - \ No newline at end of file + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index ef899132f..7ffdc3d01 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -52,7 +52,11 @@ SELECT sharing_profile_id FROM guacamole_sharing_profile_permission WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + + + + + AND permission = 'READ' @@ -99,7 +103,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT @@ -113,7 +121,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=VARCHAR} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml index be9f0b600..f3772d7f9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml @@ -41,8 +41,9 @@ guacamole_user_password_history.password_date FROM guacamole_user_password_history JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id WHERE - guacamole_user.username = #{username,jdbcType=VARCHAR} + guacamole_entity.name = #{username,jdbcType=VARCHAR} ORDER BY guacamole_user_password_history.password_date DESC LIMIT #{maxHistorySize} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index e183fe295..a27ff1b59 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -28,7 +28,8 @@ - + + @@ -57,17 +58,24 @@ @@ -77,7 +85,8 @@ SELECT guacamole_user.user_id, - guacamole_user.username, + guacamole_entity.entity_id, + guacamole_entity.name, password_hash, password_salt, password_date, @@ -94,13 +103,15 @@ organizational_role, MAX(start_date) AS last_active FROM guacamole_user + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id - WHERE guacamole_user.username IN + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - GROUP BY guacamole_user.user_id; + AND guacamole_entity.type = 'USER' + GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; SELECT guacamole_user_attribute.user_id, @@ -108,11 +119,13 @@ guacamole_user_attribute.attribute_value FROM guacamole_user_attribute JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id - WHERE username IN + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - ; + + AND guacamole_entity.type = 'USER'; @@ -122,7 +135,8 @@ SELECT guacamole_user.user_id, - guacamole_user.username, + guacamole_entity.entity_id, + guacamole_entity.name, password_hash, password_salt, password_date, @@ -139,16 +153,22 @@ organizational_role, MAX(start_date) AS last_active FROM guacamole_user + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id - WHERE guacamole_user.username IN + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER' + AND + + + + AND permission = 'READ' - GROUP BY guacamole_user.user_id; + GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; SELECT guacamole_user_attribute.user_id, @@ -156,13 +176,19 @@ guacamole_user_attribute.attribute_value FROM guacamole_user_attribute JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id - WHERE username IN + WHERE guacamole_entity.name IN #{identifier,jdbcType=VARCHAR} - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER' + AND + + + + AND permission = 'READ'; @@ -173,7 +199,8 @@ SELECT guacamole_user.user_id, - guacamole_user.username, + guacamole_entity.entity_id, + guacamole_entity.name, password_hash, password_salt, password_date, @@ -190,10 +217,12 @@ organizational_role, MAX(start_date) AS last_active FROM guacamole_user + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id WHERE - guacamole_user.username = #{username,jdbcType=VARCHAR} - GROUP BY guacamole_user.user_id; + guacamole_entity.name = #{username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER' + GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; SELECT guacamole_user_attribute.user_id, @@ -201,14 +230,19 @@ guacamole_user_attribute.attribute_value FROM guacamole_user_attribute JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id - WHERE username = #{username,jdbcType=VARCHAR}; + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER' - DELETE FROM guacamole_user - WHERE username = #{identifier,jdbcType=VARCHAR} + DELETE FROM guacamole_entity + WHERE + name = #{identifier,jdbcType=VARCHAR} + AND type = 'USER' @@ -216,7 +250,7 @@ parameterType="org.apache.guacamole.auth.jdbc.user.UserModel"> INSERT INTO guacamole_user ( - username, + entity_id, password_hash, password_salt, password_date, @@ -233,7 +267,7 @@ organizational_role ) VALUES ( - #{object.identifier,jdbcType=VARCHAR}, + #{object.entityID,jdbcType=VARCHAR}, #{object.passwordHash,jdbcType=BINARY}, #{object.passwordSalt,jdbcType=BINARY}, #{object.passwordDate,jdbcType=TIMESTAMP}, diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml new file mode 100644 index 000000000..1b0ec4e3b --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_user_group_member + JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id + JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id + WHERE + member_entity_id = #{parent.entityID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER_GROUP' + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + guacamole_user_group.user_group_id, + #{parent.entityID,jdbcType=INTEGER} + FROM guacamole_user_group + JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + AND guacamole_entity.type = 'USER_GROUP' + AND guacamole_user_group.user_group_id NOT IN ( + SELECT guacamole_user_group_member.user_group_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER} + ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml index bbae03b07..d9c02ef54 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml @@ -44,8 +44,9 @@ guacamole_user_history.end_date FROM guacamole_user_history JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id WHERE - guacamole_user.username = #{username,jdbcType=VARCHAR} + guacamole_entity.name = #{username,jdbcType=VARCHAR} ORDER BY guacamole_user_history.start_date DESC, guacamole_user_history.end_date DESC @@ -66,7 +67,10 @@ VALUES ( #{record.remoteHost,jdbcType=VARCHAR}, (SELECT user_id FROM guacamole_user - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{record.username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'), #{record.username,jdbcType=VARCHAR}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} @@ -79,7 +83,10 @@ UPDATE guacamole_user_history SET remote_host = #{record.remoteHost,jdbcType=VARCHAR}, user_id = (SELECT user_id FROM guacamole_user - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name = #{record.username,jdbcType=VARCHAR} + AND guacamole_entity.type = 'USER'), username = #{record.username,jdbcType=VARCHAR}, start_date = #{record.startDate,jdbcType=TIMESTAMP}, end_date = #{record.endDate,jdbcType=TIMESTAMP} @@ -105,7 +112,10 @@ guacamole_user_history.user_id IN ( SELECT user_id FROM guacamole_user - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 + AND guacamole_entity.type = 'USER'), ) @@ -146,7 +156,11 @@ JOIN guacamole_user_permission ON guacamole_user_history.user_id = guacamole_user_permission.affected_user_id - AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND guacamole_user_permission.permission = 'READ' @@ -157,7 +171,10 @@ guacamole_user_history.user_id IN ( SELECT user_id FROM guacamole_user - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 + AND guacamole_entity.type = 'USER' ) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml new file mode 100644 index 000000000..37092b4f6 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_entity + WHERE + name = #{identifier,jdbcType=VARCHAR} + AND type = 'USER_GROUP' + + + + + + INSERT INTO guacamole_user_group ( + entity_id, + disabled + ) + VALUES ( + #{object.entityID,jdbcType=VARCHAR}, + #{object.disabled,jdbcType=BOOLEAN} + ) + + + + + + UPDATE guacamole_user_group + SET disabled = #{object.disabled,jdbcType=BOOLEAN} + WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR} + + + + + DELETE FROM guacamole_user_group_attribute + WHERE user_group_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_user_group_attribute ( + user_group_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml new file mode 100644 index 000000000..aedc956c5 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_user_group_member + JOIN guacamole_entity ON guacamole_entity.entity_id = member_entity_id + WHERE + user_group_id = #{parent.objectID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER_GROUP' + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + #{parent.objectID,jdbcType=INTEGER}, + guacamole_entity.entity_id + FROM guacamole_entity + WHERE + guacamole_entity.name IN + + #{identifier} + + AND guacamole_entity.type = 'USER_GROUP' + AND guacamole_entity.entity_id NOT IN ( + SELECT guacamole_user_group_member.member_entity_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER} + ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml new file mode 100644 index 000000000..9e0820392 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_user_group_member + JOIN guacamole_entity ON guacamole_entity.entity_id = member_entity_id + WHERE + user_group_id = #{parent.objectID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER' + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + #{parent.objectID,jdbcType=INTEGER}, + guacamole_entity.entity_id + FROM guacamole_entity + WHERE + guacamole_entity.name IN + + #{identifier} + + AND guacamole_entity.type = 'USER' + AND guacamole_entity.entity_id NOT IN ( + SELECT guacamole_user_group_member.member_entity_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER} + ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml new file mode 100644 index 000000000..4ef3c72ba --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_group_member + USING guacamole_user_group_member + JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id + JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id + WHERE + member_entity_id = #{parent.entityID,jdbcType=INTEGER} + AND guacamole_entity.type = 'USER_GROUP' + AND guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user_group_member ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + guacamole_user_group.user_group_id, + #{parent.entityID,jdbcType=INTEGER} + FROM guacamole_user_group + JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id + WHERE + guacamole_entity.name IN + + #{identifier,jdbcType=VARCHAR} + + AND guacamole_entity.type = 'USER_GROUP' + AND guacamole_user_group.user_group_id NOT IN ( + SELECT guacamole_user_group_member.user_group_id + FROM guacamole_user_group_member + WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER} + ) + + + From dec7b3c340dfe1ccd76292fc8e99ae4ec42dcc03 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 8 Sep 2018 18:11:36 -0700 Subject: [PATCH 22/32] GUACAMOLE-220: Dynamically detect whether the MariaDB / MySQL server supports recursive CTEs. --- .../guacamole/auth/jdbc/JDBCEnvironment.java | 6 +- .../auth/jdbc/base/EntityMapper.java | 11 +- .../auth/jdbc/base/EntityService.java | 16 +- .../auth/mysql/MySQLEnvironment.java | 52 +++++- .../guacamole/auth/mysql/MySQLVersion.java | 153 ++++++++++++++++++ .../guacamole/auth/jdbc/base/EntityMapper.xml | 99 ++++++++---- .../postgresql/PostgreSQLEnvironment.java | 3 +- .../auth/sqlserver/SQLServerEnvironment.java | 3 +- 8 files changed, 300 insertions(+), 43 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java index 93cc7f7a3..9158afb85 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; +import org.apache.ibatis.session.SqlSession; /** * A JDBC-specific implementation of Environment that defines generic properties @@ -143,9 +144,12 @@ public abstract class JDBCEnvironment extends LocalEnvironment { * not supported, queries that are intended to be recursive may need to be * invoked multiple times to retrieve the same data. * + * @param session + * The SqlSession provided by MyBatis for the current transaction. + * * @return * true if the database supports recursive queries, false otherwise. */ - public abstract boolean isRecursiveQuerySupported(); + public abstract boolean isRecursiveQuerySupported(SqlSession session); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java index 53b029091..dbe7cb4d0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java @@ -60,12 +60,21 @@ public interface EntityMapper { * The identifiers of any known effective groups that should be taken * into account, such as those defined externally to the database. * + * @param recursive + * Whether the query should leverage database engine features to return + * absolutely all effective groups, including those inherited through + * group membership. If false, this query will return only one level of + * depth and may need to be executed multiple times. If it is known + * that the database engine in question will always support (or always + * not support) recursive queries, this parameter may be ignored. + * * @return * The set of identifiers of all groups that the given entity is a * member of, including those where membership is inherited through * membership in other groups. */ Set selectEffectiveGroupIdentifiers(@Param("entity") EntityModel entity, - @Param("effectiveGroups") Collection effectiveGroups); + @Param("effectiveGroups") Collection effectiveGroups, + @Param("recursive") boolean recursive); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java index 1e40bb0ae..cc2a9aaf9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java @@ -23,6 +23,8 @@ import com.google.inject.Inject; import java.util.Collection; import java.util.Set; import org.apache.guacamole.auth.jdbc.JDBCEnvironment; +import org.apache.ibatis.session.SqlSession; +import org.mybatis.guice.transactional.Transactional; /** * Service which provides convenience methods for creating, retrieving, and @@ -42,6 +44,12 @@ public class EntityService { @Inject private EntityMapper entityMapper; + /** + * The current SQL session used by MyBatis. + */ + @Inject + private SqlSession sqlSession; + /** * Returns the set of all group identifiers of which the given entity is a * member, taking into account the given collection of known group @@ -64,20 +72,22 @@ public class EntityService { * member of, including those where membership is inherited through * membership in other groups. */ + @Transactional public Set retrieveEffectiveGroups(ModeledPermissions entity, Collection effectiveGroups) { // Retrieve the effective user groups of the given entity, recursively if possible - Set identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups); + boolean recursive = environment.isRecursiveQuerySupported(sqlSession); + Set identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups, recursive); // If the set of user groups retrieved was not produced recursively, // manually repeat the query to expand the set until all effective // groups have been found - if (!environment.isRecursiveQuerySupported() && !identifiers.isEmpty()) { + if (!recursive && !identifiers.isEmpty()) { Set previousIdentifiers; do { previousIdentifiers = identifiers; - identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers); + identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers, false); } while (identifiers.size() > previousIdentifiers.size()); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java index 062d6dfa4..7a9315197 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java @@ -19,11 +19,16 @@ package org.apache.guacamole.auth.mysql; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; +import org.apache.ibatis.exceptions.PersistenceException; +import org.apache.ibatis.session.SqlSession; /** * A MySQL-specific implementation of JDBCEnvironment provides database @@ -35,7 +40,17 @@ public class MySQLEnvironment extends JDBCEnvironment { * Logger for this class. */ private static final Logger logger = LoggerFactory.getLogger(MySQLEnvironment.class); - + + /** + * The earliest version of MariaDB that supported recursive CTEs. + */ + private static final MySQLVersion MARIADB_SUPPORTS_CTE = new MySQLVersion(10, 2, 2, true); + + /** + * The earliest version of MySQL that supported recursive CTEs. + */ + private static final MySQLVersion MYSQL_SUPPORTS_CTE = new MySQLVersion(8, 0, 1, false); + /** * The default host to connect to, if MYSQL_HOSTNAME is not specified. */ @@ -227,8 +242,39 @@ public class MySQLEnvironment extends JDBCEnvironment { } @Override - public boolean isRecursiveQuerySupported() { - return false; // Only very recent versions of MySQL / MariaDB support recursive queries through CTEs + public boolean isRecursiveQuerySupported(SqlSession session) { + + // Retrieve database version string from JDBC connection + String versionString; + try { + Connection connection = session.getConnection(); + DatabaseMetaData metaData = connection.getMetaData(); + versionString = metaData.getDatabaseProductVersion(); + } + catch (SQLException e) { + throw new PersistenceException("Cannot determine whether " + + "MySQL / MariaDB supports recursive queries.", e); + } + + try { + + // Parse MySQL / MariaDB version from version string + MySQLVersion version = new MySQLVersion(versionString); + logger.debug("Database recognized as {}.", version); + + // Recursive queries are supported for MariaDB 10.2.2+ and + // MySQL 8.0.1+ + return version.isAtLeast(MARIADB_SUPPORTS_CTE) + || version.isAtLeast(MYSQL_SUPPORTS_CTE); + + } + catch (IllegalArgumentException e) { + logger.debug("Unrecognized MySQL / MariaDB version string: " + + "\"{}\". Assuming database engine does not support " + + "recursive queries.", session); + return false; + } + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java new file mode 100644 index 000000000..577506ef0 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.mysql; + +import com.google.common.collect.ComparisonChain; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The specific version of a MySQL or MariaDB server. + */ +public class MySQLVersion { + + /** + * Pattern which matches the version string returned by a MariaDB server, + * extracting the major, minor, and patch numbers. + */ + private final Pattern MARIADB_VERSION = Pattern.compile("^.*-([0-9]+)\\.([0-9]+)\\.([0-9]+)-MariaDB$"); + + /** + * Pattern which matches the version string returned by a non-MariaDB + * server (including MySQL and Aurora), extracting the major, minor, and + * patch numbers. All non-MariaDB servers use normal MySQL version numbers. + */ + private final Pattern MYSQL_VERSION = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$"); + + /** + * Whether the associated server is a MariaDB server. All non-MariaDB + * servers use normal MySQL version numbers and are comparable against each + * other. + */ + private final boolean isMariaDB; + + /** + * The major component of the MAJOR.MINOR.PATCH version number. + */ + private final int major; + + /** + * The minor component of the MAJOR.MINOR.PATCH version number. + */ + private final int minor; + + /** + * The patch component of the MAJOR.MINOR.PATCH version number. + */ + private final int patch; + + /** + * Creates a new MySQLVersion having the specified major, minor, and patch + * components. + * + * @param major + * The major component of the MAJOR.MINOR.PATCH version number of the + * MariaDB / MySQL server. + * + * @param minor + * The minor component of the MAJOR.MINOR.PATCH version number of the + * MariaDB / MySQL server. + * + * @param patch + * The patch component of the MAJOR.MINOR.PATCH version number of the + * MariaDB / MySQL server. + * + * @param isMariaDB + * Whether the associated server is a MariaDB server. + */ + public MySQLVersion(int major, int minor, int patch, boolean isMariaDB) { + this.major = major; + this.minor = minor; + this.patch = patch; + this.isMariaDB = isMariaDB; + } + + public MySQLVersion(String version) throws IllegalArgumentException { + + // Extract MariaDB version number if version string appears to be + // a MariaDB version string + Matcher mariadb = MARIADB_VERSION.matcher(version); + if (mariadb.matches()) { + this.major = Integer.parseInt(mariadb.group(1)); + this.minor = Integer.parseInt(mariadb.group(2)); + this.patch = Integer.parseInt(mariadb.group(3)); + this.isMariaDB = true; + return; + } + + // If not MariaDB, assume version string is a MySQL version string + // and attempt to extract the version number + Matcher mysql = MYSQL_VERSION.matcher(version); + if (mysql.matches()) { + this.major = Integer.parseInt(mysql.group(1)); + this.minor = Integer.parseInt(mysql.group(2)); + this.patch = Integer.parseInt(mysql.group(3)); + this.isMariaDB = false; + return; + } + + throw new IllegalArgumentException("Unrecognized MySQL / MariaDB version string."); + + } + + /** + * Returns whether this version is at least as recent as the given version. + * + * @param version + * The version to compare against. + * + * @return + * true if the versions are associated with the same database server + * type (MariaDB vs. MySQL) and this version is at least as recent as + * the given version, false otherwise. + */ + public boolean isAtLeast(MySQLVersion version) { + + // If the databases use different version numbering schemes, the + // version numbers are not comparable + if (isMariaDB != version.isMariaDB) + return false; + + // Compare major, minor, and patch number in order of precedence + return ComparisonChain.start() + .compare(major, version.major) + .compare(minor, version.minor) + .compare(patch, version.patch) + .result() >= 0; + + } + + @Override + public String toString() { + return String.format("%s %d.%d.%d", isMariaDB ? "MariaDB" : "MySQL", + major, minor, patch); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml index eb7a7714a..21efb9954 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -65,43 +65,76 @@ diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java index d5d259e6f..4ac99e8d1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java @@ -24,6 +24,7 @@ import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; +import org.apache.ibatis.session.SqlSession; /** * A PostgreSQL-specific implementation of JDBCEnvironment provides database @@ -244,7 +245,7 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { } @Override - public boolean isRecursiveQuerySupported() { + public boolean isRecursiveQuerySupported(SqlSession session) { return true; // All versions of PostgreSQL support recursive queries through CTEs } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java index 03f2cf865..db068b9b8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java @@ -24,6 +24,7 @@ import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; +import org.apache.ibatis.session.SqlSession; /** * A SQLServer-specific implementation of JDBCEnvironment provides database @@ -252,7 +253,7 @@ public class SQLServerEnvironment extends JDBCEnvironment { } @Override - public boolean isRecursiveQuerySupported() { + public boolean isRecursiveQuerySupported(SqlSession session) { return true; // All versions of SQL Server support recursive queries through CTEs } From ee356201948c7d566b37733dcbe1fb0098d95a6d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 8 Sep 2018 18:52:10 -0700 Subject: [PATCH 23/32] GUACAMOLE-220: Update SQL Server mapping with respect to user group support. --- .../guacamole/auth/jdbc/base/EntityMapper.xml | 123 ++++++++++ .../auth/jdbc/connection/ConnectionMapper.xml | 30 ++- .../connection/ConnectionRecordMapper.xml | 22 +- .../connectiongroup/ConnectionGroupMapper.xml | 36 ++- .../ConnectionGroupPermissionMapper.xml | 52 ++-- .../permission/ConnectionPermissionMapper.xml | 44 ++-- .../SharingProfilePermissionMapper.xml | 44 ++-- .../permission/SystemPermissionMapper.xml | 40 +-- .../permission/UserGroupPermissionMapper.xml | 153 ++++++++++++ .../jdbc/permission/UserPermissionMapper.xml | 100 ++++---- .../sharingprofile/SharingProfileMapper.xml | 18 +- .../auth/jdbc/user/PasswordRecordMapper.xml | 3 +- .../guacamole/auth/jdbc/user/UserMapper.xml | 84 +++++-- .../jdbc/user/UserParentUserGroupMapper.xml | 96 ++++++++ .../auth/jdbc/user/UserRecordMapper.xml | 29 ++- .../auth/jdbc/usergroup/UserGroupMapper.xml | 229 ++++++++++++++++++ .../UserGroupMemberUserGroupMapper.xml | 93 +++++++ .../usergroup/UserGroupMemberUserMapper.xml | 93 +++++++ .../UserGroupParentUserGroupMapper.xml | 96 ++++++++ 19 files changed, 1218 insertions(+), 167 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml new file mode 100644 index 000000000..f61463a82 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -0,0 +1,123 @@ + + + + + + + + + + ( + ${column} = ${entityID} + + OR ${column} IN ( + SELECT [guacamole_entity].entity_id + FROM [guacamole_entity] + JOIN [guacamole_user_group] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id + WHERE + type = 'USER_GROUP' + AND name IN + + #{effectiveGroup,jdbcType=VARCHAR} + + AND disabled = 0 + ) + + ) + + + + + + + + + INSERT INTO [guacamole_entity] ( + name, + type + ) + VALUES ( + #{entity.identifier,jdbcType=VARCHAR}, + #{entity.entityType,jdbcType=VARCHAR} + ) + + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index fb617578b..54cb575c0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -68,7 +68,11 @@ SELECT connection_id FROM [guacamole_connection_permission] WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + + + + + AND permission = 'READ' @@ -89,7 +93,11 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ' @@ -170,7 +178,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id @@ -181,7 +193,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT @@ -195,7 +211,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index d7ae41c4b..2abf1ae35 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -79,7 +79,10 @@ #{record.sharingProfileIdentifier,jdbcType=INTEGER}, #{record.sharingProfileName,jdbcType=VARCHAR}, (SELECT user_id FROM [guacamole_user] - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + [guacamole_entity].name = #{record.username,jdbcType=VARCHAR} + AND [guacamole_entity].type = 'USER'), #{record.username,jdbcType=VARCHAR}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} @@ -161,13 +164,21 @@ JOIN [guacamole_connection_permission] ON [guacamole_connection_history].connection_id = [guacamole_connection_permission].connection_id - AND [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND [guacamole_connection_permission].permission = 'READ' JOIN [guacamole_user_permission] ON [guacamole_connection_history].user_id = [guacamole_user_permission].affected_user_id - AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND [guacamole_user_permission].permission = 'READ' @@ -178,7 +189,10 @@ [guacamole_connection_history].user_id IN ( SELECT user_id FROM [guacamole_user] - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0 + AND [guacamole_entity].type = 'USER' ) OR [guacamole_connection_history].connection_id IN ( diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index f75943ee4..32c1d1348 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -69,7 +69,11 @@ SELECT connection_group_id FROM [guacamole_connection_group_permission] WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + + + + + AND permission = 'READ' @@ -90,7 +94,11 @@ WHERE parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ' @@ -161,7 +169,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT parent_id, [guacamole_connection_group].connection_group_id @@ -172,7 +184,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT parent_id, [guacamole_connection].connection_id @@ -183,7 +199,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT @@ -197,7 +217,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index 3cc0988c2..b89186887 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -25,24 +25,26 @@ - - + - + @@ -50,26 +52,32 @@ - + SELECT - [guacamole_connection_permission].user_id, - username, + #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, connection_id FROM [guacamole_connection_permission] - JOIN [guacamole_user] ON [guacamole_connection_permission].user_id = [guacamole_user].user_id - WHERE [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER} + WHERE + + + + + @@ -50,26 +52,32 @@ - + SELECT - [guacamole_sharing_profile_permission].user_id, - username, + #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, sharing_profile_id FROM [guacamole_sharing_profile_permission] - JOIN [guacamole_user] ON [guacamole_sharing_profile_permission].user_id = [guacamole_user].user_id - WHERE [guacamole_sharing_profile_permission].user_id = #{user.objectID,jdbcType=INTEGER} + WHERE + + + + + @@ -50,26 +52,32 @@ - + - SELECT - [guacamole_system_permission].user_id, - username, + SELECT DISTINCT + #{entity.entityID} AS entity_id, permission FROM [guacamole_system_permission] - JOIN [guacamole_user] ON [guacamole_system_permission].user_id = [guacamole_user].user_id - WHERE [guacamole_system_permission].user_id = #{user.objectID,jdbcType=INTEGER} + WHERE + + + + + @@ -66,7 +70,7 @@ WHERE - (user_id = #{permission.userID,jdbcType=INTEGER} + (entity_id = #{permission.entityID,jdbcType=INTEGER} AND permission = #{permission.type,jdbcType=VARCHAR}) @@ -76,21 +80,21 @@ INSERT INTO [guacamole_system_permission] ( - user_id, + entity_id, permission ) SELECT DISTINCT - permissions.user_id, + permissions.entity_id, permissions.permission FROM - SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, #{permission.type,jdbcType=VARCHAR} AS permission AS permissions WHERE NOT EXISTS (SELECT 1 FROM [guacamole_system_permission] - WHERE [guacamole_system_permission].user_id = permissions.user_id + WHERE [guacamole_system_permission].entity_id = permissions.entity_id AND [guacamole_system_permission].permission = permissions.permission ); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml new file mode 100644 index 000000000..331a3a32e --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE [guacamole_user_group_permission] + FROM [guacamole_user_group_permission] + JOIN [guacamole_user_group] affected_group ON [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id + JOIN [guacamole_entity] affected_entity ON affected_group.entity_id = affected_entity.entity_id + WHERE + + ([guacamole_user_group_permission].entity_id = #{permission.entityID,jdbcType=INTEGER} AND + permission = #{permission.type,jdbcType=VARCHAR} AND + affected_entity.name = #{permission.objectIdentifier,jdbcType=VARCHAR} AND + affected_entity.type = 'USER_GROUP') + + + + + + + + INSERT INTO [guacamole_user_group_permission] ( + entity_id, + permission, + affected_user_group_id + ) + SELECT DISTINCT + permissions.entity_id, + permissions.permission, + affected_group.user_group_id + FROM + + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, + #{permission.type,jdbcType=VARCHAR} AS permission, + #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name + + AS permissions + JOIN [guacamole_entity] affected_entity ON + affected_entity.name = permissions.affected_name + AND affected_entity.type = 'USER_GROUP' + JOIN [guacamole_user_group] affected_group ON affected_group.entity_id = affected_entity.entity_id + WHERE NOT EXISTS (SELECT 1 FROM [guacamole_user_group_permission] + WHERE [guacamole_user_group_permission].entity_id = permissions.entity_id + AND [guacamole_user_group_permission].permission = permissions.permission + AND [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id + ); + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index 453777d0c..53ed02707 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -25,25 +25,29 @@ - - + - + - + @@ -51,55 +55,66 @@ - + - DELETE FROM [guacamole_user_permission] - USING [guacamole_user] affected + DELETE [guacamole_user_permission] + FROM [guacamole_user_permission] + JOIN [guacamole_user] affected_user ON [guacamole_user_permission].affected_user_id = affected_user.user_id + JOIN [guacamole_entity] affected_entity ON affected_user.entity_id = affected_entity.entity_id WHERE - [guacamole_user_permission].affected_user_id = affected.user_id - AND ([guacamole_user_permission].user_id, permission, affected.username) IN - - (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}, - #{permission.objectIdentifier,jdbcType=INTEGER}) - + + ([guacamole_user_permission].entity_id = #{permission.entityID,jdbcType=INTEGER} AND + permission = #{permission.type,jdbcType=VARCHAR} AND + affected_entity.name = #{permission.objectIdentifier,jdbcType=VARCHAR} AND + affected_entity.type = 'USER') + @@ -107,27 +122,30 @@ INSERT INTO [guacamole_user_permission] ( - user_id, + entity_id, permission, affected_user_id ) SELECT DISTINCT - permissions.user_id, + permissions.entity_id, permissions.permission, - [guacamole_user].user_id + affected_user.user_id FROM - SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id, #{permission.type,jdbcType=VARCHAR} AS permission, - #{permission.objectIdentifier,jdbcType=INTEGER} AS username + #{permission.objectIdentifier,jdbcType=INTEGER} AS affected_name AS permissions - JOIN [guacamole_user] ON [guacamole_user].username = permissions.username + JOIN [guacamole_entity] affected_entity ON + affected_entity.name = permissions.affected_name + AND affected_entity.type = 'USER' + JOIN [guacamole_user] affected_user ON affected_user.entity_id = affected_entity.entity_id WHERE NOT EXISTS (SELECT 1 FROM [guacamole_user_permission] - WHERE [guacamole_user_permission].user_id = permissions.user_id + WHERE [guacamole_user_permission].entity_id = permissions.entity_id AND [guacamole_user_permission].permission = permissions.permission - AND [guacamole_user_permission].affected_user_id = [guacamole_user].user_id + AND [guacamole_user_permission].affected_user_id = affected_user.user_id ); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index 0b3212f53..dc87f53b9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -52,7 +52,11 @@ SELECT sharing_profile_id FROM [guacamole_sharing_profile_permission] WHERE - user_id = #{user.objectID,jdbcType=INTEGER} + + + + + AND permission = 'READ' @@ -99,7 +103,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; SELECT @@ -113,7 +121,11 @@ open="(" separator="," close=")"> #{identifier,jdbcType=INTEGER} - AND user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND permission = 'READ'; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml index 20d2cfb06..21fd986b1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml @@ -41,8 +41,9 @@ [guacamole_user_password_history].password_date FROM [guacamole_user_password_history] JOIN [guacamole_user] ON [guacamole_user_password_history].user_id = [guacamole_user].user_id + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id WHERE - [guacamole_user].username = #{username,jdbcType=VARCHAR} + [guacamole_entity].name = #{username,jdbcType=VARCHAR} ORDER BY [guacamole_user_password_history].password_date DESC diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index 177ab939a..7d70950af 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -28,7 +28,8 @@ - + + @@ -57,17 +58,24 @@ @@ -77,7 +85,8 @@ SELECT [guacamole_user].user_id, - [guacamole_user].username, + [guacamole_entity].entity_id, + [guacamole_entity].name, password_hash, password_salt, password_date, @@ -98,11 +107,13 @@ WHERE [guacamole_user_history].user_id = [guacamole_user].user_id ) AS last_active FROM [guacamole_user] - WHERE [guacamole_user].username IN + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE [guacamole_entity].name IN #{identifier,jdbcType=VARCHAR} - ; + + AND [guacamole_entity].type = 'USER'; SELECT [guacamole_user_attribute].user_id, @@ -110,11 +121,13 @@ [guacamole_user_attribute].attribute_value FROM [guacamole_user_attribute] JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id - WHERE username IN + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE [guacamole_entity].name IN - #{identifier,jdbcType=INTEGER} - ; + #{identifier,jdbcType=VARCHAR} + + AND [guacamole_entity].type = 'USER'; @@ -124,7 +137,8 @@ SELECT [guacamole_user].user_id, - [guacamole_user].username, + [guacamole_entity].entity_id, + [guacamole_entity].name, password_hash, password_salt, password_date, @@ -145,13 +159,19 @@ WHERE [guacamole_user_history].user_id = [guacamole_user].user_id ) AS last_active FROM [guacamole_user] + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id - WHERE [guacamole_user].username IN + WHERE [guacamole_entity].name IN #{identifier,jdbcType=VARCHAR} - AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND [guacamole_entity].type = 'USER' + AND + + + + AND permission = 'READ'; SELECT @@ -160,13 +180,19 @@ [guacamole_user_attribute].attribute_value FROM [guacamole_user_attribute] JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id - WHERE username IN + WHERE [guacamole_entity].name IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=VARCHAR} - AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND [guacamole_entity].type = 'USER' + AND + + + + AND permission = 'READ'; @@ -176,8 +202,9 @@ resultSets="users,arbitraryAttributes"> SELECT - user_id, - username, + [guacamole_user].user_id, + [guacamole_entity].entity_id, + [guacamole_entity].name, password_hash, password_salt, password_date, @@ -198,8 +225,10 @@ WHERE [guacamole_user_history].user_id = [guacamole_user].user_id ) AS last_active FROM [guacamole_user] + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id WHERE - [guacamole_user].username = #{username,jdbcType=VARCHAR}; + [guacamole_entity].name = #{username,jdbcType=VARCHAR} + AND [guacamole_entity].type = 'USER'; SELECT [guacamole_user_attribute].user_id, @@ -207,14 +236,19 @@ [guacamole_user_attribute].attribute_value FROM [guacamole_user_attribute] JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id - WHERE username = #{username,jdbcType=VARCHAR}; + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + [guacamole_entity].name = #{username,jdbcType=VARCHAR} + AND [guacamole_entity].type = 'USER' - DELETE FROM [guacamole_user] - WHERE username = #{identifier,jdbcType=VARCHAR} + DELETE FROM [guacamole_entity] + WHERE + name = #{identifier,jdbcType=VARCHAR} + AND type = 'USER' @@ -222,7 +256,7 @@ parameterType="org.apache.guacamole.auth.jdbc.user.UserModel"> INSERT INTO [guacamole_user] ( - username, + entity_id, password_hash, password_salt, password_date, @@ -239,7 +273,7 @@ organizational_role ) VALUES ( - #{object.identifier,jdbcType=VARCHAR}, + #{object.entityID,jdbcType=VARCHAR}, #{object.passwordHash,jdbcType=BINARY}, #{object.passwordSalt,jdbcType=BINARY}, #{object.passwordDate,jdbcType=TIMESTAMP}, diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml new file mode 100644 index 000000000..e6eccba96 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + DELETE [guacamole_user_group_member] + FROM [guacamole_user_group_member] + JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id + JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id + WHERE + member_entity_id = #{parent.entityID,jdbcType=INTEGER} + AND [guacamole_entity].type = 'USER_GROUP' + AND [guacamole_entity].name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO [guacamole_user_group_member] ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + [guacamole_user_group].user_group_id, + #{parent.entityID,jdbcType=INTEGER} + FROM [guacamole_user_group] + JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id + WHERE + [guacamole_entity].name IN + + #{identifier,jdbcType=VARCHAR} + + AND [guacamole_entity].type = 'USER_GROUP' + AND [guacamole_user_group].user_group_id NOT IN ( + SELECT [guacamole_user_group_member].user_group_id + FROM [guacamole_user_group_member] + WHERE [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER} + ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml index 22a0cc75f..4d4a3cc69 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml @@ -44,8 +44,9 @@ [guacamole_user_history].end_date FROM [guacamole_user_history] JOIN [guacamole_user] ON [guacamole_user_history].user_id = [guacamole_user].user_id + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id WHERE - [guacamole_user].username = #{username,jdbcType=VARCHAR} + [guacamole_entity].name = #{username,jdbcType=VARCHAR} ORDER BY [guacamole_user_history].start_date DESC, [guacamole_user_history].end_date DESC @@ -66,7 +67,10 @@ VALUES ( #{record.remoteHost,jdbcType=VARCHAR}, (SELECT user_id FROM [guacamole_user] - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + [guacamole_entity].name = #{record.username,jdbcType=VARCHAR} + AND [guacamole_entity].type = 'USER'), #{record.username,jdbcType=VARCHAR}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} @@ -79,7 +83,10 @@ UPDATE [guacamole_user_history] SET remote_host = #{record.remoteHost,jdbcType=VARCHAR}, user_id = (SELECT user_id FROM [guacamole_user] - WHERE username = #{record.username,jdbcType=VARCHAR}), + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + [guacamole_entity].name = #{record.username,jdbcType=VARCHAR} + AND [guacamole_entity].type = 'USER'), username = #{record.username,jdbcType=VARCHAR}, start_date = #{record.startDate,jdbcType=TIMESTAMP}, end_date = #{record.endDate,jdbcType=TIMESTAMP} @@ -105,7 +112,10 @@ [guacamole_user_history].user_id IN ( SELECT user_id FROM [guacamole_user] - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0 + AND [guacamole_entity].type = 'USER'), ) @@ -144,7 +154,11 @@ JOIN [guacamole_user_permission] ON [guacamole_user_history].user_id = [guacamole_user_permission].affected_user_id - AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND + + + + AND [guacamole_user_permission].permission = 'READ' @@ -155,7 +169,10 @@ [guacamole_user_history].user_id IN ( SELECT user_id FROM [guacamole_user] - WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 + JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id + WHERE + POSITION(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0 + AND [guacamole_entity].type = 'USER' ) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml new file mode 100644 index 000000000..aed0247be --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM [guacamole_entity] + WHERE + name = #{identifier,jdbcType=VARCHAR} + AND type = 'USER_GROUP' + + + + + + INSERT INTO [guacamole_user_group] ( + entity_id, + disabled + ) + VALUES ( + #{object.entityID,jdbcType=VARCHAR}, + #{object.disabled,jdbcType=BOOLEAN} + ) + + + + + + UPDATE [guacamole_user_group] + SET disabled = #{object.disabled,jdbcType=BOOLEAN} + WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR} + + + + + DELETE FROM [guacamole_user_group_attribute] + WHERE user_group_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO [guacamole_user_group_attribute] ( + user_group_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml new file mode 100644 index 000000000..2092f24e9 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + DELETE [guacamole_user_group_member] + FROM [guacamole_user_group_member] + JOIN [guacamole_entity] ON [guacamole_entity].entity_id = member_entity_id + WHERE + user_group_id = #{parent.objectID,jdbcType=INTEGER} + AND [guacamole_entity].type = 'USER_GROUP' + AND [guacamole_entity].name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO [guacamole_user_group_member] ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + #{parent.objectID,jdbcType=INTEGER}, + [guacamole_entity].entity_id + FROM [guacamole_entity] + WHERE + [guacamole_entity].name IN + + #{identifier} + + AND [guacamole_entity].type = 'USER_GROUP' + AND [guacamole_entity].entity_id NOT IN ( + SELECT [guacamole_user_group_member].member_entity_id + FROM [guacamole_user_group_member] + WHERE [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER} + ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml new file mode 100644 index 000000000..2c91c92c2 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + DELETE [guacamole_user_group_member] + FROM [guacamole_user_group_member] + JOIN [guacamole_entity] ON [guacamole_entity].entity_id = member_entity_id + WHERE + user_group_id = #{parent.objectID,jdbcType=INTEGER} + AND [guacamole_entity].type = 'USER' + AND [guacamole_entity].name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO [guacamole_user_group_member] ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + #{parent.objectID,jdbcType=INTEGER}, + [guacamole_entity].entity_id + FROM [guacamole_entity] + WHERE + [guacamole_entity].name IN + + #{identifier} + + AND [guacamole_entity].type = 'USER' + AND [guacamole_entity].entity_id NOT IN ( + SELECT [guacamole_user_group_member].member_entity_id + FROM [guacamole_user_group_member] + WHERE [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER} + ) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml new file mode 100644 index 000000000..0ea9252e7 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + DELETE [guacamole_user_group_member] + FROM [guacamole_user_group_member] + JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id + JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id + WHERE + member_entity_id = #{parent.entityID,jdbcType=INTEGER} + AND [guacamole_entity].type = 'USER_GROUP' + AND [guacamole_entity].name IN + + #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO [guacamole_user_group_member] ( + user_group_id, + member_entity_id + ) + SELECT DISTINCT + [guacamole_user_group].user_group_id, + #{parent.entityID,jdbcType=INTEGER} + FROM [guacamole_user_group] + JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id + WHERE + [guacamole_entity].name IN + + #{identifier,jdbcType=VARCHAR} + + AND [guacamole_entity].type = 'USER_GROUP' + AND [guacamole_user_group].user_group_id NOT IN ( + SELECT [guacamole_user_group_member].user_group_id + FROM [guacamole_user_group_member] + WHERE [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER} + ) + + + From 8399b252cd335d4d0e4b977cd8613e0fe2ed4a4a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 16 Sep 2018 22:33:12 -0700 Subject: [PATCH 24/32] GUACAMOLE-220: Detect cycles within recursive query. SQL Server cannot deal with cycles on its own. --- .../apache/guacamole/auth/jdbc/base/EntityMapper.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml index f61463a82..a13279ed5 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml @@ -65,9 +65,10 @@