/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.security.plugin; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ThreadContext; import org.junit.Test; import org.opensaml.core.xml.XMLObject; import org.opensaml.core.xml.schema.XSString; import org.opensaml.saml.saml2.core.Attribute; import org.opensaml.saml.saml2.core.AttributeStatement; import ddf.catalog.data.Metacard; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.operation.CreateRequest; import ddf.catalog.operation.DeleteRequest; import ddf.catalog.operation.Query; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.ResourceRequest; import ddf.catalog.operation.UpdateRequest; import ddf.catalog.operation.impl.CreateRequestImpl; import ddf.security.SecurityConstants; import ddf.security.Subject; import ddf.security.SubjectUtils; import ddf.security.assertion.SecurityAssertion; public class SecurityPluginTest { public static final String TEST_USER = "test-user"; @Test public void testNominalCaseCreateWithEmailAndNoTags() throws Exception { Subject mockSubject = setupMockSubject(); ThreadContext.bind(mockSubject); CreateRequest request = new MockCreateRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); assertThat(request.getMetacards() .size(), is(2)); request.getMetacards() .forEach(metacard -> assertThat(metacard.getAttribute(Metacard.POINT_OF_CONTACT) .getValue(), equalTo(TEST_USER))); } @Test public void testNominalCaseCreateWithEmailAndResourceTag() throws Exception { Subject mockSubject = setupMockSubject(); ThreadContext.bind(mockSubject); MetacardImpl metacardWithTags = new MetacardImpl(); Set<String> setOfTags = new HashSet<String>(); setOfTags.add("resource"); metacardWithTags.setTags(setOfTags); CreateRequest request = new CreateRequestImpl(metacardWithTags); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); assertThat(request.getMetacards() .size(), is(1)); assertThat(request.getMetacards() .get(0) .getAttribute(Metacard.POINT_OF_CONTACT) .getValue(), equalTo(TEST_USER)); } @Test public void testNominalCaseCreateWithoutEmail() throws Exception { Subject mockSubject = mock(Subject.class); ThreadContext.bind(mockSubject); CreateRequest request = new MockCreateRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); assertThat(request.getMetacards() .size(), is(2)); request.getMetacards() .forEach(metacard -> assertThat(metacard.getAttribute(Metacard.POINT_OF_CONTACT), is(nullValue()))); } @Test public void testNominalCaseCreateWithNonResourceMetacard() throws Exception { Subject mockSubject = setupMockSubject(); ThreadContext.bind(mockSubject); MetacardImpl metacardWithTags = new MetacardImpl(); Set<String> setOfTags = new HashSet<String>(); setOfTags.add("workspace"); metacardWithTags.setTags(setOfTags); CreateRequest request = new CreateRequestImpl(metacardWithTags); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); assertThat(request.getMetacards() .size(), is(1)); assertThat(request.getMetacards() .get(0) .getAttribute(Metacard.POINT_OF_CONTACT), is(nullValue())); } @Test public void testNominalCaseUpdate() throws Exception { Subject mockSubject = mock(Subject.class); ThreadContext.bind(mockSubject); UpdateRequest request = new MockUpdateRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreUpdate(request, new HashMap<>()); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); } @Test public void testNominalCaseDelete() throws Exception { Subject mockSubject = mock(Subject.class); ThreadContext.bind(mockSubject); DeleteRequest request = new MockDeleteRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreDelete(request); request = plugin.processPreDelete(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); } @Test public void testNominalCaseQuery() throws Exception { Subject mockSubject = mock(Subject.class); ThreadContext.bind(mockSubject); QueryRequest request = new MockQueryRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreQuery(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); } @Test public void testNominalCaseResource() throws Exception { Subject mockSubject = mock(Subject.class); ThreadContext.bind(mockSubject); ResourceRequest request = new MockResourceRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreResource(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); } @Test public void testSubjectExists() throws Exception { Subject mockSubject = mock(Subject.class); CreateRequest request = new MockCreateRequest(); request.getProperties() .put(SecurityConstants.SECURITY_SUBJECT, mockSubject); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); } @Test public void testBadSubjectCase() throws Exception { Subject mockSubject = mock(Subject.class); ThreadContext.bind(mockSubject); CreateRequest request = new MockCreateRequest(); request.getProperties() .put(SecurityConstants.SECURITY_SUBJECT, new HashMap<>()); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(mockSubject)); } @Test public void testWrongSubjectCase() throws Exception { org.apache.shiro.subject.Subject wrongSubject = mock(org.apache.shiro.subject.Subject.class); ThreadContext.bind(wrongSubject); CreateRequest request = new MockCreateRequest(); SecurityPlugin plugin = new SecurityPlugin(); request = plugin.processPreCreate(request); assertThat(request.getPropertyValue(SecurityConstants.SECURITY_SUBJECT), equalTo(null)); } private Subject setupMockSubject() { XSString mockAttributeValue = mock(XSString.class); when(mockAttributeValue.getValue()).thenReturn(TEST_USER); List<XMLObject> listOfAttributeValues = Arrays.asList(mockAttributeValue); Attribute mockAttribute = mock(Attribute.class); when(mockAttribute.getName()).thenReturn(SubjectUtils.EMAIL_ADDRESS_CLAIM_URI); when(mockAttribute.getAttributeValues()).thenReturn(listOfAttributeValues); List<Attribute> listOfAttributes = Arrays.asList(mockAttribute); AttributeStatement mockAttributeStatement = mock(AttributeStatement.class); when(mockAttributeStatement.getAttributes()).thenReturn(listOfAttributes); List<AttributeStatement> listOfAttributeStatements = Arrays.asList(mockAttributeStatement); Subject mockSubject = mock(Subject.class); PrincipalCollection mockPrincipals = mock(PrincipalCollection.class); SecurityAssertion mockSecurityAssertion = mock(SecurityAssertion.class); when(mockSecurityAssertion.getAttributeStatements()).thenReturn(listOfAttributeStatements); when(mockPrincipals.oneByType(SecurityAssertion.class)).thenReturn(mockSecurityAssertion); when(mockSubject.getPrincipals()).thenReturn(mockPrincipals); return mockSubject; } public static class MockCreateRequest implements CreateRequest { private Map<String, Serializable> props = new HashMap<>(); private List<Metacard> metacards; @Override public List<Metacard> getMetacards() { if (metacards == null) { metacards = new ArrayList<>(); metacards.add(new MetacardImpl()); metacards.add(new MetacardImpl()); } return metacards; } @Override public Set<String> getPropertyNames() { return props.keySet(); } @Override public Serializable getPropertyValue(String name) { return props.get(name); } @Override public boolean containsPropertyName(String name) { return props.containsKey(name); } @Override public boolean hasProperties() { return true; } @Override public Map<String, Serializable> getProperties() { return props; } } public static class MockUpdateRequest implements UpdateRequest { private Map<String, Serializable> props = new HashMap<>(); @Override public Set<String> getPropertyNames() { return props.keySet(); } @Override public Serializable getPropertyValue(String name) { return props.get(name); } @Override public boolean containsPropertyName(String name) { return props.containsKey(name); } @Override public boolean hasProperties() { return true; } @Override public Map<String, Serializable> getProperties() { return props; } @Override public String getAttributeName() { return ""; } @Override public List<Map.Entry<Serializable, Metacard>> getUpdates() { return new ArrayList<>(); } } public static class MockDeleteRequest implements DeleteRequest { private Map<String, Serializable> props = new HashMap<>(); @Override public Set<String> getPropertyNames() { return props.keySet(); } @Override public Serializable getPropertyValue(String name) { return props.get(name); } @Override public boolean containsPropertyName(String name) { return props.containsKey(name); } @Override public boolean hasProperties() { return true; } @Override public Map<String, Serializable> getProperties() { return props; } @Override public String getAttributeName() { return ""; } @Override public List<? extends Serializable> getAttributeValues() { return null; } } public static class MockQueryRequest implements QueryRequest { private Map<String, Serializable> props = new HashMap<>(); @Override public Set<String> getPropertyNames() { return props.keySet(); } @Override public Serializable getPropertyValue(String name) { return props.get(name); } @Override public boolean containsPropertyName(String name) { return props.containsKey(name); } @Override public boolean hasProperties() { return true; } @Override public Map<String, Serializable> getProperties() { return props; } @Override public Query getQuery() { return mock(Query.class); } @Override public Set<String> getSourceIds() { return new HashSet<>(); } @Override public boolean isEnterprise() { return false; } } public static class MockResourceRequest implements ResourceRequest { private Map<String, Serializable> props = new HashMap<>(); @Override public Set<String> getPropertyNames() { return props.keySet(); } @Override public Serializable getPropertyValue(String name) { return props.get(name); } @Override public boolean containsPropertyName(String name) { return props.containsKey(name); } @Override public boolean hasProperties() { return true; } @Override public Map<String, Serializable> getProperties() { return props; } @Override public String getAttributeName() { return ""; } @Override public Serializable getAttributeValue() { return ""; } } }