WebAPI + SimpleMembership + WebSecurity - can never authenticate? - asp.net-mvc

I'm trying to implement a single-page app. I carried over some of my working code from another project (MVC4) to implement authentication. Right now I see cookies being set, but WebSecurity / User.Identity do not seem to be working for some reason. After logging in, subsequent requests never validate as authenticated, either via WebSecurity.IsAuthenticated, or User.Identity.IsAuthenticated. Does anyone know why this is happening?
Controller code:
public class AccountController : ApiController {
private readonly UserService _userService;
public AccountController() {}
public AccountController(UserService userService) {
_userService = userService;
}
[AllowAnonymous]
[HttpGet]
[Route("api/authpayload")]
// This gets called when the app loads. Always, User.Identity.IsAuthenticated is false.
public HttpResponseMessage AuthPayload() {
var payload = new AuthPayloadDto();
try {
var userId = WebSecurity.GetUserId(User.Identity.Name);
if (User.Identity.IsAuthenticated && userId > 0) {
payload.Username = User.Identity.Name;
} else {
LogOut();
payload.IsAuthenticated = false;
}
return Request.CreateResponse(HttpStatusCode.OK, payload);
} catch (Exception e) {
return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
}
}
[HttpPost]
[Route("api/login")]
[AllowAnonymous]
public HttpResponseMessage LogIn(LoginModel model) {
if (!ModelState.IsValid)
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
try {
if (WebSecurity.IsAuthenticated)
return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
if (!WebSecurity.UserExists(model.Username))
return Request.CreateResponse(HttpStatusCode.Conflict, "User does not exist.");
if (WebSecurity.Login(model.Username, model.Password, persistCookie: model.RememberMe)) {
// This code always gets hit when I log in, no problems. I see a new cookie get sent down as well, using Chrome debugger.
var payload = new AuthPayloadDto();
return Request.CreateResponse(HttpStatusCode.OK, payload);
}
LogOut();
return Request.CreateResponse(HttpStatusCode.Forbidden, "Login Failed.");
} catch (Exception e) {
return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
}
}
Web.config:
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="~/" timeout="2880" />
</authentication>
<roleManager enabled="true" defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
<!--
If you are deploying to a cloud environment that has multiple web server instances,
you should change session state mode from "InProc" to "Custom". In addition,
change the connection string named "DefaultConnection" to connect to an instance
of SQL Server (including SQL Azure and SQL Compact) instead of to SQL Server Express.
-->
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
</providers>
</sessionState>
</system.web>
The cookie that gets sent after login is not expired, and it does get sent back on subsequent requests, but IsAuthenticated is always false. What am I doing wrong?
Update:
I updated my web.config to the following to get everything working:
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<roleManager enabled="true" defaultProvider="SimpleRoleProvider">
<providers>
<clear />
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear />
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
</system.web>
But I'd like to leave this open in case anyone has an explanation of why this works; I'm pretty lost.

In my current mvc 4 project with mssql,
its a simple one i so I just wanted very simple memmbership provider
I disabled
InitializeSimpleMembershipAttribute
by
[Authorize]
//[InitializeSimpleMembership]
public partial class AccountController : Controller
and added this code to global.asax under Application_Start
WebSecurity.InitializeDatabaseConnection(
connectionStringName: "DefaultConnection",
userTableName: "UserProfile",
userIdColumn: "UserID",
userNameColumn: "UserName",
autoCreateTables: true);
in my sql database the application created some tables on of them was Roles and UserInRoles just added the roles I needed like Admin, customer, etc...
and I restrict the access to some Controllers or Actions by adding this code
[Authorize(Roles = "Admin")]
public class MessagesController : Controller

Related

Login Using Active Directory in Asp.net Mvc 5?

I am new for Active Directory authentication. Need to create login using active directory. Please help me with explained example or link where I can learn to create active directory login
My web.config file:
<authentication mode="Forms">
<forms name=".ADAuthCookie" loginUrl="~/Service/Index" timeout="45" slidingExpiration="false" protection="All" />
</authentication>
<trust level="Full" originUrl="" />
<membership defaultProvider="ADMembershipProvider">
<providers>
<clear />
<add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a "
connectionStringName="ADConnectionString"
connectionProtection="Secure"
connectionUsername="bos\user10"
connectionPassword="user#101"
attributeMapUsername="sAMAccountName" />
</providers>
</membership>
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP://fontier.bos.com:389/DC=fontier,DC=bos,DC=com" />
</connectionStrings>
And my login action method is:
[HttpPost]
[AllowAnonymous]
public ActionResult LoginUser(LoginUser login, string returnUrl)
{
if (ModelState.IsValid)
{
//MembershipProvider domainProvider = Membership.Providers["ADMembershipProvider"];
//if (domainProvider.ValidateUser(login.UserName, login.Password))
if (Membership.ValidateUser(login.UserName, login.Password))
{
FormsAuthentication.SetAuthCookie(login.UserName,true);
if(Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Service");
}
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect");
}
return View(login);
}
Logout action:
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("LoginUser", "User");
}
Here, I am getting error : The specified domain or server could not be contacted.
I googled a lot but couldn't get anything useful....Please give your valuable suggestion for this....Thanks.

User.Identity.IsAuthenticated always false after PasswordSignInAsync gives success

I've got a standard MVC project, with the UserManager and SignInManager objects and an AccountController, with the pre-created login and register type functionality.
I can register new users to my AspNetUsers table, but when I login I call:-
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
The data is coming through from the form correctly, and the result is Success, which I expected.
I then tried the following redirects:-
case SignInStatus.Success:
//return RedirectToLocal("/admin/");
return RedirectToAction("Index", "Admin");
but on any page, after this successful login, User.Identity.IsAuthenticated is always false, and User.Identity.Name is an empty string.
What am I doing wrong? I've done another project in the same way with the same setup in the past and I've had zero problems.
web.config
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
<!--<authentication mode="Forms">
<forms loginUrl="~/Account/Login/" timeout="1000" />
</authentication>-->
<authentication mode="None" />
</system.web>
<modules>
<remove name="FormsAuthentication" />
</modules>
Can anyone suggest what I am doing wrong? It's causing major issues now.
Cheers!
Check to see if you have a Startup.Auth.cs file in your App_Start folder in the project.
public partial class Startup {
public void ConfigureAuth(IAppBuilder app) {
// This uses cookie to store information for the signed in user
var authOptions = new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
LogoutPath = new PathString("/Account/Logout"),
ExpireTimeSpan = TimeSpan.FromDays(7),
};
app.UseCookieAuthentication(authOptions);
}
}
and is called from the Startup class
public partial class Startup {
public void Configuration(IAppBuilder app) {
// Surface Identity provider
ConfigureAuth(app);
//..other start up code
}
}
Depending on the version of asp.net and identity you are using, you should take a look at this
ASP.NET Identity AuthenticationManager vs. SignInManager and cookie expiration
For me it was the web.config, comment following lines
<system.webServer>
<modules>
<!--<remove name="FormsAuthentication" />
<remove name="ApplicationInsightsWebTracking" />
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
-->
</modules>
</system.webServer>

asp.net MVC Hide url origin when login required

I have an html page that requires "SuperAdmin" role in order to access it. Here is my web.config and all works well :
....
<handlers>
<add name="HTMLHandler" type="System.Web.StaticFileHandler" path="*.html" verb="GET" />
</handlers>
....
<location path="app/html/_superAdmin/Dashboards.html">
<system.web>
<authorization>
<allow roles="SuperAdmin" />
<deny users="*" />
</authorization>
</system.web>
</location>
The problem is the url string when the user is sent to login:
http://localhost:50138/Account/Login?ReturnUrl=%2Fapp%2Fhtml%2F_superAdmin%2FDashboards.html
I do not want the user to see "ReturnUrl=%2Fapp%2Fhtml%2F_superAdmin%2FDashboards.html".
How can I remove this querystring when the user is redirected to the login page.
Unless anyone can come up with something more elegant, this worked:
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
try
{
if (returnUrl.Contains("_superAdmin"))
{
return RedirectToAction("Login", "Account", new { area = "" });
}
}
catch (Exception)
{
}
return View();
}

Securing ELMAH in ADFS Claims aware MVC 4 app using elmah.mvc.allowedRoles AppSettings

ELMAH for MVC support following appsettings configurations
elmah.mvc.allowedRoles
elmah.mvc.allowedUsers
to secure the elmah route path using roles/users. Apparently, it works fine for windows or forms authentications. But I couldn't make it working for the claim based authentication.
Does anyone have experience with this?
I do this in web config
<elmah>
<security allowRemoteAccess="true" />
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sqlserver" applicationName="Eers.Web"/>
</elmah>
and further down
<location path="elmah">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
</handlers>
</system.webServer>
</location>
If you take note of the node it works just like any other security in MVC. It does not work with Claims though. for that You will have to write an Action filter
<authorization>
<allow users="*"/>
</authorization>
Here is my Actionfilter
public class ElmahRequestAuthorizationFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.IsChildAction) return;
var controller = filterContext.RouteData.Values["controller"] as string;
if (controller != null && controller.ToLowerInvariant() != "elmah") return;
var authenticationComponent = GetAuthenticationInfo() // A method that will return us roles;
var goodRoles = new List<string> {
"TestRole",
"ThirdLevelSupport",
"Administrator"
};
var roles = authenticationComponent.Roles ?? new List<string>();
var thouShaltPass = roles.Intersect(goodRoles).Any();
if (!thouShaltPass)
{
throw new HttpException(404, "Not Found");
}
}
}

C# MVC Do i have to use DB for Role Provider

I've been trying to use role provider but its been giving me headaches for a week.
All I am trying to do is allow a user to be able to see "Admin" Page if they are an admin (I've added Admin Coloumn in my database, to be 0 or 1)
Here is the code in my Controller for Login
if (user.Admin == 1)
{
addUserToRole(user.UserID, "Admin");
}
else
{
}
here is the method to add user to a role
public void addUserToRole(String user, String role)
{
if (!Roles.RoleExists(role))
Roles.CreateRole(role);
Roles.AddUserToRole(user, role);
}
for the admin controller, I want to enter this
[Authorize(role= "admin")]
Here is my webconfig
<profile defaultProvider="DefaultProfileProvider">
<providers>
<add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxxxx" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</profile>
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxx" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<roleManager defaultProvider="DefaultRoleProvider" enabled="true">
<providers>
<add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxx" connectionStringName="Database2Entities1" applicationName="/" />
</providers>
</roleManager>
my question is do I have to use database (meaning I had to add roles tables, etc) to use this role provider.
If yes is there another way I could implement this?
If you use SimpleMembership Provider the tables you will get automaticlly will be --> Your user table, Roles, UsersInRoles, Membership where in Roles you can add roles you wish and in UsersInRoles you can add users to role with this line:
assuming you already have the role "Admin" seed-ed into your database table for Roles
System.Web.Security.Roles.AddUsersToRole("username, "yourrolename");
the seeding of the role in the Roles table in the database is as you do it:
WebSecurity.InitializeDatabaseConnection("DefaultConnection",
"UserProfile", "UserId", "UserName", autoCreateTables: true);
var roles = (SimpleRoleProvider)Roles.Provider;
var membership = (SimpleMembershipProvider)Membership.Provider;
if (!roles.RoleExists("Admin"))
{
roles.CreateRole("Admin");
}
// you can do the seed of the role to user in the seed method too
if (membership.GetUser("user", false) == null)
{
membership.CreateUserAndAccount("user", "123456");
}
if (!roles.GetRolesForUser("user1").Contains("Admin"))
{
roles.AddUsersToRoles(new[] { "user" }, new[] { "Admin" });
}
you will also have to change the membership paragraph in your web config with this:
<roleManager enabled="true" defaultProvider="SimpleRoleProvider">
<providers>
<clear />
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear />
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
but is not needed to be done every time you add user to role. Hope this helps.

Resources