FIM2010: Protect passwords in configuration files

Originally posted at: FIM2010: Protect passwords in configuration files @ IS4U Blog

Intro

One of the great features of FIM is that it is relatively easy to plugin custom functionality. You can extend the synchronization engine by developing rules extension and you can add custom workflows to the FIM portal. Rules extensions run under the FIM synchronization service account, workflows under the FIM service service account. This article describes an approach to enable communication to external systems (eg Exchange). Because you typically do not grant a service account rights to Microsoft Exchange, you need the ability to run part of your code using different credentials.

Encrypt password

You do not want to have passwords in clear text in configuration files or source code. That is where encryption comes into play. Encryption can be handled in a myriad of different ways. The method described here uses powershell cmdlets, which keeps it quite simple and understandable.

So, how do we convert plain text to something more secure that cannot be read by anyone who happens to have read access to the files? Following two powershell commands are the answer:

$secureString = ConvertTo-SecureString -AsPlainText -Force -String $pwd
$text = ConvertFrom-SecureString $secureString

The cmdlet ConvertTo-SecureString creates a secure string object from the password stored in the variable $pwd. The $text variable is a textual representation of the secure string and looks something like this: 01000000d08c9ddf0115d1118c7a00c04fc297eb01000000c6c2de88df8670438e7ac64054c971490000000002000000000003660000c000000010000000103f2b826467c9fdaff555bc064b4da50000000004800000a00000001000000006673bf0a8cd2463ec9f9fd1a911dfc30800000076d2a3f9c1102b6e1e0000006452d271a75a5df3a600f0f7cb45c18df98d3aae

Decrypt password

PowerShell

To decrypt the password in powershell, use the ConvertTo-SecureString cmdlet:

ConvertTo-SecureString $text

The output of this cmdlet is a secure string object which can be used to build a PSCredential object.

C#

To perform decryption in C# you need to add a reference to System.Management.Automation in your project. To export the dll to the current directory execute following powershell cmd:

Copy ([PSObject].Assembly.Location) .

Following code shows how to use the PowerShell library to construct a PSCredential object. The PSCredential object can then be used to perform management operations on Exchange.

using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Security;

private string PWD = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000c6c2de88df8670438e7ac64054c971490000000002000000000003660000c000000010000000103f2b826467c9fdaff555bc064b4da50000000004800000a00000001000000006673bf0a8cd2463ec9f9fd1a911dfc30800000076d2a3f9c1102b6e1e0000006452d271a75a5df3a600f0f7cb45c18df98d3aae";
private string USER = @"is4u\sa-ms-exch";

private PSCredential getPowershellCredential()
{
  PSCredential powershellCredential;
	string powershellUsername = USER;
	SecureString pwd = getPowershellPassword(PWD);
	if (pwd != null)
	{
		powershellCredential = new PSCredential(powershellUsername, pwd);
	}
	else
	{
		throw new Exception("Password is invalid");
	}
  return powershellCredential;
}

private SecureString getPowershellPassword(string encryptedPwd)
{
	SecureString pwd = null;
	using (PowerShell powershell = PowerShell.Create())
	{
		powershell.AddCommand("ConvertTo-SecureString");
		powershell.AddParameter("String", encryptedPwd);
		Collection<PSObject> results = powershell.Invoke();
		if (results.Count > 0)
		{
			PSObject result = results[0];
			pwd = (SecureString)result.BaseObject;
		}
	}
	return pwd;
}

NetworkCredential

If your operation requires you to connect using a network credential instead of a PSCredential object, this is very easy. You can get the corresponding NetworkCredential object from the PSCredential.

using System.Net;

private NetworkCredential getNetworkCredential()
{
  NetworkCredential cred = getPowershellCredential().GetNetworkCredential();
  return cred;
}

Security aspects

Only the user account that encrypted the password can decrypt it (because Kerberos keys are used under the hood). This is illustrated in following screenshot. If you look carefully, you can check I did not cheat on the parameter.

secureString

Conclusion

The approach described here is simple, quick and secure. You need to run a few PowerShell commands and you can store passwords securely in your configuration files. Make sure to encrypt the required password using the service account that will be performing the decryption. Note that this technique is not limited to use in FIM deployments. You can use this technique in any .Net/Windows context.

References

Scripting Guy – Decrypt PowerShell Secure String Password

Leave a Reply

Your email address will not be published. Required fields are marked *