How to get user details in asp.net Windows Authentication - asp.net

I am using windows Authentication and accessing user name as.
IIdentity winId = HttpContext.Current.User.Identity;
string name = winId.Name;
but i want to get other details like User full name and EmailID.

Since you're on a windows network, then you need to query the Active directory to search for user and then get it's properties such as the email
Here is an example function DisplayUser that given an IIdentity on a windows authenticated network, finds the user's email:
public static void Main() {
DisplayUser(WindowsIdentity.GetCurrent());
Console.ReadKey();
}
public static void DisplayUser(IIdentity id) {
WindowsIdentity winId = id as WindowsIdentity;
if (id == null) {
Console.WriteLine("Identity is not a windows identity");
return;
}
string userInQuestion = winId.Name.Split('\\')[1];
string myDomain = winId.Name.Split('\\')[0]; // this is the domain that the user is in
// the account that this program runs in should be authenticated in there
DirectoryEntry entry = new DirectoryEntry("LDAP://" + myDomain);
DirectorySearcher adSearcher = new DirectorySearcher(entry);
adSearcher.SearchScope = SearchScope.Subtree;
adSearcher.Filter = "(&(objectClass=user)(samaccountname=" + userInQuestion + "))";
SearchResult userObject = adSearcher.FindOne();
if (userObject != null) {
string[] props = new string[] { "title", "mail" };
foreach (string prop in props) {
Console.WriteLine("{0} : {1}", prop, userObject.Properties[prop][0]);
}
}
}
gives this:
Edit: If you get 'bad user/password errors'
The account that the code runs under must have access the users domain. If you run code in asp.net then the web application must be run under an application pool with credentials with domain access. See here for more information

You can define a MyCustomIdentity by overriding from IIdentity and add your own properties etc.

Cast it to the specific Identity, for example WindowsIdentity

Related

MVC - FormsAuthentication Get the RoleName

I am new to ASP.NET MVC and learning how to custom Roles using FormAuthentication from this tutorial link
This code below is stored the Roles. It works fine when I perform this [Authorize(Roles="admin")] in the controller
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (userDbEntities entities = new userDbEntities())
{
User user = entities.Users.SingleOrDefault(u => u.username == username);
roles = user.Roles;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Is there a way to get the actual Role Name based on the current User.Identity? like below pseudo-code.
[Authorize]
public ActionResult Index()
{
bool isAdmin = System.Web.HttpContext.Current.User.IsInRole("admin"); // This also works correctly.
Response.Write("role: " + isAdmin);
string roleName = // The Code of How to get the actual Role Name
Response.Write("roleName: " + roleName); //e.g Admin, User...
return View();
}
From Comment: Do you know any good article about OWIN cookie
authentication for custom table for username and roles?
It has few pieces, so I created a sample project in GitHub AspNetMvcActiveDirectoryOwin. The original souce is to authenticate with AD, but you just need to modify ActiveDirectoryService class where you query custom tables.
The following three are the main classes -
AccountController
ActiveDirectoryService
OwinAuthenticationService replaces FormsAuthentication.

How to pass connection string name from Silverlight Application to DomainService

First I want to say I'm not SL developer. I just need to modify one legacy Silverlight 5 application.
It is using RIA services and XAP is hosted in Asp.Net page.
User on login page enters credentials and is able to select database from dropdown. Whole web is using multiple connections and user is able to select database to connect.
This selected database (or any identificator for data connection) is sent do XAP's InitParams, so I can access it from SL.
private void Application_Startup(object sender, StartupEventArgs e)
{
foreach (var item in e.InitParams)
{
Resources.Add(item.Key, item.Value);
}
var selectedConnectionString = GetInitParam("ConnectionString");
// TODO: Different way to store connection string
SetCookie("ConnectionString", selectedConnectionString);
RootVisual = new LoadingPage();
}
Currently I'm trying to use cookie to store selected database. I found it somewhere as one possible solution. But it needs to change.
Ok, then we have DomainService.
public class CommissionDomainService : LinqToEntitiesDomainService<CommissionEntitiesContext>
{
...
}
I know that I need to use CreateObjectContext to change ConnectionString in service. So I have:
protected override CommissionEntitiesContext CreateObjectContext()
{
// TODO: Different way to store connection string
string connectionStringName;
if (System.Web.HttpContext.Current.Request.Cookies["ConnectionString"] != null)
{
connectionStringName = System.Web.HttpContext.Current.Request.Cookies["ConnectionString"].Value;
}
else
{
throw new Exception("Missing connectionStringName");
}
var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
var entityCs = new EntityConnectionStringBuilder
{
Metadata = "res://*/CommissionEntities.csdl|res://*/CommissionEntities.ssdl|res://*/CommissionEntities.msl",
Provider = connectionStringSettings.ProviderName,
ProviderConnectionString = connectionStringSettings.ConnectionString
};
return new CommissionEntitiesContext(entityCs.ConnectionString);
}
Again, I used Cookie to pass value from application to service.
But it is not the best idea. Because of cookie and because of persistance etc.
My question is, how to pass my ConnectionString value from main application to DomainService? Or Can I access some application context from service? Or maybe can I get connection string somewhere in EntitiesContext?
Ok, I did it this way.
I made selected database part of user identity. Because I'm using Owin, I just used one of Claims.
So when user logs in, I just put one claim with selected database
// build a list of claims
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Name),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.UserData, selectedDatabase)
};
// create the identity
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationType);
// sign in
Context.GetOwinContext().Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, identity);
Then in DomainService I used Initialize and CreateObjectContext methods
private string _connectionStringName;
public override void Initialize(DomainServiceContext context)
{
// Načteme z kontextu usera zvolenou databázi
var claim = ((ClaimsIdentity)context.User.Identity).FindFirst(ClaimTypes.UserData);
_connectionStringName = claim.Value;
base.Initialize(context);
...
}
protected override CommissionEntitiesContext CreateObjectContext()
{
if (string.IsNullOrEmpty(_connectionStringName))
{
throw new Exception("Missing connectionStringName");
}
var connectionStringSettings = ConfigurationManager.ConnectionStrings[_connectionStringName];
var entityCs = new EntityConnectionStringBuilder
{
Metadata = "res://*/CommissionEntities.csdl|res://*/CommissionEntities.ssdl|res://*/CommissionEntities.msl",
Provider = connectionStringSettings.ProviderName,
ProviderConnectionString = connectionStringSettings.ConnectionString
};
return new CommissionEntitiesContext(entityCs.ConnectionString);
}

Get user photo from Active directory not working at server

I am developing an intranent website that take the user name direct from windows authentication then get more data from active directory such as user image and user email and so on at the folowing function
public Boolean userAuth()
{
String myUser = Environment.UserName;
if (myUser == null)
{
return false;
}
DirectoryEntry de = new DirectoryEntry();
de.Path = "LDAP://mydomain.com";
DirectorySearcher search = new DirectorySearcher();
search.Filter = "(SAMAccountName=" + myUser + ")";
search.PropertiesToLoad.Add("cn");
search.Filter = "(&(objectClass=user)(objectCategory=person)(sAMAccountName=" +myUser + "))";
search.PropertiesToLoad.Add("samaccountname");
search.PropertiesToLoad.Add("thumbnailPhoto");
search.PropertiesToLoad.Add("Company");
SearchResult user;
user = search.FindOne();
String userName;
userName = Convert.ToString(user.Properties["sAMAccountName"][0]);
byte[] bb = (byte[])user.Properties["thumbnailPhoto"][0];
string imgString = Convert.ToBase64String(bb);
Session["UserPhoto"] = String.Format("<img width='40' src=\"data:image/Bmp;base64,{0}\">", imgString);
result = search.FindOne();
if (null == result)
{
return false;
}
return true;
}
My pc is connected to the domain when i run the site in my local pc it works fine but when i put it in company application server
the Environment.UserName will not return the username so i use System.Web.HttpContext.Current.User.Identity.Name.Replace("mydomain","") but it will return that user null
I want to get user photo from AD to use it in the intranet site.
I found the answer at iis application pool advance settings set process module identity to a user who is already in the domain

MVC 3 Authorize custom roles

I am new MVC 3 user and I am trying to make admin through SQL database.
First of all, I have Customer entity and admin can be defined through admin field which is boolean type in Customer entity.
I want to make to access admin only in Product page, not normal customer.
And I want to make [Authorize(Roles="admin")] instead of [Authorize].
However, I don't know how can I make admin role in my code really.
Then in my HomeController, I written this code.
public class HomeController : Controller
{
[HttpPost]
public ActionResult Index(Customer model)
{
if (ModelState.IsValid)
{
//define user whether admin or customer
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["rentalDB"].ToString());
String find_admin_query = "SELECT admin FROM Customer WHERE userName = '" + model.userName + "' AND admin ='true'";
SqlCommand cmd = new SqlCommand(find_admin_query, conn);
conn.Open();
SqlDataReader sdr = cmd.ExecuteReader();
//it defines admin which is true or false
model.admin = sdr.HasRows;
conn.Close();
//if admin is logged in
if (model.admin == true) {
Roles.IsUserInRole(model.userName, "admin"); //Is it right?
if (DAL.UserIsVaild(model.userName, model.password))
{
FormsAuthentication.SetAuthCookie(model.userName, true);
return RedirectToAction("Index", "Product");
}
}
//if customer is logged in
if (model.admin == false) {
if (DAL.UserIsVaild(model.userName, model.password))
{
FormsAuthentication.SetAuthCookie(model.userName, true);
return RedirectToAction("Index", "Home");
}
}
ModelState.AddModelError("", "The user name or password is incorrect.");
}
// If we got this far, something failed, redisplay form
return View(model);
}
And DAL class is
public class DAL
{
static SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["rentalDB"].ToString());
public static bool UserIsVaild(string userName, string password)
{
bool authenticated = false;
string customer_query = string.Format("SELECT * FROM [Customer] WHERE userName = '{0}' AND password = '{1}'", userName, password);
SqlCommand cmd = new SqlCommand(customer_query, conn);
conn.Open();
SqlDataReader sdr = cmd.ExecuteReader();
authenticated = sdr.HasRows;
conn.Close();
return (authenticated);
}
}
Finally, I want to make custom [Authorize(Roles="admin")]
[Authorize(Roles="admin")]
public class ProductController : Controller
{
public ViewResult Index()
{
var product = db.Product.Include(a => a.Category);
return View(product.ToList());
}
}
These are my source code now. Do I need to make 'AuthorizeAttribute' class?
If I have to do, how can I make it? Could you explain to me? I cannot understand how to set particular role in my case.
Please help me how can I do. Thanks.
I know this question is a bit old but here's how I did something similar. I created a custom authorization attribute that I used to check if a user had the correct security access:
[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
// Get the roles from the Controller action decorated with the attribute e.g.
// [AccessDeniedAuthorize(Roles = MyRoleEnum.UserRole + "," + MyRoleEnum.ReadOnlyRole)]
var requiredRoles = Roles.Split(Convert.ToChar(","));
// Get the highest role a user has, from role provider, db lookup, etc.
// (This depends on your requirements - you could also get all roles for a user and check if they have the correct access)
var highestUserRole = GetHighestUserSecurityRole();
// If running locally bypass the check
if (filterContext.HttpContext.Request.IsLocal) return;
if (!requiredRoles.Any(highestUserRole.Contains))
{
// Redirect to access denied view
filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
}
}
}
Now decorate the Controller with the custom attribute (you can also decorate individual Controller actions):
[AccessDeniedAuthorize(Roles="user")]
public class ProductController : Controller
{
[AccessDeniedAuthorize(Roles="admin")]
public ViewResult Index()
{
var product = db.Product.Include(a => a.Category);
return View(product.ToList());
}
}
Your Role.IsInRole usage isn't correct. Thats what the
[Authorize(Roles="Admin")] is used for, no need to call it.
In your code you are not setting the roles anywhere. If you want to do custom role management you can use your own role provider or store them in the auth token as shown here:
http://www.codeproject.com/Articles/36836/Forms-Authentication-and-Role-based-Authorization
note the section:
// Get the stored user-data, in this case, user roles
if (!string.IsNullOrEmpty(ticket.UserData))
{
string userData = ticket.UserData;
string[] roles = userData.Split(',');
//Roles were put in the UserData property in the authentication ticket
//while creating it
HttpContext.Current.User =
new System.Security.Principal.GenericPrincipal(id, roles);
}
}
However an easier approach here is to use the built in membership in asp.net.
Create a new mvc project using the 'internet application' template and this will all be setup for you. In visual studio click on the "asp.net configuration" icon above solution explorer. You can manage roles here and assignment to roles.

Active Directory Account locking out on first try

I have a website which requires users to enter their corporate network username and password. It then looks for that account in Active Directory and gets a list of any email addresses associated with that account.
The problem I am having is that ONE incorrect password is locking out an account. Our domain policy is that an account will lock out after three incorrect entries, so I am assuming that I am doing something wrong in my code. I am not very knowledgeable about Active Directory or .NET DirectoryServices in general, which may be apparent from my code. Here it is:
public ArrayList AuthenticateActiveDirectory(string Domain, string UserName, string Password)
{
// An error occurs if the username/password combo does not exist.
// That is how we know it is not a valid entry.
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + Domain, UserName, Password);
object nativeObject = entry.NativeObject;
ArrayList emails = new ArrayList();
DirectorySearcher ds = new DirectorySearcher(entry);
ds.Filter = "samaccountname=" + UserName;
ds.PropertiesToLoad.Add("mail");
SearchResult sr = ds.FindOne();
if (sr.Properties["mail"] != null)
{
for (int email = 0; email < sr.Properties["mail"].Count; email++)
{
emails.Add(sr.Properties["mail"][email]);
}
}
return emails;
}
catch (DirectoryServicesCOMException) { throw; }
catch (Exception) { throw; }
}
I did some searching and found some code (thanks to Ayende Rahien for the solution) to use that just authenticates and doesn't search for emails or anything else. I am using this prior to the other function, and it seems to be working fine. I am guessing that my other code is hitting AD more than once - at least 3 times - which is resulting in the lockout. Here is the code I am using now to just authenticate:
private bool Authenticate(string domain, string user, string password)
{
try
{
using (DirectoryEntry de = new DirectoryEntry("LDAP://" + domain,
user, password))
{
return de.NativeObject != null;
}
}
catch
{
return false;
}
}

Resources