Getting an error implementing Roles in MVC 4 - asp.net-mvc-4

I am trying to register a user to a role but i am getting the following error:
No user found was found that has the name "MyName"
I have created an MVC 4 Application using the default template.
I have created a custom membership provider and implemented the CreateUser method as follow
public User CreateUser(User i_userToCreate)
{
using (var _db = new Repository())
{
User _user = _db.CreateUser(i_userToCreate);
MembershipUser _membershipUser = new MembershipUser(providerName: "ATWMembershipProvider",
name: _user.UserName,
providerUserKey: null,
email: _user.Email,
passwordQuestion: "",
comment: "",
isApproved: true,
isLockedOut: false,
creationDate: DateTime.UtcNow,
lastLoginDate: DateTime.UtcNow,
lastActivityDate: DateTime.UtcNow,
lastPasswordChangedDate: DateTime.UtcNow,
lastLockoutDate: DateTime.UtcNow);
return _user;
}
This is how i configured my web.config
<appSettings>
<add key="enableSimpleMembership" value="false"/>
<add key="autoFormsAuthentication" value="false"/>
</appSettings>
<system.web>
<membership defaultProvider="ATWMembershipProvider">
<providers>
<clear/>
<add name="ATWMembershipProvider" type="AroundTheWorld.Infrastructure.ATWMembershipProvider"
enablePasswordRetrieval="false"
ConnetionStringName="Context"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
equiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10" applicationName="myApplication" />
</providers>
</membership>
<roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
<providers>
<remove name="AspNetSqlRoleProvider" />
<add name="AspNetSqlRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<!-- note: WebMatrix registers SimpleRoleProvider with name
'AspNetSqlRoleProvider'. I don't know why but i kept it. -->
</providers>
</roleManager>
Now the authenticate method is as follow:
var MembershipProvider = new ATWMembershipProvider();
User authentictedUser = MembershipProvider.CreateUser(_userToCreate);
FormsAuthentication.SetAuthCookie(authentictedUser.UserName, true);
System.Web.Security.Roles.AddUserToRole(authentictedUser.UserName, authentictedUser.Role.Name);
Session.Add("UserID", authentictedUser.ID);
Session.Add("UserName", authentictedUser.UserName);
I have already checked the following:
My User as all necessary information
I have registered two roles in App_start "user" , "admin"
but i still getting an error that No user found was found that has the name "MyName"
In asp web form that wasn't necessary in order to secure a folder based on a role
All i am trying to do is to secure an action inside a controller to a specific "Role"
[Authorize(Roles = "admin")]
public ActionResult GetAllLocations()
{
using (var _db = new Repository())
{
return View(_db.GetLocations());
}
}

I have fixed the problem...
The problem was because I implemented only a custom membership provider without a role provider.
I have followed this blog.
Basically I have created a class MyOwnRoleProvider which inherits from RoleProvider
and:
Implemented the method called GetRolesForUser
Implemented the method called GetUsersInRole
finally I modified my web.config to
<roleManager defaultProvider="ATWRoleProvider" enabled="true" cacheRolesInCookie="true">
<providers>
<clear />
<add name="ATWRoleProvider" type="AroundTheWorld.Infrastructure.ATWRoleProvider, AroundTheWorld" connectionStringName="Context" />
</providers>
</roleManager>
after it I was able to use the following
[Authorize(Roles="admin")]
public ActionResult GetAllLocations()
{
using (var _db = new Repository())
{
return View(_db.GetLocations());
}
}
AND
#if (User.IsInRole("user"))
I hope it will be helpful for someone...

Related

Is Active Directory authentication used?

I've inherited MVC4 application. It looks like Windows Authentication is used, but I also was told that "Active Directory Authentication" is used for some permissions. I do not see anything in web.config about Active Directory.
In web.config:
<authentication mode="Windows" />
<roleManager defaultProvider="DefaultRoleProvider">
<providers>
<add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=21bf1234ad634e53" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</roleManager>
In Controller:
[Authorize(Roles = #"ABCD\EFG"), HandleError(ExceptionType = typeof(UnauthorizedAccessException), View = "UnauthorizedUser", Order = 1)]
public class HomeController : Controller
{ .............
}
public ActionResult MyAction()
{
if (!User.IsInRole(#"ABCD\EFG"))
{
// some code
}
//.............
}
Is "Active Directory Authentication" used in this application ?
Thank you
The windows authentication will indeed integrate with Active Directory as long as the application server is on the domain your users are registered in.
The below line in your config file enables such functionality.
<authentication mode="Windows" />
This post might help you get further:
Configure ASP.NET MVC for authentication against AD

Windows-authentication MVC app with Claims, Authenticate called multiple times and looses Security Token cookie

I'm developing Windows-authentication claims-based MVC application. I've implemented the IHttpModule (aka "ClaimsTransformation Module", which interceps the Identity) and custom ClaimsAuthenticationManager (which adds additional claims to this identity), as shown below. Page loads, and I can retrieve newly added claim, but there few serious issues...
The problems are:
Even on initial page load my custom RomesClaimsAuthenticationManager.Authenticate method gets called 27+ times (I assume some calls are parrallel/async).
The FedAuth (SessionToken) cookie check never returns true, even though right after SAM (SessionAuthenticationManager) writes SesstionToken to cookie - I can see it, but at the next call (still during original page load) it's gone - same thing happens if I open other pages.
public class RomesClaimsAuthorizationModule : IHttpModule, IDisposable
{
public void Init(System.Web.HttpApplication application)
{
// intercept PostAuthenticationRequest to add custom logic
application.PostAuthenticateRequest += TransformPrincipal;
}
private static void TransformPrincipal(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
// PROBLEM HERE - this is always false, even after cookie has been set
// check if cookie with auth info about curr user already exists
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
{
return;
}
else
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// this will pick up our custom Romes.Adminn.Security.RomesClaimsAuthenticationManager
// it is specified in web.config, so our app will use it as default
// which will add our custom additional claims to our principal
var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
if (transformer != null)
{
var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, context.User as ClaimsPrincipal);
// generate cookie
SessionSecurityToken sst = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
sst.IsReferenceMode = true; // used when there are a lot of claims - will be faster
sst.IsPersistent = true;
// write cookie to session
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sst);
// write to context
context.User = transformedPrincipal;
Thread.CurrentPrincipal = transformedPrincipal;
}
}
}
}
}
Custom ClaimsAuthenticationManager:
public class RomesClaimsAuthenticationManager : ClaimsAuthenticationManager
{
// PROBLEM - THIS GETS HIT 27+ times on original page load
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true)
{
((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(new Claim(ClaimTypes.Email, "myTestEmail#email.com"));
// i will be making a db call here to get add'l user info from DB, and then convert it into claims
}
return incomingPrincipal;
}
}
Web.config file:
<configSections>
<!--this is required for custom ClaimsAuthorizationManager-->
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<!--this will allow us to write ClaimsPrincipal to a cookie, saving from calls to db on each request-->
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
...
<system.identityModel>
<identityConfiguration>
<claimsAuthenticationManager type="ROMES.Admin.Security.RomesClaimsAuthenticationManager, ROMES.Admin" />
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler mode="Default" requireSsl="true" />
</federationConfiguration>
</system.identityModel.services>
<system.web>
<authentication mode="Windows"/>
...
<authorization>
<allow roles="WINDOWS\ROMES_Admins"/>
<deny users="*" />
</authorization>
<!--must be in both here and system.webServer/modules-->
<!--see here WHY: https://msdn.microsoft.com/en-us/library/gg638734.aspx-->
<httpModules>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</httpModules>
</system.web>
<system.webServer>
<!-- same as in system.web/httpModules-->
<modules>
<add name="RomesClaimsAuthorizationModule" type="ROMES.Admin.Security.RomesClaimsAuthorizationModule"/>
<!--this module will handle reading and writing cookie for identity/claims - so that there will be no need to call db every request for user info-->
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</modules>
...
</system.webServer>
My main issues are:
(1) why is my Authenticate block gets called so many times and
(2) Why is Session Security Token cookie does not persist - seems like such a waste of resources.
In here
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies)
change to
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(context.Request.Cookie)
and see if the condition started to be true and your code returns.
EDITED after David's comment: context replaced with context.Request.Cookie

MVC 4 with AspNetSqlMembershipProvider

I've been tasked with rewriting an existing Asp.Net Classic web app in MVC4, using the existing DB and authentication.
The old app still uses the "aspnet_" prefix to its tables. I've modified the new site's web.config to include these providers (copied straight form the old site)
<roleManager enabled="true">
<providers>
<remove name="AspNetSqlRoleProvider" />
<add connectionStringName="LocalSqlServer" applicationName="MyApp" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove name="AspNetWindowsTokenRoleProvider" />
<add applicationName="IOL" name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</roleManager>
<membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<remove name="AspNetSqlMembershipProvider" />
<add connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="MyApp" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<remove name="AspNetAdminMembershipProvider" />
<add connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="IOL" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" name="AspNetAdminMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</membership>
In my account controller's login action:
public ActionResult Login(LoginModel model, string returnUrl)
{
var auth = Membership.ValidateUser(model.UserName, model.Password);
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
The auth variable is true if I remove the [InitializeSimpleMembership] from the controller, if I add it back, I get an error stating "Cannot convert type 'System.Guid' to 'int'". he Websecurity.Login() method fails both with and without the class attribute.
So in a nutshell, if I remove the simple membership, the forms auth validate user works, but when I inspect the User.Identity.IsAuthenticated object, is says false.
What am I missing? I'm not even sure if I'm implementing this security model correctly, I can't find any information on it.
You cannot use the old membership providers with SimpleMembership (e.g. WebSecurity). You need to use the SimpleMembershipProvider. And you will have to migrate the data from the old table structures to the schema used by SimpleMembership. The only thing you can customize in SimpleMembership tables is the table that contains the user profile information, which you can read about here.
Migrating to MVC4 and SimpleMembership will already put you behind the curve. SimpleMembership has been depreciated for ASP.NET Identity. ASP.NET Identity requires MVC5, which you should migrate to anyway to take advantage of all of the added features as well of the general benefits of keeping your underlying components current. ASP.NET Identity is much more flexible than SimpleMembership (SimpleMembership was designed to be simple and not exactly flexible) and there is even an article that walks you through the steps of migrating SQL Membership to ASP.NET Identity.

WebSecurity.InitializeDatabaseConnection fails with "The Role Manager feature has not been enabled." when called from console program

I have a MVC4 application using SimpleMembership to authenticate users.
I want to add users from a console program.
The console program that references a class library that has the method that will do the user creation.
It looks like this:
public class UserBuilder
{
private static readonly SimpleMembershipInitializer _membershipInitializer;
private static readonly bool _isInitialized;
private static readonly object _initializerLock = new object();
static UserBuilder()
{
LazyInitializer.EnsureInitialized(ref _membershipInitializer, ref _isInitialized, ref _initializerLock);
}
public void HandleEvent(UserAdded #event)
{
if (!WebSecurity.UserExists("ReportModels"))
{
WebSecurity.CreateUserAndAccount("ReportModels", "ReportModels");
};
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
}
}
When I start my console application I get System.Configuration.Provider.ProviderException {"The Role Manager feature has not been enabled."} at the line starting with WebSecurity.InitializeDatabaseConnection.
What do I need to do to accomplish this?
I've tried:
adding the nuget package Microsoft ASP.NET Web Pages 2 Web Data to both the console project and the class library project.
the answers listed in this post: SimpleMembershipProvider not working.
verified the connection string.
verified that the tables are in place in the database.
verified that creating users and authenticating them from the MVC4 project works.
Finally solved it thanks to information found in this blog post: http://insomniacgeek.com/to-call-this-method-the-membership-provider-property-must-be-an-instance-of-extendedmembershipprovider/ and some googling.
In essence I needed to add this to my app.config file:
<system.web>
<profile defaultProvider="SimpleProfileProvider">
<providers>
<add name="SimpleProfileProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData"
connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</profile>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
<roleManager defaultProvider="SimpleRoleProvider" enabled="true">
<providers>
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
</providers>
</roleManager>
</system.web>
Please note the enabled="true" on the roleManager element. Without that the same exception will be thrown.

You must call the "WebSecurity.InitializeDatabaseConnection"

I have a problem with using [Authorize(Roles = "admin")] attribute.
[Authorize(Roles = "admin")]
public ActionResult GetAllLocations()
{
I am getting the following error
You must call the "WebSecurity.InitializeDatabaseConnection" method
before you call any other method of the "WebSecurity" class. This call
should be placed in an _AppStart.cshtml file in the root of your site.
I have built a MVC 4 application using EF 5 Code first with my own database.
A little background:
I have created a custom membership provider I have inherited from
MembershipProvider
I have look at a lot of questions in this site about this issue, but
didn't found an answer.
In some answers i saw how to disable the membership provider
like this:
<add key="enableSimpleMembership" value="false"/>
<add key="autoFormsAuthentication" value="false"/>
This is how i implemented my custom membership provider
<membership defaultProvider="ATWMembershipProvider">
<providers>
<clear/>
<add name="ATMMembershipProvider" type="AroundTheWorldWeb.Infrastructure.AuthenticationProvider.ATMMembershipProvider"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
equiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10" applicationName="myApplication" />
</providers>
</membership>
<roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
<providers>
<remove name="AspNetSqlRoleProvider" />
<add name="AspNetSqlRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<!-- note: WebMatrix registers SimpleRoleProvider with name
'AspNetSqlRoleProvider'. I don't know why but i kept it. -->
</providers>
</roleManager>
I fixed this problem by creating the MVC 4 from template. I think there some DLL's aren't loaded when choosing Empty template. So i have created it from a template and override all the Account's methods And also implemented custom member and role provider