/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.core.domain.auth; import java.io.Serializable; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.QueryHint; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import javax.persistence.Transient; import org.jetbrains.annotations.NotNull; import org.rhq.core.domain.authz.Role; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.content.Repo; import org.rhq.core.domain.dashboard.Dashboard; import org.rhq.core.domain.resource.group.ResourceGroup; /** * @author Greg Hinkle */ @Entity @NamedQueries({ @NamedQuery(name = Subject.QUERY_GET_SUBJECTS_ASSIGNED_TO_ROLE, query = "" // + "SELECT s " // + " FROM Subject s " // + " JOIN s.roles r " // + " WHERE r.id = :id " // + " AND s.fsystem = FALSE " // + " AND s.factive = TRUE"), /* AuthorizationManager queries */ @NamedQuery(name = Subject.QUERY_GET_GLOBAL_PERMISSIONS, hints = { @QueryHint(name = "org.hibernate.cacheable", value = "true"), @QueryHint(name = "org.hibernate.cacheRegion", value = "security") }, query = "SELECT distinct p " + "FROM Subject AS s, IN (s.roles) r, IN (r.permissions) p " + "WHERE s = :subject"), @NamedQuery(name = Subject.QUERY_HAS_GLOBAL_PERMISSION, hints = { @QueryHint(name = "org.hibernate.cacheable", value = "true"), @QueryHint(name = "org.hibernate.cacheRegion", value = "security") }, query = "SELECT COUNT(p) " + "FROM Subject AS s, IN (s.roles) r, IN (r.permissions) p " + "WHERE s = :subject AND p = :permission"), @NamedQuery(name = Subject.QUERY_GET_PERMISSIONS_BY_GROUP_ID, query = "SELECT DISTINCT p " + "FROM Role r JOIN r.subjects s JOIN r.permissions p " + "WHERE " + " (" + " r in (SELECT r2 from ResourceGroup g JOIN g.roles r2 WHERE g.id = :groupId) " + " OR r in (SELECT r3 from ResourceGroup g JOIN g.clusterResourceGroup crg JOIN crg.roles r3 WHERE g.id = :groupId AND crg.recursive = true) " + " ) " + " AND s = :subject"), @NamedQuery(name = Subject.QUERY_GET_PERMISSIONS_BY_PRIVATE_GROUP_ID, query = "" // + "SELECT p, count(distinct res.id) " // + " FROM ResourceGroup rg, IN (rg.explicitResources) res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.permissions) p " // + " WHERE rg.id = :privateGroupId " // + " AND rg.subject.id = :subjectId " // + " GROUP BY p " // + " HAVING count(distinct res.id) = " // + " ( SELECT count(*) " // + " FROM ResourceGroup g2 JOIN g2.explicitResources res2 " // + " WHERE g2.id = :privateGroupId )"), @NamedQuery(name = Subject.QUERY_HAS_GROUP_PERMISSION, query = "SELECT count(r) " + "FROM Role r JOIN r.subjects s JOIN r.permissions p " + "WHERE " + " (" + " r in (SELECT r2 from ResourceGroup g JOIN g.roles r2 WHERE g.id = :groupId) " + " OR r in (SELECT r3 from ResourceGroup g JOIN g.clusterResourceGroup crg JOIN crg.roles r3 WHERE g.id = :groupId AND crg.recursive = true) " + " ) " + " AND s = :subject " + " AND p = :permission"), @NamedQuery(name = Subject.QUERY_HAS_PRIVATE_GROUP_PERMISSION, query = "" // + "SELECT p, count(distinct res.id) " // + " FROM ResourceGroup rg, IN (rg.explicitResources) res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.permissions) p " // + " WHERE rg.id = :privateGroupId " // + " AND rg.subject.id = :subjectId " // + " AND p = :permission " // + " GROUP BY p " // + " HAVING count(distinct res.id) = " // + " ( SELECT count(*) " // + " FROM ResourceGroup g2 JOIN g2.explicitResources res2 " // + " WHERE g2.id = :privateGroupId )"), @NamedQuery(name = Subject.QUERY_GET_PERMISSIONS_BY_RESOURCE_ID, query = "SELECT distinct p " + "FROM Resource res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.subjects) s, IN (r.permissions) p " + "WHERE s = :subject AND res.id = :resourceId"), @NamedQuery(name = Subject.QUERY_HAS_RESOURCE_PERMISSION, query = "SELECT COUNT(res) " + "FROM Resource res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.subjects) s, IN (r.permissions) p " + "WHERE s = :subject AND res.id = :resourceId AND p = :permission"), //@Deprecated @NamedQuery(name = Subject.QUERY_HAS_AUTO_GROUP_PERMISSION, query = "" // + "SELECT COUNT(res.id) " // + " FROM Resource res " // + " WHERE res.parentResource.id = :parentResourceId " // + " AND res.resourceType.id = :resourceTypeId " // + " AND ( :subjectId = -1 OR res.id IN ( SELECT ires " // + " FROM Resource ires " // + " JOIN ires.implicitGroups g " // + " JOIN g.roles r " // + " JOIN r.permissions p " // + " JOIN r.subjects s " // + " WHERE s.id = :subjectId and p = :permission ) ) "), @NamedQuery(name = Subject.QUERY_GET_PERMISSIONS_BY_BUNDLE_ID, query = "SELECT distinct p " + "FROM Bundle bundle, IN (bundle.bundleGroups) bg, IN (bg.roles) r, IN (r.subjects) s, IN (r.permissions) p " + "WHERE s = :subject AND bundle.id = :bundleId"), @NamedQuery(name = Subject.QUERY_HAS_BUNDLE_PERMISSION, query = "SELECT COUNT(b) " + "FROM Bundle b, IN (b.bundleGroups) bg, IN (bg.roles) r, IN (r.subjects) s, IN (r.permissions) p " + "WHERE s = :subject AND b.id = :bundleId AND p = :permission"), @NamedQuery(name = Subject.QUERY_GET_PERMISSIONS_BY_BUNDLE_GROUP_ID, query = "SELECT DISTINCT p " + "FROM Role r JOIN r.subjects s JOIN r.permissions p " + "WHERE r in (SELECT r2 from BundleGroup bg JOIN bg.roles r2 WHERE bg.id = :bundleGroupId) " + " AND s = :subject "), @NamedQuery(name = Subject.QUERY_HAS_BUNDLE_GROUP_PERMISSION, query = "SELECT count(r) " + "FROM Role r JOIN r.subjects s JOIN r.permissions p " + "WHERE r in (SELECT r2 from BundleGroup bg JOIN bg.roles r2 WHERE bg.id = :bundleGroupId) " + " AND s = :subject " + " AND p = :permission"), @NamedQuery(name = Subject.QUERY_CAN_VIEW_RESOURCE, query = "SELECT COUNT(res) " + "FROM Resource res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.subjects) s " + "WHERE s = :subject AND res.id = :resourceId"), @NamedQuery(name = Subject.QUERY_CAN_VIEW_RESOURCES, query = "SELECT COUNT(DISTINCT res) " + "FROM Resource res, IN (res.implicitGroups) g, IN (g.roles) r, IN (r.subjects) s " + "WHERE s = :subject AND res.id IN (:resourceIds)"), @NamedQuery(name = Subject.QUERY_CAN_VIEW_GROUP, query = "" // + "SELECT count(g) " // + " FROM ResourceGroup g " // + " WHERE g.id = :groupId " // + " AND ( g.subject = :subject " // private group case (autogroup backing group) + " OR g.id IN (SELECT rg.id " // role-associated group case + " FROM ResourceGroup rg " // + " JOIN rg.roles r " // + " JOIN r.subjects s " // + " WHERE s = :subject) " // + " OR g.id IN (SELECT rg.id " // autocluster backing group case + " FROM ResourceGroup rg " // + " JOIN rg.clusterResourceGroup crg " // + " JOIN crg.roles r " // + " JOIN r.subjects s " // + " WHERE crg.recursive = true AND s = :subject))"), // @Deprecated @NamedQuery(name = Subject.QUERY_CAN_VIEW_AUTO_GROUP, query = "" // + "SELECT COUNT(res.id) " // + " FROM Resource res " // + " WHERE res.parentResource.id = :parentResourceId " // + " AND res.resourceType.id = :resourceTypeId " // + " AND ( :subjectId = -1 OR res.id IN ( SELECT ires " // + " FROM Resource ires " // + " JOIN ires.implicitGroups g " // + " JOIN g.roles r " // + " JOIN r.subjects s " // + " WHERE s.id = :subjectId ) ) "), @NamedQuery(name = Subject.QUERY_CAN_VIEW_BUNDLE, query = "SELECT COUNT(b) " + "FROM Bundle b, IN (b.bundleGroups) bg, IN (bg.roles) r, IN (r.subjects) s " + "WHERE s = :subject AND b.id = :bundleId"), @NamedQuery(name = Subject.QUERY_CAN_VIEW_BUNDLE_GROUP, query = "" // + "SELECT count(bg) " // + " FROM BundleGroup bg " // + " WHERE bg.id = :bundleGroupId " // + " AND bg.id IN (SELECT innerbg.id " // + " FROM BundleGroup innerbg " // + " JOIN innerbg.roles r " // + " JOIN r.subjects s " // + " WHERE s = :subject) "), /* * No easy way to test whether ALL resources are in some group in some role in some subject where * subject.id = <id> & role.permission = <perm> * * Instead, we must use this potentially VERY costly resource query (costly because the result list could be huge in large * environments). However, we can return res.id only, to save a lot of traffic across the line and speed it up. */ @NamedQuery(name = Subject.QUERY_GET_RESOURCES_BY_PERMISSION, query = "SELECT distinct res.id " + "FROM Subject s, IN (s.roles) r, IN (r.permissions) p, IN (r.resourceGroups) g, IN (g.implicitResources) res " + "WHERE s = :subject AND p = :permission AND res.inventoryStatus = 'COMMITTED'"), /* * No easy way to test whether ALL bundles are in some bundle group in some role in some subject where * subject.id = <id> & role.permission = <perm> * * Instead, we must use this potentially VERY costly query (costly because the result list could be huge in large * environments). However, we can return bundle.id only, to save a lot of traffic across the line and speed it up. */ @NamedQuery(name = Subject.QUERY_GET_BUNDLES_BY_PERMISSION, query = "SELECT distinct bundle.id " + "FROM Subject s, IN (s.roles) r, IN (r.permissions) p, IN (r.bundleGroups) g, IN (g.bundles) bundle " + "WHERE s = :subject AND p = :permission"), @NamedQuery(name = Subject.QUERY_FIND_AVAILABLE_SUBJECTS_FOR_ROLE_WITH_EXCLUDES, query = "" // + "SELECT DISTINCT s " + " FROM Subject AS s LEFT JOIN s.roles AS r " // + " WHERE s.id NOT IN " // + " ( " // + " SELECT ss.id " // + " FROM Role rr JOIN rr.subjects AS ss " // + " WHERE rr.id = :roleId" // + " ) " // + " AND s.id NOT IN ( :excludes ) " // + " AND s.fsystem = FALSE " // + " AND s.factive = TRUE"), // @NamedQuery(name = Subject.QUERY_FIND_AVAILABLE_SUBJECTS_FOR_ROLE, query = "" // + "SELECT DISTINCT s " // + " FROM Subject AS s LEFT JOIN s.roles AS r " // + " WHERE s.id NOT IN " // + " ( " // + " SELECT ss.id " // + " FROM Role rr JOIN rr.subjects AS ss " // + " WHERE rr.id = :roleId" + " ) " // + " AND s.fsystem = FALSE " // + " AND s.factive = TRUE"), // @NamedQuery(name = Subject.QUERY_DYNAMIC_CONFIG_VALUES, query = "" // + "SELECT s.name, s.name FROM Subject AS s WHERE s.fsystem = false") }) @SequenceGenerator(allocationSize = org.rhq.core.domain.util.Constants.ALLOCATION_SIZE, name = "RHQ_SUBJECT_ID_SEQ", sequenceName = "RHQ_SUBJECT_ID_SEQ") @Table(name = "RHQ_SUBJECT") /*@Cache(usage= CacheConcurrencyStrategy.TRANSACTIONAL)*/ public class Subject implements Serializable { public static final String QUERY_GET_SUBJECTS_ASSIGNED_TO_ROLE = "Subject.getSubjectsAssignedToRole"; public static final String QUERY_GET_GLOBAL_PERMISSIONS = "Subject.getGlobalPermissions"; public static final String QUERY_GET_PERMISSIONS_BY_GROUP_ID = "Subject.getPermissionsByGroup"; public static final String QUERY_GET_PERMISSIONS_BY_PRIVATE_GROUP_ID = "Subject.getPermissionsByPrivateGroup"; public static final String QUERY_GET_PERMISSIONS_BY_RESOURCE_ID = "Subject.getPermissionsByResource"; public static final String QUERY_GET_PERMISSIONS_BY_BUNDLE_ID = "Subject.getPermissionsByBundle"; public static final String QUERY_GET_PERMISSIONS_BY_BUNDLE_GROUP_ID = "Subject.getPermissionsByBundleGroup"; public static final String QUERY_ROLES_BY_RESOURCE_IDS = "Subject.getRolesByResources"; public static final String QUERY_HAS_GLOBAL_PERMISSION = "Subject.hasGlobalPermission"; public static final String QUERY_HAS_GROUP_PERMISSION = "Subject.hasGroupPermission"; public static final String QUERY_HAS_PRIVATE_GROUP_PERMISSION = "Subject.hasPrivateGroupPermission"; public static final String QUERY_HAS_RESOURCE_PERMISSION = "Subject.hasResourcePermission"; public static final String QUERY_HAS_AUTO_GROUP_PERMISSION = "Subject.hasAutoGroupPermission"; public static final String QUERY_HAS_BUNDLE_PERMISSION = "Subject.hasBundlePermission"; public static final String QUERY_HAS_BUNDLE_GROUP_PERMISSION = "Subject.hasBundleGroupPermission"; /** This query can return more than 1 if the resource is accessible via separate groups */ public static final String QUERY_CAN_VIEW_RESOURCE = "Subject.canViewResource"; public static final String QUERY_CAN_VIEW_RESOURCES = "Subject.canViewResources"; public static final String QUERY_CAN_VIEW_GROUP = "Subject.canViewGroup"; public static final String QUERY_CAN_VIEW_AUTO_GROUP = "Subject.canViewAutoGroup"; public static final String QUERY_CAN_VIEW_BUNDLE = "Subject.canViewBundle"; public static final String QUERY_CAN_VIEW_BUNDLE_GROUP = "Subject.canViewBundleGroup"; public static final String QUERY_GET_BUNDLES_BY_PERMISSION = "Subject.getBundlesByPermission"; public static final String QUERY_GET_RESOURCES_BY_PERMISSION = "Subject.getResourcesByPermission"; public static final String QUERY_FIND_AVAILABLE_SUBJECTS_FOR_ROLE_WITH_EXCLUDES = "Subject.findAvailableSubjectsForRoleWithExcludes"; public static final String QUERY_FIND_AVAILABLE_SUBJECTS_FOR_ROLE = "Subject.findAvailableSubjectsForRole"; public static final String QUERY_DYNAMIC_CONFIG_VALUES = "Subject.dynamicConfigValues"; private static final long serialVersionUID = 1L; @Column(name = "ID", nullable = false) @GeneratedValue(strategy = GenerationType.AUTO, generator = "RHQ_SUBJECT_ID_SEQ") @Id private int id; @Column(name = "NAME", nullable = false) private String name; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; @Column(name = "EMAIL_ADDRESS") private String emailAddress; @Column(name = "SMS_ADDRESS") private String smsAddress; @Column(name = "PHONE_NUMBER") private String phoneNumber; @Column(name = "DEPARTMENT") private String department; @Column(name = "FACTIVE", nullable = false) private boolean factive; @Column(name = "FSYSTEM", nullable = false) private boolean fsystem; @JoinColumn(name = "CONFIGURATION_ID") @OneToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE }) private Configuration configuration; @JoinTable(name = "RHQ_SUBJECT_ROLE_MAP", joinColumns = { @JoinColumn(name = "SUBJECT_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") }) @ManyToMany private java.util.Set<Role> roles; @JoinTable(name = "RHQ_SUBJECT_ROLE_LDAP_MAP", joinColumns = { @JoinColumn(name = "SUBJECT_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") }) @ManyToMany private java.util.Set<Role> ldapRoles; // When a subject is removed any owned groups are removed manually, no cascade delete for groups @OneToMany(mappedBy = "subject", fetch = FetchType.LAZY) private List<ResourceGroup> ownedGroups = null; @OneToMany(mappedBy = "owner", fetch = FetchType.LAZY) private Set<Repo> ownedRepos; // When a subject is removed any owned dashboards are removed automatically @OneToMany(mappedBy = "owner", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) private List<Dashboard> ownedDashboards = null; @Transient private Integer sessionId = null; private void init() { roles = new HashSet<Role>(); ldapRoles = new HashSet<Role>(); } /** * Creates a new instance of Subject */ public Subject() { init(); } public Subject(@NotNull String name, boolean factive, boolean fsystem) { init(); this.name = name; this.factive = factive; this.fsystem = fsystem; } public int getId() { return this.id; } /** * When a user successfully logs in, the user will be assigned a session ID. This is that session ID - when not * <code>null</code>, you can assume this user has been authenticated and is currently logged into the system. * * @param sessionId */ public void setSessionId(Integer sessionId) { this.sessionId = sessionId; } /** * If not <code>null</code>, you can assume the user associated with this Subject has been authenticated. * * @return the logged in user's session ID */ public Integer getSessionId() { return this.sessionId; } public void setId(int id) { this.id = id; } @NotNull public String getName() { return this.name; } public void setName(@NotNull String name) { this.name = name; } public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmailAddress() { return this.emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String getSmsAddress() { return this.smsAddress; } public void setSmsAddress(String smsAddress) { this.smsAddress = smsAddress; } public String getPhoneNumber() { return this.phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getDepartment() { return this.department; } public void setDepartment(String department) { this.department = department; } public boolean getFactive() { return this.factive; } public void setFactive(boolean factive) { this.factive = factive; } public boolean getFsystem() { return this.fsystem; } public void setFsystem(boolean fsystem) { this.fsystem = fsystem; } public Configuration getUserConfiguration() { return this.configuration; } public void setUserConfiguration(Configuration configuration) { this.configuration = configuration; } public java.util.Set<Role> getRoles() { if (this.roles == null) { this.roles = new HashSet<Role>(); } return this.roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } public void addRole(Role role, boolean isLdap) { if (this.roles == null) { this.roles = new HashSet<Role>(); } this.roles.add(role); if (isLdap) { if (this.ldapRoles == null) { this.ldapRoles = new HashSet<Role>(); } this.ldapRoles.add(role); } } public void addRole(Role role) { addRole(role, false); } public void removeRole(Role role) { if (this.roles != null) { this.roles.remove(role); } } public java.util.Set<Role> getLdapRoles() { if (this.ldapRoles == null) { this.ldapRoles = new HashSet<Role>(); } return this.ldapRoles; } public void setLdapRoles(Set<Role> roles) { this.ldapRoles = roles; } public void addLdapRole(Role role) { addRole(role, true); } public void removeLdapRole(Role role) { if (this.ldapRoles != null) { this.ldapRoles.remove(role); } } public List<ResourceGroup> getOwnedGroups() { return ownedGroups; } public void setOwnedGroups(List<ResourceGroup> ownedGroups) { this.ownedGroups = ownedGroups; } protected Set<Repo> getOwnedrepos() { return ownedRepos; } protected void setOwnedRepos(Set<Repo> repos) { ownedRepos = repos; } protected List<Dashboard> getOwnedDashboards() { return ownedDashboards; } protected void setOwnedDashboards(List<Dashboard> ownedDashboards) { this.ownedDashboards = ownedDashboards; } @Override public String toString() { return "Subject[id=" + id + ",name=" + name + "]"; } @Override public int hashCode() { final int PRIME = 31; int result = 1; result = (PRIME * result) + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if ((obj == null) || !(obj instanceof Subject)) { return false; } final Subject other = (Subject) obj; if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } }