Mock default role provider for controller's action unit test - asp.net-mvc-3

Hope this is not a dumb question. I've been searching for two days a way to mock calls for system.web.security.roles on my actions.
I want my unit tests to be isolated and not involve calls to external resources such as database where the roles get Stored.
all the answers i found suggested the creation of a custom role provider, but i prefer mocking over the creation of fakes.
the closest i got was with this solution but i didn't found a way for ninject to pass the default role Provider to the constructor when running the project outside the tests.
I know that type Mock provides a more easy solution to this, but I'm using rhino Mocks and is too late to change now.

I've had same problem like you and after two hours searching I gave it up.
Finally I ended up with creating own mocking role provider - code bellow.
public class MockRoleProvider : RoleProvider
{
public MockRoleProvider()
: base()
{
Users = new List<User>();
Roles = new List<Role>();
}
#region RoleProvider members
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
if (usernames == null) throw new ArgumentNullException("usernames");
if (roleNames == null) throw new ArgumentNullException("roleNames");
foreach (string role in roleNames)
{
if (!RoleExists(role)) throw new ProviderException("Role name does not exist.");
}
foreach (string user in usernames)
{
if (Users.FirstOrDefault(u => u.Username == user) == null) throw new ProviderException("Username does not exist.");
}
foreach (string username in usernames)
{
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) continue;
foreach (var rolename in roleNames)
{
Role role = Roles.FirstOrDefault(r => r.RoleName == rolename);
user.Roles.Add(role);
role.Users.Add(user);
}
}
}
public override string ApplicationName { get; set; }
public override void CreateRole(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
if (roleName.Contains(",")) throw new ArgumentException("Role names cannot contain commas.");
if (RoleExists(roleName)) throw new ProviderException("Role name already exists.");
Roles.Add(new Role { RoleName = roleName });
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
if (role == null) throw new ProviderException("Role name does not exist.");
if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0) throw new ProviderException("Cannot delete a populated role.");
Roles.Remove(Roles.FirstOrDefault(r => r.RoleName == roleName));
return true;
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
return GetUsersInRole(roleName).Where(n => n.Contains(usernameToMatch)).ToArray();
}
public override string[] GetAllRoles()
{
return Roles.Select(r => r.RoleName).ToArray();
}
public override string[] GetRolesForUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) return new string[0];
return user.Roles.Select(r => r.RoleName).ToArray();
}
public override string[] GetUsersInRole(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
if (role == null) throw new ProviderException("Role '" + roleName + "' does not exist.");
return role.Users.Select(u => u.Username).OrderBy(n => n).ToArray();
}
public override bool IsUserInRole(string username, string roleName)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
Role role = Roles.FirstOrDefault(r => r.RoleName == roleName);
return role != null && role.Users.FirstOrDefault(u => u.Username == username) != null;
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
foreach (string roleName in roleNames)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
if (!RoleExists(roleName)) throw new ProviderException("Role name not found.");
}
foreach (string username in usernames)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
foreach (string roleName in roleNames)
{
if (!IsUserInRole(username, roleName)) throw new ProviderException("User is not in role.");
}
}
foreach (string username in usernames)
{
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) continue;
foreach (string roleName in roleNames)
{
Role role = user.Roles.FirstOrDefault(r => r.RoleName == roleName);
role.Users.Remove(user);
user.Roles.Remove(role);
}
}
}
public override bool RoleExists(string roleName)
{
if (roleName == null || roleName == "") throw new ProviderException("Role name cannot be empty or null.");
return Roles.FirstOrDefault(r => r.RoleName == roleName) != null;
}
#endregion
public void ClearAll()
{
Users = new List<User>();
Roles = new List<Role>();
}
public void ClearRoles()
{
Roles = new List<Role>();
Users.ForEach(u => u.Roles = new List<Role>());
}
public void ClearUsers()
{
Users = new List<User>();
Roles.ForEach(r => r.Users = new List<User>());
}
public void CreateUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
if (UserExists(username)) throw new ProviderException("User name already exists.");
Users.Add(new User { Username = username });
}
public bool DeleteUser(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
User user = Users.FirstOrDefault(u => u.Username == username);
if (user == null) throw new ProviderException("User name does not exist.");
foreach (Role role in user.Roles)
{
role.Users.Remove(user);
}
Users.Remove(user);
return true;
}
public bool UserExists(string username)
{
if (username == null || username == "") throw new ProviderException("User name cannot be empty or null.");
return Users.FirstOrDefault(u => u.Username == username) != null;
}
private List<Role> Roles { get; set; }
private List<User> Users { get; set; }
private class Role
{
public Role()
{
Users = new List<User>();
}
public string RoleName { get; set; }
public List<User> Users { get; set; }
}
private class User
{
public User()
{
Roles = new List<Role>();
}
public string Username { get; set; }
public List<Role> Roles { get; set; }
}
}
It is really basic but full implementation of RoleProvider.
For use MockRoleProvider add to you App.config this lines of XML into <configuration> element:
<system.web>
<roleManager enabled="true" defaultProvider="MockRoleProvider">
<providers>
<add name="MockRoleProvider" type="YourProject.Tests.MockRoleProvider, YourProject.Tests"/>
</providers>
</roleManager>
</system.web>
Then in unit test arrange part use this code:
MockRoleProvider mock = Roles.Provider as MockRoleProvider;
if (mock == null) throw new NullReferenceException("MockRoleProvider null exception.");
mock.ClearAll();
mock.CreateUser("SomeUser");
mock.CreateRole("SomeRole");
mock.AddUsersToRoles(new string[] { "SomeUser" }, new string[] { "SomeRole" });

Related

How to get a exception from Mono<Void> reactor Java

I am using spring cloud gateway to authenticate the application via identity providers.
I have implemented the GlobalFilter where I get the Principal from exchange class as OAuth2AuthenticationToken. Here is code snippet
return exchange.getPrincipal()
.defaultIfEmpty(DEFAULT_PRINCIPAL).map(principal -> {
// adds header to proxied request
ServerHttpRequest.Builder b = exchange.getRequest().mutate();
if (principal.getClass()
.equals(OAuth2AuthenticationToken.class)) {
OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) principal;
OAuth2User p = (OAuth2User) auth.getPrincipal();
String userId = (String) p.getAttributes()
.getOrDefault("sub", new String());
String firstName = (String) p.getAttributes()
.getOrDefault("given_name", new String());
String lastName = (String) p.getAttributes()
.getOrDefault("family_name", new String());
String name = (String) p.getAttributes()
.getOrDefault("preferred_username",
new String());
String email = (String) p.getAttributes()
.getOrDefault("email",
new String());
String groupName = (String) p.getAttributes()
.getOrDefault("group",
new String());
if (groupName.equalsIgnoreCase("data-admins")) {
// TODO throw something HTML
}
if (principal != DEFAULT_PRINCIPAL) {
b.header("X-APP-USER", p.getName());
b.header("X-APP-USERID", userId);
if (firstName != null) {
b.header("X-APP-FIRSTNAME", firstName);
}
if (lastName != null) {
b.header("X-APP-LASTNAME", lastName);
}
if (name != null) {
b.header("X-APP-PREFERRED-USERNAME", name);
}
if (email != null) {
b.header("X-APP-EMAIL", email);
}
}
}
b.build();
return exchange;
}).flatMap(chain::filter);
Inside the if condition I need to check if in principal object the group value matching with as value data-admin or NOT. If principal (or User) doesn't belong with this group then throw an error (preferably HTML)
If make throw new RuntimeException("User is not part of a Group"); it works but how to send this as an HTML. As return can be Mono
How to achieve this?

Multiple authentication attributes

I`m working on my website using .net web-api as back .
Now I made different authentication attributes on the web site such as users employees and admin .
for my question how can I use multiple authentication attributes on a controller?
public class AuthFilterManager : Attribute, IAuthenticationFilter
{
public bool AllowMultiple => throw new NotImplementedException();
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var auth = context.Request.Headers.Authorization;
string[] UserNameAndPass = (auth.Parameter).Split(':');
string UserName = UserNameAndPass[0];
string Pass = UserNameAndPass[1];
Luxury_wheelsEntities entities = new Luxury_wheelsEntities();
Management manager = entities.Managements.FirstOrDefault(m => m.User_name == UserName);
if (auth != null && auth.Scheme == "LuxuryWheelsLogin")
{
if (LoginSecurity.CheckManagerLogin(UserName, Pass))
{
var Claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier,(manager.ID)),
new Claim(ClaimTypes.Name,(manager.Full_name)),
new Claim(ClaimTypes.Gender,(manager.Sex))
};
var identity = new ClaimsIdentity(Claims, "Token");
context.Principal = new ClaimsPrincipal(new[] { identity });
}
else
{
context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
}
}
return Task.FromResult(0);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
return Task.FromResult(0);
}
}
seperatly the AuthFilterEmployee and the AuthFilterManager works just fine.
[AuthFilterEmployee ]
[AuthFilterManager]
[Authorize]
public IEnumerable<User> Get()
{
return LuxuryWheelsDB.Users;
}

How to customize authentication to my own set of tables in asp.net web api 2?

In the default AccountController created I see
public AccountController()
: this(Startup.UserManagerFactory(), Startup.OAuthOptions.AccessTokenFormat)
{
}
In Startup.Auth.cs I see
UserManagerFactory = () =>
new UserManager<IdentityUser>(new UserStore<IdentityUser>());
Seems like the implementation of UserStore comes from Microsoft.AspNet.Identity.EntityFramework.
So, to customize the authentication do I have to implement my own version of UserStore like
class MYSTUFFUserStore<IdentityUser> : UserStore<IdentityUser>
{
}
and override the methods and then do this in Startup.Auth.cs
UserManagerFactory = () =>
new UserManager<IdentityUser>(new MYSTUFFUserStore<IdentityUser>());
I am looking for a correct way to customize the authentication.
Assuming your table is called AppUser, convert your own AppUser domain object to IUser(using Microsoft.AspNet.Identity) like this
using Microsoft.AspNet.Identity;
public class AppUser : IUser
{
//Existing database fields
public long AppUserId { get; set; }
public string AppUserName { get; set; }
public string AppPassword { get; set; }
public AppUser()
{
this.Id = Guid.NewGuid().ToString();
}
[Ignore]
public virtual string Id { get; set; }
[Ignore]
public string UserName
{
get
{
return AppUserName;
}
set
{
AppUserName = value;
}
}
}
Implement the UserStore object like this
using Microsoft.AspNet.Identity;
public class UserStoreService
: IUserStore<AppUser>, IUserPasswordStore<AppUser>
{
CompanyDbContext context = new CompanyDbContext();
public Task CreateAsync(AppUser user)
{
throw new NotImplementedException();
}
public Task DeleteAsync(AppUser user)
{
throw new NotImplementedException();
}
public Task<AppUser> FindByIdAsync(string userId)
{
throw new NotImplementedException();
}
public Task<AppUser> FindByNameAsync(string userName)
{
Task<AppUser> task = context.AppUsers.Where(
apu => apu.AppUserName == userName)
.FirstOrDefaultAsync();
return task;
}
public Task UpdateAsync(AppUser user)
{
throw new NotImplementedException();
}
public void Dispose()
{
context.Dispose();
}
public Task<string> GetPasswordHashAsync(AppUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
return Task.FromResult(user.AppPassword);
}
public Task<bool> HasPasswordAsync(AppUser user)
{
return Task.FromResult(user.AppPassword != null);
}
public Task SetPasswordHashAsync(AppUser user, string passwordHash)
{
throw new NotImplementedException();
}
}
If you have your own custom password hashing you will also need to implement IPasswordHasher. Below is an example where there is no hashing of the password(Oh no!)
using Microsoft.AspNet.Identity;
public class MyPasswordHasher : IPasswordHasher
{
public string HashPassword(string password)
{
return password;
}
public PasswordVerificationResult VerifyHashedPassword
(string hashedPassword, string providedPassword)
{
if (hashedPassword == HashPassword(providedPassword))
return PasswordVerificationResult.Success;
else
return PasswordVerificationResult.Failed;
}
}
In Startup.Auth.cs replace
UserManagerFactory = () =>
new UserManager<IdentityUser>(new UserStore<IdentityUser>());
with
UserManagerFactory = () =>
new UserManager<AppUser>(new UserStoreService()) { PasswordHasher = new MyPasswordHasher() };
In ApplicationOAuthProvider.cs, replace IdentityUser with AppUser
In AccountController.cs, replace IdentityUser with AppUser and delete all the external authentication methods like GetManageInfo and RegisterExternal etc.

Spring MVC binding to same #RequestMapping

Suppose we have this code for login & we want if the credential was for admin page the RequestMapping be for admin & if it was for user credential the user redirect to user panel.
now, the main page of both oppose the same url as I defined in my code below, something like :
http://localhost:8080/project/{username}/main
my question is :
how we can separate these two method in here when they have the same RequestMapping "main" after the login checking finished inside the Controller class?
#RequestMapping(value = "/login")
public String welcome(#RequestParam("j_username") String username, #RequestParam("j_password") String password, HttpSession session, Model model) throws RemoteException, NotBoundException {
int checkAccount = uiClient.checkAdminAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
checkAccount = uiClient.checkAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
return "login";
}
} else {
return "databaseError";
}
return "login";
}
#RequestMapping(value = "/{username}/main")
public String indexPage(#PathVariable("username") String username) {
return "/user/userPanel";
}
#RequestMapping(value = "{username}/main")
public String adminIndexPage(#PathVariable("username") String username){
return "/admin/adminPanel";
}
I mean, is there any way like special tag or something that we can put for each Mapping & separate them after the login process finished so the admin redirect to adminPanel & the user also redirect to userPanel but both with the same url:
http://localhost:8080/project/{username}/main
???
What about this way:
#RequestMapping(value = "/login")
public String welcome(#RequestParam("j_username") String username, #RequestParam("j_password") String password, HttpSession session, Model model) throws RemoteException, NotBoundException {
int checkAccount = uiClient.checkAdminAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
session.setAttribute("userrole", "Admin");
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
checkAccount = uiClient.checkAccount(username, password);
if (checkAccount == 1) {
session.setAttribute("username", username);
session.setAttribute("userrole", "Admin");
return "redirect:/" + username + "/main";
} else if (checkAccount == 0) {
return "login";
}
} else {
return "databaseError";
}
return "login";
}
#RequestMapping(value = "/{username}/main")
public String indexPage(#PathVariable("username") String username) {
if ("Admin".equals(session.getAttribute("userrole"))) {
return "/admin/adminPanel";
} else {
return "/user/userPanel";
}
}
For simplicity, I didn't use Spring Security to check user role here.

MVC3 Model Validation (Compare propery in another class)

public class User
{
string username;
string password;
}
public class registration
{
User user;
**[compare(user.password)]**
string newPass;
}
It produces error (Property is not found)
Is there a way to create validation for a property inside another class ?
thanks
public class CompareOther:ValidationAttribute, IClientValidatable
{
private readonly string testedPropertyName;
private readonly string className;
public CompareOther(string testedPropertyName)
{
string[] word = testedPropertyName.Split('.');
this.testedPropertyName = word[1];
this.className = word[0];
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.className);
if (propertyTestedInfo == null)
{
//return new ValidationResult("unknown property");
return new ValidationResult(string.Format("unknown property {0}.{1}",this.className ,this.testedPropertyName));
}
var propertyObject = propertyTestedInfo.GetValue(validationContext.ObjectInstance,null);
var propertyTestedValue = getValue(testedPropertyName,propertyObject);
if (value == null)
{
return ValidationResult.Success;
}
if (propertyTestedValue == null)
{
return ValidationResult.Success;
}
if (propertyTestedValue.ToString() == value.ToString())
{
return ValidationResult.Success;
}
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessageString,
ValidationType = "lessthan"
};
rule.ValidationParameters["propertytested"] = this.testedPropertyName;
yield return rule;
}
private Object getValue(string name,Object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(name);
if (info == null)
{ return null; }
obj = info.GetValue(obj, null);
return obj;
}
}

Resources