how to get current windows user in wcf - wcf-security

I already tried link from stackoverflow
I have a silverlight client and wcf service. The application has 3 authentication modes
Active Directory
Windows Pass Through
Proprietary - I don't have a problem with this one obviously.
(I really don't know what is the difference between active directory and Window Pass Through. I just use the same code for both, except for windows pass through I get the current user and for AD the app prompts for username password)
.
private string GetCurrentUser()
{
try
{
string result = WindowsIdentity.GetCurrent().Name;
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
result = wp.Identity.Name;
if (result.Contains(#"\"))
{
int position = result.LastIndexOf(#"\") + 1;
result = result.Substring(position);
}
return result;
}
catch (Exception ex)
{
return "";
}
}
Both WindowsIdentity and WindowsPrincipal returns 'DefaultAppPool' or whatever the AppPool the current thread runs. Even Environment.UserName returns the same.
When I turn on <identity impersonate ="true"/> in web.config the silverlight client fails to connect to wcf. It gets a 'Not Found' error. So, I need to keep <identity impersonate ="false"/>
All I need is the current logged on user, I didn't know that it's this difficult.

I changed the identity on the Application Pool to my own user account and it worked.
Open IIS Console
Select Application Pools.
Select the AppPool (in my case it was DefaultAppPool).
On the right pane click Advanced Settings.
There are different categories of settings like General, CPU, Process Model.
Under Process Model -> Identity click the right side input box, a button shows up, click it.
It opens a dialog box with 2 radio buttons (Built-in account and Custom account).
Select custom account and hit Set.
Set Credentials dialog box opens.
Enter your credentials and hit okay. You may have to enter [domain][user name]
Hit Ok to all the dialog boxes to close everything.
Now test your app, WindowsIdentity.GetCurrent().Name should return the username associated with the Application Pool.

Related

.GetDirectoryEntry throws COM exception, code:0x800720720 when attempting to bind to object

My application is running on IIS 7.0, it is supposed to impersonate the authenticated user and unlock or reset other user accounts. It worked fine when I was developing it on my workstation, but when I uploaded it to the server the impersonation stopped working, it won't bind to the AD objects and keeps throwing the same exception. I had the same problem earlier with using PrincipalContext but I was able to get around that using using(HostingEnvironment.Impersonate()) because I didn't need the authenticated user for that action. But now I do so I can't use that workaround. I need an actual fix for the issue and I would really appreciate some input. I've been searching far and wide for a solution to the problem and so far none of them have worked. Here is the code I'm using that keeps throwing the exception.
using (DirectorySearcher search = new DirectorySearcher(directoryEntries[counter]))
{
//Sets the filter to find a user object with the target user username
search.Filter = "(&(objectClass=user)(sAMAccountName=" + username + "))";
//Sets the searchscope to search the whole AD
search.SearchScope = SearchScope.Subtree;
//Executes the search for one result and stores it in result.
SearchResult result = search.FindOne();
//Creates a directory entry from the result.
using (DirectoryEntry targetUser = result.GetDirectoryEntry())
{
//This if-else statement checks if the user is locked, if it is then
//the unlock is performed, and the unlockPerformed variable is set to
//true, if it isn't then unlockPerformed is set to false.
if (Convert.ToBoolean(targetUser.InvokeGet("IsAccountLocked")))
{
targetUser.InvokeSet("IsAccountLocked", false);
targetUser.CommitChanges();
unlockPerformed = true;
}
else
{
unlockPerformed = false;
}
}
}
This code worked perfectly before I uploaded it, any suggestions are greatly appreciated, I'll be monitoring this so I can get a fix asap.
Thanks in advance.
UPDATE: FIXED THE ISSUE
Apparently the program running from the hosting machine but not from a remote machine is actually a very telling symptom according to this article: http://msdn.microsoft.com/en-us/library/vstudio/ms730088(v=vs.100).aspx .
According to that article, the problem is that the impersonate setting was set to impersonation which causes this behaviour, I wanted DELEGATION. In order to do this I used this page to get information on different methods of delegation and impersonation, I used the "Impersonating Original Caller Temporarily" section.
In the web.config file:
<identity impersonate="false"/>
If this is set to false then it tries to impersonate the user for every action, which can cause issues like the one I was experiencing and isn't what I was trying to achieve.
In the code:
using System.Security.Principal;
...
// Obtain the authenticated user's Identity
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
WindowsImpersonationContext ctx = null;
try
{
// Start impersonating
ctx = winId.Impersonate();
// Now impersonating
// Access resources using the identity of the authenticated user
}
// Prevent exceptions from propagating
catch
{
}
finally
{
// Revert impersonation
if (ctx != null)
ctx.Undo();
}
// Back to running under the default ASP.NET process identity
This fix is fairly easy, but its damn near impossible to find good clear information on this topic, I hope someone will find this useful some day, I can't be the only one experiencing these issues.
Apparently the program running from the hosting machine but not from a remote machine is actually a very telling symptom according to this article: http://msdn.microsoft.com/en-us/library/vstudio/ms730088(v=vs.100).aspx . According to that article, the problem is that the impersonate setting was set to impersonation which causes this behaviour, I wanted DELEGATION. In order to do this I used this page to get information on different methods of delegation and impersonation, I used the "Impersonating Original Caller Temporarily" section.
In the web.config file:
<identity impersonate="false"/>
If this is set to false then it tries to impersonate the user for every action, which can cause issues like the one I was experiencing and isn't what I was trying to achieve.
In the code:
using System.Security.Principal;
...
// Obtain the authenticated user's Identity
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
WindowsImpersonationContext ctx = null;
try
{
// Start impersonating
ctx = winId.Impersonate();
// Now impersonating
// Access resources using the identity of the authenticated user
}
// Prevent exceptions from propagating
catch
{
}
finally
{
// Revert impersonation
if (ctx != null)
ctx.Undo();
}
// Back to running under the default ASP.NET process identity
This fix is fairly easy, but its damn near impossible to find good clear information on this topic, I hope someone will find this useful some day, I can't be the only one experiencing these issues.

Single login in asp.net

I am working on a website for a college project. I want to add a feature to my project website.
When a user logs in to the website, all other logins for the same user account should be logged-out, i.e., only one login per account should be allowed at a time .
When the same user ID is trying to log in on multiple devices, how do I kill the session on the other device?
You can be out of the situation by doing something like this:
The Idea
Whenever a user logs in to their account we store their username along with their Session ID. The next time someone that is logged in tries to make a request, we check if their Session ID matches with the Session ID we stored for them. If it's a mismatch, that means someone else logged in after them! Thus we can safely log them out.
The Implementation
We'll make use of 3 things.
Session ID: Allowing us to distinguish someone's browsing instance
Global.asax: To grab the Session End Event
One Storage Location:
HttpContext.Current.Application
Database
If your website is running on one server, then you can just use Application, but if its running on multiple you'll have to go for the Database. The code shows it being done for Application.
When the user logs in you need to store the session id:
UserAccout ua = GetUserAccount();
HttpContext.Current.Application["usr_" + ua.UserName] = HttpContext.Current.Session.SessionID;
And when they log out we need to clear it:
UserAccout ua = GetUserAccount();
HttpContext.Current.Application.Remove("usr_" + ua.UserName);
In your Global.asax file you should call the same Logout code to clean up when their Session Ends
void Session_End(object sender, EventArgs e)
{
UserAccout ua = GetUserAccount();
if (ua != null)
{
HttpContext.Current.Application.Remove("usr_" + ua.UserName);
}
}
And now that we need to actually check if a user should be kicked out or not, so execute this in the beginning of all requests:
UserAccout ua = GetUserAccount();
if (!HttpContext.Current.Application["usr_" + ua.UserName].Equals(HttpContext.Current.Session.SessionID))
{
Logout();
HttpContext.Current.Response.Redirect("SignOut.aspx");
}

Security settings to start a windows service in a ASP.net web app

I have a bit of code in an internal ASP.net application that we use to start automatic services should they be stopped on the server that the web app is running on. The only problem is that it doesn't seem to start the service when its run on the server. It does so fine when its run on my desktop locally though so I'm guessing I have to give certain security settings to the the ASP.net user?
Here's my code:
protected void StartService(object sender, EventArgs e)
{
LinkButton serviceButton = (LinkButton)sender;
string name = serviceButton.ID;
ManagementPath path = new ManagementPath();
path.Server = System.Environment.MachineName;
path.NamespacePath = #"root\CIMV2";
path.RelativePath = "Win32_service.Name='" + name + "'";
ManagementObject service = new ManagementObject(path);
ManagementBaseObject temp = service.InvokeMethod("StartService", null, null);
Thread.Sleep(100);
GetStoppedServices();
}
Anyone have any ideas on how to get this to work?
Edit: For clarification the web app is run on the same server as the server that I want to start services on.
Edit 2: Had a brainwave and tried to use this code instead.. no dice.
ProcessInfo = new ProcessStartInfo("cmd.exe", "/C net start " + name);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
Process.Close();
Rather than using the System.Management objects for controlling services, look into the ServiceController class. All the methods for start/stop/pause are available and in a much more structured manner.
You may still encounter permission issues, though. The executing account for your web app will require permissions to control the target service you wish to affect.
Depending on your platform (which version of Win Serv), different accounts will execute for anonymous requests for your web application. Verify which accounts come into play (or if you have authenticated requests, you know your user) and determine their privileges against your Windows service.
Could be an access rights issue. When you run the application locally (through Visual Studio and the built-in Cassini web server) I think you're running it as yourself, so it makes sense that it would work.
When you run the application through IIS (on the server), its running as whatever user is specified in the application pool. (I think its "Network Service" by default). Check which user it is in IIS and try giving that user permission to start your service.
What version of IIS are you running? If its a Win 2K3 server, I'm guessing 6.0.
Information on configuring the application pool:
IIS 7.0
IIS 6.0
EDIT: You can use SubInACL.exe (a microsoft tool) to configure service permissions:
So let's say you have user "Johnny" and you want Johnny to be able to stop and start the World Wide Web Publishing service. Simply run the following subinacl.exe command:
subinacl /service W3SVC /GRANT=YOURDOMAIN\Johnny=TO
Obviously you will want to replace YOURDOMAIN with the name of your domain. The TO at the end are the identifiers that tell subinacl which actions you actually want grant to Johnny. T is used for "Start Service" and O is for "Stop Service".
For more information, check out Ingmar's blog post about it.
For Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista
Open IIS Manager.(From start->run-> type inetmgr and press enter)
In the Connections pane, expand the server node and click Application Pools.
On the Application Pools page, select the application pool for which you want to specify an identity, and then click Advanced Settings in the Actions pane.
For the Identity property, click the ... button to open the Application Pool Identity dialog box.
If you want to use a built-in account, select the Built-in account option and select an account from the list. Select Local System from the list
If you want to use a custom identity, select the Custom account option and click Set to open the Set Credentials dialog box. Then type the custom account name in the User name text box, type a password in the Password text box, retype the password in the Confirm password text box, and then click OK.
Click OK to dismiss the Application Pool Identity dialog box.
Right click on the application pull and then stop and again click on start

Get the current WindowsPrincipal on a Forms authentication website

I'm coming across a peculiar request: I have a website that uses Forms Authentication, but it now needs to grab the WindowsPrincipal (Windows Authentication) at some point in order to reuse it.
My first instinct was to create a new page, and to disable Anonymous Access on IIS for that precise page. When I'm on that page, Request.ServerVariables["LOGON_USER"] gives me the current Windows login name as expected.
Unfortunately, Context.User still gives me a GenericPrincipal.
Any idea on how I could get the current WindowsPrincipal in a FormsAuthentication Application? (recreating it by asking the user for his password is not an option)
Found it: Context.Request.LogonUserIdentity is what should be used in this scenario.
It will return the windows user that made the request if Anonymous Access is disabled on IIS (otherwise it'll return the IIS anonymous user).
For those interested on how to reuse it:
lblUserName.Text = WindowsIdentity.GetCurrent().Name;
// will return the ASP.Net user (that's useless to us)
WindowsIdentity id = Context.Request.LogonUserIdentity;
WindowsImpersonationContext ctx = id.Impersonate();
try
{
lblUserName.Text = WindowsIdentity.GetCurrent().Name;
// will return the correct user
// (...) do your stuff
}
finally
{
ctx.Undo();
}

Create A Default User for an ASP.NET Application Using Forms Authentication

I'm creating an ASP.NET web application which I want to secure with Forms Authentication.
When the application is run for the first time, I want it to create a default administrator account so that the owner is able to log in and configure the application.
I managed to get something working for this by running the following method from the Application_Start method:
private static void InitializeMembership(MembershipProvider provider)
{
int total;
provider.GetAllUsers(0, 1, out total);
if (total == 0)
{
Membership.CreateUser("admin", "admin");
}
}
The problem is this fails with an error about the chosen password not being secure enough. Normally this would be fine as I do want to enforce a strong password, but in this specific case I want a simple password
Is there a way of disabling the check for just this call, or am I approaching the whole problem incorrectly?
I would ship the DATABASE with the admin user in there by default, and force that password to get changed on the first login.
This is helpful in two ways:
1) You know that the default admin will always be there
2) you don't have to maintain that user creation code that will only run at very random intervals.
Alternatively, you could make your default password be more complex.

Resources