Ejemplo n.º 1
0
        /// <inheritdoc />
        public ulong GetRight(RightsType rightsType)
        {
            var isInstance = RightsHelper.IsInstanceRight(rightsType);

            //forces the null user check
            var pullThis = User;

            if (isInstance && InstanceUser == null)
            {
                return(0);
            }
            var rightsEnum = RightsHelper.RightToType(rightsType);
            // use the api versions because they're the ones that contain the actual properties
            var typeToCheck = isInstance ? typeof(InstanceUser) : typeof(User);

            var nullableType       = typeof(Nullable <>);
            var nullableRightsType = nullableType.MakeGenericType(rightsEnum);

            var prop = typeToCheck.GetProperties().Where(x => x.PropertyType == nullableRightsType).First();

            var right = prop.GetMethod.Invoke(isInstance ? (object)InstanceUser : User, Array.Empty <object>());

            if (right == null)
            {
                throw new InvalidOperationException("A user right was null!");
            }
            return((ulong)right);
        }
        /// <inheritdoc />
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            if (operation == null)
            {
                throw new ArgumentNullException(nameof(operation));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            operation.OperationId = $"{context.MethodInfo.DeclaringType.Name}.{context.MethodInfo.Name}";

            var authAttributes = context
                                 .MethodInfo
                                 .DeclaringType
                                 .GetCustomAttributes(true)
                                 .Union(
                context
                .MethodInfo
                .GetCustomAttributes(true))
                                 .OfType <TgsAuthorizeAttribute>();

            if (authAttributes.Any())
            {
                var tokenScheme = new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id   = TokenSecuritySchemeId
                    }
                };

                operation.Security = new List <OpenApiSecurityRequirement>
                {
                    new OpenApiSecurityRequirement
                    {
                        {
                            tokenScheme,
                            new List <string>()
                        }
                    }
                };

                if (authAttributes.Any(attr => attr.RightsType.HasValue && RightsHelper.IsInstanceRight(attr.RightsType.Value)))
                {
                    operation.Parameters.Add(new OpenApiParameter
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.Parameter,
                            Id   = ApiHeaders.InstanceIdHeader
                        }
                    });
                }
            }
            else
            {
                // HomeController.CreateToken
                var passwordScheme = new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id   = PasswordSecuritySchemeId
                    }
                };

                operation.Security = new List <OpenApiSecurityRequirement>
                {
                    new OpenApiSecurityRequirement
                    {
                        {
                            passwordScheme,
                            new List <string>()
                        }
                    }
                };
            }
        }
        /// <inheritdoc />
        public async Task InjectClaimsIntoContext(TokenValidatedContext tokenValidatedContext, CancellationToken cancellationToken)
        {
            if (tokenValidatedContext == null)
            {
                throw new ArgumentNullException(nameof(tokenValidatedContext));
            }

            // Find the user id in the token
            var userIdClaim = tokenValidatedContext.Principal.FindFirst(JwtRegisteredClaimNames.Sub);

            if (userIdClaim == default)
            {
                throw new InvalidOperationException("Missing required claim!");
            }

            long userId;

            try
            {
                userId = Int64.Parse(userIdClaim.Value, CultureInfo.InvariantCulture);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Failed to parse user ID!", e);
            }

            ApiHeaders apiHeaders;

            try
            {
                apiHeaders = new ApiHeaders(tokenValidatedContext.HttpContext.Request.GetTypedHeaders());
            }
            catch (InvalidOperationException)
            {
                // we are not responsible for handling header validation issues
                return;
            }

            // This populates the CurrentAuthenticationContext field for use by us and subsequent controllers
            await authenticationContextFactory.CreateAuthenticationContext(userId, apiHeaders.InstanceId, tokenValidatedContext.SecurityToken.ValidFrom, cancellationToken).ConfigureAwait(false);

            var authenticationContext = authenticationContextFactory.CurrentAuthenticationContext;

            var enumerator = Enum.GetValues(typeof(RightsType));
            var claims     = new List <Claim>();

            foreach (RightsType I in enumerator)
            {
                // if there's no instance user, do a weird thing and add all the instance roles
                // we need it so we can get to OnActionExecutionAsync where we can properly decide between BadRequest and Forbid
                // if user is null that means they got the token with an expired password
                var rightInt  = authenticationContext.User == null || (RightsHelper.IsInstanceRight(I) && authenticationContext.InstanceUser == null) ? ~0U : authenticationContext.GetRight(I);
                var rightEnum = RightsHelper.RightToType(I);
                var right     = (Enum)Enum.ToObject(rightEnum, rightInt);
                foreach (Enum J in Enum.GetValues(rightEnum))
                {
                    if (right.HasFlag(J))
                    {
                        claims.Add(new Claim(ClaimTypes.Role, RightsHelper.RoleName(I, J)));
                    }
                }
            }

            tokenValidatedContext.Principal.AddIdentity(new ClaimsIdentity(claims));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Runs after a <see cref="Token"/> has been validated. Creates the <see cref="IAuthenticationContext"/> for the <see cref="ControllerBase.Request"/>
        /// </summary>
        /// <param name="context">The <see cref="TokenValidatedContext"/> for the operation</param>
        /// <returns>A <see cref="Task"/> representing the running operation</returns>
        public static async Task OnTokenValidated(TokenValidatedContext context)
        {
            var databaseContext = context.HttpContext.RequestServices.GetRequiredService <IDatabaseContext>();
            var authenticationContextFactory = context.HttpContext.RequestServices.GetRequiredService <IAuthenticationContextFactory>();

            var userIdClaim = context.Principal.FindFirst(JwtRegisteredClaimNames.Sub);

            if (userIdClaim == default(Claim))
            {
                throw new InvalidOperationException("Missing required claim!");
            }

            long userId;

            try
            {
                userId = Int64.Parse(userIdClaim.Value, CultureInfo.InvariantCulture);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Failed to parse user ID!", e);
            }

            ApiHeaders apiHeaders;

            try
            {
                apiHeaders = new ApiHeaders(context.HttpContext.Request.GetTypedHeaders());
            }
            catch
            {
                //let OnActionExecutionAsync handle the reponse
                return;
            }

            await authenticationContextFactory.CreateAuthenticationContext(userId, apiHeaders.InstanceId, context.SecurityToken.ValidFrom, context.HttpContext.RequestAborted).ConfigureAwait(false);

            var authenticationContext = authenticationContextFactory.CurrentAuthenticationContext;

            var enumerator = Enum.GetValues(typeof(RightsType));
            var claims     = new List <Claim>();

            foreach (RightsType I in enumerator)
            {
                //if there's no instance user, do a weird thing and add all the instance roles
                //we need it so we can get to OnActionExecutionAsync where we can properly decide between BadRequest and Forbid
                //if user is null that means they got the token with an expired password
                var rightInt  = authenticationContext.User == null || (RightsHelper.IsInstanceRight(I) && authenticationContext.InstanceUser == null) ? ~0U : authenticationContext.GetRight(I);
                var rightEnum = RightsHelper.RightToType(I);
                var right     = (Enum)Enum.ToObject(rightEnum, rightInt);
                foreach (Enum J in Enum.GetValues(rightEnum))
                {
                    if (right.HasFlag(J))
                    {
                        claims.Add(new Claim(ClaimTypes.Role, RightsHelper.RoleName(I, J)));
                    }
                }
            }

            context.Principal.AddIdentity(new ClaimsIdentity(claims));
        }