001/** 002 * Copyright 2005-2014 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.kew.docsearch; 017 018import org.junit.Test; 019import org.kuali.rice.kew.api.WorkflowDocument; 020import org.kuali.rice.kew.api.WorkflowDocumentFactory; 021import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition; 022import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria; 023import org.kuali.rice.kew.api.document.search.DocumentSearchResults; 024import org.kuali.rice.kew.docsearch.service.DocumentSearchService; 025import org.kuali.rice.kew.engine.RouteContext; 026import org.kuali.rice.kew.service.KEWServiceLocator; 027import org.kuali.rice.kew.test.KEWTestCase; 028import org.kuali.rice.kim.api.KimConstants; 029import org.kuali.rice.kim.api.group.Group; 030import org.kuali.rice.kim.api.identity.Person; 031import org.kuali.rice.kim.api.services.KimApiServiceLocator; 032 033import static org.junit.Assert.*; 034 035/** 036 * This is a description of what this class does - jjhanso don't forget to fill this in. 037 * 038 * @author Kuali Rice Team (rice.collab@kuali.org) 039 * 040 */ 041public class DocumentSearchSecurityTest extends KEWTestCase { 042 private static final String WORKFLOW_ADMIN_USER_NETWORK_ID = "bmcgough"; 043 private static final String APPROVER_USER_NETWORK_ID = "user2"; 044 private static final String STANDARD_USER_NETWORK_ID = "user1"; 045 DocumentSearchService docSearchService; 046 047 @Override 048 protected void setUpAfterDataLoad() throws Exception { 049 docSearchService = (DocumentSearchService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE); 050 } 051 052 @Override 053 protected void loadTestData() throws Exception { 054 loadXmlFile("SearchSecurityConfig.xml"); 055 056 } 057 058 /** 059 * Test for https://test.kuali.org/jira/browse/KULRICE-1968 - Document search fails when users are missing 060 * Tests that we can safely search on docs whose initiator no longer exists in the identity management system 061 * This test searches by doc type name criteria. 062 * @throws Exception 063 */ 064 @Test public void testDocSearchSecurityPermissionDocType() throws Exception { 065 String documentTypeName = "SecurityDoc_PermissionOnly"; 066 String userNetworkId = "arh14"; 067 // route a document to enroute and route one to final 068 WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(getPrincipalId(userNetworkId), documentTypeName); 069 workflowDocument.setTitle("testDocSearch_PermissionSecurity"); 070 workflowDocument.route("routing this document."); 071 072 Person user = KimApiServiceLocator.getPersonService().getPersonByPrincipalName("edna"); 073 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 074 criteria.setDocumentTypeName(documentTypeName); 075 DocumentSearchResults results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build()); 076 assertEquals(0, results.getNumberOfSecurityFilteredResults()); 077 assertEquals("Search returned invalid number of documents", 1, results.getSearchResults().size()); 078 } 079 080 @Test public void testDocSearchBadPermission() throws Exception { 081 String documentTypeName = "SecurityDoc_InvalidPermissionOnly"; 082 String userNetworkId = "arh14"; 083 // route a document to enroute and route one to final 084 WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(getPrincipalId(userNetworkId), documentTypeName); 085 workflowDocument.setTitle("testDocSearch_PermissionSecurity"); 086 workflowDocument.route("routing this document."); 087 088 Person user = KimApiServiceLocator.getPersonService().getPersonByPrincipalName("edna"); 089 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 090 criteria.setDocumentTypeName(documentTypeName); 091 DocumentSearchResults results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build()); 092 assertEquals("Search returned invalid number of documents", 0, results.getSearchResults().size()); 093 } 094 095 @Test public void testFilteringInitiator() throws Exception { 096 String documentType = "SecurityDoc_InitiatorOnly"; 097 String initiator = getPrincipalId(STANDARD_USER_NETWORK_ID); 098 WorkflowDocument document = WorkflowDocumentFactory.createDocument(initiator, documentType); 099 document.route(""); 100 assertFalse("Document should not be in init status after routing", document.isInitiated()); 101 102 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 103 criteria.setDocumentId(document.getDocumentId()); 104 DocumentSearchResults results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(initiator, criteria.build()); 105 assertEquals("Should retrive one record from search", 1, results.getSearchResults().size()); 106 assertEquals("No rows should have been filtered due to security", 0, results.getNumberOfSecurityFilteredResults()); 107 108 criteria = DocumentSearchCriteria.Builder.create(); 109 criteria.setDocumentId(document.getDocumentId()); 110 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId("user3"), criteria.build()); 111 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 112 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 113 114 criteria = DocumentSearchCriteria.Builder.create(); 115 criteria.setDocumentId(document.getDocumentId()); 116 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId(WORKFLOW_ADMIN_USER_NETWORK_ID), criteria.build()); 117 assertEquals("Should retrive one record from search", 1, results.getSearchResults().size()); 118 assertEquals("No rows should have been filtered due to security", 0, results.getNumberOfSecurityFilteredResults()); 119 } 120 121 @Test public void testFiltering_Workgroup() throws Exception { 122 String documentType = "SecurityDoc_WorkgroupOnly"; 123 String initiator = getPrincipalId(STANDARD_USER_NETWORK_ID); 124 WorkflowDocument document = WorkflowDocumentFactory.createDocument(initiator, documentType); 125 document.route(""); 126 assertFalse("Document should not be in init status after routing", document.isInitiated()); 127 128 // verify that initiator cannot see the document 129 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 130 criteria.setDocumentId(document.getDocumentId()); 131 DocumentSearchResults results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(initiator, criteria.build()); 132 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 133 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 134 135 // verify that workgroup can see the document 136 String workgroupName = "Test_Security_Group"; 137 Group group = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName( 138 KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, workgroupName); 139 assertNotNull("Workgroup '" + workgroupName + "' should be valid", group); 140 for (String workgroupUserId : KimApiServiceLocator.getGroupService().getMemberPrincipalIds(group.getId())) { 141 Person workgroupUser = KimApiServiceLocator.getPersonService().getPerson(workgroupUserId); 142 criteria = DocumentSearchCriteria.Builder.create(); 143 criteria.setDocumentId(document.getDocumentId()); 144 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(workgroupUser.getPrincipalId(), criteria.build()); 145 assertEquals("Should retrive one record from search for user " + workgroupUser, 1, results.getSearchResults().size()); 146 assertEquals("No rows should have been filtered due to security for user " + workgroupUser, 0, results.getNumberOfSecurityFilteredResults()); 147 } 148 149 // verify that user3 cannot see the document 150 criteria = DocumentSearchCriteria.Builder.create(); 151 criteria.setDocumentId(document.getDocumentId()); 152 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId("user3"), criteria.build()); 153 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 154 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 155 156 // verify that WorkflowAdmin can see the document 157 criteria = DocumentSearchCriteria.Builder.create(); 158 criteria.setDocumentId(document.getDocumentId()); 159 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId(WORKFLOW_ADMIN_USER_NETWORK_ID), criteria.build()); 160 assertEquals("Should retrive one record from search", 1, results.getSearchResults().size()); 161 assertEquals("No rows should have been filtered due to security", 0, results.getNumberOfSecurityFilteredResults()); 162 } 163 164 @Test public void testFiltering_SearchAttribute() throws Exception { 165 166 String searchAttributeName = "UserEmployeeId"; 167 String searchAttributeFieldName = "employeeId"; 168 String documentTypeName = "SecurityDoc_SearchAttributeOnly"; 169 String initiatorNetworkId = STANDARD_USER_NETWORK_ID; 170 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalId(initiatorNetworkId), documentTypeName); 171 WorkflowAttributeDefinition.Builder definition = WorkflowAttributeDefinition.Builder.create(searchAttributeName); 172 definition.addPropertyDefinition(searchAttributeFieldName, "user3"); 173 document.addSearchableDefinition(definition.build()); 174 document.route(""); 175 assertFalse("Document should not be in init status after routing", document.isInitiated()); 176 177 // verify that initiator cannot see the document 178 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 179 criteria.setDocumentId(document.getDocumentId()); 180 DocumentSearchResults results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId(initiatorNetworkId), criteria.build()); 181 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 182 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 183 184 // verify that user3 can see the document 185 criteria = DocumentSearchCriteria.Builder.create(); 186 criteria.setDocumentId(document.getDocumentId()); 187 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId("user3"), criteria.build()); 188 assertEquals("Should retrive one record from search", 1, results.getSearchResults().size()); 189 assertEquals("No rows should have been filtered due to security", 0, results.getNumberOfSecurityFilteredResults()); 190 191 // verify that user2 cannot see the document 192 criteria = DocumentSearchCriteria.Builder.create(); 193 criteria.setDocumentId(document.getDocumentId()); 194 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId("user2"), criteria.build()); 195 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 196 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 197 198 // verify that WorkflowAdmin can see the document 199 criteria = DocumentSearchCriteria.Builder.create(); 200 criteria.setDocumentId(document.getDocumentId()); 201 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId(WORKFLOW_ADMIN_USER_NETWORK_ID), criteria.build()); 202 assertEquals("Should retrive one record from search", 1, results.getSearchResults().size()); 203 assertEquals("No rows should have been filtered due to security", 0, results.getNumberOfSecurityFilteredResults()); 204 205 RouteContext.clearCurrentRouteContext(); 206 document = WorkflowDocumentFactory.loadDocument(getPrincipalId(APPROVER_USER_NETWORK_ID), document.getDocumentId()); 207 document.clearSearchableContent(); 208 definition = WorkflowAttributeDefinition.Builder.create(searchAttributeName); 209 definition.addPropertyDefinition(searchAttributeFieldName, "user2"); 210 document.addSearchableDefinition(definition.build()); 211 document.saveDocumentData(); 212 213 // verify that user2 can see the document 214 criteria = DocumentSearchCriteria.Builder.create(); 215 criteria.setDocumentId(document.getDocumentId()); 216 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId("user2"), criteria.build()); 217 assertEquals("Should retrive one record from search", 1, results.getSearchResults().size()); 218 assertEquals("No rows should have been filtered due to security", 0, results.getNumberOfSecurityFilteredResults()); 219 220 // verify that user3 cannot see the document 221 criteria = DocumentSearchCriteria.Builder.create(); 222 criteria.setDocumentId(document.getDocumentId()); 223 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId("user3"), criteria.build()); 224 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 225 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 226 227 // verify that initiator cannot see the document 228 criteria = DocumentSearchCriteria.Builder.create(); 229 criteria.setDocumentId(document.getDocumentId()); 230 results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(getPrincipalId(initiatorNetworkId), criteria.build()); 231 assertEquals("Should retrive no records from search", 0, results.getSearchResults().size()); 232 assertEquals("One row should have been filtered due to security", 1, results.getNumberOfSecurityFilteredResults()); 233 } 234 235 private String getPrincipalId(String principalName) { 236 return KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalName).getPrincipalId(); 237 } 238 239}