Role-based Security Authorization in web froms using Identity 2.0 - c#

I've seen not hundred but THOUSANDS of example where from scratch to complete examples with MVC identity 2.0 are done but not a single one with bloody web forms and the one which are present are not even worth while just very basic.
I'm working on an application where I've three roles, user,admin,superUser and all these are in AspNetRoles table because I'm using identity 2.0. now when I create a user I also assign that user one of these roles too.
before this role and stuff I've worked on customize roles system as we use to do on desktop applications.
so here I tried all the links and articles written on CodeProject about form authentication and all that what we can do in web.config but nothing was helpful
Please take a look at this screen shot http://prntscr.com/6ca09i you might get a little idea what I mean by that.
My C# code on register is
protected void btnSubmit_Click(object sender, EventArgs e)
{
//owin entity
var userStore = new UserStore<IdentityUser>();
userStore.Context.Database.Connection.ConnectionString =
System.Configuration.ConfigurationManager
.ConnectionStrings["GCR"].ConnectionString;
var manager = new UserManager<IdentityUser>(userStore);
//string userInfor;// = new UserInformation();
// check if the url contains an id perameter
if (!String.IsNullOrWhiteSpace(Request.QueryString["id"]))
{
var id = Convert.ToInt32(Request.QueryString["id"]);
var userInfo = new UserInformation
{
Email = txtEmail.Text,
FirstName = txtFirstName.Text,
LastName = txtLastName.Text,
AddressLine1 = txtAddressLine1.Text,
AddressLine2 = txtAddressLine2.Text,
City = txtCity.Text,
State = ddlState.SelectedValue,
ZipCode = Convert.ToInt32(txtZip.Text),
PhoneNumber = txtPhone.Text,
RoleId = Convert.ToInt32(ddlRole.SelectedValue)
and here is my registration page where I am assigning the roles which are not actually getting assigned http://prntscr.com/6ca1xi
Now please tell me how can I create role based app where in a single folder we have different files which User with different role can get access
Please I'd already wasted my two days on Identity I have no wich to waste more time on it

This is how you are going to properly deal with this
var userInfo = new UserInformation
{
Email = txtEmail.Text,
FirstName = txtFirstName.Text,
LastName = txtLastName.Text,
AddressLine1 = txtAddressLine1.Text,
AddressLine2 = txtAddressLine2.Text,
City = txtCity.Text,
State = ddlState.SelectedValue,
ZipCode = Convert.ToInt32(txtZip.Text),
PhoneNumber = txtPhone.Text,
RoleId = ddlRole.SelectedValue
Fist your role should be some text value because it does not take role as id
after saving this object or model above `db.saveChanges();
you in the end are going to add this role to aspnetroles table and how you are going to do that is very simple just a single line
// add role to the user which is created right now
manager.AddToRole(userInfo.GUID, ddlRole.Text.Trim());
The first argument is the id of the user and the second one is the dropdown in which you are selecting the user roles and you can also do that role exist stuff in it. now how you are going to check this one page load is very simple
and its just like this
#region page load
if (!IsPostBack)
{
if (User.IsInRole("admin") || User.IsInRole("superuser"))
{
}
else
{
string unAuthorizedRedirect = WebConfigurationManager.AppSettings["UnAuthorizedRedirect"];
Response.Redirect("~/" + unAuthorizedRedirect);
}
}
#endregion
I hope this helps you completely

I got the roles from aspnetroles table and this is how I got those
var context = new ApplicationDbContext();
var roleStore = new RoleStore<IdentityRole>(context);
var roleMgr = new RoleManager<IdentityRole>(roleStore);
if (User.IsInRole("admin"))
{
//come here
}

Related

Inserting a row into Relational database table

I am very new to c# and asp.net mvc. I'm building a HR portal for our company where a user can submit a leave form among other things... So I'm using mssql as the database server and using Entity Frame work to communicate with it. I have 3 entities, user (Containing user details), permissions (the user permissions for allowing actions in the app) and then the leave form table (where the leave form details are stored). There is a one to many relationship between user - permission and then a one to many relationship between user-leave. I am not fazed about the permissions as that gets created when the user account is being created.
The problem I am facing is, how do I add a leave form for a specific user? Below is my controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Leave(MasterViewModel model)
{
DocSubViewModel mv = model.DSModel;
int userId = Convert.ToInt32(Session["userID"]);
try
{
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.dateFrom = mv.DateFrom;
leave.dateSubmitted = DateTime.Now;
leave.dateTo = mv.DateTo;
leave.nrDays = mv.NrDays;
leave.reason = mv.SpecialLeave;
leave.TLApproval = null;
leave.TLApprovalDate = null;
leave.TLApprovalID = mv.TeamLeaderID;
leave.DMApprovalDate = null;
leave.DMApprovalID = mv.DepManagerID;
leave.DMApproval = null;
leave.type = mv.Type;
leave.user = userId;
db.leaves.Add(leave);
db.SaveChanges();
}
ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
catch (Exception ex)
{
ViewBag.Message = ex;
//ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
The problem comes in leave.user = userId;. It says:
Cannot implicitly convert int to Portal.Model.user
I can't seem to find out how to do this...
You're telling it to put the UserId where your leave model is asking for a User.
Your relationship requires a User to go in there, so you'll have to update your code a little bit:
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.user = db.users.First(x => x.Id == userId);
}
This will put reference to the actual user in the new leave record. If you go later and check it out you'll see a column in the leave table called user_Id that has an integer value in it and is set as a foreign key to the users table.
Note that this will error if no user exists having the specified Id value. If you anticipate this to be a problem, rather use .FirstOrDefault() instead of .First() and then account for the value being null before you add it to your new leave object.
That's expected since User is a object and not int. What you should be doing probably is leave.user.UserId = userId; instead [Assuming leave.user is of type User which has a UserId property]

Active Directory UserPrincipal issue

I have some code which gets a user based on the current context and this happens in the Page_Load() method of my application.
var context = new PrincipalContext(ContextType.Domain, "dc", "DC=domain,DC=com", "user", "password");
UserPrincipal user = UserPrincipal.FindByIdentity(context, User.Identity.Name);
string Name = user.Name.Trim();
lblName.Text = Name;
This works and the label is correctly showing the logged in user (Windows Authentication).
However, another part of my code, on button press, does some looping through a datagrid which contains other usernames and uses a similar method to obtain information about those users.
I've utilized labels on the page to display relevant user information but one of those labels seems to change based on which user it is dealing with in the loop, when it actually needs to only ever refer to the currently logged in user.
Is there a way around this? I thought by having separate methods that essentially do the same thing, I would get different objects. The return values are different so I'm not sure how this is happening.
Relevant code below with some comments to explain or point out where the code is not relevant (sending emails and dealing with exceptions - all removed).
public string getUserEmail()
{
var context = new PrincipalContext(ContextType.Domain, "dc", "DC=domain,DC=com", "user", "password"); ;
UserPrincipal user = UserPrincipal.FindByIdentity(context, User.Identity.Name);
string email = user.EmailAddress;
return email;
}
public string getOtherUserEmail(string user)
{
user = user.Trim();
var context = new PrincipalContext(ContextType.Domain, "dc", "DC=domain,DC=com", "user", "password");
UserPrincipal u = UserPrincipal.FindByIdentity(context, user);
string email2= u.EmailAddress;
return email2;
}
protected void btnEmail_Click(object sender, EventArgs e)
{
foreach (GridViewRow row in gdView1.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
Label FullName = gdView1.Rows[index].FindControl("lblFullName") as Label; // other username from gridview
string FromAddress = getUserEmail(); //logged in user
try
{
string otherName = FullName.Text.ToString();
string ToAddress1 = getOtherUserEmail(FullName); //Other user
//Generate an email message....
smtpClient.Send(mail);
lblMessage.Text = "Email sent!";
}
catch
{ // exception handling
}
}
}
protected void gdView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
TableCell cell = gdView1.Rows[e.RowIndex].Cells[2]; //Cell containing "other" user name
Message.Text = cell.Text;
string otherName = cell.Text.ToString();
string ToAddress = getOtherUserEmail(otherName); //Other user
string FromAddress = getUserEmail(); //logged in user
try
{ //email as above
}
catch
{ // exception handling
}
}
Based on what you posted, I would expect you to get different objects as well. Maybe there's something happening in code you haven't included?
On a side note, for the current logged on user you should define a field (call it _loggedOnUser) outside of the Page_Load(). That way all methods have access to it. This will keep your code easier to follow, also, and might even solve your reference problem.
public partial class Page1 {
UserPrincipal _loggedOnUser;
public void Page_Load() {
var context = new PrincipalContext(ContextType.Domain, "dc", "DC=domain,DC=com", "user", "password");
_loggedOnUser= UserPrincipal.FindByIdentity(context, User.Identity.Name);
string Name = _loggedOnUser.Name.Trim();
lblName.Text = Name;
}
}
Then you can refer to it in the rest of your class, and you won't have to waste time going back to Active Directory in your loop.
Thus, this line: string FromAddress = getUserEmail();
can be changed to string FromAddress = _loggedOnUser.EmailAddress;
and you avoid another expensive call to AD to get info you already have.

How to retrieve ZipCode from UserProfileManager in SharePoint 2010?

I need to know how I can retrieve the ZipCode from Active Directory. Currently, I can get the User and Department but I can't retrieve ZipCode.
In the docs I can't see the ZipCode as a property:
This is my code in C#:
using(SPSite site = new SPSite("Server"))
{
site.AllowUnsafeUpdates = true;
SPServiceContext context = SPServiceContext.GetContext(site);
UserProfileManager upm = new UserProfileManager(context);
UserProfile profile = upm.GetUserProfile(GetNodeValue("xPath"));
String department = profile[PropertyConstants.Department].Value.ToString();
String position = profile[PropertyConstants.Title].Value.ToString();
String zipCode = profile[PropertyConstants.?????].Value.ToString();
}
You need to manually map this in the User Profile Service Application first.
Properties can be added in Central Administration -> Manage Service Application - > User profile service application -> Manage User Properties -> Add User Profile Property -> Choose the Zip Code Attribute.
Now you can run another sync, each user should have this property mapped. You can then access it like you are doing but with the string name you assigned :
String zipCode = profile["SPS-ZipCode"].Value.ToString();

Seed method does not add user while migrating with "-" in name

Please read the paragraph EDIT2 for the actual state of the question
I am trying to add an initial account to my database while a migration is running, to ensure access to my application.
Unfortunatly the table AspNetUsers is not changed after the Seed method is finished and I can't find a proper way to debug for possible errors.
Configuration.cs
internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
ContextKey = "Namespace.Models.ApplicationDbContext";
}
protected override void Seed(ApplicationDbContext context)
{
var manager = new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(
new ApplicationDbContext()));
var user = new ApplicationUser()
{
UserName = "admin",
Email = "admin#admin",
LastName ="lname",
FirstName = "fname"
};
manager.Create(user, #"gibberish");
/* context.SaveChanges(); ?valid */
}
}
After issuing the update-database -force -verbose command the pm console writes The Seed method is being executed (free translation from German), but as stated above the table is not updated with a new user.
Where did I go wrong?
EDIT:
I just tried the following:
if (!context.Roles.Any(r => r.Name == "Administrator"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "Administrator" };
manager.Create(role);
}
which did work. So a role named Administrator has been created after Update-Database -Force was issued. The user however, not.
EDIT2:
So apparently I found the culprit.
I was trying to make sure that an admin account was always available. Therefor I tried to add a user username-admin. However this did not work. After some time I thought about trying it with a different approach and changed the username to username. Now this did the trick and the user was added and pushed into the role Administrator.
The question remains: why does it not work adding a user with a special character like -?
By default, UserName can only be alphanumeric, i.e. not even an email address is allowed. You need to turn off the validation or implement your own validator (as easily found on SO), e.g.
_userManager = new UserManager<IdentityUser>(_userStore);
_userManager.UserValidator = new UserValidator<IdentityUser>(_userManager) { AllowOnlyAlphanumericUserNames = false };

linq to sql one-one relationship C#

It is necessary that after the creation of records in the table "Clients" took up ID. Later ID used to create a new entry in the "Clients_details".
var user = GetUsers();
var userdet = GetclientsDetails();
string hashedpass = getMd5Hash(UIPassword.Text);
var newreg = new Clients
{
login = UILogin.Text,
password = hashedpass,
subscribeid = Convert.ToInt32(UIId.Text)
};
user.InsertOnSubmit(newreg);
user.Context.SubmitChanges();
var details = new Clients_details
{
city = UICity.Text,
first_name = UIFirst_name.Text,
last_name = UIFamiliya.Text,
name = UIName.Text,
Clients = newreg
};
userdet.InsertOnSubmit(details);
userdet.Context.SubmitChanges();
After this code fails:
"An attempt was made to perform an operation Attach or Add in relation to an object that is not new, and possibly loaded from another DataContext. This operation is not supported."
How to properly create a record that does not appear a mistake? Thank you!
private static Table<Clients> GetUsers()
{
var dce = new BaseDBMLDataContext();
return dce.Clients;
}
private static Table<Clients_details> GetclientsDetails()
{
var dce = new BaseDBMLDataContext();
return dce.Clients_details;
}
Looks like userdet.Context and user.Context was built using a different dataContext and that needs to be created using the same dataContext rather than instantiating a new one.
I think you need to only call the SubmitChanges only once in the end, and also you need to make sure the user and userdet you are using share the same context
As the error clearly states, you're using different contexts (user and userdet) for each entity to add. You should have one DataContext and use that one to add the entities.
Yes looks like you're using two different instances of the same context:
user.Context.SubmitChanges();
userdet.Context.SubmitChanges();
A good approach to build up your entities should be something like :
//Create your client details entity
var details = new Clients_details
{
city = UICity.Text,
first_name = UIFirst_name.Text,
last_name = UIFamiliya.Text,
name = UIName.Text
};
//Create your client entity
var newreg = new Clients
{
login = UILogin.Text,
password = hashedpass,
subscribeid = Convert.ToInt32(UIId.Text),
//Assigning the details entity (FK) to the client
ClientDetails = details
};
//Saving both the client and its details
user.InsertOnSubmit(newreg);
user.Context.SubmitChanges();

Categories