/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * Licensed 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.picketlink.idm.file.internal; import org.picketlink.common.properties.Property; import org.picketlink.common.properties.query.AnnotatedPropertyCriteria; import org.picketlink.common.properties.query.NamedPropertyCriteria; import org.picketlink.common.properties.query.PropertyQueries; import org.picketlink.common.properties.query.PropertyQuery; import org.picketlink.common.properties.query.TypedPropertyCriteria; import org.picketlink.idm.IdentityManagementException; import org.picketlink.idm.config.FileIdentityStoreConfiguration; import org.picketlink.idm.credential.handler.DigestCredentialHandler; import org.picketlink.idm.credential.handler.PasswordCredentialHandler; import org.picketlink.idm.credential.handler.TOTPCredentialHandler; import org.picketlink.idm.credential.handler.TokenCredentialHandler; import org.picketlink.idm.credential.handler.X509CertificateCredentialHandler; import org.picketlink.idm.credential.handler.annotations.CredentialHandlers; import org.picketlink.idm.credential.storage.CredentialStorage; import org.picketlink.idm.internal.AbstractAttributeStore; import org.picketlink.idm.internal.RelationshipReference; import org.picketlink.idm.internal.util.IdentityTypeUtil; import org.picketlink.idm.internal.util.PermissionUtil; import org.picketlink.idm.model.Account; import org.picketlink.idm.model.Attribute; 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.AttributeProperty; import org.picketlink.idm.permission.IdentityPermission; import org.picketlink.idm.permission.Permission; import org.picketlink.idm.permission.acl.spi.PermissionStore; import org.picketlink.idm.query.AttributeParameter; import org.picketlink.idm.query.Condition; import org.picketlink.idm.query.IdentityQuery; import org.picketlink.idm.query.QueryParameter; import org.picketlink.idm.query.RelationshipQuery; import org.picketlink.idm.query.RelationshipQueryParameter; import org.picketlink.idm.query.internal.BetweenCondition; import org.picketlink.idm.query.internal.EqualCondition; import org.picketlink.idm.query.internal.GreaterThanCondition; import org.picketlink.idm.query.internal.InCondition; import org.picketlink.idm.query.internal.LessThanCondition; import org.picketlink.idm.query.internal.LikeCondition; import org.picketlink.idm.spi.AttributeStore; import org.picketlink.idm.spi.CredentialStore; import org.picketlink.idm.spi.IdentityContext; import org.picketlink.idm.spi.PartitionStore; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static java.util.Map.Entry; import static org.picketlink.common.properties.query.TypedPropertyCriteria.MatchOption; import static org.picketlink.common.reflection.Reflections.newInstance; import static org.picketlink.common.util.StringUtil.isNullOrEmpty; import static org.picketlink.idm.IDMInternalMessages.MESSAGES; import static org.picketlink.idm.credential.util.CredentialUtils.getCurrentCredential; import static org.picketlink.idm.internal.util.PermissionUtil.asOperationList; import static org.picketlink.idm.internal.util.PermissionUtil.hasAttributes; /** * <p> File based {@link IdentityStore} implementation. </p> * * @author <a href="mailto:psilva@redhat.com">Pedro Silva</a> */ @CredentialHandlers({ PasswordCredentialHandler.class, X509CertificateCredentialHandler.class, DigestCredentialHandler.class, TOTPCredentialHandler.class, TokenCredentialHandler.class}) public class FileIdentityStore extends AbstractAttributeStore<FileIdentityStoreConfiguration> implements PartitionStore<FileIdentityStoreConfiguration>, CredentialStore<FileIdentityStoreConfiguration>, AttributeStore<FileIdentityStoreConfiguration>, PermissionStore { private FileDataSource fileDataSource; @Override public void setup(FileIdentityStoreConfiguration configuration) { super.setup(configuration); this.fileDataSource = new FileDataSource(configuration); } @Override protected void removeFromRelationships(IdentityContext context, IdentityType identityType) { Map<String, Map<String, FileRelationship>> relationships = this.fileDataSource.getRelationships(); for (Map<String, FileRelationship> relationshipsType : relationships.values()) { for (FileRelationship fileRelationship : new HashMap<String, FileRelationship>(relationshipsType).values()) { if (fileRelationship.hasIdentityType(identityType)) { relationshipsType.remove(fileRelationship.getId()); } } } this.fileDataSource.flushRelationships(); } @Override protected void removeCredentials(IdentityContext context, Account account) { Partition partition = account.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); Map<String, Map<String, List<FileCredentialStorage>>> credentials = filePartition.getCredentials(); credentials.remove(account.getId()); this.fileDataSource.flushCredentials(filePartition); } @Override public void addAttributedType(IdentityContext context, final AttributedType attributedType) { AttributedType clonedAttributedType = cloneAttributedType(context, attributedType); if (IdentityType.class.isInstance(clonedAttributedType)) { storeIdentityType(context, (IdentityType) clonedAttributedType); } else if (Relationship.class.isInstance(clonedAttributedType)) { storeRelationshipType((Relationship) clonedAttributedType); } else { this.fileDataSource.getAttributedTypes().put(attributedType.getId(), new FileAttributedType(attributedType)); } } @Override public void updateAttributedType(IdentityContext context, final AttributedType attributedType) { AttributedType updatedAttributedType = cloneAttributedType(context, (attributedType)); if (IdentityType.class.isInstance(attributedType)) { storeIdentityType(context, (IdentityType) updatedAttributedType); } else if (Relationship.class.isInstance(attributedType)) { storeRelationshipType((Relationship) updatedAttributedType); } } @Override public void removeAttributedType(IdentityContext context, AttributedType attributedType) { if (IdentityType.class.isInstance(attributedType)) { IdentityType identityType = (IdentityType) attributedType; Partition partition = identityType.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); Map<String, FileIdentityType> identityTypes = filePartition.getIdentityTypes().get(attributedType.getClass().getName()); if (identityTypes != null) { identityTypes.remove(identityType.getId()); } this.fileDataSource.flushAttributedTypes(filePartition); } else if (Relationship.class.isInstance(attributedType)) { Map<String, FileRelationship> fileRelationships = this.fileDataSource.getRelationships() .get(attributedType.getClass().getName()); for (FileRelationship fileRelationship : new HashMap<String, FileRelationship>(fileRelationships).values()) { if (fileRelationship.getId().equals(attributedType.getId())) { fileRelationships.remove(fileRelationship.getId()); } } this.fileDataSource.flushRelationships(); } else { this.fileDataSource.getAttributedTypes().remove(attributedType.getId()); this.fileDataSource.flushAttributedTypes(); } } @Override public String getConfigurationName(IdentityContext identityContext, Partition partition) { FilePartition filePartition = resolve(partition.getClass(), partition.getName()); if (isNullOrEmpty(filePartition.getConfigurationName())) { throw MESSAGES.partitionWithNoConfigurationName(partition); } return filePartition.getConfigurationName(); } @Override public <P extends Partition> P get(IdentityContext identityContext, Class<P> partitionClass, String name) { try { return (P) cloneAttributedType(identityContext, (P) resolve(partitionClass, name).getEntry()); } catch (IdentityManagementException ime) { //just ignore if not found. } return null; } @Override public <P extends Partition> List<P> get(IdentityContext identityContext, Class<P> partitionClass) { List<P> result = new ArrayList<P>(); for (FilePartition filePartition : this.fileDataSource.getPartitions().values()) { Partition partition = filePartition.getEntry(); if (Partition.class.equals(partitionClass) || partitionClass.equals(partition.getClass())) { result.add((P) cloneAttributedType(identityContext, partition)); } } return result; } @Override public <P extends Partition> P lookupById(final IdentityContext context, final Class<P> partitionClass, final String id) { FilePartition filePartition = this.fileDataSource.getPartitions().get(id); if (filePartition != null && partitionClass.isInstance(filePartition.getEntry())) { return (P) cloneAttributedType(context, filePartition.getEntry()); } return null; } @Override public void add(IdentityContext identityContext, Partition partition, String configurationName) { partition.setId(identityContext.getIdGenerator().generate()); FilePartition filePartition = new FilePartition(cloneAttributedType(identityContext, partition), configurationName); this.fileDataSource.getPartitions().put(filePartition.getId(), filePartition); this.fileDataSource.flushPartitions(filePartition); } @Override public void update(IdentityContext identityContext, Partition partition) { FilePartition filePartition = resolve(partition.getClass(), partition.getName()); this.fileDataSource.getPartitions().put(partition.getId(), new FilePartition(cloneAttributedType(identityContext, partition), filePartition.getConfigurationName())); this.fileDataSource.flushPartitions(); } @Override public void remove(IdentityContext identityContext, Partition partition) { FilePartition filePartition = resolve(partition.getClass(), partition.getName()); this.fileDataSource.getPartitions().remove(filePartition.getId()); this.fileDataSource.flushPartitions(); } @Override public void storeCredential(IdentityContext context, Account account, CredentialStorage storage) { List<FileCredentialStorage> credentials = getCredentials(account, storage.getClass()); credentials.add(new FileCredentialStorage(storage)); flushCredentials(context.getPartition()); } @Override public <T extends CredentialStorage> T retrieveCurrentCredential(IdentityContext context, Account account, Class<T> storageClass) { return getCurrentCredential(context, account, this, storageClass); } @Override public <T extends CredentialStorage> List<T> retrieveCredentials(IdentityContext context, Account account, Class<T> storageClass) { List<T> storedCredentials = new ArrayList<T>(); List<FileCredentialStorage> credentials = getCredentials(account, storageClass); for (FileCredentialStorage fileCredentialStorage : credentials) { storedCredentials.add((T) fileCredentialStorage.getEntry()); } Collections.sort(storedCredentials, new Comparator<T>() { @Override public int compare(final T o1, final T o2) { return o2.getEffectiveDate().compareTo(o1.getEffectiveDate()); } }); return storedCredentials; } @Override public void removeCredential(IdentityContext context, Account account, Class<? extends CredentialStorage> storageClass) { List<FileCredentialStorage> credentials = getCredentials(account, storageClass); if (credentials != null) { credentials.clear(); } flushCredentials(context.getPartition()); } @Override public <V extends IdentityType> List<V> fetchQueryResults(IdentityContext context, IdentityQuery<V> identityQuery) { Partition partition = null; for (Condition condition : identityQuery.getConditions()) { if (IdentityType.PARTITION.equals(condition.getParameter())) { if (!EqualCondition.class.isInstance(condition)) { throw new IdentityManagementException("Only equality conditions are allowed when queryng based on a partition."); } EqualCondition equalCondition = (EqualCondition) condition; partition = (Partition) equalCondition.getValue(); } } if (partition == null) { partition = context.getPartition(); } FilePartition filePartition = resolve(partition.getClass(), partition.getName()); List<V> result = new ArrayList<V>(); Map<String, Map<String, FileIdentityType>> identityTypes = filePartition.getIdentityTypes(); Map<String, FileIdentityType> typedIdentityTypes = null; if (IdentityType.class.equals(identityQuery.getIdentityType())) { typedIdentityTypes = new HashMap<String, FileIdentityType>(); for (String type : identityTypes.keySet()) { typedIdentityTypes.putAll(identityTypes.get(type)); } } else { typedIdentityTypes = identityTypes.get(identityQuery.getIdentityType().getName()); } if (typedIdentityTypes == null) { return result; } for (FileIdentityType storedIdentityType : typedIdentityTypes.values()) { IdentityType storedEntry = storedIdentityType.getEntry(); boolean match = identityQuery.getConditions().isEmpty(); for (Condition condition : identityQuery.getConditions()) { QueryParameter queryParameter = condition.getParameter(); if (IdentityType.ID.equals(queryParameter)) { if (!EqualCondition.class.isInstance(condition)) { throw new IdentityManagementException("Only equality conditions are allowed when queryng based on the identifier."); } EqualCondition equalCondition = (EqualCondition) condition; Object value = equalCondition.getValue(); if (value != null) { FileIdentityType fileAttributedType = typedIdentityTypes.get(value); if (fileAttributedType != null) { result.add(cloneAttributedType(context, (V) fileAttributedType.getEntry())); } } return result; } if (AttributeParameter.class.isInstance(queryParameter)) { AttributeParameter attributeParameter = (AttributeParameter) queryParameter; String attributeParameterName = attributeParameter.getName(); Property<Serializable> property = PropertyQueries.<Serializable>createQuery(identityQuery.getIdentityType()) .addCriteria(new NamedPropertyCriteria(attributeParameterName)) .getFirstResult(); if (property != null && property.getName().equals(attributeParameterName)) { Serializable storedValue = property.getValue(storedEntry); match = matches(condition, storedValue); } else { loadAttributes(context, storedEntry); Attribute<Serializable> attribute = storedEntry.getAttribute(attributeParameterName); match = attribute != null ? matches(condition, attribute.getValue()) : false; } if (!match) { break; } } } if (match) { result.add((V) cloneAttributedType(context, storedEntry)); } } // Apply sorting Collections.sort(result, new FileSortingComparator<V>(identityQuery)); // Apply pagination if (identityQuery.getLimit() > 0) { int numberOfItems = Math.min(identityQuery.getLimit(), result.size() - identityQuery.getOffset()); result = result.subList(identityQuery.getOffset(), identityQuery.getOffset() + numberOfItems); } return result; } private <V extends IdentityType> boolean matches(Condition condition, Serializable storedValue) { boolean match = false; if (storedValue != null) { if (EqualCondition.class.isInstance(condition)) { EqualCondition equalCondition = (EqualCondition) condition; match = storedValue != null && storedValue.equals(equalCondition.getValue()); } else if (LikeCondition.class.isInstance(condition)) { LikeCondition likeCondition = (LikeCondition) condition; String parameterValue = (String) likeCondition.getValue(); if (parameterValue.startsWith("%") && parameterValue.endsWith("%")) { String pattern = parameterValue.toLowerCase(); pattern = pattern.replace(".", "\\."); pattern = pattern.replace("%", ".*"); pattern = pattern.replace("?", "."); match = storedValue.toString().toLowerCase().matches(pattern); } } else if (GreaterThanCondition.class.isInstance(condition)) { GreaterThanCondition greaterThanCondition = (GreaterThanCondition) condition; Comparable parameterValue = (Comparable) greaterThanCondition.getValue(); if (greaterThanCondition.isOrEqual()) { match = parameterValue.compareTo(storedValue) <= 0; } else { match = parameterValue.compareTo(storedValue) < 0; } } else if (LessThanCondition.class.isInstance(condition)) { LessThanCondition lessThanCondition = (LessThanCondition) condition; Comparable parameterValue = (Comparable) lessThanCondition.getValue(); if (lessThanCondition.isOrEqual()) { match = parameterValue.compareTo(storedValue) >= 0; } else { match = parameterValue.compareTo(storedValue) > 0; } } else if (BetweenCondition.class.isInstance(condition)) { BetweenCondition betweenCondition = (BetweenCondition) condition; Comparable x = betweenCondition.getX(); Comparable y = betweenCondition.getY(); match = x.compareTo(storedValue) <= 0 && y.compareTo(storedValue) >= 0; } else if (InCondition.class.isInstance(condition)) { InCondition inCondition = (InCondition) condition; Object[] valuesToCompare = inCondition.getValue(); int count = valuesToCompare.length; for (Object value : valuesToCompare) { if (storedValue.getClass().isArray()) { Object[] userValues = (Object[]) storedValue; for (Object object : userValues) { if (object.equals(value)) { count--; } } } else { if (value.equals(storedValue)) { count--; } } } match = count <= 0; } else { throw new IdentityManagementException("Unsupported query condition [" + condition + "]."); } } return match; } @Override public <T extends Relationship> List<T> fetchQueryResults(IdentityContext context, RelationshipQuery<T> query) { List<T> result = new ArrayList<T>(); Class<T> typeToSearch = query.getRelationshipClass(); Object[] idParameter = query.getParameter(Relationship.ID); if (idParameter != null && idParameter.length > 0) { String id = idParameter[0].toString(); for (Map<String, FileRelationship> partitionRelationships : this.fileDataSource.getRelationships().values()) { FileRelationship storedRelationship = partitionRelationships.get(id); if (storedRelationship != null && typeToSearch.isAssignableFrom(storedRelationship.getEntry().getClass())) { result.add((T) cloneAttributedType(context, storedRelationship.getEntry())); return result; } } } else { List<FileRelationship> relationships = new ArrayList<FileRelationship>(); if (Relationship.class.equals(typeToSearch)) { for (Map<String, FileRelationship> partitionRelationships : this.fileDataSource.getRelationships().values()) { relationships.addAll(partitionRelationships.values()); } } else { Map<String, FileRelationship> typedRelationship = this.fileDataSource.getRelationships().get( typeToSearch.getName()); if (typedRelationship != null) { relationships.addAll(typedRelationship.values()); } } for (FileRelationship storedRelationship : relationships) { boolean match = query.getParameters().isEmpty(); if (typeToSearch.isInstance(storedRelationship.getEntry())) { for (Entry<QueryParameter, Object[]> entry : query.getParameters().entrySet()) { QueryParameter queryParameter = entry.getKey(); Object[] values = entry.getValue(); if (Relationship.IDENTITY.equals(queryParameter)) { int valuesMathCount = values.length; for (Object object : values) { IdentityType identityType = (IdentityType) object; if (storedRelationship.hasIdentityType(identityType)) { valuesMathCount--; } } match = valuesMathCount <= 0; } else if (queryParameter instanceof RelationshipQueryParameter) { RelationshipQueryParameter identityTypeParameter = (RelationshipQueryParameter) queryParameter; for (Object value : values) { IdentityType identityType = (IdentityType) value; String identityTypeId = storedRelationship.getIdentityTypeId(identityTypeParameter.getName()); match = identityTypeId != null && identityTypeId.equals(IdentityTypeUtil.formatId(identityType)); } } else if (AttributeParameter.class.isInstance(queryParameter) && values != null) { AttributeParameter attributeParameter = (AttributeParameter) queryParameter; Property<Serializable> property = PropertyQueries .<Serializable>createQuery(query.getRelationshipClass()) .addCriteria(new NamedPropertyCriteria(attributeParameter.getName())) .getFirstResult(); if (property != null) { Serializable value = property.getValue(storedRelationship.getEntry()); if (value != null) { match = value.equals(values[0]); } } else { loadAttributes(context, storedRelationship.getEntry()); match = matchAttribute(storedRelationship.getEntry(), attributeParameter.getName(), values); } } if (!match) { break; } } } if (match) { T relationship = (T) cloneAttributedType(context, storedRelationship.getEntry()); List<Property<IdentityType>> properties = PropertyQueries.<IdentityType>createQuery(query .getRelationshipClass()) .addCriteria(new TypedPropertyCriteria(IdentityType.class, MatchOption.SUB_TYPE)) .getResultList(); RelationshipReference reference = new RelationshipReference(relationship); for (Property<IdentityType> property : properties) { reference.addIdentityTypeReference(property.getName(), storedRelationship.getIdentityTypeId (property.getName())); } result.add((T) reference); } } } return result; } @Override public void doSetAttribute(IdentityContext context, AttributedType type, Attribute<? extends Serializable> attribute) { FileAttribute fileAttribute = getFileAttribute(type); if (fileAttribute == null) { fileAttribute = new FileAttribute(type); } removeAttribute(context, type, attribute.getName()); fileAttribute.getEntry().add(attribute); this.fileDataSource.getAttributes().put(type.getId(), fileAttribute); this.fileDataSource.flushAttributes(); } @Override public void removeAttribute(IdentityContext context, AttributedType type, String attributeName) { FileAttribute fileAttribute = getFileAttribute(type); if (fileAttribute != null) { for (Attribute<? extends Serializable> attribute : new ArrayList<Attribute<? extends Serializable>> (fileAttribute.getEntry())) { if (attribute.getName().equals(attributeName)) { fileAttribute.getEntry().remove(attribute); } } } this.fileDataSource.flushAttributes(); } @Override protected Collection<Attribute<? extends Serializable>> getAttributes(IdentityContext context, AttributedType attributedType) { Collection<Attribute<? extends Serializable>> attributes = new HashSet<Attribute<? extends Serializable>>(); FileAttribute fileAttribute = getFileAttribute(attributedType); if (fileAttribute != null) { for (Attribute<? extends Serializable> attribute : fileAttribute.getEntry()) { attributes.add(attribute); } } return attributes; } private FileAttribute getFileAttribute(final AttributedType type) { return this.fileDataSource.getAttributes().get(type.getId()); } private FilePartition resolve(Class<? extends Partition> type, String name) throws IdentityManagementException { for (FilePartition filePartition : this.fileDataSource.getPartitions().values()) { Partition storedPartition = filePartition.getEntry(); if (storedPartition.getClass().equals(type) && storedPartition.getName().equals(name)) { return filePartition; } } throw MESSAGES.partitionNotFoundWithName(type, name); } private <T extends AttributedType> T cloneAttributedType(IdentityContext context, T attributedType) { T clonedAttributedType = null; try { clonedAttributedType = (T) newInstance(attributedType.getClass()); } catch (Exception e) { throw MESSAGES.instantiationError(attributedType.getClass(), e); } clonedAttributedType.setId(attributedType.getId()); PropertyQuery<Serializable> query = PropertyQueries.createQuery(attributedType.getClass()); query.addCriteria(new AnnotatedPropertyCriteria(AttributeProperty.class)); for (Property<Serializable> property : query.getResultList()) { property.setValue(clonedAttributedType, property.getValue(attributedType)); } if (IdentityType.class.isInstance(attributedType)) { IdentityType identityType = (IdentityType) attributedType; identityType.setPartition(context.getPartition()); IdentityType clonedIdentityType = (IdentityType) clonedAttributedType; clonedIdentityType.setPartition(identityType.getPartition()); clonedIdentityType.setExpirationDate(identityType.getExpirationDate()); clonedIdentityType.setCreatedDate(identityType.getCreatedDate()); clonedIdentityType.setEnabled(identityType.isEnabled()); } else if (Relationship.class.isInstance(attributedType)) { Relationship relationship = (Relationship) attributedType; Relationship clonedRelationship = (Relationship) clonedAttributedType; PropertyQuery<Serializable> identityPropertiesQuery = PropertyQueries.createQuery(relationship.getClass()); identityPropertiesQuery.addCriteria(new TypedPropertyCriteria(IdentityType.class, MatchOption.SUB_TYPE)); for (Property<Serializable> property : identityPropertiesQuery.getResultList()) { property.setValue(clonedRelationship, property.getValue(relationship)); } } return clonedAttributedType; } private List<FileCredentialStorage> getCredentials(Account account, Class<? extends CredentialStorage> storageType) { Partition partition = account.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); Map<String, List<FileCredentialStorage>> agentCredentials = filePartition.getCredentials().get(account.getId()); if (agentCredentials == null) { agentCredentials = new ConcurrentHashMap<String, List<FileCredentialStorage>>(); this.fileDataSource.getPartitions().get(partition.getId()).getCredentials().put(account.getId(), agentCredentials); } List<FileCredentialStorage> credentials = agentCredentials.get(storageType.getName()); if (credentials == null) { credentials = Collections.synchronizedList(new ArrayList<FileCredentialStorage>()); } agentCredentials.put(storageType.getName(), credentials); return credentials; } private void storeRelationshipType(Relationship relationship) { String type = relationship.getClass().getName(); Map<String, FileRelationship> storedRelationships = this.fileDataSource.getRelationships().get(type); if (storedRelationships == null) { storedRelationships = new ConcurrentHashMap<String, FileRelationship>(); this.fileDataSource.getRelationships().put(type, storedRelationships); } storedRelationships.put(relationship.getId(), new FileRelationship(relationship)); this.fileDataSource.flushRelationships(); } private void storeIdentityType(IdentityContext context, IdentityType identityType) { FilePartition filePartition = resolve(context.getPartition().getClass(), context.getPartition().getName()); Map<String, FileIdentityType> identityTypes = filePartition.getIdentityTypes().get(identityType.getClass().getName()); if (identityTypes == null) { identityTypes = new ConcurrentHashMap<String, FileIdentityType>(); filePartition.getIdentityTypes().put(identityType.getClass().getName(), identityTypes); } identityTypes.put(identityType.getId(), new FileIdentityType(identityType)); this.fileDataSource.flushAttributedTypes(filePartition); } private boolean matchAttribute(AttributedType attributedType, String parameterName, Object[] valuesToCompare) { Attribute<Serializable> userAttribute = attributedType.getAttribute(parameterName); Serializable userAttributeValue = null; if (userAttribute != null) { userAttributeValue = userAttribute.getValue(); } if (userAttributeValue != null) { int count = valuesToCompare.length; for (Object value : valuesToCompare) { if (userAttributeValue.getClass().isArray()) { Object[] userValues = (Object[]) userAttributeValue; for (Object object : userValues) { if (object.equals(value)) { count--; } } } else { if (value.equals(userAttributeValue)) { count--; } } } return count <= 0; } return false; } private void flushCredentials(Partition partition) { this.fileDataSource.flushCredentials(resolve(partition.getClass(), partition.getName())); } @Override public List<Permission> listPermissions(IdentityContext context, Object resource) { return listPermissions(context, new IdentityPermission(resource, null, null)); } @Override public List<Permission> listPermissions(IdentityContext context, IdentityType identityType) { return listPermissions(context, new IdentityPermission(null, identityType, null)); } @Override public List<Permission> listPermissions(IdentityContext context, Object resource, String operation) { return listPermissions(context, new IdentityPermission(resource, null, operation)); } @Override public List<Permission> listPermissions(IdentityContext context, Set<Object> resources, String operation) { List<Permission> permissions = new ArrayList<Permission>(); for (Object resource : resources) { permissions.addAll(listPermissions(context, resource, operation)); } return permissions; } @Override public List<Permission> listPermissions(IdentityContext context, Class<?> resourceClass, Serializable identifier) { return listPermissions(context, resourceClass, identifier, null); } @Override public List<Permission> listPermissions(IdentityContext context, Class<?> resourceClass, Serializable identifier, String operation) { return listPermissions(context, new IdentityPermission(resourceClass, identifier, null, operation)); } @Override public boolean grantPermission(IdentityContext context, IdentityType assignee, Object resource, String operation) { Partition partition = assignee.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); Class resourceClass = context.getPermissionHandlerPolicy().getResourceClass(resource); Serializable resourceIdentifier = context.getPermissionHandlerPolicy().getIdentifier(resource); List<Permission> existingPermissions = listPermissions(context, new IdentityPermission(resource, assignee, null)); if (existingPermissions.isEmpty()) { List<FilePermission> permissions = filePartition.getPermissions().get(assignee.getId()); if (permissions == null) { permissions = new ArrayList<FilePermission>(); filePartition.getPermissions().put(assignee.getId(), permissions); } FilePermission filePermission = new FilePermission(assignee, new IdentityPermission(resourceClass, resourceIdentifier .toString(), assignee, operation)); permissions.add(filePermission); } else { Permission permission = existingPermissions.get(0); revokePermission(context, assignee, resource, null); String newOperations = PermissionUtil.addOperation(permission.getOperation(), operation); grantPermission(context, assignee, resource, newOperations); } this.fileDataSource.flushPermissions(filePartition); return true; } @Override public boolean revokePermission(IdentityContext context, IdentityType assignee, Object resource, String operation) { Partition partition = assignee.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); List<FilePermission> permissions = filePartition.getPermissions().get(assignee.getId()); Class resourceClass = context.getPermissionHandlerPolicy().getResourceClass(resource); Serializable resourceIdentifier = context.getPermissionHandlerPolicy().getIdentifier(resource); if (permissions != null) { for (FilePermission filePermission : new ArrayList<FilePermission>(permissions)) { Permission permission = filePermission.getEntry(); if (hasAttributes(permission, resourceClass, resourceIdentifier, operation)) { String newOperations = PermissionUtil.removeOperation(permission.getOperation(), operation); permissions.remove(filePermission); if (operation != null && !isNullOrEmpty(newOperations)) { grantPermission(context, assignee, resource, newOperations); } } } } return false; } @Override public void revokeAllPermissions(IdentityContext context, Object resource) { Partition partition = context.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); Collection<List<FilePermission>> allPermissions = filePartition.getPermissions().values(); Class resourceClass = context.getPermissionHandlerPolicy().getResourceClass(resource); Serializable resourceIdentifier = context.getPermissionHandlerPolicy().getIdentifier(resource); if (allPermissions != null) { for (List<FilePermission> permissions : allPermissions) { for (FilePermission filePermission : new ArrayList<FilePermission>(permissions)) { Permission permission = filePermission.getEntry(); if (hasAttributes(permission, resourceClass, resourceIdentifier, null)) { permissions.remove(filePermission); } } } this.fileDataSource.flushPermissions(filePartition); } } private List<Permission> listPermissions(IdentityContext context, IdentityPermission query) { Partition partition = context.getPartition(); FilePartition filePartition = resolve(partition.getClass(), partition.getName()); List<Permission> permissions = new ArrayList<Permission>(); Collection<List<FilePermission>> storedPermissions = filePartition.getPermissions().values(); IdentityType identityType = query.getAssignee(); if (identityType != null) { storedPermissions = new ArrayList<List<FilePermission>>(); List<FilePermission> identityTypePermissions = filePartition.getPermissions().get(identityType.getId()); if (identityTypePermissions != null) { storedPermissions.add(identityTypePermissions); } } for (List<FilePermission> filePermissions : storedPermissions) { for (FilePermission filePermission : filePermissions) { IdentityType referencedIdentityType = lookupIdentityById(context, filePermission.getIdentityTypeId(), context .getPartition()); boolean match = false; if (identityType != null && filePermission.getIdentityTypeId().equals(referencedIdentityType.getId())) { match = true; } Class<?> resourceClass = query.getResourceClass(); Serializable resourceIdentifier = query.getResourceIdentifier(); String operation = query.getOperation(); Permission permission = filePermission.getEntry(); Object resource = query.getResource(); if (resource != null) { resourceClass = context.getPermissionHandlerPolicy().getResourceClass(resource); resourceIdentifier = context.getPermissionHandlerPolicy().getIdentifier(resource); } if (resourceClass != null && resourceIdentifier != null) { match = hasAttributes(permission, resourceClass, resourceIdentifier, operation); } if (match) { Set<String> operationsToreturn; if (operation != null) { operationsToreturn = asOperationList(operation); } else { operationsToreturn = asOperationList(permission.getOperation()); } for (String op : operationsToreturn) { if (resource != null) { permissions.add(new IdentityPermission(resource, referencedIdentityType, op)); } else { permissions.add(new IdentityPermission(permission.getResourceClass(), permission.getResourceIdentifier(), referencedIdentityType, op)); } } } } } return permissions; } private IdentityType lookupIdentityById(IdentityContext context, String id, Partition partition) { FilePartition filePartition = resolve(partition.getClass(), partition.getName()); Map<String, Map<String, FileIdentityType>> identityTypes = filePartition.getIdentityTypes(); Map<String, FileIdentityType> typedIdentityTypes = new HashMap<String, FileIdentityType>(); for (String type : identityTypes.keySet()) { typedIdentityTypes.putAll(identityTypes.get(type)); } if (id != null) { FileIdentityType fileAttributedType = typedIdentityTypes.get(id); if (fileAttributedType != null) { return cloneAttributedType(context, fileAttributedType.getEntry()); } } return null; } }