Encrypting files as a different user

by timvasil 4/28/2009 12:08:00 AM

I'm running a C# application that needs to encrypt/decrypt files (using NTFS's EFS encryption) on behalf of a specific user account--a user account other than the one under which the application is running.  I didn't want to go through the hassle of firing up a new process (using CreateProcessAsUser) because I'd have to worry about IPC and it'd be less performant.  The question I had was:  is it possible to encrypt/decrypt files as a user other than the one under which the process is running within that process?  I couldn't find any resource on the web that stated an answer definitively, so I wrote some code to try it.  The answer is:  yes.

Here are the steps (it involves a mix of Interop and managed methods):

  1. Get a handle to the desired user (the one whose encryption key you want to use) by calling LogonUser.  (You'll need the user's password.)
  2. Load the user's profile (aka registry hive) by calling LoadUserProfile.
  3. Construct a WindowsIdentity object using the handle provided by the call in step 1.
  4. Invoke WindowsIdentity.Impersonate().
  5. Perform any file I/O -- it'll be in the context of that user.  The user's encryption key will be used with any File.Encrypt() / FileInfo.Encrypt() invocation.
  6. Unload the profile by calling UnloadUserProfile.
  7. Close the user handle by calling CloseHandle.

You can do steps 1-4 in the constructor of an IDisposable object and do steps 5-7 in the Dispose() method to ensure proper resource cleanup. 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Windows | .NET Framework | C# | Security

Fixing "Instance names used for writing to custom counters must be 127 characters or less."

by timvasil 11/11/2008 12:39:00 PM

If you've run a unit test in Visual Studio 2008 that utilizes database connectivity, you may have seen this error when creating a connection object:

Instance names used for writing to custom counters must be 127 characters or less.

The problem crops up when you're running the test within a directory structure with a fairly long name, i.e. you're organizing your code well and giving your projects descriptive names.  Well, this error is punishment for being organized.

There are several Microsoft bug reports on the issue.  One has been ignored, the other closed.

There are posts on the web with some workarounds, but none worked for me, perhaps because I'm using Visual Studio 2008?  No matter what I tweaked in .testrunconfig I was still getting the error.  The other approach--shortening the pathname--was really a non-starter.  I wasn't going to compromize well-thought-out organization to get around a Microsoft bug.

So I took a peek at the source of the problem as hinted by the call stack when the error appeared.  It's a method in the internal DbConnectionPoolCounters class in the System.Data.ProviderBase assembly.  Here's the code:

private string GetInstanceName()
{
    string assemblyName = this.GetAssemblyName();
    if (ADP.IsEmpty(assemblyName))
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        if (currentDomain != null)
        {
            assemblyName = currentDomain.FriendlyName;
        }
    }
    int currentProcessId = SafeNativeMethods.GetCurrentProcessId();
    return string.Format(null, "{0}[{1}]", new object[] { assemblyName, currentProcessId }).Replace('(', '[').Replace(')', ']').Replace('#', '_').Replace('/', '_').Replace('\\', '_');
}

The instance name of the performance counter is being built, in part, from the name of the AppDomain.  When running tests in Visual Studio, this name can be very, very long, especially if your project's home has a long pathname.

The workaround I pursued, then, is to shorten the name of the app domain.  While AppDomain.FriendlyName is a read-only property, and there's no private field of the AppDomain class to change it, there is a private extern method of AppDomain called nSetupFriendlyName.  And, like magic, if you invoke this method and give the app domain a shorter name, problem solved!

Here's the workaround, utilizing a little reflection magic:

[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
    typeof(AppDomain).GetMethod("nSetupFriendlyName", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(AppDomain.CurrentDomain, new object[] { "Test" });
}

Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Visual Studio | .NET Framework | C# | ADO.NET | MSTest

NHibernate & Spring.NET with Oracle

by timvasil 2/14/2008 1:50:00 PM
The documentation for using NHibernate with Oracle is a bit spotty.  Based on some internet searches and trial & error, here's what I've found to work:
  1. Download the Oracle client (or "instant client"):
     
    http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/winsoft.html
     
    Without this client, you'll see the following error message when using Microsoft's Oracle driver:  Class Initialization method Imd.Tests.ServerApi.DeploymentTest.Initialize threw exception. NHibernate.HibernateException:  NHibernate.HibernateException: System.Data.OracleClient requires Oracle client software version 8.1.7 or greater. --->  System.Exception: System.Data.OracleClient requires Oracle client software version 8.1.7 or greater.
     
  2. Set the ORACLE_HOME environment variable and restart your IDE.  An example value is C:\Oracle\product\10.1.0\Client_1. If you don't set this variable you get an error message stating:
     
    Unable to load DLL
    'OraOps10.dll': The specified module could not be found
     
     
    If you specify the wrong directory, i.e. specify a directory one level too high or too low, you'll see bizarre exceptions, including NullReferenceExceptions circa Oracle.DataAccess.Client.OracleException.get_Source() or Oracle.DataAccess.Client.OracleException.get_Message().
      
  3. Add a project assembly reference to Oracle.DataAccess.dll.  I found this in C:\Oracle\product\10.1.0\Client_1\BIN.
     
  4. Update your App.config (or Web.config) properties to specify the Oracle connection string, driver, dialect, etc:

        <db:provider provider="OracleClient-2.0"
                     connectionString="Data Source=(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = {hostname})(PORT = 1521)))(CONNECT_DATA = (SERVICE_NAME = {serviceName})));User Id={username};Password={pass};"/>
     
        <object id="ConfigDbSessionFactory"
                type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
            <property name="HibernateProperties">
                <dictionary>
                    <entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/>
                    <entry key="hibernate.dialect" value="NHibernate.Dialect.Oracle9Dialect"/>
                    <entry key="hibernate.connection.driver_class" value="NHibernate.Driver.OracleClientDriver"/>
                </dictionary>
            </property>
           . . .
        </object>

These instructions are for using Microsoft's .NET driver (System.Data.OracleClient / V2.0.0.0).  A few settings would have to change if you want to use Oracle's .NET driver driver instead (System.DataAccess.Client / V2.102.2.20):

  1. Change OracleClient-2.0 to OracleODP-2.0.
  2. Change NHibernate.Driver.OracleClientDriver to NHibernate.Driver.OracleDataClientDriver

According to the NHibernate documentation, "Microsoft's driver does not handle long character strings correctly. An error happens in some circumstances when using a string of length 2000-4000 as a parameter value.  Oracle cannot handle empty strings (""), you should use null instead. An IUserType implementation to perform the conversion is contained in Nullables.NHibernate library (part of NHibernateContrib package)."  I've also seen problems with the Microsoft driver not being able to convert a Guid into a byte[].  So pick your poison :-)

Common Pitfalls:
  • You may recieve a perplexing "invalid username/password" error when your username and password is, in fact, correct.  ODP.NET might be adjusting the case of your password before hashing it and sending it to Oracle; you can get around this by turning off case sensitivity:
    ALTER SYSTEM SET SEC_CASE_SENSITIVE_LOGON = FALSE;
  • You may see NullReferenceExceptions with Oracle.DataAccess.Client.OracleException.get_Source() in the stack trace.  This may be indicative of a mismatch between the Spring.NET provider name and the NHibernate driver, i.e. using an Oracle provider name and a Microsoft driver.  If you specify OracleClient-2.0, use the NHibernate.Driver.OracleDataClientDriver driver; if you specify OracleODP-2.0, use NHibernate.Driver.OracleClientDriver.

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET Framework | Hibernate | Oracle | Spring.NET

WCF serialization with NHibernate object graphs

by timvasil 2/5/2008 11:05:00 AM

Say you have a complex object graph with circular references and you need to send it across the wire as XML.  The good ol' XmlSerializer is not going to help you; you need a more powerful too like WCF's DataContractSerializer.  By slapping [DataContract] onto the classes in your object graph and [DataMember] onto the non-transient properties and fields of these classes, you're golden.  WCF serializes cyclical object graphs without complaint.  Well, almost.

If you're using Hibernate's lazy-initialization feature, you'll see a problem:  .NET will compain about unknown types (proxy wrappers) that need to be registered as well-known types.  Unfortunately the types aren't known until run-time.  Sure, you could traverse the object graph at runtime, figure out these proxy types, and pass them into a DataContractSerializer costructor, but that's far from elegant.  Even if you make it over that hurdle, .NET will complain about Hibernate's persistent set implementations too; you'll have to add those types too.  If you're using generics, that could quickly balloon to a lot of types.

Fortunately there's a straightforward solution:  IDataContractSurrogate.  WCF provides this interface specifically to get around sticky situations like this.  You can use it to unwrap and initialize proxies, and to replace Hibernate's persistent collections with built-in well-known collections. Here's how it works:

public class HibernateDataContractSurrogate : IDataContractSurrogate
{
    public HibernateDataContractSurrogate()
    {
    }

    public Type GetDataContractType(Type type)
    {
        // Serialize proxies as the base type
        if (typeof(INHibernateProxy).IsAssignableFrom(type))
        {
            type = type.GetType().BaseType;
        }

        // Serialize persistent collections as the collection interface type
        if (typeof(IPersistentCollection).IsAssignableFrom(type))
        {
            foreach (Type collInterface in type.GetInterfaces())
            {
                if (collInterface.IsGenericType)
                {
                    type = collInterface;
                    break;
                }
                else if (!collInterface.Equals(typeof(IPersistentCollection)))
                {
                    type = collInterface;
                }
            }
        }

        return type;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        // Serialize proxies as the base type
        if (obj is INHibernateProxy)
        {
            // Getting the implementation of the proxy forces an initialization of the proxied object (if not yet initialized)
            obj = NHibernateProxyHelper.GetLazyInitializer((INHibernateProxy)obj).GetImplementation();
        }

        // Serialize persistent collections as the collection interface type
        if (obj is IPersistentCollection)
        {
            IPersistentCollection persistentCollection = (IPersistentCollection)obj;
            persistentCollection.ForceInitialization();
            obj = persistentCollection.Entries(); // This returns the "wrapped" collection
        }

        return obj;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        return obj;
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        return null;
    }

    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        return null;
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        return null;
    }

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
    {
        return typeDeclaration;
    }
}

To use this surrogate, simply pass in an instance to the DataContractSerializer constructor:

DataContractSerializer serializer = new DataContractSerializer(typeof(rootObj.GetType()), null, int.MaxValue, false, true, new HibernateDataContractSurrogate());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, rootObj);

Notes:

  • With this technique, you avoid having to translate your Hibernate objects into DTOs before serialization.
  • There's an alternative:  you can use NetDataContractSerializer, however that would assume you've got NHibernate and Castyle.DynamicProxy at the other end of the wire.  It also requires a bit more legwork, as described here.
  • WCF doesn't know about Iesi sets, so you're still on the hook for adding attributes such as [WellKnown(typeof(HasedSet<type>))] to classes that use sets.

Currently rated 5.0 by 11 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET Framework | Hibernate | WCF

Serving embedded resources with WebResource.axd

by timvasil 11/26/2007 1:56:00 PM

If you need to build a URL to an embedded resource and don't have a reference to the Page object to call ClientScript.GetWebResourceUrl, you can use the following:

private static readonly MethodInfo _getWebResourceUrlMethod =
    typeof(ClientScriptManager).GetMethod(
        "GetWebResourceUrl",
        BindingFlags.NonPublic | BindingFlags.Static,
        null,
        new Type[] { typeof(Page), typeof(Type), typeof(string), typeof(bool) }, null);

        /// <summary>
        /// Provides a URL to an embedded resource.
        /// The resource is served with .NET's built in WebResource.axd handler.
        /// You <b>must</b> supply an <c>[assembly: WebResource(resourcePath, mimeType)]
        /// attribute for each resource to be served in this manner.</c>
        /// </summary>
        /// <param name="url">Location of the resource, e.g.
        /// <c>assembly://Assembly.Name/Assembly.Name.Folder1.Folder2/Resource.txt</c>.
        /// The hostname portion specifies the assemby name, and the path specifies the
        /// namespace name and resource name of the resource.</param>
        /// <returns>The external URL to access the embedded resource</returns>
        public static string GetEmbeddedResourceUrl(Uri url)
        {
            if (url == null)
            {
                throw new ArgumentNullException();
            }
            if (url.Scheme != "assembly")
            {
                throw new ArgumentException("Supplied URI must use 'assembly' scheme");
            }
            string assemblyName = url.Host;
            string resourcePath = url.AbsolutePath.Substring(1).Replace('/', '.');
            Assembly resourceAssembly = Assembly.Load(assemblyName);
            return (string)_getWebResourceUrlMethod.Invoke(null,
                   new object[] { null, resourceAssembly.GetTypes()[0], resourcePath, false });
        }

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

ASP.NET | .NET Framework

Parsing HTML tables with regular expressions

by timvasil 11/12/2007 4:04:00 PM

Grabbing the content of rows in an HTML table seemed like a good job for regular expressions.

My first stab was to use a regex that essentially looked like <tr>(.*)</tr>.  Since * is greedy, this didn't work when there were multiple rows in the table; the capture would contain embedded </tr><tr> tags.

I wanted a way to say .*, but for anything but </tr> tags--basically a way to say [^(</tr>)], but of course [^] works with single characters, not for a whole string.  How could I say "not </tr>"?

Enter:  the zero-width negative lookahead assertion, (?!subexpression).  This tells * not to be so greedy.  Combining this with a named capture of "row" it became pretty easy to process data one HTML row at a time:

Regex ex = new Regex("<tr>(?<row>((?!</tr>).)*)</tr>", RegexOptions.Compiled | RegexOptions.Singleline);
int num = ex.Matches("<tr>row1</tr><tr>row2</tr>").Count;

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET Framework | Regex

Changing the case of linked embedded resources

by timvasil 11/2/2007 1:40:00 PM

If you embed a resource in Visual Studio by linking to a file and then want to adjust the case of that link, you have to do it in two places:

Open up the project file and find the link:

<EmbeddedResource Include="..\..\..\..\Yui.zip">
   <
Link>Yui.zip</Link>
</
EmbeddedResource>

Ensure that both instances of the name (in this case "Yui.zip") have the same case.  The text you specify in the "Include" attribute is what shows up in Visual Studio, however the text you specify in the <Link> element becomes the actual name of the embedded resource.  If these two aren't consistent, it'll definitely lead to confusion. Assembly.GetManifestResourceStream is case-sensitive and won't return what you expect unless you get the case right!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET Framework | Visual Studio

Wouldn't Enum generic constraints be nice?

by timvasil 10/31/2007 11:48:00 AM

I wanted to design a utility class that provided some bit manipulation methods for enums with [Flags].  Ideally I wanted to embed these methods directly in the enum definition like I can do in Java, but no such luck in C#.  So the helper class seemed like the next best thing.

Turns out this is pretty hard to do!  You can't build a class with the constraint where T : Enum, for example.  Bill Rodenbaugh comes close in his enum helper class, Enum<T>. 

But when all is said and done, using the helper class doesn't really improve upon readability, efficiency, or even number of characters typed!

Here's a sample using the helper class:

public bool Enabled
{
   
get { return !Enum<MenuItemAttributes>.Flags.IsFlagSet(_attributes, MenuItemAttributes.Disabled); }
   
set { _attributes = Enum<MenuItemAttributes>.Flags.SetOrClearFlag(_attributes, MenuItemAttributes.Disabled, value); }
}

And the alternative--doing bit manipulations directly:

public bool Enabled
{
   
get { return (_attributes & MenuItemAttributes.Disabled) != MenuItemAttributes.Disabled; }
   
set { if (value) _attributes |= ~MenuItemAttributes.Disabled; else _attributes &= MenuItemAttributes.Disabled; }
}

I'm going to stick to manual bit manipulations!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

.NET Framework

 

About the author

Tim Vasil Tim Vasil
I'm a software engineer living in Cambridge, MA.

E-mail me Send mail

Search

Calendar

<<  September 2010  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

Recent comments