I am Implementing Social login in my application but I am getting an error "No parameterless constructor defined for this object".I am not able to find out the reason behind this.can any one tell me exactly what haapening.My Controller is as follows:
[AllowAnonymous]
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 I am getting an error in this line:
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
Please Let me know..
Related
I have to get roles of a user from DB as per my application nature. I am authenticating user in context.AcquireRequestState += context_AcquireRequestState; event handler in HttpModule. Can I do db calls from HttpModule to assign roles in Identity? Is it good practice? if not, where I have to do it before controller’s action method called.?
I dont know what you doing with Aquaire request state, Ideally you have to do as below:
[Authorize(Roles="Admin")]
[Route("user/{id:guid}/roles")]
[HttpPut]
public async Task<IHttpActionResult> AssignRolesToUser([FromUri] string id, [FromBody] string[] rolesToAssign)
{
var appUser = await this.AppUserManager.FindByIdAsync(id);
if (appUser == null)
{
return NotFound();
}
var currentRoles = await this.AppUserManager.GetRolesAsync(appUser.Id);
var rolesNotExists = rolesToAssign.Except(this.AppRoleManager.Roles.Select(x => x.Name)).ToArray();
if (rolesNotExists.Count() > 0) {
ModelState.AddModelError("", string.Format("Roles '{0}' does not exixts in the system", string.Join(",", rolesNotExists)));
return BadRequest(ModelState);
}
IdentityResult removeResult = await this.AppUserManager.RemoveFromRolesAsync(appUser.Id, currentRoles.ToArray());
if (!removeResult.Succeeded)
{
ModelState.AddModelError("", "Failed to remove user roles");
return BadRequest(ModelState);
}
IdentityResult addResult = await this.AppUserManager.AddToRolesAsync(appUser.Id, rolesToAssign);
if (!addResult.Succeeded)
{
ModelState.AddModelError("", "Failed to add user roles");
return BadRequest(ModelState);
}
return Ok();
}
Source read here
I try to set an user object property in my unit test. This property is correctly passed to a custom user validator and was verified to be set during debugging. However, the IdentityResult still shows a blank property error.
I have this custom user validator:
public class CustomUserValidator : UserValidator<AppUser>
{
public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> userManager, AppUser user)
{
//Here, the user.UserName property is set from the unit test, but the result still has an error for a blank UserName property
IdentityResult result = await base.ValidateAsync(userManager, user);
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
if (user.Email.ToLower().EndsWith("#myDomain.com"))
{
return await Task.FromResult(IdentityResult.Success);
}
else
{
errors.Add(new IdentityError
{
Code = "EmailDomainError",
Description = "Only myDomain.com email addresses are allowed"
});
}
return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
}
}
And I'm trying to use Moq and xUnit to create a test for the domain check on the email:
[Fact]
public async void Validate_User_Email()
{
//Arrange
var userManager = GetMockUserManager();
var customVal = new CustomUserValidator();
var user = Mock.Of<AppUser>(m => m.UserName == "joe" && m.Email == "joe#example.com");
//Act
//try to validate the user
IdentityResult result = await customVal.ValidateAsync(userManager.Object, user);
//Assert
//demonstrate that there are errors present
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
//Here there are 2 errors, one for a blank UserName and one (expected) error for the email address
Assert.Equal(1, errors.Count);
}
I'm writing my first Web API 2. I'm performing authorization using a custom HttpMessageHandler. However, my controller needs to know the username specified in the credentials.
Researching this, it appears that ApiController does not have a Controller.HttpContext property. And I see there are potential issues accessing HttpContext.Current. So while I am actually able to store the username in HttpContext.Current.Items in my HttpMessageHandler and then access that information from my controller, I'm not sure that will always be reliable.
I also saw recommendations to use the RequestContext.Principal property; however, I could not find the current request's username anywhere in this data.
How can my controller reliably get the username for the current request?
NOTE: I refer to the username but in this case the actual user is another piece of software calling the API. The "username" reflects the software that is making the call.
#Win: Well, that part is what I am developing. But currently basic
authentication seems appropriate, where the username identifies the
software contacting us and the password is a special key
Here is the sample code for BasicAuthenticationMessageHandler which uses message handler to support HTTP Basic Authentication.
You can read more at Page 121 of ASP.NET Web API 2: Building a REST Service from Start to Finish.
IBasicSecurityService
public interface IBasicSecurityService
{
bool SetPrincipal(string username, string password);
}
BasicSecurityService
public class BasicSecurityService : IBasicSecurityService
{
public bool SetPrincipal(string username, string password)
{
// Get user from database
var user = GetUser(username);
IPrincipal principal = null;
if (user == null || (principal = GetPrincipal(user)) == null)
{
// System could not validate user
return false;
}
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
return true;
}
public virtual IPrincipal GetPrincipal(User user)
{
var identity = new GenericIdentity(user.Username, Constants.SchemeTypes.Basic);
identity.AddClaim(new Claim(ClaimTypes.GivenName, user.Firstname));
identity.AddClaim(new Claim(ClaimTypes.Surname, user.Lastname));
// Get authroized roles and add them as Role Claim.
identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));
return new ClaimsPrincipal(identity);
}
}
BasicAuthenticationMessageHandler
public class BasicAuthenticationMessageHandler : DelegatingHandler
{
public const char AuthorizationHeaderSeparator = ':';
private const int UsernameIndex = 0;
private const int PasswordIndex = 1;
private const int ExpectedCredentialCount = 2;
private readonly IBasicSecurityService _basicSecurityService;
public BasicAuthenticationMessageHandler(IBasicSecurityService basicSecurityService)
{
_basicSecurityService = basicSecurityService;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// Already authenticated; passing on to next handler...
return await base.SendAsync(request, cancellationToken);
}
if (!CanHandleAuthentication(request))
{
// Not a basic auth request; passing on to next handler...
return await base.SendAsync(request, cancellationToken);
}
bool isAuthenticated;
try
{
isAuthenticated = Authenticate(request);
}
catch (Exception e)
{
// Failure in auth processing
return CreateUnauthorizedResponse();
}
if (isAuthenticated)
{
var response = await base.SendAsync(request, cancellationToken);
return response;
}
return CreateUnauthorizedResponse();
}
public bool CanHandleAuthentication(HttpRequestMessage request)
{
return (request.Headers != null
&& request.Headers.Authorization != null
&& request.Headers.Authorization.Scheme.ToLowerInvariant() == Constants.SchemeTypes.Basic);
}
public bool Authenticate(HttpRequestMessage request)
{
// Attempting to authenticate...
var authHeader = request.Headers.Authorization;
if (authHeader == null)
{
return false;
}
var credentialParts = GetCredentialParts(authHeader);
if (credentialParts.Length != ExpectedCredentialCount)
{
return false;
}
return _basicSecurityService.SetPrincipal(credentialParts[UsernameIndex], credentialParts[PasswordIndex]);
}
public string[] GetCredentialParts(AuthenticationHeaderValue authHeader)
{
var encodedCredentials = authHeader.Parameter;
var credentialBytes = Convert.FromBase64String(encodedCredentials);
var credentials = Encoding.ASCII.GetString(credentialBytes);
var credentialParts = credentials.Split(AuthorizationHeaderSeparator);
return credentialParts;
}
public HttpResponseMessage CreateUnauthorizedResponse()
{
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(Constants.SchemeTypes.Basic));
return response;
}
}
this my code for login :
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = UserManager.FindByNameAsync(model.UserName);
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
if (returnUrl != null)
return RedirectToLocal(returnUrl);
else if (await UserManager.IsInRoleAsync(user.Id, "Admin")) //<= Checking Role and redirecting accordingly.
return Redirect("~/Admin/Home/");
else
return Redirect("~/User/Home");
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
but it show me this error :
Argument 1: cannot convert from 'int' to 'string' GoKhoda
show error in this line :
else if (await UserManager.IsInRoleAsync(user.Id, "Admin"))
this line for find user and role of user for redirect to page .
how can i solve this ?
Edit
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
Edit(2)
When i using the .TosString() show me this error .
IMHO your error is more than just int to String conversion, it is related to FindByNameAsync method. The problem occurs when IsInRoleAsync method requested for UserId property but the property doesn't exist in ApplicationUser class (related to Dapper mapping issue).
According to MVC - InvalidOperationException: UserId not found, ensure FindByNameAsync to include Id property in ApplicationUser like this one (use your EF database context if you have it instead of query statement):
public async Task<ApplicationUser> FindByNameAsync(string userName)
{
ApplicationUser result = null;
using (var conn = await GetOpenDBConnection())
{
try
{
// note that UserId does not exist on ApplicationUser by default
// thus we need to adjust the query statement
var queryResults = await conn.QueryAsync<ApplicationUser>(
"SELECT UserId AS [Id], UserName, Email FROM dbo.Users WHERE UserName = #UserName;",
new { UserName = userName });
result = queryResults.FirstOrDefault();
}
catch (Exception ex)
{
// handle exception
}
}
return result;
}
Alternatively you may try FindByName method instead of FindByNameAsync there.
Regarding the await usage error, the exception explains that only one async operation allowed at a time in given context (see Multi-async in Entity Framework 6?), hence you need to move await outside if-condition or create a new context before executing second await:
var isInRole = await UserManager.IsInRoleAsync(user.Id.ToString(), "Admin");
// inside switch...case
if (returnUrl != null)
return RedirectToLocal(returnUrl);
else if (isInRole) //<= Checking Role and redirecting accordingly.
return Redirect("~/Admin/Home/");
else
return Redirect("~/User/Home");
or change to IsInRole if it still throwing exception:
if (returnUrl != null)
return RedirectToLocal(returnUrl);
else if (UserManager.IsInRole(user.Id.ToString(), "Admin")) //<= Checking Role and redirecting accordingly.
return Redirect("~/Admin/Home/");
else
return Redirect("~/User/Home");
This may or may not solve your entire issue, but may explain what should you do to handle async-related issues.
Related problems:
MVC InvalidOperationException adding role to user
Manually Map column names with class properties
Entity framework async issues context or query?
I am trying to get to grips with the new Membership system introduced in ASP.NET MVC 5 and I've come across a small issue which I am pretty sure you will be able to help me with.
I am going based off this tutorial and have introduced custom properties to ApplicationUser such as Name, Surname, DOB, etc.
However, instead of creating the user, I am trying to update the currently logged in one. I am looking at the controller method which is currently used to change password.
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
string userId = User.Identity.GetUserId();
bool hasLocalLogin = await IdentityManager.Logins.HasLocalLoginAsync(userId);
ViewBag.HasLocalPassword = hasLocalLogin;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasLocalLogin)
{
if (ModelState.IsValid)
{
IdentityResult result = await IdentityManager.Passwords.ChangePasswordAsync(User.Identity.GetUserName(), model.OldPassword, model.NewPassword);
if (result.Success)
{
return RedirectToAction("Manage", new { Message = "Your password has been changed." });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a local password so remove any validation errors caused by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
// Create the local login info and link it to the user
IdentityResult result = await IdentityManager.Logins.AddLocalLoginAsync(userId, User.Identity.GetUserName(), model.NewPassword);
if (result.Success)
{
return RedirectToAction("Manage", new { Message = "Your password has been set." });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
How exactly would I go on about updating an ApplicationUser's Surname for example? Do I need to call the DbContext or?
I hope my question is clear.
Explore IdentityManager.Store.UserManagement and IdentityManager.Store.Users.
ApplicationUser cUser = (ApplicationUser) await IdentityManager.Store.Users.FindByNameAsync(HttpContext.User.Identity.Name, new System.Threading.CancellationToken());
cUser.Surname = "New Something";
IdentityResult result1 = await IdentityManager.Store.SaveChangesAsync();
Above code is an example only. Basically you need to explore the Store property of IdentityManage.
When we used the Users object of our database context we ran into other tracking errors. In our application, we would retrieve users as such
var user = UserManager.FindById(userId);
Edit the properties:
user.StorageName = "gooblygook";
//whatever other properties you would like to use
And then we would save it with the UserManager in the controller:
UserManager.Update(user);
This is currently a working solution for us.
Mark the Person object as virtual in your ApplicationUser definition. That worked for me.
public class ApplicationUser : IdentityUser
{
public virtual Person Person { get; set; }