Background : We are using MVC4 and using WIF for Claims/Authorization. We are using Moq/MvcContrib for Mockup Objects. I have looked here and created the MockIdentity and MockPrincipal Objects - do I need them?
Goal : I have a controller class that has a class level attribute that only allows users with 'Manager' claim to access the actions. I want to create mock users and test to see if anyone that doesn't have 'Manager' claim can access the actions or not.
I get the mock concept but I have only dealt with the data objects mocking and having a tough time figuring out what plugins/classes/methods/setups I need in place to do what I need to do.
Thanks in advance.
I want to create mock users and test to see if anyone that doesn't have 'Manager' claim can access the actions or not.
No, you don't. You just want to pass users to that attribute you wrote and test that sets the filterContext.Result correctly. That's it. You don't need to test that System.Web.Mvc works. Single unit under test!
Presumably your attribute is an AuthorizeAttribute, correct? So you need to test OnAuthorization(AuthorizationContext).
Disclaimer: I haven't used moq in a while, but your code would presumably look generally like this:
var user = new Mock<IPrincipal>();
user.Setup(/* whatever you need to look at */);
var authContext = new Mock<AuthorizationContext>();
authContext.Setup(ac => ac.HttpContext.User).Returns(user);
var myAttribute = new RequireManagerAttribute();
myAttribute.OnAuthorization(authContext);
authContext.VerifySet(ac => ac.Result = /* whatever you expect */);
Related
I've got an architecture issue that I'm hoping someone can be of assistance to guide me in a more ideal strategy. The way I've been forced to do this reeks of "code smell".
I've got two different kinds of "Roles". I've got the built in Identity Roles, and I've got a custom set of roles (User Group Roles). I store these User Group Roles in a database, essentially a relationship between a user id, a usergroup role id, and a usergroup id. I'm using Ninject for dependency injection of my UserGroupService that handles all the CRUD operations of assigning users with certain usergroup roles to usergroups.
My first plan of attack was to create a custom authorization attribute that I could place on actions, similar to the Identity [Authorize(Role="")] attribute. I did not have any luck with this because I cannot inject a service into an attribute class (needs a parameterless constructor).
After that didn't work, my second plan of attack was to write an extension method for IPrincipal, essentially mimicking User.IsInRole("") with User.IsInUserGroupRole(""). This didn't work because I cannot inject a service into a static class.
Currently I am stuck including some booleans in the model of every view that has role based logic involved. So for instance:
public ActionResult Navigation()
{
var isSystemAdmin = User.IsInRole("Administrator");
var isUserGroupAdmin = _userGroupService.IsUserGroupAdmin(User.Identity.GetUserId()) && !isSystemAdmin;
var isGeneralUser = !isSystemAdmin && !isUserGroupAdmin;
var model = new NavigationViewModel
{
IsSystemAdmin = isSystemAdmin,
IsUserGroupAdmin = isUserGroupAdmin,
IsGeneralUser = isGeneralUser
};
return PartialView("_Navigation", model);
}
The issue here is that I have to do this any time I want to determine what kind of roles the user is currently in. It works, but it smells.
Am I missing something here? I think the most ideal option would be the extension method strategy of being able to call it right off of User, but cannot seem to make that work.
Constructor DI is not the only way to get access to a dependency.
Each IOC has a way of resolving a dependency, all you need is a reference to the IOC container. So, even if your attribute requires a parameterless constructor you could still resolve the dependency manually.
Something like this should help :
http://www.c-sharpcorner.com/UploadFile/47fc0a/resolving-dependency-using-ninject/
Is it a great way to use your IOC this way? Probably not but it sure beats what you're doing now.
In my MVC application I have Player and Coach objects, and a user can be one or the other. I also have Team objects and what I want to know is how I prevent a user who is in a list of Players or is the Coach of a Team gaining access to a route like /Teams/Details/2 where 2 is the id of a team other than that which he/she is part of.
Thanks in advance!
Since you want to restrict an id that they aren't a part of, this seems like a situation where you can Inherit from the AuthorizeAttribute and provide your implementation for AuthorizeCore
Your implementation could check their role/team id and decide what to do / redirect.
public class TeamAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return UserIsInTeam(httpContext); //whatever code you are using to check if the team id is right
}
}
You can now apply it like any other attribute.
[TeamAuthorize]
The very simplest solution would be to change the URLs from using IDs to random GUIDs. You would almost eliminate the chance of someone guessing another valid value. Of course, this is not secure by definition (mostly because someone could get the other URL from history or another source), but in some scenarios this is enough.
A better solution is to create a new attribute based on IActionFilter interface that implements OnActionExecuting method and checks the ID by using this.ControllerContext.HttpContext.User.Identity.Name and this.RouteData.Values["id"]. You will then apply this attribute to your controller methods.
In our current system we implemented row level security in controller methods by just adding the code that verifies the user permissions as the first line in each method. The checking code is the same as with the attribute and it requires the same amount of code to add. This approach has one additional benefit - it is easier to implement scenarios like where a coach would be able to see the details of other teams but not modify them (we have one action and view for both reading and updating depending on permissions).
You would also use the last approach if you need to go to the database to check the permissions and you are using IoC frameworks such as Ninject with constructor based injection - since you will not have access to those values in the attribute.
I want to be able to access custom properties for an authenticated user like UserId and FirstName without querying the database each time. I found this site through a post on Stack Overflow and I like the approach - but I use IoC / repositories and decided not to try and get global.asax to communicate with the database for fear that it would be incompatible with the repository pattern.
Instead, I created an interface to CustomPrincipal and I use IoC (Castle) to create an instance and pass it to the controllers (and subsequently to my base controller).
The base controller uses methods I created in CustomPrincipal to achieve the same task that the blog author addressed in global.asax. Namely, CustomPrincipal is initialized from the database or cache and assigned to HttpContext.Current.User.
My controllers/views can then reference the properties as follows...
((ICustomPrincipal)(HttpContext.Current.User)).FirstName;
It works, but I'm sensing some code smells. First and foremost, if I reference HttpContext from the controllers I've killed my unit testing. I'm thinking about modifying my CustomPrincipal object to return the above value (such that I can mock it in my unit tests) but I'm wondering if this is a workaround as opposed to a good solution.
Am I going about this the right way? Are there minor tweaks I could do to make it a robust solution or should I start from scratch with FormsAuthenticationTicket or something to that effect?
Thanks!
I wanted to throw out an alternative idea just so people looking for this information can have some choices.
I went searching for a viable FormsAuthenticationTicket example and found that NerdDinner does a pretty decent job adding custom properties without impacting unit testing.
In my case, I modified my LogOn routine (which I was already mocking in my unit tests) to create a FormsAuthenticationTicket. NerdDinner encrypts the ticket and adds it as a cookie, but I am also able to add the encrypted ticket to cache like the original proposal. I also replaced the single UserData property with a JSON serialized object representing all of my custom properties.
CustomIdentityDTO dto = new CustomIdentityDTO {
UserId = userId, FirstName = firstName, LastName = lastName };
JavaScriptSerializer serializer = new JavaScriptSerializer();
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1, // version
username,
DateTime.Now, // creation
DateTime.Now.AddMinutes(30), // expiration
false, // not persistent
serializer.Serialize(dto));
string encTicket = FormsAuthentication.Encrypt(authTicket);
//HttpContext.Current.Response.Cookies.Add(...)
HttpContext.Current.Cache.Add(username, encTicket, ...
Then I retrieve the encrypted ticket (either from cache or cookies) in global.asax through a PostAuthenticateRequest handler much like NerdDinner (for cookie) or the blogger's proposal (for cache).
NerdDinner implements IIdentity instead of IPrincipal. References to the custom fields in the code are as follows:
((CustomIdentity)Page.User.Identity).FirstName // from partial view
((CustomIdentity)User.Identity).FirstName // from controller
After working with both methods, I find that NerdDinner's approach works very well. After switching over I haven't encountered much in the way of obstacles.
What about creating an ICustomPrincipalManager interface?
public interface ICustomPrincipalManager
{
ICustomPrincipal Current {get;}
}
It can be implemented by a class that accesses HttpContext, the database, caching, or whatever, but you could also mock the interface for unit testing. Your controllers would use the IoC framework to get your ICustomPrincipalManager, and then access information like this:
_customPrincipalManager.Current.FirstName
I’m not sure how to mock an ASP.NET Membership for my controller test.
Controller Code:
MembershipUser username = Membership.GetUser();
string UserID = username.UserName.ToString();
Does anyone know how to mock this for a controller test? I'm using RhinoMocks.
I've started working on something like this. Rather than doing a true mock, I created a FakeMembershipProvider that just implements the minimum of MembershipProvider that I need and provides a way to set the users and such. I'm doing the same for RoleProvider. Then I've set the App.config for my test project so it uses these as the providers.
So far, it seems to be working well.
I would watch the MVS StoreFront Serieshttp://www.asp.net/learn/mvc-videos/
For one on Mocking -
http://www.asp.net/learn/mvc-videos/video-365.aspx
And the Membership one
http://www.asp.net/learn/mvc-videos/video-372.aspx
One for Membership and the view of refactor with OpenID
http://www.asp.net/learn/mvc-videos/video-425.aspx
To mock the objects connectected with Membership static class, you should use its Abstract classes in that case, for mocking the GetUser() method, use MembershipProvider class, it is possible to mock, just pass it to your controller and it's done.
Good luck, if you'll have any problems, just let me now, I'll post up some code examples.
I've been writing tests for my domain objects for some time now, but I'm still not quite sure how to go about testing for security in my web project. Certain users in certain environments can access certain properties of my models etc, but how would you go about testing this? Right now, I'm basing it on the current authenticated user, but how would I go about injecting a fake authentication provider?
This is probably a dumb question, but if anyone can help me get out of the testing dark ages, it would be much appreciated.
That link is ONE way, but it's nicer to use a Mock:
Mock<ControllerContext> MockContext(string userName)
{
var mockContext = new Mock<ControllerContext>();
// mock an authenticated user
mockContext.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
mockContext.SetupGet(p => p.HttpContext.User.Identity.IsAuthenticated).Returns(true);
return mockContext;
}
[TestMethod]
public void DinnersController_Delete_Should_Fail_With_InvalidOwner_Given_Wrong_User()
{
//set by default
var mockContext = MockContext("scottha");
// mock an authenticated user
_dinnerController.ControllerContext = mockContext.Object;
ViewResult result = _dinnerController.Delete(1, "") as ViewResult;
Assert.AreEqual("InvalidOwner", result.ViewName);
}
If using TDD your tests should only test the code in question, all other associated objects should be mocks/fakes
among others, you'll need a mock security provider that can simulate the user cases you require to test (guest, user1, user2, admin etc)
When you make a blank MVC project with current MVC RC you get a basic test framework with mock security providers (membership/roles etc). They need some fleshing out, but give the basic design
There is a third option, that is using Xania.AspNet.Simulator
first prepare the controller action
// arrange
var controllerAction = new AccountController().Action(c => c.ChangePassword())
.Authenticate(<username>, <roles>);
next you have two options depending on your implementation,
first scenario, if you return an HttpUnauthorizedResult, i.e. when using Authorize attribute or when you override AuthorizeCore of your controller, then you could test it like following, in which case the actual action method is not invoked.
// act, assert
controllerAction.Authorize().Should().BeNull();
Second scenario is when you actually validate the user inside the action method:
// act
var result = controllerAction.Execute();
// assert
result.ActionResult.Should().NotBeOfType<HttpUnauthorizedResult>();