61876871fd0f2367007cdd27947dc0251977aaae
java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/GPSFixStoreListenerTest.java
| ... | ... | @@ -33,9 +33,9 @@ public class GPSFixStoreListenerTest extends AbstractGPSFixStoreTest { |
| 33 | 33 | CyclicBarrier barrier = new CyclicBarrier(2); |
| 34 | 34 | // We need 3 listener instances to guarantee that the iterator isn't finished |
| 35 | 35 | // when adding another listener in the thread below. |
| 36 | - store.addListener(new ListenerAwaitingBarier(barrier), device); |
|
| 37 | - store.addListener(new ListenerAwaitingBarier(barrier), device); |
|
| 38 | - store.addListener(new ListenerAwaitingBarier(barrier), device); |
|
| 36 | + store.addListener(new ListenerAwaitingBarrier(barrier), device); |
|
| 37 | + store.addListener(new ListenerAwaitingBarrier(barrier), device); |
|
| 38 | + store.addListener(new ListenerAwaitingBarrier(barrier), device); |
|
| 39 | 39 | |
| 40 | 40 | Thread thread = new Thread() { |
| 41 | 41 | public void run() { |
| ... | ... | @@ -63,11 +63,11 @@ public class GPSFixStoreListenerTest extends AbstractGPSFixStoreTest { |
| 63 | 63 | } |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | - private static class ListenerAwaitingBarier implements FixReceivedListener<GPSFixMoving> { |
|
| 66 | + private static class ListenerAwaitingBarrier implements FixReceivedListener<GPSFixMoving> { |
|
| 67 | 67 | |
| 68 | 68 | private final CyclicBarrier barrier; |
| 69 | 69 | |
| 70 | - public ListenerAwaitingBarier(CyclicBarrier barrier) { |
|
| 70 | + public ListenerAwaitingBarrier(CyclicBarrier barrier) { |
|
| 71 | 71 | this.barrier = barrier; |
| 72 | 72 | } |
| 73 | 73 |
java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/fixtracker/FixLoaderAndTracker.java
| ... | ... | @@ -191,7 +191,6 @@ public class FixLoaderAndTracker implements TrackingDataLoader { |
| 191 | 191 | @Override |
| 192 | 192 | public Iterable<RegattaAndRaceIdentifier> fixReceived(DeviceIdentifier device, Timed fix) { |
| 193 | 193 | Set<RegattaAndRaceIdentifier> maneuverChanged = new HashSet<>(); |
| 194 | - |
|
| 195 | 194 | if (!preemptiveStopRequested.get() && trackedRace.getStartOfTracking() != null) { |
| 196 | 195 | final TimePoint timePoint = fix.getTimePoint(); |
| 197 | 196 | deviceMappings.forEachMappingOfDeviceIncludingTimePoint(device, fix.getTimePoint(), |
java/com.sap.sailing.server.gateway.test/.settings/org.eclipse.core.resources.prefs
| ... | ... | @@ -0,0 +1,2 @@ |
| 1 | +eclipse.preferences.version=1 |
|
| 2 | +encoding//src/com/sap/sailing/server/gateway/test/jaxrs/CompetitorsResourceTest.java=UTF-8 |
java/com.sap.sailing.server.gateway.test/META-INF/MANIFEST.MF
| ... | ... | @@ -14,7 +14,8 @@ Require-Bundle: org.mockito.mockito-core;bundle-version="1.9.5", |
| 14 | 14 | com.sap.sailing.domain.racelogtrackingadapter.testsupport, |
| 15 | 15 | com.sap.sse.common, |
| 16 | 16 | com.sun.jersey, |
| 17 | - org.apache.commons.io;bundle-version="2.2.0" |
|
| 17 | + org.apache.commons.io;bundle-version="2.2.0", |
|
| 18 | + com.sap.sse.security.testsupport |
|
| 18 | 19 | Import-Package: com.sap.sailing.domain.common.impl, |
| 19 | 20 | com.sap.sailing.domain.persistence.impl, |
| 20 | 21 | com.sap.sailing.server.impl, |
java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java
| ... | ... | @@ -10,8 +10,6 @@ import java.util.ArrayList; |
| 10 | 10 | import java.util.Collections; |
| 11 | 11 | import java.util.Date; |
| 12 | 12 | import java.util.List; |
| 13 | -import java.util.UUID; |
|
| 14 | -import java.util.concurrent.Callable; |
|
| 15 | 13 | |
| 16 | 14 | import javax.ws.rs.core.Response; |
| 17 | 15 | |
| ... | ... | @@ -21,8 +19,6 @@ import org.apache.shiro.subject.Subject; |
| 21 | 19 | import org.apache.shiro.subject.support.SubjectThreadState; |
| 22 | 20 | import org.apache.shiro.util.ThreadState; |
| 23 | 21 | import org.mockito.Mockito; |
| 24 | -import org.mockito.invocation.InvocationOnMock; |
|
| 25 | -import org.mockito.stubbing.Answer; |
|
| 26 | 22 | |
| 27 | 23 | import com.sap.sailing.domain.base.Competitor; |
| 28 | 24 | import com.sap.sailing.domain.base.impl.CompetitorImpl; |
| ... | ... | @@ -39,13 +35,11 @@ import com.sap.sse.common.TimePoint; |
| 39 | 35 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 40 | 36 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 41 | 37 | import com.sap.sse.mongodb.MongoDBService; |
| 42 | -import com.sap.sse.security.Action; |
|
| 43 | 38 | import com.sap.sse.security.SecurityService; |
| 44 | 39 | import com.sap.sse.security.shared.OwnershipAnnotation; |
| 45 | -import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; |
|
| 46 | 40 | import com.sap.sse.security.shared.impl.Ownership; |
| 47 | 41 | import com.sap.sse.security.shared.impl.User; |
| 48 | -import com.sap.sse.security.shared.impl.UserGroupImpl; |
|
| 42 | +import com.sap.sse.security.testsupport.SecurityServiceMockFactory; |
|
| 49 | 43 | |
| 50 | 44 | public abstract class AbstractJaxRsApiTest { |
| 51 | 45 | protected RacingEventService racingEventService; |
| ... | ... | @@ -60,52 +54,17 @@ public abstract class AbstractJaxRsApiTest { |
| 60 | 54 | |
| 61 | 55 | protected static SimpleDateFormat TIMEPOINT_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); |
| 62 | 56 | |
| 63 | - @SuppressWarnings("unchecked") |
|
| 64 | 57 | public void setUp() throws Exception { |
| 65 | 58 | service = MongoDBConfiguration.getDefaultTestConfiguration().getService(); |
| 66 | 59 | service.getDB().drop(); |
| 67 | 60 | racingEventService = Mockito.spy(new RacingEventServiceImpl(/* clearPersistentCompetitorStore */ true, |
| 68 | 61 | new MockSmartphoneUuidServiceFinderFactory(), /* restoreTrackedRaces */ false)); |
| 69 | - |
|
| 70 | - UserGroupImpl defaultTenant = new UserGroupImpl(new UUID(0, 1), "defaultTenant"); |
|
| 71 | - |
|
| 72 | - securityService = Mockito.mock(SecurityService.class); |
|
| 73 | 62 | SecurityManager securityManager = Mockito.mock(org.apache.shiro.mgt.SecurityManager.class); |
| 74 | 63 | Subject fakeSubject = Mockito.mock(Subject.class); |
| 75 | - |
|
| 64 | + Mockito.doReturn(true).when(fakeSubject).isAuthenticated(); |
|
| 76 | 65 | SecurityUtils.setSecurityManager(securityManager); |
| 77 | 66 | Mockito.doReturn(fakeSubject).when(securityManager).createSubject(Mockito.any()); |
| 78 | - |
|
| 79 | - Mockito.doReturn(defaultTenant).when(securityService).getDefaultTenant(); |
|
| 80 | - |
|
| 81 | - Mockito.doAnswer(new Answer<Object>() { |
|
| 82 | - @Override |
|
| 83 | - public Object answer(InvocationOnMock invocation) throws Throwable { |
|
| 84 | - return invocation.getArgumentAt(4, Callable.class).call(); |
|
| 85 | - } |
|
| 86 | - }).when(securityService).setOwnershipCheckPermissionForObjectCreationAndRevertOnError( |
|
| 87 | - Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(Action.class)); |
|
| 88 | - Mockito.doAnswer(new Answer<Object>() { |
|
| 89 | - @SuppressWarnings("rawtypes") |
|
| 90 | - @Override |
|
| 91 | - public Object answer(InvocationOnMock invocation) throws Throwable { |
|
| 92 | - for (Object arg : invocation.getArguments()) { |
|
| 93 | - if (arg instanceof Callable) { |
|
| 94 | - return ((Callable) arg).call(); |
|
| 95 | - } |
|
| 96 | - } |
|
| 97 | - return null; |
|
| 98 | - } |
|
| 99 | - }).when(securityService).setOwnershipCheckPermissionForObjectCreationAndRevertOnError(Mockito.any(), |
|
| 100 | - Mockito.any(), Mockito.any(), Mockito.any(Callable.class)); |
|
| 101 | - |
|
| 102 | - Mockito.doReturn(true).when(securityService) |
|
| 103 | - .hasCurrentUserReadPermission(Mockito.any(WithQualifiedObjectIdentifier.class)); |
|
| 104 | - |
|
| 105 | - Mockito.doNothing().when(securityService).checkCurrentUserReadPermission(Mockito.any()); |
|
| 106 | - |
|
| 107 | - Mockito.doReturn(true).when(fakeSubject).isAuthenticated(); |
|
| 108 | - |
|
| 67 | + securityService = SecurityServiceMockFactory.mockSecurityService(); |
|
| 109 | 68 | OwnershipAnnotation mockedOwnership = Mockito.mock(OwnershipAnnotation.class); |
| 110 | 69 | Ownership ownership = Mockito.mock(Ownership.class); |
| 111 | 70 | Mockito.doReturn(mockedOwnership).when(securityService).getOwnership(Mockito.any()); |
java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/CompetitorsResourceTeamImageTest.java
| ... | ... | @@ -39,7 +39,7 @@ public class CompetitorsResourceTeamImageTest extends AbstractJaxRsApiTest { |
| 39 | 39 | @Before |
| 40 | 40 | public void setUpSubClass() throws Exception { |
| 41 | 41 | super.setUp(); |
| 42 | - storageService = AmazonS3TestSupport.createService(); |
|
| 42 | + storageService = AmazonS3TestSupport.createService(securityService); |
|
| 43 | 43 | FileStorageManagementService fsmsMock = mock(FileStorageManagementService.class); |
| 44 | 44 | doReturn(fsmsMock).when(racingEventService).getFileStorageManagementService(); |
| 45 | 45 | doReturn(storageService).when(fsmsMock).getActiveFileStorageService(); |
| ... | ... | @@ -52,26 +52,21 @@ public class CompetitorsResourceTeamImageTest extends AbstractJaxRsApiTest { |
| 52 | 52 | @Test |
| 53 | 53 | public void storeAndRemoveTeamImage() throws URISyntaxException, ParseException, MalformedURLException, |
| 54 | 54 | IOException, OperationFailedException, InvalidPropertiesException { |
| 55 | - //set team image |
|
| 55 | + // set team image |
|
| 56 | 56 | String fileExtension = teamImageFile.substring(teamImageFile.lastIndexOf("."));; |
| 57 | 57 | InputStream stream = getClass().getResourceAsStream("/" + teamImageFile); |
| 58 | - |
|
| 59 | 58 | // this is not ideal, as this #available() is not supposed to be used for getting the file size |
| 60 | 59 | // however, working with a File() descriptor does not work, as when running via maven/tycho the |
| 61 | 60 | // URL has the bundleresource:// scheme instead of file:, which File() can't handle |
| 62 | 61 | long length = stream.available(); |
| 63 | - |
|
| 64 | 62 | String jsonString = competitorsResource.setTeamImage(id, stream, fileExtension, length, null, null); |
| 65 | - |
|
| 66 | - //now download and compare |
|
| 63 | + // now download and compare |
|
| 67 | 64 | JSONObject json = (JSONObject) JSONValue.parseWithException(jsonString); |
| 68 | 65 | String imageUriString = (String) json.get(DeviceMappingConstants.JSON_TEAM_IMAGE_URI); |
| 69 | 66 | URI imageUri = new URI(imageUriString); |
| 70 | - |
|
| 71 | 67 | InputStream downloadStream = imageUri.toURL().openStream(); |
| 72 | 68 | stream = getClass().getResourceAsStream("/" + teamImageFile); |
| 73 | 69 | IOUtils.contentEquals(downloadStream, stream); |
| 74 | - |
|
| 75 | 70 | storageService.removeFile(imageUri); |
| 76 | 71 | } |
| 77 | 72 | } |
java/com.sap.sse.filestorage.test/META-INF/MANIFEST.MF
| ... | ... | @@ -13,7 +13,8 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0", |
| 13 | 13 | com.sap.sse.replication;bundle-version="1.0.0", |
| 14 | 14 | org.mockito.mockito-core;bundle-version="1.10.14", |
| 15 | 15 | org.apache.shiro.core;bundle-version="1.2.2", |
| 16 | - org.objenesis;bundle-version="2.1.0" |
|
| 16 | + org.objenesis;bundle-version="2.1.0", |
|
| 17 | + com.sap.sse.security.testsupport |
|
| 17 | 18 | Import-Package: org.apache.commons.logging, |
| 18 | 19 | org.slf4j;version="1.6.4" |
| 19 | 20 | Automatic-Module-Name: com.sap.sse.filestorage.test |
java/com.sap.sse.filestorage.test/src/com/sap/sse/filestorage/services/test/AmazonS3Test.java
| ... | ... | @@ -18,18 +18,18 @@ import com.sap.sse.filestorage.FileStorageService; |
| 18 | 18 | import com.sap.sse.filestorage.InvalidPropertiesException; |
| 19 | 19 | import com.sap.sse.filestorage.OperationFailedException; |
| 20 | 20 | import com.sap.sse.filestorage.testsupport.AmazonS3TestSupport; |
| 21 | +import com.sap.sse.security.testsupport.SecurityServiceMockFactory; |
|
| 21 | 22 | |
| 22 | 23 | public class AmazonS3Test { |
| 23 | 24 | @Before |
| 24 | 25 | public void setup() throws InvalidPropertiesException { |
| 25 | 26 | setUpSecurity(); |
| 26 | - storageService = AmazonS3TestSupport.createService(); |
|
| 27 | + storageService = AmazonS3TestSupport.createService(SecurityServiceMockFactory.mockSecurityService()); |
|
| 27 | 28 | } |
| 28 | 29 | |
| 29 | 30 | private void setUpSecurity() { |
| 30 | 31 | org.apache.shiro.mgt.SecurityManager securityManager = Mockito.mock(org.apache.shiro.mgt.SecurityManager.class); |
| 31 | 32 | Subject fakeSubject = Mockito.mock(Subject.class); |
| 32 | - |
|
| 33 | 33 | SecurityUtils.setSecurityManager(securityManager); |
| 34 | 34 | Mockito.doReturn(fakeSubject).when(securityManager).createSubject(Mockito.any()); |
| 35 | 35 | Mockito.doReturn(true).when(fakeSubject).isAuthenticated(); |
| ... | ... | @@ -42,14 +42,11 @@ public class AmazonS3Test { |
| 42 | 42 | @Test |
| 43 | 43 | public void testStoreAndRemoveFileTest() throws URISyntaxException, IOException, OperationFailedException, InvalidPropertiesException { |
| 44 | 44 | InputStream stream = getClass().getClassLoader().getResourceAsStream(teamImageFile); |
| 45 | - |
|
| 46 | 45 | // this is not ideal, as this #available() is not supposed to be used for getting the file size |
| 47 | 46 | // however, working with a File() descriptor does not work, as when running via maven/tycho the |
| 48 | 47 | // URL has the bundleresource:// scheme instead of file:, which File() can't handle |
| 49 | 48 | long length = stream.available(); |
| 50 | - |
|
| 51 | 49 | URI uri = storageService.storeFile(stream, teamImageFile, length); |
| 52 | - |
|
| 53 | 50 | InputStream downloadStream = uri.toURL().openStream(); |
| 54 | 51 | stream = getClass().getClassLoader().getResourceAsStream(teamImageFile); |
| 55 | 52 | try { |
java/com.sap.sse.filestorage/META-INF/MANIFEST.MF
| ... | ... | @@ -25,5 +25,6 @@ Require-Bundle: org.apache.servicemix.bundles.aws-java-sdk;bundle-version="1.9.8 |
| 25 | 25 | org.apache.commons.io, |
| 26 | 26 | org.mongodb.mongo-java-driver;bundle-version="3.6.4", |
| 27 | 27 | org.apache.shiro.core, |
| 28 | - com.sap.sailing.domain.common |
|
| 28 | + com.sap.sailing.domain.common, |
|
| 29 | + com.sap.sse.security |
|
| 29 | 30 | Automatic-Module-Name: com.sap.sse.filestorage |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/Activator.java
| ... | ... | @@ -31,11 +31,11 @@ public class Activator implements BundleActivator { |
| 31 | 31 | |
| 32 | 32 | Dictionary<String, String> dict = new Hashtable<>(); |
| 33 | 33 | dict.put(TypeBasedServiceFinder.TYPE, AmazonS3FileStorageServiceImpl.NAME); |
| 34 | - context.registerService(FileStorageService.class, new AmazonS3FileStorageServiceImpl(), dict); |
|
| 34 | + context.registerService(FileStorageService.class, new AmazonS3FileStorageServiceImpl(context), dict); |
|
| 35 | 35 | |
| 36 | 36 | Dictionary<String, String> localStorageDict = new Hashtable<>(); |
| 37 | 37 | localStorageDict.put(TypeBasedServiceFinder.TYPE, LocalFileStorageServiceImpl.NAME); |
| 38 | - context.registerService(FileStorageService.class, new LocalFileStorageServiceImpl(), localStorageDict); |
|
| 38 | + context.registerService(FileStorageService.class, new LocalFileStorageServiceImpl(context), localStorageDict); |
|
| 39 | 39 | |
| 40 | 40 | // register mgmt service |
| 41 | 41 | FileStorageManagementServiceImpl mgmtService = new FileStorageManagementServiceImpl( |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/AmazonS3FileStorageServiceImpl.java
| ... | ... | @@ -9,6 +9,7 @@ import java.util.logging.Logger; |
| 9 | 9 | |
| 10 | 10 | import org.apache.shiro.SecurityUtils; |
| 11 | 11 | import org.apache.shiro.authz.UnauthorizedException; |
| 12 | +import org.osgi.framework.BundleContext; |
|
| 12 | 13 | |
| 13 | 14 | import com.amazonaws.AmazonClientException; |
| 14 | 15 | import com.amazonaws.auth.AWSCredentials; |
| ... | ... | @@ -53,8 +54,8 @@ public class AmazonS3FileStorageServiceImpl extends BaseFileStorageServiceImpl i |
| 53 | 54 | private final FileStorageServicePropertyImpl bucketName = new FileStorageServicePropertyImpl("bucketName", true, |
| 54 | 55 | "s3BucketNameDesc"); |
| 55 | 56 | |
| 56 | - public AmazonS3FileStorageServiceImpl() { |
|
| 57 | - super(NAME, "s3Desc"); |
|
| 57 | + public AmazonS3FileStorageServiceImpl(BundleContext bundleContext) { |
|
| 58 | + super(NAME, "s3Desc", bundleContext); |
|
| 58 | 59 | addProperties(accessId, accessKey, bucketName); |
| 59 | 60 | } |
| 60 | 61 | |
| ... | ... | @@ -98,48 +99,42 @@ public class AmazonS3FileStorageServiceImpl extends BaseFileStorageServiceImpl i |
| 98 | 99 | final ObjectMetadata metadata = new ObjectMetadata(); |
| 99 | 100 | metadata.setContentLength(lengthInBytes); |
| 100 | 101 | final String key = getKey(fileExtension); |
| 101 | - |
|
| 102 | - SecurityUtils.getSubject().checkPermission( |
|
| 103 | - SecuredDomainType.FILE_STORAGE.getStringPermissionForTypeRelativeIdentifier(DefaultActions.CREATE, |
|
| 104 | - new TypeRelativeObjectIdentifier(key))); |
|
| 105 | - |
|
| 106 | - final PutObjectRequest request = new PutObjectRequest(bucketName.getValue(), key, is, metadata) |
|
| 107 | - .withCannedAcl(CannedAccessControlList.PublicRead); |
|
| 108 | - final AmazonS3Client s3Client = createS3Client(); |
|
| 109 | - try { |
|
| 110 | - s3Client.putObject(request); |
|
| 111 | - } catch (AmazonClientException e) { |
|
| 112 | - logger.log(Level.SEVERE, "Could not store file", e); |
|
| 113 | - throw new OperationFailedException(e.getMessage(), e); |
|
| 114 | - } |
|
| 115 | - URI uri = getUri(key); |
|
| 116 | - logger.info("Stored file " + uri); |
|
| 117 | - return uri; |
|
| 102 | + return getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError( |
|
| 103 | + SecuredDomainType.FILE_STORAGE, new TypeRelativeObjectIdentifier(key), |
|
| 104 | + key, () -> { |
|
| 105 | + final PutObjectRequest request = new PutObjectRequest(bucketName.getValue(), key, is, metadata) |
|
| 106 | + .withCannedAcl(CannedAccessControlList.PublicRead); |
|
| 107 | + final AmazonS3Client s3Client = createS3Client(); |
|
| 108 | + try { |
|
| 109 | + s3Client.putObject(request); |
|
| 110 | + } catch (AmazonClientException e) { |
|
| 111 | + logger.log(Level.SEVERE, "Could not store file", e); |
|
| 112 | + throw new OperationFailedException(e.getMessage(), e); |
|
| 113 | + } |
|
| 114 | + URI uri = getUri(key); |
|
| 115 | + logger.info("Stored file " + uri); |
|
| 116 | + return uri; |
|
| 117 | + }); |
|
| 118 | 118 | } |
| 119 | 119 | |
| 120 | 120 | @Override |
| 121 | 121 | public void removeFile(URI uri) throws InvalidPropertiesException, OperationFailedException, UnauthorizedException { |
| 122 | 122 | String key = uri.getPath().substring(uri.getPath().lastIndexOf("/")+1); |
| 123 | - |
|
| 124 | - SecurityUtils.getSubject().checkPermission( |
|
| 125 | - SecuredDomainType.FILE_STORAGE.getStringPermissionForTypeRelativeIdentifier(DefaultActions.DELETE, |
|
| 126 | - new TypeRelativeObjectIdentifier(key))); |
|
| 127 | - |
|
| 128 | - AmazonS3Client s3Client = createS3Client(); |
|
| 129 | - |
|
| 130 | - try { |
|
| 131 | - s3Client.deleteObject(new DeleteObjectRequest(bucketName.getValue(), key)); |
|
| 132 | - } catch (AmazonClientException e) { |
|
| 133 | - throw new OperationFailedException("Could not remove file " + uri.toString(), e); |
|
| 134 | - } |
|
| 135 | - logger.info("Removed file " + uri); |
|
| 123 | + getSecurityService().checkPermissionAndDeleteOwnershipForObjectRemoval(SecuredDomainType.FILE_STORAGE.getQualifiedObjectIdentifier( |
|
| 124 | + new TypeRelativeObjectIdentifier(key)), () -> { |
|
| 125 | + AmazonS3Client s3Client = createS3Client(); |
|
| 126 | + try { |
|
| 127 | + s3Client.deleteObject(new DeleteObjectRequest(bucketName.getValue(), key)); |
|
| 128 | + } catch (AmazonClientException e) { |
|
| 129 | + throw new OperationFailedException("Could not remove file " + uri.toString(), e); |
|
| 130 | + } |
|
| 131 | + logger.info("Removed file " + uri); |
|
| 132 | + }); |
|
| 136 | 133 | } |
| 137 | 134 | |
| 138 | 135 | @Override |
| 139 | 136 | public void testProperties() throws InvalidPropertiesException { |
| 140 | 137 | AmazonS3Client s3 = createS3Client(); |
| 141 | - |
|
| 142 | - |
|
| 143 | 138 | if (bucketName.getValue().equals("")) { |
| 144 | 139 | throw new InvalidPropertiesException("empty bucketname is not allowed"); |
| 145 | 140 | } |
| ... | ... | @@ -152,7 +147,6 @@ public class AmazonS3FileStorageServiceImpl extends BaseFileStorageServiceImpl i |
| 152 | 147 | new Pair<FileStorageServiceProperty, String>(accessId, "seems to be invalid"), |
| 153 | 148 | new Pair<FileStorageServiceProperty, String>(accessKey, "seems to be invalid")); |
| 154 | 149 | } |
| 155 | - |
|
| 156 | 150 | // test if bucket exists |
| 157 | 151 | if (!s3.doesBucketExist(bucketName.getValue())) { |
| 158 | 152 | throw new InvalidPropertiesException("invalid bucket", new Pair<FileStorageServiceProperty, String>( |
| ... | ... | @@ -163,9 +157,8 @@ public class AmazonS3FileStorageServiceImpl extends BaseFileStorageServiceImpl i |
| 163 | 157 | @Override |
| 164 | 158 | public void doPermissionCheckForGetFile(URI uri) throws UnauthorizedException { |
| 165 | 159 | String key = uri.getPath().substring(uri.getPath().lastIndexOf("/") + 1); |
| 166 | - |
|
| 167 | 160 | SecurityUtils.getSubject().checkPermission( |
| 168 | - SecuredDomainType.FILE_STORAGE.getStringPermissionForTypeRelativeIdentifier(DefaultActions.DELETE, |
|
| 161 | + SecuredDomainType.FILE_STORAGE.getStringPermissionForTypeRelativeIdentifier(DefaultActions.READ, |
|
| 169 | 162 | new TypeRelativeObjectIdentifier(key))); |
| 170 | 163 | } |
| 171 | 164 | } |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/BaseFileStorageServiceImpl.java
| ... | ... | @@ -4,20 +4,35 @@ import java.util.LinkedHashMap; |
| 4 | 4 | import java.util.Locale; |
| 5 | 5 | import java.util.Map; |
| 6 | 6 | |
| 7 | +import org.osgi.framework.BundleContext; |
|
| 8 | +import org.osgi.util.tracker.ServiceTracker; |
|
| 9 | + |
|
| 7 | 10 | import com.sap.sse.common.IsManagedByCache; |
| 8 | 11 | import com.sap.sse.filestorage.FileStorageService; |
| 9 | 12 | import com.sap.sse.filestorage.FileStorageServiceProperty; |
| 10 | 13 | import com.sap.sse.filestorage.FileStorageServiceResolver; |
| 14 | +import com.sap.sse.security.SecurityService; |
|
| 15 | +import com.sap.sse.util.ServiceTrackerFactory; |
|
| 11 | 16 | |
| 12 | 17 | public abstract class BaseFileStorageServiceImpl implements FileStorageService { |
| 13 | 18 | private static final long serialVersionUID = 7787261863522200165L; |
| 14 | 19 | private final String name; |
| 15 | 20 | private final String descriptionKey; |
| 16 | 21 | protected final Map<String, FileStorageServicePropertyImpl> propertiesByNameInInsertionOrder = new LinkedHashMap<>(); |
| 22 | + private final ServiceTracker<SecurityService, SecurityService> securityServiceTracker; |
|
| 17 | 23 | |
| 18 | - protected BaseFileStorageServiceImpl(String name, String descriptionKey) { |
|
| 24 | + protected BaseFileStorageServiceImpl(String name, String descriptionKey, BundleContext bundleContext) { |
|
| 19 | 25 | this.name = name; |
| 20 | 26 | this.descriptionKey = descriptionKey; |
| 27 | + this.securityServiceTracker = bundleContext == null ? null : ServiceTrackerFactory.createAndOpen(bundleContext, SecurityService.class); |
|
| 28 | + } |
|
| 29 | + |
|
| 30 | + protected SecurityService getSecurityService() { |
|
| 31 | + try { |
|
| 32 | + return securityServiceTracker.waitForService(0); |
|
| 33 | + } catch (InterruptedException e) { |
|
| 34 | + throw new RuntimeException(e); |
|
| 35 | + } |
|
| 21 | 36 | } |
| 22 | 37 | |
| 23 | 38 | protected void addProperties(FileStorageServicePropertyImpl... properties) { |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/LocalFileStorageServiceImpl.java
| ... | ... | @@ -15,6 +15,7 @@ import java.util.logging.Logger; |
| 15 | 15 | import org.apache.commons.io.IOUtils; |
| 16 | 16 | import org.apache.shiro.SecurityUtils; |
| 17 | 17 | import org.apache.shiro.authz.UnauthorizedException; |
| 18 | +import org.osgi.framework.BundleContext; |
|
| 18 | 19 | |
| 19 | 20 | import com.sap.sailing.domain.common.security.SecuredDomainType; |
| 20 | 21 | import com.sap.sse.common.Util.Pair; |
| ... | ... | @@ -54,44 +55,38 @@ public class LocalFileStorageServiceImpl extends BaseFileStorageServiceImpl impl |
| 54 | 55 | private final FileStorageServicePropertyImpl localPath = new FileStorageServicePropertyImpl("localPath", true, "localLocalPathDesc"); |
| 55 | 56 | |
| 56 | 57 | |
| 57 | - protected LocalFileStorageServiceImpl() { |
|
| 58 | - super(NAME, "localDesc"); |
|
| 58 | + protected LocalFileStorageServiceImpl(BundleContext bundleContext) { |
|
| 59 | + super(NAME, "localDesc", bundleContext); |
|
| 59 | 60 | addProperties(baseURL, localPath); |
| 60 | 61 | } |
| 61 | 62 | |
| 62 | 63 | @Override |
| 63 | 64 | public URI storeFile(InputStream is, String fileExtension, long lengthInBytes) |
| 64 | 65 | throws IOException, UnauthorizedException { |
| 65 | - OutputStream outputStream = null; |
|
| 66 | 66 | String fileName = getKey(fileExtension); |
| 67 | 67 | String pathToFile = localPath.getValue() + "/" + fileName; |
| 68 | - SecurityUtils.getSubject().checkPermission( |
|
| 69 | - SecuredDomainType.FILE_STORAGE.getStringPermissionForTypeRelativeIdentifier(DefaultActions.CREATE, |
|
| 70 | - new TypeRelativeObjectIdentifier(pathToFile))); |
|
| 71 | - |
|
| 72 | - File outputFile = new File(pathToFile); |
|
| 73 | - logger.log(Level.FINE, "Storing file in " + outputFile.getAbsolutePath()); |
|
| 74 | - outputStream = new FileOutputStream(outputFile); |
|
| 75 | - |
|
| 76 | - try { |
|
| 77 | - int read = 0; |
|
| 78 | - byte[] bytes = new byte[1024]; |
|
| 79 | - |
|
| 80 | - while ((read = is.read(bytes)) != -1) { |
|
| 81 | - outputStream.write(bytes, 0, read); |
|
| 82 | - } |
|
| 83 | - |
|
| 84 | - } finally { |
|
| 85 | - if (is != null) { |
|
| 86 | - is.close(); |
|
| 87 | - } |
|
| 88 | - if (outputStream != null) { |
|
| 89 | - outputStream.flush(); |
|
| 90 | - outputStream.close(); |
|
| 91 | - } |
|
| 92 | - } |
|
| 93 | - |
|
| 94 | - return getUri(fileName); |
|
| 68 | + return getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError(SecuredDomainType.FILE_STORAGE, |
|
| 69 | + new TypeRelativeObjectIdentifier(pathToFile), pathToFile, () -> { |
|
| 70 | + final File outputFile = new File(pathToFile); |
|
| 71 | + logger.log(Level.FINE, "Storing file in " + outputFile.getAbsolutePath()); |
|
| 72 | + final OutputStream outputStream = new FileOutputStream(outputFile); |
|
| 73 | + try { |
|
| 74 | + int read = 0; |
|
| 75 | + byte[] bytes = new byte[1024]; |
|
| 76 | + while ((read = is.read(bytes)) != -1) { |
|
| 77 | + outputStream.write(bytes, 0, read); |
|
| 78 | + } |
|
| 79 | + } finally { |
|
| 80 | + if (is != null) { |
|
| 81 | + is.close(); |
|
| 82 | + } |
|
| 83 | + if (outputStream != null) { |
|
| 84 | + outputStream.flush(); |
|
| 85 | + outputStream.close(); |
|
| 86 | + } |
|
| 87 | + } |
|
| 88 | + return getUri(fileName); |
|
| 89 | + }); |
|
| 95 | 90 | } |
| 96 | 91 | |
| 97 | 92 | private static String getKey(String fileEnding) { |
| ... | ... | @@ -118,16 +113,13 @@ public class LocalFileStorageServiceImpl extends BaseFileStorageServiceImpl impl |
| 118 | 113 | if (!file.exists()) { |
| 119 | 114 | throw new FileNotFoundException(uri.toString()); |
| 120 | 115 | } |
| 121 | - |
|
| 122 | - SecurityUtils.getSubject() |
|
| 123 | - .checkPermission(SecuredDomainType.FILE_STORAGE.getStringPermissionForTypeRelativeIdentifier( |
|
| 124 | - DefaultActions.DELETE, |
|
| 125 | - new TypeRelativeObjectIdentifier(pathToFile))); |
|
| 126 | - |
|
| 127 | - if (!file.delete()) { |
|
| 128 | - logger.warning("Could not delete file with path " + filePath); |
|
| 129 | - throw new IOException("Could not delete file with path "+filePath); |
|
| 130 | - } |
|
| 116 | + getSecurityService().checkPermissionAndDeleteOwnershipForObjectRemoval(SecuredDomainType.FILE_STORAGE. |
|
| 117 | + getQualifiedObjectIdentifier(new TypeRelativeObjectIdentifier(pathToFile)), () -> { |
|
| 118 | + if (!file.delete()) { |
|
| 119 | + logger.warning("Could not delete file with path " + filePath); |
|
| 120 | + throw new IOException("Could not delete file with path "+filePath); |
|
| 121 | + } |
|
| 122 | + }); |
|
| 131 | 123 | } |
| 132 | 124 | |
| 133 | 125 | @Override |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/testsupport/AmazonS3TestSupport.java
| ... | ... | @@ -2,14 +2,22 @@ package com.sap.sse.filestorage.testsupport; |
| 2 | 2 | |
| 3 | 3 | import com.sap.sse.filestorage.InvalidPropertiesException; |
| 4 | 4 | import com.sap.sse.filestorage.impl.AmazonS3FileStorageServiceImpl; |
| 5 | +import com.sap.sse.security.SecurityService; |
|
| 5 | 6 | |
| 6 | 7 | public class AmazonS3TestSupport { |
| 7 | 8 | public static final String s3AccessId = "AKIAJOX7PZ6ACI2FQU4A"; |
| 8 | 9 | public static final String s3AccessKey = "NkijH2DfhWgb9fmESPjpeIbpUF+tC220KyTOfvGJ"; |
| 9 | 10 | private static final String s3BucketName = "sapsailing-automatic-upload-test"; |
| 10 | 11 | |
| 11 | - public static AmazonS3FileStorageServiceImpl createService() throws InvalidPropertiesException { |
|
| 12 | - AmazonS3FileStorageServiceImpl service = new AmazonS3FileStorageServiceImpl(); |
|
| 12 | + public static AmazonS3FileStorageServiceImpl createService(final SecurityService securityService) throws InvalidPropertiesException { |
|
| 13 | + AmazonS3FileStorageServiceImpl service = new AmazonS3FileStorageServiceImpl(/* bundleContext */ null) { |
|
| 14 | + private static final long serialVersionUID = 6887160074291578082L; |
|
| 15 | + |
|
| 16 | + @Override |
|
| 17 | + protected SecurityService getSecurityService() { |
|
| 18 | + return securityService; |
|
| 19 | + } |
|
| 20 | + }; |
|
| 13 | 21 | service.internalSetProperty("accessId", s3AccessId); |
| 14 | 22 | service.internalSetProperty("accessKey", s3AccessKey); |
| 15 | 23 | service.internalSetProperty("bucketName", s3BucketName); |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/testsupport/DummyFileStorageService.java
| ... | ... | @@ -21,7 +21,7 @@ public class DummyFileStorageService extends BaseFileStorageServiceImpl implemen |
| 21 | 21 | private static final long serialVersionUID = -3871744982404841496L; |
| 22 | 22 | |
| 23 | 23 | public DummyFileStorageService() { |
| 24 | - super(NAME, ""); |
|
| 24 | + super(NAME, "", /* bundleContext */ null); |
|
| 25 | 25 | addProperties(property); |
| 26 | 26 | } |
| 27 | 27 |
java/com.sap.sse.security.testsupport/.classpath
| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<classpath> |
|
| 3 | + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> |
|
| 4 | + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> |
|
| 5 | + <classpathentry kind="src" path="src"/> |
|
| 6 | + <classpathentry kind="output" path="bin"/> |
|
| 7 | +</classpath> |
java/com.sap.sse.security.testsupport/.project
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<projectDescription> |
|
| 3 | + <name>com.sap.sse.security.testsupport</name> |
|
| 4 | + <comment></comment> |
|
| 5 | + <projects> |
|
| 6 | + </projects> |
|
| 7 | + <buildSpec> |
|
| 8 | + <buildCommand> |
|
| 9 | + <name>org.eclipse.jdt.core.javabuilder</name> |
|
| 10 | + <arguments> |
|
| 11 | + </arguments> |
|
| 12 | + </buildCommand> |
|
| 13 | + <buildCommand> |
|
| 14 | + <name>org.eclipse.pde.ManifestBuilder</name> |
|
| 15 | + <arguments> |
|
| 16 | + </arguments> |
|
| 17 | + </buildCommand> |
|
| 18 | + <buildCommand> |
|
| 19 | + <name>org.eclipse.pde.SchemaBuilder</name> |
|
| 20 | + <arguments> |
|
| 21 | + </arguments> |
|
| 22 | + </buildCommand> |
|
| 23 | + </buildSpec> |
|
| 24 | + <natures> |
|
| 25 | + <nature>org.eclipse.pde.PluginNature</nature> |
|
| 26 | + <nature>org.eclipse.jdt.core.javanature</nature> |
|
| 27 | + </natures> |
|
| 28 | +</projectDescription> |
java/com.sap.sse.security.testsupport/.settings/org.eclipse.jdt.core.prefs
| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | +eclipse.preferences.version=1 |
|
| 2 | +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled |
|
| 3 | +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 |
|
| 4 | +org.eclipse.jdt.core.compiler.compliance=1.8 |
|
| 5 | +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error |
|
| 6 | +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error |
|
| 7 | +org.eclipse.jdt.core.compiler.source=1.8 |
java/com.sap.sse.security.testsupport/.settings/org.eclipse.pde.core.prefs
| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | +eclipse.preferences.version=1 |
|
| 2 | +pluginProject.extensions=false |
|
| 3 | +resolve.requirebundle=false |
java/com.sap.sse.security.testsupport/META-INF/MANIFEST.MF
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +Manifest-Version: 1.0 |
|
| 2 | +Bundle-ManifestVersion: 2 |
|
| 3 | +Bundle-Name: Testsupport |
|
| 4 | +Bundle-SymbolicName: com.sap.sse.security.testsupport |
|
| 5 | +Bundle-Version: 1.0.0.qualifier |
|
| 6 | +Bundle-Vendor: SAP |
|
| 7 | +Automatic-Module-Name: com.sap.sse.security.testsupport |
|
| 8 | +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
|
| 9 | +Require-Bundle: com.sap.sse.security, |
|
| 10 | + org.mockito.mockito-core;bundle-version="1.10.14", |
|
| 11 | + com.sap.sse.common |
|
| 12 | +Export-Package: com.sap.sse.security.testsupport |
java/com.sap.sse.security.testsupport/build.properties
| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | +source.. = src/ |
|
| 2 | +output.. = bin/ |
|
| 3 | +bin.includes = META-INF/,\ |
|
| 4 | + . |
java/com.sap.sse.security.testsupport/pom.xml
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|
| 4 | + <modelVersion>4.0.0</modelVersion> |
|
| 5 | + <parent> |
|
| 6 | + <artifactId>root</artifactId> |
|
| 7 | + <groupId>com.sap.sailing</groupId> |
|
| 8 | + <version>1.0.0-SNAPSHOT</version> |
|
| 9 | + </parent> |
|
| 10 | + <artifactId>com.sap.sse.security.testsupport</artifactId> |
|
| 11 | + <packaging>eclipse-plugin</packaging> |
|
| 12 | +</project> |
java/com.sap.sse.security.testsupport/src/com/sap/sse/security/testsupport/SecurityServiceMockFactory.java
| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | +package com.sap.sse.security.testsupport; |
|
| 2 | + |
|
| 3 | +import java.util.UUID; |
|
| 4 | +import java.util.concurrent.Callable; |
|
| 5 | + |
|
| 6 | +import org.mockito.Mockito; |
|
| 7 | +import org.mockito.invocation.InvocationOnMock; |
|
| 8 | +import org.mockito.stubbing.Answer; |
|
| 9 | + |
|
| 10 | +import com.sap.sse.security.Action; |
|
| 11 | +import com.sap.sse.security.SecurityService; |
|
| 12 | +import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; |
|
| 13 | +import com.sap.sse.security.shared.impl.UserGroupImpl; |
|
| 14 | + |
|
| 15 | +public class SecurityServiceMockFactory { |
|
| 16 | + @SuppressWarnings("unchecked") |
|
| 17 | + public static SecurityService mockSecurityService() { |
|
| 18 | + UserGroupImpl defaultTenant = new UserGroupImpl(new UUID(0, 1), "defaultTenant"); |
|
| 19 | + final SecurityService result = Mockito.mock(SecurityService.class); |
|
| 20 | + Mockito.doReturn(defaultTenant).when(result).getDefaultTenant(); |
|
| 21 | + Mockito.doAnswer(new Answer<Object>() { |
|
| 22 | + @Override |
|
| 23 | + public Object answer(InvocationOnMock invocation) throws Throwable { |
|
| 24 | + return invocation.getArgumentAt(4, Callable.class).call(); |
|
| 25 | + } |
|
| 26 | + }).when(result).setOwnershipCheckPermissionForObjectCreationAndRevertOnError( |
|
| 27 | + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(Action.class)); |
|
| 28 | + Mockito.doAnswer(new Answer<Object>() { |
|
| 29 | + @SuppressWarnings("rawtypes") |
|
| 30 | + @Override |
|
| 31 | + public Object answer(InvocationOnMock invocation) throws Throwable { |
|
| 32 | + for (Object arg : invocation.getArguments()) { |
|
| 33 | + if (arg instanceof Callable) { |
|
| 34 | + return ((Callable) arg).call(); |
|
| 35 | + } |
|
| 36 | + } |
|
| 37 | + return null; |
|
| 38 | + } |
|
| 39 | + }).when(result).setOwnershipCheckPermissionForObjectCreationAndRevertOnError(Mockito.any(), |
|
| 40 | + Mockito.any(), Mockito.any(), Mockito.any(Callable.class)); |
|
| 41 | + Mockito.doReturn(true).when(result) |
|
| 42 | + .hasCurrentUserReadPermission(Mockito.any(WithQualifiedObjectIdentifier.class)); |
|
| 43 | + Mockito.doNothing().when(result).checkCurrentUserReadPermission(Mockito.any()); |
|
| 44 | + return result; |
|
| 45 | + } |
|
| 46 | +} |
java/pom.xml
| ... | ... | @@ -174,6 +174,7 @@ |
| 174 | 174 | <module>com.sap.sse.gwt.test</module> |
| 175 | 175 | <module>com.sap.sse.datamining.test</module> |
| 176 | 176 | <module>com.sap.sse.security.replication.test</module> |
| 177 | + <module>com.sap.sse.security.testsupport</module> |
|
| 177 | 178 | <module>com.sap.sse.security.test</module> |
| 178 | 179 | <module>com.sap.sse.operationaltransformation.test</module> |
| 179 | 180 | <module>com.sap.sse.common.test</module> |
wiki/info/security/permission-migration-tests.md
| ... | ... | @@ -27,9 +27,11 @@ Any permissions directly or indirectly associated with the <all> user will be us |
| 27 | 27 | All pre existing users will receive the following additions: |
| 28 | 28 | |
| 29 | 29 | * A group named by the user with suffix "-tenant" is created. |
| 30 | +* The new group owns itself; the user is the group's owning user. |
|
| 30 | 31 | * The user is a member of the newly created tenant group |
| 31 | 32 | * The user is the owner of itself and the associated group |
| 32 | -* The user has the role "user" qualified by the user itself but without a group qualification |
|
| 33 | +* The user has the role "user" qualified by the user itself |
|
| 34 | +* The user has another role "user" qualified by the newly created tenant group as a group qualification |
|
| 33 | 35 | |
| 34 | 36 | ### User called "admin" |
| 35 | 37 | |
| ... | ... | @@ -51,14 +53,14 @@ There are several RoleDefinitions that are automatically created for new or migr |
| 51 | 53 | |
| 52 | 54 | These roles are system roles that are intended to be used by any user. To ensure this, an ACL entry is generated for those roles granting action "READ" to the null group (all users). |
| 53 | 55 | |
| 54 | -Most of those default RoleDefinitions also had role with the same name in the old role model (all but sailing_viewer). On existing servers, users having any old role, need to get an equivalent role associated. Any user having one of these old roles (excluding the "admin" case described below) will have the new version of this role qualified by the server's default group associated. |
|
| 56 | +Most of those default RoleDefinitions also had a role with the same name in the old role model (all but sailing_viewer). On existing servers, users having any old role need to get an equivalent role associated. Any user having one of these old roles (excluding the "admin" case described below) will have the new version of this role qualified by the server's default group associated. |
|
| 55 | 57 | This means those users should still have equivalent permissions but only for objects owned by the mentioned server group. |
| 56 | 58 | |
| 57 | 59 | Any other role would be lost. This is most probably an unlikely case due to the fact that the old permission UI had no possibility to define new roles. |
| 58 | 60 | |
| 59 | 61 | ### Tenants |
| 60 | 62 | |
| 61 | -Existing users (including the "admin" but excluding "<all>) will automatically get a UserGroup created named like the user with the suffix "-tenant". This means the admin's tenant is called "admin-tenant". |
|
| 63 | +Existing users (including the "admin" but excluding "<all>") will automatically get a UserGroup created named like the user with the suffix "-tenant". This means the admin's tenant is called "admin-tenant". |
|
| 62 | 64 | |
| 63 | 65 | ### Default creation tenant |
| 64 | 66 | |
| ... | ... | @@ -80,7 +82,7 @@ Any security and domain object being loaded will receive an initial ownership. T |
| 80 | 82 | |
| 81 | 83 | ### ACLs |
| 82 | 84 | |
| 83 | -The only ACLs that are automatically created on migration or server initialization are those to make the initial RoleDefinitions publicly readable. No other ACLs are intended to exist for new or initially migrated servers. |
|
| 85 | +The only ACLs that are automatically created on migration or server initialization are those to make the initial RoleDefinitions publicly readable. No other ACLs are intended to exist for new or initially migrated server. |
|
| 84 | 86 | |
| 85 | 87 | ### Users having specific permissions |
| 86 | 88 |
wiki/info/security/security-end-user-docs.md