feat(logging): unified request logging (graphql, openapi, restli) (#10802)

This commit is contained in:
david-leifker 2024-06-29 02:50:10 -05:00 committed by GitHub
parent a35089048a
commit b4e05050d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 320 additions and 103 deletions

View File

@ -7,6 +7,8 @@ dependencies {
api project(':metadata-auth:auth-api')
implementation externalDependency.slf4jApi
implementation externalDependency.servletApi
implementation spec.product.pegasus.restliServer
compileOnly externalDependency.lombok
annotationProcessor externalDependency.lombok

View File

@ -1,5 +1,8 @@
package io.datahubproject.metadata.context;
import com.google.common.net.HttpHeaders;
import com.linkedin.restli.server.ResourceContext;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@ -11,7 +14,9 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Getter
@Builder
public class RequestContext implements ContextInterface {
@ -19,6 +24,8 @@ public class RequestContext implements ContextInterface {
public static final RequestContext TEST =
RequestContext.builder().requestID("test").requestAPI(RequestAPI.TEST).build();
@Nonnull private final String actorUrn;
@Nonnull private final String sourceIP;
@Nonnull private final RequestAPI requestAPI;
/**
@ -27,6 +34,23 @@ public class RequestContext implements ContextInterface {
*/
@Nonnull private final String requestID;
@Nonnull private final String userAgent;
public RequestContext(
@Nonnull String actorUrn,
@Nonnull String sourceIP,
@Nonnull RequestAPI requestAPI,
@Nonnull String requestID,
@Nonnull String userAgent) {
this.actorUrn = actorUrn;
this.sourceIP = sourceIP;
this.requestAPI = requestAPI;
this.requestID = requestID;
this.userAgent = userAgent;
// Uniform common logging of requests across APIs
log.info(toString());
}
@Override
public Optional<Integer> getCacheKeyComponent() {
return Optional.empty();
@ -34,39 +58,76 @@ public class RequestContext implements ContextInterface {
public static class RequestContextBuilder {
private RequestContext build() {
return new RequestContext(this.requestAPI, this.requestID);
return new RequestContext(
this.actorUrn, this.sourceIP, this.requestAPI, this.requestID, this.userAgent);
}
public RequestContext buildGraphql(@Nonnull String queryName, Map<String, Object> variables) {
public RequestContext buildGraphql(
@Nonnull String actorUrn,
@Nonnull HttpServletRequest request,
@Nonnull String queryName,
Map<String, Object> variables) {
actorUrn(actorUrn);
sourceIP(extractSourceIP(request));
requestAPI(RequestAPI.GRAPHQL);
requestID(buildRequestId(queryName, Set.of()));
userAgent(extractUserAgent(request));
return build();
}
public RequestContext buildRestli(String action, @Nullable String entityName) {
return buildRestli(action, entityName == null ? null : List.of(entityName));
public RequestContext buildRestli(
@Nonnull String actorUrn,
@Nullable ResourceContext resourceContext,
String action,
@Nullable String entityName) {
return buildRestli(
actorUrn, resourceContext, action, entityName == null ? null : List.of(entityName));
}
public RequestContext buildRestli(@Nonnull String action, @Nullable String[] entityNames) {
public RequestContext buildRestli(
@Nonnull String actorUrn,
@Nullable ResourceContext resourceContext,
@Nonnull String action,
@Nullable String[] entityNames) {
return buildRestli(
actorUrn,
resourceContext,
action,
entityNames == null ? null : Arrays.stream(entityNames).collect(Collectors.toList()));
}
public RequestContext buildRestli(String action, @Nullable Collection<String> entityNames) {
public RequestContext buildRestli(
@Nonnull String actorUrn,
@Nullable ResourceContext resourceContext,
String action,
@Nullable Collection<String> entityNames) {
actorUrn(actorUrn);
sourceIP(resourceContext == null ? "" : extractSourceIP(resourceContext));
requestAPI(RequestAPI.RESTLI);
requestID(buildRequestId(action, entityNames));
userAgent(resourceContext == null ? "" : extractUserAgent(resourceContext));
return build();
}
public RequestContext buildOpenapi(@Nonnull String action, @Nullable String entityName) {
return buildOpenapi(action, entityName == null ? null : List.of(entityName));
public RequestContext buildOpenapi(
@Nonnull String actorUrn,
@Nonnull HttpServletRequest request,
@Nonnull String action,
@Nullable String entityName) {
return buildOpenapi(
actorUrn, request, action, entityName == null ? null : List.of(entityName));
}
public RequestContext buildOpenapi(
@Nonnull String action, @Nullable Collection<String> entityNames) {
@Nonnull String actorUrn,
@Nullable HttpServletRequest request,
@Nonnull String action,
@Nullable Collection<String> entityNames) {
actorUrn(actorUrn);
sourceIP(request == null ? "" : extractSourceIP(request));
requestAPI(RequestAPI.OPENAPI);
requestID(buildRequestId(action, entityNames));
userAgent(request == null ? "" : extractUserAgent(request));
return build();
}
@ -77,6 +138,46 @@ public class RequestContext implements ContextInterface {
: String.format(
"%s(%s)", action, entityNames.stream().distinct().collect(Collectors.toList()));
}
private static String extractUserAgent(@Nonnull HttpServletRequest request) {
return Optional.ofNullable(request.getHeader(HttpHeaders.USER_AGENT)).orElse("");
}
private static String extractUserAgent(@Nonnull ResourceContext resourceContext) {
return Optional.ofNullable(resourceContext.getRequestHeaders().get(HttpHeaders.USER_AGENT))
.orElse("");
}
private static String extractSourceIP(@Nonnull HttpServletRequest request) {
return Optional.ofNullable(request.getHeader(HttpHeaders.X_FORWARDED_FOR))
.orElse(request.getRemoteAddr());
}
private static String extractSourceIP(@Nonnull ResourceContext resourceContext) {
return Optional.ofNullable(
resourceContext.getRequestHeaders().get(HttpHeaders.X_FORWARDED_FOR))
.orElse(resourceContext.getRawRequestContext().getLocalAttr("REMOTE_ADDR").toString());
}
}
@Override
public String toString() {
return "RequestContext{"
+ "actorUrn='"
+ actorUrn
+ '\''
+ ", sourceIP='"
+ sourceIP
+ '\''
+ ", requestAPI="
+ requestAPI
+ ", requestID='"
+ requestID
+ '\''
+ ", userAgent='"
+ userAgent
+ '\''
+ '}';
}
public enum RequestAPI {

View File

@ -59,7 +59,8 @@ public class GraphQLController {
private static final int MAX_LOG_WIDTH = 512;
@PostMapping(value = "/graphql", produces = "application/json;charset=utf-8")
CompletableFuture<ResponseEntity<String>> postGraphQL(HttpEntity<String> httpEntity) {
CompletableFuture<ResponseEntity<String>> postGraphQL(
HttpServletRequest request, HttpEntity<String> httpEntity) {
String jsonStr = httpEntity.getBody();
ObjectMapper mapper = new ObjectMapper();
@ -117,13 +118,18 @@ public class GraphQLController {
SpringQueryContext context =
new SpringQueryContext(
true, authentication, _authorizerChain, systemOperationContext, query, variables);
true,
authentication,
_authorizerChain,
systemOperationContext,
request,
operationName,
query,
variables);
Span.current().setAttribute("actor.urn", context.getActorUrn());
// operationName is an optional field only required if multiple operations are present
final String queryName = operationName != null ? operationName : context.getQueryName();
final String threadName = Thread.currentThread().getName();
log.info("Processing request, operation: {}, actor urn: {}", queryName, context.getActorUrn());
final String queryName = context.getQueryName();
log.debug("Query: {}, variables: {}", query, variables);
return GraphQLConcurrencyUtils.supplyAsync(

View File

@ -7,8 +7,10 @@ import graphql.language.OperationDefinition;
import graphql.parser.Parser;
import io.datahubproject.metadata.context.OperationContext;
import io.datahubproject.metadata.context.RequestContext;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Getter;
@Getter
@ -25,26 +27,33 @@ public class SpringQueryContext implements QueryContext {
final Authentication authentication,
final Authorizer authorizer,
@Nonnull final OperationContext systemOperationContext,
@Nonnull final HttpServletRequest request,
@Nullable final String operationName,
String jsonQuery,
Map<String, Object> variables) {
this.isAuthenticated = isAuthenticated;
this.authentication = authentication;
this.authorizer = authorizer;
// operationName is an optional field only required if multiple operations are present
this.queryName =
new Parser()
.parseDocument(jsonQuery).getDefinitions().stream()
.filter(def -> def instanceof OperationDefinition)
.map(def -> (OperationDefinition) def)
.filter(opDef -> opDef.getOperation().equals(OperationDefinition.Operation.QUERY))
.findFirst()
.map(OperationDefinition::getName)
.orElse("graphql");
operationName != null
? operationName
: new Parser()
.parseDocument(jsonQuery).getDefinitions().stream()
.filter(def -> def instanceof OperationDefinition)
.map(def -> (OperationDefinition) def)
.filter(
opDef -> opDef.getOperation().equals(OperationDefinition.Operation.QUERY))
.findFirst()
.map(OperationDefinition::getName)
.orElse("graphql");
this.operationContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildGraphql(queryName, variables),
RequestContext.builder()
.buildGraphql(authentication.getActor().toUrnStr(), request, queryName, variables),
authorizer,
authentication,
true);

View File

@ -19,7 +19,7 @@ dependencies {
implementation externalDependency.springWebMVC
implementation externalDependency.springBeans
implementation externalDependency.springContext
implementation externalDependency.servletApi
implementation externalDependency.reflections
implementation externalDependency.slf4jApi
compileOnly externalDependency.lombok

View File

@ -12,6 +12,7 @@ import io.datahubproject.metadata.context.OperationContext;
import io.datahubproject.metadata.context.RequestContext;
import io.datahubproject.openapi.exception.UnauthorizedException;
import io.datahubproject.openapi.v2.generated.controller.DatahubUsageEventsApiDelegate;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
@ -27,6 +28,8 @@ public class DatahubUsageEventsImpl implements DatahubUsageEventsApiDelegate {
@Qualifier("systemOperationContext")
OperationContext systemOperationContext;
@Autowired private HttpServletRequest request;
public static final String DATAHUB_USAGE_INDEX = "datahub_usage_event";
@Override
@ -36,7 +39,8 @@ public class DatahubUsageEventsImpl implements DatahubUsageEventsApiDelegate {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("raw", List.of()),
RequestContext.builder()
.buildOpenapi(authentication.getActor().toUrnStr(), request, "raw", List.of()),
_authorizationChain,
authentication,
true);

View File

@ -59,6 +59,7 @@ import io.datahubproject.openapi.generated.StatusAspectRequestV2;
import io.datahubproject.openapi.generated.StatusAspectResponseV2;
import io.datahubproject.openapi.util.OpenApiEntitiesUtil;
import io.datahubproject.openapi.v1.entities.EntitiesController;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
@ -85,6 +86,7 @@ public class EntityApiDelegateImpl<I, O, S> {
private final Class<I> _reqClazz;
private final Class<O> _respClazz;
private final Class<S> _scrollRespClazz;
private final HttpServletRequest request;
private static final String BUSINESS_ATTRIBUTE_ERROR_MESSAGE =
"business attribute is disabled, enable it using featureflag : BUSINESS_ATTRIBUTE_ENTITY_ENABLED";
@ -92,6 +94,7 @@ public class EntityApiDelegateImpl<I, O, S> {
public EntityApiDelegateImpl(
OperationContext systemOperationContext,
HttpServletRequest request,
EntityService<?> entityService,
SearchService searchService,
EntitiesController entitiesController,
@ -100,6 +103,7 @@ public class EntityApiDelegateImpl<I, O, S> {
Class<O> respClazz,
Class<S> scrollRespClazz) {
this.systemOperationContext = systemOperationContext;
this.request = request;
this._entityService = entityService;
this._searchService = searchService;
this._entityRegistry = systemOperationContext.getEntityRegistry();
@ -119,7 +123,7 @@ public class EntityApiDelegateImpl<I, O, S> {
.map(asp -> asp.stream().distinct().toArray(String[]::new))
.orElse(null);
ResponseEntity<UrnResponseMap> result =
_v1Controller.getEntities(new String[] {urn}, requestedAspects);
_v1Controller.getEntities(request, new String[] {urn}, requestedAspects);
return ResponseEntity.of(
OpenApiEntitiesUtil.convertEntity(
Optional.ofNullable(result).map(HttpEntity::getBody).orElse(null),
@ -146,7 +150,7 @@ public class EntityApiDelegateImpl<I, O, S> {
throw new UnsupportedOperationException(BUSINESS_ATTRIBUTE_ERROR_MESSAGE);
}
}
_v1Controller.postEntities(aspects, false, createIfNotExists, createEntityIfNotExists);
_v1Controller.postEntities(request, aspects, false, createIfNotExists, createEntityIfNotExists);
List<O> responses =
body.stream()
.map(req -> OpenApiEntitiesUtil.convertToResponse(req, _respClazz, _entityRegistry))
@ -158,7 +162,7 @@ public class EntityApiDelegateImpl<I, O, S> {
if (checkBusinessAttributeFlagFromUrn(urn)) {
throw new UnsupportedOperationException(BUSINESS_ATTRIBUTE_ERROR_MESSAGE);
}
_v1Controller.deleteEntities(new String[] {urn}, false, false);
_v1Controller.deleteEntities(request, new String[] {urn}, false, false);
return new ResponseEntity<>(HttpStatus.OK);
}
@ -177,7 +181,9 @@ public class EntityApiDelegateImpl<I, O, S> {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("head", entityUrn.getEntityType()),
RequestContext.builder()
.buildOpenapi(
auth.getActor().toUrnStr(), request, "head", entityUrn.getEntityType()),
_authorizationChain,
auth,
true);
@ -200,7 +206,7 @@ public class EntityApiDelegateImpl<I, O, S> {
Class<A> aspectRespClazz) {
String[] requestedAspects = new String[] {aspect};
ResponseEntity<UrnResponseMap> result =
_v1Controller.getEntities(new String[] {urn}, requestedAspects);
_v1Controller.getEntities(request, new String[] {urn}, requestedAspects);
return ResponseEntity.of(
OpenApiEntitiesUtil.convertAspect(
result.getBody(), aspect, entityRespClass, aspectRespClazz, systemMetadata));
@ -217,6 +223,7 @@ public class EntityApiDelegateImpl<I, O, S> {
UpsertAspectRequest aspectUpsert =
OpenApiEntitiesUtil.convertAspectToUpsert(urn, body, reqClazz);
_v1Controller.postEntities(
request,
Stream.of(aspectUpsert).filter(Objects::nonNull).collect(Collectors.toList()),
false,
createIfNotExists,
@ -238,7 +245,9 @@ public class EntityApiDelegateImpl<I, O, S> {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("headAspect", entityUrn.getEntityType()),
RequestContext.builder()
.buildOpenapi(
auth.getActor().toUrnStr(), request, "headAspect", entityUrn.getEntityType()),
_authorizationChain,
auth,
true);
@ -259,12 +268,14 @@ public class EntityApiDelegateImpl<I, O, S> {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("deleteAspect", entityUrn.getEntityType()),
RequestContext.builder()
.buildOpenapi(
auth.getActor().toUrnStr(), request, "deleteAspect", entityUrn.getEntityType()),
_authorizationChain,
auth,
true);
_entityService.deleteAspect(opContext, urn, aspect, Map.of(), false);
_v1Controller.deleteEntities(new String[] {urn}, false, false);
_v1Controller.deleteEntities(request, new String[] {urn}, false, false);
return new ResponseEntity<>(HttpStatus.OK);
}
@ -606,7 +617,9 @@ public class EntityApiDelegateImpl<I, O, S> {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("scroll", entitySpec.getName()),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "scroll", entitySpec.getName()),
_authorizationChain,
authentication,
true);
@ -644,7 +657,7 @@ public class EntityApiDelegateImpl<I, O, S> {
.map(asp -> asp.stream().distinct().toArray(String[]::new))
.orElse(null);
List<O> entities =
Optional.ofNullable(_v1Controller.getEntities(urns, requestedAspects).getBody())
Optional.ofNullable(_v1Controller.getEntities(request, urns, requestedAspects).getBody())
.map(body -> body.getResponses().entrySet())
.map(
entries -> OpenApiEntitiesUtil.convertEntities(entries, _respClazz, systemMetadata))

View File

@ -98,7 +98,7 @@ public class {{classname}}Controller implements {{classname}} {
SearchService searchService, EntitiesController v1Controller, AuthorizerChain authorizationChain) {
this.objectMapper = objectMapper;
this.request = request;
this.delegate = new EntityApiDelegateImpl<{{requestClass}}, {{responseClass}}, {{scrollResponseClass}}>(systemOperationContext, entityService, searchService, v1Controller,
this.delegate = new EntityApiDelegateImpl<{{requestClass}}, {{responseClass}}, {{scrollResponseClass}}>(systemOperationContext, request, entityService, searchService, v1Controller,
authorizationChain, {{requestClass}}.class, {{responseClass}}.class, {{scrollResponseClass}}.class);
}
{{#isJava8or11}}

View File

@ -3,6 +3,7 @@ package io.datahubproject.openapi.config;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -33,6 +34,7 @@ import io.datahubproject.openapi.v1.entities.EntitiesController;
import io.datahubproject.openapi.v1.relationships.RelationshipsController;
import io.datahubproject.openapi.v2.controller.TimelineControllerV2;
import io.datahubproject.test.metadata.context.TestOperationContexts;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
@ -109,11 +111,11 @@ public class OpenAPIEntityTestConfiguration {
@Primary
public EntitiesController entitiesController() {
EntitiesController entitiesController = mock(EntitiesController.class);
when(entitiesController.getEntities(any(), any()))
when(entitiesController.getEntities(nullable(HttpServletRequest.class), any(), any()))
.thenAnswer(
params -> {
String[] urns = params.getArgument(0);
String[] aspects = params.getArgument(1);
String[] urns = params.getArgument(1);
String[] aspects = params.getArgument(2);
return ResponseEntity.ok(
UrnResponseMap.builder()
.responses(

View File

@ -21,6 +21,7 @@ dependencies {
implementation externalDependency.springWebMVC
implementation externalDependency.springBeans
implementation externalDependency.springContext
implementation externalDependency.servletApi
implementation externalDependency.slf4jApi
compileOnly externalDependency.lombok
implementation externalDependency.antlr4Runtime

View File

@ -52,6 +52,7 @@ import io.datahubproject.openapi.models.GenericEntity;
import io.datahubproject.openapi.models.GenericEntityScrollResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
@ -133,6 +134,7 @@ public abstract class GenericEntitiesController<
@GetMapping(value = "/{entityName}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Scroll entities")
public ResponseEntity<S> getEntities(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@RequestParam(value = "aspectNames", defaultValue = "") Set<String> aspects1,
@RequestParam(value = "aspects", defaultValue = "") Set<String> aspects2,
@ -159,7 +161,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("getEntities", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "getEntities", entityName),
authorizationChain,
authentication,
true);
@ -199,6 +203,7 @@ public abstract class GenericEntitiesController<
value = "/{entityName}/{entityUrn:urn:li:.+}",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<E> getEntity(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@RequestParam(value = "aspectNames", defaultValue = "") Set<String> aspects1,
@ -217,7 +222,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("getEntity", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "getEntity", entityName),
authorizationChain,
authentication,
true);
@ -239,6 +246,7 @@ public abstract class GenericEntitiesController<
method = {RequestMethod.HEAD})
@Operation(summary = "Entity exists")
public ResponseEntity<Object> headEntity(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable(value = "includeSoftDelete", required = false) Boolean includeSoftDelete)
@ -254,7 +262,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("headEntity", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "headEntity", entityName),
authorizationChain,
authentication,
true);
@ -270,6 +280,7 @@ public abstract class GenericEntitiesController<
produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Get an entity's generic aspect.")
public ResponseEntity<Object> getAspect(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable("aspectName") String aspectName,
@ -287,7 +298,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("getAspect", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "getAspect", entityName),
authorizationChain,
authentication,
true);
@ -311,6 +324,7 @@ public abstract class GenericEntitiesController<
method = {RequestMethod.HEAD})
@Operation(summary = "Whether an entity aspect exists.")
public ResponseEntity<Object> headAspect(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable("aspectName") String aspectName,
@ -327,7 +341,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("headAspect", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "headAspect", entityName),
authorizationChain,
authentication,
true);
@ -341,7 +357,9 @@ public abstract class GenericEntitiesController<
@DeleteMapping(value = "/{entityName}/{entityUrn:urn:li:.+}")
@Operation(summary = "Delete an entity")
public void deleteEntity(
@PathVariable("entityName") String entityName, @PathVariable("entityUrn") String entityUrn)
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn)
throws InvalidUrnException {
EntitySpec entitySpec = entityRegistry.getEntitySpec(entityName);
@ -355,7 +373,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("deleteEntity", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "deleteEntity", entityName),
authorizationChain,
authentication,
true);
@ -367,6 +387,7 @@ public abstract class GenericEntitiesController<
@PostMapping(value = "/{entityName}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Create a batch of entities.")
public ResponseEntity<List<E>> createEntity(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@RequestParam(value = "async", required = false, defaultValue = "true") Boolean async,
@RequestParam(value = "systemMetadata", required = false, defaultValue = "false")
@ -385,7 +406,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("createEntity", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "createEntity", entityName),
authorizationChain,
authentication,
true);
@ -404,6 +427,7 @@ public abstract class GenericEntitiesController<
@DeleteMapping(value = "/{entityName}/{entityUrn:urn:li:.+}/{aspectName}")
@Operation(summary = "Delete an entity aspect.")
public void deleteAspect(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable("aspectName") String aspectName)
@ -419,7 +443,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("deleteAspect", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "deleteAspect", entityName),
authorizationChain,
authentication,
true);
@ -434,6 +460,7 @@ public abstract class GenericEntitiesController<
produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Create an entity aspect.")
public ResponseEntity<E> createAspect(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable("aspectName") String aspectName,
@ -456,7 +483,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("createAspect", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "createAspect", entityName),
authorizationChain,
authentication,
true);
@ -494,6 +523,7 @@ public abstract class GenericEntitiesController<
produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Patch an entity aspect. (Experimental)")
public ResponseEntity<E> patchAspect(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("entityUrn") String entityUrn,
@PathVariable("aspectName") String aspectName,
@ -517,7 +547,9 @@ public abstract class GenericEntitiesController<
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("patchAspect", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "patchAspect", entityName),
authorizationChain,
authentication,
true);

View File

@ -14,6 +14,7 @@ import io.datahubproject.openapi.openlineage.mapping.RunEventMapper;
import io.datahubproject.openlineage.generated.controller.LineageApi;
import io.openlineage.client.OpenLineage;
import io.openlineage.client.OpenLineageClientUtils;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@ -50,6 +51,8 @@ public class LineageApiImpl implements LineageApi {
return Optional.of(OBJECT_MAPPER);
}
@Autowired private HttpServletRequest request;
@Override
public ResponseEntity<Void> postRunEventRaw(String body) {
try {
@ -68,7 +71,9 @@ public class LineageApiImpl implements LineageApi {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("postRunEventRaw", List.of()),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "postRunEventRaw", List.of()),
_authorizerChain,
authentication,
true);

View File

@ -31,6 +31,7 @@ import io.datahubproject.openapi.util.ElasticsearchUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@ -133,7 +134,7 @@ public class OperationsController {
@Tag(name = "ElasticSearchOperations")
@GetMapping(path = "/getIndexSizes", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Get Index Sizes")
public ResponseEntity<String> getIndexSizes() {
public ResponseEntity<String> getIndexSizes(HttpServletRequest request) {
Authentication authentication = AuthenticationContext.getAuthentication();
String actorUrnStr = authentication.getActor().toUrnStr();
@ -145,7 +146,7 @@ public class OperationsController {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("getIndexSizes", List.of()),
RequestContext.builder().buildOpenapi(actorUrnStr, request, "getIndexSizes", List.of()),
authorizerChain,
authentication,
true);
@ -171,6 +172,7 @@ public class OperationsController {
@GetMapping(path = "/explainSearchQuery", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Explain Search Query")
public ResponseEntity<ExplainResponse> explainSearchQuery(
HttpServletRequest request,
@Parameter(
name = "query",
required = true,
@ -229,7 +231,8 @@ public class OperationsController {
OperationContext opContext =
systemOperationContext
.asSession(
RequestContext.builder().buildOpenapi("explainSearchQuery", entityName),
RequestContext.builder()
.buildOpenapi(actorUrnStr, request, "explainSearchQuery", entityName),
authorizerChain,
authentication)
.withSearchFlags(
@ -263,6 +266,7 @@ public class OperationsController {
@GetMapping(path = "/explainSearchQueryDiff", produces = MediaType.TEXT_PLAIN_VALUE)
@Operation(summary = "Explain the differences in scoring for 2 documents")
public ResponseEntity<String> explainSearchQueryDiff(
HttpServletRequest request,
@Parameter(
name = "query",
required = true,
@ -328,7 +332,8 @@ public class OperationsController {
OperationContext opContext =
systemOperationContext
.asSession(
RequestContext.builder().buildOpenapi("explainSearchQuery", entityName),
RequestContext.builder()
.buildOpenapi(actorUrnStr, request, "explainSearchQuery", entityName),
authorizerChain,
authentication)
.withSearchFlags(
@ -400,6 +405,7 @@ public class OperationsController {
@GetMapping(path = "/restoreIndices", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Restore ElasticSearch indices from primary storage based on URNs.")
public ResponseEntity<List<RestoreIndicesResult>> restoreIndices(
HttpServletRequest request,
@RequestParam(required = false, name = "aspectName") @Nullable String aspectName,
@RequestParam(required = false, name = "urn") @Nullable String urn,
@RequestParam(required = false, name = "urnLike") @Nullable String urnLike,
@ -419,7 +425,9 @@ public class OperationsController {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("restoreIndices", List.of()),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "restoreIndices", List.of()),
authorizerChain,
authentication,
true);
@ -445,6 +453,7 @@ public class OperationsController {
@PostMapping(path = "/restoreIndices", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Restore ElasticSearch indices from primary storage based on URNs.")
public ResponseEntity<List<RestoreIndicesResult>> restoreIndices(
HttpServletRequest request,
@RequestParam(required = false, name = "aspectNames") @Nullable Set<String> aspectNames,
@RequestParam(required = false, name = "batchSize", defaultValue = "100") @Nullable
Integer batchSize,
@ -459,7 +468,9 @@ public class OperationsController {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("restoreIndices", List.of()),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "restoreIndices", List.of()),
authorizerChain,
authentication,
true);

View File

@ -30,6 +30,7 @@ import io.datahubproject.openapi.generated.AspectRowSummary;
import io.datahubproject.openapi.util.MappingUtil;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Collections;
@ -90,6 +91,7 @@ public class EntitiesController {
@GetMapping(value = "/latest", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UrnResponseMap> getEntities(
HttpServletRequest request,
@Parameter(
name = "urns",
required = true,
@ -122,6 +124,8 @@ public class EntitiesController {
systemOperationContext,
RequestContext.builder()
.buildOpenapi(
actorUrnStr,
request,
"getEntities",
entityUrns.stream()
.map(Urn::getEntityType)
@ -169,6 +173,7 @@ public class EntitiesController {
@PostMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<String>> postEntities(
HttpServletRequest request,
@RequestBody @Nonnull List<UpsertAspectRequest> aspectRequests,
@RequestParam(required = false, name = "async") Boolean async,
@RequestParam(required = false, name = "createIfNotExists") Boolean createIfNotExists,
@ -191,6 +196,8 @@ public class EntitiesController {
systemOperationContext,
RequestContext.builder()
.buildOpenapi(
actorUrnStr,
request,
"postEntities",
proposals.stream()
.map(MetadataChangeProposal::getEntityType)
@ -241,6 +248,7 @@ public class EntitiesController {
@DeleteMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<RollbackRunResultDto>> deleteEntities(
HttpServletRequest request,
@Parameter(
name = "urns",
required = true,
@ -278,6 +286,8 @@ public class EntitiesController {
systemOperationContext,
RequestContext.builder()
.buildOpenapi(
actorUrnStr,
request,
"deleteEntities",
entityUrns.stream().map(Urn::getEntityType).collect(Collectors.toSet())),
_authorizerChain,

View File

@ -38,6 +38,7 @@ import io.datahubproject.openapi.v2.models.GenericEntityScrollResultV2;
import io.datahubproject.openapi.v2.models.GenericEntityV2;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@ -87,7 +88,9 @@ public class EntityController
@PostMapping(value = "/batch/{entityName}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Get a batch of entities")
public ResponseEntity<BatchGetUrnResponse> getEntityBatch(
@PathVariable("entityName") String entityName, @RequestBody BatchGetUrnRequest request)
HttpServletRequest httpServletRequest,
@PathVariable("entityName") String entityName,
@RequestBody BatchGetUrnRequest request)
throws URISyntaxException {
List<Urn> urns = request.getUrns().stream().map(UrnUtils::getUrn).collect(Collectors.toList());
@ -100,7 +103,12 @@ public class EntityController
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("getEntityBatch", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(),
httpServletRequest,
"getEntityBatch",
entityName),
authorizationChain,
authentication,
true);

View File

@ -17,6 +17,7 @@ import io.datahubproject.openapi.exception.UnauthorizedException;
import io.datahubproject.openapi.generated.MetadataChangeProposal;
import io.datahubproject.openapi.util.MappingUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@ -58,6 +59,7 @@ public class PlatformEntitiesController {
@PostMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<String>> postEntities(
HttpServletRequest request,
@RequestBody @Nonnull List<MetadataChangeProposal> metadataChangeProposals,
@RequestParam(required = false, name = "async") Boolean async) {
log.info("INGEST PROPOSAL proposal: {}", metadataChangeProposals);
@ -69,6 +71,8 @@ public class PlatformEntitiesController {
systemOperationContext,
RequestContext.builder()
.buildOpenapi(
actorUrnStr,
request,
"postEntities",
metadataChangeProposals.stream()
.map(MetadataChangeProposal::getEntityType)

View File

@ -22,6 +22,7 @@ import io.datahubproject.openapi.exception.UnauthorizedException;
import io.datahubproject.openapi.models.GenericScrollResult;
import io.datahubproject.openapi.v2.models.GenericTimeseriesAspect;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.util.List;
import java.util.stream.Collectors;
@ -56,6 +57,7 @@ public class TimeseriesController {
@GetMapping(value = "/{entityName}/{aspectName}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<GenericScrollResult<GenericTimeseriesAspect>> getAspects(
HttpServletRequest request,
@PathVariable("entityName") String entityName,
@PathVariable("aspectName") String aspectName,
@RequestParam(value = "count", defaultValue = "10") Integer count,
@ -76,7 +78,9 @@ public class TimeseriesController {
OperationContext opContext =
OperationContext.asSession(
systemOperationContext,
RequestContext.builder().buildOpenapi("getAspects", entityName),
RequestContext.builder()
.buildOpenapi(
authentication.getActor().toUrnStr(), request, "getAspects", entityName),
authorizationChain,
authentication,
true);

View File

@ -214,7 +214,7 @@ public class EntitiesControllerTest {
.build();
datasetAspects.add(glossaryTerms);
_entitiesController.postEntities(datasetAspects, false, false, false);
_entitiesController.postEntities(null, datasetAspects, false, false, false);
}
// @Test

View File

@ -14,6 +14,7 @@ import com.linkedin.restli.common.HttpStatus;
import com.linkedin.restli.server.RestLiServiceException;
import com.linkedin.restli.server.annotations.Action;
import com.linkedin.restli.server.annotations.ActionParam;
import com.linkedin.restli.server.annotations.Context;
import com.linkedin.restli.server.annotations.Optional;
import com.linkedin.restli.server.annotations.RestLiSimpleResource;
import com.linkedin.restli.server.resources.SimpleResourceTemplate;
@ -28,6 +29,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import io.datahubproject.metadata.context.OperationContext;
import io.datahubproject.metadata.context.RequestContext;
@ -80,7 +82,8 @@ public class Analytics extends SimpleResourceTemplate<GetTimeseriesAggregatedSta
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entity " + entityName);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_GET_TIMESERIES_STATS, entityName), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(),
ACTION_GET_TIMESERIES_STATS, entityName), authorizer, auth, true);
log.info("Attempting to query timeseries stats");
GetTimeseriesAggregatedStatsResponse resp = new GetTimeseriesAggregatedStatsResponse();

View File

@ -148,7 +148,7 @@ public class AspectResource extends CollectionResourceTaskTemplate<String, Versi
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get aspect for " + urn);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("authorizerChain", urn.getEntityType()), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "authorizerChain", urn.getEntityType()), _authorizer, auth, true);
final VersionedAspect aspect =
_entityService.getVersionedAspect(opContext, urn, aspectName, version);
@ -199,7 +199,7 @@ public class AspectResource extends CollectionResourceTaskTemplate<String, Versi
"User is unauthorized to get timeseries aspect for " + urn);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_GET_TIMESERIES_ASPECT, urn.getEntityType()), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_GET_TIMESERIES_ASPECT, urn.getEntityType()), _authorizer, auth, true);
GetTimeseriesAspectValuesResponse response = new GetTimeseriesAspectValuesResponse();
response.setEntityName(entityName);
@ -280,7 +280,7 @@ public class AspectResource extends CollectionResourceTaskTemplate<String, Versi
.map(MetadataChangeProposal::getEntityType)
.collect(Collectors.toSet());
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_INGEST_PROPOSAL, entityTypes), _authorizer, authentication, true);
systemOperationContext, RequestContext.builder().buildRestli(authentication.getActor().toUrnStr(), getContext(), ACTION_INGEST_PROPOSAL, entityTypes), _authorizer, authentication, true);
// Ingest Authorization Checks
List<Pair<MetadataChangeProposal, Integer>> exceptions = isAPIAuthorized(authentication, _authorizer, ENTITY,
@ -344,7 +344,7 @@ public class AspectResource extends CollectionResourceTaskTemplate<String, Versi
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get aspect counts.");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_GET_COUNT, List.of()), _authorizer, authentication, true);
systemOperationContext, RequestContext.builder().buildRestli(authentication.getActor().toUrnStr(), getContext(), ACTION_GET_COUNT, List.of()), _authorizer, authentication, true);
return _entityService.getCountAspect(opContext, aspectName, urnLike);
},
@ -373,7 +373,7 @@ public class AspectResource extends CollectionResourceTaskTemplate<String, Versi
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to update entities.");
}
return Utils.restoreIndices(systemOperationContext,
return Utils.restoreIndices(systemOperationContext, getContext(),
aspectName, urn, urnLike, start, batchSize, limit, gePitEpochMs, lePitEpochMs, _authorizer, _entityService);
},
MetricRegistry.name(this.getClass(), "restoreIndices"));

View File

@ -95,7 +95,7 @@ public class BatchIngestionRunResource
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to update entity");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("rollback", List.of()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "rollback", List.of()), authorizer, auth, true);
log.info("ROLLBACK RUN runId: {} dry run: {}", runId, dryRun);
@ -171,7 +171,7 @@ public class BatchIngestionRunResource
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entity");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("describe", List.of()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "describe", List.of()), authorizer, auth, true);
List<AspectRowSummary> summaries =
systemMetadataService.findByRunId(

View File

@ -200,7 +200,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entity " + urn);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("restrictedService", urn.getEntityType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "restrictedService", urn.getEntityType()), authorizer, auth, true);
return RestliUtil.toTask(
() -> {
@ -240,7 +240,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entities: " + urnStrs);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("batchGet", urnStrs), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "batchGet", urnStrs), authorizer, auth, true);
return RestliUtil.toTask(
() -> {
@ -289,7 +289,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to edit entity " + urn);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_INGEST, urn.getEntityType()), authorizer, authentication, true);
systemOperationContext, RequestContext.builder().buildRestli(authentication.getActor().toUrnStr(), getContext(), ACTION_INGEST, urn.getEntityType()), authorizer, authentication, true);
try {
validateOrThrow(entity);
@ -334,7 +334,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to edit entities.");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_BATCH_INGEST, urns.stream()
systemOperationContext, RequestContext.builder().buildRestli(authentication.getActor().toUrnStr(), getContext(), ACTION_BATCH_INGEST, urns.stream()
.map(Urn::getEntityType).collect(Collectors.toList())), authorizer, authentication, true);
for (Entity entity : entities) {
@ -394,7 +394,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
}
OperationContext opContext = OperationContext.asSession(systemOperationContext,
RequestContext.builder().buildRestli(ACTION_SEARCH, entityName), authorizer, auth, true)
RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_SEARCH, entityName), authorizer, auth, true)
.withSearchFlags(flags -> searchFlags != null ? searchFlags : new SearchFlags().setFulltext(Boolean.TRUE.equals(fulltext)));
log.info("GET SEARCH RESULTS for {} with query {}", entityName, input);
@ -434,7 +434,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
final Authentication auth = AuthenticationContext.getAuthentication();
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_SEARCH_ACROSS_ENTITIES, entities), authorizer, auth, true)
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_SEARCH_ACROSS_ENTITIES, entities), authorizer, auth, true)
.withSearchFlags(flags -> searchFlags != null ? searchFlags : new SearchFlags().setFulltext(true));
List<String> entityList = searchService.getEntitiesToSearch(opContext, entities == null ? Collections.emptyList() : Arrays.asList(entities), count);
@ -478,7 +478,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
final Authentication auth = AuthenticationContext.getAuthentication();
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_SCROLL_ACROSS_ENTITIES, entities), authorizer, auth, true)
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_SCROLL_ACROSS_ENTITIES, entities), authorizer, auth, true)
.withSearchFlags(flags -> searchFlags != null ? searchFlags : new SearchFlags().setFulltext(true));
List<String> entityList = searchService.getEntitiesToSearch(opContext, entities == null ? Collections.emptyList() : Arrays.asList(entities), count);
@ -547,7 +547,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_SEARCH_ACROSS_LINEAGE, entities), authorizer, auth, true)
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_SEARCH_ACROSS_LINEAGE, entities), authorizer, auth, true)
.withSearchFlags(flags -> (searchFlags != null ? searchFlags : new SearchFlags().setFulltext(true))
.setIncludeRestricted(true))
.withLineageFlags(flags -> flags.setStartTimeMillis(startTimeMillis, SetMode.REMOVE_IF_NULL)
@ -606,7 +606,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_SCROLL_ACROSS_LINEAGE, entities),
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_SCROLL_ACROSS_LINEAGE, entities),
authorizer, auth, true)
.withSearchFlags(flags -> (searchFlags != null ? searchFlags : new SearchFlags().setSkipCache(true))
.setIncludeRestricted(true))
@ -661,7 +661,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_LIST, entityName), authorizer, auth, true)
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_LIST, entityName), authorizer, auth, true)
.withSearchFlags(flags -> new SearchFlags().setFulltext(false));
log.info("GET LIST RESULTS for {} with filter {}", entityName, filter);
@ -702,7 +702,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_AUTOCOMPLETE, entityName), authorizer, auth, true)
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_AUTOCOMPLETE, entityName), authorizer, auth, true)
.withSearchFlags(flags -> searchFlags != null ? searchFlags : flags);
return RestliUtil.toTask(
@ -740,7 +740,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_BROWSE, entityName), authorizer, auth, true)
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_BROWSE, entityName), authorizer, auth, true)
.withSearchFlags(flags -> searchFlags != null ? searchFlags : flags);
log.info("GET BROWSE RESULTS for {} at path {}", entityName, path);
@ -779,7 +779,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
log.info("GET BROWSE PATHS for {}", urn);
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_GET_BROWSE_PATHS, urn.getEntityType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_GET_BROWSE_PATHS, urn.getEntityType()), authorizer, auth, true);
return RestliUtil.toTask(
() -> new StringArray(entitySearchService.getBrowsePaths(opContext, urnToEntityName(urn), urn)),
@ -848,7 +848,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to delete entities.");
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("deleteAll", urns), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "deleteAll", urns), authorizer, auth, true);
response.setEntitiesAffected(urns.size());
response.setEntitiesDeleted(
@ -899,7 +899,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to delete entity: " + urnStr);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_DELETE, urn.getEntityType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_DELETE, urn.getEntityType()), authorizer, auth, true);
return RestliUtil.toTask(
() -> {
@ -961,7 +961,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to delete entity " + urn);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("deleteTimeseriesAspects", urn.getEntityType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "deleteTimeseriesAspects", urn.getEntityType()), authorizer, auth, true);
// Construct the filter.
List<Criterion> criteria = new ArrayList<>();
@ -1017,7 +1017,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to delete entity " + urnStr);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("deleteReferences", urn.getEntityType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "deleteReferences", urn.getEntityType()), authorizer, auth, true);
return RestliUtil.toTask(
() -> deleteEntityService.deleteReferencesTo(opContext, urn, dryRun),
@ -1062,7 +1062,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entity counts.");
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("getTotalEntityCount", entityName), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "getTotalEntityCount", entityName), authorizer, auth, true);
return RestliUtil.toTask(() -> entitySearchService.docCount(opContext, entityName));
}
@ -1080,7 +1080,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entity counts.");
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("batchGetTotalEntityCount", entityNames), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "batchGetTotalEntityCount", entityNames), authorizer, auth, true);
return RestliUtil.toTask(
() -> new LongMap(searchService.docCountPerEntity(opContext, Arrays.asList(entityNames))));
}
@ -1103,7 +1103,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to search.");
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_LIST_URNS, entityName), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_LIST_URNS, entityName), authorizer, auth, true);
log.info("LIST URNS for {} with start {} and count {}", entityName, start, count);
return RestliUtil.toTask(() -> {
@ -1145,7 +1145,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to apply retention.");
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_APPLY_RETENTION, resourceSpec.getType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_APPLY_RETENTION, resourceSpec.getType()), authorizer, auth, true);
return RestliUtil.toTask(
() -> entityService.batchApplyRetention(opContext, start, count, attemptWithVersion, aspectName, urn),
@ -1171,7 +1171,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to search.");
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_FILTER, entityName), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_FILTER, entityName), authorizer, auth, true);
log.info("FILTER RESULTS for {} with filter {}", entityName, filter);
return RestliUtil.toTask(
() -> {
@ -1206,7 +1206,7 @@ public class EntityResource extends CollectionResourceTaskTemplate<String, Entit
HttpStatus.S_403_FORBIDDEN, "User is unauthorized check entity existence: " + urnStr);
}
OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_EXISTS, urn.getEntityType()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_EXISTS, urn.getEntityType()), authorizer, auth, true);
log.info("EXISTS for {}", urnStr);
final boolean includeRemoved = includeSoftDelete == null || includeSoftDelete;
return RestliUtil.toTask(

View File

@ -79,7 +79,7 @@ public class EntityV2Resource extends CollectionResourceTaskTemplate<String, Ent
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entity " + urn);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("getEntityV2", urn.getEntityType()), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "getEntityV2", urn.getEntityType()), _authorizer, auth, true);
return RestliUtil.toTask(
() -> {
@ -123,7 +123,7 @@ public class EntityV2Resource extends CollectionResourceTaskTemplate<String, Ent
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get entities " + urnStrs);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("getEntityV2", urns.stream().map(Urn::getEntityType).collect(Collectors.toList())), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "getEntityV2", urns.stream().map(Urn::getEntityType).collect(Collectors.toList())), _authorizer, auth, true);
if (urns.size() <= 0) {
return Task.value(Collections.emptyMap());

View File

@ -88,7 +88,7 @@ public class EntityVersionedV2Resource
"User is unauthorized to get entities " + versionedUrnStrs);
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("authorizerChain", urns.stream()
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "authorizerChain", urns.stream()
.map(Urn::getEntityType).collect(Collectors.toList())), _authorizer, auth, true);
log.debug("BATCH GET VERSIONED V2 {}", versionedUrnStrs);

View File

@ -107,7 +107,7 @@ public class OperationsResource extends CollectionResourceTaskTemplate<String, V
@ActionParam("gePitEpochMs") @Optional @Nullable Long gePitEpochMs,
@ActionParam("lePitEpochMs") @Optional @Nullable Long lePitEpochMs) {
return RestliUtil.toTask(
() -> Utils.restoreIndices(systemOperationContext,
() -> Utils.restoreIndices(systemOperationContext, getContext(),
aspectName, urn, urnLike, start, batchSize, limit, gePitEpochMs, lePitEpochMs, _authorizer, _entityService),
MetricRegistry.name(this.getClass(), "restoreIndices"));
}
@ -202,7 +202,7 @@ public class OperationsResource extends CollectionResourceTaskTemplate<String, V
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to get index sizes.");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_GET_INDEX_SIZES, List.of()), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_GET_INDEX_SIZES, List.of()), _authorizer, auth, true);
TimeseriesIndicesSizesResult result = new TimeseriesIndicesSizesResult();
result.setIndexSizes(
@ -232,7 +232,7 @@ public class OperationsResource extends CollectionResourceTaskTemplate<String, V
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to truncate timeseries index");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("executeTruncateTimeseriesAspect", entityType), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), "executeTruncateTimeseriesAspect", entityType), _authorizer, auth, true);
if (forceDeleteByQuery != null && forceDeleteByQuery.equals(forceReindex)) {
return "please only set forceReindex OR forceDeleteByQuery flags";

View File

@ -13,6 +13,7 @@ import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.entity.restoreindices.RestoreIndicesArgs;
import com.linkedin.metadata.entity.restoreindices.RestoreIndicesResult;
import com.linkedin.restli.common.HttpStatus;
import com.linkedin.restli.server.ResourceContext;
import com.linkedin.restli.server.RestLiServiceException;
import java.util.HashMap;
import java.util.List;
@ -32,7 +33,8 @@ public class Utils {
private Utils() {}
public static String restoreIndices(
@Nonnull OperationContext systemOperationContext,
@Nonnull OperationContext systemOperationContext,
@Nonnull ResourceContext resourceContext,
@Nonnull String aspectName,
@Nullable String urn,
@Nullable String urnLike,
@ -59,7 +61,7 @@ public class Utils {
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to restore indices.");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli("restoreIndices", List.of()), authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), resourceContext, "restoreIndices", List.of()), authorizer, auth, true);
RestoreIndicesArgs args =
new RestoreIndicesArgs()

View File

@ -141,7 +141,7 @@ public class UsageStats extends SimpleResourceTemplate<UsageAggregation> {
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to edit entities.");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_BATCH_INGEST, urns.stream()
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_BATCH_INGEST, urns.stream()
.map(Urn::getEntityType).collect(Collectors.toList())), _authorizer, auth, true);
for (UsageAggregation agg : buckets) {
@ -180,7 +180,7 @@ public class UsageStats extends SimpleResourceTemplate<UsageAggregation> {
HttpStatus.S_403_FORBIDDEN, "User is unauthorized to query usage.");
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_QUERY, resourceUrn.getEntityType()), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_QUERY, resourceUrn.getEntityType()), _authorizer, auth, true);
return UsageServiceUtil.query(opContext, _timeseriesAspectService, resource, duration, startTime, endTime, maxBuckets);
},
@ -207,7 +207,7 @@ public class UsageStats extends SimpleResourceTemplate<UsageAggregation> {
}
final OperationContext opContext = OperationContext.asSession(
systemOperationContext, RequestContext.builder().buildRestli(ACTION_QUERY_RANGE, resourceUrn.getEntityType()), _authorizer, auth, true);
systemOperationContext, RequestContext.builder().buildRestli(auth.getActor().toUrnStr(), getContext(), ACTION_QUERY_RANGE, resourceUrn.getEntityType()), _authorizer, auth, true);
return RestliUtil.toTask(
() -> UsageServiceUtil.queryRange(opContext, _timeseriesAspectService, resource, duration, range), MetricRegistry.name(this.getClass(), "queryRange"));