I'm building an ASP.Net 4.5 Web Application in Visual Studio 2012. I've put the following code in my Global.asax.cs:
protected void Session_Start(object sender, EventArgs e)
{
Session["LastError"] = "";
// Code that runs when a new session is started
string delimStr = #"\";
char[] delimiter = delimStr.ToCharArray();
string[] requestor = Request.Params["AUTH_USER"].ToString().Split(delimiter, 2);
string requestorEID = requestor[1];
Session["UserID"] = requestorEID;
//Get User data (name, roleid, rolename) from database
List<SqlParameter> paramList = new List<SqlParameter>();
paramList.Add(new SqlParameter("#EmployeeID", requestorEID));
DataTable dtUserList = KLClassLibrary.KLDataAccessLayer.ExecuteSelect("GetUserData", paramList, "OffSiteCN");
if (dtUserList.Rows.Count > 0)
{
Session["EmployeeName"] = dtUserList.Rows[0]["EmployeeName"].ToString();
}
else
{
Session["LastError"] = "You Are Not Authorized To Access This Application";
Session["EmployeeName"] = "";
Response.Redirect("~/ErrorPage.aspx");
}
}
Whenever my code gets to the line
string[] requestor = Request.Params["AUTH_USER"].ToString().Split(delimiter, 2);
Request.Params["AUTH_USER"] is equal to an empty string. I've used this code successfully for years, although I'm new to VS2012 and .Net 4.5. What's wrong?
This isn't a complete solution, but I was able to create a workaround by using the following code:
string requestor = Request.LogonUserIdentity.Name.ToString();
int requestor_length = requestor.Length;
string requestorEID = requestor.Substring(requestor_length - 5, 5);
Session["UserID"] = requestorEID;
Ensure you have "Windows Authentication" enabled in the project's properties (it is the very bottom of the properties list). This will allow IISExpress to use windows authentication.
Then ensure you have denied access to anonymous users in your web.config's system.web authorization section, system.webServer or both.
For IIS 6.5 or below:
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
For IIS 7 or above
<system.webServer>
<security>
<authorization>
<add accessType="Deny" users="?"/>
</authorization>
</security>
</system.webServer>
you can also set the windows authentication modes in these sections, but the server must allow you to override their default setting. IISExpress is not set to allow this value to be overridden so you can not try to set it here for your debug mode.
The older versions of Visual Studio used Cassini to emulate a web server for your debugging. Now it uses IISExpress, which will deliver you a closer experience to a true IIS server. There used to be certain scenarios that would differ between Cassini and your actual IIS server - now it is rare to non-existent that I run into these issue. However with correct configuration settings you can get your AUTH_USER value on session start.
Related
So I'm trying to create a Hello World custom Role Provider-solution in ASP.NET MVC 4.
Basically I've set authentication mode="Windows" in web.config along with defining a role provider like this:
<roleManager enabled="true" defaultProvider="MyRoleProvider">
<providers>
<clear />
<add name="MyRoleProvider" type="MyProject.Code.MyRoleProvider" />
</providers>
</roleManager>
Then I've decorated the About controller method like this:
[Authorize(Roles = "SomeRole")]
public ActionResult About()
{ /* ... */ }
The custom RoleProvider-class looks like this:
namespace MyProject.Code {
public class MyRoleProvider : RoleProvider
{
public override bool IsUserInRole(string username, string roleName)
{
if (roleName == "SomeRole" && username = "Administrator") return true;
return false;
}
public override string[] GetRolesForUser(string username)
{
return new string[] { "SomeRole" };
}
/* a bunch of other overridden methods simply throwing not implementedException */
}
}
Now the thing is I've put a breakpoint on every single executable line of code in MyRoleProvder but none are hit. I have tested that breakpoints elsewhere are hit so the debugger is not the problem. Why isn't my code in the role provided executed? I was expecting IsUserInRole and/or GetRolesForUser to be executed when I navigate to the About-page. Am I wrong? Have I configured something wrong?
Full web.config for reference
edit: The user is redirected to the login page when the about page is clicked. I now realize this is due to the user actually is not authenticated yet. Authorization naturally happens after authentication. Is IISExpress not providing Windows identity?
As this is the first result in a google search i want to give a solution, maybe for others:
To use the windows identity in IIEExpress you have to activate it in your applicationhost.config , which is located in
[SolutionDir].vs\config\applicationhost.config
there you can find the xml tag
<configuration>
<system.webServer>
<security>
<authentication>
<windowsAuthentication enabled="false">
change enabled="false" to enabled="true"
and you can use windows authenticatuion in IISExpress
I think your type declaration is incomplete, you should include both the full name and the assembly name.
type="MyProject.Code.MyRoleProvider, MyProject"
You might also need to set Version, Culture and PublicKeyToken if your assemblies are place in the GAC
Hope this helps
I installed VM player in my machine and installed windows 2008 standard core inside. Also via command prompt added users and groups for a particular user as below,
creating user
dsadd user "cn=username,cn=users,dc=myname,dc=ca" -pwd password -disabled no
creating group
dsadd group "cn=groupname,cn=users,dc=myname,dc=ca"
Also added user to the existing group as below,
dsmod group "cn=groupname,cn=users,dc=myname,dc=ca" -addmbr "cn=username,cn=users,dc=myname,dc=ca"
Now i connect this users via my asp.net application in my local machine as below,
Web.config settings
<authentication mode="Forms">
<forms loginUrl="logon.aspx" name="adAuthCookie" timeout="10" path="/"/>
</authentication>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
script for authentication
void Login_Click(object sender, EventArgs e)
{
string adPath = "LDAP://domainaddress:389/DC=somename,DC=m"; //Path to your LDAP directory server
LdapAuthentication adAuth = new LdapAuthentication(adPath);
try
{
if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text))
{
FormsAuthentication.SetAuthCookie(txtUsername.Text.Trim(), false);
string groups = adAuth.GetGroups();
//Create the ticket, and add the groups.
bool isCookiePersistent = chkPersist.Checked;
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
txtUsername.Text, DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups);
---------
-------
}
where i am getting exception in string groups = adAuth.GetGroups(); as below
"Error authenticating. Error getting groups. The username is incorrect or bad password. "
Please let me know if i am doing some mistakes or please let me know how i find groups of assciated user.
Regards
Sangeetha
I've just installed AD LDS on my developer PC and everything works find, I've even created the user "abc" via ADSI Edit.
My goal is to test my ASP.NET Mvc 3 web application with my test AD LDS instance.
How can I get the app to authenticate the user against the instance? Do I have to write a custom membership provider? (overriding some stuff in the default AD membership provider?)
Thank you for any help!
You don't have to do any authentication since it is handled by iis.
All you have to do is change authentication mode to windows.
<system.web>
<authentication mode="Windows" />
</system.web>
Remember to either install iis after you installed AD, or register it manually.
Because you are using AD LDS I don't think authentication mode "Windows" will be so helpful. I believe you need to create a Login View(here /Account/Logon) and use authentication mode "Forms".
Enter the followwing in web.config
<authentication mode="Forms">
<forms name=".ADAuthCookie" loginUrl="~/Account/Logon" timeout="30" slidingExpiration="false" protection="All"/>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
Authenticating the user can be accomplished by using System.DirectoryServices.AccountManagement. The controller code should look something like this:
public ActionResult Logon(LogonModel model)
{
if (model.Username != null && model.Password != null)
{
string container = "CN=...,DC=....,DC=...."; //Your container in LDS
string ldapserver = "server:port"; //LDS server
PrincipalContext context = new PrincipalContext(
ContextType.ApplicationDirectory,
ldapserver,
container,
ContextOptions.SimpleBind);
bool authenticate = context.ValidateCredentials(string.Format("CN={0},{1}", model.Username, container), model.Password, ContextOptions.SimpleBind);
if (authenticate)
{
FormsAuthentication.RedirectFromLoginPage(model.Username, false);
}
else
{
System.Threading.Thread.Sleep(5000);
this.ModelState.AddModelError("Password", "Wrong username or password");
}
}
return View("Logon", new LogonModel { Username = model.Username });
}
Note that this ONLY solves authentication and not authorization.
You can also use membership providers, but if you are looking for an easy solution I think this should do the trick.
I have a WCF service, hosted in IIS, which I require to impersonate the annon account.
in my Webconfig
<authentication mode="Windows"/>
<identity impersonate ="true"/>
Testing the following, with vs2008
public void ByRuleId(int ruleId)
{
try
{
string user = WindowsIdentity.GetCurrent().Name;
string name = Thread.CurrentPrincipal.Identity.Name;
........
//get the data as a string.
using (FileStream fs = File.Open(location, FileMode.Open))
using (StreamReader reader = new StreamReader(fs))
{
rawData = reader.ReadToEnd();
}
}
catch.....
}
this works. however if I add impersonation attribute
[OperationBehavior(Impersonation=ImpersonationOption.Required)]
public void ByRuleId(int ruleId)
this does not work with the error message
"Either a required impersonation level was not provided, or the provided impersonation level is invalid."
a little poking around I noticed the first way was authenticated by Kerboros and the second way just failed on authentication type
I am using the WCF client tool, to pass my credentials. this seems to be working.
Check the 'TokenImpersonationLevel' of identity of the current thread; you'll need it to be at least 'Impersonation' to perform operations on the machine that the service is running on.
Typically, if you are using a proxy client, you'll need to set the 'TokenImpersonationLevel' of the client:
http://www.devx.com/codemag/Article/33342/1763/page/4
the main goal of this was to get anon access, even tho MattK answer was a great help.
here is what i did to do so.
on the implementation of the WCF contract I added the
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class TransferFile : ITransferFile
and in the web.config
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled ="true" />
after this i was able to impersonate the anon account
I have a blank test app created in VS 2005 as ASP.NET application. MSDN says that
By default, ASP.NET does not use impersonation, and your code runs using the ASP.NET application's process identity.
And I have the following web.config
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
affects performance, set this value to true only
during development.
-->
<compilation debug="true" defaultLanguage="c#" />
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<identity impersonate="false"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
</system.web>
</configuration>
So it seem impersonation is disabled just like the article is suggesting.
My aspx is blank default and the codebehind is
namespace TestWebapp
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(String.Format("Before1: Current Princupal = {0}", Thread.CurrentPrincipal.Identity.Name));
WindowsImpersonationContext ctx = WindowsIdentity.Impersonate(IntPtr.Zero);
try
{
int a = 0;
System.Diagnostics.Debug.WriteLine(String.Format("After: Current Princupal = {0}", Thread.CurrentPrincipal.Identity.Name));
} finally
{
ctx.Undo();
}
}
}
}
When I reload the page I get the following debug output:
[5288] Before1: Current Princupal =
DOMAIN\User
[5288] After: Current Princupal =
DOMAIN\User
Output is the same with
<identity impersonate="false"/>
The web site uses Default Application Pool and the pool is set up to use NETWORK SERVICE account for its worker processes.
I'm sure the application uses the web.config it should use and the w3p.exe worker process is running under NETWORK SERVICE.
What can be wrong in this case?
Thanks!
#Edit: Rob, thanks for the tip!
The $user shortcut shows me that everything is happening as I expect: with impersonation on I have the process running user NT AUTHORITY\NETWORK SERVICE and the thread has DOMAIN\User before WindowsIdentity.Impersonate(IntPtr.Zero) and "No Token. Thread not impersonating." after.
But Thread.CurrentPrincipal.Identity.Name and HttpContext.Current.User.Identity.Name still give me DOMAIN\User in both places.
#Edit: I've found out that to get Thread.CurrentPrincipal and HttpContext.Current.User changed I have to manually do it:
Thread.CurrentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
HttpContext.Current.User = Thread.CurrentPrincipal;
I'm not sure what's the point here, but anyway. I now have a problem with sharepoint shared services manage user profile permission but that's another question.
I think I understand your problem here.
Things to know before moving further,
There are different security context while an application is running. Like System.Security.Principal.WindowsIdentity.GetCurrent().Name, and the one you mentioned above, i.e. System.Threading.Thread.CurrentPrincipal.Identity.Name
In a web application, System.Threading.Thread.CurrentPrincipal.Identity is always provided by HttpContext.Current.User.Identity.
Coming to your point. If you want to modify System.Threading.Thread.CurrentPrincipal.Identity, then modify HttpContext.Current.User.Identity which initially provided by your authentication mechanism.
Seems odd, A few things to try:
While in on a breakpoint in Debug type $user in a watch window, that will show you the process and thread identities.
Your use of impersonate is incorrect, try this code:
// Declare the logon types as constants
const long LOGON32_LOGON_INTERACTIVE = 2;
const long LOGON32_LOGON_NETWORK = 3;
// Declare the logon providers as constants
const long LOGON32_PROVIDER_DEFAULT = 0;
const long LOGON32_PROVIDER_WINNT50 = 3;
const long LOGON32_PROVIDER_WINNT40 = 2;
const long LOGON32_PROVIDER_WINNT35 = 1;
[DllImport("advapi32.dll", EntryPoint = "LogonUser")]
private static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
public static WindowsImpersonationContext ImpersonateCurrentUserBegin(System.Net.NetworkCredential credential)
{
WindowsImpersonationContext impersonationContext = null;
if (credential == null || credential.UserName.Length == 0 || credential.Password.Length == 0 || credential.Domain.Length == 0)
{
throw new Exception("Incomplete user credentials specified");
}
impersonationContext = Security.Impersonate(credential);
if (impersonationContext == null)
{
return null;
}
else
{
return impersonationContext;
}
}
public static void ImpersonateCurrentUserEnd(WindowsImpersonationContext impersonationContext)
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
What does HttpContext.User.Identity.Name give you?
Assume you've checked the security tab within IIS that it allows anonymous access?
Are you within an active directory that has some strange local policy?