Fixes 8371 Remove bot flag from authorizeAdmin method (#8372)

* Fixes 8371 Remove bot flag from authorizeAdmin method

* Remove authorizeAdminOrBot method

* Fix merge errors
This commit is contained in:
Suresh Srinivas 2022-10-26 20:36:17 -07:00 committed by GitHub
parent 6d404ccdc1
commit ed8c74e9b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 169 additions and 112 deletions

View File

@ -115,7 +115,7 @@ public class ReportDataResource {
public Response addReportData( public Response addReportData(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid ReportData reportData) @Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid ReportData reportData)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); authorizer.authorizeAdmin(securityContext);
return dao.addReportData(reportData); return dao.addReportData(reportData);
} }
} }

View File

@ -389,7 +389,7 @@ public class WebAnalyticEventResource extends EntityResource<WebAnalyticEvent, W
@Context SecurityContext securityContext, @Context SecurityContext securityContext,
@Valid WebAnalyticEventData webAnalyticEventData) @Valid WebAnalyticEventData webAnalyticEventData)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); authorizer.authorizeAdmin(securityContext);
return dao.addWebAnalyticEventData(uriInfo, webAnalyticEventData); return dao.addWebAnalyticEventData(uriInfo, webAnalyticEventData);
} }

View File

@ -760,7 +760,8 @@ public class TableResource extends EntityResource<Table, TableRepository> {
@Parameter(description = "Id of the table", schema = @Schema(type = "UUID")) @PathParam("id") UUID id, @Parameter(description = "Id of the table", schema = @Schema(type = "UUID")) @PathParam("id") UUID id,
@Valid SQLQuery sqlQuery) @Valid SQLQuery sqlQuery)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(entityType, MetadataOperation.EDIT_ALL);
authorizer.authorize(securityContext, operationContext, getResourceContextById(id));
Table table = dao.addQuery(id, sqlQuery); Table table = dao.addQuery(id, sqlQuery);
return addHref(uriInfo, table); return addHref(uriInfo, table);
} }
@ -784,7 +785,8 @@ public class TableResource extends EntityResource<Table, TableRepository> {
@Parameter(description = "Id of the table", schema = @Schema(type = "string")) @PathParam("id") UUID id, @Parameter(description = "Id of the table", schema = @Schema(type = "string")) @PathParam("id") UUID id,
@Valid DataModel dataModel) @Valid DataModel dataModel)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(entityType, MetadataOperation.EDIT_ALL);
authorizer.authorize(securityContext, operationContext, getResourceContextById(id));
Table table = dao.addDataModel(id, dataModel); Table table = dao.addDataModel(id, dataModel);
return addHref(uriInfo, table); return addHref(uriInfo, table);
} }

View File

@ -454,7 +454,9 @@ public class TestCaseResource extends EntityResource<TestCase, TestCaseRepositor
String fqn, String fqn,
@Valid TestCaseResult testCaseResult) @Valid TestCaseResult testCaseResult)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); ResourceContextInterface resourceContext = TestCaseResourceContext.builder().name(fqn).build();
OperationContext operationContext = new OperationContext(Entity.TABLE, MetadataOperation.EDIT_TESTS);
authorizer.authorize(securityContext, operationContext, resourceContext);
return dao.addTestCaseResult(uriInfo, fqn, testCaseResult).toResponse(); return dao.addTestCaseResult(uriInfo, fqn, testCaseResult).toResponse();
} }
@ -522,7 +524,9 @@ public class TestCaseResource extends EntityResource<TestCase, TestCaseRepositor
@PathParam("timestamp") @PathParam("timestamp")
Long timestamp) Long timestamp)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); ResourceContextInterface resourceContext = TestCaseResourceContext.builder().name(fqn).build();
OperationContext operationContext = new OperationContext(Entity.TABLE, MetadataOperation.EDIT_TESTS);
authorizer.authorize(securityContext, operationContext, resourceContext);
return dao.deleteTestCaseResult(fqn, timestamp).toResponse(); return dao.deleteTestCaseResult(fqn, timestamp).toResponse();
} }

View File

@ -125,7 +125,7 @@ public class BuildSearchIndexResource {
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateEventPublisherJob createRequest) @Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateEventPublisherJob createRequest)
throws IOException { throws IOException {
// Only admins can issue a reindex request // Only admins can issue a reindex request
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
User user = User user =
userRepository.getByName(null, securityContext.getUserPrincipal().getName(), userRepository.getFields("id")); userRepository.getByName(null, securityContext.getUserPrincipal().getName(), userRepository.getFields("id"));
if (createRequest.getRunMode() == RunMode.BATCH) { if (createRequest.getRunMode() == RunMode.BATCH) {
@ -150,7 +150,7 @@ public class BuildSearchIndexResource {
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @PathParam("runMode") String runMode) @Context UriInfo uriInfo, @Context SecurityContext securityContext, @PathParam("runMode") String runMode)
throws IOException { throws IOException {
// Only admins can issue a reindex request // Only admins can issue a reindex request
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
// Check if there is a running job for reindex for requested entity // Check if there is a running job for reindex for requested entity
String record; String record;
if (runMode.equals(RunMode.BATCH.toString())) { if (runMode.equals(RunMode.BATCH.toString())) {

View File

@ -357,7 +357,7 @@ public class FeedResource {
// don't throw any exception // don't throw any exception
} else { } else {
// Only admins or bots can close or resolve task other than the above-mentioned users // Only admins or bots can close or resolve task other than the above-mentioned users
authorizer.authorizeAdmin(securityContext, true); authorizer.authorizeAdmin(securityContext);
} }
} }
} }

View File

@ -52,6 +52,7 @@ import org.openmetadata.schema.entity.data.PipelineStatus;
import org.openmetadata.schema.type.ChangeEvent; import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory; import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include; import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.service.Entity; import org.openmetadata.service.Entity;
import org.openmetadata.service.jdbi3.CollectionDAO; import org.openmetadata.service.jdbi3.CollectionDAO;
import org.openmetadata.service.jdbi3.ListFilter; import org.openmetadata.service.jdbi3.ListFilter;
@ -60,6 +61,7 @@ import org.openmetadata.service.resources.Collection;
import org.openmetadata.service.resources.EntityResource; import org.openmetadata.service.resources.EntityResource;
import org.openmetadata.service.resources.dqtests.TestCaseResource; import org.openmetadata.service.resources.dqtests.TestCaseResource;
import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.Authorizer;
import org.openmetadata.service.security.policyevaluator.OperationContext;
import org.openmetadata.service.util.RestUtil; import org.openmetadata.service.util.RestUtil;
import org.openmetadata.service.util.ResultList; import org.openmetadata.service.util.ResultList;
@ -362,7 +364,8 @@ public class PipelineResource extends EntityResource<Pipeline, PipelineRepositor
@Parameter(description = "Id of the pipeline", schema = @Schema(type = "string")) @PathParam("fqn") String fqn, @Parameter(description = "Id of the pipeline", schema = @Schema(type = "string")) @PathParam("fqn") String fqn,
@Valid PipelineStatus pipelineStatus) @Valid PipelineStatus pipelineStatus)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(entityType, MetadataOperation.EDIT_STATUS);
authorizer.authorize(securityContext, operationContext, getResourceContextByName(fqn));
Pipeline pipeline = dao.addPipelineStatus(fqn, pipelineStatus); Pipeline pipeline = dao.addPipelineStatus(fqn, pipelineStatus);
return addHref(uriInfo, pipeline); return addHref(uriInfo, pipeline);
} }
@ -427,7 +430,8 @@ public class PipelineResource extends EntityResource<Pipeline, PipelineRepositor
@PathParam("timestamp") @PathParam("timestamp")
Long timestamp) Long timestamp)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(entityType, MetadataOperation.EDIT_STATUS);
authorizer.authorize(securityContext, operationContext, getResourceContextByName(fqn));
Pipeline pipeline = dao.deletePipelineStatus(fqn, timestamp); Pipeline pipeline = dao.deletePipelineStatus(fqn, timestamp);
return addHref(uriInfo, pipeline); return addHref(uriInfo, pipeline);
} }

View File

@ -27,7 +27,6 @@ import org.openmetadata.service.jdbi3.ServiceEntityRepository;
import org.openmetadata.service.resources.EntityResource; import org.openmetadata.service.resources.EntityResource;
import org.openmetadata.service.secrets.SecretsManager; import org.openmetadata.service.secrets.SecretsManager;
import org.openmetadata.service.secrets.SecretsManagerFactory; import org.openmetadata.service.secrets.SecretsManagerFactory;
import org.openmetadata.service.security.AuthorizationException;
import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.Authorizer;
import org.openmetadata.service.util.JsonUtils; import org.openmetadata.service.util.JsonUtils;
import org.openmetadata.service.util.ResultList; import org.openmetadata.service.util.ResultList;
@ -50,10 +49,7 @@ public abstract class ServiceEntityResource<
} }
protected T decryptOrNullify(SecurityContext securityContext, T service) { protected T decryptOrNullify(SecurityContext securityContext, T service) {
SecretsManager secretsManager = SecretsManagerFactory.getSecretsManager(); if (!authorizer.decryptSecret(securityContext)) {
try {
authorizer.authorizeAdmin(securityContext, secretsManager.isLocal());
} catch (AuthorizationException e) {
return nullifyRequiredConnectionParameters(service); return nullifyRequiredConnectionParameters(service);
} }
service.getConnection().setConfig(retrieveServiceConnectionConfig(service)); service.getConnection().setConfig(retrieveServiceConnectionConfig(service));

View File

@ -58,16 +58,16 @@ import org.openmetadata.service.util.FilterUtil;
import org.openmetadata.service.util.JsonUtils; import org.openmetadata.service.util.JsonUtils;
import org.openmetadata.service.util.ResultList; import org.openmetadata.service.util.ResultList;
/**
* 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.
*/
@Path("/v1/settings") @Path("/v1/settings")
@Api(value = "Settings Collection", tags = "Settings collection") @Api(value = "Settings Collection", tags = "Settings collection")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Collection(name = "settings") @Collection(name = "settings")
@Slf4j @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 { public class SettingsResource {
private final SettingsRepository settingsRepository; private final SettingsRepository settingsRepository;
private final Authorizer authorizer; private final Authorizer authorizer;
@ -144,7 +144,7 @@ public class SettingsResource {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = SettingsList.class))) content = @Content(mediaType = "application/json", schema = @Schema(implementation = SettingsList.class)))
}) })
public ResultList<Settings> list(@Context UriInfo uriInfo, @Context SecurityContext securityContext) { public ResultList<Settings> list(@Context UriInfo uriInfo, @Context SecurityContext securityContext) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return settingsRepository.listAllConfigs(); return settingsRepository.listAllConfigs();
} }
@ -162,7 +162,7 @@ public class SettingsResource {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = SettingsList.class))) content = @Content(mediaType = "application/json", schema = @Schema(implementation = SettingsList.class)))
}) })
public List<EventFilter> getBootstrapFilters(@Context UriInfo uriInfo, @Context SecurityContext securityContext) { public List<EventFilter> getBootstrapFilters(@Context UriInfo uriInfo, @Context SecurityContext securityContext) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return bootStrappedFilters; return bootStrappedFilters;
} }
@ -180,7 +180,7 @@ public class SettingsResource {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = SettingsList.class))) content = @Content(mediaType = "application/json", schema = @Schema(implementation = SettingsList.class)))
}) })
public Response resetFilters(@Context UriInfo uriInfo, @Context SecurityContext securityContext) { public Response resetFilters(@Context UriInfo uriInfo, @Context SecurityContext securityContext) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
Settings settings = Settings settings =
new Settings().withConfigType(ACTIVITY_FEED_FILTER_SETTING).withConfigValue(bootStrappedFilters); new Settings().withConfigType(ACTIVITY_FEED_FILTER_SETTING).withConfigValue(bootStrappedFilters);
return settingsRepository.createNewSetting(settings); return settingsRepository.createNewSetting(settings);
@ -203,7 +203,7 @@ public class SettingsResource {
@Context UriInfo uriInfo, @Context UriInfo uriInfo,
@Context SecurityContext securityContext, @Context SecurityContext securityContext,
@PathParam("settingName") String settingName) { @PathParam("settingName") String settingName) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return settingsRepository.getConfigWithKey(settingName); return settingsRepository.getConfigWithKey(settingName);
} }
@ -221,7 +221,7 @@ public class SettingsResource {
}) })
public Response createOrUpdateSetting( public Response createOrUpdateSetting(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid Settings settingName) { @Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid Settings settingName) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return settingsRepository.createOrUpdate(settingName); return settingsRepository.createOrUpdate(settingName);
} }
@ -245,7 +245,6 @@ public class SettingsResource {
@PathParam("entityName") @PathParam("entityName")
String entityName, String entityName,
@Valid List<Filters> newFilter) { @Valid List<Filters> newFilter) {
authorizer.authorizeAdmin(securityContext, false);
return settingsRepository.updateEntityFilter(entityName, newFilter); return settingsRepository.updateEntityFilter(entityName, newFilter);
} }
@ -272,7 +271,7 @@ public class SettingsResource {
@ExampleObject("[" + "{op:remove, path:/a}," + "{op:add, path: /b, value: val}" + "]") @ExampleObject("[" + "{op:remove, path:/a}," + "{op:add, path: /b, value: val}" + "]")
})) }))
JsonPatch patch) { JsonPatch patch) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return settingsRepository.patchSetting(settingName, patch); return settingsRepository.patchSetting(settingName, patch);
} }
} }

View File

@ -48,6 +48,7 @@ import org.openmetadata.schema.api.tags.CreateTag;
import org.openmetadata.schema.api.tags.CreateTagCategory; import org.openmetadata.schema.api.tags.CreateTagCategory;
import org.openmetadata.schema.entity.tags.Tag; import org.openmetadata.schema.entity.tags.Tag;
import org.openmetadata.schema.type.Include; import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.schema.type.TagCategory; import org.openmetadata.schema.type.TagCategory;
import org.openmetadata.service.Entity; import org.openmetadata.service.Entity;
import org.openmetadata.service.OpenMetadataApplicationConfig; import org.openmetadata.service.OpenMetadataApplicationConfig;
@ -56,7 +57,10 @@ import org.openmetadata.service.jdbi3.ListFilter;
import org.openmetadata.service.jdbi3.TagCategoryRepository; import org.openmetadata.service.jdbi3.TagCategoryRepository;
import org.openmetadata.service.jdbi3.TagRepository; import org.openmetadata.service.jdbi3.TagRepository;
import org.openmetadata.service.resources.Collection; import org.openmetadata.service.resources.Collection;
import org.openmetadata.service.resources.EntityResource;
import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.Authorizer;
import org.openmetadata.service.security.policyevaluator.OperationContext;
import org.openmetadata.service.security.policyevaluator.ResourceContext;
import org.openmetadata.service.util.EntityUtil.Fields; import org.openmetadata.service.util.EntityUtil.Fields;
import org.openmetadata.service.util.FullyQualifiedName; import org.openmetadata.service.util.FullyQualifiedName;
import org.openmetadata.service.util.RestUtil; import org.openmetadata.service.util.RestUtil;
@ -279,7 +283,9 @@ public class TagResource {
public Response createCategory( public Response createCategory(
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateTagCategory create) @Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateTagCategory create)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(Entity.TAG_CATEGORY, MetadataOperation.CREATE);
ResourceContext resourceContext = EntityResource.getResourceContext(Entity.TAG_CATEGORY, daoCategory).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
TagCategory category = getTagCategory(securityContext, create); TagCategory category = getTagCategory(securityContext, create);
category = addHref(uriInfo, daoCategory.create(uriInfo, category)); category = addHref(uriInfo, daoCategory.create(uriInfo, category));
return Response.created(category.getHref()).entity(category).build(); return Response.created(category.getHref()).entity(category).build();
@ -306,7 +312,9 @@ public class TagResource {
String category, String category,
@Valid CreateTag create) @Valid CreateTag create)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(Entity.TAG, MetadataOperation.CREATE);
ResourceContext resourceContext = EntityResource.getResourceContext(Entity.TAG, dao).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
Tag tag = getTag(securityContext, create, FullyQualifiedName.build(category)); Tag tag = getTag(securityContext, create, FullyQualifiedName.build(category));
URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, category); URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, category);
tag = addHref(categoryHref, dao.create(uriInfo, tag)); tag = addHref(categoryHref, dao.create(uriInfo, tag));
@ -342,7 +350,9 @@ public class TagResource {
String primaryTag, String primaryTag,
@Valid CreateTag create) @Valid CreateTag create)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(Entity.TAG, MetadataOperation.CREATE);
ResourceContext resourceContext = EntityResource.getResourceContext(Entity.TAG, dao).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
Tag tag = getTag(securityContext, create, FullyQualifiedName.build(category, primaryTag)); Tag tag = getTag(securityContext, create, FullyQualifiedName.build(category, primaryTag));
URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, category); URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, category);
URI parentHRef = RestUtil.getHref(categoryHref, primaryTag); URI parentHRef = RestUtil.getHref(categoryHref, primaryTag);
@ -364,7 +374,10 @@ public class TagResource {
String categoryName, String categoryName,
@Valid CreateTagCategory create) @Valid CreateTagCategory create)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(Entity.TAG_CATEGORY, MetadataOperation.EDIT_ALL);
ResourceContext resourceContext =
EntityResource.getResourceContext(Entity.TAG_CATEGORY, daoCategory).name(categoryName).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
TagCategory category = getTagCategory(securityContext, create); TagCategory category = getTagCategory(securityContext, create);
// TODO clean this up // TODO clean this up
if (categoryName.equals(create.getName())) { // Not changing the name if (categoryName.equals(create.getName())) { // Not changing the name
@ -398,8 +411,12 @@ public class TagResource {
String primaryTag, String primaryTag,
@Valid CreateTag create) @Valid CreateTag create)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true);
Tag tag = getTag(securityContext, create, FullyQualifiedName.build(categoryName)); Tag tag = getTag(securityContext, create, FullyQualifiedName.build(categoryName));
OperationContext operationContext = new OperationContext(Entity.TAG, MetadataOperation.EDIT_ALL);
ResourceContext resourceContext = EntityResource.getResourceContext(Entity.TAG, dao).name(categoryName).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, categoryName); URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, categoryName);
RestUtil.PutResponse<?> response; RestUtil.PutResponse<?> response;
if (primaryTag.equals(create.getName())) { // Not changing the name if (primaryTag.equals(create.getName())) { // Not changing the name
@ -442,7 +459,7 @@ public class TagResource {
String secondaryTag, String secondaryTag,
@Valid CreateTag create) @Valid CreateTag create)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
Tag tag = getTag(securityContext, create, FullyQualifiedName.build(categoryName, primaryTag)); Tag tag = getTag(securityContext, create, FullyQualifiedName.build(categoryName, primaryTag));
URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, categoryName); URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, categoryName);
URI parentHRef = RestUtil.getHref(categoryHref, primaryTag); URI parentHRef = RestUtil.getHref(categoryHref, primaryTag);
@ -471,7 +488,10 @@ public class TagResource {
@Context SecurityContext securityContext, @Context SecurityContext securityContext,
@Parameter(description = "Tag category id", schema = @Schema(type = "UUID")) @PathParam("id") UUID id) @Parameter(description = "Tag category id", schema = @Schema(type = "UUID")) @PathParam("id") UUID id)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(Entity.TAG_CATEGORY, MetadataOperation.EDIT_ALL);
ResourceContext resourceContext =
EntityResource.getResourceContext(Entity.TAG_CATEGORY, daoCategory).id(id).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
TagCategory tagCategory = daoCategory.delete(uriInfo, id); TagCategory tagCategory = daoCategory.delete(uriInfo, id);
addHref(uriInfo, tagCategory); addHref(uriInfo, tagCategory);
return new RestUtil.DeleteResponse<>(tagCategory, RestUtil.ENTITY_DELETED).toResponse(); return new RestUtil.DeleteResponse<>(tagCategory, RestUtil.ENTITY_DELETED).toResponse();
@ -490,7 +510,10 @@ public class TagResource {
@Parameter(description = "Tag id", schema = @Schema(type = "string")) @PathParam("category") String category, @Parameter(description = "Tag id", schema = @Schema(type = "string")) @PathParam("category") String category,
@Parameter(description = "Tag id", schema = @Schema(type = "UUID")) @PathParam("id") UUID id) @Parameter(description = "Tag id", schema = @Schema(type = "UUID")) @PathParam("id") UUID id)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(Entity.TAG, MetadataOperation.EDIT_ALL);
ResourceContext resourceContext = EntityResource.getResourceContext(Entity.TAG, dao).id(id).build();
authorizer.authorize(securityContext, operationContext, resourceContext);
Tag tag = dao.delete(uriInfo, id); Tag tag = dao.delete(uriInfo, id);
URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, category); URI categoryHref = RestUtil.getHref(uriInfo, TAG_COLLECTION_PATH, category);
addHref(categoryHref, tag); addHref(categoryHref, tag);

View File

@ -286,7 +286,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
description = "Generate a random pwd", description = "Generate a random pwd",
responses = {@ApiResponse(responseCode = "200", description = "Random pwd")}) responses = {@ApiResponse(responseCode = "200", description = "Random pwd")})
public Response generateRandomPassword(@Context UriInfo uriInfo, @Context SecurityContext securityContext) { public Response generateRandomPassword(@Context UriInfo uriInfo, @Context SecurityContext securityContext) {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return Response.status(OK).entity(PasswordUtil.generateRandomPassword()).build(); return Response.status(OK).entity(PasswordUtil.generateRandomPassword()).build();
} }
@ -485,7 +485,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateUser create) throws IOException { @Context UriInfo uriInfo, @Context SecurityContext securityContext, @Valid CreateUser create) throws IOException {
User user = getUser(securityContext, create); User user = getUser(securityContext, create);
if (Boolean.TRUE.equals(create.getIsAdmin())) { if (Boolean.TRUE.equals(create.getIsAdmin())) {
authorizer.authorizeAdmin(securityContext, true); authorizer.authorizeAdmin(securityContext);
} }
if (Boolean.TRUE.equals(create.getIsBot())) { if (Boolean.TRUE.equals(create.getIsBot())) {
addAuthMechanismToBot(user, create, uriInfo); addAuthMechanismToBot(user, create, uriInfo);
@ -552,8 +552,8 @@ public class UserResource extends EntityResource<User, UserRepository> {
MetadataOperation operation = resourceContext.getEntity() == null ? CREATE : EDIT_ALL; MetadataOperation operation = resourceContext.getEntity() == null ? CREATE : EDIT_ALL;
dao.prepare(user); dao.prepare(user);
if (Boolean.TRUE.equals(create.getIsAdmin()) || Boolean.TRUE.equals(create.getIsBot())) { if (Boolean.TRUE.equals(create.getIsAdmin())) {
authorizer.authorizeAdmin(securityContext, true); authorizer.authorizeAdmin(securityContext);
} else if (!securityContext.getUserPrincipal().getName().equals(user.getName())) { } 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 // 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 that is not supported for User. // we are trying to update. One option is to set users.owner as user, however that is not supported for User.
@ -590,17 +590,10 @@ public class UserResource extends EntityResource<User, UserRepository> {
@Valid GenerateTokenRequest generateTokenRequest) @Valid GenerateTokenRequest generateTokenRequest)
throws IOException { throws IOException {
User user = dao.get(uriInfo, id, Fields.EMPTY_FIELDS); User user = dao.get(uriInfo, id, Fields.EMPTY_FIELDS);
authorizeGenerateJWT(user); authorizer.authorizeAdmin(securityContext);
authorizer.authorizeAdmin(securityContext, false); jwtTokenGenerator.setAuthMechanism(user, generateTokenRequest);
JWTAuthMechanism jwtAuthMechanism =
jwtTokenGenerator.generateJWTToken(user, generateTokenRequest.getJWTTokenExpiry());
AuthenticationMechanism authenticationMechanism =
new AuthenticationMechanism().withConfig(jwtAuthMechanism).withAuthType(AuthenticationMechanism.AuthType.JWT);
user.setAuthenticationMechanism(authenticationMechanism);
User updatedUser = dao.createOrUpdate(uriInfo, user).getEntity(); User updatedUser = dao.createOrUpdate(uriInfo, user).getEntity();
jwtAuthMechanism = return Response.status(Response.Status.OK).entity(jwtTokenGenerator.getAuthMechanism(updatedUser)).build();
JsonUtils.convertValue(updatedUser.getAuthenticationMechanism().getConfig(), JWTAuthMechanism.class);
return Response.status(Response.Status.OK).entity(jwtAuthMechanism).build();
} }
@PUT @PUT
@ -622,8 +615,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
@Context UriInfo uriInfo, @Context SecurityContext securityContext, @PathParam("id") UUID id) throws IOException { @Context UriInfo uriInfo, @Context SecurityContext securityContext, @PathParam("id") UUID id) throws IOException {
User user = dao.get(uriInfo, id, Fields.EMPTY_FIELDS); User user = dao.get(uriInfo, id, Fields.EMPTY_FIELDS);
authorizeGenerateJWT(user); authorizer.authorizeAdmin(securityContext);
authorizer.authorizeAdmin(securityContext, false);
JWTAuthMechanism jwtAuthMechanism = new JWTAuthMechanism().withJWTToken(StringUtils.EMPTY); JWTAuthMechanism jwtAuthMechanism = new JWTAuthMechanism().withJWTToken(StringUtils.EMPTY);
AuthenticationMechanism authenticationMechanism = AuthenticationMechanism authenticationMechanism =
new AuthenticationMechanism().withConfig(jwtAuthMechanism).withAuthType(JWT); new AuthenticationMechanism().withConfig(jwtAuthMechanism).withAuthType(JWT);
@ -658,7 +650,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
throw new IllegalArgumentException("JWT token is only supported for bot users"); throw new IllegalArgumentException("JWT token is only supported for bot users");
} }
decryptOrNullify(securityContext, user); decryptOrNullify(securityContext, user);
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
AuthenticationMechanism authenticationMechanism = user.getAuthenticationMechanism(); AuthenticationMechanism authenticationMechanism = user.getAuthenticationMechanism();
if (authenticationMechanism != null if (authenticationMechanism != null
&& authenticationMechanism.getConfig() != null && authenticationMechanism.getConfig() != null
@ -693,7 +685,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
throw new IllegalArgumentException("JWT token is only supported for bot users"); throw new IllegalArgumentException("JWT token is only supported for bot users");
} }
decryptOrNullify(securityContext, user); decryptOrNullify(securityContext, user);
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
return user.getAuthenticationMechanism(); return user.getAuthenticationMechanism();
} }
@ -724,8 +716,8 @@ public class UserResource extends EntityResource<User, UserRepository> {
JsonObject patchOpObject = patchOp.asJsonObject(); JsonObject patchOpObject = patchOp.asJsonObject();
if (patchOpObject.containsKey("path") && patchOpObject.containsKey("value")) { if (patchOpObject.containsKey("path") && patchOpObject.containsKey("value")) {
String path = patchOpObject.getString("path"); String path = patchOpObject.getString("path");
if (path.equals("/isAdmin") || path.equals("/isBot")) { if (path.equals("/isAdmin")) {
authorizer.authorizeAdmin(securityContext, true); authorizer.authorizeAdmin(securityContext);
} }
// if path contains team, check if team is joinable by any user // if path contains team, check if team is joinable by any user
if (patchOpObject.containsKey("op") if (patchOpObject.containsKey("op")
@ -742,7 +734,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
dao.validateTeamAddition(id, UUID.fromString(teamId)); dao.validateTeamAddition(id, UUID.fromString(teamId));
if (!dao.isTeamJoinable(teamId)) { if (!dao.isTeamJoinable(teamId)) {
// Only admin can join closed teams // Only admin can join closed teams
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
} }
} }
} }
@ -1001,7 +993,7 @@ public class UserResource extends EntityResource<User, UserRepository> {
return Response.status(403).entity(new ErrorMessage(403, "Old Password is not correct")).build(); return Response.status(403).entity(new ErrorMessage(403, "Old Password is not correct")).build();
} }
} else { } else {
authorizer.authorizeAdmin(securityContext, false); authorizer.authorizeAdmin(securityContext);
User storedUser = dao.getByName(uriInfo, request.getUsername(), new Fields(fields, String.join(",", fields))); User storedUser = dao.getByName(uriInfo, request.getUsername(), new Fields(fields, String.join(",", fields)));
String newHashedPassword = BCrypt.withDefaults().hashToString(12, request.getNewPassword().toCharArray()); String newHashedPassword = BCrypt.withDefaults().hashToString(12, request.getNewPassword().toCharArray());
// Admin is allowed to set password for User directly // Admin is allowed to set password for User directly
@ -1191,12 +1183,6 @@ public class UserResource extends EntityResource<User, UserRepository> {
.withRoles(EntityUtil.toEntityReferences(create.getRoles(), Entity.ROLE)); .withRoles(EntityUtil.toEntityReferences(create.getRoles(), Entity.ROLE));
} }
private void authorizeGenerateJWT(User user) {
if (!Boolean.TRUE.equals(user.getIsBot())) {
throw new IllegalArgumentException("Generating JWT token is only supported for bot users");
}
}
public User registerUser(UriInfo uriInfo, RegistrationRequest newRegistrationRequest) throws IOException { public User registerUser(UriInfo uriInfo, RegistrationRequest newRegistrationRequest) throws IOException {
String newRegistrationRequestEmail = newRegistrationRequest.getEmail(); String newRegistrationRequestEmail = newRegistrationRequest.getEmail();
String[] tokens = newRegistrationRequest.getEmail().split("@"); String[] tokens = newRegistrationRequest.getEmail().split("@");

View File

@ -51,6 +51,7 @@ import org.openmetadata.schema.entity.data.Topic;
import org.openmetadata.schema.type.ChangeEvent; import org.openmetadata.schema.type.ChangeEvent;
import org.openmetadata.schema.type.EntityHistory; import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include; import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.schema.type.topic.TopicSampleData; import org.openmetadata.schema.type.topic.TopicSampleData;
import org.openmetadata.service.Entity; import org.openmetadata.service.Entity;
import org.openmetadata.service.jdbi3.CollectionDAO; import org.openmetadata.service.jdbi3.CollectionDAO;
@ -59,6 +60,7 @@ import org.openmetadata.service.jdbi3.TopicRepository;
import org.openmetadata.service.resources.Collection; import org.openmetadata.service.resources.Collection;
import org.openmetadata.service.resources.EntityResource; import org.openmetadata.service.resources.EntityResource;
import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.Authorizer;
import org.openmetadata.service.security.policyevaluator.OperationContext;
import org.openmetadata.service.util.ResultList; import org.openmetadata.service.util.ResultList;
@Path("/v1/topics") @Path("/v1/topics")
@ -344,7 +346,8 @@ public class TopicResource extends EntityResource<Topic, TopicRepository> {
@Parameter(description = "Id of the topic", schema = @Schema(type = "string")) @PathParam("id") UUID id, @Parameter(description = "Id of the topic", schema = @Schema(type = "string")) @PathParam("id") UUID id,
@Valid TopicSampleData sampleData) @Valid TopicSampleData sampleData)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, true); OperationContext operationContext = new OperationContext(entityType, MetadataOperation.EDIT_SAMPLE_DATA);
authorizer.authorize(securityContext, operationContext, getResourceContextById(id));
Topic topic = dao.addSampleData(id, sampleData); Topic topic = dao.addSampleData(id, sampleData);
return addHref(uriInfo, topic); return addHref(uriInfo, topic);
} }

View File

@ -56,6 +56,7 @@ import org.openmetadata.schema.entity.type.Category;
import org.openmetadata.schema.entity.type.CustomProperty; import org.openmetadata.schema.entity.type.CustomProperty;
import org.openmetadata.schema.type.EntityHistory; import org.openmetadata.schema.type.EntityHistory;
import org.openmetadata.schema.type.Include; import org.openmetadata.schema.type.Include;
import org.openmetadata.schema.type.MetadataOperation;
import org.openmetadata.service.Entity; import org.openmetadata.service.Entity;
import org.openmetadata.service.OpenMetadataApplicationConfig; import org.openmetadata.service.OpenMetadataApplicationConfig;
import org.openmetadata.service.jdbi3.CollectionDAO; import org.openmetadata.service.jdbi3.CollectionDAO;
@ -64,6 +65,7 @@ import org.openmetadata.service.jdbi3.TypeRepository;
import org.openmetadata.service.resources.Collection; import org.openmetadata.service.resources.Collection;
import org.openmetadata.service.resources.EntityResource; import org.openmetadata.service.resources.EntityResource;
import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.Authorizer;
import org.openmetadata.service.security.policyevaluator.OperationContext;
import org.openmetadata.service.util.EntityUtil.Fields; import org.openmetadata.service.util.EntityUtil.Fields;
import org.openmetadata.service.util.JsonUtils; import org.openmetadata.service.util.JsonUtils;
import org.openmetadata.service.util.RestUtil.PutResponse; import org.openmetadata.service.util.RestUtil.PutResponse;
@ -389,7 +391,9 @@ public class TypeResource extends EntityResource<Type, TypeRepository> {
@Parameter(description = "Type Id", schema = @Schema(type = "string")) @PathParam("id") UUID id, @Parameter(description = "Type Id", schema = @Schema(type = "string")) @PathParam("id") UUID id,
@Valid CustomProperty property) @Valid CustomProperty property)
throws IOException { throws IOException {
authorizer.authorizeAdmin(securityContext, false); // TODO fix this is the typeID correct? Why are we not doing this by name?
OperationContext operationContext = new OperationContext(entityType, MetadataOperation.CREATE);
authorizer.authorize(securityContext, operationContext, getResourceContextById(id));
PutResponse<Type> response = PutResponse<Type> response =
dao.addCustomProperty(uriInfo, securityContext.getUserPrincipal().getName(), id, property); dao.addCustomProperty(uriInfo, securityContext.getUserPrincipal().getName(), id, property);
addHref(uriInfo, response.getEntity()); addHref(uriInfo, response.getEntity());

View File

@ -41,5 +41,7 @@ public interface Authorizer {
SecurityContext securityContext, OperationContext operationContext, ResourceContextInterface resourceContext) SecurityContext securityContext, OperationContext operationContext, ResourceContextInterface resourceContext)
throws IOException; throws IOException;
void authorizeAdmin(SecurityContext securityContext, boolean allowBots); void authorizeAdmin(SecurityContext securityContext);
boolean decryptSecret(SecurityContext securityContext);
} }

View File

@ -229,14 +229,28 @@ public class DefaultAuthorizer implements Authorizer {
} }
@Override @Override
public void authorizeAdmin(SecurityContext securityContext, boolean allowBots) { public void authorizeAdmin(SecurityContext securityContext) {
SubjectContext subjectContext = getSubjectContext(securityContext); SubjectContext subjectContext = getSubjectContext(securityContext);
if (subjectContext.isAdmin() || (allowBots && subjectContext.isBot())) { if (subjectContext.isAdmin()) {
return; return;
} }
throw new AuthorizationException(notAdmin(securityContext.getUserPrincipal().getName())); throw new AuthorizationException(notAdmin(securityContext.getUserPrincipal().getName()));
} }
@Override
public boolean decryptSecret(SecurityContext securityContext) {
SubjectContext subjectContext = getSubjectContext(securityContext);
if (subjectContext.isAdmin()) { // Always decrypt secrets for admin
return true;
}
SecretsManager secretsManager = SecretsManagerFactory.getSecretsManager();
if (subjectContext.isBot() && secretsManager.isLocal()) {
// Local secretsManager true means secrets are not encrypted. So allow decrypted secrets for bots.
return true;
}
return false;
}
private void addUsers(Set<String> users, String domain, Boolean isAdmin) { private void addUsers(Set<String> users, String domain, Boolean isAdmin) {
for (String userName : users) { for (String userName : users) {
User user = user(userName, domain, userName).withIsAdmin(isAdmin); User user = user(userName, domain, userName).withIsAdmin(isAdmin);

View File

@ -95,7 +95,12 @@ public class NoopAuthorizer implements Authorizer {
} }
@Override @Override
public void authorizeAdmin(SecurityContext securityContext, boolean allowBots) { public void authorizeAdmin(SecurityContext securityContext) {
/* Always authorize */ /* Always authorize */
} }
@Override
public boolean decryptSecret(SecurityContext securityContext) {
return true; // Always decrypt
}
} }

View File

@ -20,10 +20,13 @@ import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.openmetadata.schema.api.security.jwt.JWTTokenConfiguration; import org.openmetadata.schema.api.security.jwt.JWTTokenConfiguration;
import org.openmetadata.schema.entity.teams.AuthenticationMechanism;
import org.openmetadata.schema.entity.teams.User; import org.openmetadata.schema.entity.teams.User;
import org.openmetadata.schema.teams.authn.GenerateTokenRequest;
import org.openmetadata.schema.teams.authn.JWTAuthMechanism; import org.openmetadata.schema.teams.authn.JWTAuthMechanism;
import org.openmetadata.schema.teams.authn.JWTTokenExpiry; import org.openmetadata.schema.teams.authn.JWTTokenExpiry;
import org.openmetadata.service.security.AuthenticationException; import org.openmetadata.service.security.AuthenticationException;
import org.openmetadata.service.util.JsonUtils;
@Slf4j @Slf4j
public class JWTTokenGenerator { public class JWTTokenGenerator {
@ -65,6 +68,17 @@ public class JWTTokenGenerator {
} }
} }
public void setAuthMechanism(User user, GenerateTokenRequest generateTokenRequest) {
JWTAuthMechanism jwtAuthMechanism = generateJWTToken(user, generateTokenRequest.getJWTTokenExpiry());
AuthenticationMechanism authenticationMechanism =
new AuthenticationMechanism().withConfig(jwtAuthMechanism).withAuthType(AuthenticationMechanism.AuthType.JWT);
user.setAuthenticationMechanism(authenticationMechanism);
}
public JWTAuthMechanism getAuthMechanism(User user) {
return JsonUtils.convertValue(user.getAuthenticationMechanism().getConfig(), JWTAuthMechanism.class);
}
public JWTAuthMechanism generateJWTToken(User user, JWTTokenExpiry expiry) { public JWTAuthMechanism generateJWTToken(User user, JWTTokenExpiry expiry) {
try { try {
JWTAuthMechanism jwtAuthMechanism = new JWTAuthMechanism().withJWTTokenExpiry(expiry); JWTAuthMechanism jwtAuthMechanism = new JWTAuthMechanism().withJWTTokenExpiry(expiry);

View File

@ -39,6 +39,10 @@ public class OperationContext {
return operations; return operations;
} }
public boolean isCreateOperation() {
return operations.contains(MetadataOperation.CREATE);
}
public static boolean isEditOperation(MetadataOperation operation) { public static boolean isEditOperation(MetadataOperation operation) {
return operation.value().startsWith("Edit"); return operation.value().startsWith("Edit");
} }

View File

@ -452,6 +452,17 @@
"EditDisplayName" "EditDisplayName"
] ]
}, },
{
"name" : "type",
"operations" : [
"Create",
"Delete",
"ViewAll",
"EditAll",
"EditDescription",
"EditDisplayName"
]
},
{ {
"name" : "type", "name" : "type",
"operations" : [ "operations" : [

View File

@ -21,7 +21,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -42,7 +41,6 @@ import org.openmetadata.service.jdbi3.CollectionDAO;
import org.openmetadata.service.jdbi3.ServiceEntityRepository; import org.openmetadata.service.jdbi3.ServiceEntityRepository;
import org.openmetadata.service.secrets.SecretsManager; import org.openmetadata.service.secrets.SecretsManager;
import org.openmetadata.service.secrets.SecretsManagerFactory; import org.openmetadata.service.secrets.SecretsManagerFactory;
import org.openmetadata.service.security.AuthorizationException;
import org.openmetadata.service.security.Authorizer; import org.openmetadata.service.security.Authorizer;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@ -105,21 +103,16 @@ public abstract class ServiceResourceTest<
throws IOException { throws IOException {
lenient().when(secretsManager.isLocal()).thenReturn(isLocalSecretManager); lenient().when(secretsManager.isLocal()).thenReturn(isLocalSecretManager);
if (isLocalSecretManager && !isAdmin && !isBot) { if (isAdmin) {
lenient() lenient().doReturn(true).when(authorizer).decryptSecret(any(SecurityContext.class));
.doThrow(new AuthorizationException("")) } else if (isLocalSecretManager && isBot) {
.when(authorizer) lenient().doReturn(true).when(authorizer).decryptSecret(any(SecurityContext.class));
.authorizeAdmin(any(SecurityContext.class), eq(true)); } else {
} else if (!isLocalSecretManager && !isAdmin) { lenient().doReturn(false).when(authorizer).decryptSecret(any(SecurityContext.class));
lenient()
.doThrow(new AuthorizationException(""))
.when(authorizer)
.authorizeAdmin(any(SecurityContext.class), eq(false));
} }
R actual = callGetFromResource(serviceResource); R actual = callGetFromResource(serviceResource);
verify(secretsManager, times(1)).isLocal();
verify(secretsManager) verify(secretsManager)
.encryptOrDecryptServiceConnectionConfig( .encryptOrDecryptServiceConnectionConfig(
notNull(), eq(serviceConnectionType()), any(), eq(serviceType()), eq(false)); notNull(), eq(serviceConnectionType()), any(), eq(serviceType()), eq(false));

View File

@ -82,6 +82,7 @@ import org.openmetadata.schema.auth.LoginRequest;
import org.openmetadata.schema.auth.RegistrationRequest; import org.openmetadata.schema.auth.RegistrationRequest;
import org.openmetadata.schema.entity.data.Table; import org.openmetadata.schema.entity.data.Table;
import org.openmetadata.schema.entity.teams.AuthenticationMechanism; import org.openmetadata.schema.entity.teams.AuthenticationMechanism;
import org.openmetadata.schema.entity.teams.AuthenticationMechanism.AuthType;
import org.openmetadata.schema.entity.teams.Role; import org.openmetadata.schema.entity.teams.Role;
import org.openmetadata.schema.entity.teams.Team; import org.openmetadata.schema.entity.teams.Team;
import org.openmetadata.schema.entity.teams.User; import org.openmetadata.schema.entity.teams.User;
@ -90,6 +91,7 @@ import org.openmetadata.schema.teams.authn.GenerateTokenRequest;
import org.openmetadata.schema.teams.authn.JWTAuthMechanism; import org.openmetadata.schema.teams.authn.JWTAuthMechanism;
import org.openmetadata.schema.teams.authn.JWTTokenExpiry; import org.openmetadata.schema.teams.authn.JWTTokenExpiry;
import org.openmetadata.schema.teams.authn.SSOAuthMechanism; import org.openmetadata.schema.teams.authn.SSOAuthMechanism;
import org.openmetadata.schema.teams.authn.SSOAuthMechanism.SsoServiceType;
import org.openmetadata.schema.type.ChangeDescription; import org.openmetadata.schema.type.ChangeDescription;
import org.openmetadata.schema.type.EntityReference; import org.openmetadata.schema.type.EntityReference;
import org.openmetadata.schema.type.ImageList; import org.openmetadata.schema.type.ImageList;
@ -418,12 +420,7 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
} }
private CreateUser createBotUserRequest(TestInfo test, int index) { private CreateUser createBotUserRequest(TestInfo test, int index) {
return createRequest(test, index) return createBotUserRequest(getEntityName(test, index));
.withIsBot(true)
.withAuthenticationMechanism(
new AuthenticationMechanism()
.withAuthType(AuthenticationMechanism.AuthType.JWT)
.withConfig(new JWTAuthMechanism().withJWTTokenExpiry(JWTTokenExpiry.Unlimited)));
} }
@Test @Test
@ -685,21 +682,18 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
@Test @Test
void put_generateToken_bot_user_200_ok(TestInfo test) throws HttpResponseException { void put_generateToken_bot_user_200_ok(TestInfo test) throws HttpResponseException {
User user = AuthenticationMechanism authMechanism =
createEntity(
createRequest(test, 6)
.withName("ingestion-bot-jwt")
.withDisplayName("ingestion-bot-jwt")
.withEmail("ingestion-bot-jwt@email.com")
.withIsBot(true)
.withAuthenticationMechanism(
new AuthenticationMechanism() new AuthenticationMechanism()
.withAuthType(AuthenticationMechanism.AuthType.SSO) .withAuthType(AuthType.SSO)
.withConfig( .withConfig(
new SSOAuthMechanism() new SSOAuthMechanism()
.withSsoServiceType(SSOAuthMechanism.SsoServiceType.GOOGLE) .withSsoServiceType(SsoServiceType.GOOGLE)
.withAuthConfig(new GoogleSSOClientConfig().withSecretKey("/path/to/secret.json")))), .withAuthConfig(new GoogleSSOClientConfig().withSecretKey("/path/to/secret.json")));
authHeaders("ingestion-bot-jwt@email.com")); CreateUser create =
createBotUserRequest("ingestion-bot-jwt")
.withEmail("ingestion-bot-jwt@email.com")
.withAuthenticationMechanism(authMechanism);
User user = createEntity(create, authHeaders("ingestion-bot-jwt@email.com"));
TestUtils.put( TestUtils.put(
getResource(String.format("users/generateToken/%s", user.getId())), getResource(String.format("users/generateToken/%s", user.getId())),
new GenerateTokenRequest().withJWTTokenExpiry(JWTTokenExpiry.Seven), new GenerateTokenRequest().withJWTTokenExpiry(JWTTokenExpiry.Seven),
@ -865,14 +859,14 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
BotResourceTest botResourceTest = new BotResourceTest(); BotResourceTest botResourceTest = new BotResourceTest();
String botName = "test-bot-user-fail"; String botName = "test-bot-user-fail";
// create bot user // create bot user
CreateUser createBotUser = creatBotUserRequest("test-bot-user", true).withBotName(botName); CreateUser createBotUser = createBotUserRequest("test-bot-user").withBotName(botName);
User botUser = updateEntity(createBotUser, CREATED, ADMIN_AUTH_HEADERS); User botUser = updateEntity(createBotUser, CREATED, ADMIN_AUTH_HEADERS);
EntityReference botUserRef = Objects.requireNonNull(botUser).getEntityReference(); EntityReference botUserRef = Objects.requireNonNull(botUser).getEntityReference();
// assign bot user to a bot // assign bot user to a bot
CreateBot create = botResourceTest.createRequest(test).withBotUser(botUserRef).withName(botName); CreateBot create = botResourceTest.createRequest(test).withBotUser(botUserRef).withName(botName);
botResourceTest.createEntity(create, ADMIN_AUTH_HEADERS); botResourceTest.createEntity(create, ADMIN_AUTH_HEADERS);
// put user with a different bot name // put user with a different bot name
CreateUser createWrongBotUser = creatBotUserRequest("test-bot-user", true).withBotName("test-bot-user-fail-2"); CreateUser createWrongBotUser = createBotUserRequest("test-bot-user").withBotName("test-bot-user-fail-2");
assertResponse( assertResponse(
() -> updateEntity(createWrongBotUser, BAD_REQUEST, ADMIN_AUTH_HEADERS), () -> updateEntity(createWrongBotUser, BAD_REQUEST, ADMIN_AUTH_HEADERS),
BAD_REQUEST, BAD_REQUEST,
@ -884,14 +878,14 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
BotResourceTest botResourceTest = new BotResourceTest(); BotResourceTest botResourceTest = new BotResourceTest();
String botName = "test-bot-ok"; String botName = "test-bot-ok";
// create bot user // create bot user
CreateUser createBotUser = creatBotUserRequest("test-bot-user-ok", true).withBotName(botName); CreateUser createBotUser = createBotUserRequest("test-bot-user-ok").withBotName(botName);
User botUser = updateEntity(createBotUser, CREATED, ADMIN_AUTH_HEADERS); User botUser = updateEntity(createBotUser, CREATED, ADMIN_AUTH_HEADERS);
EntityReference botUserRef = Objects.requireNonNull(botUser).getEntityReference(); EntityReference botUserRef = Objects.requireNonNull(botUser).getEntityReference();
// assign bot user to a bot // assign bot user to a bot
CreateBot create = botResourceTest.createRequest(test).withBotUser(botUserRef).withName(botName); CreateBot create = botResourceTest.createRequest(test).withBotUser(botUserRef).withName(botName);
botResourceTest.createEntity(create, ADMIN_AUTH_HEADERS); botResourceTest.createEntity(create, ADMIN_AUTH_HEADERS);
// put again user with same bot name // put again user with same bot name
CreateUser createDifferentBotUser = creatBotUserRequest("test-bot-user-ok", true).withBotName(botName); CreateUser createDifferentBotUser = createBotUserRequest("test-bot-user-ok").withBotName(botName);
updateEntity(createDifferentBotUser, OK, ADMIN_AUTH_HEADERS); updateEntity(createDifferentBotUser, OK, ADMIN_AUTH_HEADERS);
assertNotNull(createDifferentBotUser); assertNotNull(createDifferentBotUser);
} }
@ -1044,19 +1038,18 @@ public class UserResourceTest extends EntityResourceTest<User, CreateUser> {
return String.join(",", allowedFields); return String.join(",", allowedFields);
} }
public User createUser(String botName, boolean isBot) { public User createUser(String userName, boolean isBot) {
try { try {
CreateUser createUser = creatBotUserRequest(botName, isBot); CreateUser createUser = createBotUserRequest(userName).withIsBot(isBot);
return createEntity(createUser, ADMIN_AUTH_HEADERS); return createEntity(createUser, ADMIN_AUTH_HEADERS);
} catch (Exception ignore) { } catch (Exception ignore) {
return null; return null;
} }
} }
private CreateUser creatBotUserRequest(String botUserName, boolean isBot) { private CreateUser createBotUserRequest(String botUserName) {
return createRequest(botUserName, "", "", null) return createRequest(botUserName, "", "", null)
.withIsBot(isBot) .withIsBot(true)
.withIsAdmin(false)
.withAuthenticationMechanism( .withAuthenticationMechanism(
new AuthenticationMechanism() new AuthenticationMechanism()
.withAuthType(AuthenticationMechanism.AuthType.JWT) .withAuthType(AuthenticationMechanism.AuthType.JWT)