WebSecurity vs FormsAuthentication in ASP.NET MVC4 - asp.net-membership

I guess I am trying to mix two providers in project but I am looking to use websecurity in conjunction to my forms authentication. I need websecurity for OAUTH authentication using Facebook, and google.
The error that I am getting when I try to login using facebook is
To call this method, the Membership.Provider property must be an instance of ExtendedMembershipProvider.
Here are the code samples. How can I use both?
public ActionResult ExternalLoginCallback(string returnUrl)
{
AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
if (!result.IsSuccessful)
{
return RedirectToAction("ExternalLoginFailure");
}
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
{
return RedirectToLocal(returnUrl);
}
if (User.Identity.IsAuthenticated)
{
// If the current user is logged in add the new account
OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
return RedirectToLocal(returnUrl);
}
else
{
// User is new, ask for their desired membership name
string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
ViewBag.ReturnUrl = returnUrl;
return View("ExternalLoginConfirmation", new RegisterExternalLoginModel { UserName = result.UserName, ExternalLoginData = loginData });
}
}
and
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

Could possibly be related to the same issue as me MVC4 ExtendedMembershipProvider and entityframework
.. I removed the universal providers nuget package and this particular error dissappeared.
Also this "very recent" article by Jon Galloway may help.

If you are using Visual Studio, you might want to save yourself all this effort. The MVC 4 Internet template comes with four external identity providers out of the box. I have tested them and Google Accounts, Microsoft account, Facebook login, and Twitter login all work fine, with zero lines of code!
I think the same is provided with the Web Form template too.
More info at http://blogs.msdn.com/b/webdev/archive/2012/08/15/oauth-openid-support-for-webforms-mvc-and-webpages.aspx.

You can use an implementation of ExtendedMembershipProvider. For ex: the built-in SimpleMembershipProvider.
Every ExtendedMembershipProvider IS A MembershipProvider .
Read more at Jon Galloway's Blog.

Related

How to redirect from Identity Area to Admin in ASP.NET CORE 2

I cant redirect from Identity Area:
if (role=="Admin")
{
return RedirectToAction("Index","Home",new { Area=Input.Role ,id=9});
}
To Admin Area Controller-Home,Action-Index.Always redirect me to Index in the Identity Area;
looking at your code I am still scratching my head as to the reason that someone would specify the Role at login. Can you articulate the reasoning behind this?
Simplest answer is inline with the code within the OnPostAsync(); that resides in
//this because of the routes you have in StartUp.cs
[Authorize(Roles ="Admin")]
[Area("admin")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
Login.cs Page...
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
var user = await userManager.GetUserAsync(User); // Claims Principle
if (await userManager.IsInRoleAsync(user, "Admin"))
{
//SIMPLEST ANSWER since you using mixed environment with PAGES
return LocalRedirect("~/admin");
}
//TODO:
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
Check your issues below one by one:
I got error A method 'CakeStore.App.Areas.Admin.Controllers.HomeController.Index (CakeStore.App)' must not define attribute routed actions and non attribute routed actions at the same time, you should not define [HttpGet(Name ="AdminPanel")] and [Route(nameof(Admin) + "/[controller]")] at the same time.
//[HttpGet(Name ="AdminPanel")]
[Area(nameof(Admin))]
[Route(nameof(Admin) + "/[controller]")]
public IActionResult Index()
{
return View();
}
For var role = this.roleManage.GetUrl(Input.Username);, it will retrive the role by username, check whether you got expected role Admin.
return RedirectToAction("Index","Home",new { Area=Input.Role ,id=9});, you did not define id in Index, there is no need to add id route.

SignInStatus always returns Success on TwoFactorAuthentication is enabled in webapi using asp.net identity

I am implementing 2 factor authentication in WebApi, asp.net identity and OWIN. Every time I log in, I get SignInStatus = Success never reaches to SignInStatus = RequiresVerification though user TwoFactorAuthentication is enabled.
Below are some code snippets,
Startup.cs:
private void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
app.UseOAuthBearerTokens(OAuthOptions);
}
Action method for enabling two factor authentication,
[HttpPost]
public async Task<IHttpActionResult> EnableTwoFactorAuthentication()
{
var user = await this.AppUserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
IdentityResult result = await this.AppUserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
await this.AppSignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
}
return Ok();
}
Please suggest a solution.
If you get stuck here, one way to solve the problem is to copy the methods from SignInManager directly into your code and call those instead so you can step through the methods and see why you are getting the wrong status. For me the problem ended up being that I instantiated my UserManager with:
new MyUserManager()
instead of the right way:
HttpContext.GetOwinContext().Get<MyUserManager>()
I was using this as my template for setting it up:
https://github.com/adamtuliper/ASP.NET-Identity-Samples/tree/master/BasicTemplate%20-%20Two%20Factor/BasicTemplate
SignInManager return RequiresVerification if :
dbo.ASpnetUsers has for user set to true TwoFactorEnabled and EmailConfirmed and user email should be confirmed, email not be empty or null.
var result = SignInManager.PasswordSignIn(usernameIdentity, model.Password, model.RememberMe, shouldLockout: true);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", returnUrl);
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid username or password.");
return View(model);
}

Add admin page without full fledged user management

I am building a rather simple site with ASP.NET Core MVC 2.0 that is more or less an image gallery, just for me. I am not using any database so far. It is just a json file with metadata and the image files itself.
Now this site is supposed to get a hidden admin page where I (and only I) can upload new pictures.
What would be a simple but still secure way to add this admin page without having to introduce a full fledged user management to the site? I'd like to avoid to add a database and entity framework etc. to the site - there will only be one user.
In other words, what is a secure and simple way to add user management where there are is only one user that authenticates: Me, the admin.
Store a hashed version of your desired username/password in the appsettings.json and then rehash the values provided through the login screen and compare them.
Here's an example of how logging in could be accomplished. This bootstraps off of the default hasher present in Asp.Net Identity but you could use any hashing function.
You might want to create some other helpers too in case you want to reset the hashed password from your application versus having to go into the settings file.
appsettings.json
{
...
"LoginCredentials": {
"UsernameHash": "AQAAAAEAACcQAAAAENmv+riLvtTIa5wafXxzEX4rMSMXwVzG00q4jZKBI7Lx/oe2PFdqW1r521HBsL567g==",
"PasswordHash": "AQAAAAEAACcQAAAAEKwwppiixEQM9QO7hOXcoXXgIvHKs9QHRz1k0lAZ3noVwID2lv+I+Dwc9OheqDGFBA=="
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//Assuming services.AddIdentity<...>(...) is not added as a service
services.Configure<LoginCredentialOptions>(Configuration.GetSection("LoginCredentials"));
services.AddTransient<IPasswordHasher<User>, PasswordHasher<User>>();
...
}
LoginCredentialOptions.cs
public class LoginCredentialOptions
{
public string UsernameHash { get; set; }
public string PasswordHash { get; set; }
}
AccountController.cs
...
public async Task<IActionResult> Login([FromServices] IOptions<LoginCredentialOptions> loginCreds, LoginViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
var passwordResult = passwordHasher.VerifyHashedPassword(null, loginCreds.Value.PasswordHash, model.Password);
var usernameResult = passwordHasher.VerifyHashedPassword(null, loginCreds.Value.UsernameHash, model.Username);
if (passwordResult == PasswordVerificationResult.Success &&
usernameResult == PasswordVerificationResult.Success)
{
//Create identity cookie and sign in
RedirectToAction(nameof(Index), "Home");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

Access claims in web api controller in mvc5 project

I have a MVC5 project with ASP.NET Identity. I'm using Claims in my MVC5 controllers like below.
public ActionResult Index()
{
var prinicpal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var email = prinicpal.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();
}
However the Claims are not available in a WebApi controller in the same project. What do I have to do to get access to the Claims of the logged in user in a WebApi Controller in a MVC5 project?
Thank You.
Make sure your WebAPI controller or action is decorated with [Authorize]. You will never get current user context for anonymous requests.
[HttpGet]
[Authorize]
public IHttpActionResult Get()
{
try
{
var user = this.User as ClaimsPrincipal; //OR
var prinicpal = (ClaimsPrincipal)Thread.CurrentPrincipal;
var email = prinicpal.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
return Ok();
}

ASP.Net MVC Validation (server side)

asp.net mvc server side validation when the javascript is disabled in the browser? i used "remote" in my modal class it validates only when the javascript is enabled it doesnt validate when the javascript is disabled.
Scenario for my problem is i have a table in my db with a column "code" with the datatype varchar. any one inserts the data they must insert the unique code.
Please do help me out
I would suggest to forget about remote because if you are using code first entity framework, you can't have more that one unique column in your table. I would just write code for it like this:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Insert a new user into the database
using (UsersContext db = new UsersContext())
{
UserProfile email = db.UserProfiles.FirstOrDefault(u => u.Email.ToLower() == model.Email.ToLower());
try
{
// Check if email already exists
if (email == null)
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email });
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("Email", "Email address already exists. Please enter a different email address.");
}
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
}
Replace the email with the property you want to validate. At post, this will compare with entries with what already exists in your database, and depending on results, it will give you feedback. Throws exception if such data exists.

Resources