Programmatically set IIS Authentication for a page.

To use Mixed Windows Authentication one of the step is to set set authentication on one page only to be Windows Integrated, but not “allow anonymous”.(see instructions here and here). I wanted to do it from Web Setup Project. So I've created the class IISMetaDataHelper with the method SetIntegratedSecurityOnly Sample of the call is  IISMetaDataHelper.SetIntegratedSecurityOnly(Site, VDir, "Admin/Security/WinLogin.aspx")

Notice that.Net framework doesn't have classes to handle IISMetaData properties and enum for AuthFlags property value. I've created those helper types as well.

Update: to call folderRoot.RefreshCache to make EVERYTHING work

using System;

using System.Collections;

using System.Collections.Generic;

using System.Text;

using System.Xml;

using System.DirectoryServices;

using System.Diagnostics;

using System.IO;

using System.Reflection;

//using FSHelperLib;

namespace FSCSharpLib.IISMetadata

{

    ///

    //see also IISChameleon.INETMGRHelper

    /// Helper methods to access IIS Virtual directories

    ///

    /// Code samples used are from ASP.NET IIS Chameleon Tool(http://www.123aspx.com/redir.aspx?res=33760 and

    /// Creating Virtuals and reading Installed Sites on IIS with.Net(http://west-wind.com/weblog/posts/399.aspx )   

    public class IISMetaDataHelper

    {

        //For debugginh it is convinient to use adsutil.vbs http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/d3df4bc9-0954-459a-b5e6-7a8bc462960c.mspx

        /*e.g commands

        C:\Inetpub\AdminScripts\Cscript.exe adsutil.vbs ENUM  W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        C:\Inetpub\AdminScripts\Cscript.exe adsutil.vbs CREATE  W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        C:\Inetpub\AdminScripts\Cscript.exe adsutil.vbs SET W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx/keyType IISWebFile

        C:\Inetpub\AdminScripts\Cscript.exe adsutil.vbs delete  W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        */

        ///

        /// Concat parts of the path using Site Path in format @"/LM/W3SVC/1" passed by Web Setup to path accepted by DirectoryEntry

        ///

        /// Format @"/LM/W3SVC/1"

        /// e.g vKnowledge

        /// e.g @"admin/Security/WinLogin.aspx"

        /// e.g IIS://localhost/W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        public static void SetIntegratedSecurityOnly(string SiteMetaPath, String VDirRoot, String relPath)

        {

            string MetabasePath = IISMetaPath(SiteMetaPath, VDirRoot, relPath);

            SetIntegratedSecurityOnly(MetabasePath);

        }

        ///

        /// Concat parts of the path using Site Path in format @"/LM/W3SVC/1" passed by Web Setup to path accepted by DirectoryEntry

        ///

        /// Format @"/LM/W3SVC/1"

        /// e.g vKnowledge

        /// e.g @"admin/Security/WinLogin.aspx"

        /// e.g IIS://localhost/W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        public static string IISMetaPath(string SiteMetaPath, String VDirRoot, String relPath)

        {

            SiteMetaPath = SiteMetaPath.Replace(@"/LM/", "localhost/");

            return @"IIS://" + SiteMetaPath + @"/root/" + VDirRoot + @"/" + relPath;

        }

        ///

        /// SetIntegratedSecurityOnly

        ///

        /// e.g IIS://localhost/W3SVC/1/root/vKnowledge/admin/Security/WinLogin.aspx

        public static void SetIntegratedSecurityOnly(string MetabasePath)

        {

            if (MetabasePath!= string.Empty)

            {

                DirectoryEntry entry = null;

                if (!DirectoryEntry.Exists(MetabasePath))

                {   //Usually files are not  explicitly added to the IIS metabase

                    //See http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic12899.aspx

                    string sFolderPath = StringHelper.LeftBeforeLast(MetabasePath, @"/");//metabasePath.Substring(0,metabasePath.LastIndexOf("/"));

                    string sEntryName = StringHelper.RightAfterLast(MetabasePath, @"/");// metabasePath.Substring(metabasePath.LastIndexOf("/") + 1);

                    DirectoryEntry folder = new DirectoryEntry(sFolderPath);

                    DebugHelper.PrintDirectoryEntryProperties(folder, sFolderPath);

                    //SchemaClassNames are listed in http://blog.crowe.co.nz/archive/2006/06/01.aspx

                    string SchemaClassName = "IIsObject";

                    //can't assign "IIsWebFile" directly, causes HRESULT: 0x8000500F exception. E_ADS_SCHEMA_VIOLATION - The attempted action violates the directory service schema rules".

                // see http://groups.google.com.au/group/microsoft.public.adsi.general/browse\_frm/thread/3b339d218e673aca/050974e5903530e3 

                    entry = folder.Children.Add(sEntryName, SchemaClassName);

//Fortunately ADSUTIL shows the WARNING: The Object Type of this object was not specified or was specified as IIsObject.

//This means that you will not be able to set or get properties on the object until the KeyType property is set.

                    entry.Properties[MetabasePropertyNames.keyType].Value = "IIsWebFile";

                    folder.CommitChanges;

                    entry.CommitChanges;

                }

                //must be created as new, even if entry was just created using Children.Add

                entry = new DirectoryEntry(MetabasePath);

                DebugHelper.PrintDirectoryEntryProperties(entry, MetabasePath);

                AuthFlags nAuthFlags =  (AuthFlags)(entry.Properties[MetabasePropertyNames.AuthFlags][0]);

                nAuthFlags = nAuthFlags & ~AuthFlags.AuthAnonymous; //clear anonymous

                nAuthFlags = nAuthFlags | AuthFlags.AuthNTLM; //Add Integrated

                entry.Properties[MetabasePropertyNames.AuthFlags][0] = nAuthFlags;

                // Chameleon sets Properties["AuthNTLM"] and ["AuthAnonymous"] -does it work?

                 //virtualDirectory.Properties["AuthNTLM"][0] = parametros.AuthNTLM;

                 //virtualDirectory.Properties["AuthAnonymous"][0] = parametros.AuthAnonymous;

                entry.CommitChanges;

             }

        }

    }//class

    public class MetabasePropertyNames

    {// from http://technet2.microsoft.com/WindowsServer/en/Library/271ae19b-853f-4672-b743-5ba126e902db1033.mspx?mfr=true

        //TODO add all Properties

     public const string AuthFlags = "AuthFlags";

     public const string keyType = "keyType";

 }

    [FlagsAttribute]

    public enum AuthFlags

    {//from http://technet2.microsoft.com/WindowsServer/en/Library/271ae19b-853f-4672-b743-5ba126e902db1033.mspx?mfr=true

        AuthAnonymous=1,

        AuthBasic=2,

        AuthNTLM = 4,

        AuthMD5 = 16,

        AuthPassport=64

    }

    //Possible exceptions from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/generic\_adsi\_error\_codes.asp

    // 0x80005006 - The property does not exist, or it does not exist at the access location where you are attempting to set it.

    //0x8000500C-The data type of the property is different than the data type to which you are attempting to set it.

    //0x8000500F exception. E_ADS_SCHEMA_VIOLATION - The attempted action violates the directory service schema rules".  

}

The class uses my DebugHelper class and My StringHelper class

.

This article is part of the GWB Archives. Original Author: Michael Freidgeim

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.