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.core.api.criteria.CriteriaLookupService; 020import org.kuali.rice.core.api.criteria.QueryByCriteria; 021import org.kuali.rice.core.api.uif.RemotableAttributeError; 022import org.kuali.rice.coreservice.impl.namespace.NamespaceBo; 023import org.kuali.rice.kim.api.KimConstants; 024import org.kuali.rice.kim.api.permission.Permission; 025import org.kuali.rice.kim.api.type.KimType; 026import org.kuali.rice.kim.impl.permission.PermissionBo; 027import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 028 029import java.util.ArrayList; 030import java.util.Collections; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 034 035import static org.kuali.rice.core.api.criteria.PredicateFactory.like; 036 037/** 038 * @author Kuali Rice Team (rice.collab@kuali.org) 039 */ 040public class NamespaceWildcardAllowedAndOrStringExactMatchPermissionTypeServiceImpl 041 extends NamespacePermissionTypeServiceImpl { 042 protected static final String NAMESPACE_CODE = KimConstants.UniqueKeyConstants.NAMESPACE_CODE; 043 044 protected String exactMatchStringAttributeName; 045 protected boolean namespaceRequiredOnStoredMap; 046 private List<String> requiredAttributes = new ArrayList<String>(); 047 048 private CriteriaLookupService criteriaLookupService; 049 050 @Override 051 protected List<String> getRequiredAttributes() { 052 return Collections.unmodifiableList(requiredAttributes); 053 } 054 055 @Override 056 protected List<Permission> performPermissionMatches(Map<String, String> requestedDetails, List<Permission> permissionsList) { 057 List<Permission> matchingPermissions = new ArrayList<Permission>(); 058 List<Permission> matchingBlankPermissions = new ArrayList<Permission>(); 059 String requestedAttributeValue = requestedDetails.get(exactMatchStringAttributeName); 060 for ( Permission kpi : permissionsList ) { 061 PermissionBo bo = PermissionBo.from(kpi); 062 String permissionAttributeValue = bo.getDetails().get(exactMatchStringAttributeName); 063 if ( StringUtils.equals(requestedAttributeValue, permissionAttributeValue) ) { 064 matchingPermissions.add(kpi); 065 } else if ( StringUtils.isBlank(permissionAttributeValue) ) { 066 matchingBlankPermissions.add(kpi); 067 } 068 } 069 // if the exact match worked, use those when checking the namespace 070 // otherwise, use those with a blank additional property value 071 if ( !matchingPermissions.isEmpty() ) { 072 List<Permission> matchingWithNamespace = super.performPermissionMatches(requestedDetails, matchingPermissions); 073 if ( !namespaceRequiredOnStoredMap ) { 074 // if the namespace is not required and the namespace match would have excluded 075 // the results, return the original set of matches 076 if ( matchingWithNamespace.isEmpty() ) { 077 return matchingPermissions; 078 } 079 } 080 return matchingWithNamespace; 081 } else if ( !matchingBlankPermissions.isEmpty() ) { 082 List<Permission> matchingWithNamespace = super.performPermissionMatches(requestedDetails, matchingBlankPermissions); 083 if ( !namespaceRequiredOnStoredMap ) { 084 // if the namespace is not required and the namespace match would have excluded 085 // the results, return the original set of matches 086 if ( matchingWithNamespace.isEmpty() ) { 087 return matchingBlankPermissions; 088 } 089 } 090 return matchingWithNamespace; 091 } 092 return matchingPermissions; // will be empty if drops to here 093 } 094 095 public void setExactMatchStringAttributeName( 096 String exactMatchStringAttributeName) { 097 this.exactMatchStringAttributeName = exactMatchStringAttributeName; 098 requiredAttributes.add(exactMatchStringAttributeName); 099 } 100 101 public void setNamespaceRequiredOnStoredMap( 102 boolean namespaceRequiredOnStoredMap) { 103 this.namespaceRequiredOnStoredMap = namespaceRequiredOnStoredMap; 104 } 105 106 /** 107 * Overrides the superclass's version of this method in order to account for "namespaceCode" permission detail values containing wildcards. 108 */ 109 @Override 110 protected List<RemotableAttributeError> validateReferencesExistAndActive(KimType kimType, Map<String, String> attributes, List<RemotableAttributeError> previousValidationErrors) { 111 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>(); 112 Map<String, String> nonNamespaceCodeAttributes = new HashMap<String, String>(attributes); 113 114 // Check if "namespaceCode" is one of the permission detail values. 115 if (attributes.containsKey(NAMESPACE_CODE)) { 116 nonNamespaceCodeAttributes.remove(NAMESPACE_CODE); 117 118 String namespaceCode = attributes.get(NAMESPACE_CODE); 119 120 QueryByCriteria criteria = QueryByCriteria.Builder.fromPredicates(like("code", namespaceCode)); 121 List<NamespaceBo> namespaces = getCriteriaLookupService().lookup(NamespaceBo.class, criteria).getResults(); 122 123 if (!namespaces.isEmpty()) { 124 // If namespaces were found, let the superclass generate any appropriate errors 125 for (NamespaceBo namespace : namespaces) { 126 errors.addAll(super.validateReferencesExistAndActive(kimType, 127 Collections.singletonMap(NAMESPACE_CODE, namespace.getCode()), previousValidationErrors)); 128 } 129 } else { 130 // If no namespaces were found, let the superclass generate an appropriate error. 131 errors.addAll(super.validateReferencesExistAndActive(kimType, 132 Collections.singletonMap(NAMESPACE_CODE, namespaceCode), previousValidationErrors)); 133 } 134 } 135 136 // Validate all non-namespaceCode attributes. 137 errors.addAll(super.validateReferencesExistAndActive(kimType, nonNamespaceCodeAttributes, previousValidationErrors)); 138 139 return errors; 140 } 141 142 public CriteriaLookupService getCriteriaLookupService() { 143 if (criteriaLookupService == null) { 144 criteriaLookupService = KRADServiceLocatorWeb.getService("criteriaLookupService"); 145 } 146 147 return criteriaLookupService; 148 } 149 150 public void setCriteriaLookupService(CriteriaLookupService criteriaLookupService) { 151 this.criteriaLookupService = criteriaLookupService; 152 } 153}