WPF application with Windows authentication - c#

I have a simple wpf client (few text boxes) that uploads some data to a web service. And I want to use windows authentication to go with my application.
I am checking in OnStartup of App.xaml, whether or not the user is authenticated. My question is around what is the meaning of Thread.CurrentPrincipal.Identity.IsAuthenticated.
I don't want my application to be used from outside my network as it is connecting to a web service and uploads data. But my assumption is as long as you run this application from inside any windows network the above mentioned property will always return true?
So how do I find out if the application is being run from inside my network. I don't think checking domain name or role name is any different, because I can always setup a domain and name it whatever I want. I don't want to prompt user for username or password of any sort.
How do you check Identity of user against a particular AD (AD might not be publically available). Basically the application should only works from my local network or through VPN.

var context = new PrincipalContext(ContextType.Domain, "DOMAINNAME");
var result = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName);
If the result is null, then the user does not exists in the AD domain.
You can also user DirectorySearcher class to query AD based on a filter criteria. This is more useful only if you would like to retrieve additional details about the user like contact, email address etc.

Related

Matching current user with ActiveDirectory DirectoryEntry

My scenario:
A client app (Net Core WPF) should somehow find out the current user's identity (for example using System.Security.Principal.WindowsIdentity.GetCurrent()) and authenticate with a REST server application (Net Core) which has access to AD (it knows the address, name and password of root AD DirectoryEntry). The authentication should be successful if and only if the user from the client app is found among users in AD. This is an intranet setup btw.
Solutions to similar questions here on SO (for example How to get the current user's Active Directory details in C#) generally propose using DirectorySearcher and filtering on user name "(sAMAccountName=theUserIWantToMatch)".
But IMHO this is not sufficient:
1) It is not secure enough, you can easily impersonate anybody just by creating a user with a similar name. Not to mention man-in-the-middle attacks.
2) It needn't even be malicious, plenty of people have similar names. I might have connected to the intranet network via VPN using a computer with a similar user name (similar to somebody else already on that network).
Can you think of a better way to match the users (using some GUID or token for example) or completely different authentication method? Just to reiterate: I can't use usual ASP.NET windows auth because my client is a WPF app that communicates with the server using HttpClient instance.
Thank you.
A fail-proof way of getting the exact user that's logged in is by using the SID, which is available from WindowsIdentity.GetCurrent().User.
From there, you can bind directly to the AD object using the LDAP SID binding syntax of LDAP://<SID=XXXXX>.
That will look something like this:
var sid = WindowsIdentity.GetCurrent().User;
var currentUser = new DirectoryEntry($"LDAP://<SID={sid}>");
If the computer you're running this from is not joined to the same domain as the user (or trusted domain), then you will need to include the domain name in the LDAP path:
var currentUser = new DirectoryEntry($"LDAP://example.com/<SID={sid}>");
This method is also faster than any other method, since you're not performing a search and then binding to the object. It's all done in one network request.

Querying AD in context of an authenticated user in an ASP.NET Core MVC webapp

I'm working on a web application based on ASP.NET Core MVC 2.1. It provides the ability to execute several Active Directory related operations. One of them is a web based LAPS client. To communicate with AD, I'm using System.DirectoryServices from Microsoft.Windows.Compatibility.
Since LAPS stores its data in a computer objects AD attributes (ms-Mcs-AdmPwd), I need to query this attribute, e.g. like this:
using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, targetDomain)) {
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(principalContext, IdentityType.Name, computerName);
string password = (computer.GetUnderlyingObject() as DirectoryEntry).Properties["ms-Mcs-AdmPwd"].Value.ToString();
}
So my problem is: I need to do this in context of the authenticated user, because the attribute security permissions already control access to the LAPS passwords. I implemented cookie authentication without Identity querying PrincipalContext.ValidateCredentials() against AD in order to authenticate users. What would be the best way to achieve this without asking the user for login data a second time?
There is a PrincipalContext constructor PrincipalContext(ContextType contextType, string name, string userName, string password), but this would require a way to store the password for each session. Storing the password in the session itself would be a bad idea, I guess.
Furthermore, I could just query the data on server side as ApplicationPoolIdentity or as a dedicated service account (which would then need full access to the relevant attributes of all computer objects) and then implement some logic to determine, if the logged in user is permitted to access this specific password. But this would result in unneccessary effort, since all authorization information already exist as AD DACLs.
I hope this makes sense somehow. So if anyone can push me in the right direction, I would be very grateful. Thanks in advance!
After all, I went with a mapping approach in order to determine, if a user is allowed to access data. If the user is member of a certain AD group containing the admins of a certain department and the target computer object is located in the corresponding OU, the password will be queried and subsequently displayed. ApplicationPoolIdentity executes the actual AD query. Works flawlessly so far.

Log AD users in

I have a login form written in C# and I want only AD users to be able to login.
How should I do this?
string UserName = "";
string Pass = "";
Although it is not an ASP.Net app the active directory membership provider will work just fine.
Here is info on how to use this library:
http://msdn.microsoft.com/en-us/library/system.web.security.activedirectorymembershipprovider.aspx
and here is some more information:
http://msdn.microsoft.com/en-us/library/ff650308.aspx
I am sure that this is not a best practice, but, depending on your security needs, you could allow all domain users and exclude local users by checking just the UserDomainName in the Form_Load. This simple approach piggybacks on their computer login, and does not have the complexity of any LDAP/AD calls.
if (SystemInformation.UserDomainName.ToString() == "myDomain")
{
// your normal form load code here
}
else
{
form1.Close(); //this is a simple but effective to pull the rug out from
//under them if they do not have the permissions
//TODO email the application administrator the `SystemInformation.UserName` of the user who was not given permissions
}
In my environment, since our in-house apps are deployed via ClickOnce (installed per user per computer), a similar approach (we compare usernames too) has always been sufficient for us.
If you want to know how to verify credentials to Active Directory in order to allow AD users in you application, you should check this.
You'll find how to verify the content of your textboxes and verify if username and passowrd matches (directly with the AD).

User Permission Mask from NetworkCredentials

Although I am currently developing this WinForms application on our Sharepoint server I intend for the finished program to function from any computer on the Domain. I'm using the WSS web services to get all the information I use from Sharepoint.
I have written some code which will check Sharepoint Permission masks, with logical OR against mask, for all the permissions it covers but I am having trouble returning the Sharepoint mask for the current user. I would like users to be able to log right in through Windows Authentication so this was my immediate idea.
NetworkCredential credentails = CredentialCache.DefaultNetworkCredentials;
var userInfo = userGroupService.GetUserInfo(credentails.UserName);
However although I am able to return the permission collection for the entire Sharepoint site with DefaultNetworkCredentials (as in bellow snippet) the properties are empty strings, so I can't use it to get the UserName.
permissionService.Credentials = CredentialCache.DefaultNetworkCredentials;
permissionService.Url = "http://localhost/mySite/_vti_bin/Permissions.asmx";
// Web service request works
XmlNode node = permissionService.GetPermissionCollection(siteName, "Web");
// But I need to identify current user from this collection somehow still
I read that Windows Authentication suffers from a double-hop issue, which I want to avoid, but as I am developing on the server Sharepoint & IIS are running, I can't see this causing an immediate issue.
Is there a way around this or a better way to get the current users permission mask?
If the current user for wss will always be the same as the user currently logged on to the pc
var userInfo = userGroupService.GetUserInfo(Environment.UserDomainName +#"\"+ Environment.UserName);
or to get the permissions for the currently logged on user
XmlNode currentUserPermission = userGroupService.GetRolesAndPermissionsForCurrentUser();
You are dealing with an issue where the authentication cannot move beyond one remote host; this is known as the "one-hop" limitation.
To overcome this, you have to get into "Constrained Delegation," where a computer/account are expressly authorized to receive and accept authentication credentials from another computer/account. This is set up in Active Directory by defining the appropriate Service Principal Names (SPN's) on either "end" of the delegation.
You can get more details about Constrained Delegation here.
Good luck! CD can be a bit of a pain to set up, so tread carefully.

How to search Active Directory when dialed in remotely?

Is there a way to use a credential coming from the user's saved password list and use that instead of the local Windows credentials?
I need to look up a user's email address based on their Active Directory username to allow them to register for email updates via an intranet site. This seems easy enough if the user is actually logged into a machine directly that's part of the domain - I can use their identity name to search the AD based on their username:
using( DirectoryEntry root = new DirectoryEntry("LDAP://admachine.domain.local") )
{
using( DirectorySearcher searcher = new DirectorySearcher(root) )
{
// strip the domain from the username and find the user in AD
var username = Regex.Replace(Page.User.Identity.Name, #".*\\", string.Empty);
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.SearchScope = SearchScope.Subtree;
searcher.Filter = string.Format("(&(objectCategory=user)(objectClass=person)(sAMAccountName={0}))", username);
var foundUser = searcher.FindOne();
// error checking occurs here...
var email = foundUser.Properties["mail"][0].ToString();
// TODO: stuff with the email address
}
}
However, if working from a PC at home this doesn't work. Page.Identity.Name resolves to the name I'm logged onto my own PC (MyMachine\Dave), ignoring stored credentials I used to authenticate with my work domain (WorkDomain\dave.downs).
The DirectoryEntry picks up and uses the saved credential just fine, allowing me to actually bind to and search the AD, but I can't find a way of then using it as the var username, which will contain of my local machine username instead.
Is there a way to actually do what I'm trying to do, or am I just going about things the wrong way/hitting my head against a brick wall?
I assume you are using IIS. Disable Anonymous Access and enable windows authentication. That way anybody who is not in the domain will get a popup that allows them to specify their domain user and password. For users that are coming from a domain enabled server nothing changes. But that way you guarantee that the identity will always resolve to a valide domain user. So this should solve your "I am seeing a non-domain user" problem. Check Windows Authentication Provider for details.
If they are logged in via Windows Auth, you can use:
System.Security.Principal.WindowsIdentity.GetCurrent().User
which will give you the sid of the logged in user.
Disable anonymous access and integrated security in IIS, force them to log in via basic auth under https. This will give make sure the the current session is running under an authenticated domain user.

Categories

Resources