Archive

Archive for October, 2009

Setting the Owner of Files and Directories in C#

October 21st, 2009 Richard No comments

I recently had a requirement to set the owners of users home directories on a Windows server. The .Net framework has built-in support for this so it simply looked like a case of doing this:

IdentityReference owner = new NTAccount("MYDOMAIN\\MyUser");
DirectoryInfo directory = new DirectoryInfo("c:\\myDirectory");
DirectorySecurity directorySecurity = directory.GetAccessControl();
directorySecurity.SetOwner(owner);
directory.SetAccessControl(directorySecurity);

However, when I tried this I just got an InvalidOperationException with the message "The security identifier is not allowed to be the owner of this object".

It turns out that the reason for this is that normally you are only allowed to take ownership yourself, and not assign it. For a user to take ownership they must either have been given the Take Ownership permission or be an administrator.

There is one exception to this rule, and that is if the user has the Restore files and directories privilege then they can assign ownership to other users. Now administrators have this privilege, but by default it is disabled. More details on this from Microsoft.

So to set the owner of the file, you need to have the Restore Files and Directories privilege and then enable it before setting the owner. Really we should also disable the privilege when we’ve finished using it as well.

Unfortunately .Net doesn’t have built in support for this yet, so we are reduced to PInvoking native methods and here’s the code:

sealed class UnmanagedCode
{
    [DllImport("kernel32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);

    // Use this signature if you do not want the previous state
    [DllImport("advapi32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
        [MarshalAs(UnmanagedType.Bool)]bool disableAllPrivileges,
        ref TOKEN_PRIVILEGES newState,
        UInt32 bufferLength,
        IntPtr previousState,
        IntPtr returnLength);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    static extern bool OpenProcessToken
        (IntPtr processHandle, int desiredAccess, ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LookupPrivilegeValue
            (string host, string name, ref LUID lpLuid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct TOKEN_PRIVILEGES
    {
        public UInt32 PrivilegeCount;
        public LUID Luid;
        public UInt32 Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
       public uint LowPart;
       public int HighPart;
    }

    const int SE_PRIVILEGE_ENABLED = 0x00000002;
    const int TOKEN_QUERY = 0x00000008;
    const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
    const string SE_RESTORE_PRIVILEGE = "SeRestorePrivilege"; 

    public static void GiveRestorePrivilege()
    {
        TOKEN_PRIVILEGES tokenPrivileges;
        tokenPrivileges.PrivilegeCount = 1;
        tokenPrivileges.Luid = new LUID();
        tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED;

        IntPtr tokenHandle = RetrieveProcessToken();

        try
        {
            bool success = LookupPrivilegeValue
                        (null, SE_RESTORE_PRIVILEGE, ref tokenPrivileges.Luid);
            if (success == false)
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Exception(
                    string.Format("Could not find privilege {0}. Error {1}",
                                        SE_RESTORE_PRIVILEGE, lastError));
            }

            success = AdjustTokenPrivileges(
                                                tokenHandle, false,
                                                ref tokenPrivileges, 0,
                                                IntPtr.Zero, IntPtr.Zero);
            if (success == false)
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Exception(
                    string.Format("Could not assign privilege {0}. Error {1}",
                                    SE_RESTORE_PRIVILEGE, lastError));
            }
        }
        finally
        {
            CloseHandle(tokenHandle);
        }

    }

    static IntPtr RetrieveProcessToken()
    {
        IntPtr processHandle = GetCurrentProcess();
        IntPtr tokenHandle = IntPtr.Zero;
        bool success = OpenProcessToken(processHandle,
                                        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                                        ref tokenHandle);
        if (success == false)
        {
            int lastError = Marshal.GetLastWin32Error();
            throw new Exception(
                string.Format("Could not retrieve process token. Error {0}",
                                    lastError));
        }
        return tokenHandle;
    }
}

To remove the privilege you will just need to replace SE_PRIVILEGE_ENABLED with the disabled value. In my use I’m just setting the owner and finishing the process so it’s not really required.

Categories: Development Tags:

How to Mock HttpWebRequest when Unit Testing

October 18th, 2009 Richard 9 comments

One of our latest products interacts with a Restful web service. As this is the core part of its functionality as part of Test Driven Development and Unit Testing I needed to be able to test the calls to the web service using HttpWebRequest.

A quick Google didn’t come up with anything so I started looking at the best way to mock the calls. My initial thought was to extract all use of HttpWebRequest into a separate class, define an interface for setting the request and getting the response and use Dependency Injection to determine whether to use the ‘normal’ class or a mock.

Then I looked a bit closer at WebRequest.Create which is the method you use to create a HttpWebRequest. I noticed that it uses a Factory Method so you could actually register your own factory object depending on the url used. So without any extra code required in the class under test, you can register your factory object and the .Net Framework will automatically use your mocks or stubs. This is pretty cool.

To take advantage of this you need to implement the IWebRequestCreate interface on your factory object, and then register your factory object with WebRequest.RegisterPrefix. What you do in the Create method is up to you, but I created a simple WebRequest and WebResponse pair which store the request for you to test the input, and which returns a configurable response.

First an example of how you can use these:

string response = "my response string here";
WebRequest.RegisterPrefix("test", new TestWebRequestCreate());
TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response);

string url = "test://MyUrl";

ObjectUnderTest myObject = new ObjectUnderTest();
myObject.Url = url;
// DoStuff call the url with a request and then processes the
// response as set above
myObject.DoStuff();

string requestContent = request.ContentAsString();
Assert.AreEqual(expectedRequestContent, requestContent);

The code for these 3 objects is:

/// <summary>A web request creator for unit testing.</summary>
class TestWebRequestCreate : IWebRequestCreate
{
    static WebRequest nextRequest;
    static object lockObject = new object();

    static public WebRequest NextRequest
    {
        get { return nextRequest ;}
        set
        {
            lock (lockObject)
            {
                nextRequest = value;
            }
        }
    }

    /// <summary>See <see cref="IWebRequestCreate.Create"/>.</summary>
    public WebRequest Create(Uri uri)
    {
        return nextRequest;
    }

    /// <summary>Utility method for creating a TestWebRequest and setting
    /// it to be the next WebRequest to use.</summary>
    /// <param name="response">The response the TestWebRequest will return.</param>
    public static TestWebRequest CreateTestRequest(string response)
    {
        TestWebRequest request = new TestWebRequest(response);
        NextRequest = request;
        return request;
    }
}

class TestWebRequest : WebRequest
{
    MemoryStream requestStream = new MemoryStream();
    MemoryStream responseStream;

    public override string Method { get; set; }
    public override string ContentType { get; set; }
    public override long ContentLength { get; set; }

    /// <summary>Initializes a new instance of <see cref="TestWebRequest"/>
    /// with the response to return.</summary>
    public TestWebRequest(string response)
    {
        responseStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(response));
    }

    /// <summary>Returns the request contents as a string.</summary>
    public string ContentAsString()
    {
        return System.Text.Encoding.UTF8.GetString(requestStream.ToArray());
    }

    /// <summary>See <see cref="WebRequest.GetRequestStream"/>.</summary>
    public override Stream GetRequestStream()
    {
        return requestStream;
    }

    /// <summary>See <see cref="WebRequest.GetResponse"/>.</summary>
    public override WebResponse GetResponse()
    {
        return new TestWebReponse(responseStream);
    }
}

class TestWebReponse : WebResponse
{
    Stream responseStream;

    /// <summary>Initializes a new instance of <see cref="TestWebReponse"/>
    /// with the response stream to return.</summary>
    public TestWebReponse(Stream responseStream)
    {
        this.responseStream = responseStream;
    }

    /// <summary>See <see cref="WebResponse.GetResponseStream"/>.</summary>
    public override Stream GetResponseStream()
    {
        return responseStream;
    }
}

This is quite a simple implementation, just to check the request and return a known response. Once you’ve got this working, you can obviously do more tests such as simulating error conditions.

Categories: Development, Unit Testing Tags:

New Product – Salamander MoodleRooms

October 18th, 2009 Richard No comments

I’m pleased to announce that we’ve got a new product in our line-up, Salamander MoodleRooms. This allows integration between School Management Systems and the MoodleRooms hosted Moodle solution.

So whether you are using Sims, Facility CMIS, Integris, Phoenix or any of the other main systems, we can now automatically maintain users and courses in your hosted Moodle as they change in your MIS.

On a technical level, we using MoodleRooms’ system integration tool (UIB) over https to send the changes up to MoodleRooms.

Categories: Uncategorized Tags: