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    }