Example #1
0
        public void PolicyName_YieldsPolicyNameInRule()
        {
            var group = FieldSecurityGroup.FromAttributeCollection(typeof(PolicyNameObject));

            Assert.IsNotNull(group);
            Assert.AreEqual(1, group.Count);
            Assert.IsFalse(group.AllowAnonymous);

            var policy = group.First();

            Assert.AreEqual("TestPolicy", policy.PolicyName);
            Assert.IsEmpty(policy.AllowedRoles);
        }
Example #2
0
        public void RolePolicyCombined_YieldsSingleRule()
        {
            var group = FieldSecurityGroup.FromAttributeCollection(typeof(PolicyNameWithRolesObject));

            Assert.IsNotNull(group);
            Assert.AreEqual(1, group.Count);
            Assert.IsFalse(group.AllowAnonymous);

            var policy = group.First();

            Assert.AreEqual("TestPolicWithRoleList", policy.PolicyName);
            Assert.AreEqual(2, policy.AllowedRoles.Count);
            Assert.IsTrue(policy.AllowedRoles.Contains("roleQ"));
            Assert.IsTrue(policy.AllowedRoles.Contains("roleW"));
        }
Example #3
0
        public void Roles_YieldsRoleInRule()
        {
            var group = FieldSecurityGroup.FromAttributeCollection(typeof(RoleListObject));

            Assert.IsNotNull(group);
            Assert.AreEqual(1, group.Count);
            Assert.IsFalse(group.AllowAnonymous);

            var policy = group.First();

            Assert.AreEqual(null, policy.PolicyName);
            Assert.AreEqual(3, policy.AllowedRoles.Count);
            Assert.IsTrue(policy.AllowedRoles.Contains("role1"));
            Assert.IsTrue(policy.AllowedRoles.Contains("role2"));
            Assert.IsTrue(policy.AllowedRoles.Contains("role3"));
        }
Example #4
0
        public void MultiPolicy_HasAnonymousAttribute_IndicatesAll()
        {
            var group = FieldSecurityGroup.FromAttributeCollection(typeof(PolicyNameWithAnonymousObject));

            Assert.IsNotNull(group);
            Assert.AreEqual(2, group.Count);
            Assert.IsTrue(group.AllowAnonymous);

            var policy = group.First();

            Assert.AreEqual("TestPolicyWithAnonSupport", policy.PolicyName);
            Assert.AreEqual(0, policy.AllowedRoles.Count);

            var rolePolicy = group.Skip(1).First();

            Assert.AreEqual(3, rolePolicy.AllowedRoles.Count);
            Assert.IsTrue(rolePolicy.AllowedRoles.Contains("roleA"));
            Assert.IsTrue(rolePolicy.AllowedRoles.Contains("roleB"));
            Assert.IsTrue(rolePolicy.AllowedRoles.Contains("roleC"));
        }
Example #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BaseObjectGraphTypeTemplate"/> class.
        /// </summary>
        /// <param name="objectType">Type of the object.</param>
        internal BaseObjectGraphTypeTemplate(Type objectType)
            : base(objectType)
        {
            Validation.ThrowIfNull(objectType, nameof(objectType));

            _fields           = new GraphFieldCollection();
            _interfaces       = new HashSet <Type>();
            _securityPolicies = FieldSecurityGroup.Empty;

            // customize the error message on the thrown exception for some helpful hints.
            string rejectionReason = null;

            if (objectType.IsEnum)
            {
                rejectionReason = $"The type '{objectType.FriendlyName()}' is an enumeration and cannot be parsed as an object graph type. Use an {typeof(IEnumGraphType).FriendlyName()} instead.";
            }
            else if (objectType.IsValueType)
            {
                rejectionReason = $"The type '{objectType.FriendlyName()}' is a value type and cannot be parsed as a graph type. Try using a scalar instead.";
            }
            else if (objectType == typeof(string))
            {
                rejectionReason = $"The type '{typeof(string).FriendlyName()}' cannot be parsed as an object graph type. Use the built in scalar instead.";
            }
            else if (objectType.IsAbstract && objectType.IsClass)
            {
                rejectionReason = $"The type '{objectType.FriendlyName()}' is abstract and cannot be parsed as a graph type.";
            }

            if (rejectionReason != null)
            {
                throw new GraphTypeDeclarationException(rejectionReason, this.ObjectType);
            }

            this.ObjectType = objectType;
        }
Example #6
0
        /// <summary>
        /// When overridden in a child class this method builds out the template according to its own individual requirements.
        /// </summary>
        protected override void ParseTemplateDefinition()
        {
            _fieldDeclaration = this.SingleAttributeOfTypeOrDefault <GraphFieldAttribute>();

            // ------------------------------------
            // Common Metadata
            // ------------------------------------
            this.Route       = this.GenerateFieldPath();
            this.Mode        = _fieldDeclaration?.ExecutionMode ?? FieldResolutionMode.PerSourceItem;
            this.Complexity  = _fieldDeclaration?.Complexity;
            this.Description = this.SingleAttributeOfTypeOrDefault <DescriptionAttribute>()?.Description;
            var depreciated = this.SingleAttributeOfTypeOrDefault <DeprecatedAttribute>();

            if (depreciated != null)
            {
                this.IsDeprecated      = true;
                this.DeprecationReason = depreciated.Reason?.Trim();
            }

            var objectType     = GraphValidation.EliminateWrappersFromCoreType(this.DeclaredReturnType);
            var typeExpression = GraphValidation.GenerateTypeExpression(this.DeclaredReturnType, this);

            typeExpression = typeExpression.CloneTo(GraphTypeNames.ParseName(objectType, this.Parent.Kind));

            // ------------------------------------
            // Gather Possible Types and/or union definition
            // ------------------------------------
            this.BuildUnionProxyInstance();
            if (this.UnionProxy != null)
            {
                this.PossibleTypes = new List <Type>(this.UnionProxy.Types);
            }
            else
            {
                this.PossibleTypes = new List <Type>();

                // the possible types attribte is optional but expects taht the concrete types are added
                // to the schema else where lest a runtime exception occurs of a missing graph type.
                var typesAttrib = this.SingleAttributeOfTypeOrDefault <PossibleTypesAttribute>();
                if (typesAttrib != null)
                {
                    foreach (var type in typesAttrib.PossibleTypes)
                    {
                        this.PossibleTypes.Add(type);
                    }
                }

                // add any types decalred on the primary field declaration
                if (_fieldDeclaration != null)
                {
                    foreach (var type in _fieldDeclaration.Types)
                    {
                        var strippedType = GraphValidation.EliminateWrappersFromCoreType(type);
                        if (strippedType != null)
                        {
                            this.PossibleTypes.Add(strippedType);
                        }
                    }
                }

                if (objectType != null && !Validation.IsCastable <IGraphActionResult>(objectType) && GraphValidation.IsValidGraphType(objectType))
                {
                    this.PossibleTypes.Insert(0, objectType);
                }
            }

            this.PossibleTypes = this.PossibleTypes.Distinct().ToList();

            // ------------------------------------
            // Adjust the action result to the actual return type this field returns
            // ------------------------------------
            if (Validation.IsCastable <IGraphActionResult>(objectType))
            {
                if (this.UnionProxy != null)
                {
                    // if a union was decalred preserve whatever modifer elements
                    // were decalred but alter the return type to object (a known common element among all members of the union)
                    objectType = typeof(object);
                }
                else if (_fieldDeclaration != null && _fieldDeclaration.Types.Count > 0)
                {
                    objectType     = _fieldDeclaration.Types[0];
                    typeExpression = GraphValidation.GenerateTypeExpression(objectType, this)
                                     .CloneTo(GraphTypeNames.ParseName(objectType, this.Parent.Kind));
                    objectType = GraphValidation.EliminateWrappersFromCoreType(objectType);
                }
                else if (this.PossibleTypes.Count > 0)
                {
                    objectType     = this.PossibleTypes[0];
                    typeExpression = GraphValidation.GenerateTypeExpression(objectType, this)
                                     .CloneTo(GraphTypeNames.ParseName(objectType, this.Parent.Kind));
                    objectType = GraphValidation.EliminateWrappersFromCoreType(objectType);
                }
                else
                {
                    objectType = typeof(object);
                }
            }

            this.ObjectType = objectType;

            if (this.UnionProxy != null)
            {
                this.TypeExpression = typeExpression.CloneTo(this.UnionProxy.Name);
            }
            else
            {
                this.TypeExpression = typeExpression;
            }

            // ------------------------------------
            // Async Requirements
            // ------------------------------------
            this.IsAsyncField = Validation.IsCastable <Task>(this.DeclaredReturnType);

            // ------------------------------------
            // Security Policies
            // ------------------------------------
            _securityPolicies = FieldSecurityGroup.FromAttributeCollection(this.AttributeProvider);
        }
Example #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphTypeFieldTemplate" /> class.
 /// </summary>
 /// <param name="parent">The parent.</param>
 /// <param name="attributeProvider">The instance that will supply the various attributes used to generate this field template.
 /// This is usually <see cref="PropertyInfo"/> or <see cref="MethodInfo"/>.</param>
 protected GraphTypeFieldTemplate(IGraphTypeTemplate parent, ICustomAttributeProvider attributeProvider)
     : base(attributeProvider)
 {
     this.Parent       = Validation.ThrowIfNullOrReturn(parent, nameof(parent));
     _securityPolicies = FieldSecurityGroup.Empty;
 }
Example #8
0
        /// <summary>
        /// When overridden in a child class this method builds out the template according to its own individual requirements.
        /// </summary>
        protected override void ParseTemplateDefinition()
        {
            base.ParseTemplateDefinition();

            // ------------------------------------
            // Common Metadata
            // ------------------------------------
            this.Route       = this.GenerateFieldPath();
            this.Description = this.SingleAttributeOfTypeOrDefault <DescriptionAttribute>()?.Description;

            // ------------------------------------
            // Security Policies
            // ------------------------------------
            _securityPolicies = FieldSecurityGroup.FromAttributeCollection(this.AttributeProvider);

            // ------------------------------------
            // Parse the methods on this type for fields to include in the graph
            // ------------------------------------
            var parsedItems = new List <IGraphTypeFieldTemplate>();

            var templateMembers = this.ObjectType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                                  .Where(x => !x.IsAbstract && !x.IsGenericMethod && !x.IsSpecialName).Cast <MemberInfo>()
                                  .Concat(this.ObjectType.GetProperties(BindingFlags.Public | BindingFlags.Instance));

            foreach (var member in templateMembers)
            {
                if (this.CouldBeGraphField(member))
                {
                    // All members on types are "query operations" but are shown as part of the '[type]' collection
                    // kinda wierd when put against controllers which declare against [Query] and [Mutation] but are also types.
                    var parsedTemplate = this.CreateFieldTemplate(member);
                    parsedTemplate?.Parse();
                    if (parsedTemplate?.Route == null || !this.AllowedGraphCollectionTypes.Contains(parsedTemplate.Route.RootCollection))
                    {
                        _invalidFields = _invalidFields ?? new List <IGraphTypeFieldTemplate>();
                        _invalidFields.Add(parsedTemplate);
                    }
                    else
                    {
                        parsedItems.Add(parsedTemplate);
                    }
                }
            }

            // ensure no overloaded methods that are to be mapped onto the graph cause naming collisions
            // on the object graph with other methods or properties.
            _duplicateNames = parsedItems.Select(x => x.Route.Path)
                              .GroupBy(x => x)
                              .Where(x => x.Count() > 1)
                              .Select(x => x.Key);

            foreach (var field in parsedItems.Where(x => !_duplicateNames.Contains(x.Route.Path)))
            {
                _fields.Add(field.Route.Path, field);
            }

            // ------------------------------------
            // Pull a reference to any interfaces declared by this type for later inclusion in the object graph meta data.
            // ------------------------------------
            foreach (var iface in this.ObjectType.GetInterfaces().Where(x => x.IsPublic))
            {
                _interfaces.Add(iface);
            }
        }