Skip to content
Snippets Groups Projects
Commit afa1563c authored by Yauheni Lesnikau's avatar Yauheni Lesnikau
Browse files

Merge branch 'fix-update-issue' into 'master'

add owner permission checking to hasViewerAccessToRecord in CloudStorageImpl of Azure CSP

See merge request !606
parents d6d39c93 23d24e29
No related branches found
No related tags found
2 merge requests!744Upgraded packages to mitigated vulns in netty, guava, snakeyaml,!606add owner permission checking to hasViewerAccessToRecord in CloudStorageImpl of Azure CSP
Pipeline #166588 failed
......@@ -29,6 +29,7 @@ import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.storage.*;
import org.opengroup.osdu.storage.provider.azure.repository.GroupsInfoRepository;
import org.opengroup.osdu.storage.provider.azure.repository.RecordMetadataRepository;
import org.opengroup.osdu.storage.provider.azure.util.EntitlementsHelper;
import org.opengroup.osdu.storage.provider.azure.util.RecordUtil;
import org.opengroup.osdu.storage.provider.interfaces.ICloudStorage;
import org.opengroup.osdu.storage.util.CollaborationUtil;
......@@ -48,9 +49,6 @@ public class CloudStorageImpl implements ICloudStorage {
@Autowired
private JaxRsDpsLog logger;
@Autowired
private EntitlementsAndCacheServiceAzure dataEntitlementsService;
@Autowired
private DpsHeaders headers;
......@@ -72,6 +70,9 @@ public class CloudStorageImpl implements ICloudStorage {
@Autowired
private CrcHashGenerator crcHashGenerator;
@Autowired
private EntitlementsHelper entitlementsHelper;
@Autowired
@Named("STORAGE_CONTAINER_NAME")
private String containerName;
......@@ -223,49 +224,24 @@ public class CloudStorageImpl implements ICloudStorage {
}
hasAtLeastOneActiveRecord = true;
if (hasViewerAccessToRecord(record))
if (entitlementsHelper.hasViewerAccessToRecord(record))
return true;
}
return !hasAtLeastOneActiveRecord;
}
private boolean hasViewerAccessToRecord(RecordMetadata record)
{
String [] acls = ofNullable(record.getAcl())
.map(Acl::getViewers).
orElseGet(() -> {
logger.error("Record {} doesn't contain acl viewers or acl block has wrong structure", record.getId());
return new String[]{};
});
boolean isEntitledForViewing = dataEntitlementsService.hasAccessToData(headers,
new HashSet<>(Arrays.asList(acls)));
boolean isRecordOwner = record.getUser().equalsIgnoreCase(headers.getUserEmail());
return isEntitledForViewing || isRecordOwner;
}
private boolean hasOwnerAccessToRecord(RecordMetadata record)
{
String [] acls = ofNullable(record.getAcl())
.map(Acl::getOwners).
orElseGet(() -> {
logger.error("Record {} doesn't contain acl owners or acl block has wrong structure", record.getId());
return new String[]{};
});
return dataEntitlementsService.hasAccessToData(headers,
new HashSet<>(Arrays.asList(acls)));
}
private void validateOwnerAccessToRecord(RecordMetadata record)
{
if (!hasOwnerAccessToRecord(record)) {
if (!entitlementsHelper.hasOwnerAccessToRecord(record)) {
logger.warning(String.format("%s has no owner access to %s", headers.getUserEmail(), record.getId()));
throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG);
}
}
private void validateReadAccessToRecord(RecordMetadata record) {
if (!hasViewerAccessToRecord(record) && !hasOwnerAccessToRecord(record)) {
if (!entitlementsHelper.hasViewerAccessToRecord(record) && !entitlementsHelper.hasOwnerAccessToRecord(record)) {
logger.warning(String.format("%s has no owner/viewer access to %s", headers.getUserEmail(), record.getId()));
throw new AppException(HttpStatus.SC_FORBIDDEN, ACCESS_DENIED_ERROR_REASON, ACCESS_DENIED_ERROR_MSG);
}
......@@ -305,7 +281,7 @@ public class CloudStorageImpl implements ICloudStorage {
for (String recordId : recordIds) {
RecordMetadata recordMetadata = recordsMetadata.get(CollaborationUtil.getIdWithNamespace(recordId, collaborationContext));
if (!hasViewerAccessToRecord(recordMetadata)) {
if (!entitlementsHelper.hasViewerAccessToRecord(recordMetadata)) {
continue;
}
String path = objects.get(recordId);
......
package org.opengroup.osdu.storage.provider.azure.util;
import org.opengroup.osdu.core.common.model.entitlements.Acl;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.storage.RecordMetadata;
import org.opengroup.osdu.storage.provider.azure.EntitlementsAndCacheServiceAzure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashSet;
import static java.util.Optional.ofNullable;
import static org.apache.commons.lang3.StringUtils.EMPTY;
@Component
public class EntitlementsHelper {
private final Logger logger = LoggerFactory.getLogger(EntitlementsHelper.class);
@Autowired
private EntitlementsAndCacheServiceAzure dataEntitlementsService;
@Autowired
private DpsHeaders headers;
public boolean hasOwnerAccessToRecord(RecordMetadata record) {
String[] acls = ofNullable(record)
.map(RecordMetadata::getAcl)
.map(Acl::getOwners).
orElseGet(() -> {
logger.error("Record {} doesn't contain acl owners or acl block has wrong structure", record == null ? EMPTY : record.getId());
return new String[]{};
});
return dataEntitlementsService.hasAccessToData(headers,
new HashSet<>(Arrays.asList(acls)));
}
public boolean hasViewerAccessToRecord(RecordMetadata record) {
String[] acls = ofNullable(record)
.map(RecordMetadata::getAcl)
.map(Acl::getViewers).
orElseGet(() -> {
logger.error("Record {} doesn't contain acl viewers or acl block has wrong structure", record == null ? EMPTY : record.getId());
return new String[]{};
});
boolean isEntitledForViewing = dataEntitlementsService.hasAccessToData(headers,
new HashSet<>(Arrays.asList(acls)));
boolean isRecordCreator = ofNullable(record)
.map(RecordMetadata::getUser)
.map(user -> user.equalsIgnoreCase(headers.getUserEmail()))
.orElse(false);
if (!isEntitledForViewing && !isRecordCreator) {
return hasOwnerAccessToRecord(record);
}
return true;
}
}
......@@ -18,10 +18,10 @@ import org.opengroup.osdu.core.common.model.legal.LegalCompliance;
import org.opengroup.osdu.core.common.model.storage.Record;
import org.opengroup.osdu.core.common.model.storage.RecordMetadata;
import org.opengroup.osdu.storage.provider.azure.repository.RecordMetadataRepository;
import org.opengroup.osdu.storage.provider.azure.util.EntitlementsHelper;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Arrays;
import java.util.Set;
import static org.mockito.ArgumentMatchers.any;
......@@ -31,9 +31,6 @@ public class CloudStorageImplTest {
@Mock
private JaxRsDpsLog logger;
@Mock
private EntitlementsAndCacheServiceAzure entitlementsAndCacheServiceAzure;
@Mock
private DpsHeaders headers;
......@@ -43,6 +40,9 @@ public class CloudStorageImplTest {
@Mock
private RecordMetadataRepository recordRepository;
@Mock
private EntitlementsHelper entitlementsHelper;
@InjectMocks
private CloudStorageImpl cloudStorage;
......@@ -66,7 +66,7 @@ public class CloudStorageImplTest {
public void shouldNotInvokeDeleteOnBlobStoreWhenReferencedFromOtherDocuments() {
RecordMetadata recordMetadata = setUpRecordMetadata();
recordMetadata.setGcsVersionPaths(Arrays.asList("path1"));
Mockito.when(entitlementsAndCacheServiceAzure.hasAccessToData(any(DpsHeaders.class), any(Set.class))).thenReturn(true);
Mockito.when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(true);
Mockito.when(recordRepository.getMetadataDocumentCountForBlob("path1")).thenReturn(1);
cloudStorage.delete(recordMetadata);
Mockito.verify(blobStore, Mockito.never()).deleteFromStorageContainer(any(String.class), any(String.class), any(String.class));
......@@ -76,7 +76,7 @@ public class CloudStorageImplTest {
public void shouldThrowAppExceptionWhenDeleteWithNoOwnerAccess() {
RecordMetadata recordMetadata = setUpRecordMetadata();
recordMetadata.setGcsVersionPaths(Arrays.asList("path1", "path2"));
Mockito.when(entitlementsAndCacheServiceAzure.hasAccessToData(any(DpsHeaders.class), any(Set.class))).thenReturn(false);
Mockito.when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(false);
cloudStorage.delete(recordMetadata);
}
......@@ -84,7 +84,7 @@ public class CloudStorageImplTest {
public void shouldDeleteAllVersionsFromBlobStoreUponDeleteAction() {
RecordMetadata recordMetadata = setUpRecordMetadata();
recordMetadata.setGcsVersionPaths(Arrays.asList("path1", "path2"));
Mockito.when(entitlementsAndCacheServiceAzure.hasAccessToData(any(DpsHeaders.class), any(Set.class))).thenReturn(true);
Mockito.when(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata)).thenReturn(true);
Mockito.when(recordRepository.getMetadataDocumentCountForBlob("path1")).thenReturn(0);
Mockito.when(recordRepository.getMetadataDocumentCountForBlob("path2")).thenReturn(0);
cloudStorage.delete(recordMetadata);
......
package org.opengroup.osdu.storage.provider.azure.util;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.opengroup.osdu.core.common.model.entitlements.Acl;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.storage.RecordMetadata;
import org.opengroup.osdu.storage.provider.azure.EntitlementsAndCacheServiceAzure;
import java.util.Set;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class EntitlementsHelperTest {
private static final String OWNER_ACL = "owner_acl";
private static final String VIEWER_ACL = "viewer_acl";
private static final String USER = "test_user";
@Mock
private DpsHeaders headers;
@Mock
private EntitlementsAndCacheServiceAzure dataEntitlementsService;
@InjectMocks
private EntitlementsHelper entitlementsHelper;
@Mock
private RecordMetadata recordMetadata;
@Mock
private Acl acl;
private final ArgumentCaptor<Set<String>> captor = ArgumentCaptor.forClass(Set.class);
@Before
public void setup() {
when(recordMetadata.getAcl()).thenReturn(acl);
when(recordMetadata.getUser()).thenReturn(USER);
when(acl.getOwners()).thenReturn(new String[]{OWNER_ACL});
when(acl.getViewers()).thenReturn(new String[]{VIEWER_ACL});
}
@Test
public void hasOwnerAccessToRecord_shouldReturnTrue_ifUserIsOwner() {
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(true);
assertTrue(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, only()).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getValue().contains(OWNER_ACL));
assertEquals(1, captor.getValue().size());
}
@Test
public void hasOwnerAccessToRecord_shouldReturnFalse_ifUserIsNotOwner() {
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false);
assertFalse(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, only()).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getValue().contains(OWNER_ACL));
assertEquals(1, captor.getValue().size());
}
@Test
public void hasOwnerAccessToRecord_shouldReturnFalse_ifRecordIsNull() {
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false);
assertFalse(entitlementsHelper.hasOwnerAccessToRecord(null));
verify(dataEntitlementsService, only()).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getValue().isEmpty());
}
@Test
public void hasOwnerAccessToRecord_shouldReturnFalse_ifRecordsAclsAreNull() {
when(recordMetadata.getAcl()).thenReturn(null);
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false);
assertFalse(entitlementsHelper.hasOwnerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, only()).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getValue().isEmpty());
}
//-----
@Test
public void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsViewer() {
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(true);
assertTrue(entitlementsHelper.hasViewerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, only()).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getValue().contains(VIEWER_ACL));
assertEquals(1, captor.getValue().size());
}
@Test
public void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsNotViewerButOwner() {
when(dataEntitlementsService.hasAccessToData(eq(headers),
argThat((ArgumentMatcher<Set>) set -> set.contains(VIEWER_ACL)))).thenReturn(false);
when(dataEntitlementsService.hasAccessToData(eq(headers),
argThat((ArgumentMatcher<Set>) set -> set.contains(OWNER_ACL)))).thenReturn(true);
assertTrue(entitlementsHelper.hasViewerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, times(2)).hasAccessToData(eq(headers), captor.capture());
assertEquals(2, captor.getAllValues().size());
assertTrue(captor.getAllValues().get(0).contains(VIEWER_ACL));
assertEquals(1, captor.getAllValues().get(0).size());
assertTrue(captor.getAllValues().get(1).contains(OWNER_ACL));
assertEquals(1, captor.getAllValues().get(1).size());
}
@Test
public void hasViewerAccessToRecord_shouldReturnTrue_ifUserIsNotViewerButCreator() {
when(dataEntitlementsService.hasAccessToData(eq(headers),
argThat((ArgumentMatcher<Set>) set -> set.contains(VIEWER_ACL)))).thenReturn(false);
when(headers.getUserEmail()).thenReturn(USER);
assertTrue(entitlementsHelper.hasViewerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, only()).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getValue().contains(VIEWER_ACL));
}
@Test
public void hasViewerAccessToRecord_shouldReturnFalse_ifRecordIsNull() {
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false);
assertFalse(entitlementsHelper.hasViewerAccessToRecord(null));
verify(dataEntitlementsService, times(2)).hasAccessToData(eq(headers), captor.capture());
assertEquals(2, captor.getAllValues().size());
assertTrue(captor.getAllValues().get(0).isEmpty());
assertTrue(captor.getAllValues().get(1).isEmpty());
}
@Test
public void hasViewerAccessToRecord_shouldReturnFalse_ifRecordsAclsAreNull() {
when(recordMetadata.getAcl()).thenReturn(null);
when(dataEntitlementsService.hasAccessToData(eq(headers), anySet())).thenReturn(false);
assertFalse(entitlementsHelper.hasViewerAccessToRecord(recordMetadata));
verify(dataEntitlementsService, times(2)).hasAccessToData(eq(headers), captor.capture());
assertTrue(captor.getAllValues().get(0).isEmpty());
assertTrue(captor.getAllValues().get(1).isEmpty());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment