NetInverse Developers Blog

April 4, 2009
Category: .Net — Tags: , , , , — admin @ 5:23 pm

Following utility function EnumToArray takes an enum type and returns an array populated with each enum item. You can tweak the code a little bit to make the function to be EnumToList easily.

The sample code also demonstrates how to use Enumerable.Except to get the delta of two arrays of same type T.

using System;
using System.Collections.Generic;
using System.Linq;

namespace IEnumerableTest
{
    public static class Utils
    {
        public static T[] EnumToArray<T>()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("T must be a System.Enum");
            }
            return (Enum.GetValues(enumType) as IEnumerable<T>).ToArray();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //Convert Enum type to an array
            RoleType[] allRoles = Utils.EnumToArray();

            //Use IEnumerable.Except to get part of the array.
            RoleType[] localUserRoles = new RoleType[] { RoleType.LocalAdmin, RoleType.LocalUser, RoleType.Guest };

            RoleType[] domainUserRoles = allRoles.Except(localUserRoles).ToArray();
        }

        enum RoleType
        {
            DomainAdmin,
            LocalAdmin,
            DomainUser,
            LocalUser,
            Guest
        }
    }
}
April 2, 2009
Category: .Net — Tags: — admin @ 7:17 pm

A good Wiki based online security book.

http://alt.pluralsight.com/wiki/default.aspx/Keith.GuideBook/HomePage.html

March 11, 2009
Category: .Net, Windows API — Tags: , , — admin @ 11:57 pm

Active Directory has a global catalog (GC), which contains a partial replica of all objects in the directory. It also contains partial replicas of the schema and configuration containers. One or more domain controllers in a domain can hold a copy of the global catalog.

The global catalog holds a replica of every object in Active Directory, but with only a small number of their attributes. The attributes in the global catalog are those most frequently used in search operations, such as a user’s first and last names, login names, and so on. The global catalog attributes also include those required to locate a full replica of the object. The global catalog allows users to quickly find objects of interest without knowing what domain
holds them and without requiring a contiguous extended namespace in the enterprise; that is, you can search the entire forest.

The following sample code demonstrates a way to check if a caller is in a perticular security group. It searches the global catalog to obtain the group’s SID(Security Id), and then call CheckTokenMembership to find out if the caller is in that group. It is very useful when a service process need to check a caller’s membership for authentication or authorization.

In real applications, you may need to cache the SIDs of the groups for better performance since searching the global catalog is fast, but not that fast.

using System;
using System.IO;
using System.Text;
using System.Collections;
using System.DirectoryServices;
using System.Security.Principal;
using System.Runtime.InteropServices;

namespace IsInGroup
{
    ///
    /// Summary description for Class1.
    ///
    class Class1
    {
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        static extern int CheckTokenMembership(int TokenHandle, byte[] PSID, out bool IsMember);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        static extern bool IsValidSid(byte[] PSID);

        public static string GetCallerName()
        {
            WindowsPrincipal principal =
                new WindowsPrincipal(WindowsIdentity.GetCurrent());
            return principal.Identity.Name.Split('\\')[1];
        }

        ///
        /// The main entry point for the application.
        ///
        static void Main(string[] args)
        {
            string groupName = "administrators";

            //get current caller's information
            string user = GetCallerName();

            //search global catalog and get SID of the group
            Byte[] sid = null;

            DirectoryEntry entry = new DirectoryEntry("GC:");
            IEnumerator ie = entry.Children.GetEnumerator();
            ie.MoveNext();
            DirectorySearcher ds = new DirectorySearcher((DirectoryEntry)ie.Current);

            string sam = "(sAMAccountName=" + groupName + ")";
            ds.Filter = "(&(|" + sam + ")(objectClass=group))";
            using (SearchResultCollection resColl = ds.FindAll())
            {
                if (resColl.Count > 0)
                {
                    ResultPropertyCollection resultPropColl = resColl[0].Properties;
                    string name = (string)resultPropColl["name"][0];
                    string adsPath = (string)resultPropColl["adspath"][0];
                    sid = (byte[])resultPropColl["objectsid"][0];

                    if (sid == null || !IsValidSid(sid))
                    {
                        System.Console.WriteLine("Invalid SID for the group.");
                        return;
                    }
                    else
                    {
                        System.Console.WriteLine("Group found: " + name);
                        System.Console.WriteLine("Group ADS path: " + adsPath);
                    }
                }
                else
                {
                    System.Console.WriteLine("Required info was not found in the GC.");
                    return;
                }
            }

            bool bIsMember = false;
            if (CheckTokenMembership(0, sid, out bIsMember) == 0)
            {
                System.Console.WriteLine("Failed to call CheckTokenMembership.");
            }
            else
            {
                System.Console.WriteLine(user + (bIsMember ?
                    " is a member of " : " isn't a member of ") + groupName);
            }
        }
    }
}
Category: .Net — Tags: , — admin @ 9:20 pm

NHibernate is an Object-relational mapping (ORM) solution for the Microsoft .NET platform. It is licensed under the GNU Lesser General Public License. It is a port of the popular Java O/R mapper Hibernate to .NET. Version 1.0 mirrors the feature set of Hibernate 2.1, adding a number of features from Hibernate 3. NHibernate 1.2.0, released May of 2007, introduces many more features from Hibernate 3 and support for .NET 2.0, stored procedures, generics and nullable types.

  1. All classes and collections with 1.2 are now loaded lazily by default. You may need to change lazy=”false”, or make methods be virtual.
  2. Use .Net 2.0 Generics for all collection interfaces (You no longer have to use the NHibernate.Generics compatability library).
  3. Support Batching for SQL Server - huge perforamance increase in some scenarios.
  4. Support Stored Procedures.
  5. Support named connection strings.
  6. Support SQL Server 2005 and SQL Server 2005 Everywhere dialects.
  7. Support Parametrized types and User Collection Types.
  8. Support projections in criteria queries, i.e. CreateCriteria(typeof(T)).Count(), and CreateCriteria(typeof(T)).Max(…), etc.
  9. New IL-based reflection optimizer - another big performance boost.
  10. Use SetProjection(Projections.Count(”ID”)) instead of IQuery’s Select count(*).
  11. New DetachedCriteria
  12. New GetCurrentSession method of SessionFactory: SessionFactory.GetCurrentSession()

You can click here to check out a list of .Net ORM products.

March 9, 2009
Category: .Net, Design Pattern — Tags: , — admin @ 8:18 pm

A typicaly Singleton implementation in C# looks like below:

    using System;

    public sealed class Singleton
    {
       private static volatile Singleton instance;
       private static object syncRoot = new Object();

       private Singleton() {}

       public static Singleton Instance
       {
          get
          {
             if (instance == null)
             {
                lock (syncRoot)
                {
                   if (instance == null)
                      instance = new Singleton();
                }
             }

             return instance;
          }
       }
    }

[MSDN]This approach ensures that only one instance is created and only when the instance is needed. Also, the variable is declared to be volatile to ensure that assignment to the instance variable completes before the instance variable can be accessed. Lastly, this approach uses a syncRoot instance to lock on, rather than locking on the type itself, to avoid deadlocks. This double-check locking approach solves the thread concurrency problems while avoiding an exclusive lock in every call to the Instance property method. It also allows you to delay instantiation until the object is first accessed.

Above solution looks perfect, however, actually the ‘Double-Checked Locking’ can be still broken under certain multi-processor machine. A recommended way to implement Singleton correctly is below:

    public sealed class Singleton
    {
        Singleton(){}
        public static Singleton Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        static class Nested
        {
            internal static readonly Singleton instance = new Singleton();
        }
    }

Above code looks weird, but correct. It leverages .Net’s Class Loader to achieve thread-safe.

Category: .Net, Build — Tags: — admin @ 7:59 pm

It is very common that you need to run some commands on a remote server. For example, you may want to config your source control server to start a build process on a dedicated build machine once it receives any checkins. To achieve this, you can leverage the WMI scripting APIs.

The steps are:

  1. Use SWbemLocator to create Locator object
  2. Use the Locator object to connect to the remote server and get back a Service object
  3. Use the Service object to get a Win32 process object
  4. Finally, use the Process object to issue your command

WMI WbemScripting script sample:

    Function RemoteExecute(strServer, strUser, strPassword, CmdLine)
        Const Impersonate = 3

        RemoteExecute = -1

        Set Locator = CreateObject("WbemScripting.SWbemLocator")
        Set Service = Locator.ConnectServer(strServer, "root\cimv2", strUser, strPassword)

        Service.Security_.ImpersonationLevel = Impersonate
        Set Process = Service.Get("Win32_Process")

        result = Process.Create(CmdLine, , , ProcessId)

        If (result <> 0) Then
            WScript.Echo "Creating Remote Process Failed: " & result
            Wscript.Quit
        End If

        RemoteExecute = ProcessId
    End Function

NAnt is very popular in the .Net development community. You may want to write a C# extension for NAnt scripts to achieve some build automations on remote servers. You can achieve that easily too. I am posting a WMI C# sample below for your reference too.

WMI C# sample:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Management;

    namespace WMISample
    {
        class Program
        {
            static void Main(string[] args)
            {
                string remoteMachine = "localhost";

                ConnectionOptions connOptions = new ConnectionOptions();
                connOptions.Impersonation = ImpersonationLevel.Impersonate;
                connOptions.EnablePrivileges = true;

                ManagementScope manScope = new ManagementScope(
                    String.Format(@"\\{0}\ROOT\CIMV2", remoteMachine), connOptions);
                manScope.Connect();

                ObjectGetOptions objectGetOptions = new ObjectGetOptions();
                ManagementPath managementPath = new ManagementPath("Win32_Process");
                ManagementClass processClass = new ManagementClass(
                    manScope, managementPath, objectGetOptions);

                ManagementBaseObject inParams = processClass.GetMethodParameters("Create");

                inParams["CommandLine"] = @"notepad.exe";
                ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);

                Console.WriteLine("Creation of the process returned: " + outParams["returnValue"]);
                Console.WriteLine("Process ID: " + outParams["processId"]);
                Console.ReadLine();
            }
        }
    }
Category: .Net, ASP.Net — Tags: , , , — admin @ 7:30 pm

An ASP.Net applicatin may return an “Access Denied” error when it is accessing the Eventlog.

If it is not a GPO permission issue from your domain controller, you may need to check the SDDL string specified in the registry for the EventLog.

For example, if the identity of the App pool is the “Network service” account, “impersonation” in the web.config is true and authentication is enabled, you may need to add a WRITE access (A;;0×2;;;AU) for the authenticated users to the following registry key.

HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Application\CustomSD

(A;;0x2;;;AU)   Note: AU means "Authenticated Users"

Similarly, you can grant permissions for the “Network service” account.

(A;;0x2;;;NS)   Note: NS means "Network service" account

What (A;;0×2;;;AU) is? You can check out Microsoft’s SDDL (Security Descriptor Definition Language) on MSDN.

Windows 2008 is much easier as long as you are ok giving the user/group read access to all event logs. If that is the case just add them to the Built in Event Log Readers group.

The location on the SDDL has changed in Windows 2008 and is no longer set it via the CustomSD in the registry. You now have to use the command line wevtutil utility.

 

Category: .Net — Tags: , , , , — admin @ 7:15 pm

The code is very simple. You just need to use DirectoryEntry object to locate the local group and the domain user. Then invoke an “Add” operation on the local group object.

public class AdUtil
{
    public static void AddDomainUserToLocalGroup(
        String domain,
        String userName,
        String groupName)
    {
        String groupPath = String.Format("WinNT://{0}/{1},group",
            Environment.MachineName, groupName);
        DirectoryEntry theGroup = new DirectoryEntry(groupPath);

        if (theGroup.SchemaClassName != "Group")
        {
            throw new ArgumentException("The local group specified doesn't exist.");
        } 

        String userPath = String.Format("WinNT://{0}/{1},user", domain, userName);
        theGroup.Invoke("Add", new object[] { userPath });
        theGroup.CommitChanges();
    }
}
Category: .Net — Tags: , , — admin @ 12:16 am

Following code doesn’t compile:

    class GenericFactory where T : new()
    {
        public T Create(object a, object b)
        {
            return new T(a, b);
        }
    }

The compiler will give you following error message: “‘T’: cannot provide arguments when creating an instance of a variable type.”. Well, there are a couple ways to solve this issue.

Use reflection

    class GenericFactory
    {
        public T Create(object a, object b)
        {

            return (T) typeof(T).GetConstructor(
   new System.Type[] { typeof(object), typeof(object) }).Invoke(new object[] {a, b});
        }
    }

Use intialization

Following code uses an initialization interface to solve this issue. You can also use properties instead of a method.

    interface I
    {
        void Initialize(object a, object b);
    }

    class GenericFactory where T : I, new()
    {
        public T Create(object a, object b)
        {
            T t = new T();
            t.Initialize(a, b);
            return t;
        }
    }
Category: .Net — Tags: , — admin @ 12:12 am

In case you see following error, you can bypass the .Net Strong name verification. 

Unhandled Exception: System.IO.FileLoadException: Could not load file
or assembly 'FunkyProg, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' or one of its dependencies.
Strong name validation failed. (Exception from HRESULT: 0x8013141A)

File name: 'FunkyProg, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' ---> System.Security.SecurityException:
Strong name validation failed. (Exception from HRESULT: 0x8013141A)

The Zone of the assembly that failed was:

MyComputer

You can use sn.exe to register <assembly> for verification skipping.

 sn -Vr <assembly> [<userlist>] [<infile>]

Or you can add following entry to the registry(you need to put the right public key token value).

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification\*,b77a5c561934e089]

b77a5c561934e08 is the PublicKeyToken for the assembly.

« Newer PostsOlder Posts »

©2009 NetInverse. All rights reserved. Powered by WordPress