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}