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 */
016 package org.kuali.rice.kew.docsearch;
017
018 import org.junit.Test;
019 import org.kuali.rice.kew.api.WorkflowDocument;
020 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
021 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
022 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
023 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
024 import org.kuali.rice.kew.docsearch.service.DocumentSearchService;
025 import org.kuali.rice.kew.engine.RouteContext;
026 import org.kuali.rice.kew.service.KEWServiceLocator;
027 import org.kuali.rice.kew.test.KEWTestCase;
028 import org.kuali.rice.kim.api.KimConstants;
029 import org.kuali.rice.kim.api.group.Group;
030 import org.kuali.rice.kim.api.identity.Person;
031 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
032
033 import 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 */
041 public 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 }