From b54a824f9683aab21d7e2cb13280957bec3263c5 Mon Sep 17 00:00:00 2001 From: Alessandro Stoltenberg Date: Mon, 26 Nov 2018 18:27:23 +0100 Subject: [PATCH 01/27] bug4806: Added equalsWithNull for TagInputPanel.compareFieldsToTag and compareFieldsToTagButton --- .../gwt/ui/raceboard/tagging/TagInputPanel.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TagInputPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TagInputPanel.java index e8eba9a498e..fd1f9b53e85 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TagInputPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/tagging/TagInputPanel.java @@ -12,6 +12,7 @@ import com.sap.sailing.domain.common.dto.TagDTO; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.raceboard.tagging.TaggingPanelResources.TagPanelStyle; +import com.sap.sse.common.Util; import com.sap.sse.gwt.adminconsole.URLFieldWithFileUpload; import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; @@ -266,8 +267,10 @@ public class TagInputPanel extends FlowPanel { * false */ protected boolean compareFieldsToTag(TagDTO tag) { - return tag != null && getTag().equals(tag.getTag()) && getComment().equals(tag.getComment()) - && getImageURL().equals(tag.getImageURL()) && isVisibleForPublic() == tag.isVisibleForPublic(); + return tag != null && getTag().equals(tag.getTag()) && Util.equalsWithNull(getComment(), tag.getComment()) + && (Util.equalsWithNull(getImageURL(), tag.getImageURL()) + || (getImageURL() == null && tag.getImageURL() == "")) + && isVisibleForPublic() == tag.isVisibleForPublic(); } /** @@ -279,8 +282,9 @@ public class TagInputPanel extends FlowPanel { * false */ protected boolean compareFieldsToTagButton(TagButton tagButton) { - return tagButton != null && getTag().equals(tagButton.getTag()) && getComment().equals(tagButton.getComment()) - && getImageURL().equals(tagButton.getImageURL()) + return tagButton != null && getTag().equals(tagButton.getTag()) && Util.equalsWithNull(getComment(), tagButton.getComment()) + && (Util.equalsWithNull(getImageURL(), tagButton.getImageURL()) + || (getImageURL() == null && tagButton.getImageURL() == "")) && isVisibleForPublic() == tagButton.isVisibleForPublic(); } From 34454f7d3fb99b3e2555d3b429eb8103c4a5be96 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Tue, 27 Nov 2018 11:22:28 +0100 Subject: [PATCH 02/27] add ownership on converting to BoatDTO --- .../java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index ec0b9dd74f4..103305da626 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1297,6 +1297,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S List result = new ArrayList(); for (Boat b : iterable) { BoatDTO boatDTO = baseDomainFactory.convertToBoatDTO(b); + SecurityDTOUtil.addSecurityInformation(getSecurityService(), boatDTO, b.getIdentifier()); result.add(boatDTO); } return result; From 14ac8ad3a618f8359b89cadd163b0846a017bab3 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Tue, 27 Nov 2018 15:20:16 +0100 Subject: [PATCH 03/27] on anynomous usr regsitration set ownership for competitor and boat to same ownership as regatta --- .../test/jaxrs/AbstractJaxRsApiTest.java | 14 +++- .../test/jaxrs/RegattasResourceTest.java | 41 ++++++++--- .../gateway/jaxrs/api/RegattasResource.java | 72 +++++++++++++------ 3 files changed, 90 insertions(+), 37 deletions(-) diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java index 82151740b97..9b801f7f250 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java @@ -41,8 +41,12 @@ import com.sap.sse.mongodb.MongoDBService; import com.sap.sse.security.Action; import com.sap.sse.security.ActionWithResult; import com.sap.sse.security.SecurityService; +import com.sap.sse.security.UserImpl; +import com.sap.sse.security.shared.Ownership; +import com.sap.sse.security.shared.OwnershipAnnotation; import com.sap.sse.security.shared.User; import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; +import com.sap.sse.security.shared.impl.OwnershipImpl; import com.sap.sse.security.shared.impl.UserGroupImpl; public abstract class AbstractJaxRsApiTest { @@ -94,9 +98,8 @@ public abstract class AbstractJaxRsApiTest { } return null; } - }).when(securityService).setOwnershipCheckPermissionForObjectCreationAndRevertOnError( - Mockito.any(), Mockito.any(), Mockito.any(), - Mockito.any(ActionWithResult.class)); + }).when(securityService).setOwnershipCheckPermissionForObjectCreationAndRevertOnError(Mockito.any(), + Mockito.any(), Mockito.any(), Mockito.any(ActionWithResult.class)); Mockito.doReturn(true).when(securityService) .hasCurrentUserReadPermission(Mockito.any(WithQualifiedObjectIdentifier.class)); @@ -105,6 +108,11 @@ public abstract class AbstractJaxRsApiTest { Mockito.doReturn(true).when(fakeSubject).isAuthenticated(); + OwnershipAnnotation mockedOwnership = Mockito.mock(OwnershipAnnotation.class); + Ownership ownership = Mockito.mock(Ownership.class); + Mockito.doReturn(mockedOwnership).when(securityService).getOwnership(Mockito.any()); + Mockito.doReturn(ownership).when(mockedOwnership).getAnnotation(); + eventsResource = spyResource(new DummyEventsRessource()); doReturn(getSecurityService()).when(eventsResource).getSecurityService(); diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java index 08ba94ebbec..9914839040e 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java @@ -42,10 +42,12 @@ import com.sap.sailing.domain.base.impl.SeriesImpl; import com.sap.sailing.domain.common.CompetitorRegistrationType; import com.sap.sailing.domain.common.RegattaName; import com.sap.sailing.domain.common.ScoringSchemeType; +import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sailing.domain.ranking.OneDesignRankingMetric; import com.sap.sse.common.Color; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.security.ActionWithResult; import com.sap.sse.security.SecurityService; import com.sap.sse.security.UserImpl; import com.sap.sse.security.shared.Account; @@ -82,17 +84,34 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { Series testSeries = new SeriesImpl("TestSeries", /* isMedal */false, /* isFleetsCanRunInParallel */ true, fleets, raceColumnNames, /* trackedRegattaRegistry */null); series.add(testSeries); - racingEventService.createRegatta(closedRegattaName, boatClassName, - /* canBoatsOfCompetitorsChangePerRace */ true, CompetitorRegistrationType.CLOSED, - /* registrationLinkSecret */ null, startDate, endDate, UUID.randomUUID(), series, /* persistent */ true, - DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, - /* buoyZoneRadiusInHullLengths */2.0, /* useStartTimeInference */ true, - /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new); - racingEventService.createRegatta(openRegattaName, boatClassName, /* canBoatsOfCompetitorsChangePerRace */ true, - CompetitorRegistrationType.OPEN_MODERATED, secret, startDate, endDate, UUID.randomUUID(), series, - /* persistent */ true, DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, - /* buoyZoneRadiusInHullLengths */2.0, /* useStartTimeInference */ true, - /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new); + final UUID closedRegattaUuid = UUID.randomUUID(); + getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError(SecuredDomainType.REGATTA, + closedRegattaUuid.toString(), closedRegattaName, new ActionWithResult() { + @Override + public Regatta run() throws Exception { + return racingEventService.createRegatta(closedRegattaName, boatClassName, + /* canBoatsOfCompetitorsChangePerRace */ true, CompetitorRegistrationType.CLOSED, + /* registrationLinkSecret */ null, startDate, endDate, closedRegattaUuid, series, + /* persistent */ true, + DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, + /* buoyZoneRadiusInHullLengths */2.0, /* useStartTimeInference */ true, + /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new); + } + }); + final UUID openRegattaUuid = UUID.randomUUID(); + getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError(SecuredDomainType.REGATTA, + openRegattaUuid.toString(), openRegattaName, new ActionWithResult() { + @Override + public Regatta run() throws Exception { + return racingEventService.createRegatta(openRegattaName, boatClassName, + /* canBoatsOfCompetitorsChangePerRace */ true, + CompetitorRegistrationType.OPEN_MODERATED, secret, startDate, endDate, + UUID.randomUUID(), series, /* persistent */ true, + DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT), null, + /* buoyZoneRadiusInHullLengths */2.0, /* useStartTimeInference */ true, + /* controlTrackingFromStartAndFinishTimes */ false, OneDesignRankingMetric::new); + } + }); testSeries.addRaceColumn("R1", /* trackedRegattaRegistry */ null); testSeries.addRaceColumn("R2", /* trackedRegattaRegistry */ null); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index e9ab7e4b7ae..545bde08268 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -139,6 +139,8 @@ import com.sap.sse.common.util.RoundingUtil; import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier; import com.sap.sse.security.ActionWithResult; import com.sap.sse.security.shared.HasPermissions.DefaultActions; +import com.sap.sse.security.shared.Ownership; +import com.sap.sse.security.shared.OwnershipAnnotation; import com.sap.sse.security.shared.User; @Path("/v1/regattas") @@ -370,7 +372,8 @@ public class RegattasResource extends AbstractSailingServerResource { final User user = getSecurityService().getCurrentUser(); Response response; final Regatta regatta = findRegattaByName(regattaName); - if (regatta == null) { + OwnershipAnnotation regattaOwnerShipAnnotation = getSecurityService().getOwnership(regatta.getIdentifier()); + if (regatta == null || regattaOwnerShipAnnotation == null) { return getBadRegattaErrorResponse(regattaName); } boolean registerCompetitor = false; @@ -478,20 +481,37 @@ public class RegattasResource extends AbstractSailingServerResource { final String name = eCompetitorName; final String shortName = eCompetitorShortName; final String email = eCompetitorEmail; - final CompetitorWithBoat competitor = getSecurityService() - .setOwnershipCheckPermissionForObjectCreationAndRevertOnError(SecuredDomainType.COMPETITOR, - competitorUuid.toString(), name, new ActionWithResult() { - @Override - public CompetitorWithBoat run() throws Exception { - return getService().getCompetitorAndBoatStore().getOrCreateCompetitorWithBoat( - competitorUuid, name, shortName, color, - email, flagImageURI, team, timeOnTimeFactor, - timeOnDistanceAllowancePerNauticalMileAsMillis == null ? null - : new MillisecondsDurationImpl( - timeOnDistanceAllowancePerNauticalMileAsMillis), - searchTag, boat); - } - }); + final CompetitorWithBoat competitor; + if (subject.isAuthenticated()) { + competitor = getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError( + SecuredDomainType.COMPETITOR, competitorUuid.toString(), name, + new ActionWithResult() { + @Override + public CompetitorWithBoat run() throws Exception { + return getService().getCompetitorAndBoatStore().getOrCreateCompetitorWithBoat( + competitorUuid, name, shortName, color, email, flagImageURI, team, + timeOnTimeFactor, + timeOnDistanceAllowancePerNauticalMileAsMillis == null ? null + : new MillisecondsDurationImpl( + timeOnDistanceAllowancePerNauticalMileAsMillis), + searchTag, boat); + } + }); + } else { + competitor = getService().getCompetitorAndBoatStore().getOrCreateCompetitorWithBoat(competitorUuid, + name, shortName, color, email, flagImageURI, team, timeOnTimeFactor, + timeOnDistanceAllowancePerNauticalMileAsMillis == null ? null + : new MillisecondsDurationImpl(timeOnDistanceAllowancePerNauticalMileAsMillis), + searchTag, boat); + getSecurityService().setOwnership(competitor.getIdentifier(), + (User) regattaOwnerShipAnnotation.getAnnotation().getUserOwner(), + regattaOwnerShipAnnotation.getAnnotation().getTenantOwner(), name); + if (getSecurityService().getOwnership(boat.getIdentifier()) == null) { + getSecurityService().setOwnership(boat.getIdentifier(), + (User) regattaOwnerShipAnnotation.getAnnotation().getUserOwner(), + regattaOwnerShipAnnotation.getAnnotation().getTenantOwner(), name); + } + } regatta.registerCompetitor(competitor); response = Response.ok(CompetitorJsonSerializer.create().serialize(competitor).toJSONString()) .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); @@ -538,15 +558,21 @@ public class RegattasResource extends AbstractSailingServerResource { private DynamicBoat createBoat(String name, String boatClassName, String sailId) { final UUID boatUUID = UUID.randomUUID(); - DynamicBoat boat = getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError( - SecuredDomainType.BOAT, boatUUID.toString(), name, new ActionWithResult() { + final DynamicBoat boat; + if (SecurityUtils.getSubject().isAuthenticated()) { + boat = getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError( + SecuredDomainType.BOAT, boatUUID.toString(), name, new ActionWithResult() { - @Override - public DynamicBoat run() throws Exception { - return new BoatImpl(boatUUID, name, getService().getBaseDomainFactory() - .getOrCreateBoatClass(boatClassName, /* typicallyStartsUpwind */ true), sailId); - } - }); + @Override + public DynamicBoat run() throws Exception { + return new BoatImpl(boatUUID, name, getService().getBaseDomainFactory() + .getOrCreateBoatClass(boatClassName, /* typicallyStartsUpwind */ true), sailId); + } + }); + } else { + boat = new BoatImpl(boatUUID, name, getService().getBaseDomainFactory().getOrCreateBoatClass(boatClassName, + /* typicallyStartsUpwind */ true), sailId); + } return boat; } From f73a6c7f30dce2036ad9eab70d17a591483d8f0b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 27 Nov 2018 15:49:29 +0100 Subject: [PATCH 04/27] offer additional java11-specific Hudson Slave launch script Change-Id: I05387802166e7a032d1c4d1fd8bb1a7f0e2f84cf --- configuration/launchhudsonslave-java11 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 configuration/launchhudsonslave-java11 diff --git a/configuration/launchhudsonslave-java11 b/configuration/launchhudsonslave-java11 new file mode 100755 index 00000000000..3e2d8f42257 --- /dev/null +++ b/configuration/launchhudsonslave-java11 @@ -0,0 +1,25 @@ +#!/bin/bash +AWS=/root/.local/bin/aws +REGION=eu-west-1 +HUDSON_SLAVE_AMI_ID=ami-0afdd1680ad31c094 +echo Launching instance... +instanceid=`$AWS ec2 run-instances --image-id $HUDSON_SLAVE_AMI_ID --count 1 --instance-type c5d.4xlarge --key-name Axel --security-groups "Sailing Analytics App" --region $REGION --placement AvailabilityZone=eu-west-1c --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Hudson Ubuntu Slave}]' --instance-initiated-shutdown-behavior terminate | tee /tmp/slavelaunch.out | jq .Instances[0].InstanceId | sed -e 's/"//g'` +if [ "$instanceid" = "" ]; then + echo Error launching instance + exit 1 +else + echo Instance ID is $instanceid + while [ "`$AWS ec2 describe-instances --region $REGION --instance-ids $instanceid | jq .Reservations[0].Instances[0].State.Name`" != "\"running\"" ]; do + echo Instance $instanceid not running yet\; trying again... + sleep 5 + done + echo Instance $instanceid seems running now + private_ip=`$AWS ec2 describe-instances --region $REGION --instance-ids $instanceid | jq .Reservations[0].Instances[0].PrivateIpAddress | sed -e 's/"//g'` + echo Probing for SSH on private IP $private_ip + while su - hudson -c "ssh -o ConnectTimeout=10,StrictHostKeyChecking=no hudson@$private_ip ls >/dev/null"; do + echo SSH daemon not reachable yet. Trying again... + done + echo SSH daemon reached. State should be ready to connect to now. + su - hudson -c "ssh -o StrictHostKeyChecking=no hudson@$private_ip \"/opt/sapjvm_8/bin/java -jar slave.jar; sudo /sbin/shutdown -h now\"" + $AWS ec2 terminate-instances --instance-ids $instanceid +fi From d101fa79dd803a7a560c7447e7118206c1c183cd Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 27 Nov 2018 16:12:53 +0100 Subject: [PATCH 05/27] give Java11 Hudson nodes a recognizable name Change-Id: I9de1a0c9ebab14f8ac06d9f02fdabf16b2a8fa4d --- configuration/launchhudsonslave-java11 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/launchhudsonslave-java11 b/configuration/launchhudsonslave-java11 index 3e2d8f42257..0dc430eef52 100755 --- a/configuration/launchhudsonslave-java11 +++ b/configuration/launchhudsonslave-java11 @@ -3,7 +3,7 @@ AWS=/root/.local/bin/aws REGION=eu-west-1 HUDSON_SLAVE_AMI_ID=ami-0afdd1680ad31c094 echo Launching instance... -instanceid=`$AWS ec2 run-instances --image-id $HUDSON_SLAVE_AMI_ID --count 1 --instance-type c5d.4xlarge --key-name Axel --security-groups "Sailing Analytics App" --region $REGION --placement AvailabilityZone=eu-west-1c --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Hudson Ubuntu Slave}]' --instance-initiated-shutdown-behavior terminate | tee /tmp/slavelaunch.out | jq .Instances[0].InstanceId | sed -e 's/"//g'` +instanceid=`$AWS ec2 run-instances --image-id $HUDSON_SLAVE_AMI_ID --count 1 --instance-type c5d.4xlarge --key-name Axel --security-groups "Sailing Analytics App" --region $REGION --placement AvailabilityZone=eu-west-1c --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=Hudson Ubuntu Slave Java 11}]' --instance-initiated-shutdown-behavior terminate | tee /tmp/slavelaunch.out | jq .Instances[0].InstanceId | sed -e 's/"//g'` if [ "$instanceid" = "" ]; then echo Error launching instance exit 1 From 78e4d09b88b8e796ada36b55c54e3bbbe938d83c Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 27 Nov 2018 17:08:31 +0100 Subject: [PATCH 06/27] Added methods in UserManagementService to allow overwriting existing ACLs and retrieve unpruned ACLs. --- .../ui/client/UserManagementService.java | 6 +++++ .../ui/client/UserManagementServiceAsync.java | 6 +++++ .../ui/server/UserManagementServiceImpl.java | 25 +++++++++++++++++++ .../com/sap/sse/security/SecurityService.java | 3 +++ .../security/impl/SecurityServiceImpl.java | 7 ++++++ 5 files changed, 47 insertions(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java index 597c31de976..a4a62275eab 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java @@ -146,4 +146,10 @@ public interface UserManagementService extends RemoteService { public Pair verifySocialUser(CredentialDTO credential) throws OAuthException; OwnershipAnnotation getOwnership(QualifiedObjectIdentifier idOfOwnedObject); + + AccessControlList overrideAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, + AccessControlList acl) throws UnauthorizedException; + + AccessControlList getAccessControlListWithoutPruning(QualifiedObjectIdentifier idOfAccessControlledObject) + throws UnauthorizedException; } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java index 7f88863d752..e0b22cdacdd 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java @@ -33,6 +33,12 @@ public interface UserManagementServiceAsync { void updateAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, Map> permissionStrings, AsyncCallback callback); + void getAccessControlListWithoutPruning(QualifiedObjectIdentifier idOfAccessControlledObject, + AsyncCallback updateAclAsyncCallback); + + void overrideAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, AccessControlList acl, + AsyncCallback updateAclAsyncCallback); + void addToAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, String permission, String name, AsyncCallback callback); void removeFromAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, String permission, String name, AsyncCallback callback); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java index d4dc2146955..1a5a5fa17d9 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java @@ -787,4 +787,29 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U public String getOrCreateAccessToken(String username) { return getSecurityService().getOrCreateAccessToken(username); } + + @Override + public AccessControlList overrideAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, + AccessControlList acl) throws UnauthorizedException { + if (SecurityUtils.getSubject() + .isPermitted(idOfAccessControlledObject.getStringPermission(DefaultActions.CHANGE_ACL))) { + + return securityDTOFactory.createAccessControlListDTO(getSecurityService() + .overrideAccessControlList(idOfAccessControlledObject, acl.getActionsByUserGroup())); + } else { + throw new UnauthorizedException("Not permitted to update the ACL for a user"); + } + } + + @Override + public AccessControlList getAccessControlListWithoutPruning(QualifiedObjectIdentifier idOfAccessControlledObject) throws UnauthorizedException { + if (SecurityUtils.getSubject() + .isPermitted(idOfAccessControlledObject.getStringPermission(DefaultActions.CHANGE_ACL))) { + return securityDTOFactory.createAccessControlListDTO( + getSecurityService().getAccessControlList(idOfAccessControlledObject).getAnnotation()); + } else { + throw new UnauthorizedException("Not permitted to get the unpruned ACL for a user"); + } + } + } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java b/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java index 8d19ac3b9eb..97d25ba6cd4 100755 --- a/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java @@ -77,6 +77,9 @@ public interface SecurityService extends ReplicableWithObjectInputStream> permissionMap); + AccessControlList overrideAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, + Map> permissionMap); + /** * @param name The name of the user group to add */ diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java b/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java index e275f5360ac..6614f272534 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java @@ -426,6 +426,13 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat return null; } + @Override + public AccessControlList overrideAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, + Map> permissionMap) { + accessControlStore.removeAccessControlList(idOfAccessControlledObject); + return updateAccessControlList(idOfAccessControlledObject, permissionMap); + } + @Override public AccessControlList updateAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, Map> permissionMap) { if (getAccessControlList(idOfAccessControlledObject) == null) { From 2594053b781098bfab6491a1662e4724414c97af Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 27 Nov 2018 17:09:24 +0100 Subject: [PATCH 07/27] added change-acl icon --- .../LeaderboardConfigImagesBarCell.java | 2 +- .../com/sap/sse/gwt/client/images/change-acl.png | Bin 0 -> 1150 bytes .../com/sap/sse/gwt/client/IconResources.java | 3 +++ .../component/DefaultActionsImagesBarCell.java | 7 ++++--- 4 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/change-acl.png diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigImagesBarCell.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigImagesBarCell.java index fba05f2afb8..1ef95a2fef6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigImagesBarCell.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigImagesBarCell.java @@ -32,7 +32,7 @@ public class LeaderboardConfigImagesBarCell extends DefaultActionsImagesBarCell resources.competitorsIcon()), new ImageSpec(ACTION_CONFIGURE_URL, stringMessages.actionConfigureUrl(), resources.settingsActionIcon()), - getDeleteImageSpec(), getChangeOwnershipImageSpec(), + getDeleteImageSpec(), getChangeOwnershipImageSpec(), getChangeACLImageSpec(), new ImageSpec(ACTION_EXPORT_XML, stringMessages.actionExportXML(), resources.exportXMLIcon()), new ImageSpec(ACTION_OPEN_COACH_DASHBOARD, stringMessages.actionOpenDashboard(), resources.openCoachDashboard()), diff --git a/java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/change-acl.png b/java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/change-acl.png new file mode 100644 index 0000000000000000000000000000000000000000..c938b1c13ade3abb43852342356fccae4ff929ef GIT binary patch literal 1150 zcmV-^1cCdBP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U=HGlIti8hTpY{SppIliREB0RkMRx{`}xer*qPs zq}xwZV=90JmV`dZ4z2(E-RUn}!YmY`TFNOoTp@=n1ru}IRc6mF%znRd$K;co&IN(U zWAxjtrCq*4F4!--yzY7mi>0eujsnlk1lE-2#GhNE7m{nOC>Jsn#GKFR9YJM?LI z=;6LMU(oaHVFG=eb4BkxZ=QmdkWwi&^&R;qr00ykkl&D|8PH?F-w{gZ z_)yOALr%9yC$}5RDV>%-$y+#0oaE@h*L$*WtE(TdeF^W|2TnR!0j4XBH4x@1w_1QPT z7hjPM9#T1d;b}HcbCnH-8yg{e7|Ixr{HoC_n|dDw#q8{i75tKs+3;eJVCqupPFs|Ue2!)!QUam&yE{7dAIIKt!Jioi!6Q#OI*^Ti!FI6RjB$JYOJYhwVG>b(tJZ5x74&*%dM=uB9+###x|2h9juXqxyR8s}->_zLejN^lZbcL)Jm6VK}Qc4eh?~pu<)Z$(KB~m)k>FW!ARdZ{Z6Rp>lnTl zDtghKr&{R}Eq9syt5DI?ihMCt^qxCkYo$xHJkIQ&g^FH%c|8jiUE+=_o1!bo(FI?k z|AHd?0m}3*$;bI6hPDZ500006VoOIv00000008+zyMF)x010qNS#tmY3ljhU3ljkV znw%H_000McNliru;tLKA5g*hTRpbBw02y>eSad^gZEa<4bO1wgWnpw>WFU8GbZ8() zNlj2!fese{0034=L_t(I%VT6ffd34rfDw(4Ri1?bH~7y$1YlyI5Ma1q&AG{VHG~-D z(%1!1TYfPxFtDMA$(nPM8HqAr&AG{JScDlzT`*W(KygB1BsKG(>!sKQ0OtN9f)Xd} QcmMzZ07*qoM6N<$f-uPt{Qv*} literal 0 HcmV?d00001 diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/IconResources.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/IconResources.java index 36441c5caca..65907efc86b 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/IconResources.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/IconResources.java @@ -8,6 +8,9 @@ public interface IconResources extends ClientBundle { public static final IconResources INSTANCE = GWT.create(IconResources.class); + @Source("images/change-acl.png") + ImageResource changeACLIcon(); + @Source("images/change-ownership.png") ImageResource changeOwnershipIcon(); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/DefaultActionsImagesBarCell.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/DefaultActionsImagesBarCell.java index 1ef6f9288df..4f504a5adcf 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/DefaultActionsImagesBarCell.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/DefaultActionsImagesBarCell.java @@ -23,7 +23,8 @@ public class DefaultActionsImagesBarCell extends ImagesBarCell { @Override protected Iterable getImageSpecs() { - return Arrays.asList(getUpdateImageSpec(), getDeleteImageSpec(), getChangeOwnershipImageSpec()); + return Arrays.asList(getUpdateImageSpec(), getDeleteImageSpec(), getChangeOwnershipImageSpec(), + getChangeACLImageSpec()); } /** @@ -60,8 +61,8 @@ public class DefaultActionsImagesBarCell extends ImagesBarCell { * @return {@link ImageSpec} for {@link DefaultActions#CHANGE_ACL change acl} action */ protected ImageSpec getChangeACLImageSpec() { - return new ImageSpec(ACTION_CHANGE_OWNERSHIP, stringMessages.actionChangeOwnership(), - IconResources.INSTANCE.changeOwnershipIcon()); + return new ImageSpec(ACTION_CHANGE_ACL, stringMessages.actionChangeACL(), + IconResources.INSTANCE.changeACLIcon()); } } \ No newline at end of file From c928b2164cdd4e978ae2b53b30aa3a5f2f8a7c3c Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Tue, 27 Nov 2018 17:10:09 +0100 Subject: [PATCH 08/27] added EditACLDialog --- .../ui/client/component/AclEditPanel.java | 282 ++++++++++++++++++ .../ui/client/component/AclEditPanel.ui.xml | 13 + .../ui/client/component/EditACLDialog.java | 161 ++++++++++ .../ui/client/i18n/StringMessages.java | 1 + .../ui/client/i18n/StringMessages.properties | 3 +- .../client/i18n/StringMessages_de.properties | 3 +- .../usermanagement/UserTableWrapper.java | 14 +- 7 files changed, 472 insertions(+), 5 deletions(-) create mode 100644 java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java create mode 100644 java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml create mode 100644 java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java new file mode 100644 index 00000000000..55884910f76 --- /dev/null +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java @@ -0,0 +1,282 @@ +package com.sap.sse.security.ui.client.component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.gwt.cell.client.AbstractCell; +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.cellview.client.CellList; +import com.google.gwt.user.cellview.client.SimplePager; +import com.google.gwt.user.cellview.client.SimplePager.TextLocation; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.MultiWordSuggestOracle; +import com.google.gwt.user.client.ui.ScrollPanel; +import com.google.gwt.user.client.ui.SuggestBox; +import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.view.client.SingleSelectionModel; +import com.sap.sailing.domain.common.security.SecuredDomainType; +import com.sap.sse.gwt.client.Notification; +import com.sap.sse.gwt.client.Notification.NotificationType; +import com.sap.sse.security.shared.AccessControlList; +import com.sap.sse.security.shared.HasPermissions; +import com.sap.sse.security.shared.HasPermissions.Action; +import com.sap.sse.security.shared.UserGroup; +import com.sap.sse.security.ui.client.UserManagementServiceAsync; +import com.sap.sse.security.ui.client.i18n.StringMessages; + +public class AclEditPanel extends Composite { + + private static AclEditPanelUiBinder uiBinder = GWT.create(AclEditPanelUiBinder.class); + + interface AclEditPanelUiBinder extends UiBinder { + } + + @UiField + Button removeUserGroupButtonUi; + @UiField + Button addUserGroupButtonUi; + @UiField(provided = true) + SuggestBox suggestUserGroupUi; + @UiField + FlowPanel userGroupCellListPanelUi; + @UiField + FlowPanel permissionsCellListPanelUi; + @UiField(provided = true) + SuggestBox suggestPermissionUi; + @UiField + Button removePermissionButtonUi; + @UiField + Button addPermissionButtonUi; + + private final SingleSelectionModel userGroupSingleSelectionModel = new SingleSelectionModel<>(); + private final SingleSelectionModel permissionsSingleSelectionModel = new SingleSelectionModel<>(); + private CellList userGroupList; + private CellList permissionsList; + + private Map> userGroupsWithPermissions = new HashMap<>(); + private UserManagementServiceAsync userManagementService; + + public AclEditPanel(UserManagementServiceAsync userManagementService, StringMessages stringMessages) { + this.userManagementService = userManagementService; + setupUserGroupSuggest(userManagementService); + setupPermissionSuggest(); + initWidget(uiBinder.createAndBindUi(this)); + setupCellList(stringMessages); + + permissionsSingleSelectionModel.addSelectionChangeHandler(h -> { + removePermissionButtonUi.setEnabled(permissionsSingleSelectionModel.getSelectedObject() != null); + }); + + userGroupSingleSelectionModel.addSelectionChangeHandler(h -> { + onUserGroupsChange(); + }); + + addPermissionButtonUi.setEnabled(false); + } + + private void onUserGroupsChange() { + removeUserGroupButtonUi.setEnabled(userGroupSingleSelectionModel.getSelectedObject() != null); + } + + private void setupPermissionSuggest() { + final MultiWordSuggestOracle permissionOracle = new MultiWordSuggestOracle(); + + final List stringPermissions = new ArrayList<>(); + for (final HasPermissions permission : SecuredDomainType.getAllInstances()) { + for (final Action action : permission.getAvailableActions()) { + stringPermissions.add(permission.getStringPermission(action)); + } + } + permissionOracle.addAll(stringPermissions); + permissionOracle.setDefaultSuggestionsFromText(stringPermissions); + suggestPermissionUi = new SuggestBox(permissionOracle, new TextBox(), new DefaultSuggestionDisplay() { + @Override + public void hideSuggestions() { + updatePermissionButtonIfNecessary(); + super.hideSuggestions(); + } + }); + suggestPermissionUi.addKeyUpHandler(e -> updatePermissionButtonIfNecessary()); + } + + private void updatePermissionButtonIfNecessary() { + final Set permissionsForSelectedUG = userGroupsWithPermissions + .get(userGroupSingleSelectionModel.getSelectedObject()); + final String valueToCheck = suggestPermissionUi.getValue(); + final boolean valid = !"".equals(valueToCheck) + && (permissionsForSelectedUG == null || !permissionsForSelectedUG.contains(valueToCheck)); + addPermissionButtonUi.setEnabled(valid); + } + + private void setupUserGroupSuggest(UserManagementServiceAsync userManagementService) { + final MultiWordSuggestOracle userGroupOracle = new MultiWordSuggestOracle(); + userManagementService.getUserGroups(new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + Window.alert(caught.getMessage()); + } + + @Override + public void onSuccess(Collection result) { + final List suggestionList = result.stream().map(UserGroup::getName) + .collect(Collectors.toList()); + userGroupOracle.clear(); + userGroupOracle.addAll(suggestionList); + userGroupOracle.setDefaultSuggestionsFromText(suggestionList); + } + }); + suggestUserGroupUi = new SuggestBox(userGroupOracle, new TextBox()); + } + + private void setupCellList(StringMessages stringMessages) { + userGroupList = new CellList(new AbstractCell() { + @Override + public void render(Context context, UserGroup value, SafeHtmlBuilder sb) { + if (value != null) { + sb.appendEscaped(value.getName()); + } + } + }); + + userGroupList.setSelectionModel(userGroupSingleSelectionModel); + userGroupCellListPanelUi.add(wrapListUi(userGroupList, stringMessages.userGroups())); + userGroupSingleSelectionModel.addSelectionChangeHandler( + e -> updatePermissionsListUi(userGroupSingleSelectionModel.getSelectedObject())); + + permissionsList = new CellList(new AbstractCell() { + @Override + public void render(Context context, String value, SafeHtmlBuilder sb) { + if (value != null) { + sb.appendEscaped(value); + } + } + }); + + permissionsList.setSelectionModel(permissionsSingleSelectionModel); + permissionsCellListPanelUi.add(wrapListUi(permissionsList, stringMessages.permissions())); + } + + private void updatePermissionsListUi(UserGroup selectedUserGroup) { + final Set permissions = userGroupsWithPermissions.get(selectedUserGroup); + permissionsList.setRowCount(permissions.size()); + permissionsList.setRowData(0, new ArrayList<>(permissions)); + onUserGroupsChange(); + updatePermissionButtonIfNecessary(); + } + + private CaptionPanel wrapListUi(CellList cellList, String title) { + cellList.setPageSize(10); + final SimplePager tenantPager = new SimplePager(TextLocation.CENTER, false, /* fast forward step size */ 50, + true); + tenantPager.setDisplay(cellList); + final ScrollPanel tenantPanel = new ScrollPanel(cellList); + final VerticalPanel tenantListWrapper = new VerticalPanel(); + tenantListWrapper.add(tenantPanel); + tenantListWrapper.add(tenantPager); + final CaptionPanel tenantListCaption = new CaptionPanel(title); + tenantListCaption.add(tenantListWrapper); + return tenantListCaption; + } + + public void updateAcl(AccessControlList acl) { + userGroupsWithPermissions = (acl != null) + ? acl.getActionsByUserGroup() != null ? new HashMap<>(acl.getActionsByUserGroup()) : new HashMap<>() + : new HashMap<>(); + refreshUi(); + } + + private void refreshUi() { + userGroupList.setRowCount(userGroupsWithPermissions.size(), true); + userGroupList.setRowData(0, new ArrayList<>(userGroupsWithPermissions.keySet())); + + // select an element + if (userGroupsWithPermissions.size() > 0) { + userGroupSingleSelectionModel.setSelected(userGroupsWithPermissions.keySet().iterator().next(), true); + } + } + + @UiHandler("addPermissionButtonUi") + void onPermissionAdd(ClickEvent e) { + final UserGroup selectedUserGroup = userGroupSingleSelectionModel.getSelectedObject(); + if (selectedUserGroup != null && !"".equals(suggestPermissionUi.getText())) { + Set permissions = userGroupsWithPermissions.get(selectedUserGroup); + if (permissions == null) { + permissions = new HashSet<>(); + } + permissions.add(suggestPermissionUi.getText()); + userGroupsWithPermissions.put(selectedUserGroup, permissions); + updatePermissionsListUi(selectedUserGroup); + suggestPermissionUi.setText(""); + } + } + + @UiHandler("removePermissionButtonUi") + void onPermissionRemove(ClickEvent e) { + final UserGroup selectedUserGroup = userGroupSingleSelectionModel.getSelectedObject(); + if (selectedUserGroup != null) { + Set permissions = userGroupsWithPermissions.get(selectedUserGroup); + if (permissions == null) { + permissions = new HashSet<>(); + } + final String selectedPermission = permissionsSingleSelectionModel.getSelectedObject(); + permissions.remove(selectedPermission); + userGroupsWithPermissions.put(selectedUserGroup, permissions); + updatePermissionsListUi(selectedUserGroup); + } + } + + @UiHandler("addUserGroupButtonUi") + void onUserGroupAdd(ClickEvent e) { + final String userGroupName = suggestUserGroupUi.getValue(); + userManagementService.getUserGroupByName(userGroupName, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + // TODO: i18n + Notification.notify("Did not find user group by name x" + userGroupName, NotificationType.ERROR); + } + + @Override + public void onSuccess(UserGroup result) { + if (result == null) { + Notification.notify("Did not find user group by name x" + userGroupName, NotificationType.ERROR); + } else { + Notification.notify("Added usergroup x" + userGroupName, NotificationType.SUCCESS); + userGroupsWithPermissions.put(result, new HashSet<>()); + refreshUi(); + suggestUserGroupUi.setText(""); + userGroupSingleSelectionModel.setSelected(result, true); + } + } + }); + } + + @UiHandler("removeUserGroupButtonUi") + void onUserGroupRemove(ClickEvent e) { + userGroupsWithPermissions.remove(userGroupSingleSelectionModel.getSelectedObject()); + refreshUi(); + } + + public Map> getUserGroupsWithPermissions() { + return userGroupsWithPermissions; + } + +} diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml new file mode 100644 index 00000000000..0e7dcc9f9df --- /dev/null +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java new file mode 100644 index 00000000000..e524be01a76 --- /dev/null +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java @@ -0,0 +1,161 @@ +package com.sap.sse.security.ui.client.component; + +import static com.sap.sse.gwt.client.Notification.NotificationType.ERROR; + +import java.util.function.Consumer; +import java.util.function.Function; + +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.security.SecuredDomainType; +import com.sap.sse.common.Named; +import com.sap.sse.gwt.client.Notification; +import com.sap.sse.gwt.client.dialog.DataEntryDialog; +import com.sap.sse.security.shared.AccessControlList; +import com.sap.sse.security.shared.HasPermissions; +import com.sap.sse.security.shared.QualifiedObjectIdentifier; +import com.sap.sse.security.shared.SecuredObject; +import com.sap.sse.security.shared.impl.AccessControlListImpl; +import com.sap.sse.security.ui.client.UserManagementServiceAsync; +import com.sap.sse.security.ui.client.component.EditACLDialog.AclDialogResult; +import com.sap.sse.security.ui.client.i18n.StringMessages; + +public class EditACLDialog extends DataEntryDialog { + + private final AclEditPanel aclEditPanel; + + static class AclDialogResult { + private final AccessControlList acl; + + private AclDialogResult(final AccessControlList acl) { + this.acl = acl; + } + + public AccessControlList getAcl() { + return acl; + } + } + + private static class Validator implements DataEntryDialog.Validator { + @Override + public String getErrorMessage(AclDialogResult valueToValidate) { + // nothing to validate since user input is already validated in aclPanel + return null; + } + } + + private EditACLDialog(UserManagementServiceAsync userManagementService, + QualifiedObjectIdentifier qualifiedObjectIdentifier, + StringMessages stringMessages, DialogCallback callback) { + super("ACL", stringMessages.editACL(), stringMessages.ok(), stringMessages.cancel(), new Validator(), callback); + // TODO: ^ i18n ^ + aclEditPanel = new AclEditPanel(userManagementService, stringMessages); + userManagementService.getAccessControlListWithoutPruning(qualifiedObjectIdentifier, + new AsyncCallback() { + + @Override + public void onFailure(Throwable caught) { + // TODO Auto-generated method stub + + } + + @Override + public void onSuccess(AccessControlList result) { + aclEditPanel.updateAcl(result); + } + }); + } + + @Override + protected Widget getAdditionalWidget() { + return aclEditPanel; + } + + @Override + protected AclDialogResult getResult() { + return new AclDialogResult(new AccessControlListImpl(aclEditPanel.getUserGroupsWithPermissions())); + } + + /** + * Creates a new {@link DialogConfig dialog configuration} instance which can be (re-)used to + * {@link DialogConfig#openDialog(Named) open} a {@link EditACLDialog dialog}. + * + * @param userManagementService + * {@link UserManagementServiceAsync} to use to set the secured object's ownership + * @param type + * {@link SecuredDomainType} specifying the type of required permissions to modify the secured object + * @param typeRelativeIdFactory + * {@link Function factory} to get a {@link String type relative identifier} for the secured object + * @param updateCallback + * {@link Consumer callback} to execute when the dialog is confirmed and ownership update succeeded + * @param errorCallback + * {@link Consumer callback} to execute when the dialog is confirmed and ownership update fails + */ + public static DialogConfig create( + final UserManagementServiceAsync userManagementService, final HasPermissions type, + final Function typeRelativeIdFactory, final Consumer updateCallback, + final StringMessages stringMessages) { + return new DialogConfig<>(userManagementService, type, typeRelativeIdFactory, updateCallback, stringMessages); + } + + public static class DialogConfig { + private final UserManagementServiceAsync userManagementService; + private final Consumer updateCallback; + private final Function identifierFactory; + private final StringMessages stringMessages; + + private DialogConfig(final UserManagementServiceAsync userManagementService, final HasPermissions type, + final Function idFactory, final Consumer updateCallback, + final StringMessages stringMessages) { + this.userManagementService = userManagementService; + this.identifierFactory = idFactory.andThen(type::getQualifiedObjectIdentifier); + this.updateCallback = updateCallback; + this.stringMessages = stringMessages; + } + + /** + * Opens a {@link EditACLDialog dialog} to edit ownerships for the provided secured object instance. + * + * @param securedObject + * {@link Named} {@link SecuredObject} instance to edit ownerships for + */ + public void openDialog(final T securedObject) { + new EditACLDialog(userManagementService, identifierFactory.apply(securedObject), StringMessages.INSTANCE, + new EditAclDialogCallback(securedObject)).show(); + } + + private class EditAclDialogCallback implements DialogCallback { + + private final T securedObject; + + private EditAclDialogCallback(T securedObject) { + this.securedObject = securedObject; + } + + @Override + public void ok(AclDialogResult aclResult) { + final QualifiedObjectIdentifier objectIdentifier = identifierFactory.apply(securedObject); + userManagementService.overrideAccessControlList(objectIdentifier, aclResult.getAcl(), + new AsyncCallback() { + @Override + public void onSuccess(AccessControlList result) { + securedObject.setAccessControlList(result); + updateCallback.accept(securedObject); + } + + @Override + public final void onFailure(Throwable caught) { + // TODO: v i18n v + Notification.notify(stringMessages.errorUpdatingOwnership(securedObject.getName()), + ERROR); + } + }); + } + + @Override + public final void cancel() { + } + } + } + +} diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java index d3f3d42e9f4..0c65297e9be 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java @@ -152,4 +152,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { String pleaseWaitUntilUserGroupNameIsResolved(); String userNotFound(String username); String usergroupNotFound(String userGroupName); + String actionChangeACL(); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties index dff32c42aad..4e64169e250 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties @@ -159,4 +159,5 @@ errorObtainingUserGroup=Error obtaining user group: {0} pleaseWaitUntilUsernameIsResolved=Please wait until user name is resolved pleaseWaitUntilUserGroupNameIsResolved=Please wait until user group name is resolved userNotFound=User {0} not found -usergroupNotFound=User group {0} not found \ No newline at end of file +usergroupNotFound=User group {0} not found +actionChangeACL=Change ACL \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties index a198301270d..c2b37873066 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties @@ -158,4 +158,5 @@ errorObtainingUserGroup=Fehler beim Nachschlagen der Benutzergruppe: {0} pleaseWaitUntilUsernameIsResolved=Bitte warten, bis der Benutzername ausgelöst wurde pleaseWaitUntilUserGroupNameIsResolved=Bitte warten, bis der Benutzergruppen-Name aufgelöst wurde userNotFound=Benutzer {0} nicht gefunden -usergroupNotFound=Benutzergruppe {0} nicht gefunden \ No newline at end of file +usergroupNotFound=Benutzergruppe {0} nicht gefunden +actionChangeACL=ACL ändern \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java index 70b506c231e..ad0922a08d6 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java @@ -40,6 +40,7 @@ import com.sap.sse.gwt.client.celltable.TableWrapper; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; import com.sap.sse.security.shared.HasPermissions; +import com.sap.sse.security.shared.HasPermissions.DefaultActions; import com.sap.sse.security.shared.Role; import com.sap.sse.security.shared.UserGroup; import com.sap.sse.security.shared.WildcardPermission; @@ -48,8 +49,8 @@ import com.sap.sse.security.ui.client.UserManagementServiceAsync; import com.sap.sse.security.ui.client.UserService; import com.sap.sse.security.ui.client.component.AccessControlledActionsColumn; import com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell; +import com.sap.sse.security.ui.client.component.EditACLDialog; import com.sap.sse.security.ui.client.component.EditOwnershipDialog; -import com.sap.sse.security.ui.client.component.EditOwnershipDialog.DialogConfig; import com.sap.sse.security.ui.client.component.SecuredObjectOwnerColumn; import com.sap.sse.security.ui.client.i18n.StringMessages; import com.sap.sse.security.ui.shared.SuccessInfo; @@ -185,9 +186,16 @@ extends TableWrapper { }); } }); - final DialogConfig config = EditOwnershipDialog.create(userService.getUserManagementService(), type, + final EditOwnershipDialog.DialogConfig configOwnership = EditOwnershipDialog.create( + userService.getUserManagementService(), type, idFactory, user -> refreshUserList((Callback, Throwable>) null), stringMessages); - userActionColumn.addAction(ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, config::openDialog); + + final EditACLDialog.DialogConfig configACL = EditACLDialog.create( + userService.getUserManagementService(), type, + idFactory, user -> user.getAccessControlList(), stringMessages); + userActionColumn.addAction(ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, configOwnership::openDialog); + userActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL, + u -> configACL.openDialog(u)); filterField = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterUsers()), new ArrayList(), dataProvider) { From 515c8075e8e64d423615ba00816a08f92b81a636 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Tue, 27 Nov 2018 18:03:55 +0100 Subject: [PATCH 09/27] use id of default-tenant instead of name on update user --- .../sse/security/ui/client/usermanagement/UserTableWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java index 70b506c231e..66543b2bafc 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java @@ -274,7 +274,7 @@ extends TableWrapper { users.add(user); getUserManagementService().updateUserProperties(user.getName(), user.getFullName(), user.getCompany(), user.getLocale(), - user.getDefaultTenant() != null ? user.getDefaultTenant().getName() : null, + user.getDefaultTenant() != null ? user.getDefaultTenant().getId().toString() : null, new AsyncCallback() { @Override public void onFailure(Throwable caught) { From 5ddb98402ee1836210f216650b94a55066674f9f Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Tue, 27 Nov 2018 18:08:53 +0100 Subject: [PATCH 10/27] filter boats by permission READ_PUBLIC --- .../gwt/ui/server/SailingServiceImpl.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 103305da626..67cb1a7e050 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -5655,12 +5655,24 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public Iterable getAllBoats() { - return convertToBoatDTOs(getService().getBaseDomainFactory().getCompetitorAndBoatStore().getBoats()); + List result = new ArrayList<>(); + getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.BOAT, + SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, + getService().getBaseDomainFactory().getCompetitorAndBoatStore().getBoats(), + boat -> boat.getIdentifier().toString(), + filteredObject -> result.add(baseDomainFactory.convertToBoatDTO(filteredObject))); + return result; } @Override public Iterable getStandaloneBoats() { - return convertToBoatDTOs(getService().getBaseDomainFactory().getCompetitorAndBoatStore().getStandaloneBoats()); + List result = new ArrayList<>(); + getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.BOAT, + SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, + getService().getBaseDomainFactory().getCompetitorAndBoatStore().getStandaloneBoats(), + boat -> boat.getIdentifier().toString(), + filteredObject -> result.add(baseDomainFactory.convertToBoatDTO(filteredObject))); + return result; } @Override From 0d4597b39a4d73b923979ae511510ffcf115edbd Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 28 Nov 2018 09:10:22 +0100 Subject: [PATCH 11/27] minor cleanups --- .../regatta/GetOpenRegattaByRegattaNameAction.java | 2 +- .../gwt/home/desktop/places/qrcode/QRCodePresenter.java | 4 ---- .../server/gateway/test/jaxrs/AbstractJaxRsApiTest.java | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/regatta/GetOpenRegattaByRegattaNameAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/regatta/GetOpenRegattaByRegattaNameAction.java index d60eff330ac..ab904ecc50e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/regatta/GetOpenRegattaByRegattaNameAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/regatta/GetOpenRegattaByRegattaNameAction.java @@ -38,7 +38,7 @@ public class GetOpenRegattaByRegattaNameAction implements SailingAction callback) { + super(stringMessages.acl(), stringMessages.editACLForObject(qualifiedObjectIdentifier.toString()), + stringMessages.ok(), stringMessages.cancel(), new Validator(), callback); aclEditPanel = new AclEditPanel(userManagementService, stringMessages); userManagementService.getAccessControlListWithoutPruning(qualifiedObjectIdentifier, new AsyncCallback() { @@ -146,7 +146,7 @@ public class EditACLDialog extends DataEntryDialog { @Override public final void onFailure(Throwable caught) { // TODO: v i18n v - Notification.notify(stringMessages.errorUpdatingOwnership(securedObject.getName()), + Notification.notify(stringMessages.errorUpdatingAcl(securedObject.getName()), ERROR); } }); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java index 0c65297e9be..689c4387899 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java @@ -153,4 +153,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { String userNotFound(String username); String usergroupNotFound(String userGroupName); String actionChangeACL(); + String editACLForObject(String objectName); + String acl(); + String errorUpdatingAcl(String name); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties index 4e64169e250..a1b379afa87 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties @@ -160,4 +160,7 @@ pleaseWaitUntilUsernameIsResolved=Please wait until user name is resolved pleaseWaitUntilUserGroupNameIsResolved=Please wait until user group name is resolved userNotFound=User {0} not found usergroupNotFound=User group {0} not found -actionChangeACL=Change ACL \ No newline at end of file +actionChangeACL=Change ACL +editACLForObject=Edit ACL for ''{0}'' +acl=ACL +errorUpdatingAcl=Error updating ACL: {0}. \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties index c2b37873066..27e0305bd49 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties @@ -159,4 +159,7 @@ pleaseWaitUntilUsernameIsResolved=Bitte warten, bis der Benutzername ausgelöst pleaseWaitUntilUserGroupNameIsResolved=Bitte warten, bis der Benutzergruppen-Name aufgelöst wurde userNotFound=Benutzer {0} nicht gefunden usergroupNotFound=Benutzergruppe {0} nicht gefunden -actionChangeACL=ACL ändern \ No newline at end of file +actionChangeACL=ACL ändern +editACLForObject=ACL für ''{0}'' ändern +acl=ACL +errorUpdatingAcl=Fehler beim Aktualisieren der ACL: {0}. \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java index 1a5a5fa17d9..dcd1744ed4d 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java @@ -805,8 +805,12 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U public AccessControlList getAccessControlListWithoutPruning(QualifiedObjectIdentifier idOfAccessControlledObject) throws UnauthorizedException { if (SecurityUtils.getSubject() .isPermitted(idOfAccessControlledObject.getStringPermission(DefaultActions.CHANGE_ACL))) { + AccessControlListAnnotation accessControlList = getSecurityService().getAccessControlList(idOfAccessControlledObject); + if (accessControlList == null) { + return null; + } return securityDTOFactory.createAccessControlListDTO( - getSecurityService().getAccessControlList(idOfAccessControlledObject).getAnnotation()); + accessControlList.getAnnotation()); } else { throw new UnauthorizedException("Not permitted to get the unpruned ACL for a user"); } From 9a5f8f5412d68d8eeb852c0224b038132ca95ac1 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 09:59:27 +0100 Subject: [PATCH 13/27] adjusted EditACLDialog --- .../ui/client/component/AclEditPanel.java | 194 ++++++++---------- .../ui/client/component/AclEditPanel.ui.xml | 3 - .../ui/client/component/EditACLDialog.java | 11 +- 3 files changed, 97 insertions(+), 111 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java index fb05d702110..bf59d152a02 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java @@ -28,16 +28,14 @@ import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.MultiWordSuggestOracle; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.SuggestBox; -import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.SingleSelectionModel; -import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sse.gwt.client.Notification; import com.sap.sse.gwt.client.Notification.NotificationType; +import com.sap.sse.gwt.client.controls.listedit.StringListEditorComposite; import com.sap.sse.security.shared.AccessControlList; -import com.sap.sse.security.shared.HasPermissions; import com.sap.sse.security.shared.HasPermissions.Action; import com.sap.sse.security.shared.UserGroup; import com.sap.sse.security.ui.client.UserManagementServiceAsync; @@ -60,73 +58,73 @@ public class AclEditPanel extends Composite { FlowPanel userGroupCellListPanelUi; @UiField FlowPanel permissionsCellListPanelUi; - @UiField(provided = true) - SuggestBox suggestPermissionUi; - @UiField - Button removePermissionButtonUi; - @UiField - Button addPermissionButtonUi; + + private final StringListEditorComposite allowedActionsEditor; + private final StringListEditorComposite deniedActionsEditor; private final SingleSelectionModel userGroupSingleSelectionModel = new SingleSelectionModel<>(); - private final SingleSelectionModel permissionsSingleSelectionModel = new SingleSelectionModel<>(); private CellList userGroupList; - private CellList permissionsList; - private Map> userGroupsWithPermissions = new HashMap<>(); + // denied actions start with '!' + private Map> userGroupsWithAllowedActions = new HashMap<>(); + private Map> userGroupsWithDeniedActions = new HashMap<>(); private UserManagementServiceAsync userManagementService; - public AclEditPanel(UserManagementServiceAsync userManagementService, StringMessages stringMessages) { + public AclEditPanel(UserManagementServiceAsync userManagementService, Action[] availableActions, + StringMessages stringMessages) { this.userManagementService = userManagementService; + + final Collection actionNames = new ArrayList<>(); + for (Action a : availableActions) { + actionNames.add(a.name()); + } + setupUserGroupSuggest(userManagementService); - setupPermissionSuggest(stringMessages); initWidget(uiBinder.createAndBindUi(this)); setupCellLists(stringMessages); - permissionsSingleSelectionModel.addSelectionChangeHandler(h -> { - removePermissionButtonUi.setEnabled(permissionsSingleSelectionModel.getSelectedObject() != null); - }); - userGroupSingleSelectionModel.addSelectionChangeHandler(h -> { onUserGroupsChange(); }); - addPermissionButtonUi.setEnabled(false); + // create action editor for allowed actions + allowedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, + com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, "Allowed action name"); + // TODO: i18n ^v^v + + allowedActionsEditor.addValueChangeHandler(e -> userGroupsWithAllowedActions + .put(userGroupSingleSelectionModel.getSelectedObject(), toSet(e.getValue()))); + permissionsCellListPanelUi.add(allowedActionsEditor); + + // create action editor for denied actions + deniedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, + com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, "Denied action name"); + + deniedActionsEditor.addValueChangeHandler(e -> userGroupsWithDeniedActions + .put(userGroupSingleSelectionModel.getSelectedObject(), toDeniedSet(e.getValue()))); + permissionsCellListPanelUi.add(deniedActionsEditor); + } + + private Set toSet(Iterable iter) { + final Set set = new HashSet<>(); + for (T t : iter) { + set.add(t); + } + return set; + } + + private Set toDeniedSet(Iterable iter) { + final Set set = new HashSet<>(); + for (String s : iter) { + set.add(s.startsWith("!") ? s : "!" + s); + } + return set; } private void onUserGroupsChange() { removeUserGroupButtonUi.setEnabled(userGroupSingleSelectionModel.getSelectedObject() != null); } - private void setupPermissionSuggest(StringMessages stringMessages) { - final MultiWordSuggestOracle permissionOracle = new MultiWordSuggestOracle(); - - final List stringPermissions = new ArrayList<>(); - for (final HasPermissions permission : SecuredDomainType.getAllInstances()) { - for (final Action action : permission.getAvailableActions()) { - stringPermissions.add(permission.getStringPermission(action)); - } - } - permissionOracle.addAll(stringPermissions); - permissionOracle.setDefaultSuggestionsFromText(stringPermissions); - suggestPermissionUi = new SuggestBox(permissionOracle, new TextBox(), new DefaultSuggestionDisplay() { - @Override - public void hideSuggestions() { - updatePermissionButtonIfNecessary(); - super.hideSuggestions(); - } - }); - suggestPermissionUi.addKeyUpHandler(e -> updatePermissionButtonIfNecessary()); - } - - private void updatePermissionButtonIfNecessary() { - final Set permissionsForSelectedUG = userGroupsWithPermissions - .get(userGroupSingleSelectionModel.getSelectedObject()); - final String valueToCheck = suggestPermissionUi.getValue(); - final boolean valid = !"".equals(valueToCheck) - && (permissionsForSelectedUG == null || !permissionsForSelectedUG.contains(valueToCheck)); - addPermissionButtonUi.setEnabled(valid); - } - private void setupUserGroupSuggest(UserManagementServiceAsync userManagementService) { final MultiWordSuggestOracle userGroupOracle = new MultiWordSuggestOracle(); userManagementService.getUserGroups(new AsyncCallback>() { @@ -159,28 +157,15 @@ public class AclEditPanel extends Composite { userGroupList.setSelectionModel(userGroupSingleSelectionModel); userGroupCellListPanelUi.add(wrapListUi(userGroupList, stringMessages.userGroups())); - userGroupSingleSelectionModel.addSelectionChangeHandler( - e -> updatePermissionsListUi(userGroupSingleSelectionModel.getSelectedObject())); + userGroupSingleSelectionModel + .addSelectionChangeHandler(e -> updateActionsUi(userGroupSingleSelectionModel.getSelectedObject())); - permissionsList = new CellList(new AbstractCell() { - @Override - public void render(Context context, String value, SafeHtmlBuilder sb) { - if (value != null) { - sb.appendEscaped(value); - } - } - }); - - permissionsList.setSelectionModel(permissionsSingleSelectionModel); - permissionsCellListPanelUi.add(wrapListUi(permissionsList, stringMessages.permissions())); } - private void updatePermissionsListUi(UserGroup selectedUserGroup) { - final Set permissions = userGroupsWithPermissions.get(selectedUserGroup); - permissionsList.setRowCount(permissions.size()); - permissionsList.setRowData(0, new ArrayList<>(permissions)); + private void updateActionsUi(UserGroup selectedUserGroup) { onUserGroupsChange(); - updatePermissionButtonIfNecessary(); + allowedActionsEditor.setValue(userGroupsWithAllowedActions.get(selectedUserGroup), false); + deniedActionsEditor.setValue(userGroupsWithDeniedActions.get(selectedUserGroup), false); } private CaptionPanel wrapListUi(CellList cellList, String title) { @@ -198,49 +183,37 @@ public class AclEditPanel extends Composite { } public void updateAcl(AccessControlList acl) { - userGroupsWithPermissions = (acl != null) + final Map> combinedActions = (acl != null) ? acl.getActionsByUserGroup() != null ? new HashMap<>(acl.getActionsByUserGroup()) : new HashMap<>() : new HashMap<>(); + + for (Map.Entry> combinedAction : combinedActions.entrySet()) { + final Set allowedActions = new HashSet<>(); + final Set deniedActions = new HashSet<>(); + for (String action : combinedAction.getValue()) { + if (action.startsWith("!")) { + deniedActions.add(action); + } else { + allowedActions.add(action); + } + } + userGroupsWithAllowedActions.put(combinedAction.getKey(), allowedActions); + userGroupsWithDeniedActions.put(combinedAction.getKey(), deniedActions); + } + refreshUi(); } private void refreshUi() { - userGroupList.setRowCount(userGroupsWithPermissions.size(), true); - userGroupList.setRowData(0, new ArrayList<>(userGroupsWithPermissions.keySet())); + final Set combinedKeySet = new HashSet<>(); + combinedKeySet.addAll(userGroupsWithAllowedActions.keySet()); + combinedKeySet.addAll(userGroupsWithDeniedActions.keySet()); + userGroupList.setRowCount(combinedKeySet.size(), true); + userGroupList.setRowData(0, new ArrayList<>(combinedKeySet)); // select an element - if (userGroupsWithPermissions.size() > 0) { - userGroupSingleSelectionModel.setSelected(userGroupsWithPermissions.keySet().iterator().next(), true); - } - } - - @UiHandler("addPermissionButtonUi") - void onPermissionAdd(ClickEvent e) { - final UserGroup selectedUserGroup = userGroupSingleSelectionModel.getSelectedObject(); - if (selectedUserGroup != null && !"".equals(suggestPermissionUi.getText())) { - Set permissions = userGroupsWithPermissions.get(selectedUserGroup); - if (permissions == null) { - permissions = new HashSet<>(); - } - permissions.add(suggestPermissionUi.getText()); - userGroupsWithPermissions.put(selectedUserGroup, permissions); - updatePermissionsListUi(selectedUserGroup); - suggestPermissionUi.setText(""); - } - } - - @UiHandler("removePermissionButtonUi") - void onPermissionRemove(ClickEvent e) { - final UserGroup selectedUserGroup = userGroupSingleSelectionModel.getSelectedObject(); - if (selectedUserGroup != null) { - Set permissions = userGroupsWithPermissions.get(selectedUserGroup); - if (permissions == null) { - permissions = new HashSet<>(); - } - final String selectedPermission = permissionsSingleSelectionModel.getSelectedObject(); - permissions.remove(selectedPermission); - userGroupsWithPermissions.put(selectedUserGroup, permissions); - updatePermissionsListUi(selectedUserGroup); + if (combinedKeySet.size() > 0) { + userGroupSingleSelectionModel.setSelected(combinedKeySet.iterator().next(), true); } } @@ -260,7 +233,8 @@ public class AclEditPanel extends Composite { Notification.notify("Did not find user group by name x" + userGroupName, NotificationType.ERROR); } else { Notification.notify("Added usergroup x" + userGroupName, NotificationType.SUCCESS); - userGroupsWithPermissions.put(result, new HashSet<>()); + userGroupsWithAllowedActions.put(result, new HashSet<>()); + userGroupsWithDeniedActions.put(result, new HashSet<>()); refreshUi(); suggestUserGroupUi.setText(""); userGroupSingleSelectionModel.setSelected(result, true); @@ -271,12 +245,22 @@ public class AclEditPanel extends Composite { @UiHandler("removeUserGroupButtonUi") void onUserGroupRemove(ClickEvent e) { - userGroupsWithPermissions.remove(userGroupSingleSelectionModel.getSelectedObject()); + userGroupsWithAllowedActions.remove(userGroupSingleSelectionModel.getSelectedObject()); + userGroupsWithDeniedActions.remove(userGroupSingleSelectionModel.getSelectedObject()); refreshUi(); } public Map> getUserGroupsWithPermissions() { - return userGroupsWithPermissions; + final Map> combinedActions = new HashMap<>(userGroupsWithAllowedActions); + for (Map.Entry> actionEntry : userGroupsWithDeniedActions.entrySet()) { + if (combinedActions.containsKey(actionEntry.getKey())) { + final Set set = combinedActions.get(actionEntry.getKey()); + set.addAll(actionEntry.getValue()); + } else { + combinedActions.put(actionEntry.getKey(), actionEntry.getValue()); + } + } + return combinedActions; } } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml index 0e7dcc9f9df..624ba8b93a7 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml @@ -6,8 +6,5 @@ - - - \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java index d117ce569f1..e772e46d31f 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java @@ -13,6 +13,7 @@ import com.sap.sse.gwt.client.Notification; import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.security.shared.AccessControlList; import com.sap.sse.security.shared.HasPermissions; +import com.sap.sse.security.shared.HasPermissions.Action; import com.sap.sse.security.shared.QualifiedObjectIdentifier; import com.sap.sse.security.shared.SecuredObject; import com.sap.sse.security.shared.impl.AccessControlListImpl; @@ -45,11 +46,12 @@ public class EditACLDialog extends DataEntryDialog { } private EditACLDialog(UserManagementServiceAsync userManagementService, - QualifiedObjectIdentifier qualifiedObjectIdentifier, StringMessages stringMessages, + QualifiedObjectIdentifier qualifiedObjectIdentifier, Action[] availableActions, + StringMessages stringMessages, DialogCallback callback) { super(stringMessages.acl(), stringMessages.editACLForObject(qualifiedObjectIdentifier.toString()), stringMessages.ok(), stringMessages.cancel(), new Validator(), callback); - aclEditPanel = new AclEditPanel(userManagementService, stringMessages); + aclEditPanel = new AclEditPanel(userManagementService, availableActions, stringMessages); userManagementService.getAccessControlListWithoutPruning(qualifiedObjectIdentifier, new AsyncCallback() { @@ -102,6 +104,7 @@ public class EditACLDialog extends DataEntryDialog { private final UserManagementServiceAsync userManagementService; private final Consumer updateCallback; private final Function identifierFactory; + private final Function availableActionsFactory; private final StringMessages stringMessages; private DialogConfig(final UserManagementServiceAsync userManagementService, final HasPermissions type, @@ -109,6 +112,7 @@ public class EditACLDialog extends DataEntryDialog { final StringMessages stringMessages) { this.userManagementService = userManagementService; this.identifierFactory = idFactory.andThen(type::getQualifiedObjectIdentifier); + this.availableActionsFactory = idFactory.andThen(t -> type.getAvailableActions()); this.updateCallback = updateCallback; this.stringMessages = stringMessages; } @@ -120,7 +124,8 @@ public class EditACLDialog extends DataEntryDialog { * {@link Named} {@link SecuredObject} instance to edit ownerships for */ public void openDialog(final T securedObject) { - new EditACLDialog(userManagementService, identifierFactory.apply(securedObject), StringMessages.INSTANCE, + new EditACLDialog(userManagementService, identifierFactory.apply(securedObject), + availableActionsFactory.apply(securedObject), StringMessages.INSTANCE, new EditAclDialogCallback(securedObject)).show(); } From c995e66562219cb3b5b802569f4b4e5b244ee2f5 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 28 Nov 2018 10:03:41 +0100 Subject: [PATCH 14/27] filter competitors by permission READ_PUBLIC --- .../gwt/ui/server/SailingServiceImpl.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 67cb1a7e050..9146306e744 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -5500,17 +5500,25 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } @Override - public Iterable getCompetitors(boolean filterCompetitorsWithBoat, boolean filterCompetitorsWithoutBoat) { - Iterable result; + public Iterable getCompetitors(boolean filterCompetitorsWithBoat, + boolean filterCompetitorsWithoutBoat) { + final List result = new ArrayList<>(); CompetitorAndBoatStore competitorStore = getService().getBaseDomainFactory().getCompetitorAndBoatStore(); if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == false) { - result = convertToCompetitorDTOs(competitorStore.getAllCompetitors()); + getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.COMPETITOR, + SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, competitorStore.getAllCompetitors(), + boat -> boat.getIdentifier().toString(), + filteredObject -> result.add(baseDomainFactory.convertToCompetitorDTO(filteredObject))); } else if (filterCompetitorsWithBoat == true && filterCompetitorsWithoutBoat == false) { - result = convertToCompetitorDTOs(competitorStore.getCompetitorsWithoutBoat()); + getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.COMPETITOR, + SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, competitorStore.getCompetitorsWithoutBoat(), + boat -> boat.getIdentifier().toString(), + filteredObject -> result.add(baseDomainFactory.convertToCompetitorDTO(filteredObject))); } else if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == true) { - result = convertToCompetitorDTOs(competitorStore.getCompetitorsWithBoat()); - } else { - result = Collections.emptyList(); + getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.COMPETITOR, + SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, competitorStore.getCompetitorsWithBoat(), + boat -> boat.getIdentifier().toString(), + filteredObject -> result.add(baseDomainFactory.convertToCompetitorDTO(filteredObject))); } return result; } From 6e1758cbb9a7c41e92a7d58579c24fc042ea6c7a Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 10:06:32 +0100 Subject: [PATCH 15/27] moved EditAclDialog into separate package + added CSS resources --- .../component/editacl/AclDialogResources.gss | 10 +++++++++ .../component/editacl/AclDialogResources.java | 22 +++++++++++++++++++ .../component/{ => editacl}/AclEditPanel.java | 5 ++++- .../{ => editacl}/AclEditPanel.ui.xml | 0 .../{ => editacl}/EditACLDialog.java | 4 ++-- .../usermanagement/UserTableWrapper.java | 2 +- 6 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss create mode 100644 java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java rename java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/{ => editacl}/AclEditPanel.java (97%) rename java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/{ => editacl}/AclEditPanel.ui.xml (100%) rename java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/{ => editacl}/EditACLDialog.java (98%) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss new file mode 100644 index 00000000000..73568cde34f --- /dev/null +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss @@ -0,0 +1,10 @@ +.allowedActionsTable { + margin-right: 10px; + margin-top: 10px; + display: inline-block; +} + +.deniedActionsTable { + margin-top: 10px; + display: inline-block; +} \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java new file mode 100644 index 00000000000..ab5798065f7 --- /dev/null +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java @@ -0,0 +1,22 @@ +package com.sap.sse.security.ui.client.component.editacl; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +/** + * Resources used by the authentication framework. + */ +public interface AclDialogResources extends ClientBundle { + + public static final AclDialogResources INSTANCE = GWT.create(AclDialogResources.class); + + @Source("AclDialogResources.gss") + LocalCss css(); + + public interface LocalCss extends CssResource { + String allowedActionsTable(); + + String deniedActionsTable(); + } +} diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java similarity index 97% rename from java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java rename to java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java index bf59d152a02..674c1575328 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java @@ -1,4 +1,4 @@ -package com.sap.sse.security.ui.client.component; +package com.sap.sse.security.ui.client.component.editacl; import java.util.ArrayList; import java.util.Collection; @@ -73,6 +73,7 @@ public class AclEditPanel extends Composite { public AclEditPanel(UserManagementServiceAsync userManagementService, Action[] availableActions, StringMessages stringMessages) { this.userManagementService = userManagementService; + AclDialogResources.INSTANCE.css().ensureInjected(); final Collection actionNames = new ArrayList<>(); for (Action a : availableActions) { @@ -90,6 +91,7 @@ public class AclEditPanel extends Composite { // create action editor for allowed actions allowedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, "Allowed action name"); + allowedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().allowedActionsTable()); // TODO: i18n ^v^v allowedActionsEditor.addValueChangeHandler(e -> userGroupsWithAllowedActions @@ -102,6 +104,7 @@ public class AclEditPanel extends Composite { deniedActionsEditor.addValueChangeHandler(e -> userGroupsWithDeniedActions .put(userGroupSingleSelectionModel.getSelectedObject(), toDeniedSet(e.getValue()))); + deniedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().deniedActionsTable()); permissionsCellListPanelUi.add(deniedActionsEditor); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.ui.xml similarity index 100% rename from java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AclEditPanel.ui.xml rename to java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.ui.xml diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java similarity index 98% rename from java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java rename to java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java index e772e46d31f..791c8caa436 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/EditACLDialog.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java @@ -1,4 +1,4 @@ -package com.sap.sse.security.ui.client.component; +package com.sap.sse.security.ui.client.component.editacl; import static com.sap.sse.gwt.client.Notification.NotificationType.ERROR; @@ -18,7 +18,7 @@ import com.sap.sse.security.shared.QualifiedObjectIdentifier; import com.sap.sse.security.shared.SecuredObject; import com.sap.sse.security.shared.impl.AccessControlListImpl; import com.sap.sse.security.ui.client.UserManagementServiceAsync; -import com.sap.sse.security.ui.client.component.EditACLDialog.AclDialogResult; +import com.sap.sse.security.ui.client.component.editacl.EditACLDialog.AclDialogResult; import com.sap.sse.security.ui.client.i18n.StringMessages; public class EditACLDialog extends DataEntryDialog { diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java index a6c45b1795d..5215f7fa0de 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java @@ -49,9 +49,9 @@ import com.sap.sse.security.ui.client.UserManagementServiceAsync; import com.sap.sse.security.ui.client.UserService; import com.sap.sse.security.ui.client.component.AccessControlledActionsColumn; import com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell; -import com.sap.sse.security.ui.client.component.EditACLDialog; import com.sap.sse.security.ui.client.component.EditOwnershipDialog; import com.sap.sse.security.ui.client.component.SecuredObjectOwnerColumn; +import com.sap.sse.security.ui.client.component.editacl.EditACLDialog; import com.sap.sse.security.ui.client.i18n.StringMessages; import com.sap.sse.security.ui.shared.SuccessInfo; import com.sap.sse.security.ui.shared.UserDTO; From fa97d9cb2bc7a6283af20b1724cf61017c114e56 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 28 Nov 2018 10:21:28 +0100 Subject: [PATCH 16/27] make sure to show ownerships for comeptitors and boats --- .../gwt/ui/server/SailingServiceImpl.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 9146306e744..598462c6abe 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1256,12 +1256,17 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S private List convertToCompetitorDTOs(Iterable iterable) { List result = new ArrayList<>(); for (Competitor c : iterable) { - CompetitorDTO competitorDTO = baseDomainFactory.convertToCompetitorDTO(c); - SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorDTO, c.getIdentifier()); + CompetitorDTO competitorDTO = convertToCompetitorDTO(c); result.add(competitorDTO); } return result; } + + private CompetitorDTO convertToCompetitorDTO(Competitor competitor) { + CompetitorDTO competitorDTO = baseDomainFactory.convertToCompetitorDTO(competitor); + SecurityDTOUtil.addSecurityInformation(getSecurityService(), competitorDTO, competitor.getIdentifier()); + return competitorDTO; + } /** * Converts the {@link Competitor} objects passed as {@code iterable} to {@link CompetitorWithBoatDTO} objects with an empty boat. @@ -1302,6 +1307,12 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } return result; } + + private BoatDTO convertToBoatDTO(Boat boat) { + BoatDTO boatDTO = baseDomainFactory.convertToBoatDTO(boat); + SecurityDTOUtil.addSecurityInformation(getSecurityService(), boatDTO, boat.getIdentifier()); + return boatDTO; + } @Override public com.sap.sse.common.Util.Pair> listTracTracRacesInEvent(String eventJsonURL, boolean listHiddenRaces) throws MalformedURLException, IOException, ParseException, org.json.simple.parser.ParseException, URISyntaxException { @@ -5508,17 +5519,17 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.COMPETITOR, SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, competitorStore.getAllCompetitors(), boat -> boat.getIdentifier().toString(), - filteredObject -> result.add(baseDomainFactory.convertToCompetitorDTO(filteredObject))); + filteredObject -> result.add(convertToCompetitorDTO(filteredObject))); } else if (filterCompetitorsWithBoat == true && filterCompetitorsWithoutBoat == false) { getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.COMPETITOR, SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, competitorStore.getCompetitorsWithoutBoat(), boat -> boat.getIdentifier().toString(), - filteredObject -> result.add(baseDomainFactory.convertToCompetitorDTO(filteredObject))); + filteredObject -> result.add(convertToCompetitorDTO(filteredObject))); } else if (filterCompetitorsWithBoat == false && filterCompetitorsWithoutBoat == true) { getSecurityService().filterObjectsWithPermissionForCurrentUser(SecuredDomainType.COMPETITOR, SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, competitorStore.getCompetitorsWithBoat(), boat -> boat.getIdentifier().toString(), - filteredObject -> result.add(baseDomainFactory.convertToCompetitorDTO(filteredObject))); + filteredObject -> result.add(convertToCompetitorDTO(filteredObject))); } return result; } @@ -5668,7 +5679,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, getService().getBaseDomainFactory().getCompetitorAndBoatStore().getBoats(), boat -> boat.getIdentifier().toString(), - filteredObject -> result.add(baseDomainFactory.convertToBoatDTO(filteredObject))); + filteredObject -> result.add(convertToBoatDTO(filteredObject))); return result; } @@ -5679,7 +5690,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S SecuredDomainType.CompetitorAndBoatActions.READ_PUBLIC, getService().getBaseDomainFactory().getCompetitorAndBoatStore().getStandaloneBoats(), boat -> boat.getIdentifier().toString(), - filteredObject -> result.add(baseDomainFactory.convertToBoatDTO(filteredObject))); + filteredObject -> result.add(convertToBoatDTO(filteredObject))); return result; } From 5200b20cd441db527572bece1b50d5cce6b617ba Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 10:32:12 +0100 Subject: [PATCH 17/27] i18n + UI adjustments in EditAclDialog --- .../component/editacl/AclDialogResources.gss | 7 +- .../component/editacl/AclDialogResources.java | 2 + .../component/editacl/AclEditPanel.java | 79 ++++++++++++------- .../component/editacl/AclEditPanel.ui.xml | 3 - .../ui/client/i18n/StringMessages.java | 5 ++ .../ui/client/i18n/StringMessages.properties | 7 +- .../client/i18n/StringMessages_de.properties | 7 +- 7 files changed, 75 insertions(+), 35 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss index 73568cde34f..68f09e2504b 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss @@ -1,5 +1,6 @@ .allowedActionsTable { - margin-right: 10px; + margin-right: 5px; + margin-left: 5px; margin-top: 10px; display: inline-block; } @@ -7,4 +8,8 @@ .deniedActionsTable { margin-top: 10px; display: inline-block; +} +.additionalWidget { + margin-left: 5px; + margin-right: 5px; } \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java index ab5798065f7..ebeb3142212 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java @@ -18,5 +18,7 @@ public interface AclDialogResources extends ClientBundle { String allowedActionsTable(); String deniedActionsTable(); + + String additionalWidget(); } } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java index 674c1575328..3b1a123e820 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java @@ -15,7 +15,6 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.cellview.client.CellList; import com.google.gwt.user.cellview.client.SimplePager; import com.google.gwt.user.cellview.client.SimplePager.TextLocation; @@ -48,17 +47,17 @@ public class AclEditPanel extends Composite { interface AclEditPanelUiBinder extends UiBinder { } - @UiField - Button removeUserGroupButtonUi; - @UiField - Button addUserGroupButtonUi; - @UiField(provided = true) - SuggestBox suggestUserGroupUi; @UiField FlowPanel userGroupCellListPanelUi; @UiField FlowPanel permissionsCellListPanelUi; + private final Button removeUserGroupButtonUi; + private final Button addUserGroupButtonUi; + private final SuggestBox suggestUserGroupUi; + + private final StringMessages stringMessages; + private final StringListEditorComposite allowedActionsEditor; private final StringListEditorComposite deniedActionsEditor; @@ -72,6 +71,7 @@ public class AclEditPanel extends Composite { public AclEditPanel(UserManagementServiceAsync userManagementService, Action[] availableActions, StringMessages stringMessages) { + this.stringMessages = stringMessages; this.userManagementService = userManagementService; AclDialogResources.INSTANCE.css().ensureInjected(); @@ -80,9 +80,16 @@ public class AclEditPanel extends Composite { actionNames.add(a.name()); } - setupUserGroupSuggest(userManagementService); + suggestUserGroupUi = createUserGroupSuggest(userManagementService); + addUserGroupButtonUi = new Button(stringMessages.add()); + removeUserGroupButtonUi = new Button(stringMessages.remove()); + addUserGroupButtonUi.addClickHandler(e -> onUserGroupAdd(e)); + removeUserGroupButtonUi.addClickHandler(e -> onUserGroupRemove(e)); + initWidget(uiBinder.createAndBindUi(this)); - setupCellLists(stringMessages); + userGroupList = createUserGroupCellList(stringMessages); + userGroupCellListPanelUi.add(wrapListUi(userGroupList, stringMessages.userGroups(), suggestUserGroupUi, + addUserGroupButtonUi, removeUserGroupButtonUi)); userGroupSingleSelectionModel.addSelectionChangeHandler(h -> { onUserGroupsChange(); @@ -90,9 +97,9 @@ public class AclEditPanel extends Composite { // create action editor for allowed actions allowedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, - com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, "Allowed action name"); + com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, + stringMessages.allowedActionName()); allowedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().allowedActionsTable()); - // TODO: i18n ^v^v allowedActionsEditor.addValueChangeHandler(e -> userGroupsWithAllowedActions .put(userGroupSingleSelectionModel.getSelectedObject(), toSet(e.getValue()))); @@ -100,7 +107,8 @@ public class AclEditPanel extends Composite { // create action editor for denied actions deniedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, - com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, "Denied action name"); + com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, + stringMessages.deniedActionName()); deniedActionsEditor.addValueChangeHandler(e -> userGroupsWithDeniedActions .put(userGroupSingleSelectionModel.getSelectedObject(), toDeniedSet(e.getValue()))); @@ -128,7 +136,7 @@ public class AclEditPanel extends Composite { removeUserGroupButtonUi.setEnabled(userGroupSingleSelectionModel.getSelectedObject() != null); } - private void setupUserGroupSuggest(UserManagementServiceAsync userManagementService) { + private SuggestBox createUserGroupSuggest(UserManagementServiceAsync userManagementService) { final MultiWordSuggestOracle userGroupOracle = new MultiWordSuggestOracle(); userManagementService.getUserGroups(new AsyncCallback>() { @Override @@ -145,11 +153,11 @@ public class AclEditPanel extends Composite { userGroupOracle.setDefaultSuggestionsFromText(suggestionList); } }); - suggestUserGroupUi = new SuggestBox(userGroupOracle, new TextBox()); + return new SuggestBox(userGroupOracle, new TextBox()); } - private void setupCellLists(StringMessages stringMessages) { - userGroupList = new CellList(new AbstractCell() { + private CellList createUserGroupCellList(StringMessages stringMessages) { + final CellList userGroupCellList = new CellList<>(new AbstractCell() { @Override public void render(Context context, UserGroup value, SafeHtmlBuilder sb) { if (value != null) { @@ -158,11 +166,10 @@ public class AclEditPanel extends Composite { } }); - userGroupList.setSelectionModel(userGroupSingleSelectionModel); - userGroupCellListPanelUi.add(wrapListUi(userGroupList, stringMessages.userGroups())); + userGroupCellList.setSelectionModel(userGroupSingleSelectionModel); userGroupSingleSelectionModel .addSelectionChangeHandler(e -> updateActionsUi(userGroupSingleSelectionModel.getSelectedObject())); - + return userGroupCellList; } private void updateActionsUi(UserGroup selectedUserGroup) { @@ -171,7 +178,7 @@ public class AclEditPanel extends Composite { deniedActionsEditor.setValue(userGroupsWithDeniedActions.get(selectedUserGroup), false); } - private CaptionPanel wrapListUi(CellList cellList, String title) { + private CaptionPanel wrapListUi(CellList cellList, String title, Widget... additionalWidgets) { cellList.setPageSize(10); final SimplePager tenantPager = new SimplePager(TextLocation.CENTER, false, /* fast forward step size */ 50, true); @@ -180,6 +187,15 @@ public class AclEditPanel extends Composite { final VerticalPanel tenantListWrapper = new VerticalPanel(); tenantListWrapper.add(tenantPanel); tenantListWrapper.add(tenantPager); + + // add additional widgets + final FlowPanel additionalWidgetsPanel = new FlowPanel(); + for (Widget additionalWidget : additionalWidgets) { + additionalWidgetsPanel.add(additionalWidget); + additionalWidget.addStyleName(AclDialogResources.INSTANCE.css().additionalWidget()); + } + tenantListWrapper.add(additionalWidgetsPanel); + final CaptionPanel tenantListCaption = new CaptionPanel(title); tenantListCaption.add(tenantListWrapper); return tenantListCaption; @@ -220,22 +236,23 @@ public class AclEditPanel extends Composite { } } - @UiHandler("addUserGroupButtonUi") void onUserGroupAdd(ClickEvent e) { final String userGroupName = suggestUserGroupUi.getValue(); userManagementService.getUserGroupByName(userGroupName, new AsyncCallback() { @Override public void onFailure(Throwable caught) { - // TODO: i18n - Notification.notify("Did not find user group by name x" + userGroupName, NotificationType.ERROR); + Notification.notify(stringMessages.errorMessageUserGroupNameNotFound(userGroupName), + NotificationType.ERROR); } @Override public void onSuccess(UserGroup result) { if (result == null) { - Notification.notify("Did not find user group by name x" + userGroupName, NotificationType.ERROR); + Notification.notify(stringMessages.errorMessageUserGroupNameNotFound(userGroupName), + NotificationType.ERROR); } else { - Notification.notify("Added usergroup x" + userGroupName, NotificationType.SUCCESS); + Notification.notify(stringMessages.successMessageAddedUserGroup(userGroupName), + NotificationType.SUCCESS); userGroupsWithAllowedActions.put(result, new HashSet<>()); userGroupsWithDeniedActions.put(result, new HashSet<>()); refreshUi(); @@ -246,11 +263,15 @@ public class AclEditPanel extends Composite { }); } - @UiHandler("removeUserGroupButtonUi") void onUserGroupRemove(ClickEvent e) { - userGroupsWithAllowedActions.remove(userGroupSingleSelectionModel.getSelectedObject()); - userGroupsWithDeniedActions.remove(userGroupSingleSelectionModel.getSelectedObject()); - refreshUi(); + UserGroup selectedObject = userGroupSingleSelectionModel.getSelectedObject(); + if (selectedObject != null) { + userGroupsWithAllowedActions.remove(selectedObject); + userGroupsWithDeniedActions.remove(selectedObject); + Notification.notify(stringMessages.successMessageRemovedUserGroup(selectedObject.getName()), + NotificationType.SUCCESS); + refreshUi(); + } } public Map> getUserGroupsWithPermissions() { diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.ui.xml b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.ui.xml index 624ba8b93a7..f092d3bc472 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.ui.xml +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.ui.xml @@ -2,9 +2,6 @@ - - - \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java index 689c4387899..7f6921be8a2 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java @@ -156,4 +156,9 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { String editACLForObject(String objectName); String acl(); String errorUpdatingAcl(String name); + String allowedActionName(); + String deniedActionName(); + String errorMessageUserGroupNameNotFound(String name); + String successMessageAddedUserGroup(String name); + String successMessageRemovedUserGroup(String name); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties index a1b379afa87..5e810575d95 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties @@ -163,4 +163,9 @@ usergroupNotFound=User group {0} not found actionChangeACL=Change ACL editACLForObject=Edit ACL for ''{0}'' acl=ACL -errorUpdatingAcl=Error updating ACL: {0}. \ No newline at end of file +errorUpdatingAcl=Error updating ACL: {0}. +allowedActionName=Allowed action name +deniedActionName=Denied action name +errorMessageUserGroupNameNotFound=Did not find user group by name {0}. +successMessageAddedUserGroup=Added user group {0}. +successMessageRemovedUserGroup=Removed user group {0}. \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties index 27e0305bd49..8f27bb5625c 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties @@ -162,4 +162,9 @@ usergroupNotFound=Benutzergruppe {0} nicht gefunden actionChangeACL=ACL ändern editACLForObject=ACL für ''{0}'' ändern acl=ACL -errorUpdatingAcl=Fehler beim Aktualisieren der ACL: {0}. \ No newline at end of file +errorUpdatingAcl=Fehler beim Aktualisieren der ACL: {0}. +allowedActionName=Erlaubter Aktionsname +deniedActionName=Verweigerter Aktionsname +errorMessageUserGroupNameNotFound=Benutzergruppe nicht gefunden: {0}. +successMessageAddedUserGroup=Benutzergruppe hinzugefügt: {0}. +successMessageRemovedUserGroup=Benutzergruppe entfernt: {0}. \ No newline at end of file From daae759bc016d18d4bbf66935e53a9107af27a95 Mon Sep 17 00:00:00 2001 From: Thomas Wiese Date: Wed, 28 Nov 2018 10:48:30 +0100 Subject: [PATCH 18/27] add ownership migration for comepttiors and boat --- .../com/sap/sailing/server/impl/RacingEventServiceImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 607714aaf47..b1e7b651ad5 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -995,6 +995,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } securityService.assumeOwnershipMigrated(SecuredDomainType.MEDIA_TRACK.getName(), SecuredDomainType.getAllInstances()); + for (Competitor competitor : getCompetitorAndBoatStore().getAllCompetitors()) { + securityService.migrateOwnership(competitor, SecuredDomainType.getAllInstances()); + } + for (Boat boat : getCompetitorAndBoatStore().getBoats()) { + securityService.migrateOwnership(boat, SecuredDomainType.getAllInstances()); + } } private void loadRaceIDToRegattaAssociations() { From 497929a3e2f2542187e66641934cf608217968cc Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 10:50:26 +0100 Subject: [PATCH 19/27] javadoc and minor refactor for EditACLDialog --- .../component/editacl/AclEditPanel.java | 101 ++++++++++++------ .../component/editacl/EditACLDialog.java | 13 +-- 2 files changed, 72 insertions(+), 42 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java index 3b1a123e820..df6d3e16486 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java @@ -75,11 +75,6 @@ public class AclEditPanel extends Composite { this.userManagementService = userManagementService; AclDialogResources.INSTANCE.css().ensureInjected(); - final Collection actionNames = new ArrayList<>(); - for (Action a : availableActions) { - actionNames.add(a.name()); - } - suggestUserGroupUi = createUserGroupSuggest(userManagementService); addUserGroupButtonUi = new Button(stringMessages.add()); removeUserGroupButtonUi = new Button(stringMessages.remove()); @@ -87,20 +82,25 @@ public class AclEditPanel extends Composite { removeUserGroupButtonUi.addClickHandler(e -> onUserGroupRemove(e)); initWidget(uiBinder.createAndBindUi(this)); - userGroupList = createUserGroupCellList(stringMessages); - userGroupCellListPanelUi.add(wrapListUi(userGroupList, stringMessages.userGroups(), suggestUserGroupUi, - addUserGroupButtonUi, removeUserGroupButtonUi)); + userGroupList = createUserGroupCellList(); + userGroupCellListPanelUi.add(wrapIntoCaptionPanel(userGroupList, stringMessages.userGroups(), + suggestUserGroupUi, addUserGroupButtonUi, removeUserGroupButtonUi)); userGroupSingleSelectionModel.addSelectionChangeHandler(h -> { onUserGroupsChange(); }); + // retrieve set of available action names + final Collection actionNames = new ArrayList<>(); + for (Action a : availableActions) { + actionNames.add(a.name()); + } + // create action editor for allowed actions allowedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, stringMessages.allowedActionName()); allowedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().allowedActionsTable()); - allowedActionsEditor.addValueChangeHandler(e -> userGroupsWithAllowedActions .put(userGroupSingleSelectionModel.getSelectedObject(), toSet(e.getValue()))); permissionsCellListPanelUi.add(allowedActionsEditor); @@ -109,33 +109,18 @@ public class AclEditPanel extends Composite { deniedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, stringMessages.deniedActionName()); - deniedActionsEditor.addValueChangeHandler(e -> userGroupsWithDeniedActions - .put(userGroupSingleSelectionModel.getSelectedObject(), toDeniedSet(e.getValue()))); + .put(userGroupSingleSelectionModel.getSelectedObject(), toDeniedActionSet(e.getValue()))); deniedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().deniedActionsTable()); permissionsCellListPanelUi.add(deniedActionsEditor); } - private Set toSet(Iterable iter) { - final Set set = new HashSet<>(); - for (T t : iter) { - set.add(t); - } - return set; - } - - private Set toDeniedSet(Iterable iter) { - final Set set = new HashSet<>(); - for (String s : iter) { - set.add(s.startsWith("!") ? s : "!" + s); - } - return set; - } - + /** Called when the selected {@link UserGroup} changes. */ private void onUserGroupsChange() { removeUserGroupButtonUi.setEnabled(userGroupSingleSelectionModel.getSelectedObject() != null); } + /** @return UI element for selection of {@link UserGroup} elements. */ private SuggestBox createUserGroupSuggest(UserManagementServiceAsync userManagementService) { final MultiWordSuggestOracle userGroupOracle = new MultiWordSuggestOracle(); userManagementService.getUserGroups(new AsyncCallback>() { @@ -156,7 +141,8 @@ public class AclEditPanel extends Composite { return new SuggestBox(userGroupOracle, new TextBox()); } - private CellList createUserGroupCellList(StringMessages stringMessages) { + /** @return the UI element for visualizing {@link UserGroup} elements. */ + private CellList createUserGroupCellList() { final CellList userGroupCellList = new CellList<>(new AbstractCell() { @Override public void render(Context context, UserGroup value, SafeHtmlBuilder sb) { @@ -168,17 +154,24 @@ public class AclEditPanel extends Composite { userGroupCellList.setSelectionModel(userGroupSingleSelectionModel); userGroupSingleSelectionModel - .addSelectionChangeHandler(e -> updateActionsUi(userGroupSingleSelectionModel.getSelectedObject())); + .addSelectionChangeHandler(e -> updateActionEditors(userGroupSingleSelectionModel.getSelectedObject())); return userGroupCellList; } - private void updateActionsUi(UserGroup selectedUserGroup) { + /** + * Updates the {@link #allowedActionsEditor} and {@link #deniedActionsEditor} when the selected UserGroup changed. + */ + private void updateActionEditors(UserGroup selectedUserGroup) { onUserGroupsChange(); allowedActionsEditor.setValue(userGroupsWithAllowedActions.get(selectedUserGroup), false); deniedActionsEditor.setValue(userGroupsWithDeniedActions.get(selectedUserGroup), false); } - private CaptionPanel wrapListUi(CellList cellList, String title, Widget... additionalWidgets) { + /** + * Wraps the CellList together with a title and additional widgets (e.g. add/remove buttons) into a + * {@link CaptionPanel}. + */ + private CaptionPanel wrapIntoCaptionPanel(CellList cellList, String title, Widget... additionalWidgets) { cellList.setPageSize(10); final SimplePager tenantPager = new SimplePager(TextLocation.CENTER, false, /* fast forward step size */ 50, true); @@ -201,6 +194,11 @@ public class AclEditPanel extends Composite { return tenantListCaption; } + /** + * Updates the ACL edited in the EditAclDialog. Splits combinedActions retrieved by + * {@link AccessControlList#getActionsByUserGroup()} into {@link #allowedActionsEditor} and + * {@link #deniedActionsEditor}. + */ public void updateAcl(AccessControlList acl) { final Map> combinedActions = (acl != null) ? acl.getActionsByUserGroup() != null ? new HashMap<>(acl.getActionsByUserGroup()) : new HashMap<>() @@ -223,6 +221,10 @@ public class AclEditPanel extends Composite { refreshUi(); } + /** + * Updates the UI by refreshing the {@link #userGroupList} and selects an element to trigger the update of + * {@link #allowedActionsEditor} and {@link #deniedActionsEditor}. + */ private void refreshUi() { final Set combinedKeySet = new HashSet<>(); combinedKeySet.addAll(userGroupsWithAllowedActions.keySet()); @@ -236,8 +238,11 @@ public class AclEditPanel extends Composite { } } - void onUserGroupAdd(ClickEvent e) { + /** Called when the user clicks on the 'Add' button */ + private void onUserGroupAdd(ClickEvent e) { final String userGroupName = suggestUserGroupUi.getValue(); + + // get UserGroup object corresponding to user group name userManagementService.getUserGroupByName(userGroupName, new AsyncCallback() { @Override public void onFailure(Throwable caught) { @@ -263,7 +268,8 @@ public class AclEditPanel extends Composite { }); } - void onUserGroupRemove(ClickEvent e) { + /** Called when the user clicks on the 'Remove' button */ + private void onUserGroupRemove(ClickEvent e) { UserGroup selectedObject = userGroupSingleSelectionModel.getSelectedObject(); if (selectedObject != null) { userGroupsWithAllowedActions.remove(selectedObject); @@ -274,7 +280,8 @@ public class AclEditPanel extends Composite { } } - public Map> getUserGroupsWithPermissions() { + /** Merges {@link #userGroupsWithAllowedActions} and {@link #userGroupsWithDeniedActions}. */ + public Map> getUserGroupsWithCombinedActions() { final Map> combinedActions = new HashMap<>(userGroupsWithAllowedActions); for (Map.Entry> actionEntry : userGroupsWithDeniedActions.entrySet()) { if (combinedActions.containsKey(actionEntry.getKey())) { @@ -287,4 +294,30 @@ public class AclEditPanel extends Composite { return combinedActions; } + /** Converts an {@link Iterable} into a {@link Set}. */ + private Set toSet(Iterable iter) { + Set resultSet; + if (iter instanceof Set) { + resultSet = (Set) iter; + } else { + resultSet = new HashSet<>(); + for (T t : iter) { + resultSet.add(t); + } + } + return resultSet; + } + + /** + * Converts an {@link Iterable} into a {@link Set} and adds a '!' in front of each String to mark the action as + * denied. + */ + private Set toDeniedActionSet(Iterable iter) { + final Set set = new HashSet<>(); + for (String s : iter) { + set.add(s.startsWith("!") ? s : "!" + s); + } + return set; + } + } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java index 791c8caa436..e8de1a3ff01 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/EditACLDialog.java @@ -10,6 +10,7 @@ import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sse.common.Named; import com.sap.sse.gwt.client.Notification; +import com.sap.sse.gwt.client.Notification.NotificationType; import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.security.shared.AccessControlList; import com.sap.sse.security.shared.HasPermissions; @@ -47,8 +48,7 @@ public class EditACLDialog extends DataEntryDialog { private EditACLDialog(UserManagementServiceAsync userManagementService, QualifiedObjectIdentifier qualifiedObjectIdentifier, Action[] availableActions, - StringMessages stringMessages, - DialogCallback callback) { + StringMessages stringMessages, DialogCallback callback) { super(stringMessages.acl(), stringMessages.editACLForObject(qualifiedObjectIdentifier.toString()), stringMessages.ok(), stringMessages.cancel(), new Validator(), callback); aclEditPanel = new AclEditPanel(userManagementService, availableActions, stringMessages); @@ -57,8 +57,7 @@ public class EditACLDialog extends DataEntryDialog { @Override public void onFailure(Throwable caught) { - // TODO Auto-generated method stub - + Notification.notify(caught.getMessage(), NotificationType.ERROR); } @Override @@ -75,7 +74,7 @@ public class EditACLDialog extends DataEntryDialog { @Override protected AclDialogResult getResult() { - return new AclDialogResult(new AccessControlListImpl(aclEditPanel.getUserGroupsWithPermissions())); + return new AclDialogResult(new AccessControlListImpl(aclEditPanel.getUserGroupsWithCombinedActions())); } /** @@ -150,9 +149,7 @@ public class EditACLDialog extends DataEntryDialog { @Override public final void onFailure(Throwable caught) { - // TODO: v i18n v - Notification.notify(stringMessages.errorUpdatingAcl(securedObject.getName()), - ERROR); + Notification.notify(stringMessages.errorUpdatingAcl(securedObject.getName()), ERROR); } }); } From 199f3693a8d39dd950a332661f3a39a9f29d317e Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 28 Nov 2018 11:02:29 +0100 Subject: [PATCH 20/27] added null-safety for start/finish line construction in case COG/SOG is unknown Change-Id: I04e2890a354355f1c6b160667a1ebe0cd0769859 --- .../jaxrs/api/LeaderboardsResource.java | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java index 4388f50ecbc..602a80f95f5 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -744,32 +744,38 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { final Waypoint result; if (when != null) { final Iterable> positionsAndCogsAndSogs = getPositionsAndCogsAndSogs(trackedRace, when, extrapolate); - final Bearing averageCourse = getAverageCourse(positionsAndCogsAndSogs); - final Bearing fromStartBoatToPinEnd = averageCourse.add(new DegreeBearingImpl(-90)); - final Pair leftmostAndRightmostPositionsAtStart = getPositionsFarthestAheadAndFurthestBack(positionsAndCogsAndSogs, - averageCourse.add(new DegreeBearingImpl(90))); - final Position farthestAhead = getPositionsFarthestAheadAndFurthestBack(positionsAndCogsAndSogs, averageCourse).getA(); - if (leftmostAndRightmostPositionsAtStart.getA() != null && leftmostAndRightmostPositionsAtStart.getB() != null && - farthestAhead != null) { - final Position startBoatPosition = leftmostAndRightmostPositionsAtStart.getB().translateGreatCircle( - fromStartBoatToPinEnd.reverse(), LINE_MARGIN); - final Position pinEndPosition = leftmostAndRightmostPositionsAtStart.getA().translateGreatCircle( - fromStartBoatToPinEnd, LINE_MARGIN); - final Mark startBoat = getService().getBaseDomainFactory().getOrCreateMark(UUID.randomUUID(), "Auto "+waypointName+" Boat"); - RegattaLogDefineMarkEventImpl defineStartBoatEvent = new RegattaLogDefineMarkEventImpl(MillisecondsTimePoint.now(), - getService().getServerAuthor(), when, UUID.randomUUID(), startBoat); - regattaLog.add(defineStartBoatEvent); - final Mark pinEnd = getService().getBaseDomainFactory().getOrCreateMark(UUID.randomUUID(), "Auto "+waypointName+" Pin End"); - RegattaLogDefineMarkEventImpl definePinEndEvent = new RegattaLogDefineMarkEventImpl(MillisecondsTimePoint.now(), - getService().getServerAuthor(), when, UUID.randomUUID(), pinEnd); - regattaLog.add(definePinEndEvent); - getRaceLogTrackingAdapter().pingMark(regattaLog, startBoat, new GPSFixImpl(startBoatPosition, when), getService()); - getRaceLogTrackingAdapter().pingMark(regattaLog, pinEnd, new GPSFixImpl(pinEndPosition, when), getService()); - final ControlPoint startLineControlPoint = getService().getBaseDomainFactory().getOrCreateControlPointWithTwoMarks( - UUID.randomUUID(), "Auto "+waypointName+" Line", pinEnd, startBoat); - result = getService().getBaseDomainFactory().createWaypoint(startLineControlPoint, PassingInstruction.Line); + final Bearing averageCourse = getAverageCourse(positionsAndCogsAndSogs); // may return null, e.g., if COG/SOG information is missing + if (averageCourse != null) { + final Bearing fromStartBoatToPinEnd = averageCourse.add(new DegreeBearingImpl(-90)); + final Pair leftmostAndRightmostPositionsAtStart = getPositionsFarthestAheadAndFurthestBack(positionsAndCogsAndSogs, + averageCourse.add(new DegreeBearingImpl(90))); + final Position farthestAhead = getPositionsFarthestAheadAndFurthestBack(positionsAndCogsAndSogs, averageCourse).getA(); + if (leftmostAndRightmostPositionsAtStart.getA() != null && leftmostAndRightmostPositionsAtStart.getB() != null && + farthestAhead != null) { + final Position startBoatPosition = leftmostAndRightmostPositionsAtStart.getB().translateGreatCircle( + fromStartBoatToPinEnd.reverse(), LINE_MARGIN); + final Position pinEndPosition = leftmostAndRightmostPositionsAtStart.getA().translateGreatCircle( + fromStartBoatToPinEnd, LINE_MARGIN); + final Mark startBoat = getService().getBaseDomainFactory().getOrCreateMark(UUID.randomUUID(), "Auto "+waypointName+" Boat"); + RegattaLogDefineMarkEventImpl defineStartBoatEvent = new RegattaLogDefineMarkEventImpl(MillisecondsTimePoint.now(), + getService().getServerAuthor(), when, UUID.randomUUID(), startBoat); + regattaLog.add(defineStartBoatEvent); + final Mark pinEnd = getService().getBaseDomainFactory().getOrCreateMark(UUID.randomUUID(), "Auto "+waypointName+" Pin End"); + RegattaLogDefineMarkEventImpl definePinEndEvent = new RegattaLogDefineMarkEventImpl(MillisecondsTimePoint.now(), + getService().getServerAuthor(), when, UUID.randomUUID(), pinEnd); + regattaLog.add(definePinEndEvent); + getRaceLogTrackingAdapter().pingMark(regattaLog, startBoat, new GPSFixImpl(startBoatPosition, when), getService()); + getRaceLogTrackingAdapter().pingMark(regattaLog, pinEnd, new GPSFixImpl(pinEndPosition, when), getService()); + final ControlPoint startLineControlPoint = getService().getBaseDomainFactory().getOrCreateControlPointWithTwoMarks( + UUID.randomUUID(), "Auto "+waypointName+" Line", pinEnd, startBoat); + result = getService().getBaseDomainFactory().createWaypoint(startLineControlPoint, PassingInstruction.Line); + } else { + result = null; + } } else { result = null; + logger.warning(()->"COG/SOG information for race "+trackedRace.getRace().getName()+" at "+when+ + " missing. Cannot construct a line for waypoint "+waypointName+" enclosing tracks with unknown course."); } } else { result = null; From 8336cc3f4309ca7b71d7fd42428989339db8a39a Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 11:04:50 +0100 Subject: [PATCH 21/27] adjusted styling of EditAclDialog --- .../client/component/editacl/AclDialogResources.gss | 10 ++++++++-- .../client/component/editacl/AclDialogResources.java | 2 ++ .../ui/client/component/editacl/AclEditPanel.java | 11 ++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss index 68f09e2504b..63e8c6a0e84 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss @@ -2,14 +2,20 @@ margin-right: 5px; margin-left: 5px; margin-top: 10px; - display: inline-block; + display: inline; } .deniedActionsTable { margin-top: 10px; - display: inline-block; + display: inline; } + .additionalWidget { margin-left: 5px; margin-right: 5px; +} + +.userGroupTextBox { + min-width: 200px; + margin-bottom: 5px; } \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java index ebeb3142212..6182ca84321 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.java @@ -20,5 +20,7 @@ public interface AclDialogResources extends ClientBundle { String deniedActionsTable(); String additionalWidget(); + + String userGroupTextBox(); } } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java index df6d3e16486..c4afdf46618 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java @@ -138,7 +138,12 @@ public class AclEditPanel extends Composite { userGroupOracle.setDefaultSuggestionsFromText(suggestionList); } }); - return new SuggestBox(userGroupOracle, new TextBox()); + TextBox textBox = new TextBox(); + textBox.getElement().setPropertyString("placeholder", stringMessages.enterUserGroupName()); + + SuggestBox suggestBox = new SuggestBox(userGroupOracle, textBox); + suggestBox.addStyleName(AclDialogResources.INSTANCE.css().userGroupTextBox()); + return suggestBox; } /** @return the UI element for visualizing {@link UserGroup} elements. */ @@ -178,8 +183,6 @@ public class AclEditPanel extends Composite { tenantPager.setDisplay(cellList); final ScrollPanel tenantPanel = new ScrollPanel(cellList); final VerticalPanel tenantListWrapper = new VerticalPanel(); - tenantListWrapper.add(tenantPanel); - tenantListWrapper.add(tenantPager); // add additional widgets final FlowPanel additionalWidgetsPanel = new FlowPanel(); @@ -188,6 +191,8 @@ public class AclEditPanel extends Composite { additionalWidget.addStyleName(AclDialogResources.INSTANCE.css().additionalWidget()); } tenantListWrapper.add(additionalWidgetsPanel); + tenantListWrapper.add(tenantPanel); + tenantListWrapper.add(tenantPager); final CaptionPanel tenantListCaption = new CaptionPanel(title); tenantListCaption.add(tenantListWrapper); From b0d4a25a41b3449c6ee2ee8cebc8f8e46ac2194b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 28 Nov 2018 10:30:51 +0100 Subject: [PATCH 22/27] Removed unused constructors --- .../src/com/sap/sailing/domain/common/dto/RaceDTO.java | 4 ---- .../gwt/ui/shared/RaceWithCompetitorsAndBoatsDTO.java | 5 ----- 2 files changed, 9 deletions(-) mode change 100755 => 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java old mode 100755 new mode 100644 index 5142ada18e0..9e856a07fea --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java @@ -30,10 +30,6 @@ public class RaceDTO extends BasicRaceDTO { public RaceDTO() {} - public RaceDTO(RegattaAndRaceIdentifier raceIdentifier) { - this(raceIdentifier, null, false); - } - public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) { super(raceIdentifier, trackedRace); this.regattaName = raceIdentifier.getRegattaName(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceWithCompetitorsAndBoatsDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceWithCompetitorsAndBoatsDTO.java index fc01a9db971..dd03b609d82 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceWithCompetitorsAndBoatsDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/RaceWithCompetitorsAndBoatsDTO.java @@ -24,11 +24,6 @@ public class RaceWithCompetitorsAndBoatsDTO extends RaceDTO { this.competitorsAndBoats = competitorsAndBoats; } - public RaceWithCompetitorsAndBoatsDTO(RegattaAndRaceIdentifier raceIdentifier, Map competitorsAndBoats) { - super(raceIdentifier); - this.competitorsAndBoats = competitorsAndBoats; - } - public Map getCompetitorsAndBoats() { return competitorsAndBoats; } From 392cd3d682fdd84d5b621699936fd5f0a93b4cc6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 28 Nov 2018 10:52:46 +0100 Subject: [PATCH 23/27] Implemented initial ownership UI for TrackedRaces --- .../sailing/domain/common/dto/RaceDTO.java | 36 ++++++++++++++++++- .../AbstractEventManagementPanel.java | 16 ++++++--- .../AbstractRaceManagementPanel.java | 12 +++++-- .../AbstractTrackedRacesListComposite.java | 35 +++++++++++++++++- .../adminconsole/AdminConsoleEntryPoint.java | 4 +-- .../TrackedRacesListComposite.java | 13 +++++-- .../TrackedRacesManagementPanel.java | 8 +++-- .../gwt/ui/server/SailingServiceImpl.java | 1 + 8 files changed, 108 insertions(+), 17 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java index 9e856a07fea..52551f5efc8 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/RaceDTO.java @@ -2,6 +2,11 @@ package com.sap.sailing.domain.common.dto; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; +import com.sap.sse.security.shared.AccessControlList; +import com.sap.sse.security.shared.Ownership; +import com.sap.sse.security.shared.SecuredObject; +import com.sap.sse.security.shared.SecurityInformationDTO; +import com.sap.sse.security.shared.impl.WildcardPermissionEncoder; /** * Master data about a single race that is to be transferred to the client.

@@ -9,8 +14,10 @@ import com.sap.sailing.domain.common.RegattaNameAndRaceName; * @author Axel Uhl (d043530) * */ -public class RaceDTO extends BasicRaceDTO { +public class RaceDTO extends BasicRaceDTO implements SecuredObject { private static final long serialVersionUID = 2613189982608149975L; + + private SecurityInformationDTO securityInformation = new SecurityInformationDTO(); /** * Tells if this race is currently being tracked, meaning that a {@link RaceTracker} is @@ -89,4 +96,31 @@ public class RaceDTO extends BasicRaceDTO { return false; return true; } + + @Override + public final AccessControlList getAccessControlList() { + return securityInformation.getAccessControlList(); + } + + @Override + public final Ownership getOwnership() { + return securityInformation.getOwnership(); + } + + @Override + public final void setAccessControlList(final AccessControlList accessControlList) { + this.securityInformation.setAccessControlList(accessControlList); + } + + @Override + public final void setOwnership(final Ownership ownership) { + this.securityInformation.setOwnership(ownership); + } + + public String getTypeRelativeIdentifierAsString() { + RegattaAndRaceIdentifier regattaAndRaceId = getRaceIdentifier(); + WildcardPermissionEncoder wildcardPermissionEncoder = new WildcardPermissionEncoder(); + return wildcardPermissionEncoder.encodeStringList(regattaAndRaceId.getRegattaName(), + regattaAndRaceId.getRaceName()); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java index df4261fa983..2ee9bb0ea01 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractEventManagementPanel.java @@ -24,6 +24,7 @@ import com.sap.sse.common.Util; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.Notification; import com.sap.sse.gwt.client.Notification.NotificationType; +import com.sap.sse.security.ui.client.UserService; public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel { protected final TrackedRacesListComposite trackedRacesListComposite; @@ -31,8 +32,14 @@ public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel private final ListBox availableRegattasListBox; public AbstractEventManagementPanel(SailingServiceAsync sailingService, - RegattaRefresher regattaRefresher, - ErrorReporter errorReporter, boolean actionButtonsEnabled, StringMessages stringMessages) { + RegattaRefresher regattaRefresher, ErrorReporter errorReporter, boolean actionButtonsEnabled, + StringMessages stringMessages) { + this(sailingService, null, regattaRefresher, errorReporter, actionButtonsEnabled, stringMessages); + } + + public AbstractEventManagementPanel(SailingServiceAsync sailingService, UserService userService, + RegattaRefresher regattaRefresher, ErrorReporter errorReporter, boolean actionButtonsEnabled, + StringMessages stringMessages) { super(sailingService, regattaRefresher, errorReporter, stringMessages); this.availableRegattas = new ArrayList(); @@ -40,9 +47,8 @@ public abstract class AbstractEventManagementPanel extends AbstractRegattaPanel this.availableRegattasListBox.ensureDebugId("AvailableRegattasListBox"); // TrackedEventsComposite should exist in every *ManagementPanel. - trackedRacesListComposite = new TrackedRacesListComposite(null, null, sailingService, errorReporter, - regattaRefresher, - stringMessages, /* multiselection */ true, actionButtonsEnabled); + trackedRacesListComposite = new TrackedRacesListComposite(null, null, sailingService, userService, + errorReporter, regattaRefresher, stringMessages, /* multiselection */ true, actionButtonsEnabled); trackedRacesListComposite.ensureDebugId("TrackedRacesListComposite"); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractRaceManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractRaceManagementPanel.java index cd32c191b96..d4ba6e4ea7a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractRaceManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractRaceManagementPanel.java @@ -14,6 +14,7 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.RegattaDTO; import com.sap.sse.gwt.client.ErrorReporter; +import com.sap.sse.security.ui.client.UserService; public abstract class AbstractRaceManagementPanel extends AbstractEventManagementPanel { protected RegattaAndRaceIdentifier singleSelectedRace; @@ -26,10 +27,15 @@ public abstract class AbstractRaceManagementPanel extends AbstractEventManagemen protected final VerticalPanel selectedRaceContentPanel; - public AbstractRaceManagementPanel(final SailingServiceAsync sailingService, - ErrorReporter errorReporter, + public AbstractRaceManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter, RegattaRefresher regattaRefresher, boolean actionButtonsEnabled, StringMessages stringMessages) { - super(sailingService, regattaRefresher, errorReporter, actionButtonsEnabled, stringMessages); + this(sailingService, null, errorReporter, regattaRefresher, actionButtonsEnabled, stringMessages); + } + + public AbstractRaceManagementPanel(final SailingServiceAsync sailingService, + UserService userService, ErrorReporter errorReporter, + RegattaRefresher regattaRefresher, boolean actionButtonsEnabled, StringMessages stringMessages) { + super(sailingService, userService, regattaRefresher, errorReporter, actionButtonsEnabled, stringMessages); VerticalPanel mainPanel = new VerticalPanel(); this.setWidget(mainPanel); mainPanel.setWidth("100%"); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java index 2276205820d..b644284cf54 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractTrackedRacesListComposite.java @@ -1,9 +1,12 @@ package com.sap.sailing.gwt.ui.adminconsole; +import static com.sap.sse.security.shared.HasPermissions.DefaultActions.CHANGE_OWNERSHIP; + import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Set; +import java.util.function.Function; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.dom.client.Document; @@ -37,6 +40,7 @@ import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.TrackedRaceStatusEnum; import com.sap.sailing.domain.common.dto.RaceDTO; +import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sailing.gwt.ui.client.RegattaRefresher; import com.sap.sailing.gwt.ui.client.RegattasDisplayer; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; @@ -54,6 +58,13 @@ import com.sap.sse.gwt.client.shared.components.AbstractCompositeComponent; import com.sap.sse.gwt.client.shared.components.Component; import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent; import com.sap.sse.gwt.client.shared.settings.ComponentContext; +import com.sap.sse.security.shared.HasPermissions; +import com.sap.sse.security.ui.client.UserService; +import com.sap.sse.security.ui.client.component.AccessControlledActionsColumn; +import com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell; +import com.sap.sse.security.ui.client.component.EditOwnershipDialog; +import com.sap.sse.security.ui.client.component.EditOwnershipDialog.DialogConfig; +import com.sap.sse.security.ui.client.component.SecuredObjectOwnerColumn; public abstract class AbstractTrackedRacesListComposite extends AbstractCompositeComponent implements RegattasDisplayer { @@ -85,6 +96,8 @@ public abstract class AbstractTrackedRacesListComposite extends AbstractComposit private ListBox listBoxRegattas; + private final UserService userService; + public static class AnchorCell extends AbstractCell { @Override public void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml safeHtml, SafeHtmlBuilder sb) { @@ -95,13 +108,14 @@ public abstract class AbstractTrackedRacesListComposite extends AbstractComposit public AbstractTrackedRacesListComposite(Component parent, ComponentContext context, final SailingServiceAsync sailingService, final ErrorReporter errorReporter, final RegattaRefresher regattaRefresher, - final StringMessages stringMessages, boolean hasMultiSelection) { + final StringMessages stringMessages, boolean hasMultiSelection, UserService userService) { super(parent, context); this.sailingService = sailingService; this.errorReporter = errorReporter; this.regattaRefresher = regattaRefresher; this.multiSelection = hasMultiSelection; this.stringMessages = stringMessages; + this.userService = userService; } public void setRegattaFilterValue(String regattaName) { @@ -395,6 +409,25 @@ public abstract class AbstractTrackedRacesListComposite extends AbstractComposit raceTable.addColumn(hasGPSDataColumn, stringMessages.gpsData()); raceTable.addColumn(raceStatusColumn, stringMessages.status()); raceTable.addColumn(raceLiveDelayColumn, stringMessages.delayInSeconds()); + + if (userService != null) { + final SecuredObjectOwnerColumn groupColumn = SecuredObjectOwnerColumn.getGroupOwnerColumn(); + groupColumn.setSortable(true); + final SecuredObjectOwnerColumn userColumn = SecuredObjectOwnerColumn.getUserOwnerColumn(); + userColumn.setSortable(true); + + final HasPermissions type = SecuredDomainType.TRACKED_RACE; + final Function idFactory = race -> race.getTypeRelativeIdentifierAsString(); + final AccessControlledActionsColumn actionsColumn = new AccessControlledActionsColumn<>( + new DefaultActionsImagesBarCell(stringMessages), userService, type, idFactory); + final DialogConfig config = EditOwnershipDialog.create(userService.getUserManagementService(), type, + idFactory, race -> regattaRefresher.fillRegattas(), stringMessages); + actionsColumn.addAction(EventConfigImagesBarCell.ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, config::openDialog); + + raceTable.addColumn(groupColumn, stringMessages.group()); + raceTable.addColumn(userColumn, stringMessages.user()); + raceTable.addColumn(actionsColumn, stringMessages.actions()); + } } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java index 57fb9fc15c6..e694769cd25 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java @@ -159,8 +159,8 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements final HorizontalTabLayoutPanel racesTabPanel = panel.addVerticalTab(getStringMessages().trackedRaces(), "RacesPanel"); racesTabPanel.ensureDebugId("RacesPanel"); - final TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel(getSailingService(), this, - this, getStringMessages()); + final TrackedRacesManagementPanel trackedRacesManagementPanel = new TrackedRacesManagementPanel( + getSailingService(), getUserService(), this, this, getStringMessages()); trackedRacesManagementPanel.ensureDebugId("TrackedRacesManagement"); panel.addToTabPanel(racesTabPanel, new DefaultRefreshableAdminConsolePanel(trackedRacesManagementPanel) { @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java index 70fd97b0bd2..a36683ed86a 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java @@ -26,6 +26,7 @@ import com.sap.sse.gwt.client.async.MarkedAsyncCallback; import com.sap.sse.gwt.client.shared.components.Component; import com.sap.sse.gwt.client.shared.components.SettingsDialog; import com.sap.sse.gwt.client.shared.settings.ComponentContext; +import com.sap.sse.security.ui.client.UserService; /** * Shows the currently tracked events/races in a table. Updated if subscribed as an {@link RegattasDisplayer}, e.g., with @@ -41,10 +42,18 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite private boolean actionButtonsEnabled; public TrackedRacesListComposite(Component parent, ComponentContext context, - final SailingServiceAsync sailingService, + final SailingServiceAsync sailingService, final ErrorReporter errorReporter, + final RegattaRefresher regattaRefresher, final StringMessages stringMessages, boolean hasMultiSelection, + boolean actionButtonsEnabled) { + this(parent, context, sailingService, null, errorReporter, regattaRefresher, stringMessages, hasMultiSelection, + actionButtonsEnabled); + } + + public TrackedRacesListComposite(Component parent, ComponentContext context, + final SailingServiceAsync sailingService, UserService userService, final ErrorReporter errorReporter, final RegattaRefresher regattaRefresher, final StringMessages stringMessages, boolean hasMultiSelection, boolean actionButtonsEnabled) { - super(parent, context, sailingService, errorReporter, regattaRefresher, stringMessages, hasMultiSelection); + super(parent, context, sailingService, errorReporter, regattaRefresher, stringMessages, hasMultiSelection, userService); this.raceIsTrackedRaceChangeListener = new HashSet(); this.actionButtonsEnabled = actionButtonsEnabled; createUI(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java index d7c70fc7ed6..48ad38cd935 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesManagementPanel.java @@ -18,6 +18,7 @@ import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; +import com.sap.sse.security.ui.client.UserService; public class TrackedRacesManagementPanel extends AbstractRaceManagementPanel { private final DateTimeFormatRenderer dateFormatter = new DateTimeFormatRenderer( @@ -29,9 +30,10 @@ public class TrackedRacesManagementPanel extends AbstractRaceManagementPanel { private final Grid raceDataGrid; - public TrackedRacesManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter, - RegattaRefresher regattaRefresher, final StringMessages stringMessages) { - super(sailingService, errorReporter, regattaRefresher, /* actionButtonsEnabled */ true, stringMessages); + public TrackedRacesManagementPanel(final SailingServiceAsync sailingService, UserService userService, + ErrorReporter errorReporter, RegattaRefresher regattaRefresher, final StringMessages stringMessages) { + super(sailingService, userService, errorReporter, regattaRefresher, /* actionButtonsEnabled */ true, + stringMessages); HorizontalPanel controlsPanel = new HorizontalPanel(); Button setStartTimeButton = new Button(stringMessages.setStartTimeReceived(), new ClickHandler() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 598462c6abe..1176b1ab4ab 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1240,6 +1240,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S Map competitorAndBoatDTOs = baseDomainFactory.convertToCompetitorAndBoatDTOs(r.getCompetitorsAndTheirBoats()); RaceWithCompetitorsAndBoatsDTO raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorAndBoatDTOs, trackedRaceDTO, getService().isRaceBeingTracked(regatta, r)); + SecurityDTOUtil.addSecurityInformation(getSecurityService(), raceDTO, trackedRace.getIdentifier()); if (trackedRace != null) { getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO); } From 42ef65cb777f459e5c4db645870552d1c4acff54 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 11:18:17 +0100 Subject: [PATCH 24/27] adjusted styling +i18n in EditACLDialog --- .../component/editacl/AclDialogResources.gss | 2 ++ .../ui/client/component/editacl/AclEditPanel.java | 14 ++++++++++---- .../security/ui/client/i18n/StringMessages.java | 3 +++ .../ui/client/i18n/StringMessages.properties | 4 +++- .../ui/client/i18n/StringMessages_de.properties | 4 +++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss index 63e8c6a0e84..b61f68bd8bd 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclDialogResources.gss @@ -6,6 +6,8 @@ } .deniedActionsTable { + margin-right: 5px; + margin-left: 5px; margin-top: 10px; display: inline; } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java index c4afdf46618..6189dde12de 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java @@ -100,10 +100,13 @@ public class AclEditPanel extends Composite { allowedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), actionNames, stringMessages.allowedActionName()); - allowedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().allowedActionsTable()); allowedActionsEditor.addValueChangeHandler(e -> userGroupsWithAllowedActions .put(userGroupSingleSelectionModel.getSelectedObject(), toSet(e.getValue()))); - permissionsCellListPanelUi.add(allowedActionsEditor); + + CaptionPanel allowedActionsPanel = new CaptionPanel(stringMessages.allowedActions()); + allowedActionsPanel.add(allowedActionsEditor); + allowedActionsPanel.addStyleName(AclDialogResources.INSTANCE.css().allowedActionsTable()); + permissionsCellListPanelUi.add(allowedActionsPanel); // create action editor for denied actions deniedActionsEditor = new StringListEditorComposite(new ArrayList<>(), stringMessages, @@ -111,8 +114,11 @@ public class AclEditPanel extends Composite { stringMessages.deniedActionName()); deniedActionsEditor.addValueChangeHandler(e -> userGroupsWithDeniedActions .put(userGroupSingleSelectionModel.getSelectedObject(), toDeniedActionSet(e.getValue()))); - deniedActionsEditor.addStyleName(AclDialogResources.INSTANCE.css().deniedActionsTable()); - permissionsCellListPanelUi.add(deniedActionsEditor); + + CaptionPanel deniedActionsPanel = new CaptionPanel(stringMessages.deniedActions()); + deniedActionsPanel.add(deniedActionsEditor); + deniedActionsPanel.addStyleName(AclDialogResources.INSTANCE.css().deniedActionsTable()); + permissionsCellListPanelUi.add(deniedActionsPanel); } /** Called when the selected {@link UserGroup} changes. */ diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java index 7f6921be8a2..ec403f1f718 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java @@ -2,6 +2,7 @@ package com.sap.sse.security.ui.client.i18n; import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.LocalizableResource.DefaultLocale; +import com.google.gwt.safehtml.shared.SafeHtml; @DefaultLocale("en") public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { @@ -161,4 +162,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { String errorMessageUserGroupNameNotFound(String name); String successMessageAddedUserGroup(String name); String successMessageRemovedUserGroup(String name); + SafeHtml allowedActions(); + SafeHtml deniedActions(); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties index 5e810575d95..cef601f1213 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties @@ -168,4 +168,6 @@ allowedActionName=Allowed action name deniedActionName=Denied action name errorMessageUserGroupNameNotFound=Did not find user group by name {0}. successMessageAddedUserGroup=Added user group {0}. -successMessageRemovedUserGroup=Removed user group {0}. \ No newline at end of file +successMessageRemovedUserGroup=Removed user group {0}. +allowedActions=Allowed Actions +deniedActions=Denied Actions \ No newline at end of file diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties index 8f27bb5625c..eae56b277a0 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties @@ -167,4 +167,6 @@ allowedActionName=Erlaubter Aktionsname deniedActionName=Verweigerter Aktionsname errorMessageUserGroupNameNotFound=Benutzergruppe nicht gefunden: {0}. successMessageAddedUserGroup=Benutzergruppe hinzugefügt: {0}. -successMessageRemovedUserGroup=Benutzergruppe entfernt: {0}. \ No newline at end of file +successMessageRemovedUserGroup=Benutzergruppe entfernt: {0}. +allowedActions=Erlabute Aktionen +deniedActions=Verweigerte Aktionen \ No newline at end of file From 160482b8406070598c78ce973380ccb60700de46 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 28 Nov 2018 11:25:13 +0100 Subject: [PATCH 25/27] bug4763 Added new AccessControlledButtonPanel to secure create/remove buttons --- .../AccessControlledButtonPanel.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AccessControlledButtonPanel.java diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AccessControlledButtonPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AccessControlledButtonPanel.java new file mode 100644 index 00000000000..6c549088bce --- /dev/null +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AccessControlledButtonPanel.java @@ -0,0 +1,103 @@ +package com.sap.sse.security.ui.client.component; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.sap.sse.security.shared.HasPermissions; +import com.sap.sse.security.ui.client.UserService; + +/** + * Panel where several buttons can be added which are either {@link #addUnsecuredAction(String, Command) unsecured} or + * restricted for users with {@link #addCreateAction(String, Command) create} and /or + * {@link #addRemoveAction(String, Command) remove} permissions. The visibility of secured buttons depend on the + * permissions of the currently logged-in user and changes dynamically. + */ +public class AccessControlledButtonPanel extends Composite { + + private final HorizontalPanel panel = new HorizontalPanel(); + private final Map> buttonToPermissions = new HashMap<>(); + + private final Supplier createPermissionCheck, removePermissionCheck; + private final BiConsumer> visibilityUpdater = (btn, check) -> btn.setVisible(check.get()); + + /** + * Creates an {@link AccessControlledButtonPanel} instance for the given {@link HasPermissions type} using the + * provided {@link UserService} to check permissions and register for user status changes. + * + * @param userService + * the {@link UserService} to check permissions and register for user status changes + * @param type + * the {@link HasPermissions} representing the type of objects to be secured by this panel + */ + public AccessControlledButtonPanel(final UserService userService, final HasPermissions type) { + this.createPermissionCheck = () -> userService.hasCurrentUserPermissionToCreateObjectOfType(type); + this.removePermissionCheck = () -> userService.hasCurrentUserPermissionToDeleteAnyObjectOfType(type); + userService.addUserStatusEventHandler((user, preAuth) -> buttonToPermissions.forEach(visibilityUpdater), true); + initWidget(panel); + } + + /** + * Adds an unsecured action button, which's visibility is independent from the current user's permissions. + * + * @param text + * the {@link String text} to show on the button + * @param callback + * the {@link Command callback} to execute on button click + * @return the created {@link Button} instance + */ + public Button addUnsecuredAction(final String text, final Command callback) { + return addAction(text, () -> true, callback); + } + + /** + * Adds an secured action button, which is only visible if the current user has the + * {@link UserService#hasCurrentUserPermissionToCreateObjectOfType(HasPermissions) create permission} for the + * {@link HasPermissions type} provided in this {@link AccessControlledButtonPanel}'s constructor. + * + * @param text + * the {@link String text} to show on the button + * @param callback + * the {@link Command callback} to execute on button click, if permission is granted + * @return the created {@link Button} instance + */ + public Button addCreateAction(final String text, final Command callback) { + return addAction(text, createPermissionCheck, callback); + } + + /** + * Adds an secured action button, which is only visible if the current user has any + * {@link UserService#hasCurrentUserPermissionToDeleteAnyObjectOfType(HasPermissions) delete permission} for the + * {@link HasPermissions type} provided in this {@link AccessControlledButtonPanel}'s constructor. + * + * @param text + * the {@link String text} to show on the button + * @param callback + * the {@link Command callback} to execute on button click, if permission is granted + * @return the created {@link Button} instance + */ + public Button addRemoveAction(final String text, final Command callback) { + return addAction(text, removePermissionCheck, callback); + } + + private Button addAction(final String text, final Supplier permissionCheck, final Command callback) { + final Button button = new Button(text, (ClickHandler) event -> { + if (permissionCheck.get()) { + callback.execute(); + } + }); + this.buttonToPermissions.put(button, permissionCheck); + button.getElement().getStyle().setMarginRight(5, Unit.PX); + this.panel.add(button); + this.visibilityUpdater.accept(button, permissionCheck); + return button; + } + +} From 368ffc75c44ead5cf6a23d0c28a22dfa46110375 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 28 Nov 2018 11:25:37 +0100 Subject: [PATCH 26/27] bug4763 Integrated AccessControlledButtonPanel into EventListComposite --- .../ui/adminconsole/EventListComposite.java | 94 ++++++------------- 1 file changed, 30 insertions(+), 64 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index 694d85881c0..a0c57bec5ba 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.ui.adminconsole; +import static com.sap.sailing.domain.common.security.SecuredDomainType.EVENT; import static com.sap.sse.security.shared.HasPermissions.DefaultActions.CHANGE_OWNERSHIP; import static com.sap.sse.security.shared.HasPermissions.DefaultActions.DELETE; import static com.sap.sse.security.shared.HasPermissions.DefaultActions.UPDATE; @@ -20,8 +21,6 @@ import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.cell.client.SafeHtmlCell; import com.google.gwt.cell.client.ValueUpdater; import com.google.gwt.core.client.GWT; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; @@ -32,17 +31,15 @@ import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.SelectionChangeEvent; -import com.sap.sailing.domain.common.security.SecuredDomainType; import com.sap.sailing.gwt.ui.adminconsole.LeaderboardGroupDialog.LeaderboardGroupDescriptor; import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; import com.sap.sailing.gwt.ui.client.EventsRefresher; @@ -71,9 +68,9 @@ import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn; import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; -import com.sap.sse.security.shared.HasPermissions; import com.sap.sse.security.ui.client.UserService; import com.sap.sse.security.ui.client.component.AccessControlledActionsColumn; +import com.sap.sse.security.ui.client.component.AccessControlledButtonPanel; import com.sap.sse.security.ui.client.component.EditOwnershipDialog; import com.sap.sse.security.ui.client.component.EditOwnershipDialog.DialogConfig; import com.sap.sse.security.ui.client.component.SecuredObjectOwnerColumn; @@ -89,18 +86,13 @@ public class EventListComposite extends Composite implements EventsRefresher, Le private final UserService userService; private final ErrorReporter errorReporter; private final StringMessages stringMessages; - - private CellTable eventTable; + private final CellTable eventTable; private final RefreshableMultiSelectionModel refreshableEventSelectionModel; - private ListDataProvider eventListDataProvider; - private List allEvents; - private LabeledAbstractFilterablePanel filterTextbox; - private Button removeEventsButton; + private final ListDataProvider eventListDataProvider; + private final List allEvents; + private final LabeledAbstractFilterablePanel filterTextbox; private final Label noEventsLabel; - private final SimplePanel mainPanel; - private final VerticalPanel panel; - private Iterable availableLeaderboardGroups; public static class AnchorCell extends AbstractCell { @@ -132,63 +124,38 @@ public class EventListComposite extends Composite implements EventsRefresher, Le this.regattaRefresher = regattaRefresher; this.eventsRefresher = eventsRefresher; this.handleTabSelectable = handleTabSelectable; - availableLeaderboardGroups = Collections.emptyList(); - allEvents = new ArrayList(); + this.availableLeaderboardGroups = Collections.emptyList(); + this.allEvents = new ArrayList(); - mainPanel = new SimplePanel(); - panel = new VerticalPanel(); - mainPanel.setWidget(panel); + final VerticalPanel panel = new VerticalPanel(); + final AccessControlledButtonPanel buttonPanel = new AccessControlledButtonPanel(userService, EVENT); + panel.add(buttonPanel); - HorizontalPanel eventControlsPanel = new HorizontalPanel(); - eventControlsPanel.setSpacing(5); - panel.add(eventControlsPanel); + final Button refresh = buttonPanel.addUnsecuredAction(stringMessages.refresh(), this::fillEvents); + refresh.ensureDebugId("RefreshEventsButton"); - Button refreshButton = new Button(stringMessages.refresh()); - refreshButton.ensureDebugId("RefreshEventsButton"); - refreshButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - fillEvents(); - } - }); - eventControlsPanel.add(refreshButton); + final Button create = buttonPanel.addCreateAction(stringMessages.actionAddEvent(), this::openCreateEventDialog); + create.ensureDebugId("CreateEventButton"); - Button createEventBtn = new Button(stringMessages.actionAddEvent()); - createEventBtn.ensureDebugId("CreateEventButton"); - createEventBtn.addClickHandler(new ClickHandler() { + final Button remove = buttonPanel.addRemoveAction(stringMessages.remove(), new Command() { @Override - public void onClick(ClickEvent event) { - openCreateEventDialog(); - } - }); - eventControlsPanel.add(createEventBtn); - if (!userService.hasCurrentUserPermissionToCreateObjectOfType(SecuredDomainType.EVENT)) { - createEventBtn.setVisible(false); - } - - removeEventsButton = new Button(stringMessages.remove()); - removeEventsButton.ensureDebugId("RemoveEventsButton"); - removeEventsButton.setEnabled(false); - removeEventsButton.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - if(askUserForConfirmation()){ + public void execute() { + if (askUserForConfirmation()) { removeEvents(refreshableEventSelectionModel.getSelectedSet()); } } private boolean askUserForConfirmation() { - if(refreshableEventSelectionModel.itemIsSelectedButNotVisible(eventTable.getVisibleItems())){ - final String eventNames = refreshableEventSelectionModel.getSelectedSet().stream().map(e -> e.getName()).collect(Collectors.joining("\n")); + if (refreshableEventSelectionModel.itemIsSelectedButNotVisible(eventTable.getVisibleItems())) { + final String eventNames = refreshableEventSelectionModel.getSelectedSet().stream() + .map(EventDTO::getName).collect(Collectors.joining("\n")); return Window.confirm(stringMessages.doYouReallyWantToRemoveNonVisibleEvents(eventNames)); } return Window.confirm(stringMessages.doYouReallyWantToRemoveEvents()); } }); - eventControlsPanel.add(removeEventsButton); - if (!userService.hasCurrentUserPermissionToDeleteAnyObjectOfType(SecuredDomainType.EVENT)) { - removeEventsButton.setVisible(false); - } + remove.setEnabled(false); + remove.ensureDebugId("RemoveEventsButton"); eventListDataProvider = new ListDataProvider(); filterTextbox = new LabeledAbstractFilterablePanel(new Label(stringMessages.filterEventsByName()), @@ -222,10 +189,10 @@ public class EventListComposite extends Composite implements EventsRefresher, Le this.refreshableEventSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { - final boolean somethingSelected = !refreshableEventSelectionModel.getSelectedSet().isEmpty(); - removeEventsButton.setEnabled(somethingSelected); + remove.setEnabled(!refreshableEventSelectionModel.getSelectedSet().isEmpty()); final int numberOfItemsSelected = refreshableEventSelectionModel.getSelectedSet().size(); - removeEventsButton.setText(numberOfItemsSelected <= 1 ? stringMessages.remove() : stringMessages.removeNumber(numberOfItemsSelected)); + remove.setText(numberOfItemsSelected <= 1 ? stringMessages.remove() + : stringMessages.removeNumber(numberOfItemsSelected)); } }); panel.add(filterTextbox); @@ -235,7 +202,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le noEventsLabel.setWordWrap(false); panel.add(noEventsLabel); fillEvents(); - initWidget(mainPanel); + initWidget(panel); } private CellTable createEventTable(UserDTO user) { @@ -362,17 +329,16 @@ public class EventListComposite extends Composite implements EventsRefresher, Le final SecuredObjectOwnerColumn groupColumn = SecuredObjectOwnerColumn.getGroupOwnerColumn(); final SecuredObjectOwnerColumn userColumn = SecuredObjectOwnerColumn.getUserOwnerColumn(); - final HasPermissions type = SecuredDomainType.EVENT; final Function idFactory = event -> event.id.toString(); final AccessControlledActionsColumn actionsColumn = new AccessControlledActionsColumn<>( - new EventConfigImagesBarCell(stringMessages), userService, type, idFactory); + new EventConfigImagesBarCell(stringMessages), userService, EVENT, idFactory); actionsColumn.addAction(EventConfigImagesBarCell.ACTION_UPDATE, UPDATE, this::openEditEventDialog); actionsColumn.addAction(EventConfigImagesBarCell.ACTION_DELETE, DELETE, event -> { if (Window.confirm(stringMessages.doYouReallyWantToRemoveEvent(event.getName()))) { removeEvent(event); } }); - final DialogConfig config = EditOwnershipDialog.create(userService.getUserManagementService(), type, + final DialogConfig config = EditOwnershipDialog.create(userService.getUserManagementService(), EVENT, idFactory, event -> fillEvents(), stringMessages); actionsColumn.addAction(EventConfigImagesBarCell.ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, config::openDialog); From d869f31775db9d839bf51cc34495e96b008dd095 Mon Sep 17 00:00:00 2001 From: Steffen Jacobs Date: Wed, 28 Nov 2018 13:22:08 +0100 Subject: [PATCH 27/27] adjusted visualization in EditACLDialog --- .../ui/client/component/editacl/AclEditPanel.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java index 6189dde12de..52f7a5e84a1 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/editacl/AclEditPanel.java @@ -175,7 +175,9 @@ public class AclEditPanel extends Composite { private void updateActionEditors(UserGroup selectedUserGroup) { onUserGroupsChange(); allowedActionsEditor.setValue(userGroupsWithAllowedActions.get(selectedUserGroup), false); - deniedActionsEditor.setValue(userGroupsWithDeniedActions.get(selectedUserGroup), false); + deniedActionsEditor + .setValue(removeExclamationMarkFromStrings(userGroupsWithDeniedActions.get(selectedUserGroup)), false); + } /** @@ -331,4 +333,12 @@ public class AclEditPanel extends Composite { return set; } + private Set removeExclamationMarkFromStrings(Iterable iter) { + final Set set = new HashSet<>(); + for (String s : iter) { + set.add(s.startsWith("!") ? s.substring(1) : s); + } + return set; + } + }