Fixes #8343 Differentiate create from update in PUT operations (#8344)

This commit is contained in:
Suresh Srinivas 2022-10-25 04:14:44 -07:00 committed by GitHub
parent 7914cad8ee
commit e9ebb4dd75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 34 additions and 24 deletions

View File

@ -1,6 +1,8 @@
package org.openmetadata.service.resources;
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
import static org.openmetadata.schema.type.MetadataOperation.CREATE;
import static org.openmetadata.schema.type.MetadataOperation.EDIT_ALL;
import java.io.IOException;
import java.util.List;
@ -182,7 +184,7 @@ public abstract class EntityResource<T extends EntityInterface, K extends Entity
}
public Response create(UriInfo uriInfo, SecurityContext securityContext, T entity) throws IOException {
OperationContext operationContext = new OperationContext(entityType, MetadataOperation.CREATE);
OperationContext operationContext = new OperationContext(entityType, CREATE);
authorizer.authorize(securityContext, operationContext, getResourceContext());
entity = addHref(uriInfo, dao.create(uriInfo, entity));
LOG.info("Created {}:{}", Entity.getEntityTypeFromObject(entity), entity.getId());
@ -191,8 +193,13 @@ public abstract class EntityResource<T extends EntityInterface, K extends Entity
public Response createOrUpdate(UriInfo uriInfo, SecurityContext securityContext, T entity) throws IOException {
dao.prepare(entity);
OperationContext operationContext = new OperationContext(entityType, MetadataOperation.CREATE);
authorizer.authorize(securityContext, operationContext, getResourceContextByName(entity.getFullyQualifiedName()));
// If entity does not exist, this is a create operation, else update operation
ResourceContext resourceContext = getResourceContextByName(entity.getFullyQualifiedName());
MetadataOperation operation = resourceContext.getEntity() == null ? CREATE : EDIT_ALL;
OperationContext operationContext = new OperationContext(entityType, operation);
authorizer.authorize(securityContext, operationContext, resourceContext);
PutResponse<T> response = dao.createOrUpdate(uriInfo, entity);
addHref(uriInfo, response.getEntity());
return response.toResponse();

View File

@ -64,6 +64,10 @@ import org.openmetadata.service.util.ResultList;
@Consumes(MediaType.APPLICATION_JSON)
@Collection(name = "settings")
@Slf4j
/**
* Resource for managing OpenMetadata settings that an admin can change. Example - using APIs here, the conversation
* thread notification can be changed to include only events that an organization uses.
*/
public class SettingsResource {
private final SettingsRepository settingsRepository;
private final Authorizer authorizer;
@ -236,6 +240,7 @@ public class SettingsResource {
@PathParam("entityName")
String entityName,
@Valid List<Filters> newFilter) {
authorizer.authorizeAdmin(securityContext, false);
return settingsRepository.updateEntityFilter(entityName, newFilter);
}

View File

@ -24,6 +24,8 @@ import static org.openmetadata.schema.auth.TokenType.PASSWORD_RESET;
import static org.openmetadata.schema.auth.TokenType.REFRESH_TOKEN;
import static org.openmetadata.schema.entity.teams.AuthenticationMechanism.AuthType.BASIC;
import static org.openmetadata.schema.entity.teams.AuthenticationMechanism.AuthType.JWT;
import static org.openmetadata.schema.type.MetadataOperation.CREATE;
import static org.openmetadata.schema.type.MetadataOperation.EDIT_ALL;
import static org.openmetadata.service.exception.CatalogExceptionMessage.EMAIL_SENDING_ISSUE;
import static org.openmetadata.service.exception.CatalogExceptionMessage.INVALID_USERNAME_PASSWORD;
import static org.openmetadata.service.exception.CatalogExceptionMessage.MAX_FAILED_LOGIN_ATTEMPT;
@ -544,17 +546,21 @@ public class UserResource extends EntityResource<User, UserRepository> {
public Response createOrUpdateUser(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateUser create) throws IOException {
User user = getUser(securityContext, create);
// If entity does not exist, this is a create operation, else update operation
ResourceContext resourceContext = getResourceContextByName(user.getFullyQualifiedName());
MetadataOperation operation = resourceContext.getEntity() == null ? CREATE : EDIT_ALL;
dao.prepare(user);
if (Boolean.TRUE.equals(create.getIsAdmin()) || Boolean.TRUE.equals(create.getIsBot())) {
authorizer.authorizeAdmin(securityContext, true);
} else if (!securityContext.getUserPrincipal().getName().equals(user.getName())) {
// doing authorization check outside of authorizer here. We are checking if the logged-in user same as the user
// we are trying to update. One option is to set users.owner as user, however thats not supported User entity.
OperationContext createOperationContext = new OperationContext(entityType, MetadataOperation.CREATE);
ResourceContext resourceContext = getResourceContextByName(user.getName());
// we are trying to update. One option is to set users.owner as user, however that is not supported for User.
OperationContext createOperationContext = new OperationContext(entityType, operation);
authorizer.authorize(securityContext, createOperationContext, resourceContext);
}
if (Boolean.TRUE.equals(create.getIsBot())) {
if (Boolean.TRUE.equals(create.getIsBot())) { // TODO expect bot to be created separately
return createOrUpdateBot(user, create, uriInfo, securityContext);
}
RestUtil.PutResponse<User> response = dao.createOrUpdate(uriInfo, user);

View File

@ -259,7 +259,7 @@ public class UsageResource {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = EntityUsage.class))),
@ApiResponse(responseCode = "400", description = "Bad request")
})
public Response createorUpdateByName(
public Response createOrUpdateByName(
@Context UriInfo uriInfo,
@Parameter(
description = "Entity type for which usage is reported",

View File

@ -114,10 +114,6 @@ public class SubjectCache {
}
}
public List<EntityReference> getInheritedRolesForUser(String userName) {
return getRolesForTeams(getSubjectContext(userName).getTeams());
}
public List<EntityReference> getRolesForTeams(List<EntityReference> teams) {
List<EntityReference> roles = new ArrayList<>();
for (EntityReference teamRef : listOrEmpty(teams)) {

View File

@ -224,9 +224,12 @@ public class SubjectContext {
iterators.add(new RolePolicyIterator(Entity.USER, user.getName(), user.getRoles()));
}
// Finally, iterate over policies of teams to which the user belongs to
for (EntityReference team : user.getTeams()) {
iterators.add(new TeamPolicyIterator(team.getId(), teamsVisited));
if (!Boolean.TRUE.equals(user.getIsBot())) {
// Finally, iterate over policies of teams to which the user belongs to
// Note that ** Bots don't inherit policies or default roles from teams **
for (EntityReference team : user.getTeams()) {
iterators.add(new TeamPolicyIterator(team.getId(), teamsVisited));
}
}
}

View File

@ -10,7 +10,7 @@
},
{
"type" : "policy",
"name" : "DataQualityBotPolicy"
"name" : "QualityBotPolicy"
}
]
}

View File

@ -1008,7 +1008,7 @@ public abstract class EntityResourceTest<T extends EntityInterface, K extends Cr
assertResponse(
() -> updateEntity(updateRequest, OK, TEST_AUTH_HEADERS),
FORBIDDEN,
permissionNotAllowed(TEST_USER_NAME, List.of(MetadataOperation.CREATE)));
permissionNotAllowed(TEST_USER_NAME, List.of(MetadataOperation.EDIT_ALL)));
}
@Test

View File

@ -64,13 +64,6 @@ public class BotResourceTest extends EntityResourceTest<Bot, CreateBot> {
}
}
@Test
void put_entityNonEmptyDescriptionUpdate_200(TestInfo test) {
// PUT based updates are categorized as create operation
// PUT from a bot to update itself is rejected because of that
// TODO turning off the test for now which requires BOT to make update using PUT
}
@Test
void delete_ensureBotUserDelete(TestInfo test) throws IOException {
User testUser = new UserResourceTest().createUser("test-deleter", true);