protected async Task AuthorizeAsync(IGrainCallContext grainCallContext, string accessToken, OAuth2EndpointInfo oAuth2EndpointInfo) { if (string.IsNullOrEmpty(accessToken)) { throw new ArgumentNullException($"{nameof(accessToken)}"); } if (oAuth2EndpointInfo == null) { throw new ArgumentNullException($"{nameof(oAuth2EndpointInfo)}"); } var accessTokenValidationResult = await _accessTokenValidator.Validate(accessToken, oAuth2EndpointInfo); if (accessTokenValidationResult.IsValid) { IEnumerable <IAuthorizeData> grainAuthorizeData = null; var grainMethodAuthorizeData = grainCallContext.InterfaceMethod.GetCustomAttributes <AuthorizeAttribute>(); if (grainCallContext.InterfaceMethod.ReflectedType != null) { grainAuthorizeData = grainCallContext.InterfaceMethod.ReflectedType.GetCustomAttributes <AuthorizeAttribute>(); } await _authorizeHandler.AuthorizeAsync(accessTokenValidationResult.Claims, grainAuthorizeData, grainMethodAuthorizeData); } else { throw new OrleansClusterUnauthorizedAccessException("Invalid Access Token.", new InvalidAccessTokenException(accessTokenValidationResult.InvalidValidationMessage)); } }
public GrainTags(IGrainCallContext target) { if (target.Grain != null && target.Grain is ISystemTarget == false) { if (target.Grain.GetPrimaryKeyString() != null) { GrainId = target.Grain.GetPrimaryKeyString(); } else if (target.Grain.IsPrimaryKeyBasedOnLong()) { GrainId = target.Grain.GetPrimaryKeyLong(out var keyExt).ToString(); GrainId = (string.IsNullOrEmpty(keyExt) ? "" : keyExt + "/") + GrainId; } else { GrainId = target.Grain.GetPrimaryKey(out var keyExt).ToString(); GrainId = (string.IsNullOrEmpty(keyExt) ? "" : keyExt + "/") + GrainId; } // ReSharper disable once SuspiciousTypeConversion.Global if (target is Grain grainTarget) { SiloAddress = grainTarget.RuntimeIdentity; } } TargetType = target.Grain?.GetType().FullName ?? target.InterfaceMethod?.DeclaringType?.FullName; TargetMethod = target.InterfaceMethod?.Name; }
public async Task Invoke(IGrainCallContext ctx) { // // NOTE: this grain demonstrates incorrect usage of grain call interceptors and should not be used // as an example of proper usage. Specifically, storing the context for later execution is invalid. // this.context = ctx; if (string.Equals(ctx.Method.Name, nameof(CallWithBadInterceptors)) && (bool)ctx.Arguments[0]) { await ctx.Invoke(); } if (RequestContext.Get(Key) is string value) { RequestContext.Set(Key, value + '3'); } await ctx.Invoke(); if (string.Equals(ctx.Method?.Name, nameof(CallWithBadInterceptors)) && (bool)ctx.Arguments[1]) { await ctx.Invoke(); } this.context = null; }
public bool AuthenticationChallenge(IGrainCallContext grainCallContext) { var allowAnonymousAttribute = grainCallContext.InterfaceMethod.GetCustomAttribute <AllowAnonymousAttribute>(); // No authorization required. if (allowAnonymousAttribute != null) { return(false); } IEnumerable <IAuthorizeData> grainAuthorizeData = null; var grainMethodAuthorizeData = grainCallContext.InterfaceMethod.GetCustomAttributes <AuthorizeAttribute>(); if (grainCallContext.InterfaceMethod.ReflectedType != null) { grainAuthorizeData = grainCallContext.InterfaceMethod.ReflectedType.GetCustomAttributes <AuthorizeAttribute>(); } // No authorization required. // ReSharper disable once ConvertIfStatementToReturnStatement if (grainAuthorizeData != null && !grainAuthorizeData.Any() && !grainMethodAuthorizeData.Any()) { return(false); } return(true); }
private Activity StartActivity(IGrainCallContext callContext, IDictionary <string, object> requestContext) { var activity = new Activity(DiagnosticsLoggingStrings.GrainRequestIn); if (requestContext.TryGetValue(DiagnosticsLoggingStrings.RequestIdHeaderName, out object requestId)) { activity.SetParentId((string)requestId); // We expect baggage to be empty by default // Only very advanced users will be using it in near future, we encourage them to keep baggage small (few items) if (requestContext.TryGetValue(DiagnosticsLoggingStrings.CorrelationContextHeaderName, out object baggage)) { KeyValuePair <string, string>[] values = (KeyValuePair <string, string>[])baggage; foreach (var item in values) { activity.AddBaggage(item.Key, item.Value); } } } if (_listener.IsEnabled(DiagnosticsLoggingStrings.GrainRequestInStartName)) { _listener.StartActivity(activity, new { RequestContext = requestContext, CallContext = callContext }); } else { // always start activity activity.Start(); } return(activity); }
public async Task Invoke(IGrainCallContext context) { if (context.Method.Name == nameof(GetInputAsString)) { context.Result = $"Hah! You wanted {context.Arguments[0]}, but you got me!"; return; } await context.Invoke(); }
public Task Invoke(IGrainCallContext context) { if (string.Equals(context.Method.Name, nameof(IGrainCallFilterTestGrain.GetRequestContext))) { if (RequestContext.Get(GrainCallFilterTestConstants.Key) is string value) { RequestContext.Set(GrainCallFilterTestConstants.Key, value + '2'); } } return(context.Invoke()); }
public async Task Invoke(IGrainCallContext context) { var initialLastStreamValue = this.lastStreamValue; await context.Invoke(); // If the last stream value changed after the invoke, then the stream must have produced a value, double // it for testing purposes. if (this.lastStreamValue != initialLastStreamValue) { this.lastStreamValue *= 2; } }
private void RecordUnhandledExceptionDiagnostics(IGrainCallContext context, long timestamp, Exception exception) { //isenabled check is done in parent _listener.Write( DiagnosticsLoggingStrings.DiagnosticsUnhandledExceptionName, new { RequestContext = RequestContext.Export(_serializationManager), CallContext = context, Exception = exception, Timestamp = timestamp }); }
async Task IGrainCallFilter.Invoke(IGrainCallContext context) { var methodInfo = context.Method; if (methodInfo.Name == nameof(One) && methodInfo.GetParameters().Length == 0) { // Short-circuit the request and return to the caller without actually invoking the grain method. context.Result = "intercepted one with no args"; return; } if (methodInfo.Name == nameof(IncorrectResultType)) { // This method has a string return type, but we are setting the result to a Guid. // This should result in an invalid cast exception. context.Result = Guid.NewGuid(); return; } if (methodInfo.Name == nameof(FilterThrows)) { throw new MyDomainSpecificException("Filter THROW!"); } // Invoke the request. try { await context.Invoke(); } catch (MyDomainSpecificException e) { context.Result = "EXCEPTION! " + e.Message; return; } // To prove that the MethodInfo is from the implementation and not the interface, // we check for this attribute which is only present on the implementation. This could be // done in a simpler fashion, but this demonstrates a potential usage scenario. var shouldMessWithResult = methodInfo.GetCustomAttribute <MessWithResultAttribute>(); var resultString = context.Result as string; if (shouldMessWithResult != null && resultString != null) { context.Result = string.Concat(resultString.Reverse()); } }
public static string Format(IGrainCallContext context) { if (context.InterfaceMethod == null) { return("Unknown"); } if (string.Equals(context.InterfaceMethod.Name, nameof(IDomainObjectGrain.ExecuteAsync), StringComparison.CurrentCultureIgnoreCase) && context.Arguments?.Length == 1 && context.Arguments[0] != null) { var argumentFullName = context.Arguments[0].ToString(); if (argumentFullName != null) { var argumentParts = argumentFullName.Split('.'); var argumentName = argumentParts[^ 1];
public async Task Invoke(IGrainCallContext ctx) { // // NOTE: this grain demonstrates incorrect usage of grain call interceptors and should not be used // as an example of proper usage. Specifically, storing the context for later execution is invalid. // this.context = ctx; var value = RequestContext.Get(Key) as string; if (value != null) { RequestContext.Set(Key, value + '4'); } await ctx.Invoke(); this.context = null; }
private void PublishEvent(IGrainCallContext target, Exception ex) { var grainEvent = _eventPublisher.CreateEvent(); if (target.Grain != null && target.Grain is ISystemTarget == false) { if (target.Grain?.GetPrimaryKeyString() != null) { grainEvent.GrainKeyString = target.Grain.GetPrimaryKeyString(); } else if (target.Grain.IsPrimaryKeyBasedOnLong()) { grainEvent.GrainKeyLong = target.Grain.GetPrimaryKeyLong(out var keyExt); grainEvent.GrainKeyExtention = keyExt; } else { grainEvent.GrainKeyGuid = target.Grain.GetPrimaryKey(out var keyExt); grainEvent.GrainKeyExtention = keyExt; } if (target is Grain grainTarget) { grainEvent.SiloAddress = grainTarget.RuntimeIdentity; } } grainEvent.SiloDeploymentId = _clusterIdentity.DeploymentId; grainEvent.TargetType = target.Grain?.GetType().FullName ?? target.InterfaceMethod.DeclaringType?.FullName; grainEvent.TargetMethod = target.InterfaceMethod.Name; grainEvent.Exception = ex; grainEvent.ErrCode = ex != null ? null : (int?)0; try { _eventPublisher.TryPublish(grainEvent); } catch (Exception) { EventsDiscarded.Increment(); } }
public async Task Invoke(IGrainCallContext context) { var timerInfo = context.Method.GetCustomAttribute <LogElapsedTimeAttribute>(); var globalMillis = _runtimeConfiguration.LogGrainCallsExceedingMilliseconds; if (context.Grain is IGrain grain && (timerInfo != null || globalMillis > 0)) { var sw = Stopwatch.StartNew(); var logMillis = timerInfo?.IfExceedsMilliseconds ?? globalMillis; try { await context.Invoke(); } finally { sw.Stop(); if (sw.ElapsedMilliseconds > logMillis) { grain.Info($"GRAIN_ELAPSED_TIME {grain.GetType().Name}.{context.Method.Name}: {sw.Elapsed}", "", "", 0); } } }
protected static async Task Process(IGrainCallContext context, Activity activity) { if (activity is not null) { // rpc attributes from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md activity.SetTag("rpc.service", context.InterfaceMethod?.DeclaringType?.FullName); activity.SetTag("rpc.method", context.InterfaceMethod?.Name); activity.SetTag("net.peer.name", context.Grain?.ToString()); activity.SetTag("rpc.system", "orleans"); } try { await context.Invoke(); if (activity is not null && activity.IsAllDataRequested) { activity.SetTag("status", "Ok"); } } catch (Exception e) { if (activity is not null && activity.IsAllDataRequested) { // exception attributes from https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/exceptions.md activity.SetTag("exception.type", e.GetType().FullName); activity.SetTag("exception.message", e.Message); activity.SetTag("exception.stacktrace", e.StackTrace); activity.SetTag("exception.escaped", true); activity.SetTag("status", "Error"); } throw; } finally { activity?.Stop(); } }
public async Task Invoke(IGrainCallContext context) { Activity activity = null; // export requestcontext once IDictionary <string, object> requestContext = RequestContext.Export(_serializationManager);; if (requestContext != null && requestContext.ContainsKey(DiagnosticsLoggingStrings.RequestIdHeaderName)) { // flow activity from request headers activity = StartActivity(context, requestContext); } try { await context.Invoke().ConfigureAwait(false); if (activity != null) { // is set when diagnosticslistener is enabled // requestcontext dictionary is also not null StopActivity(context, activity, requestContext); } } catch (Exception ex) { //capture failed method... if (_listener.IsEnabled(DiagnosticsLoggingStrings.DiagnosticsUnhandledExceptionName)) { var timestamp = Stopwatch.GetTimestamp(); // Diagnostics is enabled for UnhandledException, but it may not be for BeginRequest // so call GetTimestamp if currentTimestamp is zero (from above) RecordUnhandledExceptionDiagnostics(context, timestamp, ex); } throw; } }
protected async Task <IEnumerable <Claim> > AuthorizeAsync(IGrainCallContext grainCallContext) { var accessToken = RequestContext.Get(ConfigurationKeys.AccessTokenKey)?.ToString(); if (string.IsNullOrWhiteSpace(accessToken)) { throw new InvalidOperationException("AccessToken can not be null or empty."); } var accessTokenVerificationResult = await _accessTokenVerifier.Verify(accessToken); // ReSharper disable once InvertIf if (accessTokenVerificationResult.IsVerified) { IEnumerable <IAuthorizeData> grainAuthorizeData = null; var grainMethodAuthorizeData = grainCallContext.InterfaceMethod.GetCustomAttributes <AuthorizeAttribute>(); if (grainCallContext.InterfaceMethod.ReflectedType != null) { grainAuthorizeData = grainCallContext.InterfaceMethod.ReflectedType.GetCustomAttributes <AuthorizeAttribute>(); } var authorizationSucceeded = await _authorizeHandler.AuthorizeAsync(accessTokenVerificationResult.Claims, grainAuthorizeData, grainMethodAuthorizeData); if (!authorizationSucceeded) { throw new NotAuthorizedException("Access to the requested grain denied."); } return(accessTokenVerificationResult.Claims); } throw new NotAuthorizedException("Access token verification failed.", new InvalidAccessTokenException(accessTokenVerificationResult.InvalidValidationMessage)); }
public async Task Invoke(IGrainCallContext context) { if (siloAddress == null) { var providerRuntime = services.GetRequiredService <IProviderRuntime>(); siloAddress = providerRuntime.SiloIdentity.ToSiloAddress(); } var stopwatch = Stopwatch.StartNew(); var isException = false; try { await context.Invoke(); } catch (Exception) { isException = true; throw; } finally { try { stopwatch.Stop(); var elapsedMs = (double)stopwatch.ElapsedTicks / TimeSpan.TicksPerMillisecond; var grainName = context.Grain.GetType().FullName; var methodName = formatMethodName(context); var key = string.Format("{0}.{1}", grainName, methodName); grainTrace.AddOrUpdate(key, _ => new GrainTraceEntry { Count = 1, ExceptionCount = (isException ? 1 : 0), SiloAddress = siloAddress, ElapsedTime = elapsedMs, Grain = grainName, Method = methodName, Period = DateTime.UtcNow }, (_, last) => { last.Count += 1; last.ElapsedTime += elapsedMs; if (isException) { last.ExceptionCount += 1; } return(last); }); } catch (Exception ex) { logger.LogError(100002, "error recording results for grain", ex); } } }
public Task Invoke(IGrainCallContext context) => this.interceptor.Invoke(context);
private void RejectRequestIfLateOrOverloaded(IGrainCallContext grainCallContext) { var config = _loadSheddingConfig(); var now = DateTimeOffset.UtcNow; // Too much time passed since our direct caller made the request to us; something's causing a delay. Log or reject the request, if needed. if (config.DropOrleansRequestsBySpanTime != LoadShedding.Toggle.Disabled && TracingContext.SpanStartTime != null && TracingContext.SpanStartTime.Value + config.DropOrleansRequestsOlderThanSpanTimeBy < now) { if (config.DropOrleansRequestsBySpanTime == LoadShedding.Toggle.LogOnly) { _log.Warn(_ => _("Accepted Orleans request despite that too much time passed since the client sent it to us.", unencryptedTags: new { clientSendTime = TracingContext.SpanStartTime, currentTime = now, maxDelayInSecs = config.DropOrleansRequestsOlderThanSpanTimeBy.TotalSeconds, actualDelayInSecs = (now - TracingContext.SpanStartTime.Value).TotalSeconds, })); } else if (config.DropOrleansRequestsBySpanTime == LoadShedding.Toggle.Drop) { //Add grain id to tags throw new EnvironmentException( "Dropping Orleans request since too much time passed since the client sent it to us.", unencrypted: new Tags { ["clientSendTime"] = TracingContext.SpanStartTime.ToString(), ["currentTime"] = now.ToString(), ["maxDelayInSecs"] = config.DropOrleansRequestsOlderThanSpanTimeBy.TotalSeconds.ToString(), ["actualDelayInSecs"] = (now - TracingContext.SpanStartTime.Value).TotalSeconds.ToString(), }); } } // Too much time passed since the API gateway initially sent this request till it reached us (potentially // passing through other micro-services along the way). Log or reject the request, if needed. if (config.DropRequestsByDeathTime != LoadShedding.Toggle.Disabled && TracingContext.AbandonRequestBy != null && now > TracingContext.AbandonRequestBy.Value - config.TimeToDropBeforeDeathTime) { if (config.DropRequestsByDeathTime == LoadShedding.Toggle.LogOnly) { _log.Warn(_ => _("Accepted Orleans request despite exceeding the API gateway timeout.", unencryptedTags: new { requestDeathTime = TracingContext.AbandonRequestBy, currentTime = now, overTimeInSecs = (now - TracingContext.AbandonRequestBy.Value).TotalSeconds, })); } else if (config.DropRequestsByDeathTime == LoadShedding.Toggle.Drop) { //Add grain id to tags throw new EnvironmentException("Dropping Orleans request since the API gateway timeout passed.", unencrypted: new Tags { ["requestDeathTime"] = TracingContext.AbandonRequestBy.ToString(), ["currentTime"] = now.ToString(), ["overTimeInSecs"] = (now - TracingContext.AbandonRequestBy.Value).TotalSeconds.ToString(), }); } } }
private void StopActivity(IGrainCallContext callContext, Activity activity, IDictionary <string, object> requestContext) { _listener.StopActivity(activity, new { RequestContext = requestContext, CallContext = callContext }); }