コード例 #1
0
        /// <summary>
        /// Verify if claimed Type with claimed name and value exist and there is a valid connection between it
        /// and modelType with claimed id property and value
        /// </summary>
        private bool verifyConnection(
            Type claimType,
            string claimName,
            object claimValue,
            Type modelType,
            PropertyInfo idProperty,
            object idValue)
        {
            var claimId = claimType
                          .GetProperties()
                          .Where(prop =>
                                 prop.IsDefined(typeof(KeyAttribute), true))
                          .FirstOrDefault();

            var claimIdValue = claimId.GetValue(claimValue);

            if (claimIdValue == null)
            {
                return(false);
            }

            return(Utils.VerifyConnection(
                       APIUtils.GetIQueryable(dbContext, modelType.Name),
                       modelType,
                       claimType,
                       idProperty,
                       idValue.ToString(),
                       claimName,
                       claimId,
                       claimIdValue.ToString()));
        }
コード例 #2
0
        private dynamic ReadResource(
            IRequest request,
            HttpRequestMethod requestMethod,
            PermissionHandler <TRelation, TUser> permissionHandler)
        {
            var result = APIUtils.GetResource(dbContext, request);

            if (result == null)
            {
                return(new NotFoundResult());
            }

            var serializerSettings = JsonConvert.DefaultSettings();

            serializerSettings.ContractResolver = new APIJsonResolver <TRelation, TUser> {
                PermissionHandler = permissionHandler,
                ModelAction       = ModelAction.Read,
                RequestMethod     = requestMethod,
                IRequest          = request,
                DbContext         = dbContext,
                EngineService     = EngineService,
                IncludeBindNever  = true,
                IncludeKey        = true
            };

            EngineService.OnResourceRead(dbContext, request, result);

            Response.Headers.Add("Server", "NG-API");

            return(new OkObjectResult(JsonConvert.SerializeObject(result, serializerSettings)));
        }
コード例 #3
0
        private dynamic DeleteResource(
            IRequest request,
            TRelation relationType,
            IRequest relatedRequest,
            PermissionHandler <TRelation, TUser> permissionHandler)
        {
            var resource = APIUtils.GetResource(dbContext, request) as object;

            if (resource == null)
            {
                return(new NotFoundResult());
            }

            if (!(resource is RootModel))
            {
                return(new BadRequestObjectResult(
                           new APIError {
                    Code = StatusCodes.Status424FailedDependency,
                    Message = "Only api architecture based models can be deleted"
                }
                           ));
            }

            var globalIntraction = dbContext.MagicDbSet(EngineService.MapRelationToType("Global")) as IEnumerable <dynamic>;
            var globalRelation   = Enum.Parse(enumType: typeof(TRelation), value: "Global");

            var isCreator = globalIntraction
                            .Where(predicate: intraction =>
                                   intraction.IntractionType.Equals(globalRelation) &&
                                   intraction.Valid &&
                                   ((intraction.ValidUntil == null || intraction.ValidUntil.HasValue == false) ||
                                    (intraction.ValidUntil.HasValue && System.DateTime.Now.CompareTo(intraction.ValidUntil.Value) < 0)) &&
                                   (intraction.CreatorId.Equals(permissionHandler.getRequesterID()) &&
                                    intraction.FirstModelId.Equals(permissionHandler.getRequesterID()) &&
                                    intraction.SecondModelId.Equals(resource.GetKeyPropertyValue())))
                            .Any();

            if (!isCreator)
            {
                return(new BadRequestObjectResult(
                           new APIError {
                    Code = StatusCodes.Status403Forbidden,
                    Message = "Only object creator (The owner) can delete it"
                }));
            }

            resource.GetType().GetProperty(nameof(RootModel.Deactivated)).SetValue(resource, true);

            dbContext.Entry(resource).Property(nameof(RootModel.Deactivated)).IsModified = true;
            dbContext.SaveChanges();

            EngineService.OnResourceDeleted(dbContext, request, resource);

            return(new OkResult());
        }
コード例 #4
0
        public dynamic GeneralAccessChainValidation(
            IRequest Request,
            MemberInfo Type,
            ModelAction ModelAction,
            HttpRequestMethod RequestMethod,
            TRelation RelationType,
            object ModelItself,
            object TypeValue   = null,
            bool DefaultPolicy = false)
        {
            var typeName         = Type.GetType().GetProperty("Name").GetValue(Type) as string;
            var modelPermissions = Type.GetCustomAttributes <ModelPermissionAttribute> ();

            var requirements = modelPermissions
                               .AsParallel()
                               .Where(requirement =>
                                      requirement.ModelAction == ModelAction &&
                                      requirement.RequestMethod == RequestMethod)
                               .ToList();

            if (requirements != null && requirements.Count > 0)
            {
                foreach (var requirement in requirements)
                {
                    var validation = APIUtils.InvokeMethod(
                        requirement.AccessChainResolver,
                        "Validate",
                        new object[] {
                        DbContext,
                        RequesterID,
                        Request,
                        ModelItself,
                        typeName,
                        TypeValue,
                        ModelAction,
                        RequestMethod,
                        RelationType
                    });

                    if (!(validation is bool && (bool)validation))
                    {
                        return("Requirement validation with name { " + requirement.AccessChainResolver.Name +
                               " } has been failed with result { " + validation + " }");
                    }
                }
            }
            else if (DefaultPolicy == false)
            {
                return("Requested action { " + ModelAction + " } is not valid for request method { " +
                       RequestMethod + " }, or this action is not valid for this type { " +
                       typeName + " } at all");
            }

            return(true);
        }
コード例 #5
0
        public NeutronGeneralAPI(
            DbContext dbContext,
            UserManager <TUser> userManager,
            IModelParser modelParser,
            IApiEngineService <TRelation, TUser> engineService)
        {
            this.UserManager   = userManager;
            this.dbContext     = dbContext;
            this.ModelParser   = modelParser;
            this.EngineService = engineService;

            this.Utils = new APIUtils();
        }
コード例 #6
0
        private void ResolveRelationDependency(
            object model,
            string requesterID,
            IRequest request,
            IRequest relatedRequest,
            TRelation intractionType,
            HttpRequestMethod httpRequestMethod)
        {
            var propertyList = model.GetType()
                               .GetProperties()
                               .Where(property => property.IsDefined(typeof(RelationDependentValueAttribute), true))
                               .ToList();

            var updateModel = false;

            foreach (var item in propertyList)
            {
                var attribute = item.GetCustomAttribute <RelationDependentValueAttribute> ();

                var relationDependentResolver =
                    httpRequestMethod == HttpRequestMethod.Post ?
                    attribute.OnRelationCreated :
                    attribute.OnReleationDeleted;

                var result = APIUtils.InvokeMethod(
                    relationDependentResolver,
                    "OnRelationEvent",
                    new object[] {
                    dbContext,
                    model,
                    requesterID,
                    request,
                    relatedRequest,
                    intractionType,
                    httpRequestMethod
                });

                if (result != null)
                {
                    model       = result;
                    updateModel = true;
                }
            }

            if (updateModel)
            {
                dbContext.Update(model);
            }
        }
コード例 #7
0
        private dynamic PatchResource(
            IRequest request,
            HttpRequestMethod requestMethod,
            PermissionHandler <TRelation, TUser> permissionHandler,
            string jsonData)
        {
            var jsonResolver = new APIJsonResolver <TRelation, TUser> {
                DbContext         = dbContext,
                PermissionHandler = permissionHandler,
                ModelAction       = ModelAction.Create,
                RequestMethod     = requestMethod,
                IRequest          = request,
                EngineService     = EngineService,
                IncludeKey        = true,
                IncludeBindNever  = false
            };

            var serializerSettings = JsonConvert.DefaultSettings();

            serializerSettings.ContractResolver = jsonResolver;

            var model = JsonConvert.DeserializeObject(
                jsonData,
                request.Temp_ResourceType,
                serializerSettings);

            var oldModel = APIUtils.GetResource(dbContext, request);

            if (oldModel == null)
            {
                return(new NotFoundResult());
            }

            if (oldModel is IdentityUser)
            {
                return(new BadRequestObjectResult(new APIError {
                    Message = "User model can not edited by general api, this must be handled using an special AccountController."
                }));
            }

            var modelKey = model.GetType().GetPropertiesWithAttribute(typeof(KeyAttribute)).FirstOrDefault();

            if (modelKey == null)
            {
                return(new ForbidResult());
            }

            if (request.IdentifierName != modelKey.Name)
            {
                var identifierProperty = model.GetType().GetCustomAttributes <IdentifierValidatorAttribute> ()
                                         .Where(attribute => attribute.PropertyName == request.IdentifierName)
                                         .FirstOrDefault();

                if (identifierProperty == null)
                {
                    return(new ForbidResult());
                }

                modelKey.SetValue(model, modelKey.GetValue(oldModel));
            }

            var modelKeyValue     = modelKey.GetValue(model).ToString();
            var isValidIdentifier = modelKeyValue != null && modelKeyValue != request.IdentifierValue;

            if (!isValidIdentifier ||
                !verifyModelRelationChain(model))
            {
                return(BadRequest(new APIError {
                    Message =
                        "Error: Invalid relation in received model, it can be happend when you are not " +
                        "permitted for this action or there are some invalid id(s)."
                }));
            }

            // dbContext.Update (model);
            // ExcludeAttributes (model);

            IncludeAttributes(model);

            var intraction = new ModelInteraction <TRelation> {
                CreatorId     = permissionHandler.getRequesterID(),
                FirstModelId  = permissionHandler.getRequesterID(),
                SecondModelId = modelKeyValue,
                ModelAction   = ModelAction.Update
            };

            dbContext.MagicAddIntraction(intraction, EngineService.MapRelationToType("Global"));
            dbContext.SaveChanges();

            EngineService.OnResourcePatched(dbContext, request, model);

            return(new OkResult());
        }
コード例 #8
0
        private dynamic JoinResourceAsync(
            IRequest request,
            IRequest relatedRequest,
            TRelation relationType,
            PermissionHandler <TRelation, TUser> permissionHandler,
            HttpRequestMethod httpRequestMethod)
        {
            var oneWayRelation = relatedRequest == null || !relatedRequest.filledWithData();

            if (oneWayRelation)
            {
                relatedRequest = request;
            }

            var resourceType =
                oneWayRelation ?
                typeof(TUser) :
                ModelParser.GetResourceType(request.ResourceName);

            var relatedResourceType = ModelParser.GetResourceType(relatedRequest.ResourceName);

            bool firstIdentifierNameIsKey = true;

            if (!oneWayRelation)
            {
                firstIdentifierNameIsKey = resourceType.GetProperties()
                                           .Where(property =>
                                                  property.Name.Equals(request.IdentifierName) &&
                                                  property.IsDefined(typeof(KeyAttribute), true))
                                           .Any();
            }

            bool secondIdentifierNameIsKey = relatedResourceType.GetProperties()
                                             .Where(prop =>
                                                    prop.Name.Equals(relatedRequest.IdentifierName) &&
                                                    prop.IsDefined(typeof(KeyAttribute), true))
                                             .Any();

            if (!firstIdentifierNameIsKey || !secondIdentifierNameIsKey)
            {
                return(BadRequest(new APIError {
                    Message = "To create relation only key identifier is acceptable"
                }));
            }

            // Check whether request is exist or not
            var requestModel = oneWayRelation ?
                               UserManager.FindByIdAsync(permissionHandler.getRequesterID()).Result :
                               APIUtils.GetResource(dbContext, request);

            if (requestModel == null)
            {
                return(NotFound(request));
            }

            // Check if relationType is valid for request
            var resourceCheck =
                permissionHandler.ModelValidation(
                    Request: request,
                    ModelType: resourceType,
                    ModelAction: ModelAction.Relate,
                    RequestMethod: httpRequestMethod,
                    RelationType: relationType);

            if (!(resourceCheck is bool && (bool)resourceCheck))
            {
                return(BadRequest(new APIError {
                    Message = "Request Error: " + resourceCheck
                }));
            }

            // Check whether related request is exist or not
            var relatedRequestModel = APIUtils.GetResource(dbContext, relatedRequest);

            if (relatedRequestModel == null)
            {
                return(NotFound(relatedRequest));
            }

            // Check if relationType is valid for related request
            var relatedSourceCheck =
                permissionHandler.ModelValidation(
                    Request: relatedRequest,
                    ModelType: relatedResourceType,
                    ModelAction: ModelAction.Relate,
                    RequestMethod: httpRequestMethod,
                    RelationType: relationType);

            if (!(relatedSourceCheck is bool && (bool)relatedSourceCheck))
            {
                return(BadRequest(new APIError {
                    Message = "Request Error: " + relatedSourceCheck
                }));
            }

            if (!oneWayRelation)
            {
                // Check if relationType is valid for requesterID
                var userCheck =
                    permissionHandler.ModelValidation(
                        Request: request,
                        ModelType: typeof(TUser),
                        ModelAction: ModelAction.Relate,
                        RequestMethod: httpRequestMethod,
                        RelationType: relationType);
                if (!(userCheck is bool && (bool)userCheck))
                {
                    return(BadRequest(new APIError {
                        Message = "Request Error: " + userCheck
                    }));
                }
            }

            var intractionType = EngineService.MapRelationToType(relationType.ToString());
            var queryable      = dbContext.MagicDbSet(intractionType);

            var FirstModelId  = oneWayRelation ? permissionHandler.getRequesterID() : request.IdentifierValue;
            var SecondModelId = relatedRequest.IdentifierValue;

            var relation =
                (queryable as IEnumerable <dynamic>)
                .Where(intraction =>
                       intraction.Valid &&
                       ((intraction.ValidUntil == null || intraction.ValidUntil.HasValue == false) ||
                        (intraction.ValidUntil.HasValue && DateTime.Now.CompareTo(intraction.ValidUntil.Value) < 0)) &&
                       (intraction.CreatorId.Equals(permissionHandler.getRequesterID()) &&
                        intraction.FirstModelId.Equals(FirstModelId) &&
                        intraction.SecondModelId.Equals(SecondModelId)))
                .Take(1)
                .FirstOrDefault();

            // Create relation
            if (httpRequestMethod == HttpRequestMethod.Post)
            {
                if (relation != null)
                {
                    return(new OkObjectResult(relation));
                }

                relation = new ModelInteraction <TRelation> {
                    CreatorId      = permissionHandler.getRequesterID(),
                    FirstModelId   = FirstModelId,
                    SecondModelId  = SecondModelId,
                    IntractionType = relationType
                };

                MagicExtentions.MagicAddIntraction(queryable, relation, intractionType);

                EngineService.OnRelationCreated(dbContext, request, relatedRequest, relation);
            }
            else if (httpRequestMethod == HttpRequestMethod.Delete)
            {
                if (relation == null)
                {
                    return(new OkResult());
                }

                queryable.Remove(relation);

                relation.Valid       = false;
                relation.ValidUntil  = DateTime.Now;
                relation.Information = "Extinct by " + permissionHandler.getRequesterID();

                dbContext.MagicAddIntraction(relation as object, EngineService.MapRelationToType("Invalid"));
                EngineService.OnRelationDeleted(dbContext, request, relatedRequest, relation);
            }
            else
            {
                return(BadRequest());
            }

            ResolveRelationDependency(
                requestModel,
                permissionHandler.getRequesterID(),
                request,
                relatedRequest,
                relationType,
                httpRequestMethod);

            ResolveRelationDependency(
                relatedRequestModel,
                permissionHandler.getRequesterID(),
                request,
                relatedRequest,
                relationType,
                httpRequestMethod);

            dbContext.SaveChanges();

            return(new OkObjectResult(relation));
        }
コード例 #9
0
        public dynamic ValidateRequest(
            HttpRequestMethod requestMethod,
            IRequest request,
            ModelAction requestedAction,
            TRelation relationType)
        {
            if (request == null ||
                request.ResourceName == null || string.IsNullOrWhiteSpace(request.ResourceName))
            {
                return("Request Error: Route parameters should not be empty");
            }

            // Check ResourceName
            //* Check whether resource is exist or not? is direct access allowed or not?
            var resourceType = modelParser.GetResourceType(request.ResourceName);

            if (resourceType == null)
            {
                return("Requested resource {" + request.ResourceName +
                       "} is not exist or direct access is not permitted");
            }

            request.Temp_ResourceType = resourceType;

            if (requestedAction != ModelAction.Create)
            {
                if (request.IdentifierName == null || string.IsNullOrWhiteSpace(request.IdentifierName) ||
                    request.IdentifierValue == null || string.IsNullOrWhiteSpace(request.IdentifierValue))
                {
                    return("Request Error: Route parameters should not be empty");
                }

                //* Check whether this identifier is exist or not for model
                var identifierValidator =
                    (resourceType.GetCustomAttributes(typeof(IdentifierValidatorAttribute), true) as IdentifierValidatorAttribute[])
                    .Union(
                        resourceType.GetProperties()
                        .Where(property => property.IsDefined(typeof(IdentifierValidatorAttribute)))
                        .Select(validator => validator.GetCustomAttribute(typeof(IdentifierValidatorAttribute), true) as IdentifierValidatorAttribute)
                        )
                    .Where(validator => validator.PropertyName == request.IdentifierName)
                    .FirstOrDefault();

                if (identifierValidator == null || identifierValidator.Validator == null)
                {
                    return("Requested model identifier does not exist or it's not permitted to use it as an identifier");
                }

                var identifierValidation =
                    APIUtils.InvokeMethod(
                        identifierValidator.Validator,
                        "Validate",
                        new object[] {
                    request.IdentifierValue
                });

                if (!(identifierValidation is bool && (bool)identifierValidation))
                {
                    return("Request Error: The value {" + request.IdentifierValue +
                           "} is not a valid value for identifier {" + request.IdentifierName + "}");
                }
            }

            return(ModelValidation(
                       Request: request,
                       ModelType: resourceType,
                       ModelAction: requestedAction,
                       RequestMethod: requestMethod,
                       RelationType: relationType));
        }
コード例 #10
0
        public dynamic ReadCardList(
            string resourceName,
            string requesterID,
            string cursor
            )
        {
            Cursor objCursor = null;

            if (cursor != null && !string.IsNullOrWhiteSpace(cursor))
            {
                try {
                    var decryptedCursor = cursor.DecryptString(
                        engineService.GetCursorEncryptionKey()
                        );
                    objCursor = JsonConvert.DeserializeObject <Cursor> (decryptedCursor);
                } catch (Exception) { }
            }

            var maxPage = engineService.GetMaxRangeReadPage(resourceName);
            var maxOPP  = engineService.GetMaxRangeReadObjectPerPage(resourceName);

            if (objCursor == null)
            {
                objCursor = new Cursor(requesterID, resourceName);
            }
            else
            {
                if (objCursor.isExpired())
                {
                    return(new BadRequestObjectResult(new APIError {
                        Message = "Cursor time limit has been expired."
                    }));
                }

                if (objCursor.RequesterID != requesterID ||
                    objCursor.IssuedFor != resourceName)
                {
                    return(new BadRequestObjectResult(new APIError {
                        Message = "Cursor has been issued for someone else."
                    }));
                }

                if (objCursor.PageNumber < 1 ||
                    objCursor.PageNumber > maxPage ||
                    objCursor.ObjPerPage < 1 ||
                    objCursor.ObjPerPage > maxOPP)
                {
                    return(new BadRequestObjectResult(new APIError {
                        Message = "Cursor page number or object/page is out of bound."
                    }));
                }
            }

            var resourceType = modelParser.IsRangeReaderAllowed(resourceName);

            if (resourceType == null)
            {
                return(new NotFoundResult());
            }

            var endPoint   = objCursor.PageNumber * objCursor.ObjPerPage;
            var startpoint = endPoint - objCursor.ObjPerPage;

            var rangeAttribute = resourceType.GetCustomAttribute <RangeReaderAllowedAttribute> ();

            if (endPoint > rangeAttribute.MaxObjToRead)
            {
                return(new BadRequestObjectResult(new APIError {
                    Message = "Requested range is exceeded from resource limitations (" +
                              rangeAttribute.MaxObjToRead + ")"
                }));
            }

            var nextCursor = string.Empty;

            if (endPoint + objCursor.ObjPerPage <= rangeAttribute.MaxObjToRead &&
                objCursor.PageNumber <= maxPage &&
                objCursor.ObjPerPage <= maxOPP)
            {
                try {
                    nextCursor =
                        JsonConvert.SerializeObject(
                            new Cursor(
                                requesterID,
                                resourceName,
                                objCursor.PageNumber + 1,
                                objCursor.ObjPerPage
                                )
                            )
                        .EncryptString(engineService.GetCursorEncryptionKey());
                } catch (Exception) {
                    return(new BadRequestObjectResult(new APIError {
                        Message = "Cursor creation has been failed"
                    }));
                }
            }

            APIUtils utils = new APIUtils();

            var result = utils.GetResourceWithRange(
                APIUtils.GetIQueryable(dbContext, resourceType.Name),
                startpoint,
                endPoint) as ICollection <Card>;

            if (result == null || result.Count == 0)
            {
                return(new CardList());
            }

            var rangerIdProp = resourceType.GetProperties()
                               .Where(prop => prop.IsDefined(typeof(KeyAttribute), false))
                               .FirstOrDefault();

            var permissionHandler = new PermissionHandler <TRelation, TUser> (
                requesterID,
                modelParser,
                engineService,
                dbContext);
            var iRequest = new IRequest {
                ResourceName   = resourceType.Name,
                IdentifierName = rangerIdProp.Name
            };

            foreach (var item in result)
            {
                iRequest.IdentifierValue = rangerIdProp.GetValue(item).ToString();
                permissionHandler.CheckPermissionRequirements(
                    iRequest,
                    ModelAction.Read,
                    HttpRequestMethod.Get,
                    item);
            }

            return(new CardList {
                PageNumber = objCursor.PageNumber,
                Cursor = nextCursor,
                Cards = result.ToList(),
            });
        }