private ActionBase GetMethodBasedAction(string name, Content content, object state) { var httpContext = (HttpContext)state; //var odataRequest = (ODataRequest) httpContext.Items[ODataMiddleware.ODataRequestHttpContextKey]; OperationCallingContext method; try { method = OperationCenter.GetMethodByRequest(content, name, ODataMiddleware.ReadToJsonAsync(httpContext) .GetAwaiter().GetResult(), httpContext.Request.Query); } catch (OperationNotFoundException e) { throw new InvalidContentActionException(e, InvalidContentActionReason.UnknownAction, content.Path, e.Message, name); } catch (AmbiguousMatchException e) { throw new InvalidContentActionException(e, InvalidContentActionReason.UnknownAction, content.Path, e.Message, name); } method.HttpContext = httpContext; return(new ODataOperationMethodExecutor(method)); }
public async Task OD_Security_SetPermissions() { await IsolatedODataTestAsync(async() => { InstallCarContentType(); var testRoot = CreateTestRoot("ODataTestRoot"); var content = Content.CreateNew("Car", testRoot, Guid.NewGuid().ToString()); content.Save(); var resourcePath = ODataMiddleware.GetEntityUrl(content.Path); // ACTION var response = await ODataPostAsync( string.Concat("/OData.svc/", resourcePath, "/SetPermissions"), "", "{r:[" + "{identity:\"/Root/IMS/BuiltIn/Portal/Visitor\", OpenMinor:\"allow\", Save:\"deny\"}," + "{identity:\"/Root/IMS/BuiltIn/Portal/Owners\", Custom16:\"A\", Custom17:\"1\"}]}") .ConfigureAwait(false); // ASSERT AssertNoError(response); Assert.AreEqual(0, response.Result.Length); Assert.AreEqual(204, response.StatusCode); // 204 No Content }).ConfigureAwait(false); }
public async Task OD_Middleware() { await ODataTestAsync(async() => { // ARRANGE // Create HttpContext var httpContext = new DefaultHttpContext(); var request = httpContext.Request; request.Path = "/OData.svc/Root('IMS')/Name/$value"; request.QueryString = QueryString.Empty; request.Method = "GET"; var responseStream = httpContext.Response.Body = new MemoryStream(); // ACTION: Simulate the aspnet framework // instantiate the OData with the next chain member var odata = new ODataMiddleware(new TestMiddleware(null).InvokeAsync); // call the first of the chain await odata.InvokeAsync(httpContext); // ASSERT // check response string text; responseStream.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(responseStream)) text = reader.ReadToEnd(); Assert.AreEqual("IMS", text); // check additional header var header = httpContext.Response.Headers.FirstOrDefault(h => h.Key == "Header1"); Assert.IsNotNull(header); Assert.AreEqual("HeaderValue1", header.Value.ToString()); }).ConfigureAwait(false); }
public async Task OD_Security_SetPermissions_NotPropagates() { await IsolatedODataTestAsync(async() => { InstallCarContentType(); var testRoot = CreateTestRoot("ODataTestRoot"); var content = Content.CreateNew("Folder", testRoot, Guid.NewGuid().ToString()); content.Save(); var folderPath = ODataMiddleware.GetEntityUrl(content.Path); var folderRepoPath = content.Path; content = Content.CreateNew("Car", testRoot, Guid.NewGuid().ToString()); content.Save(); var carRepoPath = content.Path; // ACTION var response = await ODataPostAsync( $"/OData.svc/{folderPath}/SetPermissions", "", "{r:[{identity:\"/Root/IMS/BuiltIn/Portal/Visitor\"," + " OpenMinor:\"allow\", propagates:false}]}") .ConfigureAwait(false); // ASSERT AssertNoError(response); Assert.AreEqual(0, response.Result.Length); Assert.AreEqual(204, response.StatusCode); var folder = Node.LoadNode(folderRepoPath); var car = Node.LoadNode(carRepoPath); Assert.IsTrue(folder.Security.HasPermission(User.Visitor as IUser, PermissionType.OpenMinor)); Assert.IsFalse(car.Security.HasPermission(User.Visitor as IUser, PermissionType.OpenMinor)); }).ConfigureAwait(false); }
private static async Task <ODataResponse> ODataProcessRequestAsync(string resource, string queryString, string requestBodyJson, string httpMethod, IConfiguration config) { var httpContext = CreateHttpContext(resource, queryString); var request = httpContext.Request; request.Method = httpMethod; request.Path = resource; request.QueryString = new QueryString(queryString); if (requestBodyJson != null) { request.Body = CreateRequestStream(requestBodyJson); } httpContext.Response.Body = new MemoryStream(); var odata = new ODataMiddleware(null, config, null); var odataRequest = ODataRequest.Parse(httpContext); await odata.ProcessRequestAsync(httpContext, odataRequest).ConfigureAwait(false); var responseOutput = httpContext.Response.Body; responseOutput.Seek(0, SeekOrigin.Begin); string output; using (var reader = new StreamReader(responseOutput)) output = await reader.ReadToEndAsync().ConfigureAwait(false); return(new ODataResponse { Result = output, StatusCode = httpContext.Response.StatusCode }); }
public async Task OD_POST_Creation_FIX_InconsistentNameAfterCreation() { await ODataTestAsync(async() => { InstallCarContentType(); var testRoot = CreateTestRoot("ODataTestRoot"); var name = "Car"; // ACTION var names = new string[3]; for (int i = 0; i < 3; i++) { var response = await ODataPostAsync( String.Concat("/OData.svc", ODataMiddleware.GetEntityUrl(testRoot.Path)), "?metadata=no&$select=Name", $@"models=[{{""__ContentType"":""Car"",""Name"":""{name}""}}]") .ConfigureAwait(false); var entity = GetEntity(response); names[i] = entity.Name; } // ASSERT Assert.AreNotEqual(names[0], names[1]); Assert.AreNotEqual(names[0], names[2]); Assert.AreNotEqual(names[1], names[2]); }); }
private ActionBase GetMethodBasedAction(string name, Content content, object state) { var httpContext = (HttpContext)state; OperationCallingContext method; try { //TODO:~ Combine request body and querystring parameters into the 3th parameter. method = OperationCenter.GetMethodByRequest(content, name, ODataMiddleware.Read(httpContext.Request.Body)); } catch (OperationNotFoundException e) { throw new InvalidContentActionException(e, InvalidContentActionReason.UnknownAction, content.Path, e.Message, name); } catch (AmbiguousMatchException e) { throw new InvalidContentActionException(e, InvalidContentActionReason.UnknownAction, content.Path, e.Message, name); } method.HttpContext = httpContext; return(new ODataOperationMethodExecutor(method)); }
public async Task OD_Middleware_null() { await ODataTestAsync(async() => { // ARRANGE // Create HttpContext var httpContext = new DefaultHttpContext(); var request = httpContext.Request; request.Host = new HostString("example.com"); request.Path = "/OData.svc/Root('IMS')/Name/$value"; request.QueryString = QueryString.Empty; request.Method = "GET"; var responseStream = httpContext.Response.Body = new MemoryStream(); // ACTION: Simulate the aspnet framework var odata = new ODataMiddleware(null, null, null); // call the first of the chain await odata.InvokeAsync(httpContext, null); // ASSERT // check response string text; responseStream.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(responseStream)) text = reader.ReadToEnd(); Assert.AreEqual("IMS", text); // there is no additional headers var header = httpContext.Response.Headers.FirstOrDefault(h => h.Key == "Header1"); Assert.IsNull(header.Key); Assert.AreEqual(0, header.Value.Count); }).ConfigureAwait(false); }
public static object Import(Content content, string path, object data) { var jData = data as JObject; var imported = new ImportedContent(jData); var name = imported.Name; var type = imported.Type; JObject model = imported.Fields; model.Remove("Name"); string action; List <string> brokenReferences; var messages = new List <string>(); var targetContent = Content.Load(path); if (targetContent != null) { ODataMiddleware.UpdateFields(targetContent, model, true, out brokenReferences); targetContent.Save(); action = "updated"; } else { var parentPath = RepositoryPath.GetParentPath(path); targetContent = ODataMiddleware.CreateNewContent(parentPath, type, null, name, null, false, model, true, out brokenReferences); action = "created"; } SetPermissions(targetContent, imported.Permissions, messages, out var retryPermissions); return(new { path, name, type, action, brokenReferences, retryPermissions, messages }); }
// --------------------------------------------------------------------------------------------------------------- operations /// <summary> /// Handles GET operations. Parameters come from the URL or the request stream. /// </summary> internal async Task WriteGetOperationResultAsync(HttpContext httpContext, ODataRequest odataReq, IConfiguration appConfig) { var content = ODataMiddleware.LoadContentByVersionRequest(odataReq.RepositoryPath, httpContext); if (content == null) { throw new ContentNotFoundException(string.Format(SNSR.GetString("$Action,ErrorContentNotFound"), odataReq.RepositoryPath)); } var action = ODataMiddleware.ActionResolver.GetAction(content, odataReq.Scenario, odataReq.PropertyName, null, null, httpContext, appConfig); if (action == null) { // check if this is a versioning action (e.g. a checkout) SavingAction.AssertVersioningAction(content, odataReq.PropertyName, true); SnTrace.System.WriteError($"OData: {odataReq.PropertyName} operation not found " + $"for content {content.Path} and user {User.Current.Username}."); throw new InvalidContentActionException(InvalidContentActionReason.UnknownAction, content.Path, null, odataReq.PropertyName); } if (!action.IsODataOperation) { throw new ODataException("Not an OData operation.", ODataExceptionCode.IllegalInvoke); } if (action.CausesStateChange) { throw new ODataException("OData action cannot be invoked with HTTP GET.", ODataExceptionCode.IllegalInvoke); } if (action.Forbidden || (action.GetApplication() != null && !action.GetApplication().Security.HasPermission(PermissionType.RunApplication))) { throw new InvalidContentActionException("Forbidden action: " + odataReq.PropertyName); } var response = action is ODataOperationMethodExecutor odataAction ? (odataAction.IsAsync ? await odataAction.ExecuteAsync(content) : action.Execute(content)) : action.Execute(content, GetOperationParameters(action, httpContext.Request)); if (response is Content responseAsContent) { await WriteSingleContentAsync(responseAsContent, httpContext) .ConfigureAwait(false); return; } response = ProcessOperationResponse(response, odataReq, httpContext, out var count); await WriteOperationResultAsync(response, httpContext, odataReq, count) .ConfigureAwait(false); }
internal async Task WriteMetadataAsync(HttpContext httpContext, ODataRequest req) { var content = ODataMiddleware.LoadContentByVersionRequest(req.RepositoryPath, httpContext); //var isRoot = content?.ContentType.IsInstaceOfOrDerivedFrom("Site") ?? true; var isRoot = content == null; var metadata = isRoot ? MetaGenerator.GetMetadata() : MetaGenerator.GetMetadata(content, req.IsCollection); var mimeType = this.MimeType; if (mimeType != null) { httpContext.Response.ContentType = mimeType; } await WriteMetadataAsync(httpContext, metadata); }
public async Task OD_Security_Break() { await IsolatedODataTestAsync(async() => { InstallCarContentType(); var testRoot = CreateTestRoot("ODataTestRoot"); var content = Content.CreateNew("Car", testRoot, Guid.NewGuid().ToString()); content.Save(); var resourcePath = ODataMiddleware.GetEntityUrl(content.Path); // ACTION 1: Break var response = await ODataPostAsync( $"/OData.svc/{resourcePath}/SetPermissions", "", "{inheritance:\"break\"}") .ConfigureAwait(false); // ASSERT 1: Not inherited AssertNoError(response); var entity = GetEntity(response); Assert.AreEqual(content.Id, entity.Id); Assert.AreEqual(200, response.StatusCode); var node = Node.LoadNode(content.Id); Assert.IsFalse(node.Security.IsInherited); // ACTION 2: Unbreak response = await ODataPostAsync( $"/OData.svc/{resourcePath}/SetPermissions", "", "{inheritance:\"unbreak\"}") .ConfigureAwait(false); // ASSERT 2: Inherited AssertNoError(response); entity = GetEntity(response); Assert.AreEqual(content.Id, entity.Id); Assert.AreEqual(200, response.StatusCode); node = Node.LoadNode(content.Id); Assert.IsTrue(node.Security.IsInherited); }).ConfigureAwait(false); }
private ActionBase GetMethodBasedAction(string name, Content content, object state) { var(httpContext, config) = ((HttpContext, IConfiguration))state; //var odataRequest = (ODataRequest) httpContext.Items[ODataMiddleware.ODataRequestHttpContextKey]; OperationCallingContext method; try { method = OperationCenter.GetMethodByRequest(content, name, ODataMiddleware.ReadToJsonAsync(httpContext) .GetAwaiter().GetResult(), httpContext.Request.Query); } catch (OperationNotFoundException e) { SnTrace.System.WriteError($"Operation {name} not found. " + $"Content: {content.Path}, User: {User.Current.Username}"); throw new InvalidContentActionException(e, InvalidContentActionReason.UnknownAction, content.Path, e.Message, name); } catch (AmbiguousMatchException e) { SnTrace.System.WriteError($"Operation {name} is ambiguous. " + $"Content: {content.Path}, User: {User.Current.Username}"); throw new InvalidContentActionException(e, InvalidContentActionReason.UnknownAction, content.Path, e.Message, name); } catch (Exception ex) { SnTrace.System.WriteError($"Error during discovery of method {name}. {ex.Message} " + $"Content: {content.Path}, User: {User.Current.Username}"); throw; } method.HttpContext = httpContext; method.ApplicationConfiguration = config; return(new ODataOperationMethodExecutor(method)); }
/// <summary> /// Handles POST operations. Parameters come from request stream. /// </summary> internal async Task WritePostOperationResultAsync(HttpContext httpContext, ODataRequest odataReq, IConfiguration appConfig) { var content = ODataMiddleware.LoadContentByVersionRequest(odataReq.RepositoryPath, httpContext); if (content == null) { throw new ContentNotFoundException(string.Format(SNSR.GetString("$Action,ErrorContentNotFound"), odataReq.RepositoryPath)); } var action = ODataMiddleware.ActionResolver.GetAction(content, odataReq.Scenario, odataReq.PropertyName, null, null, httpContext, appConfig); if (action == null) { // check if this is a versioning action (e.g. a checkout) SavingAction.AssertVersioningAction(content, odataReq.PropertyName, true); throw new InvalidContentActionException(InvalidContentActionReason.UnknownAction, content.Path, null, odataReq.PropertyName); } if (action.Forbidden || (action.GetApplication() != null && !action.GetApplication().Security.HasPermission(PermissionType.RunApplication))) { throw new InvalidContentActionException("Forbidden action: " + odataReq.PropertyName); } var response = action is ODataOperationMethodExecutor odataAction ? (odataAction.IsAsync ? await odataAction.ExecuteAsync(content) : action.Execute(content)) : action.Execute(content, await GetOperationParametersAsync(action, httpContext, odataReq)); if (response is Content responseAsContent) { await WriteSingleContentAsync(responseAsContent, httpContext) .ConfigureAwait(false); return; } response = ProcessOperationResponse(response, odataReq, httpContext, out var count); await WriteOperationResultAsync(response, httpContext, odataReq, count) .ConfigureAwait(false); }
internal static async Task <HttpContext> ODataProcessRequestEmptyResponseAsync(string resource, string queryString, string requestBodyJson, string httpMethod, IConfiguration config) { var httpContext = CreateHttpContext(resource, queryString); var request = httpContext.Request; request.Method = httpMethod; request.Path = resource; request.QueryString = new QueryString(queryString); if (requestBodyJson != null) { request.Body = CreateRequestStream(requestBodyJson); } //httpContext.Response.Body = new MemoryStream(); var odata = new ODataMiddleware(null, config, null); var odataRequest = ODataRequest.Parse(httpContext); await odata.ProcessRequestAsync(httpContext, odataRequest).ConfigureAwait(false); return(httpContext); }
private async Task ODataTestAsync(IUser user, Action <RepositoryBuilder> initialize, Func <Task> callback) { Providers.Instance.ResetBlobProviders(); OnTestInitialize(); var builder = base.CreateRepositoryBuilderForTestInstance(); //CreateRepositoryBuilder(); //UNDONE:<?: do not call discovery and providers setting in the static ctor of ODataMiddleware var _ = new ODataMiddleware(null, null, null); // Ensure running the first-touch discover in the static ctor OperationCenter.Operations.Clear(); OperationCenter.Discover(); Providers.Instance.SetProvider(typeof(IOperationMethodStorage), new OperationMethodStorage()); initialize?.Invoke(builder); Indexing.IsOuterSearchEngineEnabled = true; Cache.Reset(); ResetContentTypeManager(); using (var repo = Repository.Start(builder)) { User.Current = user ?? User.Administrator; if (user == null) { User.Current = User.Administrator; using (new SystemAccount()) await callback().ConfigureAwait(false); } else { User.Current = user; await callback().ConfigureAwait(false); } } }
private async Task <object[]> GetOperationParametersAsync(ActionBase action, HttpContext httpContext, ODataRequest odataRequest) { if (action.ActionParameters.Length == 0) { return(ActionParameter.EmptyValues); } var inputStream = httpContext?.Request?.Body; var values = new object[action.ActionParameters.Length]; var parameters = action.ActionParameters; if (parameters.Length == 1 && parameters[0].Name == null) { var parameter = parameters[0]; if (parameter.Type == null) { using (var reader = new StreamReader(inputStream)) values[0] = reader.ReadToEnd(); if (parameter.Required && values[0] == null) { // ReSharper disable once NotResolvedInText throw new ArgumentNullException("[unnamed]", "Request parameter is required."); } } else { values[0] = ODataMiddleware.Read(inputStream, parameter.Type); if (parameter.Required && values[0] == null) { // ReSharper disable once NotResolvedInText throw new ArgumentNullException("[unnamed]", "Request parameter is required. Type: " + parameter.Type.FullName); } } } else { var model = await ODataMiddleware.ReadToJsonAsync(httpContext); var i = 0; foreach (var parameter in parameters) { var name = parameter.Name; var type = parameter.Type; if (type == typeof(HttpContext)) { values[i] = httpContext; } else if (type == typeof(ODataRequest)) { values[i] = odataRequest; } else { var val = model?[name]; if (val == null) { if (parameter.Required) { throw new ArgumentNullException(parameter.Name); } values[i] = Type.Missing; } else { var valStr = val.ToString(); if (type == typeof(string)) { values[i] = valStr; } else if (type == typeof(Boolean)) { // we handle "True", "true" and "1" as boolean true values values[i] = JsonConvert.DeserializeObject(valStr.ToLower(), type); } else if (type.IsEnum) { values[i] = Enum.Parse(type, valStr, true); } else { values[i] = JsonConvert.DeserializeObject(valStr, type); } } } i++; } } return(values); }
internal async Task WriteContentPropertyAsync(string path, string propertyName, bool rawValue, HttpContext httpContext, ODataRequest req, IConfiguration appConfig) { var content = ODataMiddleware.LoadContentByVersionRequest(path, httpContext); if (content == null) { ODataMiddleware.ContentNotFound(httpContext); return; } if (propertyName == ODataMiddleware.ActionsPropertyName) { var actionItems = ODataTools.GetActionItems(content, req, httpContext).ToArray(); await WriteActionsAsync(actionItems, httpContext, req); return; } if (propertyName == ODataMiddleware.ChildrenPropertyName) { await WriteChildrenCollectionAsync(path, httpContext, req) .ConfigureAwait(false); } if (content.Fields.TryGetValue(propertyName, out var field)) { if (field is ReferenceField refField) { var refFieldSetting = refField.FieldSetting as ReferenceFieldSetting; var isMultiRef = true; if (refFieldSetting != null) { isMultiRef = refFieldSetting.AllowMultiple == true; } if (isMultiRef) { await WriteMultiRefContentsAsync(refField.GetData(), httpContext, req) .ConfigureAwait(false); } else { await WriteSingleRefContentAsync(refField.GetData(), httpContext) .ConfigureAwait(false); } } else if (field is AllowedChildTypesField actField) { await WriteMultiRefContentsAsync(actField.GetData(), httpContext, req) .ConfigureAwait(false); } else if (!rawValue) { await WriteSingleContentAsync(httpContext, new ODataEntity { { propertyName, field.GetData() } }) .ConfigureAwait(false); } else { await WriteRawAsync(field.GetData(), httpContext) .ConfigureAwait(false); } } else { await WriteGetOperationResultAsync(httpContext, req, appConfig) .ConfigureAwait(false); } }