InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Security class library updated

Several changes in this release… so a new class diagram is advised:


Class diagram of the InfiniTec.Security 1.4 package (click to enlarge)

Breaking change is the renaming of the *SecurityContext* classes to *ImpersonationScope* classes. Additionally, a new base class has been introduced, the ImpersonationScope class, which essentially takes a username/password combination and does the impersonation.

Also new is the privilege handling: Privileges held by a WindowsIdentity can be enumerated, activated and permanently removed from the token.

Finally, the IdentityResolver can be used for two things:

  1. Translate a SID to an NT account name and vice versa on a remote machine.
  2. Identify the type of an account (User, group, computer, alias,…)

Change log

  • The *SecurityContext* classes have been renamed to *ImpersonationScope*
  • The SecurityContext class has been renamed to CallbackImpersonationScope
  • New ImpersonationScope class, which accepts a username/password combination
  • The AcquireCredentialCallbackEventHandler class has been removed in favor of the EventHandler<AcquireCredentialEventArgs> class
  • Privilege Management: The Privileges and Privilege classes allows the manipulation of privileges held by a WindowsIdentity.
  • New IdentityResolver. Basically, the same functionality as IdentityReference.Translate(). However, a remote computer can be used for the translation process. Additionally, the type of the account type (user, group, computer, etc) is returned

Downloads

InfiniTec.Security_1.4_Source.zip (51,460 Bytes)
Source code of the 1.4 version
InfiniTec.Security_1.4_Release.zip (48,179 Bytes)
Release build with debug symbols. Signed with the InfiniTec private key
InfiniTec.Security_1.4_Documentation.zip (240,624 Bytes)
Documentation of this release as CHM file.

Technorati:

Posted by Henning Krause on Sunday, October 29, 2006 12:00 AM, last modified on Sunday, October 29, 2006 11:00 AM
Permalink | Post RSSRSS comment feed

A class library providing methods for acquiring and managing user credentials.

The QueryCredentialDialog

If you connect to a network resource, windows uses a common dialog to query for a username / password, as shown hiere:
(click to enlarge)This dialog can also be used from custom applications, by calling the CredUIPromptForCredentials. The QueryCredentialDialog is essentially a wrapper around this function. It is derived from the CommonDialog class, and as such, can be dropped on any Windows form. The entered password is returned securely in a SecureString object. As such, the password is encrypted most of the time.

Note that the dialog does not check whether the entered credential represents a correct username and password. This makes it possible, to use this dialog even if you are requesting arbitrary credentials.

The CredentialManager

Windows also has a credential manager, which is tightly integrated with the CredUIPromptForCredentials method. If you choose to save the credential you enter into the dialog, this credential is stored in the Windows credential manager. Unfortunately, this is true for an unlimited amount of time, so the entered credential do not expire over time.

The CredentialManager implemented by this class saves the provided credentials in a secure manner (using a SecureString for the passwords). The credentials do expire over time, using two different expiration schemes:

  • Absolute expiration: Regardless how often a credential is used in a given timespan, the credential will expire after this timespan.
  • Sliding expiration: If a credential is not used for a specified timespan, the credential will expire.

The two expiration schemes can be used in together.

The SecurityContext

If you want to execute a region of code in the context of another user, you can use this class. The base class must be provided with a callback that provides the logon credential used for the impersonation. The main advantage, however, is the possibility to use the using construct, as shown in this example:

    1 using (SecurityContext context = new SecurityContext("target", AcquireCallback, true))

    2 {

    3     DoSomething();

    4 }

The AcquireCallback method could be implemented like this example:

    1 privatevoid AcquireCredential(object source, AcquireCredentialCallbackArgs e)

    2 {

    3     CmdLinePromptForCredential prompt;

    4 

    5 

    6     prompt = new CmdLinePromptForCredential(e.TargetName,

    7         string.IsNullOrEmpty(e.Username) ? _Username : e.Username,

    8         QueryCredentialOptions.ExcludeCertificates | QueryCredentialOptions.DoNotPersist |

    9         QueryCredentialOptions.ValidateUsername);

   10 

   11     e.Cancel = !prompt.Prompt();

   12     e.Username = prompt.Username;

   13     e.Password = prompt.Password;

   14 }

If do not want to impersonate immediately, you can set the last parameter in the SecurityContext constructor to false. You can either use the context.Impersonate() method later, or use the StartProcess method to run a process under the usercontext of the SecurityContext.

Two derived classes are implemented, which simplyfies the usage of the SecurityContext object: The DialogSecurityContext, and the CmdLineSecurityContext. The first one is designed for use in a Windows Forms application, as it utilizes the QueryCredentialDialog to get a valid username/password combination. The latter one uses the CmdLinePromptForCredential class, which is essentially a console version of the QueryCredentialDialog.

The credential acquired by the impersonation context is cached in the Credential manager for future use. Unless the credential expires, the user will not be asked again to enter a username/password.

The SecureStringDecryptor

The SecureString is a very usefull class when handling sensitive data, because its contents are encryped most of the time. Unfortunately, if you want to use such a string to encrypt using the Rijndael algorithm, you are stuck, because it does not accept a SecureString as a key. It requires an array of bytes. So, the right thing to do is to use one of the DeriveBytes classes: PasswordDeriveBytes or the Rfc2898DeriveBytes class. Because the PasswordDeriveBytes.GetBytes method is marked obsolete, you should stick to the latter one.

Next disappointment: Neither one of the DeriveBytes implementations accept a SecureString as a password. Only a string or a byte array. At this point, you can use the SecureStringDecryptor: It decrypts the SecureString into a pinned byte array, that can then be used to initialize one of the DeriveBytes classes. Once you are finished, just call the Dispose method of the SecureStringDecryptor, and the password array is zeroed out. Here is an example in C#:

    1 privatevoid EncryptData(byte[] dataToProtect)

    2 {

    3     SecureString secret = GetSecret();

    4     byte[] salt = GetSalt();

    5     DeriveBytes db;

    6     Rijndael rijndael;

    7     ICryptoTransform transform;

    8 

    9     using (SecureStringDecryptor helper = newSecureStringDecryptor(secret)) {

   10         db = newRfc2898DeriveBytes(helper.Password, salt, 1024);

   11     }

   12     rijndael = Rijndael.Create();

   13     transform = rijndael.CreateEncryptor(db.GetBytes(16), rijndael.GenerateIV())

   14 

   15     return transform.TransformFinalBlock(dataToProtect, 0, dataToProtect.Length);

   16 }

ChangeLog

Version 1.3

  • The ImpersonationContext class has been renamed to SecurityContext
  • The DialogImpersonationContext class has been renamed to DialogSecurityContext
  • The DialogImpersonationContextInfo class has been renamed to DialogSecurityContextInfo

  • The CmdLineImpersonationContext class has been renamed to CmdLineSecurityContext

Version 1.2

  • Added a Confirm and Invalidate method the the SecurityContext. This is useful when generic credentials are queried from the user instead of Windows credentials (for example to authenticate to a remote webserver). In this case you can manually confirm or invalidate the credential.
  • Added a Username and Password property to the SecurityContext class. Again this is important when working with generic credentials.
  • Added a new class: SecureStringDecryptor. This class allows you to get a byte array containing the decrypted content of a SecureString instance. But be careful when using this class. Do not convert the byte array to a string instance. Do not make a copy the byte array. You should use this class as described in this article only. Otherwise, most of the security advantages of the SecureString class are gone. You have been warned!

Version 1.0

Initial Release

Downloads

infiniTec.Security_Documentation.zip (102,170 Bytes)
Documentation
infiniTec.Security_source.zip (28,660 Bytes)
Full source code
InfiniTec.Security_release.zip (31,638 Bytes)
Strong named release binaries with debug symbols.

Technorati:

Posted by Henning Krause on Tuesday, November 29, 2005 12:00 AM, last modified on Friday, December 30, 2005 12:00 PM
Permalink | Post RSSRSS comment feed