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 00000000000..c938b1c13ad Binary files /dev/null and b/java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/change-acl.png differ 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/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/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/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 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 66543b2bafc..a6c45b1795d 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) { 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) {