I have changed the AspNetUser (identity) tabe to only user with the following code.
// Change the name of the table to be Users instead of AspNetUsers
modelBuilder.Entity<IdentityUser>()
.ToTable("Users").Property(p => p.Id).HasColumnName("UserID");
modelBuilder.Entity<ApplicationUser>()
.ToTable("Users").Property(p => p.Id).HasColumnName("UserID");
My application works fine but not my seed. I have this code in Migrations/Configuration.cs
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
string role = "Admin";
string password = "Password#1234";
//Create Role Admin if it does not exist
if (!RoleManager.RoleExists(role))
{
var roleresult = RoleManager.Create(new IdentityRole(role));
}
//Create Admin users with password=123456
var admin1 = new ApplicationUser();
admin1.UserName = "admin1#admin1.com";
admin1.Email = "admin1#admin1.com";
admin1.EmailConfirmed = true;
UserManager.Create(admin1, password);
UserManager.AddToRole(admin1.Id, role);
context.SaveChanges();
I get the error message "UserId not found". Seems like my UserManager.Create fails.
How can I change my seed code to use the UserID insted of standard Id?
Actually, when you save the user, it does not have an id given yet, you'll have to retrieve the user in between the creation of the user & addToRole:
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var RoleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
string role = "Admin";
string password = "Password#1234";
//Create Role Admin if it does not exist
if (!RoleManager.RoleExists(role))
{
var roleresult = RoleManager.Create(new IdentityRole(role));
}
//Create Admin users with password=123456
var admin1 = new ApplicationUser();
admin1.UserName = "admin1#admin1.com";
admin1.Email = "admin1#admin1.com";
admin1.EmailConfirmed = true;
UserManager.Create(admin1, password);
// Refetch user with ID:
dbAdmin1 = context.Users.FirstOrDefault(x => x.UserName == admin1.UserName);
UserManager.AddToRole(dbAdmin1.Id, role);
context.SaveChanges();
Related
I am registering AAD Applications through the following code
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await GetAppTokenAsync());
Application application = new Application()
{
AvailableToOtherTenants = false,
DisplayName = appName,
ErrorUrl = null,
GroupMembershipClaims = null,
Homepage = "http://"+appName,
IdentifierUris = new List<string>() { "https://"+appName },
KeyCredentials = new List<KeyCredential>(),
KnownClientApplications = new List<Guid>(),
LogoutUrl = null,
Oauth2AllowImplicitFlow = false,
Oauth2AllowUrlPathMatching = false,
Oauth2Permissions = new List<OAuth2Permission>(),
Oauth2RequirePostResponse = false,
// PasswordCredentials = new List<PasswordCredential>(),
PasswordCredentials = new List<PasswordCredential>(),
PublicClient = false,
ReplyUrls = new List<string>(),
// RequiredResourceAccess = new List<RequiredResourceAccess>(),
RequiredResourceAccess = new List<RequiredResourceAccess>(),
SamlMetadataUrl = null,
ExtensionProperties = new List<ExtensionProperty>(),
Manager = null,
ObjectType = "Application",
DeletionTimestamp = null,
CreatedOnBehalfOf = null,
CreatedObjects = new List<DirectoryObject>(),
DirectReports = new List<DirectoryObject>(),
Members = new List<DirectoryObject>(),
MemberOf = new List<DirectoryObject>(),
Owners = new List<DirectoryObject>(),
OwnedObjects = new List<DirectoryObject>(),
Policies = new List<DirectoryObject>()
};
I also have an object of type Microsoft.Azure.ActiveDirectory.GraphClient.User which contains all the information of a User that I want to add as owner of the application.
How can I do that?
The way I was trying that is by doing this
activeDirectoryClient.Applications.AddApplicationAsync(application).Wait();
ServicePrincipal newServicePrincpal = new ServicePrincipal();
if (application != null)
{
newServicePrincpal.DisplayName = application.DisplayName;
newServicePrincpal.AccountEnabled = true;
newServicePrincpal.AppId = application.AppId;
newServicePrincpal.Owners.Add(user);
try
{
activeDirectoryClient.ServicePrincipals.AddServicePrincipalAsync(newServicePrincpal).Wait();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
But when I navigate to the application manually in the Azure Portal, the only owner that appears is my own account and not also the other account I got in the user variable
Any idea how to add other owners to the application?
I can reproduce this issue too. The root cause for this issue is that the Azure AD Graph library doesn't provide the owner info when it try to create the service principal.
If you want to add the owner for the service principal, you can use code below after you creating the service principal:
var activeDirectoryClient = GraphHelper.CreateGraphClient();
var sp = (ServicePrincipal)activeDirectoryClient.ServicePrincipals.GetByObjectId("4af8365b-1b49-481c-8c47-7b3fab5611fc").ExecuteAsync().Result;
var user = new Users().GetUserByUserName(activeDirectoryClient, "user2#adfei.onmicrosoft.com").Result;
sp.Owners.Add(user);
sp.UpdateAsync();
And if you want to add the owner of application, here is the code for you reference:
var activeDirectoryClient = GraphHelper.CreateGraphClient();
var app = (Application)activeDirectoryClient.Applications.GetByObjectId("bd87934b-dd4f-446a-a025-7675d1b2464a").ExecuteAsync().Result;
var user = new Users().GetUserByUserName(activeDirectoryClient, "user2#adfei.onmicrosoft.com").Result;
app.Owners.Add(user);
app.UpdateAsync();
More detail about the difference between application and service principal please check this document.
And if you want the Graph client library to support adding the owner when creating the them, you can try to submit the feedback from here.
Update
public static ActiveDirectoryClient CreateGraphClient()
{
string accessToken = "";
string tenantId= "";
string graphResourceId = "https://graph.windows.net";
Uri servicePointUri = new Uri(graphResourceId);
Uri serviceRoot = new Uri(servicePointUri, tenantId);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
return activeDirectoryClient;
}
Add a runalbe code sample to add an owner for the service principal:
https://github.com/VitorX/AddServicePrincipalWithOwner
Update2
After you run the code sample in the above, you could capture the result using the Fiddler like below. And we can get the object id of service principal via the response of creating the service principal:
Then we can check the owners of principals via the REST like figure below:
In the AppHost module, I'm opening/creating an NHibernate based authentication repository (using the "ServiceStack.Authentication.NHibernate" module), and subsequently creating a default user:
HibernateFactory = RepoDatabaseFactory(typeof(ServiceStack.Authentication.NHibernate.UserAuthMap).Assembly);
NHSession = HibernateFactory.OpenSession();
container.Register(NHSession);
NHibernateUserAuthRepository UserRepository = new NHibernateUserAuthRepository(HibernateFactory);
container.Register(UserRepository);
CurrentSessionContext.Bind(NHSession);
var Authorization = UserRepository.GetUserAuthByUserName("miga");
if (Authorization == null)
{
UserRepository.CreateUserAuth(
new UserAuth
{
UserName = "miga",
FirstName = "xxxxxx",
LastName = "xxxxxx",
Address = "xxxxxxxxxxxx",
PostalCode = "xxxxxx",
City = "xxxxxx",
Country = "xxxxx",
Gender = "xxxxx",
PhoneNumber = "xxxxxx",
Email = "xxxxxxx",
Roles = new List<string> { RoleNames.Admin },
Culture = "xxxxx"
},
"xxxxxx");
}
container.Register<ICacheClient>(new MemoryCacheClient());
UserRepository.InitSchema();
where the RepoDatabaseFactory is:
public NHibernate.ISessionFactory RepoDatabaseFactory(Assembly AuthAssembly)
{
var Configuration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(ConnString).UseReflectionOptimizer()).Mappings(m =>
{
m.FluentMappings.AddFromAssembly(AuthAssembly);
})
.CurrentSessionContext("web")
.BuildConfiguration();
var Exporter = new SchemaExport(Configuration);
Exporter.Execute(false, false, false);
var SessionFactory = Configuration.BuildSessionFactory();
return (SessionFactory);
}
To a certain extent this works; i.e. the relevant tables are created ("UserAuth", "UserAuth_Permissions", "UserAuth_Roles", "UserOAuthProvider" and "UserOAuthProvider_Items"). When creating the user "miga" as above, you'll notice the line "Roles = new List { RoleNames.Admin }" in the "new UserAuth" statement. Subsequently, the user data above is in fact added to the "UserAuth" table, but the "Admin" role is not added to the "UserAuth_Roles" table as I would have expected. Inserting a new record in the "UserAuth_Roles" table manually (containing the user id of the "miga" user and the admin rolename - e.g. 1, "Admin") still - it appears - does not provide the "miga" user with an "Admin" role:
Using the following fragment:
var Client = new RestClient("http://localhost:42147/");
Client.Authenticator = new HttpBasicAuthenticator("miga", "xxxxxxxx");
var Request = new RestRequest("assignroles", Method.POST);
Request.RequestFormat = DataFormat.Json;
Request.AddBody(new { UserName = "Sally", Roles = "Write" });
var Response = Client.Post<AssignRoleResponse>(Request);
I get an authorization error with an "Invalid Role" message. So my question is basically how to get this working in an NHibernate context ?
I have a ServiceStack application that coexists with mvc5 in a single web project. The only purpose of the mvc5 part is to host a single controller action that receives a callback from janrain for javascript initiated social login. I could receive this callback in a SS service request, too, but then I don't know how I would do a redirect to the returnUrl that is passed through all the way from the javascript context. Even if I was able to figure this out, my question would still be the same.
Inside of the controller action, once I verify the janrain provided token resolves to a user in my system, I need to manually tell ServiceStack "hey trust me - this person is authorized".
All my searches lead to some code along the lines of the following snippet:
var authService = AppHostBase.Resolve<AuthService>();
authService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var AuthResponse = authService.Authenticate(new Auth
{
provider = "credentials",
UserName = user.user_id,
Password = user.password,
RememberMe = true
});
My first problem here is that I store hashed passwords (I support social login as well as manual login), so I don't know the user's password (and I shouldn't).
My second problem is that this code seems to only work for SS 3.X and not 4.X. I requires a ServiceStack.ServiceInterface.dll that is mysteriously missing from 4.X.
Is there a short and precise way to manually authenticate a user with SS on the server side?
Thanks
EDIT:
So far this is what I am doing: (This is not final code - I have commented out some things I don't know what to do with):
public class UsernameOnlyAuthorizationService : Service
{
public object Post(UsernameOnlyLoginRequest request)
{
var authProvider = new UsernameOnlyAuthProvider();
authProvider.Authenticate(this, GetSession(), new Authenticate()
{
UserName = request.username,
Password = "NotRelevant",
RememberMe = true
});
return HttpResult.Redirect(request.returnUrl);
}
}
public class UsernameOnlyAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
var authRepo = authService.TryResolve<IAuthRepository>().AsUserAuthRepository(authService.GetResolver());
ReferScienceDataContext db = authService.TryResolve<ReferScienceDataContext>();
var session = authService.GetSession();
IUserAuth userAuth;
var user = db.Users.FirstOrDefault(u => u.Username == userName);
if (user != null)
{
//AssertNotLocked(userAuth);
//session.PopulateWith(userAuth);
session.Id = user.Id.ToString();
session.UserName = user.Username;
session.FirstName = user.FirstName;
session.LastName = user.LastName;
session.IsAuthenticated = true;
session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture);
session.ProviderOAuthAccess = authRepo.GetUserAuthDetails(session.UserAuthId)
.ConvertAll(x => (IAuthTokens)x);
return true;
}
return false;
}
}
And from within my Janrain success callback code I call it so:
HostContext.ResolveService<UsernameOnlyAuthorizationService>().Post(new UsernameOnlyLoginRequest() {username = user.Username, returnUrl= returnUrl});
This seems to work nicely, however, I can't get it to remember my session across browser closes. I am hardcoding RememberMe = true - why is this not working?
I would do this by creating an internal service, which you can call from your MVC5 controller action, where you only require to pass the username of the user you have authenticated.
public class JanrainSuccessService : Service
{
public void CreateSessionFor(string username)
{
var repository = TryResolve<IAuthRepository>().AsUserAuthRepository(GetResolver());
var user = repository.GetUserAuthByUserName(username);
var session = GetSession();
session.PopulateWith(user);
session.IsAuthenticated = true;
session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture);
session.ProviderOAuthAccess = repository.GetUserAuthDetails(session.UserAuthId).ConvertAll(x => (IAuthTokens)x);
}
}
The code in this method, is effectively the same could that is used by the CredentialsAuthProvider, but has the advantage of not requiring the password of the user. (See the TryAuthenticate method here for original code)
In your MVC5 controller action method you would need to call:
HostContext.ResolveService<JanrainSuccessService>().CreateSessionFor(user.user_id);
This assumes that you have a valid repository of users configured to match username's against.
You should update your code to be:
public class UsernameOnlyAuthorizationService : Service
{
public object Post(UsernameOnlyLoginRequest request)
{
var authProvider = new UsernameOnlyAuthProvider();
authProvider.Authenticate(this, GetSession(), new Authenticate()
{
UserName = request.username,
Password = "NotRelevant",
RememberMe = true
});
// Remember the session
base.Request.AddSessionOptions(SessionOptions.Permanent);
return HttpResult.Redirect(request.returnUrl);
}
}
public class UsernameOnlyAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
var authRepo = authService.TryResolve<IAuthRepository>().AsUserAuthRepository(authService.GetResolver());
ReferScienceDataContext db = authService.TryResolve<ReferScienceDataContext>();
var session = authService.GetSession();
var user = db.Users.FirstOrDefault(u => u.Username == userName);
if (user == null)
return false;
session.Id = user.Id.ToString();
session.UserName = user.Username;
session.FirstName = user.FirstName;
session.LastName = user.LastName;
session.IsAuthenticated = true;
session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture);
session.ProviderOAuthAccess = authRepo.GetUserAuthDetails(session.UserAuthId).ConvertAll(x => (IAuthTokens)x);
return true;
}
}
I'm relatively new to MVC and SQL CE, and I seem to be having a problem with my primary key field. Inside my database I have 'User' table, and that table has a primary key called 'UserId'. I've created a registration page which gets some data from and should then store that data in the database. However, when the form submit button is clicked, the following error is detected:
The column cannot be modified. [ Column name = UserId ]
This is weird because i'm not attempting to UserId value. The code below is my post action for the registration action:
[HttpPost]
public ActionResult Registration(UserModel user)
{
if (ModelState.IsValid)
{
using (var db = new BlogDbContext())
{
var crypto = new SimpleCrypto.PBKDF2();
var encryptPassword = crypto.Compute(user.Password);
var newUser = db.Users.Create();
newUser.Username = user.Username;
newUser.FirstName = user.FirstName;
newUser.LastName = user.LastName;
newUser.Email = user.Email;
newUser.Password = encryptPassword;
newUser.PasswordSalt = crypto.Salt;
newUser.JoinDate = DateTime.Now;
db.Users.Add(newUser);
db.SaveChanges();
return RedirectToAction("Index", "User");
}
}
else
{
ModelState.AddModelError("", "Registration Failure");
}
return View();
}
When I originally created the database using SQL CE in VS 2012, I set the identity option to 'true' believing that this would auto-increment the primary key column. I've looked on SO for similar questions, however, the majority see to include some sort of SQL query, which I haven't delved into yet. Any help will be greatly appreciated.
I am using managed client side object model in sharepoint 2010. And I want to get loginaName of the AssignedTo user in Task list.
In server side object model I use SPFieldUserValue.User.LoginName to get this property but in client side object model FieldUserValue.User does not exists.
How can I resolve this situation ?
Thanks
Here is the code for that. I've taken an example of AssignedTo field from Task list. I hope that helps.
public static User GetUserFromAssignedToField(string siteUrl)
{
// create site context
ClientContext ctx = new ClientContext(siteUrl);
// create web object
Web web = ctx.Web;
ctx.Load(web);
// get Tasks list
List list = ctx.Web.Lists.GetByTitle("Tasks");
ctx.Load(list);
// get list item using Id e.g. updating first item in the list
ListItem targetListItem = list.GetItemById(1);
// Load only the assigned to field from the list item
ctx.Load(targetListItem,
item => item["AssignedTo"]);
ctx.ExecuteQuery();
// create and cast the FieldUserValue from the value
FieldUserValue fuv = (FieldUserValue)targetListItem["AssignedTo"];
Console.WriteLine("Request succeeded. \n\n");
Console.WriteLine("Retrieved user Id is: {0}", fuv.LookupId);
Console.WriteLine("Retrieved login name is: {0}", fuv.LookupValue);
User user = ctx.Web.EnsureUser(fuv.LookupValue);
ctx.Load(user);
ctx.ExecuteQuery();
// display the user's email address.
Consol.writeLine("User Email: " + user.Email);
return user;
}
The fuv.LookupValue may contain the display name, not the login name, so my suggestion is (assuming you have the FieldUserValue - fuv in code (as descibed by #ekhanna):
var userId = fuv.LookupId;
var user = ctx.Web.GetUserById(userId);
ctx.Load(user);
ctx.ExecuteQuery();
You get the column which as the FieldUserValue from the list, once you have that you use the lookup id value and then query against the Sites User Info List. In the example below I cache the results to prevent looking up the same id more than once since the query can be expensive.
private readonly Dictionary<int, string> userNameCache = new Dictionary<int, string>();
public string GetUserName(object user)
{
if (user == null)
{
return string.Empty;
}
var username = string.Empty;
var spUser = user as FieldUserValue;
if (spUser != null)
{
if (!userNameCache.TryGetValue(spUser.LookupId, out username))
{
var userInfoList = context.Web.SiteUserInfoList;
context.Load(userInfoList);
var query = new CamlQuery { ViewXml = "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='ID' /><Value Type='int'>" + spUser.LookupId + "</Value></Eq></Where></Query></View>" };
var users = userInfoList.GetItems(query);
context.Load(users, items => items.Include(
item => item.Id,
item => item["Name"]));
if (context.TryExecuteQuery())
{
var principal = users.GetById(spUser.LookupId);
context.Load(principal);
context.ExecuteQuery()
username = principal["Name"] as string;
userNameCache.Add(spUser.LookupId, username);
}
}
}
return username;
}
Everything above worked for me, but instead of:
FieldUserValue fuv = (FieldUserValue)targetListItem["AssignedTo"];
I used:
FieldUserValue[] fuv = targetListItem["AssignedTo"] as FieldUserValue[];