Beispiel #1
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());
        }
Beispiel #2
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(),
            });
        }
        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));
        }
Beispiel #4
0
        private IActionResult Handle(
            IRequest request,
            ModelAction requestedAction,
            TRelation relationType,
            IRequest relatedRequest,
            string jsonObject)
        {
            try {
                // Parse type of request method to something we can understand
                if (!Enum.TryParse <HttpRequestMethod> (
                        Request.Method,
                        true,
                        out var httpRequestMethod))
                {
                    // Request method is not valid, it must be something like Post, Delete and ...
                    return(BadRequest(new APIError {
                        Message = "Request method is not valid, it must be " +
                                  "{Post | Get | Patch | Delete}"
                    }));
                }

                var permissionHandler = new PermissionHandler <TRelation, TUser> (
                    UserManager.GetUserId(User),
                    ModelParser,
                    EngineService,
                    dbContext);

                //* Security Checks *//
                //* Check whether this set is consistent or not {HttpRequestMethod,
                //* IRequest, ModelAction, RelationType}
                var consistentRequest =
                    permissionHandler.ValidateRequest(
                        httpRequestMethod,
                        request,
                        requestedAction,
                        relationType);
                if (!(consistentRequest is bool && (bool)consistentRequest))
                {
                    return(BadRequest(new APIError {
                        Message = consistentRequest
                    }));
                }

                // If this is a relation request
                if (requestedAction == ModelAction.Relate)
                {
                    if (relationType == null)
                    {
                        return(BadRequest(new APIError {
                            Message = "Relation type must be determined"
                        }));
                    }

                    if (relatedRequest == null || relatedRequest.ResourceName == null)
                    {
                        // if this isn't a relation request, related input args are better to be empty
                        relatedRequest = null;
                    }
                    else
                    {
                        //* Check whether this set is consistent or not {HttpRequestMethod,
                        //* IRequest, ModelAction, RelationType}
                        var consistentRelatedRequest =
                            permissionHandler.ValidateRequest(
                                httpRequestMethod,
                                relatedRequest,
                                requestedAction,
                                relationType);
                        if (!(consistentRelatedRequest is bool && (bool)consistentRelatedRequest))
                        {
                            return(BadRequest(new APIError {
                                Message = consistentRelatedRequest
                            }));
                        }
                    }
                }

                //* Get which user is trying to send this request
                switch (requestedAction)
                {
                case ModelAction.Create:
                    return(CreateResource(
                               request,
                               httpRequestMethod,
                               permissionHandler,
                               jsonObject));

                case ModelAction.Read:
                    return(ReadResource(
                               request,
                               httpRequestMethod,
                               permissionHandler));

                case ModelAction.Delete:
                    return(DeleteResource(
                               request,
                               relationType,
                               relatedRequest,
                               permissionHandler));

                case ModelAction.Update:
                    return(PatchResource(
                               request,
                               httpRequestMethod,
                               permissionHandler,
                               jsonObject));

                case ModelAction.Relate:
                    return(JoinResourceAsync(
                               request,
                               relatedRequest,
                               relationType,
                               permissionHandler,
                               httpRequestMethod));

                default:
                    return(BadRequest(new APIError {
                        Message = "Requested ModelAction is not supported yet"
                    }));
                }
            } catch (Exception exception) {
                return(EngineService.OnRequestError(dbContext, exception, this));
            }
        }