Refactored roles and rolePermissionModels

This commit is contained in:
Jonas Dann
2017-11-24 12:39:54 +01:00
parent b463fcc76d
commit 8528cce300
30 changed files with 202 additions and 157 deletions
@@ -15,7 +15,7 @@ public class SailingPermissionsForRoleProvider implements PermissionsForRoleProv
public Iterable<String> getPermissions(String role, RolePermissionModel rolePermissionModel) {
final Iterable<String> result;
if (rolePermissionModel == null) {
if (AdminRole.getInstance().getDisplayName().equals(role)) {
if (AdminRole.getInstance().getName().equals(role)) {
ArrayList<String> permissions = new ArrayList<>();
permissions.add("*");
result = permissions;
@@ -10,7 +10,6 @@ import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.security.Permission;
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
@@ -49,7 +48,7 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
SAPHeaderWithAuthentication header = new SAPHeaderWithAuthentication(getStringMessages().sapSailingAnalytics(), getStringMessages().dataMining());
GenericAuthentication genericSailingAuthentication = new FixedSailingAuthentication(getUserService(), header.getAuthenticationMenuView());
AuthorizedContentDecorator authorizedContentDecorator = new GenericAuthorizedContentDecorator(genericSailingAuthentication);
authorizedContentDecorator.setPermissionToCheck(Permission.DATA_MINING, SailingPermissionsForRoleProvider.INSTANCE);
authorizedContentDecorator.setPermissionToCheck(Permission.DATA_MINING);
authorizedContentDecorator.setContentWidgetFactory(new WidgetFactory() {
@Override
public Widget get() {
@@ -11,7 +11,6 @@ import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.security.Permission;
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.settings.client.leaderboardedit.LeaderboardEditContextDefinition;
@@ -42,7 +41,7 @@ public class LeaderboardEditPage extends AbstractSailingEntryPoint {
SAPHeaderWithAuthentication header = initHeader();
GenericAuthentication genericSailingAuthentication = new FixedSailingAuthentication(getUserService(), header.getAuthenticationMenuView());
AuthorizedContentDecorator authorizedContentDecorator = new GenericAuthorizedContentDecorator(genericSailingAuthentication);
authorizedContentDecorator.setPermissionToCheck(Permission.MANAGE_LEADERBOARD_RESULTS, SailingPermissionsForRoleProvider.INSTANCE);
authorizedContentDecorator.setPermissionToCheck(Permission.MANAGE_LEADERBOARD_RESULTS);
authorizedContentDecorator.setContentWidgetFactory(new WidgetFactory() {
@Override
public Widget get() {
@@ -446,8 +446,7 @@ public class AdminConsolePanel extends DockLayoutPanel implements HandleTabSelec
private boolean userHasPermissionsToSeeWidget(UserDTO user, Widget widget) {
for (Permission requiredStringPermission : permissionsAnyOfWhichIsRequiredToSeeWidget.get(widget)) {
WildcardPermission requiredPermission = new WildcardPermission(requiredStringPermission.getStringPermission());
for (String userStringPermission : user.getAllPermissions(permissionsForRoleProvider)) {
WildcardPermission userPermission = new WildcardPermission(userStringPermission);
for (WildcardPermission userPermission : user.getAllPermissions(permissionsForRoleProvider)) {
if (requiredPermission.implies(userPermission) || userPermission.implies(requiredPermission)) {
return true;
}
@@ -6,13 +6,14 @@ import java.util.Set;
import java.util.UUID;
public class AdminRole implements Role {
private static final long serialVersionUID = 3291793984984443193L;
private static AdminRole INSTANCE;
private static final String NAME = "admin";
private static final String UUID_STRING = "dc77e3d1-d405-435e-8699-ce7245f6fd7a";
private final UUID id;
private final Set<WildcardPermission> permissions;
AdminRole() {
id = UUID.fromString(UUID_STRING);
permissions = new HashSet<>();
@@ -20,7 +21,7 @@ public class AdminRole implements Role {
}
@Override
public String getDisplayName() {
public String getName() {
return NAME;
}
@@ -2,6 +2,7 @@ package com.sap.sse.security.shared;
import java.util.List;
import java.util.Set;
import java.util.UUID;
/**
* The {@link PermissionChecker} is an implementation of the permission
@@ -31,7 +32,7 @@ public class PermissionChecker {
* The instance id can be omitted when a general permission for the data
* object type is asked after (e.g. "event:create").
*/
public static boolean isPermitted(WildcardPermission permission, String user, Iterable<UserGroup> tenants, Iterable<WildcardPermission> directPermissions, Iterable<String> roles,
public static boolean isPermitted(WildcardPermission permission, String user, Iterable<UserGroup> tenants, Iterable<WildcardPermission> directPermissions, Iterable<UUID> roles,
RolePermissionModel rolePermissionModel, Owner ownership, AccessControlList acl) {
List<Set<String>> parts = permission.getParts();
// permission has at least data object type and action as parts
@@ -43,7 +44,7 @@ public class PermissionChecker {
PermissionState result = PermissionState.NONE;
// 1. check ownership
if (ownership != null && user.equals(ownership.getOwner())) { // TODO check for tenant ownership
if (ownership != null && user.equals(ownership.getOwner())) {
result = PermissionState.GRANTED;
}
// 2. check ACL
@@ -61,7 +62,7 @@ public class PermissionChecker {
}
// 4. check role permissions
if (result == PermissionState.NONE) {
for (String role : roles) {
for (UUID role : roles) {
if (rolePermissionModel.implies(role, permission, ownership)) {
result = PermissionState.GRANTED;
break;
@@ -2,9 +2,8 @@ package com.sap.sse.security.shared;
import java.util.Set;
import com.sap.sse.common.WithID;
import com.sap.sse.common.NamedWithID;
public interface Role extends WithID {
String getDisplayName();
public interface Role extends NamedWithID {
Set<WildcardPermission> getPermissions();
}
@@ -6,32 +6,34 @@ import java.util.Set;
import java.util.UUID;
public class RoleImpl implements Role {
private static final long serialVersionUID = -402472324567793082L;
private final UUID id;
private final String displayName;
private final String name;
private final Set<WildcardPermission> permissions;
public RoleImpl(UUID id, String displayName) {
this(id, displayName, new HashSet<WildcardPermission>());
}
public RoleImpl(UUID id, String displayName, Set<WildcardPermission> permissions) {
public RoleImpl(UUID id, String name, Set<WildcardPermission> permissions) {
this.id = id;
this.displayName = displayName;
this.name = name;
this.permissions = permissions;
}
@Override
public Set<WildcardPermission> getPermissions() {
return permissions;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public Serializable getId() {
return id;
}
@Override
public String getName() {
return name;
}
@Override
public Set<WildcardPermission> getPermissions() {
return permissions;
}
}
@@ -1,11 +1,16 @@
package com.sap.sse.security.shared;
public interface RolePermissionModel {
Iterable<String> getPermissions(String role);
import java.util.UUID;
boolean implies(String role, WildcardPermission permission);
public interface RolePermissionModel {
String getName(UUID id);
Iterable<WildcardPermission> getPermissions(UUID id);
boolean implies(UUID id, WildcardPermission permission);
boolean implies(UUID id, WildcardPermission permission, Owner ownership);
/**
* @param role Role of the for "role_title:tenant". The tenant is an optional
* @param id Id of role
* @param name Role name of the form "role_title:tenant". The tenant is an optional
* parameter. It restricts permissions with a * as the instance id
* to data objects where the tenant parameter equals the tenant owner
* of the data object. E.g.:
@@ -16,5 +21,5 @@ public interface RolePermissionModel {
* "tw2016-dyas" would have "tw2016" as the tenant owner)
* @param ownership Ownership of the data object
*/
boolean implies(String role, WildcardPermission permission, Owner ownership);
boolean implies(UUID id, String name, WildcardPermission permission, Owner ownership);
}
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.net.UnknownHostException;
import java.util.UUID;
import org.apache.shiro.SecurityUtils;
import org.junit.Before;
@@ -69,9 +70,10 @@ public class LoginTest {
@Test
public void rolesTest() throws UserManagementException {
store.createUser("me", "me@sap.com", "admin");
store.addRoleForUser("me", "testrole");
UUID testId = UUID.randomUUID();
store.addRoleForUser("me", testId);
UserStoreImpl store2 = new UserStoreImpl();
assertTrue(Util.contains(store2.getUserByName("me").getRoles(), "testrole"));
assertTrue(Util.contains(store2.getUserByName("me").getRoles(), testId));
}
@Test
@@ -1,7 +1,8 @@
package com.sap.sse.security.ui.authentication.app;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.HashMap;
import java.util.UUID;
import com.sap.sse.security.ui.shared.AccountDTO;
import com.sap.sse.security.ui.shared.RolePermissionModelDTO;
@@ -14,7 +15,7 @@ public class AuthenticationContextImpl implements AuthenticationContext {
private final UserDTO currentUser;
private final static UserDTO ANONYMOUS = new UserDTO("Anonymous", "", "", "", null, false, new ArrayList<AccountDTO>(),
new ArrayList<String>(), new RolePermissionModelDTO(new HashSet<>()), new ArrayList<String>());
new ArrayList<UUID>(), new RolePermissionModelDTO(new HashMap<>()), new ArrayList<String>());
/**
* Creating an {@link AuthenticationContextImpl} containing an anonymous {@link UserDTO} object.
@@ -9,7 +9,6 @@ import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.security.shared.Permission;
import com.sap.sse.security.shared.PermissionsForRoleProvider;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.client.i18n.StringMessages;
@@ -20,13 +19,11 @@ import com.sap.sse.security.ui.client.i18n.StringMessages;
*
*/
public class AuthorizedContentDecorator extends Composite implements RequiresResize, NeedsAuthenticationContext {
private final SimplePanel contentHolder = new SimplePanel();
private Widget content;
private WidgetFactory contentWidgetFactory;
private final NotLoggedInView notLoggedInView;
private String permissionToCheck;
private PermissionsForRoleProvider permissionsForRoleProvider;
public AuthorizedContentDecorator(NotLoggedInPresenter presenter, NotLoggedInView notLoggedInView) {
this.notLoggedInView = notLoggedInView;
@@ -116,13 +113,6 @@ public class AuthorizedContentDecorator extends Composite implements RequiresRes
|| userManagementContext.getCurrentUser().hasPermission(permissionToCheck);
}
/**
* @param permissionsForRoleProvider the PermissionsForRoleProvider used when checking the required permission of a user.
*/
public void setPermissionsForRoleProvider(PermissionsForRoleProvider permissionsForRoleProvider) {
this.permissionsForRoleProvider = permissionsForRoleProvider;
}
/**
* Setting a permission causes that the user not only needs to be logged in but also needs to have the given permission.
*
@@ -140,16 +130,4 @@ public class AuthorizedContentDecorator extends Composite implements RequiresRes
public void setPermissionToCheck(Permission permissionToCheck) {
setPermissionToCheck(permissionToCheck.getStringPermission());
}
/**
* Setting a permission causes that the user not only needs to be logged in but also needs to have the given permission.
*
* @param permissionToCheck the permission to check
* @param permissionsForRoleProvider the PermissionsForRoleProvider used when checking the required permission of a user.
*/
public void setPermissionToCheck(Permission permissionToCheck, PermissionsForRoleProvider permissionsForRoleProvider) {
setPermissionToCheck(permissionToCheck);
setPermissionsForRoleProvider(permissionsForRoleProvider);
}
}
@@ -4,6 +4,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import com.google.gwt.user.client.rpc.RemoteService;
import com.sap.sse.common.mail.MailException;
@@ -71,7 +72,7 @@ public interface UserManagementService extends RemoteService {
SuccessInfo logout();
SuccessInfo setRolesForUser(String username, Iterable<String> roles);
SuccessInfo setRolesForUser(String username, Iterable<UUID> roles);
SuccessInfo setPermissionsForUser(String username, Iterable<String> permissions);
@@ -32,6 +32,7 @@ import com.sap.sse.security.shared.Permission;
import com.sap.sse.security.shared.PermissionsForRoleProvider;
import com.sap.sse.security.shared.Role;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.ui.client.IconResources;
import com.sap.sse.security.ui.client.UserChangeEventHandler;
import com.sap.sse.security.ui.client.UserManagementServiceAsync;
@@ -75,7 +76,7 @@ public class UserDetailsView extends FlowPanel {
for (Permission permission : additionalPermissions) {
defaultPermissionNames.add(permission.getStringPermission());
}
rolesEditor = new StringListEditorComposite(user==null?Collections.<String>emptySet():user.getRoles(), stringMessages, com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), defaultRoleNames,
rolesEditor = new StringListEditorComposite(user==null?Collections.<String>emptySet():user.getStringRoles(), stringMessages, com.sap.sse.gwt.client.IconResources.INSTANCE.removeIcon(), defaultRoleNames,
stringMessages.enterRoleName());
rolesEditor.addValueChangeHandler(new ValueChangeHandler<Iterable<String>>() {
@Override
@@ -254,11 +255,11 @@ public class UserDetailsView extends FlowPanel {
}
accountPanels.add(accountPanelDecorator);
}
rolesEditor.setValue(user.getRoles(), /* fireEvents */ false);
rolesEditor.setValue(user.getStringRoles(), /* fireEvents */ false);
permissionsEditor.setValue(user.getStringPermissions(), /* fireEvents */ false);
allPermissionsList.clear();
for (String permission : user.getAllPermissions(permissionForRoleProvider)) {
allPermissionsList.addItem(permission);
for (WildcardPermission permission : user.getAllPermissions(permissionForRoleProvider)) {
allPermissionsList.addItem(permission.toString());
}
}
}
@@ -332,7 +332,7 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
public void updateSimpleUserPassword(final String username, String oldPassword, String passwordResetSecret, String newPassword) throws UserManagementException {
final Subject subject = SecurityUtils.getSubject();
// the signed-in subject has role ADMIN
if (subject.hasRole(AdminRole.getInstance().getDisplayName())
if (subject.hasRole(AdminRole.getInstance().getName())
// someone knew a username and the correct password for that user
|| (oldPassword != null && getSecurityService().checkPassword(username, oldPassword))
// someone provided the correct password reset secret for the correct username
@@ -355,7 +355,7 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
private void ensureThatUserInQuestionIsLoggedInOrCurrentUserIsAdmin(String username) throws UserManagementException {
final Subject subject = SecurityUtils.getSubject();
// the signed-in subject has role ADMIN or is changing own user
if (!subject.hasRole(AdminRole.getInstance().getDisplayName()) && (subject.getPrincipal() == null
if (!subject.hasRole(AdminRole.getInstance().getName()) && (subject.getPrincipal() == null
|| !username.equals(subject.getPrincipal().toString()))) {
throw new UserManagementException(UserManagementException.INVALID_CREDENTIALS);
}
@@ -410,23 +410,23 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
}
@Override
public SuccessInfo setRolesForUser(String username, Iterable<String> roles) {
public SuccessInfo setRolesForUser(String username, Iterable<UUID> roles) {
Subject currentSubject = SecurityUtils.getSubject();
if (currentSubject.hasRole(AdminRole.getInstance().getDisplayName())) {
if (currentSubject.hasRole(AdminRole.getInstance().getName())) {
User u = getSecurityService().getUserByName(username);
if (u == null) {
return new SuccessInfo(false, "User does not exist.", /* redirectURL */null, null);
}
Set<String> rolesToRemove = new HashSet<>();
Set<UUID> rolesToRemove = new HashSet<>();
Util.addAll(u.getRoles(), rolesToRemove);
Util.removeAll(roles, rolesToRemove);
for (String roleToRemove : rolesToRemove) {
for (UUID roleToRemove : rolesToRemove) {
getSecurityService().removeRoleFromUser(username, roleToRemove);
}
Set<String> rolesToAdd = new HashSet<>();
Set<UUID> rolesToAdd = new HashSet<>();
Util.addAll(roles, rolesToAdd);
Util.removeAll(u.getRoles(), rolesToAdd);
for (String roleToAdd : rolesToAdd) {
for (UUID roleToAdd : rolesToAdd) {
getSecurityService().addRoleForUser(username, roleToAdd);
}
return new SuccessInfo(true, "Set roles " + roles + " for user " + username, /* redirectURL */null,
@@ -439,7 +439,7 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
@Override
public SuccessInfo setPermissionsForUser(String username, Iterable<String> permissions) {
Subject currentSubject = SecurityUtils.getSubject();
if (currentSubject.hasRole(AdminRole.getInstance().getDisplayName()) || currentSubject.isPermitted(Permission.MANAGE_USERS.getStringPermissionForObjects(DefaultModes.UPDATE, username))) {
if (currentSubject.hasRole(AdminRole.getInstance().getName()) || currentSubject.isPermitted(Permission.MANAGE_USERS.getStringPermissionForObjects(DefaultModes.UPDATE, username))) {
User u = getSecurityService().getUserByName(username);
if (u == null) {
return new SuccessInfo(false, "User does not exist.", /* redirectURL */null, null);
@@ -493,7 +493,7 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
}
userDTO = new UserDTO(user.getName(), user.getEmail(), user.getFullName(), user.getCompany(),
user.getLocale() != null ? user.getLocale().toLanguageTag() : null, user.isEmailValidated(),
accountDTOs, user.getRoles(), new RolePermissionModelDTO(new HashSet<>()), user.getPermissions());
accountDTOs, user.getRoles(), new RolePermissionModelDTO(new HashMap<>()), user.getPermissions());
return userDTO;
}
@@ -1,38 +1,51 @@
package com.sap.sse.security.ui.shared;
import java.util.Set;
import java.util.Map;
import java.util.UUID;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sse.security.shared.Owner;
import com.sap.sse.security.shared.Role;
import com.sap.sse.security.shared.RolePermissionModel;
import com.sap.sse.security.shared.WildcardPermission;
public class RolePermissionModelDTO implements RolePermissionModel, IsSerializable {
private Set<String> rules;
private Map<UUID, Role> roles;
RolePermissionModelDTO() {} // for serialization only
public RolePermissionModelDTO(Set<String> rules) {
this.rules = rules;
public RolePermissionModelDTO(Map<UUID, Role> roles) {
this.roles = roles;
}
@Override
public Iterable<String> getPermissions(String role) {
return rules;
public String getName(UUID id) {
return roles.get(id).getName();
}
@Override
public boolean implies(String role, WildcardPermission permission) { // TODO as default implementation in interface
return implies(role, permission, null);
public Iterable<WildcardPermission> getPermissions(UUID id) {
return roles.get(id).getPermissions();
}
// TODO as default implementation in interface
@Override
public boolean implies(UUID id, WildcardPermission permission) {
return implies(id, permission, null);
}
@Override
public boolean implies(String role, WildcardPermission permission, Owner ownership) { // TODO as default implementation in interface
String[] parts = role.split(":");
public boolean implies(UUID id, WildcardPermission permission, Owner ownership) {
return implies(id, roles.get(id).getName(), permission, ownership);
}
// TODO as default implementation in interface
@Override
public boolean implies(UUID id, String name, WildcardPermission permission, Owner ownership) {
String[] parts = name.split(":");
// if there is no parameter or the first parameter (tenant) equals the tenant owner
if (parts.length < 2 || (ownership != null && ownership.getTenantOwner().equals(parts[1]))) {
for (String rolePermissionString : getPermissions(role)) {
WildcardPermission rolePermission = new WildcardPermission(rolePermissionString, true);
for (WildcardPermission rolePermission : getPermissions(id)) {
if (rolePermission.implies(permission)) {
return true;
}
@@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sse.common.Util;
@@ -20,15 +21,15 @@ public class UserDTO implements IsSerializable {
private String company;
private String locale;
private List<AccountDTO> accounts;
private Set<String> roles;
private RolePermissionModelDTO rolePermissionModelDTO;
private Set<UUID> roles;
private RolePermissionModelDTO rolePermissionModel;
private Set<WildcardPermission> permissions;
private boolean emailValidated;
UserDTO() {} // for serialization only
public UserDTO(String name, String email, String fullName, String company, String locale, boolean emailValidated,
List<AccountDTO> accounts, Iterable<String> roles, RolePermissionModelDTO rolePermissionModelDTO,
List<AccountDTO> accounts, Iterable<UUID> roles, RolePermissionModelDTO rolePermissionModelDTO,
Iterable<String> stringPermissions) {
this.name = name;
this.email = email;
@@ -39,7 +40,7 @@ public class UserDTO implements IsSerializable {
this.accounts = accounts;
this.roles = new HashSet<>();
Util.addAll(roles, this.roles);
this.rolePermissionModelDTO = rolePermissionModelDTO;
this.rolePermissionModel = rolePermissionModelDTO;
this.permissions = new HashSet<>();
for (String permission : stringPermissions) {
this.permissions.add(new WildcardPermission(permission, true));
@@ -62,10 +63,18 @@ public class UserDTO implements IsSerializable {
return locale;
}
public Iterable<String> getRoles() {
public Iterable<UUID> getRoles() {
return roles;
}
public Iterable<String> getStringRoles() {
ArrayList<String> result = new ArrayList<>();
for (UUID id : roles) {
result.add(rolePermissionModel.getName(id));
}
return result;
}
public boolean hasRole(String role) {
return roles.contains(role);
}
@@ -102,12 +111,12 @@ public class UserDTO implements IsSerializable {
* @return a set of permissions with no duplicates, all in the format parsable by
* {@link WildcardPermission#WildcardPermission(String)}
*/
public Iterable<String> getAllPermissions(PermissionsForRoleProvider permissionsForRoleProvider) {
Set<String> result = new LinkedHashSet<>();
Util.addAll(getStringPermissions(), result);
if (permissionsForRoleProvider != null) {
for (String role : getRoles()) {
Util.addAll(permissionsForRoleProvider.getPermissions(role, null), result);
public Iterable<WildcardPermission> getAllPermissions(PermissionsForRoleProvider permissionsForRoleProvider) {
Set<WildcardPermission> result = new LinkedHashSet<>();
Util.addAll(permissions, result);
if (rolePermissionModel != null) {
for (UUID role : getRoles()) {
Util.addAll(rolePermissionModel.getPermissions(role), result);
}
}
return result;
@@ -130,7 +139,7 @@ public class UserDTO implements IsSerializable {
if (acl != null) {
userGroups = new ArrayList<>(acl.getUserGroupPermissionMap().keySet());
}
return PermissionChecker.isPermitted(permission, name, userGroups, permissions, roles, rolePermissionModelDTO, owner, acl);
return PermissionChecker.isPermitted(permission, name, userGroups, permissions, roles, rolePermissionModel, owner, acl);
}
public List<AccountDTO> getAccounts() {
@@ -183,7 +183,7 @@ public class AccessControlStoreImpl implements AccessControlStore {
@Override
public AccessControlStore setRolePermissions(UUID id, Set<WildcardPermission> permissions) {
Role role = roleList.get(id);
role = new RoleImpl(id, role.getDisplayName(), permissions);
role = new RoleImpl(id, role.getName(), permissions);
mongoObjectFactory.storeRole(role);
return this;
}
@@ -193,7 +193,7 @@ public class AccessControlStoreImpl implements AccessControlStore {
Role role = roleList.get(id);
Set<WildcardPermission> permissions = role.getPermissions();
permissions.add(permission);
role = new RoleImpl(id, role.getDisplayName(), permissions);
role = new RoleImpl(id, role.getName(), permissions);
mongoObjectFactory.storeRole(role);
return this;
}
@@ -203,7 +203,7 @@ public class AccessControlStoreImpl implements AccessControlStore {
Role role = roleList.get(id);
Set<WildcardPermission> permissions = role.getPermissions();
permissions.remove(permission);
role = new RoleImpl(id, role.getDisplayName(), permissions);
role = new RoleImpl(id, role.getName(), permissions);
mongoObjectFactory.storeRole(role);
return this;
}
@@ -249,7 +249,7 @@ public class UserStoreImpl implements UserStore {
public String getAccessToken(String username) {
// only the user or an administrator may request a user's access token
final Object principal = SecurityUtils.getSubject().getPrincipal();
if (SecurityUtils.getSubject().hasRole(AdminRole.getInstance().getDisplayName()) ||
if (SecurityUtils.getSubject().hasRole(AdminRole.getInstance().getName()) ||
(principal != null && principal.toString().equals(username))) {
return getPreference(username, ACCESS_TOKEN_KEY);
} else {
@@ -260,7 +260,7 @@ public class UserStoreImpl implements UserStore {
@Override
public void removeAccessToken(String username) {
// only the user or an administrator may request a user's access token
if (SecurityUtils.getSubject().hasRole(AdminRole.getInstance().getDisplayName()) ||
if (SecurityUtils.getSubject().hasRole(AdminRole.getInstance().getName()) ||
SecurityUtils.getSubject().getPrincipal().toString().equals(username)) {
User user = users.get(username);
if (user != null) {
@@ -508,7 +508,7 @@ public class UserStoreImpl implements UserStore {
}
@Override
public Iterable<String> getRolesFromUser(String username) throws UserManagementException {
public Iterable<UUID> getRolesFromUser(String username) throws UserManagementException {
if (users.get(username) == null) {
throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST);
}
@@ -516,7 +516,7 @@ public class UserStoreImpl implements UserStore {
}
@Override
public void addRoleForUser(String name, String role) throws UserManagementException {
public void addRoleForUser(String name, UUID role) throws UserManagementException {
final User user = users.get(name);
if (user == null) {
throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST);
@@ -528,7 +528,7 @@ public class UserStoreImpl implements UserStore {
}
@Override
public void removeRoleFromUser(String name, String role) throws UserManagementException {
public void removeRoleFromUser(String name, UUID role) throws UserManagementException {
if (users.get(name) == null) {
throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST);
}
@@ -129,7 +129,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
private Role loadRole(DBObject roleDBObject) {
final String id = (String) roleDBObject.get(FieldNames.Role.ID.name());
final String displayName = (String) roleDBObject.get(FieldNames.Role.DISPLAY_NAME.name());
final String displayName = (String) roleDBObject.get(FieldNames.Role.NAME.name());
final Set<WildcardPermission> permissions = new HashSet<>();
for (Object o : (BasicDBList) roleDBObject.get(FieldNames.Role.PERMISSIONS.name())) {
permissions.add(new WildcardPermission(o.toString(), true));
@@ -217,12 +217,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
Boolean emailValidated = (Boolean) userDBObject.get(FieldNames.User.EMAIL_VALIDATED.name());
String passwordResetSecret = (String) userDBObject.get(FieldNames.User.PASSWORD_RESET_SECRET.name());
String validationSecret = (String) userDBObject.get(FieldNames.User.VALIDATION_SECRET.name());
Set<String> roles = new HashSet<String>();
Set<String> permissions = new HashSet<String>();
Set<UUID> roles = new HashSet<>();
Set<String> permissions = new HashSet<>();
BasicDBList rolesO = (BasicDBList) userDBObject.get(FieldNames.User.ROLES.name());
if (rolesO != null) {
for (Object o : rolesO) {
roles.add((String) o);
roles.add(UUID.fromString((String) o));
}
}
BasicDBList permissionsO = (BasicDBList) userDBObject.get(FieldNames.User.PERMISSIONS.name());
@@ -234,7 +234,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
DBObject accountsMap = (DBObject) userDBObject.get(FieldNames.User.ACCOUNTS.name());
Map<AccountType, Account> accounts = createAccountMapFromdDBObject(accountsMap);
User result = new User(name, email, fullName, company, locale, emailValidated==null?false:emailValidated, passwordResetSecret, validationSecret, accounts.values());
for (String role : roles) {
for (UUID role : roles) {
result.addRole(role);
}
for (String permission : permissions) {
@@ -17,7 +17,7 @@ public class FieldNames {
public static enum Role {
ID,
DISPLAY_NAME,
NAME,
PERMISSIONS
}
@@ -91,7 +91,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
DBObject dbRole = new BasicDBObject();
DBObject query = new BasicDBObject(FieldNames.Role.ID.name(), role.getId().toString());
dbRole.put(FieldNames.Role.ID.name(), role.getId().toString());
dbRole.put(FieldNames.Role.DISPLAY_NAME.name(), role.getDisplayName());
dbRole.put(FieldNames.Role.NAME.name(), role.getName());
HashSet<String> stringPermissions = new HashSet<>();
for (WildcardPermission permission : role.getPermissions()) {
stringPermissions.add(permission.toString());
@@ -161,7 +161,11 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
dbUser.put(FieldNames.User.PASSWORD_RESET_SECRET.name(), user.getPasswordResetSecret());
dbUser.put(FieldNames.User.VALIDATION_SECRET.name(), user.getValidationSecret());
dbUser.put(FieldNames.User.ACCOUNTS.name(), createAccountMapObject(user.getAllAccounts()));
dbUser.put(FieldNames.User.ROLES.name(), user.getRoles());
HashSet<String> roles = new HashSet<>();
for (UUID id : user.getRoles()) {
roles.add(id.toString());
}
dbUser.put(FieldNames.User.ROLES.name(), roles);
dbUser.put(FieldNames.User.PERMISSIONS.name(), user.getPermissions());
usersCollection.update(query, dbUser, /* upsrt */true, /* multi */false, WriteConcern.SAFE);
}
@@ -3,6 +3,7 @@ package com.sap.sse.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -21,7 +22,7 @@ import org.osgi.util.tracker.ServiceTracker;
import com.sap.sse.security.impl.Activator;
import com.sap.sse.security.shared.Owner;
import com.sap.sse.security.shared.PermissionChecker;
import com.sap.sse.security.shared.PermissionsForRoleProvider;
import com.sap.sse.security.shared.Role;
import com.sap.sse.security.shared.RolePermissionModel;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.WildcardPermission;
@@ -30,7 +31,6 @@ public abstract class AbstractCompositeAuthrizingRealm extends AuthorizingRealm
private static final Logger logger = Logger.getLogger(AbstractCompositeAuthrizingRealm.class.getName());
private final Future<UserStore> userStore;
private final Future<AccessControlStore> aclStore;
private PermissionsForRoleProvider permissionsForRoleProvider;
/**
* In a non-OSGi test environment, having Shiro instantiate this class with a default constructor makes it difficult
@@ -62,10 +62,6 @@ public abstract class AbstractCompositeAuthrizingRealm extends AuthorizingRealm
}
}
public void setPermissionsForRoleProvider(PermissionsForRoleProvider permissionsForRoleProvider) {
this.permissionsForRoleProvider = permissionsForRoleProvider;
}
private Future<UserStore> createUserStoreFuture(BundleContext bundleContext) {
final ServiceTracker<UserStore, UserStore> tracker = new ServiceTracker<>(bundleContext, UserStore.class, /* customizer */ null);
tracker.open();
@@ -213,8 +209,8 @@ public abstract class AbstractCompositeAuthrizingRealm extends AuthorizingRealm
public boolean hasRole(PrincipalCollection principal, String roleIdentifier) {
String user = (String) principal.getPrimaryPrincipal();
try {
for (String role : getUserStore().getRolesFromUser(user)) {
if (role.equals(roleIdentifier)) {
for (UUID role : getUserStore().getRolesFromUser(user)) {
if (role.equals(UUID.fromString(roleIdentifier))) {
return true;
}
}
@@ -266,23 +262,58 @@ public abstract class AbstractCompositeAuthrizingRealm extends AuthorizingRealm
return null; // As all the public methods of AuthorizingRealm are overridden to not use this, this should never be called.
}
@Override
public Iterable<String> getPermissions(String role) {
return permissionsForRoleProvider.getPermissions(role, null);
private Role getRole(UUID id) {
try {
return aclStore.get().getRole(id);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean implies(String role, WildcardPermission permission) { // TODO as default implementation in interface
return implies(role, permission, null);
public String getName(UUID id) {
Role role = getRole(id);
if (role != null) {
return role.getName();
} else {
return "";
}
}
@Override
public boolean implies(String role, WildcardPermission permission, Owner ownership) { // TODO as default implementation in interface
String[] parts = role.split(":");
public Iterable<WildcardPermission> getPermissions(UUID id) {
Role role = getRole(id);
if (role != null) {
return role.getPermissions();
} else {
return new ArrayList<>();
}
}
// TODO as default implementation in interface
@Override
public boolean implies(UUID id, WildcardPermission permission) {
return implies(id, permission, null);
}
@Override
public boolean implies(UUID id, WildcardPermission permission, Owner ownership) {
Role role = getRole(id);
if (role != null) {
return implies(id, role.getName(), permission, ownership);
} else {
return false;
}
}
// TODO as default implementation in interface
@Override
public boolean implies(UUID id, String name, WildcardPermission permission, Owner ownership) {
String[] parts = name.split(":");
// if there is no parameter or the first parameter (tenant) equals the tenant owner
if (parts.length < 2 || (ownership != null && ownership.getTenantOwner().equals(parts[1]))) {
for (String rolePermissionString : getPermissions(role)) {
WildcardPermission rolePermission = new WildcardPermission(rolePermissionString, true);
for (WildcardPermission rolePermission : getPermissions(id)) {
if (rolePermission.implies(permission)) {
return true;
}
@@ -30,5 +30,4 @@ public class BearerTokenRealm extends AbstractCompositeAuthrizingRealm {
SaltedAuthenticationInfo sai = new SimpleSaltedAuthenticationInfo(user.getName(), accessToken.getCredentials(), /* salt */ null);
return sai;
}
}
@@ -134,11 +134,11 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica
void deleteUser(String username) throws UserManagementException;
Iterable<String> getRolesFromUser(String username) throws UserManagementException;
Iterable<UUID> getRolesFromUser(String username) throws UserManagementException;
void addRoleForUser(String username, String role);
void addRoleForUser(String username, UUID role);
void removeRoleFromUser(String username, String role);
void removeRoleFromUser(String username, UUID role);
Iterable<String> getPermissionsFromUser(String username) throws UserManagementException;
@@ -10,6 +10,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import org.apache.shiro.crypto.hash.Sha256Hash;
@@ -64,7 +65,7 @@ public class User implements NamedWithID {
private boolean emailValidated;
private final Set<String> roles;
private final Set<UUID> roles;
private final Set<String> permissions;
private final Map<AccountType, Account> accounts;
@@ -136,19 +137,19 @@ public class User implements NamedWithID {
return locale == null ? Locale.ENGLISH : locale;
}
public Iterable<String> getRoles() {
public Iterable<UUID> getRoles() {
return roles;
}
public void addRole(String role) {
public void addRole(UUID role) {
roles.add(role);
}
public boolean hasRole(String role) {
public boolean hasRole(UUID role) {
return roles.contains(role);
}
public void removeRole(String role) {
public void removeRole(UUID role) {
roles.remove(role);
}
@@ -55,11 +55,11 @@ public interface UserStore extends Named {
void updateUser(User user);
Iterable<String> getRolesFromUser(String username) throws UserManagementException;
Iterable<UUID> getRolesFromUser(String username) throws UserManagementException;
void addRoleForUser(String name, String role) throws UserManagementException;
void addRoleForUser(String name, UUID role) throws UserManagementException;
void removeRoleFromUser(String name, String role) throws UserManagementException;
void removeRoleFromUser(String name, UUID role) throws UserManagementException;
Iterable<String> getPermissionsFromUser(String username) throws UserManagementException;
@@ -63,9 +63,9 @@ public interface ReplicableSecurityService extends SecurityService {
Void internalAddSetting(String key, Class<?> clazz);
Void internalAddRoleForUser(String username, String role) throws UserManagementException;
Void internalAddRoleForUser(String username, UUID role) throws UserManagementException;
Void internalRemoveRoleFromUser(String username, String role) throws UserManagementException;
Void internalRemoveRoleFromUser(String username, UUID role) throws UserManagementException;
Void internalAddPermissionForUser(String username, String permissionToAdd) throws UserManagementException;
@@ -207,7 +207,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
logger.info("No users found, creating default user \"admin\" with password \"admin\"");
createSimpleUser("admin", "nobody@sapsailing.com", "admin",
/* fullName */ null, /* company */ null, /* validationBaseURL */ null);
addRoleForUser("admin", AdminRole.getInstance().getDisplayName());
addRoleForUser("admin", (UUID) AdminRole.getInstance().getId());
} catch (UserManagementException | MailException e) {
logger.log(Level.SEVERE, "Exception while creating default admin user", e);
}
@@ -223,7 +223,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
Set<String> adminPermissions = new HashSet<>();
adminPermissions.add("*");
AdminRole role = AdminRole.getInstance();
aclStore.createRole((UUID) role.getId(), role.getDisplayName(), role.getPermissions());
aclStore.createRole((UUID) role.getId(), role.getName(), role.getPermissions());
}
}
@@ -748,28 +748,28 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
}
@Override
public Iterable<String> getRolesFromUser(String name) throws UserManagementException {
public Iterable<UUID> getRolesFromUser(String name) throws UserManagementException {
return userStore.getRolesFromUser(name);
}
@Override
public void addRoleForUser(String username, String role) {
public void addRoleForUser(String username, UUID role) {
apply(s->s.internalAddRoleForUser(username, role));
}
@Override
public Void internalAddRoleForUser(String username, String role) throws UserManagementException {
public Void internalAddRoleForUser(String username, UUID role) throws UserManagementException {
userStore.addRoleForUser(username, role);
return null;
}
@Override
public void removeRoleFromUser(String username, String role) {
public void removeRoleFromUser(String username, UUID role) {
apply(s->s.internalRemoveRoleFromUser(username, role));
}
@Override
public Void internalRemoveRoleFromUser(String username, String role) throws UserManagementException {
public Void internalRemoveRoleFromUser(String username, UUID role) throws UserManagementException {
userStore.removeRoleFromUser(username, role);
return null;
}
@@ -1127,7 +1127,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
private void ensureThatUserInQuestionIsLoggedInOrCurrentUserIsAdmin(String username) {
final Subject subject = SecurityUtils.getSubject();
if (!subject.hasRole(AdminRole.getInstance().getDisplayName()) && (subject.getPrincipal() == null
if (!subject.hasRole(AdminRole.getInstance().getName()) && (subject.getPrincipal() == null
|| !username.equals(subject.getPrincipal().toString()))) {
final String currentUserName = subject.getPrincipal() == null ? "<anonymous>"
: subject.getPrincipal().toString();
@@ -1228,7 +1228,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
@Override
public void removeAccessToken(String username) {
Subject subject = SecurityUtils.getSubject();
if (subject.hasRole(AdminRole.getInstance().getDisplayName()) || username.equals(subject.getPrincipal().toString())) {
if (subject.hasRole(AdminRole.getInstance().getName()) || username.equals(subject.getPrincipal().toString())) {
apply(s -> s.internalRemoveAccessToken(username));
} else {
throw new org.apache.shiro.authz.AuthorizationException("User " + subject.getPrincipal().toString()
@@ -68,7 +68,7 @@ public class SecurityResource extends AbstractSecurityResource {
@Produces("text/plain;charset=UTF-8")
public Response changePassword(@FormParam("username") String username, @FormParam("password") String password) {
final Subject subject = SecurityUtils.getSubject();
if (!subject.hasRole(AdminRole.getInstance().getDisplayName()) && (subject.getPrincipal() == null
if (!subject.hasRole(AdminRole.getInstance().getName()) && (subject.getPrincipal() == null
|| !username.equals(subject.getPrincipal().toString()))) {
return Response.status(Status.UNAUTHORIZED).build();
} else {
@@ -144,7 +144,7 @@ public class SecurityResource extends AbstractSecurityResource {
final Subject subject = SecurityUtils.getSubject();
// ADMIN can query all; otherwise, only the owning user can query
// TODO: ideally, we would introduce a USER:READ:<username> permission which later can be granted to tenant admins for all users of that tenant
if (subject.getPrincipal() == null || (username != null && !subject.hasRole(AdminRole.getInstance().getDisplayName()))) {
if (subject.getPrincipal() == null || (username != null && !subject.hasRole(AdminRole.getInstance().getName()))) {
return Response.status(Status.UNAUTHORIZED).build();
} else {
final User user = getService().getUserByName(username == null ? subject.getPrincipal().toString() : username);
@@ -167,7 +167,7 @@ public class SecurityResource extends AbstractSecurityResource {
public Response deleteUser(@QueryParam("username") String username) {
final Subject subject = SecurityUtils.getSubject();
// the signed-in subject has role ADMIN
if (!subject.hasRole(AdminRole.getInstance().getDisplayName()) && (subject.getPrincipal() == null
if (!subject.hasRole(AdminRole.getInstance().getName()) && (subject.getPrincipal() == null
|| !username.equals(subject.getPrincipal().toString()))) {
return Response.status(Status.UNAUTHORIZED).build();
} else {
@@ -188,7 +188,7 @@ public class SecurityResource extends AbstractSecurityResource {
@QueryParam("company") String company) {
final Subject subject = SecurityUtils.getSubject();
// the signed-in subject has role ADMIN
if (!subject.hasRole(AdminRole.getInstance().getDisplayName()) && (subject.getPrincipal() == null
if (!subject.hasRole(AdminRole.getInstance().getName()) && (subject.getPrincipal() == null
|| !username.equals(subject.getPrincipal().toString()))) {
return Response.status(Status.UNAUTHORIZED).build();
} else {