Authenticated User and Service Layer - asp.net-mvc

I have a MVC 4 application which uses a Service Layer in a different class library.
Some of the calls to that service layer needs to know which uses is requesting the data.
The data records is different depending on the User Roles.
For Prevent Coupling Issue, Should I pass the username in the request (HttpContext.User.Identity.Name) or should I access it directly on the service layer using the same HttpContext.User.Identity.Name .
I am never sure if I should hide the HttpContext from the service layer.

Simply pass the currently authenticated user as parameter to your service layer. Never use HttpContext.User.Identity.Name in your service layer.
For example:
[Authorize]
public ActionResult SomeAction()
{
string user = User.Identity.Name;
this.someService.SomeOperation(user);
...
}
Your service layer should never be tied to an HttpContext.

Passing HttpContext to the service layer may look tempting, but would be a bad choice. It would make a hard link between ASP.net runtime services and the business logic (this is exactly what you are trying to avoide, i assume). The best would be to create class to represent the logged in user, which you can populate in a base controller and pass that on to the service layer.
This way, you get best of both worlds

Related

Global Variable over Layers on MVC API

We are building a MVC API + Entity project, right now we are creating our log layer, we wanna log every single entity that we add, alter or delete, however we need to log the user id that is performing the action as well, the id is provided with the Header [Authorization].
Our log is performed as the action previous to the database action, because of that we would need to add the user id to every method signature on all layers until the DAL.
After researching a bit on the internet, looking at Global Variables, HTTPContext, etc, we did not find any solution that did not "harm" the project layers, any ideias ? How should we proceed ?
You could use DI to inject the current user into whatever DAL classes need it. For example, I use Ninject to do this so I don't need to have the user id as a parameter on every update function:
kernel.Bind<IPrincipal>().ToMethod(c => HttpContext.Current.User);
Then in whatever classes in the app need it:
[Inject]
public IPrincipal CurrentUser { get; set; }

MVC with WCF service design

Being new to MVC, and WCF (somewhat), I'd like to ask a design question. I have an MVC application, with a simple screen. I need to call a WCF service, which returns a reply object type. To separate the WCF calls from my MVC app, I have created a ServiceProxy dll, which exposes a method called RegisterWithService, passing it an IP address.
So, MVC app, calls
ServiceProxy.RegisterWithService(xxx.xxx.xxx.xxx);
The method then creates a RegistrationRequest object, and sends that to the WCF service. The reply (a RegisterResponce object) replies with an object.
My question is, is it OK to pass that object back to the MVC controller to deal with, or should I create some form of DTO... so that the ServiceProxy creates a new object type (maybe, RegistrationDTO, which has the same fields as the WCF reply object, and passes that back to the MVC app? That, I guess, makes the MVC non-reliant on the WCF objects... so a change in the service contract would only cause a change in the proxy class I created - leaving the MVC app segregated.
Does that seem like a good design?
I think that 2 levels of objects are enough:
Domain models (coming from your WCF service)
View models (specific to the MVC application)
So you could use the service proxy interface that was generated for you when you imported the WCF service definition as repository layer. This interface will return your data contracts which will represent the domain models. The Controller will be responsible for calling various methods on this interface and mapping the domain models to view models that will be passed to the view.
For example:
public class HomeController: Controller
{
private readonly IServiceProxy service;
public HomeController(IServiceProxy service)
{
this.service = service;
}
public ActionResult Index(int id)
{
SomeDataContract domainModel = this.service.Get(id);
MyViewModel model = Mapper.Map<SomeDataContract, MyViewModel>(domainModel);
return View(model);
}
}
Of course if your application gets more complex you could introduce an additional abstraction layer and DTOs.

Obtaining the current Principal outside of the Web tier

I have the following ntier app: MVC > Services > Repository > Domain. I am using Forms authentication. Is it safe to use Thread.CurrentPrincipal outside of my MVC layer to get the currently logged in user of my application or should I be using HttpContext.Current.User?
The reason I ask is there seems to be some issues around Thread.CurrentPrincipal, but I am cautious to add a reference to System.Web outside of my MVC layer in case I need to provide a non web font end in the future.
Update
I have been following the advice recieved so far to pass the username into the Service as part of the params to the method being called and this has lead to a refinement of my original question. I need to be able to check if the user is in a particular role in a number of my Service and Domain methods. There seems to be a couple of solutions to this, just wondering which is the best way to proceed:
Pass the whole HttpContext.Current.User as a param instead of just the username.
Call Thread.CurrentPrincipal outside of my web tier and use that. But how do I ensure it is equal to HttpContext.Current.User?
Stick to passing in the username as suggested so far and then use Roles.IsUserInRole. The problem with this approach is that it requires a ref to System.Web which I feel is not correct outside of my MVC layer.
How would you suggest I proceed?
I wouldn't do either, HttpContext.Current.User is specific to your web layer.
Why not inject the username into your service layer?
Map the relevant User details to a new Class to represent the LoggedInUser and pass that as an argument to your Business layer method
public class LoggedInUser
{
public string UserName { set;get;}
//other relevant proerties
}
Now set the values of this and pass to your BL method
var usr=new LoggedInUser();
usr.UserName="test value "; //Read from the FormsAuthentication stuff and Set
var result=YourBusinessLayerClass.SomeOperation(usr);
You should abstract your user information so that it doesn't depend on Thread.CurrentPrincipal or HttpContext.Current.User.
You could add a constructor or method parameter that accepts a user name, for example.
Here's an overly simplified example of a constructor parameter:
class YourBusinessClass
{
string _userName;
public YourBusinessClass(string userName)
{
_userName = userName;
}
public void SomeBusinessMethodThatNeedsUserName()
{
if (_userName == "sally")
{
// do something for sally
}
}
}
I prefer option number 2( use Thread.CurrentPrincipal outside of web tier ). since this will not polute your service tier & data tier methods. with bonuses: you can store your roles + additional info in the custom principal;
To make sure Thread.CurrentPrincipal in your service and data tier is the same as your web tier; you can set your HttpContext.Current.User (Context.User) in Global.asax(Application_AuthenticateRequest). Other alternative location where you can set this are added at the bottom.
sample code:
//sample synchronizing HttpContext.Current.User with Thread.CurrentPrincipal
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
//make sure principal is not set for anonymous user/unauthenticated request
if (authCookie != null && Request.IsAuthenticated)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
//your additional info stored in cookies: multiple roles, privileges, etc
string userData = authTicket.UserData;
CustomPrincipal userPrincipal = PrincipalHelper.CreatePrincipal(authTicket.Name, authTicket.UserData, Request.IsAuthenticated);
Context.User = userPrincipal;
}
}
of course first you must implement your login form to create authorization cookies containing your custom principal.
Application_AuthenticateRequest will be executed for any request to server(css files, javascript files, images files etc). To limit this functionality only to controller action, you can try setting the custom principal in ActionFilter(I haven't tried this). What I have tried is setting this functionality inside an Interceptor for Controllers(I use Castle Windsor for my Dependency Injection and Aspect Oriented Programming).
I believe you are running into this problem because you need to limit your domains responsibility further. It should not be the responsibility of your service or your document to handle authorization. That responsibility should be handled by your MVC layer, as the current user is logged in to your web app, not your domain.
If, instead of trying to look up the current user from your service, or document, you perform the check in your MVC app, you get something like this:
if(Roles.IsUserInRole("DocumentEditorRole")){
//UpdateDocument does NOT authorize the user. It does only 1 thing, update the document.
myDocumentService.UpdateDocument(currentUsername, documentToEdit);
} else {
lblPermissionDenied.InnerText = #"You do not have permission
to edit this document.";
}
which is clean, easy to read, and allows you to keep your services and domain classes free from authorization concerns. You can still map Roles.IsUserInRole("DocumentEditorRole")to your viewmodel, so the only this you are losing, is the CurrentUserCanEdit method on your Document class. But if you think of your domain model as representing real world objects, that method doesn't belong on Document anyway. You might think of it as a method on a domain User object (user.CanEditDocument(doc)), but all in all, I think you will be happier if you keep your authorization out of your domain layer.

What to return from service to ASP MVC web app?

Right now I have an ASP MVC web application along a Models project, a Service project, an Utilities project, and a few Datastores projects that function as repository for one or more domain models. I'm pretty happy with the separation of each layer but I'm stuck on what to return from service layer to the web app.
For example, when a user try to register, a RegisterViewModel is received by the controller. Individual pieces (email, password, etc.) are send to service layer which construct the Member domain object with guid, status, createdate, etc., send it to repository for storage and finally return the Member object for the web app to redirect to /Member/{guid}.
But how should the service layer inform the web app if an email already exists? In a more complex situation I may have to check the existence/validity of multiple domain objects and business rules so would have to return multiple errors in one go. In addition, I don't want exception to bubble to the web layer so service layer traps all exceptions but need to notify the web layer some how.
Even if I find a way to return all that, the web layer would be burdened to process all that and provide user various feedback. The controller code would be bulky and error prune. Is there a best practice on service result to the presentation? Should I eliminate separate service layer and have the code inside controller? Any thoughts are welcomed.
I wrote the operation model library for this purpose, which allows you to write code like this:
public OperationResult Register(RegisterInput input) {
var errors = new ErrorBuilder();
if (errors.NotValid(input) // Invoke DataAnnotations validation
|| errors.Not(this.repo.FindUserByEmail(input.Email) == null, "Email '{0}' already exists.", () => input.Email))
return errors;
// Do stuff
return HttpStatusCode.OK;
}
...and in the controller the error messages are copied to ModelState:
[HttpPost]
public ActionResult Register(RegisterInput input) {
var result = this.service.Register(input);
if (result.IsError)
return View().WithErrors(result);
// Do stuff
}
Check out the source code of the MvcAccount project which is written using this pattern.
First of all you need to decide if you are writing service layer for distribution purposes or not.
If you are not planning to distribute the service layer to a different process/machine,
Create a Message class
Create an array of message classes and store it in
HttpContext.Items
Now add any new message in any layer in to that array
consume it in the views/controller
HttpContext.Items is available for the life time of the request and you can use it all the way up to views.
If you use a DI framework you can achieve the same by using a request per life time object.
If you want to distribute the object nothing wrong in throwing the exceptions from your service layer.

asp.net mvc authentication against shibboleth and authorization

Where do I get information about the currently connected user? That is, how does shibboleth pass the information?
Can I set some restrictions on actions using [Authorize] attribute based on data acquired from shibboleth?
Shibboleth publishes user attributes associated with
sessions into HTTP request headers, based on header names defined
in Attribute Acceptance Policy (1.3.x) or Attribute Mapping (2.x)
files. These headers are transformed into CGI variables based
on mapping rules defined by the CGI specification.
You should be aware of this security advisory:
http://shibboleth.net/community/advisories/secadv_20090615.txt
I have never user shibboleth, but you can get information about the user from Controller.User property. It will return a generic principal of current thread. Using this principal you can check whether the user is authenticated and get a login name of the user. This is due to the reason that after logon an authentication cookie is set and this cookie contains limited amount of information. And on each request after logon only this cookie is checked (if it exists and valid - user is authenticated).
So if you need in some specific information you can manually load a user (it's better to use cache here) and check whatever you want.
Also you can create and attach your own principal with necessary information to the thread on start of a request (e.g. on start of a request load the user from db/cache using user name from base principal, create and set your own principal to thread). After this you can check all properties of the user you need.
Where would you attach your own principal? You say on the start of the request but what if you don't want every request authorizing?
You'll want to create a method in Global.asax.cs that has the following signature
protected void Application_PostAuthenticateRequest()
{
//Your code here.
}
This will be called automatically before almost anything else is done (MVC will call this method if it exists, you don't have to "turn it on" anywhere), and this is where you need to set the Principal. For instance, let's assume you have a header called RolesHeader that has a comma separated value of roles and another header called UserId that has (duh) the user ID.
Your code, without any error handling, might look something like:
protected void Application_PostAuthenticateRequest()
{
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
}
It's the Principal/Identity that the [Authorize] attribute uses, so setting it here at the beginning of the request lifecycle means the [Authorize] attribute will work correctly.
The rest of this is optional, but I recommend it:
I like to create my own custom classes that implement IPrincipal and IIdentity instead of using the GenericPrincipal and GenericIdentity, so I can stuff more user information in it. My custom Principal and Identity objects then have much more rich information, such as branch numbers or email addresses or whatever.
Then, I create a Controller called BaseController that has the following
protected new CustomPrincipal User
{
get
{
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
}
}
This allows me to access all my rich, custom Principal data instead of just what's defined in IPrincipal. All of my real controllers then inherit from BaseController instead of directly from Controller.
Obviously, when using a custom Principal like this, in the Application_PostAuthenticateRequest() method, you'd set the Context.User to be your CustomPrincipal instead of a GenericPrincipal.

Resources