How can I get an X509Certificate2 object for an authenticated user? - c#

I'm a bit out of my depth here so bear with me if I say/ask/do something idiotic.
Anyways, I have a dll that I need to use for a project of mine. Essentially, this dll is my interface to another service I need to use. I don't own the dll so I can't change it's interface/code at all, and the interface to the underlying service is unknown (expect by using its SDK dll obviously). One of the functions I need to use from this sdk requires me to provide either the user's name & password in plain String format, in String and SecureString formats, or just provide an X509Certificate2 object.
My website is currently configured to use windows authentication. What I would like to do is be able to call into this dll without asking for the user's password (seeing as they already had to enter it in order to access the site). I am assuming that there is a snowball's chance in hell that I have access to the user's password itself as either a String or SecureString, but it looked like I could construct the x509 certificate object doing something like this:
var x509 = new X509Certificate2(Request.ClientCertificate.Certificate);
Unfortunately, it appears like Request.ClientCertificate.Certificate is always empty for whatever reason.
Is there some other way that I can access this information? If I have sufficient information to impersonate the user (via HttpContext.Request.LogonUserIdentity.Impersonate()), then should I not have enough information to construct a X509Certificate2 object for this user as well? If not, what would I need to do to get the client certificate populated in the request?
Any help is greatly appreciated. Thanks!

Related

How to make certificate accessible to CurrentUser\My installed on store location LocalMachine\My

My applications uses the method X509Store(someStoreName). someStoreName is custom store name which will be removed. And because of this we need to access all the certificate from MY/Personal store which are installed on location LocalMachine. I provided the access to certificate in MMC for user id to make it accessible using X509Store(someStoreName). But I am still not able to find it, what should id do for finding it.
X509Store(someStoreName,StoreLocation.LocalMachine) this solution is working but I cant use it because of heavy dependency of X509Store(someStoreName) in our code base.
You have to rewrite all existing code to use X509Store(someStoreName,StoreLocation.LocalMachine) overload. There is no way to propagate certificate from LocalMachine\My to CurrentUser\My.

How to create Postgresql user without any trace of password in logs?

I have a question about creating new Postgresql database user in C# application.
If I create user like this in psql:
create role foo with login; \password foo
this encrypts password on client side, so no plainText is in the logs.
Guys on IRC community forum recommended that I look for something like PQencryptPasswordConn() in driver that I am using, in this case Npgsql, but I can't seem to find anything like that.
Has anybody got any idea how to create user in the same safe way as with psql?
If you are using md5 password "encryption", you can easily do this yourself as long as you can find a c# library which computes md5 hashes as hex. The encrypted password is simply 'md5' . md5_hex(password . username), where . is string concatenation operator. Once you have that, you would simply do something like:
create role foo with login password 'md5258f951d4d9d3ea3854f265195f63dda'
I don't think npgsql supports using scram authentication at all, so there should be no need to set a scram-encrypted password using npgsql. It does support using scram to log in, but it seems to be undocumented and does not seem to support changing the password on the client side.

Hide password in c# source code

I am using the following code in c# to download a file from my website:
WebClient webClient = new WebClient();
webClient.Credentials = new System.Net.NetworkCredential("username", "password");
webClient.DownloadFile("http://example.com/file.txt", "file.txt");
The file is only downloaded when certain criteria are met, so I don't want the users to be able to access the files on my site
My corcern is that if a curios users decompiles the code, he will find the password and be able to access all the files on my site.
I've read that a secure way to save the password is to store its hash, but I don't know how to implement it in this example.
What options do I have to keep my password secure and make it impossible for a user to find it?
A sobering reality: You can't protect information contained in your program like this.
A must-do: Choose a username/password that is only for accessing the special files this single program needs - not your "access my whole website" username and password.
But just know that all you are doing is adding a little bit of an obstacle, here; anyone who wants to can examine your program and find the username and password.
The only 'correct' way to do this is to do it based on the user's own credentials; their username and password within your own system, for example. Then you would need to give them access based on that information, and your program would need to prompt them for it.
You simply don't. Users give you passwords to do stuff, not the other way around.
If the user has to prove "certain conditions", then pass proof of those certain conditions to the server, and let it decide whether to allow the download or not.
There is no way to prevent that. If you program is able to access the file under condition X, the user is able to trick the program into condition X and get the file no matter what. You can make it harder, but you can't make it impossible.
If the data are in the program itself you can considered them as already being exposed to users. If the credentials are on the users computer regardless on how many measures you take to combat this there is always a possibility to find a way around it.
What you can do is implement a login form for your program and provide the users with login info. Then when the user enters the login info do a check on the server side if the credentials exist (usually by checking in a database) and if it matches send them the file.
But as always, there is the issue with users just sharing the login info with other people and so on.

How to Get and Change Windows Credential Username and Password

I want to write a application in C# using WMI that can get and change Windows credential stored in the Windows Credential Manager, as you see in the picture below:
Ookii.Dialogs contains a credential dialog, which calls into CredUIPromptForCredentials or CredUIPromptForWindowsCredentials as appropriate.
Edit: The Credentials API is detailed at http://msdn.microsoft.com/en-us/library/aa374731%28v=VS.85%29.aspx#credentials_management_ui_functions - but it could be tricky to implement from managed code. After CredUIPromptForWindowsCredentials you would call CredWrite to save the credentials.
Edit: Misunderstood the original question since the pic wasn't visible.
I'm not sure if you can do what you want via WMI. However, I think it might be possible using the DPAPI, but the documentation for that doesn't seem to make it very easy. However, there is an opensource project called NCrypto that has a class called UICredentialsHelper which might show you how to do it, or at least how to get started.
There is no Windows API to get a user's password. Passwords are not stored in Windows. Instead Windows stores a one-way hashed version.
You can get the username using WindowsIdentity.GetCurrent(). Alternatively you can get the logged in user name via the Environment.UserName property.
Although to change credentials..... good luck :) Thats my best answer on that. I don't think Microsoft would ever give us the ability to do that.
[void]Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
(new-object Windows.Security.Credentials.PasswordVault).RetrieveAll() | % { $.RetrievePassword(); $ }

Secure password solution for a web service authenticating against Active Directory?

An application I'm modifying has a Web Service, and one of the web methods on that web methods is used to authenticate a user against active directory. So the current code called by the AuthenticateUser web method looks something like this:
string domainAndUsername = aDomain + #"\\" + username;
string ldsPath = buildLdsPath(searchBase);
DirectoryEntry entry = new DirectoryEntry(ldsPath, domainAndUsername,
password);
try
{
//Bind to the native AdsObject to force authentication.
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(sAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
// more code to validate the result, etc...
}
When I started looking at this code, the first thing that worried me is the arguments to the web method look like this:
[WebMethod]
public ResultObj AddRole(string roleToAdd, string username, string password)
{
// code that calls above Authentication fragment...
}
So the current web service is expecting a password string, presumably sent in the clear over the network as XML, when the request is made to the service.asmx page.
Has anyone dealt with this type of issue before? Are there alternative Active Directory authentication mechanisms I could use that would avoid having to pass in a plain-text password? The best option I could come up with on my own is to invoke the WebMethod using an encrypted password, and have the code on the other side decrypt it. However, I'd prefer a better solution--e.g.: is there some way to do search for a DirectoryEntry using a one-way hash instead of a password?
Edit:
Additional Details: To this point I haven't considered SSL as this is a tool that is internal to our company, so it seems like overkill, and possibly problematic (it'll be running on a company intranet, and not externally visible). The only reason I'm even worried about the security of sending plain-text passwords is the escalating amount of (possibly password-sniffing) malware present even on company intranets these days.
If you have a public/private key combination, then the client could encrypt with the public key, and you decrypt with the private key.
However, that's too much work for the client, and not a very "web method" way of doing it.
Since you are sending the user name and password as parameters then you should resort to transport security, HTTPS, basically, which requires you to have a public/private key combination issued to you from a trusted certificate authority.
It should be noted that your association of SSL encrypted channel with an external facing site is incorrect. The point of wanting to encrypt a channel is to prevent man-in-the-middle attacks, exactly like you are trying to do here.
You could use a self-issued certificate, but that would require installing the public key of the certificate on each machine that is going to call your web method. It's easier to just get one from a trusted authority.
HTTPS (as mentioned) is the easy choice. Or, you could just let IIS handle authentication thru Digest or NTLM. Your app can still make authorization rules. NTLM is secure, but it'll hurt your interop. Otherwise, AD does offer some digest authentication methods, but I don't have tested code using them.
With Server 2000 domains, there's an option for "Store passwords in reversible format" - that will allow a domain controller to calculate MD5 hashes of the password to compare against your presented MD5 hash. MS realized this was a bit of a security problem, though, so Server 2003 implemented "Advanced" digest authentication - which precomputes the hash.
LDAP signon should select MD5 Digest as the authentication type, supply the username, and then supply the MD5 hash of the password. The normal LDAP clients will probably want to MD5 your password themselves though, so you'll have to override or craft them yourself.
We put our AD service on its own web site and got an SSL cert. Problem solved.
I think SSL, or possibly IPSec, are probably your best solutions.
For our particular situation, because both the client and the web service are running on our company Intranet, a solution that may work for us is to handle the Authentication on the client end using the Integrated Windows NTLM authentication, and then then just have the client supply the credentials to the Web Service. Here is the client code:
public void AddRole(string roleName)
{
webSvc.Credentials = CredentialCache.DefaultCredentials;
// Invoke the WebMethod
webSvc.AddRole(roleName);
}
The web method will now look like this:
[WebMethod]
public ResultObj AddRole(string roleToAdd)
{
IIdentity identity = Thread.CurrentPrincipal.Identity;
if (!identity.IsAuthenticated)
{
throw new UnauthorizedAccessException(
ConfigurationManager.AppSettings["NotAuthorizedErrorMsg"]);
}
// Remaining code to add role....
}
Again, I must stress this solution will probably only work if the server trusts the client, and both talk to the same Active Directory server. For public Web Services, one of the other answers given is going to be a better solution.
For further information, see:
Microsoft Support Article on passing credentials
MSDN Article on Building Secure Applications
MSDN Article on Windows Authentication - includes info on correctly configuring the web service to use the Windows Principal and Identity objects needed.

Categories