/// <summary> /// Instatiates a DomainService instance along with the DomainServiceContext. /// </summary> /// <param name="instance">Wrapper representing the instance passed to invocation.</param> /// <returns>New DomainService instance.</returns> private DomainService GetDomainService(object instance) { // Create and initialize the DomainService for this request. DomainDataServiceContractBehavior.DomainDataServiceInstanceInfo instanceInfo = (DomainDataServiceContractBehavior.DomainDataServiceInstanceInfo)instance; IServiceProvider serviceProvider = (IServiceProvider)OperationContext.Current.Host; DomainServiceContext context = new WcfDomainServiceContext(serviceProvider, this.operationType); try { DomainService domainService = DomainService.Factory.CreateDomainService(instanceInfo.DomainServiceType, context); instanceInfo.DomainServiceInstance = domainService; return(domainService); } catch (TargetInvocationException tie) { // If the exception has already been transformed to a DomainServiceException just rethrow it. if (tie.InnerException != null) { throw new DomainDataServiceException(Resource.DomainDataService_General_Error, tie.InnerException); } throw new DomainDataServiceException(Resource.DomainDataService_General_Error, tie); } catch (Exception ex) { if (ex.IsFatal()) { throw; } else { // We need to ensure that any time an exception is thrown by the service it is transformed to a // properly sanitized/configured DomainDataService exception. throw new DomainDataServiceException(Resource.DomainDataService_General_Error, ex); } } }
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_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"); } }