Archive

Archive for the ‘Development’ Category

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 4 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:

Memory Leaks in My Planner Web Part

June 12th, 2009 Richard 1 comment

Just spent an evening hunting down and fixing memory leaks in the MLG My Planner web part. The code was opening SPSite and SPWeb objects and then not disposing them. Level 101 error by whoever wrote it!

The layout of the code is a bit bizarre. There’s the main web part project, and 6 other supporting projects, all of which are required by the web part, but not used by another other project. They each only contain 1 or 2 files. This is totally unnecessary and leads to having to ship 6 extra dlls. When I get a bit more time to work on it I’ll have to combine them all into one dll.

My Sql Table Names and Case-Sensitivity

June 9th, 2009 Richard No comments

While implementing the generate quote page for the Learning Gateway Conference I was storing the quote details in a My Sql database. Normally I use Sql Server, but that’s an optional extra on my hosting plan, so I went for MySql which is included, thinking how different can it be. I’d already got had some experience of working with it while integrating with Moodle.

So I had everything up an running nicely on my development server, until I uploaded the code to the live server, then suddenly, bang, the database calls stopped working with the exceptions talking about an invalid query. I finally tracked it down to the case-sensitivity of the table names in MySql. In windows, the table names are case-insensitive, while on Linux the table names are case-sensitive, and my ISP hosts the MySql databases on Linux machines.

The most annoying thing is that I’m normally very careful about case-sensitivity, but didn’t pay attention to it in this specific case. Moral of the story is always be case-sensitive when coding even if you don’t have to be.

Getting SPControls.DateTimeControl to display the local date format

May 29th, 2009 RichardWillis No comments

One of the minor problems with SLK was that on the Assignment Properties page the Start and Due dates were always being shown in US format, no matter what the regional setting were. There was a really simple fix, you just need to set the LocaleId of the DateTimeControl and then it will display the date in the regional format of the site.

                spDateTimeStart.LocaleId = SPWeb.Locale.LCID;
                spDateTimeDue.LocaleId = SPWeb.Locale.LCID;

A version with this fix in is now available on the 1.3.2 build page.

Categories: Development, SLK Tags:

Running IIS application pool as a domain user

March 25th, 2009 RichardWillis 1 comment

Just finished setting up an IIS application pool to run as a domain user. There’s a number of hurdles you have to jump over before it will work.

  1. In local policies, set the account to “Act as part of the operating system”. Administrative Tools | Local Security Settings | Local Policies | User Rights Assignments | Act as part of the operating system
  2. In local policies, set the account to log on as a service.
  3. Give the account Modify permissions on the folders asp.net uses to create it’s temporary files.
Categories: Development Tags:

SharePoint Manager 2007

March 3rd, 2009 RichardWillis No comments

I’ve just come across a great free tool for SharePoint 2007. It’s SharePoint Manager 2007 and is hosted over at CodePlex. It’s quite simply an object model explorer for SharePoint, allowing you to drill down into any detail of SharePoint, from server properties, to web users even down to individual list items. It will even let you modify the properties if you’re feeling brave.

I’ve lost count of all the little console utilities I’ve written to dump things like list fields, view CAML etc, all of which you can browse to with the tool. I think that it’s going to save me a lot of time and increase my knowledge of SharePoint.

Categories: Development, SharePoint Tags:

Finding out if SharePoint Objects are Disposed Correctly

February 27th, 2009 RichardWillis No comments

Everyone should know by now that certain SharePoint objects, including SPSite and SPWeb need to be disposed of when you have finished with them or you will get a memory leak. If you want to refresh your memory have a look at the MSDN white papers Best Practices: Using Disposable Windows SharePoint Services Objects on MSDN and Best Practices: Common Coding Issues When using the SharePoint object model.

What you may not know is that there are a couple of tools/techniques which can help you find areas in your code where you are not disposing of objects correctly.

  1. SPDisposeCheck. This is a tool which will analyze your assemblies to search for coding patterns which lead to objects not being disposed correctly. It’s a great tool and worth running regularly on your assemblies.
  2. SPRequestStackTrace registry value. Creating the registry key

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings
SPRequestStackTrace: DWORD = 1

Will cause the SharePoint runtime to log a stack trace everytime a SPRequest object is not disposed of correctly. This will actually pick up all the types of objects not being disposed of as internally the problem with not disposing of them is that they contain a reference to SPRequest.

At this point I have to say thank you to Jared Kahlil who pointed out a memory leak in the SLK by using the second method above and started my research into both of these methods. Unfortunately we can’t use SPDisposeCheck on SLK as it checks to see if the file name begins with Microsoft and if there are any namespaces beginning with Microsoft, and if so ignores the assembly.

Categories: Development, SLK, SharePoint Tags:

WCF – WSHttpBinding and Clock Skew

January 28th, 2009 RichardWillis 2 comments

I was deploying a WCF service and when testing it started to get the following error:

The security timestamp is invalid because its creation time (’2009-01-28T16:18:26.625Z’) is in the future. Current time is ‘2009-01-28T16:11:40.173Z’ and allowed clock skew is ‘00:05:00′.

A quick search of the internet threw light on what the problem was, by default in WCF the clocks on the client and server have to be within 5 minutes of each other. Now this can be controlled if all the machines involved are on the same network, but as soon as you start having clients on other networks, you will get them with bigger time differences than this. After another bit of searching I found that you can control the size of the allowed clock skew. However, you can’t do this with the WSHttpBinding, you have to create a custom binding.

The problem then is that the documentation about doing this in web.config is pretty poor. With a custom binding you start with nothing about your connection set up and have to build it from scratch, which given the complexity of the possble binding is really difficult. I found several posts in newsgroups asking about it, but for a long time couldn’t find a decent answer. Then I stumbled across http://social.msdn.microsoft.com/forums/en-US/wcf/thread/6554776e-4b05-427f-ad6f-5d72c6579746/ and discovered that you could programmatically create the binding, convert it to a custom binding and save it to a configuration file, which will then contain all the settings you need to duplicate your original binding, but within a custom binding where I could then set maxClockSkew.

The code I used is:

public static void Main(){     //Create the custom binding based on your original binding     WSHttpBinding binding = new WSHttpBinding();     binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;     binding.SendTimeout = new TimeSpan(0, 15, 0);     binding.MaxReceivedMessageSize = 65536000;     CustomBinding custom = new CustomBinding(binding);     //Set up the config file to save     Configuration machineConfig = ConfigurationManager.OpenMachineConfiguration();     ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();     fileMap.ExeConfigFilename = "out.config";     fileMap.MachineConfigFilename = machineConfig.FilePath;     Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);     config.NamespaceDeclared = true;     //Save the binding in the config file     ServiceContractGenerator scg = new ServiceContractGenerator(config);     string sectionName;     string configName;     scg.GenerateBinding(custom, out sectionName, out configName);     config.Save();}So from my original binding specification

<wsHttpBinding>    <binding name="SalamanderBinding" receiveTimeout="00:15:00"            maxReceivedMessageSize="65536000">            <security mode="Message">                <message clientCredentialType="UserName"/>            </security>       <readerQuotas maxArrayLength="65536000"/>     </binding></wsHttpBinding>

I got the following custom binding

<customBinding>    <binding name="SalamanderBinding">        <transactionFlow transactionProtocol="WSAtomicTransactionOctober2004" />        <security defaultAlgorithmSuite="Default" authenticationMode="SecureConversation"            requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"            keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"            messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"            requireSecurityContextCancellation="true" requireSignatureConfirmation="false">            <localClientSettings cacheCookies="true" detectReplays="true"                replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"                replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"                sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="false"                timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />            <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00"                maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"                negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"                sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"                reconnectTransportOnFailure="false" maxPendingSessions="128"                maxCachedCookies="1000" timestampValidityDuration="00:05:00" />            <secureConversationBootstrap defaultAlgorithmSuite="Default"                authenticationMode="UserNameForSslNegotiated" requireDerivedKeys="true"                securityHeaderLayout="Strict" includeTimestamp="true" keyEntropyMode="CombinedEntropy"                messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"                messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"                requireSecurityContextCancellation="true" requireSignatureConfirmation="false">                <localClientSettings cacheCookies="true" detectReplays="true"                    replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"                    replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"                    sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"                    timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />                <localServiceSettings detectReplays="true" issuedCookieLifetime="00:15:00"                    maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"                    negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"                    sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"                    reconnectTransportOnFailure="true" maxPendingSessions="128"                    maxCachedCookies="1000" timestampValidityDuration="00:05:00" />            </secureConversationBootstrap>        </security>        <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"            messageVersion="Default" writeEncoding="utf-8">            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"                maxBytesPerRead="4096" maxNameTableCharCount="16384" />        </textMessageEncoding>        <httpTransport manualAddressing="false" maxBufferPoolSize="524288"            maxReceivedMessageSize="65536000" allowCookies="false" authenticationScheme="Anonymous"            bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"            keepAliveEnabled="true" maxBufferSize="65536000" proxyAuthenticationScheme="Anonymous"            realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"            useDefaultWebProxy="true" />    </binding></customBinding>

and I just needed to change the maxClockSkew values.

You do need to set the clock skew on the client and server sides.

Easy when you know how.

Categories: Development Tags:

Support to Preview Extra File Types in Outlook 2007 or Vista

January 27th, 2009 RichardWillis No comments

If you use Outlook 2007 you probably already know that you can preview attachments from within Outlook. However, the built in support in fairly limited, being restricted to common types like office files, video and audio files.

However, this list is extensible using custom preview handlers. If you search on the internet for Outlook 2007 file previewers there’s a lot of hits. I’ve just downloaded some sample ones from a MSDN magazine article. Now I can preview files such as xml and pdf from within Outlook without saving them to disk and then re-opening them.

There’s more information at My Digital Life.

Windows Explorer in Vista can also take advantage of the same handlers if you turn on the Preview pane under Organize | Layout. I’ve now got this turned on and am finding it really useful as I generally have a lot of xml files which I need a quick look into.

So an example of previewing an xml file in Outlook is:

Categories: Development Tags: