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.kim.document.rule; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 020import org.kuali.rice.core.api.uif.RemotableAttributeError; 021import org.kuali.rice.core.api.util.RiceKeyConstants; 022import org.kuali.rice.kim.api.common.template.Template; 023import org.kuali.rice.kim.api.permission.Permission; 024import org.kuali.rice.kim.api.services.KimApiServiceLocator; 025import org.kuali.rice.kim.api.type.KimType; 026import org.kuali.rice.kim.impl.permission.GenericPermissionBo; 027import org.kuali.rice.kim.impl.permission.PermissionBo; 028import org.kuali.rice.kim.impl.permission.PermissionTemplateBo; 029import org.kuali.rice.kim.framework.permission.PermissionTypeService; 030import org.kuali.rice.kim.service.KIMServiceLocatorInternal; 031import org.kuali.rice.kns.document.MaintenanceDocument; 032import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 033import org.kuali.rice.krad.util.GlobalVariables; 034import org.apache.commons.lang.StringUtils; 035 036import javax.xml.namespace.QName; 037import java.util.List; 038import java.util.Map; 039import java.util.regex.Matcher; 040import java.util.regex.Pattern; 041 042/** 043 * This is a description of what this class does - kellerj don't forget to fill this in. 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 * 047 */ 048public class GenericPermissionMaintenanceDocumentRule extends MaintenanceDocumentRuleBase { 049 protected static final String DETAIL_VALUES_PROPERTY = "detailValues"; 050 protected static final String NAMESPACE_CODE_PROPERTY = "namespaceCode"; 051 protected static final String ERROR_MESSAGE_PREFIX = "error.document.kim.genericpermission."; 052 protected static final String ERROR_MISSING_TEMPLATE = ERROR_MESSAGE_PREFIX + "missingtemplate"; 053 protected static final String ERROR_UNKNOWN_ATTRIBUTE = ERROR_MESSAGE_PREFIX + "unknownattribute"; 054 protected static final String ERROR_ATTRIBUTE_VALIDATION = ERROR_MESSAGE_PREFIX + "attributevalidation"; 055 protected static final String ERROR_NAMESPACE_AND_NAME_VALIDATION = ERROR_MESSAGE_PREFIX + "namespaceandnamevalidation"; 056 057 058 @Override 059 protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { 060 boolean rulesPassed = super.processCustomRouteDocumentBusinessRules( document ); 061 try { 062 GenericPermissionBo perm = (GenericPermissionBo)getNewBo(); 063 GenericPermissionBo orgBo = (GenericPermissionBo)getOldBo(); 064 rulesPassed &= validateDetailValuesFormat(perm.getDetailValues()); 065 if(StringUtils.isNotBlank(perm.getNamespaceCode()) && StringUtils.isNotBlank(perm.getName()) && StringUtils.isBlank(perm.getId())){ 066 rulesPassed &= validateNamespaceCodeAndName(perm.getNamespaceCode(), perm.getName()); 067 } 068 // rule case for copy 069 if(StringUtils.isNotBlank(perm.getNamespaceCode()) && 070 StringUtils.isNotBlank(perm.getName()) && 071 StringUtils.isNotBlank(orgBo.getId()) && 072 StringUtils.isNotBlank(perm.getId()) && 073 !StringUtils.equals(orgBo.getId(), perm.getId())){ 074 rulesPassed &= validateNamespaceCodeAndName(perm.getNamespaceCode(), perm.getName()); 075 } 076 // rule case for edit 077 if(StringUtils.isNotBlank(perm.getNamespaceCode()) && 078 StringUtils.isNotBlank(perm.getName()) && 079 StringUtils.isNotBlank(orgBo.getId()) && 080 StringUtils.isNotBlank(perm.getId()) && 081 StringUtils.equals(orgBo.getId(), perm.getId()) && 082 ( !StringUtils.equals(orgBo.getNamespaceCode(), perm.getNamespaceCode()) || 083 !StringUtils.equals(orgBo.getName(), perm.getName()) 084 ) 085 ) { 086 rulesPassed &= validateNamespaceCodeAndName(perm.getNamespaceCode(), perm.getName()); 087 } 088 // detailValues 089 // get the type from the template for validation 090 Template template = null; 091 if(StringUtils.isNotBlank(perm.getTemplateId())){ 092 template = KimApiServiceLocator.getPermissionService().getPermissionTemplate(perm.getTemplateId()); 093 if ( template == null ) { 094 GlobalVariables.getMessageMap().addToErrorPath( MAINTAINABLE_ERROR_PATH ); 095 GlobalVariables.getMessageMap().putError( DETAIL_VALUES_PROPERTY, ERROR_MISSING_TEMPLATE, perm.getTemplateId() ); 096 GlobalVariables.getMessageMap().removeFromErrorPath( MAINTAINABLE_ERROR_PATH ); 097 rulesPassed &= false; 098 } else { 099 KimType kimType = KimApiServiceLocator.getKimTypeInfoService().getKimType(template.getKimTypeId()); 100 Map<String, String> details = perm.getDetails(); 101 // check that add passed attributes are defined 102 for ( String attributeName : details.keySet() ) { 103 if ( kimType.getAttributeDefinitionByName(attributeName) == null ) { 104 GlobalVariables.getMessageMap().addToErrorPath( MAINTAINABLE_ERROR_PATH ); 105 GlobalVariables.getMessageMap().putError( DETAIL_VALUES_PROPERTY, ERROR_UNKNOWN_ATTRIBUTE, attributeName, template.getNamespaceCode(), template.getName() ); 106 GlobalVariables.getMessageMap().removeFromErrorPath( MAINTAINABLE_ERROR_PATH ); 107 rulesPassed &= false; 108 } 109 } 110 // if all attributes are known, pass to the service for validation 111 if ( !GlobalVariables.getMessageMap().hasErrors() ) { 112 PermissionTypeService service = getPermissionTypeService( kimType.getServiceName() ); 113 if ( service != null ) { 114 List<RemotableAttributeError> validationErrors = service.validateAttributes( kimType.getId(), details); 115 if ( validationErrors != null && !validationErrors.isEmpty() ) { 116 for ( RemotableAttributeError error : validationErrors ) { 117 GlobalVariables.getMessageMap().addToErrorPath( MAINTAINABLE_ERROR_PATH ); 118 for (String errMsg : error.getErrors()) { 119 GlobalVariables.getMessageMap().putError( DETAIL_VALUES_PROPERTY, ERROR_ATTRIBUTE_VALIDATION, error.getAttributeName(), errMsg ); 120 } 121 GlobalVariables.getMessageMap().removeFromErrorPath( MAINTAINABLE_ERROR_PATH ); 122 } 123 rulesPassed &= false; 124 } 125 } 126 } 127 128 } 129 130 } 131 // check each permission name against the type 132 } catch ( RuntimeException ex ) { 133 LOG.error( "Error in processCustomRouteDocumentBusinessRules()", ex ); 134 throw ex; 135 } 136 return rulesPassed; 137 } 138 139 protected boolean validateDetailValuesFormat(String permissionDetailValues){ 140 if(permissionDetailValues != null){ 141 String spacesPattern = "[\\s\\t]*"; 142 Pattern pattern = Pattern.compile(".+"+"="+".+"); 143 Matcher matcher; 144 // ensure that all line delimiters are single linefeeds 145 permissionDetailValues = permissionDetailValues.replace( "\r\n", "\n" ); 146 permissionDetailValues = permissionDetailValues.replace( '\r', '\n' ); 147 if(StringUtils.isNotBlank(permissionDetailValues)){ 148 String[] values = permissionDetailValues.split( "\n" ); 149 for(String attrib: values){ 150 matcher = pattern.matcher(attrib); 151 if(!matcher.matches()){ 152 GlobalVariables.getMessageMap().putError(MAINTAINABLE_ERROR_PATH+"."+DETAIL_VALUES_PROPERTY, RiceKeyConstants.ERROR_INVALID_FORMAT, new String[]{"Detail Values", permissionDetailValues}); 153 return false; 154 } 155 } 156 } 157 } 158 return true; 159 } 160 protected boolean validateNamespaceCodeAndName(String namespaceCode,String name){ 161 Permission permission = KimApiServiceLocator.getPermissionService().findPermByNamespaceCodeAndName(namespaceCode,name); 162 if(null != permission){ 163 GlobalVariables.getMessageMap().putError(MAINTAINABLE_ERROR_PATH+"."+NAMESPACE_CODE_PROPERTY,ERROR_NAMESPACE_AND_NAME_VALIDATION,namespaceCode,name); 164 return false; 165 } else{ 166 return true; 167 } 168 } 169 170 protected PermissionTypeService getPermissionTypeService( String serviceName ) { 171 if ( StringUtils.isBlank( serviceName ) ) { 172 return null; 173 } 174 try { 175 Object service = GlobalResourceLoader.getService(QName.valueOf(serviceName)); 176 // if we have a service name, it must exist 177 if ( service == null ) { 178 LOG.warn("null returned for permission type service for service name: " + serviceName); 179 } else { 180 // whatever we retrieved must be of the correct type 181 if ( !(service instanceof PermissionTypeService) ) { 182 LOG.warn( "Service " + serviceName + " was not a KimPermissionTypeService. Was: " + service.getClass().getName() ); 183 service = null; 184 } 185 } 186 return (PermissionTypeService)service; 187 } catch( Exception ex ) { 188 LOG.error( "Error retrieving service: " + serviceName + " from the KimImplServiceLocator.", ex ); 189 } 190 return null; 191 } 192 193}