I have two questions related to WCF Data Service:
is there a way to restrict the entities visible to a user according to her privileges ? For instance user in role super-user should be able to query the full 'Contact' entity but user with less privileges would only be able to see specific properties of the 'Contact' entity.
whenever a user runs a query on the service, I would like this to be logged in a database for audit purpose. Is this possible ?
1) There is the concept of interceptors: http://msdn.microsoft.com/en-us/library/dd744842.aspx
But I think they won't satisfy you in your case:
With change interceptors you can handle requests which try to change a specific entity. This could help you to avoid users without certain privileges to add/change/delete contact entities. With QueryInterceptors you can handle GET-Requests. But they don't allow you to restrict certain properties of your contact entity.
You are not the first with such requirements -> WCF Dataservice - modify object before returning results?
Maybe you could use a combination of a (custom) ServiceOperation and a View to handle this.
2) Yes, you can do this for instance by handling the ProcessingRequest-Event:
public class YourService : DataService<Entities>
{
/// <summary>
/// The logger.
/// </summary>
private readonly LogWriter logger;
/// <summary>
/// Initializes a new instance of the <see cref="YourService"/> class.
/// </summary>
public YourService()
{
this.logger = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
this.ProcessingPipeline.ProcessingRequest += this.ProcessingPipelineProcessingRequest;
}
/// <summary>
/// OnProcessingRequest
/// </summary>
/// <param name="sender">source</param>
/// <param name="e">event args</param>
public void ProcessingPipelineProcessingRequest(object sender, DataServiceProcessingPipelineEventArgs e)
{
this.logger.Write(new LogEntry { Message = "SOP ProcessingPipelineProcessingRequest: Unauthorized Access", Severity = TraceEventType.Warning })
}
}
You can find all those ProcessingPipeline-Events here: http://msdn.microsoft.com/en-us/library/system.data.services.dataserviceprocessingpipeline(v=vs.103).aspx
Related
I have been developing a asp.net core razor application and I have stuck to using views and models. However, I added a frontend framework so making HTTP request is used quite often so I thought I would test out the Web API in asp.net core by adding a controller and it is awesome how easy it is to pass usable json arrays to the frontend. My issue is I implemented the following code to my razor application's startup.cs to restrict any non logged in users from accessing any other pages or page models unless logged in:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(cookieOptions => {
cookieOptions.Cookie.Name = "UserLoginCookie";
cookieOptions.LoginPath = "/Login/";
cookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(30);
cookieOptions.SlidingExpiration = true;
});
This works great except the issue I am finding is my test HomeController is still accessible (url/home/index) even if I am not logged in. Is there a way to use the identity authentication I used for my razor pages to restrict access to the controller for only logged in users. Also, for an extra layer of security I wanted to store a variable server side for the logged in user's ID and integrated that into the controller so i can limit my queries to that user without letting it be a HTTP parameter which could then allow anyone to access other users data.
Adding [Authorize] above the homecontroller class did the trick but not sure why I was required to use this tag to make it work.
If you add [Authorize] on the whole controller it will prevent all the methods in that class to be accessible. Requires the specified authorization
In this case the CookieAuthenticationDefaults.
If you have more than one you can specify the name of the policy you want it to check for
[Authorize(Roles = "Administrator")]
Here is the AuthorizeAttribute class for more information
using System;
namespace Microsoft.AspNetCore.Authorization
{
/// <summary>
/// Specifies that the class or method that this attribute is applied to requires the
specified authorization.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple =true,
Inherited = true)]
public class AuthorizeAttribute : Attribute, IAuthorizeData
{
/// <summary>
/// Initializes a new instance of the <see cref="AuthorizeAttribute"/> class with
the specified policy.
/// </summary>
/// <param name="policy">The name of the policy to require for authorization.</param>
public AuthorizeAttribute(string policy)
{
Policy = policy;
}
/// <summary>
/// Gets or sets the policy name that determines access to the resource.
/// </summary>
public string? Policy { get; set; }
/// <summary>
/// Gets or sets a comma delimited list of roles that are allowed to access the resource.
/// </summary>
public string? Roles { get; set; }
/// <summary>
/// Gets or sets a comma delimited list of schemes from which user information is constructed.
/// </summary>
public string? AuthenticationSchemes { get; set; }
}
}
Is it not possible to target different logging providers based on which logger is used?
For example, refer to the below code:
// Establish loggers
var someLogger = loggerFactory.CreateLogger("SomeLogger");
var anotherLogger = loggerFactory.CreateLogger("AnotherLogger");
// Hook up providers (but not at the individual logger's level??)
loggerFactory.AddDebug(minimumLevel: LogLevel.Debug);
loggerFactory.AddConsole(minimumLevel: LogLevel.Debug);
loggerFactory.AddBlob(connectionString, minimumLevel: LogLevel.Information);
// Log stuff
someLogger.LogError("Logging with someLogger");
anotherLogger.LogError("Logging with anotherLogger");
All providers will be logged too here, regardless of which logger is used.
Is this really not possible? What is the point of defining separate loggers if they all log to every provider regardless?
I'm not sure if that's possible but what you can do is log messages of different log levels to different providers. The example below logs all warning level messages and above to the event log using the SourceSwitch API. The use case here which may satisfy your needs is that you may not want information or debug messages filling up your event log.
private static void ConfigureLogging(ILoggerFactory loggerFactory)
{
var sourceSwitch = new SourceSwitch("EventLog");
sourceSwitch.Level = SourceLevels.Warning;
loggerFactory.AddTraceSource(sourceSwitch, new EventLogTraceListener("Application"));
}
UPDATE
ASP.NET 5 is very light on examples at the moment but the AddProvider method on ILoggerFactory is used to add it's own custom providers specific to it:
/// <summary>
/// Used to create logger instances of the given name.
/// </summary>
public interface ILoggerFactory : IDisposable
{
/// <summary>
/// The minimum level of log messages sent to registered loggers.
/// </summary>
LogLevel MinimumLevel { get; set; }
/// <summary>
/// Creates a new ILogger instance of the given name.
/// </summary>
/// <param name="categoryName"></param>
/// <returns></returns>
ILogger CreateLogger(string categoryName);
void AddProvider(ILoggerProvider provider);
}
So you could create another ILoggerFactory but register different providers to it. Then inject the right ILoggerFactory into your classes depending on where you want to log to.
I am using the WebApi Help pages within an MVC4 project.
As per the following link, http://blogs.msdn.com/b/yaohuang1/archive/2012/10/13/asp-net-web-api-help-page-part-2-providing-custom-samples-on-the-help-page.aspx I have been setting the HelpPageConfig to set actual response types.
I have a controller that has two get methods on it
/// <summary>
/// Get the list of plans for a specified portfolio
/// </summary>
/// <param name="portfolioIdentifier">Portfolio Identifier (guid)</param>
/// <returns>
/// Returns a list of <see cref="RestDTOs.Plan"/> Plan objects
/// </returns>
public HttpResponseMessage Get(Guid portfolioIdentifier)
{
}
/// <summary>
/// Get full plan details.
/// </summary>
/// <param name="planIdentifier">Plan Identifier (guid)</param>
/// <returns>
/// Returns the <see cref="RestDTOs.Plan"/> Plan object
/// </returns>
[HttpGet]
public HttpResponseMessage Detail(Guid planIdentifier)
{
}
Within HelpPageConfig.cs i have added the following to try and set an example ResponseBody format
config.SetActualResponseType(typeof(Plan), "Plan", "GET");
This is working great on the Get method, but is not producing anything on the Detail method
What do I need to add to the HelpPageConfig so that the web api help will pick up and produce samples for the Detail method
MVC 5 has a built in attribute to set the response type.
More information here:
http://thesoftwaredudeblog.wordpress.com/2014/01/05/webapi-2-helppage-using-responsetype-attribute-instead-of-setactualresponsetype/
Just use:
ResponseType(typeof([Your_Class]))]
Try config.SetActualResponseType(typeof(Plan), "Plan", "Detail");...the second parameter here is expecting an action name...I see you are using Web API 1, so just FYI...in Web API 2, there is an attribute called ResponseType which you can use to decorate on an action to describe the actual response type for a given action..
I'm working on an application which should validate the model based on some metadata saved in a database. The purpose of this is to allow administrators change how some models are validated, without changing the code, depending on clients' preferences. The changes are applied for the entire application, not for specific users accessing it. How it is changed, doesn't matter at the moment. They could be modified directly on the database, or using an application. The idea is that they should be customizable.
Let's say i have the model "Person" with the property "Name" of type "string".
public class Person
{
public string Name { get; set; }
}
This model is used by my app which is distributed and istalled on several servers. Each of them is independent. Some users may want the Name to have maximum 30 letters and to be required when creating a new "Person", others may want it to have 25 and not to be required. Normally, this would be solved using data annotations, but those are evaluated during the compile time and are somehow "hardcoded".
Shortly, I want to find a way to customize and store in a database how the model validates, without the need of altering the application code.
Also, it would be nice to work with jquery validation and have as few request to database(/service) as possible. Besides that, i can't use any known ORM like EF.
You could create a custom validation attribute that validates by examining the metadata stored in the database. Custom validation attributes are easy to create, simply extend System.ComponentModel.DataAnnotations.ValidationAttribute and override the IsValid() method.
To get the client side rules that work with jQuery validation you will need to create a custom adapter for the type of your custom validation attribute that extends System.Web.Mvc.DataAnnotationsModelValidator<YourCustomValidationAttribute>. This class then needs to be registered in the OnApplicationStart() method of your Global.asax.
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(YourCustomValidationAttribute), typeof(YourCustomAdapter));
Here's an example adapter:
public class FooAdapter : DataAnnotationsModelValidator<FooAttribute>
{
/// <summary>
/// This constructor is used by the MVC framework to retrieve the client validation rules for the attribute
/// type associated with this adapter.
/// </summary>
/// <param name="metadata">Information about the type being validated.</param>
/// <param name="context">The ControllerContext for the controller handling the request.</param>
/// <param name="attribute">The attribute associated with this adapter.</param>
public FooAdapter(ModelMetadata metadata, ControllerContext context, FooAttribute attribute)
: base(metadata, context, attribute)
{
_metadata = metadata;
}
/// <summary>
/// Overrides the definition in System.Web.Mvc.ModelValidator to provide the client validation rules specific
/// to this type.
/// </summary>
/// <returns>The set of rules that will be used for client side validation.</returns>
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return new[] { new ModelClientValidationRequiredRule(
String.Format("The {0} field is invalid.", _metadata.DisplayName ?? _metadata.PropertyName)) };
}
/// <summary>
/// The metadata associated with the property tagged by the validation attribute.
/// </summary>
private ModelMetadata _metadata;
}
This may also be useful if you would like to asynchronously call server side validation http://msdn.microsoft.com/en-us/library/system.web.mvc.remoteattribute(v=vs.108).aspx
We're using NServiceBus to perform document processing for a number of tenants.
Each tenant has their own database and we're using NHibernate for data access. In the web application we're using our IoC tool (StructureMap) to handle session management. Essentially we maintain a session factory for each tenant. We're able to identify the tenant from HttpContext.
When we kick off document processing using NServiceBus we have access to the tenant identifier. We need this tenant id to be available throughout the processing of the document (we have 2 sagas and fire off a number of events).
We would need to create a NHibernate SessionFactory for each tenant so would need some way of obtaining the tenant id when we configure StructureMap.
I've seen a few posts suggesting to use a message header to store the tenant identifier but am unsure how to:
Set a message header when we first submit a document (sending a SubmitDocumentCommand)
Reference the header when we configure StructureMap
Access the header within our sagas/handlers
Ensure the header flows from one message to the next. When we send a SubmitDocumentCommand it is handled by the DocumentSubmissionSaga. If the submission succeeds we will send off a DocumentSubmittedEvent. We'd want to make sure the tenant id is available at all points in the process.
I believe with this information I can successfully implement multitenancy with NHibernate but anything more specific to this scenario would be appreciated.
You can flow the header using a message mutator that registers itself: Here is a quick example from my own code. And you can always use Bus.CurrentMessageContext.Headers to set/get to the header anywhere...
Hope this helps :)
/// <summary>
/// Mutator to set the channel header
/// </summary>
public class FlowChannelMutator : IMutateOutgoingTransportMessages, INeedInitialization
{
/// <summary>
/// The bus is needed to get access to the current message context
/// </summary>
public IBus Bus { get; set; }
/// <summary>
/// Keeps track of the channel
/// </summary>
/// <param name="messages"></param>
/// <param name="transportMessage"></param>
public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
{
if (Bus.CurrentMessageContext != null &&
Bus.CurrentMessageContext.Headers.ContainsKey("x-messagehandler-channel"))
{
if (!transportMessage.Headers.ContainsKey("x-messagehandler-channel"))
{
transportMessage.Headers["x-messagehandler-channel"] =
Bus.CurrentMessageContext.Headers["x-messagehandler-channel"];
}
}
}
/// <summary>
/// Initializes
/// </summary>
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<FlowChannelMutator>(DependencyLifecycle.InstancePerCall);
}
}