/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.picketlink.authorization.util; import org.picketlink.Identity; import org.picketlink.authentication.levels.Level; import org.picketlink.common.properties.Property; import org.picketlink.common.properties.query.AnnotatedPropertyCriteria; import org.picketlink.common.properties.query.PropertyQueries; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.PartitionManager; import org.picketlink.idm.RelationshipManager; import org.picketlink.idm.config.IdentityConfiguration; import org.picketlink.idm.config.IdentityStoreConfiguration; import org.picketlink.idm.model.Account; import org.picketlink.idm.model.AttributedType; import org.picketlink.idm.model.IdentityType; import org.picketlink.idm.model.Partition; import org.picketlink.idm.model.Relationship; import org.picketlink.idm.model.annotation.IdentityStereotype; import org.picketlink.idm.model.annotation.RelationshipStereotype; import org.picketlink.idm.model.annotation.StereotypeProperty; import org.picketlink.idm.query.IdentityQueryBuilder; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import static org.picketlink.common.util.StringUtil.isNullOrEmpty; import static org.picketlink.idm.model.annotation.IdentityStereotype.Stereotype.GROUP; import static org.picketlink.idm.model.annotation.IdentityStereotype.Stereotype.ROLE; import static org.picketlink.idm.model.annotation.RelationshipStereotype.Stereotype.GRANT; import static org.picketlink.idm.model.annotation.RelationshipStereotype.Stereotype.GROUP_MEMBERSHIP; import static org.picketlink.idm.model.annotation.StereotypeProperty.Property.IDENTITY_GROUP_NAME; import static org.picketlink.idm.model.annotation.StereotypeProperty.Property.IDENTITY_ROLE_NAME; /** * <p>Provides some comon authorization methods.</p> * * @author Pedro Igor */ public class AuthorizationUtil { /** * <p>Checks if the user is logged in.</p> * * @param identity The {@link org.picketlink.Identity} instance representing an authenticated user. * * @return True if the user is logged in. Otherwise, returns false. */ public static boolean isLoggedIn(Identity identity) { if (identity == null) { throw new IllegalArgumentException("You must provide an Identity instance."); } return identity.isLoggedIn(); } /** * <p>Checks if the user has permissions to a resource considering an operation.</p> * * @param identity The {@link org.picketlink.Identity} instance representing an authenticated user. * @param resource The resource. * @param resourceClass The resource class if specified. * @param resourceIdentifier The resource identifier, if specified. * @param operation The operation. */ public static boolean hasPermission(Identity identity, Object resource, Class<?> resourceClass, Serializable resourceIdentifier, String operation) { if (resource == null && resourceClass == null) { throw new IllegalArgumentException("You must provide a resource or resourceClass in order to check a permission."); } if (isNullOrEmpty(operation)) { throw new IllegalArgumentException("You must provide an operation in order to check a permission."); } if (!isLoggedIn(identity)) { return false; } if (resource != null && !isNullOrEmpty(resource.toString())) { return identity.hasPermission(resource, operation); } else if (resourceClass != null) { if (resourceIdentifier == null || isNullOrEmpty(resourceIdentifier.toString())) { resourceIdentifier = null; } return identity.hasPermission(resourceClass, resourceIdentifier, operation); } return false; } /** * <p>Checks if an authenticated user is granted with a role with the given name.</p> * * @param identity The {@link org.picketlink.Identity} instance representing an authenticated user. * @param partitionManager * @param roleName The role name. * * @return True if the user is granted with the role. Otherwise, returns false. */ public static boolean hasRole(Identity identity, PartitionManager partitionManager, String roleName) { if (!isLoggedIn(identity)) { return false; } List<Class<? extends IdentityType>> roleTypes = new ArrayList<Class<? extends IdentityType>>(); List<Class<? extends Relationship>> grantRelationshipTypes = new ArrayList<Class<? extends Relationship>>(); // let's get all role and grant relationship types supported by the configuration for (IdentityConfiguration configuration : partitionManager.getConfigurations()) { for (IdentityStoreConfiguration storeConfiguration : configuration.getStoreConfiguration()) { for (Class<? extends AttributedType> attributedType : storeConfiguration.getSupportedTypes().keySet()) { if (IdentityType.class.isAssignableFrom(attributedType)) { IdentityStereotype identityStereotype = attributedType.getAnnotation(IdentityStereotype.class); if (identityStereotype != null && ROLE.equals(identityStereotype.value())) { roleTypes.add((Class<? extends IdentityType>) attributedType); } } if (Relationship.class.isAssignableFrom(attributedType)) { RelationshipStereotype relationshipStereotype = attributedType.getAnnotation(RelationshipStereotype.class); if (relationshipStereotype != null && GRANT.equals(relationshipStereotype.value())) { grantRelationshipTypes.add((Class<? extends Relationship>) attributedType); } } } } } List<IdentityType> roles = new ArrayList<IdentityType>(); // now we need to get the role instance by its name against all stored partitions for (Class<? extends IdentityType> attributedType : roleTypes) { List<Property<Object>> identityStereotypeProperties = PropertyQueries .createQuery(attributedType) .addCriteria(new AnnotatedPropertyCriteria(StereotypeProperty.class)) .getResultList(); for (Property<Object> property : identityStereotypeProperties) { StereotypeProperty attributeProperty = property.getAnnotatedElement().getAnnotation(StereotypeProperty.class); StereotypeProperty.Property stereotypeProperty = attributeProperty.value(); if (IDENTITY_ROLE_NAME.equals(stereotypeProperty)) { for (Partition partition : partitionManager.getPartitions(Partition.class)) { IdentityManager identityManager = partitionManager.createIdentityManager(partition); IdentityQueryBuilder queryBuilder = identityManager.getQueryBuilder(); List<? extends IdentityType> result = queryBuilder .createIdentityQuery(attributedType) .where(queryBuilder.equal(AttributedType.QUERY_ATTRIBUTE.byName(property.getName()), roleName)) .getResultList(); if (!result.isEmpty()) { roles.add(result.get(0)); } } } } } RelationshipManager relationshipManager = partitionManager.createRelationshipManager(); // now we check the relationship between the authenticated account and roles considering the grant types supported by the configuration. for (IdentityType role : roles) { for (Class<? extends Relationship> relationshipType : grantRelationshipTypes) { List<Property<Object>> relationshipStereotypeProperties = PropertyQueries .createQuery(relationshipType) .addCriteria(new AnnotatedPropertyCriteria(StereotypeProperty.class)) .getResultList(); Property roleProperty = null; Property accountProperty = null; for (Property<Object> property : relationshipStereotypeProperties) { StereotypeProperty attributeProperty = property.getAnnotatedElement().getAnnotation(StereotypeProperty.class); StereotypeProperty.Property stereotypeProperty = attributeProperty.value(); if (StereotypeProperty.Property.RELATIONSHIP_GRANT_ROLE.equals(stereotypeProperty)) { roleProperty = property; } else if (StereotypeProperty.Property.RELATIONSHIP_GRANT_ASSIGNEE.equals(stereotypeProperty)) { accountProperty = property; } } if (roleProperty != null && accountProperty != null) { List<? extends Relationship> result = relationshipManager .createRelationshipQuery(relationshipType) .setParameter(Relationship.RELATIONSHIP_QUERY_ATTRIBUTE.byName(roleProperty.getName()), role) .setParameter(Relationship.RELATIONSHIP_QUERY_ATTRIBUTE.byName(accountProperty.getName()), identity .getAccount()) .getResultList(); if (!result.isEmpty()) { return true; } boolean inheritsPrivileges = relationshipManager.inheritsPrivileges(identity.getAccount(), role); if (inheritsPrivileges) { return true; } } } } return false; } /** * <p>Checks if an authenticated user is member of the a group with the given name.</p> * * @param identity The {@link org.picketlink.Identity} instance representing an authenticated user. * @param partitionManager * @param groupName The group name. * * @return True if the user is granted with the role. Otherwise, returns false. */ public static boolean isMember(Identity identity, PartitionManager partitionManager, String groupName) { if (!isLoggedIn(identity)) { return false; } List<Class<? extends IdentityType>> groupTypes = new ArrayList<Class<? extends IdentityType>>(); List<Class<? extends Relationship>> groupMembershipTypes = new ArrayList<Class<? extends Relationship>>(); // let's get all group and grant relationship types supported by the configuration for (IdentityConfiguration configuration : partitionManager.getConfigurations()) { for (IdentityStoreConfiguration storeConfiguration : configuration.getStoreConfiguration()) { for (Class<? extends AttributedType> attributedType : storeConfiguration.getSupportedTypes().keySet()) { if (IdentityType.class.isAssignableFrom(attributedType)) { IdentityStereotype identityStereotype = attributedType.getAnnotation(IdentityStereotype.class); if (identityStereotype != null && GROUP.equals(identityStereotype.value())) { groupTypes.add((Class<? extends IdentityType>) attributedType); } } if (Relationship.class.isAssignableFrom(attributedType)) { RelationshipStereotype relationshipStereotype = attributedType.getAnnotation(RelationshipStereotype.class); if (relationshipStereotype != null && GROUP_MEMBERSHIP.equals(relationshipStereotype.value())) { groupMembershipTypes.add((Class<? extends Relationship>) attributedType); } } } } } List<IdentityType> groups = new ArrayList<IdentityType>(); // now we need to get the group instance by its name against all stored partitions for (Class<? extends IdentityType> attributedType : groupTypes) { List<Property<Object>> identityStereotypeProperties = PropertyQueries .createQuery(attributedType) .addCriteria(new AnnotatedPropertyCriteria(StereotypeProperty.class)) .getResultList(); for (Property<Object> property : identityStereotypeProperties) { StereotypeProperty attributeProperty = property.getAnnotatedElement().getAnnotation(StereotypeProperty.class); StereotypeProperty.Property stereotypeProperty = attributeProperty.value(); if (IDENTITY_GROUP_NAME.equals(stereotypeProperty)) { for (Partition partition : partitionManager.getPartitions(Partition.class)) { IdentityManager identityManager = partitionManager.createIdentityManager(partition); IdentityQueryBuilder queryBuilder = identityManager.getQueryBuilder(); List<? extends IdentityType> result = queryBuilder .createIdentityQuery(attributedType) .where(queryBuilder.equal(AttributedType.QUERY_ATTRIBUTE.byName(property.getName()), groupName)) .getResultList(); if (!result.isEmpty()) { groups.add(result.get(0)); } } } } } RelationshipManager relationshipManager = partitionManager.createRelationshipManager(); // now we check the relationship between the authenticated account and groups considering the group membership types supported by the configuration. for (IdentityType group : groups) { for (Class<? extends Relationship> relationshipType : groupMembershipTypes) { List<Property<Object>> relationshipStereotypeProperties = PropertyQueries .createQuery(relationshipType) .addCriteria(new AnnotatedPropertyCriteria(StereotypeProperty.class)) .getResultList(); Property groupProperty = null; Property memberProperty = null; for (Property<Object> property : relationshipStereotypeProperties) { StereotypeProperty attributeProperty = property.getAnnotatedElement().getAnnotation(StereotypeProperty.class); StereotypeProperty.Property stereotypeProperty = attributeProperty.value(); if (StereotypeProperty.Property.RELATIONSHIP_GROUP_MEMBERSHIP_GROUP.equals(stereotypeProperty)) { groupProperty = property; } else if (StereotypeProperty.Property.RELATIONSHIP_GROUP_MEMBERSHIP_MEMBER.equals(stereotypeProperty)) { memberProperty = property; } } if (groupProperty != null && memberProperty != null) { List<? extends Relationship> result = relationshipManager .createRelationshipQuery(relationshipType) .setParameter(Relationship.RELATIONSHIP_QUERY_ATTRIBUTE.byName(groupProperty.getName()), group) .setParameter(Relationship.RELATIONSHIP_QUERY_ATTRIBUTE.byName(memberProperty.getName()), identity .getAccount()) .getResultList(); if (!result.isEmpty()) { return true; } } } } return false; } /** * <p>Checks if an authenticated user is associated with a partition with the given type and name.</p> * * @param identity The {@link org.picketlink.Identity} instance representing an authenticated user. * @param partitionType The required type of the partition. If null, all partition types should be considered. * @param partitionNames The name of the partitions that should be associated with an authenticated user. * * @return True if the user is associated with the partition. Otherwise, returns false. */ public static boolean hasPartition(Identity identity, Class<?> partitionType, String... partitionNames) { if (!isLoggedIn(identity)) { return false; } Account account = identity.getAccount(); Partition partition = account.getPartition(); if (partitionType != null && !partitionType.isInstance(partition)) { return false; } // this is the case when the type is being checked and the name is empty or null. if (partitionNames == null) { return true; } else if (partitionNames.length == 1) { if (isNullOrEmpty(partitionNames[0])) { return true; } } for (String partitionName : partitionNames) { if (!isNullOrEmpty(partitionName)) { if (partition.getName().equals(partitionName)) { return true; } } } return false; } /** * <p>Checks if an user has given security level.</p> * * @param identity The {@link org.picketlink.Identity} instance representing an authenticated user. * @param level Level which user should have * * @return True if the user has at least given level */ public static boolean hasLevel(Identity identity, Level level){ return (level.compareTo(identity.getLevel()) <= 0); } }