public bool TryGetInvocationContext(HttpRequestMessage request, out InvocationContext context)
        {
            context = new InvocationContext();
            // Required properties
            context.ConnectionId = request.Headers.GetValues(Constants.AsrsConnectionIdHeader).FirstOrDefault();
            if (string.IsNullOrEmpty(context.ConnectionId))
            {
                return(false);
            }
            context.Hub      = request.Headers.GetValues(Constants.AsrsHubNameHeader).FirstOrDefault();
            context.Category = request.Headers.GetValues(Constants.AsrsCategory).FirstOrDefault();
            context.Event    = request.Headers.GetValues(Constants.AsrsEvent).FirstOrDefault();
            // Optional properties
            if (request.Headers.TryGetValues(Constants.AsrsUserId, out var values))
            {
                context.UserId = values.FirstOrDefault();
            }
            if (request.Headers.TryGetValues(Constants.AsrsClientQueryString, out values))
            {
                context.Query = SignalRTriggerUtils.GetQueryDictionary(values.FirstOrDefault());
            }
            if (request.Headers.TryGetValues(Constants.AsrsUserClaims, out values))
            {
                context.Claims = SignalRTriggerUtils.GetClaimDictionary(values.FirstOrDefault());
            }
            context.Headers = SignalRTriggerUtils.GetHeaderDictionary(request.Headers);

            return(true);
        }
        // The algorithm is defined in spec: Hex_encoded(HMAC_SHA256(access-key, connection-id))
        public bool ValidateSignature(HttpRequestMessage request, string accessToken)
        {
            if (!_validateSignature)
            {
                return(true);
            }

            if (!string.IsNullOrEmpty(accessToken) &&
                request.Headers.TryGetValues(Constants.AsrsSignature, out var values))
            {
                var signatures = SignalRTriggerUtils.GetSignatureList(values.FirstOrDefault());
                if (signatures == null)
                {
                    return(false);
                }
                using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(accessToken)))
                {
                    var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(request.Headers.GetValues(Constants.AsrsConnectionIdHeader).First()));
                    var hash      = "sha256=" + BitConverter.ToString(hashBytes).Replace("-", "");
                    return(signatures.Contains(hash, StringComparer.OrdinalIgnoreCase));
                }
            }

            return(false);
        }
        internal SignalRTriggerAttribute GetParameterResolvedAttribute(SignalRTriggerAttribute attribute, ParameterInfo parameterInfo)
        {
            //TODO: AutoResolve more properties in attribute
            var hubName                 = attribute.HubName;
            var category                = attribute.Category;
            var @event                  = attribute.Event;
            var parameterNames          = attribute.ParameterNames ?? Array.Empty <string>();
            var connectionStringSetting = attribute.ConnectionStringSetting;

            // We have two models for C#, one is function based model which also work in multiple language
            // Another one is class based model, which is highly close to SignalR itself but must keep some conventions.
            var method       = (MethodInfo)parameterInfo.Member;
            var declaredType = method.DeclaringType;

            string[] parameterNamesFromAttribute;

            if (declaredType != null && IsServerlessHub(declaredType))
            {
                // Class based model
                if (!string.IsNullOrEmpty(hubName) ||
                    !string.IsNullOrEmpty(category) ||
                    !string.IsNullOrEmpty(@event) ||
                    parameterNames.Length != 0)
                {
                    throw new ArgumentException($"{nameof(SignalRTriggerAttribute)} must use parameterless constructor in class based model.");
                }
                parameterNamesFromAttribute = method.GetParameters().Where(IsLegalClassBasedParameter).Select(p => p.Name).ToArray();
                hubName  = declaredType.Name;
                category = GetCategoryFromMethodName(method.Name);
                @event   = GetEventFromMethodName(method.Name, category);
                connectionStringSetting = SignalRTriggerUtils.GetConnectionNameFromAttribute(declaredType) ?? attribute.ConnectionStringSetting;
            }
            else
            {
                parameterNamesFromAttribute = method.GetParameters().
                                              Where(p => p.GetCustomAttribute <SignalRParameterAttribute>(false) != null).
                                              Select(p => p.Name).ToArray();

                if (parameterNamesFromAttribute.Length != 0 && parameterNames.Length != 0)
                {
                    throw new InvalidOperationException(
                              $"{nameof(SignalRTriggerAttribute)}.{nameof(SignalRTriggerAttribute.ParameterNames)} and {nameof(SignalRParameterAttribute)} can not be set in the same Function.");
                }

                // If we aren't using the class-based model, make sure we resolve binding expressions for attribute properties here.
                hubName  = _nameResolver.ResolveWholeString(hubName);
                category = _nameResolver.ResolveWholeString(category);
                @event   = _nameResolver.ResolveWholeString(@event);
            }

            parameterNames = parameterNamesFromAttribute.Length != 0
                ? parameterNamesFromAttribute
                : parameterNames;

            return(new SignalRTriggerAttribute(hubName, category, @event, parameterNames)
            {
                ConnectionStringSetting = connectionStringSetting
            });
        }
        public Task <IListener> CreateListenerAsync(ListenerFactoryContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // It's not a real listener, and it doesn't need a start or close.
            _dispatcher.Map((_attribute.HubName, _attribute.Category, _attribute.Event),
                            new ExecutionContext {
                Executor = context.Executor, AccessKey = SignalRTriggerUtils.GetAccessKey(_attribute.ConnectionStringSetting)
            });

            return(Task.FromResult <IListener>(new NullListener()));
        }
示例#5
0
        // The algorithm is defined in spec: Hex_encoded(HMAC_SHA256(access-key, connection-id))
        public bool ValidateSignature(HttpRequestMessage request, AccessKey[] accessKeys)
        {
            if (!_validateSignature)
            {
                return(true);
            }

            if (accessKeys is null)
            {
                throw new ArgumentNullException(nameof(accessKeys));
            }

            foreach (var accessKey in accessKeys)
            {
                // Skip validation for aad access key.
                if (accessKey is AadAccessKey)
                {
                    return(true);
                }
                var accessToken = accessKey.Value;
                if (!string.IsNullOrEmpty(accessToken) &&
                    request.Headers.TryGetValues(Constants.AsrsSignature, out var values))
                {
                    var signatures = SignalRTriggerUtils.GetSignatureList(values.FirstOrDefault());
                    if (signatures == null)
                    {
                        continue;
                    }
                    using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(accessToken)))
                    {
                        var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(request.Headers.GetValues(Constants.AsrsConnectionIdHeader).First()));
                        var hash      = "sha256=" + BitConverter.ToString(hashBytes).Replace("-", "");
                        if (signatures.Contains(hash, StringComparer.OrdinalIgnoreCase))
                        {
                            return(true);
                        }
                        else
                        {
                            continue;
                        }
                    }
                }
            }
            return(false);
        }