Can't connect to Database to execute Identity functions - authentication

I've created a new application with ASP.NET MVC5, using Individual User Accounts for security and Code-First Migrations for the Models/Database modeling. All options are default.
I want to setup custom Users and Roles to it, so i created a Seed using RoleManager and UserManager just to populate the Database. It works fine, create 3 Users, 3 Roles and set each User's Role correctly.
I can log in to the application correctly. The problem is that i can't execute any Identity method using the
User, which is the logged User, the only things that i can get is the User.Identity.IsAuthenticated value, and the User.Identity.Name, which are correct. Every other method like Roles.GetRolesForUser("John"), or User.IsInRole("Student"), always generates this exception:
ProviderException : The Role Manager feature has not been enabled.
So okay, as in this article, i managed to insert the the <roleManager enabled="true" /> in the Web.config, and now it takes a really long time to respond, and generates Exceptions like:
Referring to:
Roles.IsUserInRole("Student")
Generates:
HttpException
Referring to:
Roles.GetRolesForUser(User.Identity.Name)
Generates:
NullReferenceException
Accessing the About page with a User in Student role logged in:
[Authorize(Roles="Teacher")]
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
Generates:
SqlException
HttpException
It's like i have no connection to the Database at all, which is LocalDB, automatically generated and i could populate in the Seed Method and even make Login to the application.
I could even load data from the AspNetUsers table and show it in the View using the code below:
using (Models.ApplicationDbContext db = new Models.ApplicationDbContext())
{
List<Models.ApplicationUser> Users = db.Users.ToList();
ViewBag.Users = Users;
}
return View();
PLEASE HELP :'(
Here's the Seed code, that works fine, so it can connect to the Database using the Identity engine.
protected override void Seed(LocalBDAuthTest.Models.ApplicationDbContext context)
{
#region Create Roles Student, Teacher e Administrator
var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
// Student
if (!RoleManager.RoleExists("Student"))
{
RoleManager.Create(new IdentityRole("Student"));
}
// Teacher
if (!RoleManager.RoleExists("Teacher"))
{
RoleManager.Create(new IdentityRole("Teacher"));
}
// Administrator
if (!RoleManager.RoleExists("Administrator"))
{
RoleManager.Create(new IdentityRole("Administrator"));
}
#endregion
#region Create Users for Student, Teacher e Administrator Roles.
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
// Create a Student user and set it's role to Student
if (!context.Users.Any(u => u.UserName == "John"))
{
var Student = new ApplicationUser() { UserName = "John" };
var Result = UserManager.Create(Student, "123456");
}
if (!UserManager.FindByName("John").Roles.Any())
{
UserManager.AddToRole(UserManager.FindByName("John").Id, "Student");
}
// Create a Teacher user and set it's role to Teacher
if (!context.Users.Any(u => u.UserName == "Arnold"))
{
var Teacher = new ApplicationUser() { UserName = "Arnold" };
var Result = UserManager.Create(Teacher, "123456");
UserManager.AddToRole(Teacher.Id, "Teacher");
}
if (!UserManager.FindByName("Arnold").Roles.Any())
{
UserManager.AddToRole(UserManager.FindByName("Arnold").Id, "Teacher");
}
// Create a Administrator user and set it's role to Administrator
if (!context.Users.Any(u => u.UserName == "Caroline"))
{
var Administrator = new ApplicationUser() { UserName = "Caroline" };
var Result = UserManager.Create(Administrator, "123456");
UserManager.AddToRole(Administrator.Id, "Administrator");
}
if (!UserManager.FindByName("Caroline").Roles.Any())
{
UserManager.AddToRole(UserManager.FindByName("Caroline").Id, "Administrator");
}
#endregion
}

This is due to having a mix of both ASP.NET Identity and ASP.NET Membership, having done this:
<system.web>
<roleManager enabled="true" />
</system.web>
You enabled membership SqlRoleProvider, which use the role store in the default SQL Express instance in a database in your Web site's \app_dir folder.
If you open your machine.config, you'll find:
<connectionStrings>
<add name="LocalSqlServer"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient"/>
</connectionStrings>
.
.
.
<roleManager>
<providers>
<add name="AspNetSqlRoleProvider" connectionStringName="LocalSqlServer" ...
</providers>
</roleManager>
Most likely you don't have SQL Express installed, and that's why you are getting timeouts and SQL exceptions.
For ASP.NET Identity DON'T use System.Web.Security.Roles (it is part of the ASP.NET Membership) but use Microsoft.AspNet.Identity.RoleManager instead.

Related

How to use identity server for authenticating active directory users?

I want to use identity server for authenticating and authorizing my users.
I want only for users resource use active directory users and for roles etc I want to use from asp.net identity.
Also i don't want to use windows authentication to authenticate.
I'm using identity server 4 and asp.net core 3.2.
services.AddIdentityServer().AddDeveloperSigningCredential()
//.AddTestUsers(Config.GetUsers())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryClients(Config.GetClients());
First of all, You need to install below package to use ActiveDirectory features.
Install-Package Microsoft.Windows.Compatibility
Secondly, You need to implement IResourceOwnerPasswordValidator and check user password with ActiveDirectory within that.
public class ActiveDirectoryResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
const string LDAP_DOMAIN = "exldap.example.com:5555";
using (var pcontext = new PrincipalContext(ContextType.Domain, LDAP_DOMAIN, "service_acct_user", "service_acct_pswd"))
{
if (pcontext.ValidateCredentials(context.UserName, context.Password))
{
// user authenticated and set context.Result
}
}
// User not authenticated and set context.Result
return Task.CompletedTask;
}
}
Then register it on Startup.cs
services.AddSingleton<IResourceOwnerPasswordValidator, ActiveDirectoryResourceOwnerPasswordValidator>();

is it a bug in mvc4 on cross domain authentication?

i used cross domain cookie authentication on mvc3 and .net4 it works fine and nice,
i create a another project on mvc4 and .net 4.5 and copy/past my codes from lower to uper version on mvc (i mean to mvc4),now my authentication cookie create on main domain but sub domain can not realize that user has been authenticated.
is it a bug in mvc4 or i must enable some futures or somethings like this?
my codes to create authentication cookie on main domain:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
"fc5f06b006b44b05a257c406f4218638",//username
DateTime.Now,
DateTime.Now.AddDays(5),
true,
"members",
FormsAuthentication.FormsCookiePath);
// To give more security it is suggested to hash it
string hashCookies = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
hashCookies); // Hashed ticket
cookie.Expires = DateTime.Now.AddDays(5);
cookie.Domain = ".maindomain.com";
Response.Cookies.Add(cookie);
in sub domain use this line of codes to test user authentication:
var result = System.Web.HttpContext.Current.User.Identity.IsAuthenticated + "-" +
System.Web.HttpContext.Current.User.Identity.Name;
and in my global i have:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
// look if any security information exists for this request
if (System.Web.HttpContext.Current.User != null)
{
// see if this user is authenticated, any authenticated cookie (ticket) exists for this user
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// see if the authentication is done using FormsAuthentication
if (System.Web.HttpContext.Current.User.Identity is FormsIdentity)
{
// Get the roles stored for this request from the ticket
// get the identity of the user
FormsIdentity identity = (FormsIdentity)System.Web.HttpContext.Current.User.Identity;
// get the forms authetication ticket of the user
FormsAuthenticationTicket ticket = identity.Ticket;
// get the roles stored as UserData into the ticket
string[] roles = ticket.UserData.Split(',');
// create generic principal and assign it to the current request
System.Web.HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(identity, roles);
}
}
}
}
and in my web config :
<authentication mode="Forms">
<forms domain=".maindomain.com" name="atnc"
loginUrl="~/home" timeout="120" requireSSL="false" />
</authentication>

Custom Authorization & Role in MVC 4 not working

I need to implement a Single Sign on where a Com+ component should be called to authenticate the user & provide the roles. In short, I need to bypass the default mechanism in MVC 4 where it tries to access the aspnetdb database. So I started with a new MVC4 internet project and added the following code.
In Global.asax
public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
bool retval = CreateUserObject("John", "pwd");
}
private bool CreateUserObject(string userName, string password)
{
string[] currentUserRoles = { "Admin", "User" };
GenericPrincipal userPrincipal = new GenericPrincipal(new GenericIdentity(userName), currentUserRoles);
HttpContext.Current.User = userPrincipal;
//Thread.CurrentPrincipal = userPrincipal;
return true;
}
Within the HomeController.cs, I added the [Authorize] attribute for the "About" action as below and it works as expected
[Authorize]
public ActionResult About()
However if I modify the [Authorize] attribute to permit only "Admin" role as below I get a runtime error (at the bottom). Is there a way around this to use my own collection of roles for the logged in user, instead of querying the database? I also need to do something similar to the user Profile as well (i.e, instead of database, I should populate the values from the Com+ application.
[Authorize(Roles = "Admin")]
public ActionResult About()
Server Error in '/' Application.
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
Maybe you need to create a Custom RoleProvider, like this:
namespace DemoApp.Providers
{
public class MyCustomRoleProvider : System.Web.Security.SqlRoleProvider
{
public override string[] GetRolesForUser(string username)
{
string[] currentUserRoles = { "Admin", "User" };
return currentUserRoles;
}
}
}
And in the web.config of the application, change the default role provider:
<system.web>
<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
<providers>
<add name="DefaultRoleProvider" type="DemoApp.Providers.MyCustomRoleProvider, DemoApp"/>
</providers>
</roleManager>
<system.web>

Seeding data and creating/managing roles in MVC4 - how hard can it be?

I'm about to go insane, so I'll try getting some help one more time...
I'm using Visual Studio Express 2012 for Web to create an internet project using C# + MVC4 + Razor + Entity Framework + ASP.NET 4.5.
I need to do the following: automatically create an "admin" user (who will be authorized all over the site) and then create some user roles.
I've read about SimpleMembership, roles and everything all over the web, but nothing seems to give me a straightforward method to make the whole thing work.
This is what I've done so far:
1- Created a DataContext class:
public class DataContext : DbContext
{
public DataContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
}
2- Created an initializer class with what I assume would get me the admin user and Admins role created:
public class DataContextDbInitializer : DropCreateDatabaseAlways<DataContext>
{
protected override void Seed(DataContext context)
{
var roles = (Webmatrix.WebData.SimpleRoleProvider)System.Web.Security.Roles.Provider;
var membership = (Webmatrix.WebData.SimpleMembershipProvider)System.Web.Security.Membership.Provider;
if (!roles.RoleExists("Admins")) {
roles.CreateRole("Admins");
}
if (membership.GetUser("admin", false) == null) {
membership.CreateUserAndAccount("admin", "123456");
}
if (!roles.GetRolesForUser("admin").Contains("Admins")) {
roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
}
}
}
(I've tried inheriting from DropCreateDatabaseIfModelChanges but that doesn't help).
3- Added two lines to the App_Start method in Global.asax:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
Database.SetInitializer<DataContext>(new DataContextDbInitializer());
I also tried using WebSecurity.InitializeDatabaseConnection in the Seed method in my DataContextDbInitializer class, but didn't work.
4- Removed the [InitializeSimpleMembership] annotation from the AccountController, so I can initialize it from the very beginning of the application life cycle (using WebSecurity.InitializeDatabaseConnection in App_Start, as I've explained in number 3). I tried adding [InitializeSimpleMembership] on top of the Index method in the HomeController and removing WebSecurity.InitializeDatabaseConnection from App_Start, but that doesn't help either.
5- In Web.config I have authentication method as Forms (default) and also left the default connection string:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-TPFinal-20130121210447;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-TPFinal-20130121210447.mdf" providerName="System.Data.SqlClient" />
</connectionStrings>
And added this inside the system.web tag:
<roleManager enabled="true" cacheRolesInCookie="true" />
6- Then, to test if everything works, I use the [Authorize(Roles = "Admins")] annotation on top of the About() method in the HomeController. If things were working as expected, this should force me to log in as admin/123456 in order to be able to see the "About" page, controlled by HomeController/About.
7- I haven't added EF migrations or anything else. All the other stuff is by default as VS2012 automatically created it.
So I run my application and click on the "About" link, and I get presented with the login form (that means that the [Authorize(Roles = "Admins")] annotation is doing what it's expected to do). I attempt to log in as admin/123456 but the log in page is reloaded over and over, every time I click on the log in button.
A few things I have noticed:
-if I add a breakpoint in the Seed method, it seems it's not getting called.
-when I use DropCreateDatabaseAlways and run the application again, I'm able to log in as admin/123456, which makes me think again that my whole DataContextDbInitializer class is not even being used, since I assume the DB should be created from scratch, which would delete the admin user.
I don't know what else to read, what else to try... I'm new to asp.net (needed I say that?) and just going nuts.
Thanks!!
Finally, I managed to make the whole thing work!
My seed method now looks like this:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
if (!Roles.RoleExists("Admins"))
{
Roles.CreateRole("Admins");
}
if (!WebSecurity.UserExists("admin"))
{
WebSecurity.CreateUserAndAccount("admin", "123456");
}
if (!Roles.GetRolesForUser("admin").Contains("Admins"))
{
Roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
}
base.Seed(context);
My App_Start in Global.asax looks like this:
Database.SetInitializer(new DataContextDbInitializer());
DataContext c = new DataContext();
c.Database.Initialize(true);
I'm not sure if this is actually doing something, but I have this inside the the system.web tag in Web.config:
<roleManager enabled="true" cacheRolesInCookie="true" />
I also removed [InitializeSimpleMembership] from AccountController, and the UsersContext class in AccountModels. I moved this bit to my own context class:
public DbSet<UserProfile> UserProfiles { get; set; }
Then, to test if everything works, I use the [Authorize(Roles = "Admins")] annotation on top of the About() method in the HomeController. If things are working as expected, this should force me to log in as admin/123456 in order to be able to see the "About" page, controlled by HomeController/About. Which does ;)
Thanks for the help! It contributed to me understanding a bit more what was going on.
In MVC4 a default Internet Application has Authentication built-in. A class called InitializeSimpleMembershipAttribute is located in a Filters directory. As the name suggests this class Initializes the Simple Membership Database. If you look at the constructor you'll see the following line:
WebSecurity.InitializeDatabaseConnection("UserContext", "UserProfile", "UserId", "UserName", autoCreateTables: true);
Below this line you can insert the following code to create a default user:
// Create admin user.
if (!WebSecurity.UserExists("admin"))
{
WebSecurity.CreateUserAndAccount("admin", "12345678!");
}
Just another way to do things.
Try like this:
public class DataContextDbInitializer : DropCreateDatabaseAlways<DataContext>
{
protected override void Seed(DataContext context)
{
if (!Roles.RoleExists("Admins"))
{
Roles.CreateRole("Admins");
}
if (!WebSecurity.UserExists("admin"))
{
WebSecurity.CreateUserAndAccount("admin", "123456");
}
if (!Roles.GetRolesForUser("admin").Contains("Admins"))
{
Roles.AddUsersToRoles(new[] { "admin" }, new[] { "Admins" });
}
}
}
and in your Application_Start:
Database.SetInitializer<DataContext>(new DataContextDbInitializer());
using (var ctx = new DataContext())
{
ctx.Database.Initialize(true);
}
WebSecurity.InitializeDatabaseConnection(
"DefaultConnection",
"UserProfile",
"UserId",
"UserName",
autoCreateTables: true
);

MVC 4 Using Authorize with Custom Code Not Working

New to MVC 4. What I do not want to do is used the built-in Account management that comes with MVC 4. However, I have created an Account folder under Views, an AccountModel, and AccountController.
What I would like to do is restrict access to Views within the Account folder. for this, in my AccountController, I use the following:
[Authorize]
public class AccountController : Controller
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
public ActionResult bob()
{
return View();
}...
On my home page, I have a link to the bob view under the Accounts view which now reroutes me to the login page (which is correct).
Now, upon form submittal, with the right credentials (anything goes) I should be able to see bob, but instead I am redirected back to the Login because I was not authorized. The code:
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
return RedirectToLocal(returnUrl);
}...
I do not want to use the built-in connect to the DB, but rather what do I need to check the username against a string and then keep an authorization = true so that I can view bob?
In the long run, I plan on connecting to a DB and pulling info back with a SPROC, so right now, I just want the user to be authenticed based upon a string that is checked.
You continue to be Redirected until ASP.net sees a Forms Authenticated cookie.
FormsAuthentication.SetAuthCookie(theUsersNameasString, boolForSessionOrPersistentCookie);
Assuming your Web.Config is configured for Forms Authentication
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
ASP.Net will look for .ASPXAUTH cookie unless the name of this cookie was altered in WEB.CONFIG