bug5684: added SecuredServer.createUserGroupAndAddCurrentUser method with test case

This commit is contained in:
Axel Uhl
2022-03-01 12:51:01 +01:00
parent e87c9629fe
commit 83f4db2192
6 changed files with 82 additions and 25 deletions
@@ -24,7 +24,8 @@ Require-Bundle: com.sap.sse.landscape,
com.sap.sailing.domain.shared.android,
com.sap.sailing.domain,
com.sap.sailing.landscape.common,
com.sap.sailing.shared.server
com.sap.sailing.shared.server,
org.apache.shiro.core
Export-Package: com.sap.sailing.landscape,
com.sap.sailing.landscape.impl,
com.sap.sailing.landscape.procedures
@@ -4,6 +4,7 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -11,7 +12,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -20,6 +20,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.client.ClientProtocolException;
import org.apache.shiro.authz.AuthorizationException;
import org.json.simple.parser.ParseException;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
@@ -89,10 +90,10 @@ import com.sap.sse.landscape.mongodb.MongoEndpoint;
import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.SessionUtils;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
import com.sap.sse.security.util.RemoteServerUtil;
import com.sap.sse.shared.util.Wait;
import com.sap.sse.util.ServiceTrackerFactory;
@@ -675,26 +676,29 @@ public class LandscapeServiceImpl implements LandscapeService {
final UUID userGroupId = securityServiceServer.getUserGroupIdByName(serverGroupName);
// TODO bug5684: use this userGroupId instead of the following old code to check existence, then ownership!
if (userGroupId != null) {
final Pair<UUID, String> serverGroupOwnership = securityServiceServer.getGroupAndUserOwner(
SecuredSecurityTypes.USER_GROUP, new TypeRelativeObjectIdentifier(userGroupId.toString()));
final Pair<UUID, String> serverOwnership = securityServiceServer.getGroupAndUserOwner(SecuredSecurityTypes.SERVER,
new TypeRelativeObjectIdentifier(serverName));
// TODO bug5684: check ownerships and permissions; user should have CREATE and UPDATE permission at least, probably also DELETE?
}
final UserGroup existingServerGroup = getSecurityService().getUserGroupByName(serverGroupName);
final UserGroup serverGroup;
if (existingServerGroup == null) {
final UUID serverGroupId = UUID.randomUUID();
// FIXME bug5678: if this runs on a server with separate security realm, using the local security service doesn't help!
serverGroup = getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError(SecuredSecurityTypes.USER_GROUP,
new TypeRelativeObjectIdentifier(serverGroupId.toString()), /* securityDisplayName */ serverGroupName,
(Callable<UserGroup>)()->getSecurityService().createUserGroup(serverGroupId, serverGroupName));
} else {
serverGroup = existingServerGroup;
final User currentUser = getSecurityService().getCurrentUser();
if (!Util.contains(serverGroup.getUsers(), currentUser) && getSecurityService().hasCurrentUserUpdatePermission(serverGroup)) {
getSecurityService().addUserToUserGroup(serverGroup, currentUser);
final TypeRelativeObjectIdentifier serverGroupTypeRelativeObjectId = new TypeRelativeObjectIdentifier(userGroupId.toString());
final Iterable<Pair<WildcardPermission, Boolean>> permissions = securityServiceServer.hasPermissions(Arrays.asList(
SecuredSecurityTypes.USER_GROUP.getPermissionForTypeRelativeIdentifier(DefaultActions.CREATE, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.USER_GROUP.getPermissionForTypeRelativeIdentifier(DefaultActions.READ, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.USER_GROUP.getPermissionForTypeRelativeIdentifier(DefaultActions.UPDATE, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.USER_GROUP.getPermissionForTypeRelativeIdentifier(DefaultActions.DELETE, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.SERVER.getPermissionForTypeRelativeIdentifier(DefaultActions.CREATE, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.SERVER.getPermissionForTypeRelativeIdentifier(DefaultActions.READ, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.SERVER.getPermissionForTypeRelativeIdentifier(DefaultActions.UPDATE, serverGroupTypeRelativeObjectId),
SecuredSecurityTypes.SERVER.getPermissionForTypeRelativeIdentifier(DefaultActions.DELETE, serverGroupTypeRelativeObjectId)));
for (final Pair<WildcardPermission, Boolean> permission : permissions) {
if (!permission.getB()) {
final String msg = "Subject "+securityServiceServer.getUsername()+" on server "+securityServiceHostname+
" is not allowed "+permission.getA()+". Not allowing to create application replica set for "+serverName;
logger.warning(msg);
throw new AuthorizationException(msg);
}
}
// Now we know the user is permitted to create/read/update/delete the user group and the server object in the remote
// security realm that the application replica set's master process will use if it existed already. Add the user to the group
securityServiceServer.addUserToGroup(userGroupId);
} else {
securityServiceServer.createUserGroupAndAddCurrentUser(serverGroupName);
}
}
@@ -92,6 +92,16 @@ public class SecurityApiTest extends AbstractSeleniumTest {
assertEquals(adminTenantGroupId, userAndGroupOwner.getA());
}
@Test
public void testCreateUserGroup() throws ClientProtocolException, IOException, ParseException {
final ApiContext adminCtx = createAdminApiContext(getContextRoot(), SECURITY_CONTEXT);
final SecuredServer securedServer = createSecuredServer(adminCtx);
final UUID humbaGroupId = securedServer.createUserGroupAndAddCurrentUser("Humba");
assertNotNull(humbaGroupId);
final UUID humbaGroupIdAgain = securedServer.createUserGroupAndAddCurrentUser("Humba");
assertNull(humbaGroupIdAgain);
}
@Test
public void testGetPermissions() throws ClientProtocolException, IOException, ParseException {
final ApiContext adminCtx = createAdminApiContext(getContextRoot(), SECURITY_CONTEXT);
@@ -25,9 +25,9 @@ import org.json.simple.parser.ParseException;
import com.sap.sse.common.Util;
import com.sap.sse.security.jaxrs.AbstractSecurityResource;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes;
import com.sap.sse.security.shared.impl.User;
@@ -35,7 +35,7 @@ import com.sap.sse.security.shared.impl.UserGroup;
import com.sap.sse.security.shared.impl.UserGroupImpl;
import com.sun.jersey.api.client.ClientResponse.Status;
@Path("/restsecurity/usergroup")
@Path(UserGroupResource.RESTSECURITY_USERGROUP)
public class UserGroupResource extends AbstractSecurityResource {
public static final String RESTSECURITY_USERGROUP = "/restsecurity/usergroup";
public static final String KEY_ROLE_NAME = "roleName";
@@ -42,4 +42,16 @@ public interface SecuredServer {
* The name of the user authenticated by the credentials used by this facade object.
*/
String getUsername() throws MalformedURLException, ClientProtocolException, IOException, ParseException;
/**
* If the user authenticated for this server is permitted to update the user group identified by the {@code userGroupId}, the
* current user is added to the group.
*/
void addUserToGroup(UUID userGroupId);
/**
* Create a user group named {@code serverGroupName} if no group by that name exists yet. The group will be owned by the
* user authenticated for this server, and the user will be added to the group.
*/
UUID createUserGroupAndAddCurrentUser(String serverGroupName) throws ClientProtocolException, IOException, ParseException;
}
@@ -9,6 +9,7 @@ import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
@@ -17,7 +18,9 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.json.simple.JSONArray;
@@ -36,6 +39,8 @@ import com.sap.sse.security.util.SecuredServer;
import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
public class SecuredServerImpl implements SecuredServer {
private static final Logger logger = Logger.getLogger(SecuredServerImpl.class.getName());
private final String bearerToken;
private final URL baseUrl;
@@ -137,9 +142,34 @@ public class SecuredServerImpl implements SecuredServer {
final Object usernameValue = accessTokenJson.get(SecurityResource.USERNAME);
final String username = usernameValue == null ? null : usernameValue.toString();
return username;
}
@Override
public void addUserToGroup(UUID userGroupId) {
// TODO Auto-generated method stub
}
@Override
public UUID createUserGroupAndAddCurrentUser(String userGroupName) throws ClientProtocolException, IOException, ParseException {
final UUID result;
if (getUserGroupIdByName(userGroupName) == null) {
final JSONObject paramPayload = new JSONObject();
paramPayload.put(UserGroupResource.KEY_GROUP_NAME, userGroupName);
final URL createUserGroupUrl = new URL(getBaseUrl(), SECURITY_API_PREFIX + UserGroupResource.RESTSECURITY_USERGROUP);
final HttpPut putRequest = new HttpPut(createUserGroupUrl.toString());
putRequest.setEntity(new StringEntity(paramPayload.toJSONString()));
putRequest.setHeader("Content-type", "application/json");
final JSONObject userGroupJson = (JSONObject) getJsonParsedResponse(putRequest).getA();
final UUID newGroupId = UUID.fromString(userGroupJson.get(UserGroupResource.KEY_GROUP_ID).toString());
result = newGroupId;
} else {
logger.warning("User group name "+userGroupName+" already exists on server "+getBaseUrl()+". Not creating again.");
result = null;
}
return result;
}
@Override
public String toString() {
return getBaseUrl().toString();