MVC5 Identity Seed Users in database - asp.net-mvc-5

I am getting an error that says: "UserId not found." when trying to seed multiple users into my database.
Here is my seed method:
protected override void Seed(newBestPlay.Models.ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
InitialCreate create = new InitialCreate();
create.Down();
create.Up();
context.Configuration.LazyLoadingEnabled = true;
if (!context.Roles.Any(r => r.Name == "Admin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "Admin" };
manager.Create(role);
}
if (!context.Roles.Any(r => r.Name == "User"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "User" };
manager.Create(role);
}
if (!context.Users.Any(u => u.UserName == "user1"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "user1", Email = "email1" };
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
if (!context.Users.Any(u => u.UserName == "user2"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "user2", Email = "email2" };
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
}
It is failing on that last "manager.AddToRole" line. I figured out the second user isn't even getting added to the database, so it can't find a user.Id since it never got added.

Figured it out. It was not allowing dashes in my username. My username(email) has a dash in the domain part. I had to add in
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false };
into my IdentityConfig.cs file into the ApplicationUserManager constructor so it now looks like this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false };
}
.....

add this into your seed method:
var manager = new UserManager<ApplicationUser>(store);
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
};

Related

IdentityServer 4 - user roles missing

In my Client I have the following set up.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
//options.DefaultSignInScheme = "Cookies",
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = "...";
options.ClientId = "...";
options.SaveTokens = true;
options.ClientSecret = "secret";
options.SignInScheme = "Cookies";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("roles");
options.ResponseType = "code id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Events = new OpenIdConnectEvents()
{
OnTokenValidated = tokenValidatedContext =>
{
var identity = tokenValidatedContext.Principal.Identity
as ClaimsIdentity;
var targetClaims = identity.Claims.Where(z =>
new[] {"sub"}.Contains(z.Type));
var newClaimsIdentity = new ClaimsIdentity(
targetClaims,
identity.AuthenticationType,
"given_name",
"role");
tokenValidatedContext.Principal =
new ClaimsPrincipal(newClaimsIdentity);
return Task.CompletedTask;
},
OnUserInformationReceived = userInformationReceivedContext =>
{
return Task.FromResult(0);
}
};
});
My client at the level of IdentityServer is defined as follows.
new Client()
{
ClientName = "My App",
ClientId = "mymagicapp",
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = new List<string>()
{
"https://..."
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"roles"
},
ClientSecrets = { new Secret("secret".Sha256()) },
PostLogoutRedirectUris =
{
"https://..."
}
}
The new "roles" scope is added as per below.
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>()
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource("roles", "Your role(s)", new List<string>(){"role"})
};
}
A user is defined as follows.
new TestUser()
{
SubjectId = "abcdef",
Username = "Jane",
Password = "password",
Claims = new List<Claim>()
{
new Claim("given_name", "Jane"),
new Claim("family_name", "Doe"),
new Claim("role", "FreeUser")
}
}
After logging in to my MVC client, in the Controller the User.Claims object does not contain role claim.
However, in the OnUserInformationReceived the userInformationReceivedContext's User object does contain the role claim.
What am I missing?
Based on
Missing Claims in the ASP.NET Core 2 OpenID Connect Handler?
OIDC, I cannot add extra claims from userinfo endpoint
the solution was to add options.ClaimActions.MapJsonKey("role", "role"); inside .AddOpenIdConnect(options => ...)
From the second link:
2.0 no longer adds all possible information from the user-info endpoint, it was causing major cookie bloat leading to login issues. There is now a system called ClaimActions where you can select which elements you want to map from the user info doc to claims. See OpenIdConnectOptions.ClaimActions.

MVC 5 create user using Identity 2 in synchronous way

I'm trying to create new user and add him to selected role. I want to do it sync way, but always get stacked at point of creating in part ModelState. If I make it without ModelState then method will stack at point adminresult where is user created with UserManager. It looks like there is a problem with adding user to selected role, but I'm not sure. I'm using Identity 2. Is it possible to create user sync way or is it totally async process?
[HttpPost]
public ActionResult Create(User userViewModel, params string[] selectedRoles)
{
if (ModelState.IsValid)
{
var user = new User()
{
UserName = userViewModel.UserName,
Email = userViewModel.Email,
FirstName = userViewModel.FirstName,
LastName = userViewModel.LastName,
Password = userViewModel.Password
};
var adminresult = UserManager.Create(user, userViewModel.Password); // without using ModelState stack here
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var userStore = new UserStore<User>(context);
var userManager = new UserManager<User>(userStore);
var result = userManager.AddToRoles(user.Id, selectedRoles);
if (adminresult.Succeeded)
{
if (selectedRoles != null)
{
if (!result.Succeeded)
{
ModelState.AddModelError("", result.Errors.First());
// gets all names of roles to list
ViewBag.RoleId = new SelectList(RoleManager.Roles.ToList(), "Name", "Name");
return View("_Create");
}
}
return RedirectToAction("UserWizardIndex");
}
return View("_Create");
}
I would recommend you to use group based roles instead of giving multiple roles at login.
Your a sync will work fine in this way if single role is at login..
one thing that I saw in your code is if you have selected multiple
roles why there isn't any way to add every role against that user...
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var roleManager = new RoleManager<IdentityRole>
(
new RoleStore<IdentityRole>
(
new ApplicationDbContext()
)
);
if (!roleManager.RoleExists(model.RoleName))
{
roleManager.Create(new IdentityRole(model.RoleName));
}
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var role = Db.GetUserRoleId(model.RoleName);
var strRole = role.FirstOrDefault().ToList();
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var userInfo = new UserInformation
{
FirstName = model.FirstName,
LastName = model.LastName,
GUID = user.Id,
RoleId = model.RoleId
};
Db.UserInformations.Add(userInfo);
UserManager.AddToRoles(userInfo.GUID, model.RoleName);
await UserManager.UpdateSecurityStampAsync(user.Id);
Db.SaveChanges();
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}

Can`t login with seeded database configuration using asp.net identity

I have a problem with login, even though i see the tables are filled with my seeded user info from Configuration.cs:
protected override void Seed(www.Models.ApplicationDbContext context)
{
if (!context.Roles.Any(x => x.Name == "admin"))
{
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var role = new IdentityRole { Name = "admin" };
roleManager.Create(role);
}
if (!context.Users.Any(x => x.UserName == "admin" && x.Email == "admin#admin.com"))
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var user = new ApplicationUser { UserName = "admin", Email = "admin#admin.com" };
var hasher = new PasswordHasher();
userManager.Create(user, "MySecret5");
userManager.AddToRole(user.Id, "admin");
}
}
and when i try to login i get error "Invalid login attempt".
What am i missing?
EDIT:
Im in the process of learning all stuff about asp.net so im pretty big noob now :( so i found this example to be working for me, and if anyone else needs it here it is:
protected override void Seed(www.Models.ApplicationDbContext context)
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!context.Users.Any(x => x.UserName == "admin#v.com"))
{
var user = new ApplicationUser { UserName = "admin#v.com", Email = "admin#v.com" };
userManager.Create(user, "Password5%");
context.Roles.AddOrUpdate(x => x.Name, new IdentityRole { Name = "admin" });
context.SaveChanges();
userManager.AddToRole(user.Id, "admin");
}
}
And thanks for all your help and time.
It seems that the problem with logging in with seeded users is associated with MVC inaccuracy, look at:
var result = await SignInManager.PasswordSignInAsync(model.Emali, model.Password, model.RememberMe, shouldLockout: false);
if we seed this user:
var user = new ApplicationUser { UserName = "SomeName", Email = "admin#v.com" };
result will be == false, but if we change model.Emali in result to model.UserName then login end with success - of course now when we log in, we must give the UserName e.g:
UserName: SomeName;
Passwort: Password5%;
This worked flawlessly for me.
protected override void Seed(www.Models.ApplicationDbContext context)
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!context.Users.Any(x => x.UserName == "admin#v.com"))
{
var user = new ApplicationUser { UserName = "admin#v.com", Email = "admin#v.com" };
userManager.Create(user, "Password5%");
context.Roles.AddOrUpdate(x => x.Name, new IdentityRole { Name = "admin" });
context.SaveChanges();
userManager.AddToRole(user.Id, "admin");
}
}

Check if Current Users belongs to SP group using javascript Client Side Object Model

I havent found a specific example of how to get the current user and then check if it belongs to a specific sharepoint group, as I havent found anything I cant provide a code,
help on the right direction is appreciated.
SharePoint 2013 CSOM
Prerequisites: compatible with SharePoint 2013 CSOM API only since
SP.GroupCollection.getByName Method is not available in
SharePoint 2010
How to check if current user belongs to SharePoint group via CSOM (JavaScript):
function IsCurrentUserMemberOfGroup(groupName, OnComplete) {
var currentContext = new SP.ClientContext.get_current();
var currentWeb = currentContext.get_web();
var currentUser = currentContext.get_web().get_currentUser();
currentContext.load(currentUser);
var allGroups = currentWeb.get_siteGroups();
currentContext.load(allGroups);
var group = allGroups.getByName(groupName);
currentContext.load(group);
var groupUsers = group.get_users();
currentContext.load(groupUsers);
currentContext.executeQueryAsync(OnSuccess,OnFailure);
function OnSuccess(sender, args) {
var userInGroup = false;
var groupUserEnumerator = groupUsers.getEnumerator();
while (groupUserEnumerator.moveNext()) {
var groupUser = groupUserEnumerator.get_current();
if (groupUser.get_id() == currentUser.get_id()) {
userInGroup = true;
break;
}
}
OnComplete(userInGroup);
}
function OnFailure(sender, args) {
OnComplete(false);
}
}
Usage
IsCurrentUserMemberOfGroup("Approvers", function (isCurrentUserInGroup) {
if(isCurrentUserInGroup)
{
//...
}
});
SharePoint 2010/2013 CSOM
function isUserMemberOfGroup(userId, groupId, success,error) {
var ctx = SP.ClientContext.get_current();
var allGroups = ctx.get_web().get_siteGroups();
var group = allGroups.getById(groupId);
ctx.load(group,'Users');
ctx.executeQueryAsync(
function(sender, args) {
var userInGroup = findUserById(group.get_users(),userId);
success(userInGroup);
},
error);
var findUserById = function(users,id){
var found = false;
var e = group.get_users().getEnumerator();
while (e.moveNext()) {
var user = e.get_current();
if (user.get_id() == id) {
found = true;
break;
}
}
return found;
};
}
Usage
var currentUserId = _spPageContextInfo.userId;
var groupId = 4;
isUserMemberOfGroup(currentUserId, groupId,
function (isCurrentUserInGroup) {
if(isCurrentUserInGroup)
console.log('Current user is a member of Owners group');
else
console.log('Current user is not a member of Owners group');
},
function(sender,args){
console.log(args.get_message());
});
Here's a quicker way with SharePoint 2013:
function CheckCurrentUserMembership() {
var clientContext = new SP.ClientContext.get_current();
this.currentUser = clientContext.get_web().get_currentUser();
clientContext.load(this.currentUser);
this.userGroups = this.currentUser.get_groups();
clientContext.load(this.userGroups);
clientContext.executeQueryAsync(OnQuerySucceeded);
}
function OnQuerySucceeded() {
var isMember = false;
var groupsEnumerator = this.userGroups.getEnumerator();
while (groupsEnumerator.moveNext()) {
var group= groupsEnumerator.get_current();
if(group.get_title() == "Administrator Group") {
isMember = true;
break;
}
}
OnResult(isMember);
}
function OnQueryFailed() {
OnResult(false);
}
If anyone is interested. This approach can be used when you want to check if a user is a member of a group using the group name.
var currentUserIsMemberOf = function(groupName){
var found = false;
var dfd = $.Deferred(function(){
SP.SOD.executeOrDelayUntilScriptLoaded(function(){
context = new SP.ClientContext.get_current();
allGroups = context.get_web().get_siteGroups();
context.load(allGroups);
context.load(allGroups, 'Include(Users)');
context.executeQueryAsync(
function(){
var groupsEnumerator = allGroups.getEnumerator();
while (groupsEnumerator.moveNext()) {
var group = groupsEnumerator.get_current();
if(group.get_title() == groupName) {
var usersEnumerator = group.get_users().getEnumerator();
while (usersEnumerator.moveNext()) {
var user = usersEnumerator.get_current();
if(user.get_id() == _spPageContextInfo.userId) {
found = true;
break;
}
}
}
}
dfd.resolve(found);
},
function(){
dfd.reject(args.get_message());
}
);
}, 'sp.js');
});
return dfd.promise();
}
You can use like this
currentUserIsMemberOf("Members of Demo").done(function(result){
alert(result)
});
Note this code use Promise, you can reference jQuery use your own custom Deferred object or remove Deferred object.

Xamarin.Auth with Twitter

I am trying to implement login with Facebook and Twitter. I got it working with Facebook but don't know how to do it with Twitter. Are there any examples? My Facebook implementation is like this:
var auth = new OAuth2Authenticator(
clientId: "*****************",
scope: "email",
authorizeUrl: new System.Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new System.Uri("http://www.facebook.com/connect/login_success.html"));
StartActivity(auth.GetUI(this));
auth.Completed += (senderFb, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
AccountStore.Create(this).Save(eventArgs.Account, "Facebook");
// Now that we're logged in, make a OAuth2 request to get the user's info.
var request = new OAuth2Request("GET", new System.Uri("https://graph.facebook.com/me"), null, eventArgs.Account);
request.GetResponseAsync().ContinueWith(t =>
{
if (!t.IsFaulted && !t.IsCanceled)
{
var obj = JsonValue.Parse(t.Result.GetResponseText());
if (obj != null)
{
var user = new UserProfile
{
FirstName = obj["first_name"],
LastName = obj["last_name"],
FacebookProfileLink = obj["link"],
FacebookToken = eventArgs.Account.Properties["access_token"],
Gender = obj["gender"] == "female" ? "Female" : "Male",
EmailAddress = obj["email"],
DisplayName = obj["name"],
Name = obj["name"],
LoginName = obj["email"]
};
SignUpUser(user);
}
}
}, uiScheduler);
}
};
You can use oauth1 like this.
this.Authenticator = new OAuth1Authenticator (ConsumerKey, ConsumerSecret, RequestTokenUrl, AuthorizeUrl, AccessTokenUrl, DummyCallBackUrl, (IDictionary<string, string> accountProperties) => {
string screen_name = "";
if (accountProperties.TryGetValue("screen_name", out screen_name)) {
Account a = new Account(screen_name, accountProperties);
AuthenticatorCompletedEventArgs e = new AuthenticatorCompletedEventArgs(a);
CompleteAuthentication(e);
}
return null;
});
twitter api dosen't fully support OAuth2

Resources