/// <summary> /// Helper method performs a query operation against a given proxy instance. /// </summary> /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param> /// <param name="context">The current context.</param> /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created /// <see cref="DomainServices"/> will be added to.</param> /// <param name="queryName">The name of the query to invoke.</param> /// <param name="parameters">The query parameters.</param> /// <returns>The query results. May be null if there are no query results.</returns> /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="queryName"/> is null or an empty string.</exception> /// <exception cref="InvalidOperationException">if no match query operation exists on the <paramref name="context"/>.</exception> /// <exception cref="OperationException">if operation errors are thrown during execution of the query operation.</exception> public static IEnumerable Query(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, string queryName, object[] parameters) { context = new DomainServiceContext(context, DomainOperationType.Query); DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry queryOperation = serviceDescription.GetQueryMethod(queryName); if (queryOperation == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, Resource.DomainServiceProxy_QueryOperationNotFound, queryName, domainService); throw new InvalidOperationException(errorMessage); } int totalCount; IEnumerable <ValidationResult> validationErrors; object[] parameterValues = parameters ?? new object[0]; QueryDescription queryDescription = new QueryDescription(queryOperation, parameterValues); IEnumerable result = service.Query(queryDescription, out validationErrors, out totalCount); if (validationErrors != null && validationErrors.Any()) { IEnumerable <ValidationResultInfo> operationErrors = validationErrors.Select(ve => new ValidationResultInfo(ve.ErrorMessage, ve.MemberNames)); throw new OperationException(Resource.DomainServiceProxy_OperationError, operationErrors); } return(result); }
public async Task DomainService_DirectQuery() { DomainServiceDescription description = DomainServiceDescription.GetDescription(typeof(TestDomainServices.EF.Catalog)); TestDomainServices.EF.Catalog service = new TestDomainServices.EF.Catalog(); DomainServiceContext dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew") { IsAuthenticated = true }), DomainOperationType.Query); service.Initialize(dsc); DomainOperationEntry queryOperation = description.GetQueryMethod("GetPurchaseOrders"); ServiceQuery serviceQuery = new ServiceQuery(); serviceQuery.QueryParts = new ServiceQueryPart[] { new ServiceQueryPart("where", "(it.Freight!=0)"), new ServiceQueryPart("take", "1") }; QueryResult <AdventureWorksModel.PurchaseOrder> result = await QueryProcessor.ProcessAsync <AdventureWorksModel.PurchaseOrder>(service, queryOperation, Array.Empty <object>(), serviceQuery); Assert.AreEqual(1, result.RootResults.Count()); }
public void DomainService_DirectQuery() { DomainServiceDescription description = DomainServiceDescription.GetDescription(typeof(TestDomainServices.EF.Catalog)); TestDomainServices.EF.Catalog service = new TestDomainServices.EF.Catalog(); DomainServiceContext dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew") { IsAuthenticated = true }), DomainOperationType.Query); service.Initialize(dsc); DomainOperationEntry queryOperation = description.GetQueryMethod("GetPurchaseOrders"); ServiceQuery serviceQuery = new ServiceQuery(); serviceQuery.QueryParts = new ServiceQueryPart[] { new ServiceQueryPart("where", "(it.Freight!=0)"), new ServiceQueryPart("take", "1") }; IEnumerable <ValidationResult> validationErrors; int totalCount; QueryResult <AdventureWorksModel.PurchaseOrder> result = QueryProcessor.Process <AdventureWorksModel.PurchaseOrder>(service, queryOperation, new object[0], serviceQuery, out validationErrors, out totalCount); Assert.AreEqual(1, result.RootResults.Count()); }
/// <summary> /// Helper method performs a query operation against a given proxy instance. /// </summary> /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param> /// <param name="context">The current context.</param> /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created /// <see cref="DomainServices"/> will be added to.</param> /// <param name="queryName">The name of the query to invoke.</param> /// <param name="parameters">The query parameters.</param> /// <returns>The query results. May be null if there are no query results.</returns> /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="queryName"/> is null or an empty string.</exception> /// <exception cref="InvalidOperationException">if no match query operation exists on the <paramref name="context"/>.</exception> /// <exception cref="OperationException">if operation errors are thrown during execution of the query operation.</exception> public static IEnumerable Query(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, string queryName, object[] parameters) { context = new DomainServiceContext(context, DomainOperationType.Query); DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry queryOperation = serviceDescription.GetQueryMethod(queryName); if (queryOperation == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, Resource.DomainServiceProxy_QueryOperationNotFound, queryName, domainService); throw new InvalidOperationException(errorMessage); } object[] parameterValues = parameters ?? Array.Empty <object>(); QueryDescription queryDescription = new QueryDescription(queryOperation, parameterValues); var actualMethod = s_queryGeneric.MakeGenericMethod(queryDescription.Method.AssociatedType); try { return((IEnumerable)actualMethod.Invoke(null, new object[] { service, queryDescription })); } catch (TargetInvocationException tie) when(tie.InnerException is object) { throw tie.InnerException; } }
public async Task Authorization_Custom_Authorization_On_Query() { CityDomainService cities = new CityDomainService(); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService)); DomainOperationEntry getZipsIfUser = serviceDescription.GetQueryMethod("GetZipsIfUser"); // The attribute permits only a user named mathew to access the query MockUser user = new MockUser("NotZipGuy"); MockDataService dataService = new MockDataService(user); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); // not authenticated should be denied cleanly because there is no user name Exception expectedException = null; System.Collections.IEnumerable result; try { user.IsAuthenticated = false; result = (await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfUser), CancellationToken.None)).Result; } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); Assert.AreEqual("Only one user is authorized for this query, and it isn't you.", expectedException.Message, "Expected this custom authorization deny message for non-authenticated user."); // Authenticated, but still not the right user name -- should be denied cities = new CityDomainService(); expectedException = null; user = new MockUser("NotZipGuy", new string[] { "clerk" }); user.IsAuthenticated = true; dataService = new MockDataService(user); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); try { result = (await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfUser), CancellationToken.None)) .Result; } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); Assert.AreEqual("Only one user is authorized for this query, and it isn't you.", expectedException.Message, "Expected this custom authorization deny message for authenticated user with wrong name."); // authenticated and in with the right name -- should be allowed cities = new CityDomainService(); user = new MockUser("ZipGuy"); user.IsAuthenticated = true; dataService = new MockDataService(user); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); var queryResult = await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfUser), CancellationToken.None); Assert.IsNotNull(queryResult.Result); Assert.IsNull(queryResult.ValidationErrors); Assert.IsTrue(queryResult.Result.OfType <Zip>().Any(), "Expected non-zero number of zip codes returned"); }
public async Task DomainService_InvalidOperationType() { TestDomainServices.EF.Northwind nw = new TestDomainServices.EF.Northwind(); DomainServiceContext dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew") { IsAuthenticated = true }), DomainOperationType.Submit); nw.Initialize(dsc); DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(TestDomainServices.EF.Northwind)); DomainOperationEntry entry = dsd.GetQueryMethod(nameof(TestDomainServices.EF.Northwind.GetOrderDetails)); QueryDescription qd = new QueryDescription(entry); await ExceptionHelper.ExpectExceptionAsync <InvalidOperationException>(() => { return(nw.QueryAsync <NorthwindModel.Order_Detail>(qd, CancellationToken.None).AsTask()); }, string.Format(Resource.DomainService_InvalidOperationType, DomainOperationType.Submit, DomainOperationType.Query)); InvokeDescription id = new InvokeDescription(entry, null); await ExceptionHelper.ExpectExceptionAsync <InvalidOperationException>(() => { return(nw.InvokeAsync(id, CancellationToken.None).AsTask()); }, string.Format(Resource.DomainService_InvalidOperationType, DomainOperationType.Submit, DomainOperationType.Invoke)); nw = new TestDomainServices.EF.Northwind(); dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew") { IsAuthenticated = true }), DomainOperationType.Query); nw.Initialize(dsc); ChangeSet cs = new ChangeSet(new ChangeSetEntry[] { new ChangeSetEntry() { Entity = new ServiceContext_CurrentOperation_Entity() { Key = 1 }, Operation = DomainOperation.Insert } }); await ExceptionHelper.ExpectExceptionAsync <InvalidOperationException>(async() => { await nw.SubmitAsync(cs, CancellationToken.None); }, string.Format(Resource.DomainService_InvalidOperationType, DomainOperationType.Query, DomainOperationType.Submit)); }
public async Task ServiceContext_CurrentOperation() { DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(ServiceContext_CurrentOperation_DomainService)); ServiceContext_CurrentOperation_DomainService ds; // Execute a query. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Query); DomainOperationEntry queryOp = dsd.GetQueryMethod("GetEntities"); Assert.IsNotNull(queryOp); QueryDescription desc = new QueryDescription(queryOp); var queryResult = await ds.QueryAsync <ServiceContext_CurrentOperation_Entity>(desc, CancellationToken.None); Assert.AreEqual(queryOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Invoke); DomainOperationEntry invokeOp = dsd.GetInvokeOperation("Echo"); Assert.IsNotNull(invokeOp); await ds.InvokeAsync(new InvokeDescription(invokeOp, null), CancellationToken.None); Assert.AreEqual(invokeOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an insert operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Submit); DomainOperationEntry insertOp = dsd.GetSubmitMethod(typeof(ServiceContext_CurrentOperation_Entity), DomainOperation.Insert); Assert.IsNotNull(insertOp); await ds.SubmitAsync(new ChangeSet(new ChangeSetEntry[] { new ChangeSetEntry() { Entity = new ServiceContext_CurrentOperation_Entity() { Key = 1 }, Operation = DomainOperation.Insert } }), CancellationToken.None); Assert.AreEqual(insertOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); }
public void ServiceContext_CurrentOperation() { DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(ServiceContext_CurrentOperation_DomainService)); ServiceContext_CurrentOperation_DomainService ds; IEnumerable <ValidationResult> validationErrors; // Execute a query. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Query); DomainOperationEntry queryOp = dsd.GetQueryMethod("GetEntities"); Assert.IsNotNull(queryOp); QueryDescription desc = new QueryDescription(queryOp); int totalCount; ds.Query(desc, out validationErrors, out totalCount); Assert.AreEqual(queryOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Invoke); DomainOperationEntry invokeOp = dsd.GetInvokeOperation("Echo"); Assert.IsNotNull(invokeOp); ds.Invoke(new InvokeDescription(invokeOp, null), out validationErrors); Assert.AreEqual(invokeOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an insert operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Submit); DomainOperationEntry insertOp = dsd.GetSubmitMethod(typeof(ServiceContext_CurrentOperation_Entity), DomainOperation.Insert); Assert.IsNotNull(insertOp); ds.Submit(new ChangeSet(new ChangeSetEntry[] { new ChangeSetEntry() { Entity = new ServiceContext_CurrentOperation_Entity() { Key = 1 }, Operation = DomainOperation.Insert } })); Assert.AreEqual(insertOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); }
/// <summary> /// Helper method performs a query operation against a given proxy instance. /// </summary> /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param> /// <param name="context">The current context.</param> /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created /// <see cref="DomainServices"/> will be added to.</param> /// <param name="queryName">The name of the query to invoke.</param> /// <param name="parameters">The query parameters.</param> /// <returns>The query results. May be null if there are no query results.</returns> /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="queryName"/> is null or an empty string.</exception> /// <exception cref="InvalidOperationException">if no match query operation exists on the <paramref name="context"/>.</exception> /// <exception cref="OperationException">if operation errors are thrown during execution of the query operation.</exception> public static IEnumerable Query(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, string queryName, object[] parameters) { context = new DomainServiceContext(context, DomainOperationType.Query); DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry queryOperation = serviceDescription.GetQueryMethod(queryName); if (queryOperation == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, Resource.DomainServiceProxy_QueryOperationNotFound, queryName, domainService); throw new InvalidOperationException(errorMessage); } IEnumerable <ValidationResult> validationErrors; object[] parameterValues = parameters ?? Array.Empty <object>(); QueryDescription queryDescription = new QueryDescription(queryOperation, parameterValues); // TODO: Look into removing this blocking Wait var actualMethod = s_queryAsync.MakeGenericMethod(queryDescription.Method.AssociatedType); var queryResult = ((ValueTask <ServiceQueryResult>)actualMethod.Invoke(service, new object[] { queryDescription, CancellationToken.None })) .GetAwaiter().GetResult(); validationErrors = queryResult.ValidationErrors; var result = queryResult.Result; if (validationErrors != null && validationErrors.Any()) { IEnumerable <ValidationResultInfo> operationErrors = validationErrors.Select(ve => new ValidationResultInfo(ve.ErrorMessage, ve.MemberNames)); throw new OperationException(Resource.DomainServiceProxy_OperationError, operationErrors); } return(result); }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { DomainServiceDescription description = DomainServiceDescription.GetDescription(endpoint.Contract.ContractType); ServiceMetadataGenerator.GenerateEntitiesMetadataJsonMap(description); foreach (OperationDescription od in endpoint.Contract.Operations) { foreach (IOperationBehavior behavior in od.Behaviors) { Type behaviorType = behavior.GetType(); if (behaviorType.IsGenericType && behaviorType.GetGenericTypeDefinition().Equals(typeof(QueryOperationBehavior <>))) { IDispatchMessageFormatter innerFormatter = endpointDispatcher.DispatchRuntime.Operations[od.Name].Formatter; endpointDispatcher.DispatchRuntime.Operations[od.Name].Formatter = new ServiceMetadataQueryOperationMessageFormatter(innerFormatter, DomainOperationType.Query, description.GetQueryMethod(od.Name).ReturnType); } } } }
public async Task Authorization_Custom_Authorization_On_Invoke() { // Specifically, the City data is marked so that no one can delete a Zip code // from WA unless their user name is WAGuy MockUser notWaGuy = new MockUser("notWAGuy"); notWaGuy.IsAuthenticated = true; DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService)); DomainOperationEntry invokeOperation = serviceDescription.GetInvokeOperation("GetStateIfUser"); Assert.IsNotNull(invokeOperation, "Could not locate GetStateIfUser Invoke operation"); DomainOperationEntry getCitiesQuery = serviceDescription.GetQueryMethod("GetCities"); City city = null; // Execute a query to get a City from WA using (CityDomainService cities = new CityDomainService()) { // Now prepare for a query to find a Zip in WA DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Query); cities.Initialize(ctxt); IEnumerable result = (await cities.QueryAsync <City>(new QueryDescription(getCitiesQuery), CancellationToken.None)).Result; city = result.OfType <City>().FirstOrDefault(z => z.StateName == "WA"); Assert.IsNotNull(city, "Could not find a city in WA"); } // Perform an invoke against a method that has a custom auth attribute requiring WaGuy // where the user is something else -- should be denied using (CityDomainService cities = new CityDomainService()) { // Prepare an invoke to call a method that has a custom auth attribute DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Invoke); cities.Initialize(ctxt); // verify that even top level exceptions go through // the OnError handler UnauthorizedAccessException expectedException = null; try { // cause a domain service not initialized exception await cities.InvokeAsync(new InvokeDescription(invokeOperation, new object[] { city }), CancellationToken.None); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException, "Expected Invoke to be denied"); Assert.AreEqual("Access to operation 'GetStateIfUser' was denied.", expectedException.Message); } // Perform an invoke against a method that has a custom auth attribute requiring WaGuy // where the user is correct -- should be allowed using (CityDomainService cities = new CityDomainService()) { MockUser waGuy = new MockUser("WAGuy"); waGuy.IsAuthenticated = true; // Prepare an invoke to call a method that has a custom auth attribute DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(waGuy), DomainOperationType.Invoke); cities.Initialize(ctxt); // verify that even top level exceptions go through // the OnError handler UnauthorizedAccessException expectedException = null; try { // cause a domain service not initialized exception await cities.InvokeAsync(new InvokeDescription(invokeOperation, new object[] { city }), CancellationToken.None); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNull(expectedException, "Expected Invoke to be allowed"); } }
public async Task Authorization_MockUser() { CityDomainService cities = new CityDomainService(); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService)); DomainOperationEntry getZipsIfAuthenticated = serviceDescription.GetQueryMethod("GetZipsIfAuthenticated"); DomainOperationEntry getZipsIfInRole = serviceDescription.GetQueryMethod("GetZipsIfInRole"); // Validate a null principal is denied MockUser user = null; MockDataService dataService = new MockDataService(user); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); Exception expectedException = null; ServiceQueryResult <Zip> result; try { result = await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfAuthenticated), CancellationToken.None); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); Assert.AreEqual("Access to operation 'GetZipsIfAuthenticated' was denied.", expectedException.Message, "Expected standard deny message for null principal"); // Validate a non-authenticated user is denied user = new MockUser("mathew"); dataService = new MockDataService(user); cities = new CityDomainService(); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); expectedException = null; try { user.IsAuthenticated = false; result = await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfAuthenticated), CancellationToken.None); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); // we're authenticated, so this should succeed expectedException = null; user.IsAuthenticated = true; result = await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfAuthenticated), CancellationToken.None); Assert.IsNotNull(result.Result); // authenticated, but not in role, so we should fail cities = new CityDomainService(); expectedException = null; user = new MockUser("mathew", new string[] { "clerk" }); user.IsAuthenticated = true; dataService = new MockDataService(user); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); try { result = await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfInRole), CancellationToken.None); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); // authenticated and in role, so we should succeed cities = new CityDomainService(); user = new MockUser("mathew", new string[] { "manager" }); user.IsAuthenticated = true; dataService = new MockDataService(user); cities.Initialize(new WcfDomainServiceContext(dataService, DomainOperationType.Query)); result = await cities.QueryAsync <Zip>(new QueryDescription(getZipsIfInRole), CancellationToken.None); Assert.IsNotNull(result); }
public async Task Authorization_Custom_Authorization_On_Custom_Update() { // Specifically, the City data is marked so that no one can delete a Zip code // from WA unless their user name is WAGuy MockUser notWaGuy = new MockUser("notWAGuy"); notWaGuy.IsAuthenticated = true; DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService)); City city = null; // Execute a query to get a City from WA using (CityDomainService cities = new CityDomainService()) { DomainOperationEntry getCitiesQuery = serviceDescription.GetQueryMethod("GetCities"); // Now prepare for a query to find a Zip in WA DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Query); cities.Initialize(ctxt); IEnumerable result = (await cities.QueryAsync <City>(new QueryDescription(getCitiesQuery), CancellationToken.None)).Result; city = result.OfType <City>().FirstOrDefault(z => z.StateName == "WA"); Assert.IsNotNull(city, "Could not find a city in WA"); } using (CityDomainService cities = new CityDomainService()) { // Now prepare for a submit to invoke AssignCityZoneIfAuthorized as a named update method DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Submit); cities.Initialize(ctxt); // Prepare an attempt to delete this with a user whose name is not WAGuy // This should fail due to a custom auth attribute List <ChangeSetEntry> entries = new List <ChangeSetEntry>(); ChangeSetEntry entry = new ChangeSetEntry(); entry.DomainOperationEntry = serviceDescription.GetCustomMethod(typeof(City), "AssignCityZoneIfAuthorized"); entry.EntityActions = new EntityActionCollection { { "AssignCityZoneIfAuthorized", new object[] { "SomeZone" } } }; entry.Operation = DomainOperation.Update; entry.Entity = city; entries.Add(entry); UnauthorizedAccessException exception = null; try { await ChangeSetProcessor.ProcessAsync(cities, entries); } catch (UnauthorizedAccessException ex) { exception = ex; } Assert.IsNotNull(exception, "Expected failure attempting to perform custom method on WA with inappropriate user name"); Assert.AreEqual("Only one user is authorized to execute operation 'AssignCityZoneIfAuthorized', and it isn't you.", exception.Message); } // Now do that again but with a user who is WAGuy -- it should succeed using (CityDomainService cities = new CityDomainService()) { MockUser waGuy = new MockUser("WAGuy"); waGuy.IsAuthenticated = true; // Now prepare for a submit to invoke AssignCityZoneIfAuthorized as a named update method DomainServiceContext ctxt = new WcfDomainServiceContext(new MockDataService(waGuy), DomainOperationType.Submit); cities.Initialize(ctxt); // Prepare an attempt to delete this with a user whose name is not WAGuy // This should fail due to a custom auth attribute // Prepare a submit to call the AssignCityZoneIfAuthorized with an unauthorized user List <ChangeSetEntry> entries = new List <ChangeSetEntry>(); ChangeSetEntry entry = new ChangeSetEntry(); entry.DomainOperationEntry = serviceDescription.GetCustomMethod(typeof(City), "AssignCityZoneIfAuthorized"); entry.EntityActions = new EntityActionCollection { { "AssignCityZoneIfAuthorized", new object[] { "SomeZone" } } }; entry.Operation = DomainOperation.Update; entry.Entity = city; entries.Add(entry); Exception exception = null; try { await ChangeSetProcessor.ProcessAsync(cities, entries); } catch (UnauthorizedAccessException ex) { exception = ex; } Assert.IsNull(exception, "Expected success attempting to delete a zip from WA with inappropriate user name"); } }
public async Task Authorization_Custom_Authorization_On_CUD() { // Specifically, the City data is marked so that no one can delete a Zip code // from WA unless their user name is WAGuy MockUser notWaGuy = new MockUser("notWAGuy"); notWaGuy.IsAuthenticated = true; DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService)); Zip zip = null; // First execute a query to get some zips DomainOperationEntry getZipsQuery = serviceDescription.GetQueryMethod("GetZips"); DomainServiceContext ctxt; using (CityDomainService cities = new CityDomainService()) { // Now prepare for a query to find a Zip in WA ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Query); cities.Initialize(ctxt); IEnumerable result = (await cities.QueryAsync <Zip>(new QueryDescription(getZipsQuery), CancellationToken.None)).Result; zip = result.OfType <Zip>().FirstOrDefault(z => z.StateName == "WA"); Assert.IsNotNull(zip, "Could not find a zip code in WA"); } // Prepare a submit to delete this zip from a user who is not authorized using (CityDomainService cities = new CityDomainService()) { // Now prepare for a query to find a Zip in WA ctxt = new WcfDomainServiceContext(new MockDataService(notWaGuy), DomainOperationType.Submit); cities.Initialize(ctxt); // Prepare an attempt to delete this with a user whose name is not WAGuy // This should fail due to a custom auth attribute List <ChangeSetEntry> entries = new List <ChangeSetEntry>(); ChangeSetEntry entry = new ChangeSetEntry(1, zip, zip, DomainOperation.Delete); entries.Add(entry); UnauthorizedAccessException exception = null; try { await ChangeSetProcessor.ProcessAsync(cities, entries); } catch (UnauthorizedAccessException ex) { exception = ex; } Assert.IsNotNull(exception, "Expected failure attempting to delete a zip from WA with inappropriate user name"); Assert.AreEqual("Only one user can delete zip codes from that state, and it isn't you.", exception.Message); } // Now do that again but with a user who is WAGuy -- it should succeed using (CityDomainService cities = new CityDomainService()) { MockUser waGuy = new MockUser("WAGuy"); waGuy.IsAuthenticated = true; // Now try a submit where the user *is* Mathew to validate we succeed ctxt = new WcfDomainServiceContext(new MockDataService(waGuy), DomainOperationType.Submit); cities.Initialize(ctxt); List <ChangeSetEntry> entries = new List <ChangeSetEntry>(); ChangeSetEntry entry = new ChangeSetEntry(1, zip, zip, DomainOperation.Delete); entries.Add(entry); Exception exception = null; try { await ChangeSetProcessor.ProcessAsync(cities, entries); } catch (UnauthorizedAccessException ex) { exception = ex; } Assert.IsNull(exception, "Expected success attempting to delete a zip from WA with inappropriate user name"); } }
public void Authorization_MockUser() { int count; CityDomainService cities = new CityDomainService(); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(CityDomainService)); DomainOperationEntry getZipsIfAuthenticated = serviceDescription.GetQueryMethod("GetZipsIfAuthenticated"); DomainOperationEntry getZipsIfInRole = serviceDescription.GetQueryMethod("GetZipsIfInRole"); // Validate a null principal is denied MockUser user = null; MockDataService dataService = new MockDataService(user); cities.Initialize(new DomainServiceContext(dataService, DomainOperationType.Query)); Exception expectedException = null; System.Collections.IEnumerable result; IEnumerable <ValidationResult> validationErrors = null; try { result = cities.Query(new QueryDescription(getZipsIfAuthenticated), out validationErrors, out count); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); Assert.IsNull(validationErrors); Assert.AreEqual("Access to operation 'GetZipsIfAuthenticated' was denied.", expectedException.Message, "Expected standard deny message for null principal"); // Validate a non-authenticated user is denied user = new MockUser("mathew"); dataService = new MockDataService(user); cities = new CityDomainService(); cities.Initialize(new DomainServiceContext(dataService, DomainOperationType.Query)); expectedException = null; validationErrors = null; try { user.IsAuthenticated = false; result = cities.Query(new QueryDescription(getZipsIfAuthenticated), out validationErrors, out count); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); Assert.IsNull(validationErrors); // we're authenticated, so this should succeed expectedException = null; user.IsAuthenticated = true; result = cities.Query(new QueryDescription(getZipsIfAuthenticated), out validationErrors, out count); Assert.IsNotNull(result); Assert.IsNull(validationErrors); // authenticated, but not in role, so we should fail cities = new CityDomainService(); expectedException = null; user = new MockUser("mathew", new string[] { "clerk" }); user.IsAuthenticated = true; dataService = new MockDataService(user); cities.Initialize(new DomainServiceContext(dataService, DomainOperationType.Query)); try { result = cities.Query(new QueryDescription(getZipsIfInRole), out validationErrors, out count); } catch (UnauthorizedAccessException e) { expectedException = e; } Assert.IsNotNull(expectedException); Assert.IsNull(validationErrors); // authenticated and in role, so we should succeed cities = new CityDomainService(); expectedException = null; user = new MockUser("mathew", new string[] { "manager" }); user.IsAuthenticated = true; dataService = new MockDataService(user); cities.Initialize(new DomainServiceContext(dataService, DomainOperationType.Query)); result = cities.Query(new QueryDescription(getZipsIfInRole), out validationErrors, out count); Assert.IsNotNull(result); Assert.IsNull(validationErrors); }