001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.kim; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator; 020import org.kuali.rice.coreservice.api.namespace.Namespace; 021import org.kuali.rice.core.api.uif.RemotableAttributeError; 022import org.kuali.rice.kim.api.KimConstants; 023import org.kuali.rice.kim.api.permission.Permission; 024import org.kuali.rice.kim.api.type.KimType; 025import org.kuali.rice.kim.impl.permission.PermissionBo; 026import org.kuali.rice.krad.kim.NamespacePermissionTypeServiceImpl; 027 028import java.util.ArrayList; 029import java.util.Collections; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Map; 033 034/** 035 * @author Kuali Rice Team (rice.collab@kuali.org) 036 */ 037public class NamespaceWildcardAllowedAndOrStringExactMatchPermissionTypeServiceImpl 038 extends NamespacePermissionTypeServiceImpl { 039 protected static final String NAMESPACE_CODE = KimConstants.UniqueKeyConstants.NAMESPACE_CODE; 040 041 protected String exactMatchStringAttributeName; 042 protected boolean namespaceRequiredOnStoredMap; 043 private List<String> requiredAttributes = new ArrayList<String>(); 044 045 @Override 046 protected List<String> getRequiredAttributes() { 047 return Collections.unmodifiableList(requiredAttributes); 048 } 049 050 @Override 051 protected List<Permission> performPermissionMatches(Map<String, String> requestedDetails, List<Permission> permissionsList) { 052 List<Permission> matchingPermissions = new ArrayList<Permission>(); 053 List<Permission> matchingBlankPermissions = new ArrayList<Permission>(); 054 String requestedAttributeValue = requestedDetails.get(exactMatchStringAttributeName); 055 for ( Permission kpi : permissionsList ) { 056 PermissionBo bo = PermissionBo.from(kpi); 057 String permissionAttributeValue = bo.getDetails().get(exactMatchStringAttributeName); 058 if ( StringUtils.equals(requestedAttributeValue, permissionAttributeValue) ) { 059 matchingPermissions.add(kpi); 060 } else if ( StringUtils.isBlank(permissionAttributeValue) ) { 061 matchingBlankPermissions.add(kpi); 062 } 063 } 064 // if the exact match worked, use those when checking the namespace 065 // otherwise, use those with a blank additional property value 066 if ( !matchingPermissions.isEmpty() ) { 067 List<Permission> matchingWithNamespace = super.performPermissionMatches(requestedDetails, matchingPermissions); 068 if ( !namespaceRequiredOnStoredMap ) { 069 // if the namespace is not required and the namespace match would have excluded 070 // the results, return the original set of matches 071 if ( matchingWithNamespace.isEmpty() ) { 072 return matchingPermissions; 073 } 074 } 075 return matchingWithNamespace; 076 } else if ( !matchingBlankPermissions.isEmpty() ) { 077 List<Permission> matchingWithNamespace = super.performPermissionMatches(requestedDetails, matchingBlankPermissions); 078 if ( !namespaceRequiredOnStoredMap ) { 079 // if the namespace is not required and the namespace match would have excluded 080 // the results, return the original set of matches 081 if ( matchingWithNamespace.isEmpty() ) { 082 return matchingBlankPermissions; 083 } 084 } 085 return matchingWithNamespace; 086 } 087 return matchingPermissions; // will be empty if drops to here 088 } 089 090 public void setExactMatchStringAttributeName( 091 String exactMatchStringAttributeName) { 092 this.exactMatchStringAttributeName = exactMatchStringAttributeName; 093 requiredAttributes.add(exactMatchStringAttributeName); 094 } 095 096 public void setNamespaceRequiredOnStoredMap( 097 boolean namespaceRequiredOnStoredMap) { 098 this.namespaceRequiredOnStoredMap = namespaceRequiredOnStoredMap; 099 } 100 101 /** 102 * Overrides the superclass's version of this method in order to account for "namespaceCode" permission detail values containing wildcards. 103 */ 104 @Override 105 protected List<RemotableAttributeError> validateReferencesExistAndActive(KimType kimType, Map<String, String> attributes, List<RemotableAttributeError> previousValidationErrors) { 106 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>(); 107 Map<String, String> nonNamespaceCodeAttributes = new HashMap<String, String>(attributes); 108 // Check if "namespaceCode" is one of the permission detail values. 109 if (attributes.containsKey(NAMESPACE_CODE)) { 110 nonNamespaceCodeAttributes.remove(NAMESPACE_CODE); 111 112 final Namespace namespace = 113 StringUtils.isBlank(attributes.get(NAMESPACE_CODE)) ? 114 null : CoreServiceApiServiceLocator.getNamespaceService().getNamespace(attributes.get(NAMESPACE_CODE)); 115 116 if (namespace != null) { 117 errors.addAll(super.validateReferencesExistAndActive(kimType, Collections.singletonMap(NAMESPACE_CODE, 118 namespace.getCode()), previousValidationErrors)); 119 } else { 120 // If no namespaces were found, let the superclass generate an appropriate error. 121 errors.addAll(super.validateReferencesExistAndActive(kimType, Collections.singletonMap(NAMESPACE_CODE, 122 attributes.get(NAMESPACE_CODE)), previousValidationErrors)); 123 } 124 } 125 // Validate all non-namespaceCode attributes. 126 errors.addAll(super.validateReferencesExistAndActive(kimType, nonNamespaceCodeAttributes, previousValidationErrors)); 127 return errors; 128 } 129}