Securing WCF Service with Self Signed Certificates programmatically

I’ve spent some time to deal with WCF securing with certificates and came to a solution that I want to share.

As you probably know, WCF supports certificate authentication and it’s not so hard to set up. However you will need to install certificates on both the service machine and the caller machine. This can be a problem if you want to host the service on a shared hosting environment for example. Even if the service is hosted on a machine in your network you will still need some permissions to be given to the service application pool user in order to access the certificate private key.So with the help of this blog post I found a way to create Self Signed certificate using some windows native methods.

using System;
using System.Runtime.InteropServices;

namespace Certificate.Native
{
    internal static class NativeMethods
    {
        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool FileTimeToSystemTime(
            [In] ref long fileTime,
            out SystemTime systemTime);

        [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptAcquireContextW(
            out IntPtr providerContext,
            [MarshalAs(UnmanagedType.LPWStr)] string container,
            [MarshalAs(UnmanagedType.LPWStr)] string provider,
            int providerType,
            int flags);

        [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptReleaseContext(
            IntPtr providerContext,
            int flags);

        [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptGenKey(
            IntPtr providerContext,
            int algorithmId,
            int flags,
            out IntPtr cryptKeyHandle);

        [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CryptDestroyKey(
            IntPtr cryptKeyHandle);

        [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
        public static extern IntPtr CertCreateSelfSignCertificate(
            IntPtr providerHandle,
            [In] ref CryptoApiBlob subjectIssuerBlob,
            int flags,
            [In] ref CryptKeyProviderInformation keyProviderInformation,
            IntPtr signatureAlgorithm,
            [In] ref SystemTime startTime,
            [In] ref SystemTime endTime,
            IntPtr extensions);

        [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CertFreeCertificateContext(
            IntPtr certificateContext);
    }
}

I have created CertificateSerializer to serialize the certificate to base64string:

using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
namespace Certificate
{
    public class CertificateSerializer
    {
        public X509Certificate2 Deserialize(string certificateString)
        {
            byte[] numArray = Convert.FromBase64String(certificateString);
            string tempFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            try
            {
                File.WriteAllBytes(tempFileName, numArray);
                X509Certificate2 certificate = new X509Certificate2(tempFileName, default(string), X509KeyStorageFlags.Exportable);
                return certificate;
            }
            finally
            {
                File.Delete(tempFileName);
            }
        }

        public string Serialize(X509Certificate2 certificate)
        {
            byte[] numArray = certificate.Export(X509ContentType.Pfx);
            string base64String = Convert.ToBase64String(numArray);

            return base64String;
        }
    }
}

In the configuration section we can store the serialized certificate and the Thumbprints and Subjects of the trusted certificates, so that we can give the service the information about the trusted parties. Here’s an example of the custom section content:

    <configSections>
        <section name="certificateSection" type="Certificate.Configuration.CertificatesSection, Certificate"/>
    </configSections>
    <certificateSection certificate="MIIExgIBAzCCBIYGCSqGSIb3DQEHAaCCBHcEggRzMIIEbzCCApgGCSqGSIb3DQEHAaCCAokEggKFMIICgTCCAn0GCyqGSIb3DQEMCgECoIIBjjCCAYowHAYKKoZIhvcNAQwBAzAOBAgbm3IPSqU0BQICB9AEggFojvCBmeSJ6n4IlKxgSv1XgIB5LaD7tb06f/yTLsZRK+4rnqCaesmYFFHP889JTySdqPPyE6fNrpFXTcvcRC6lQQglLnxbRZQotPHvDv4MEzEdI67zkkfM7RsxxXRUQE+ex5H+oQxjScvVRWlKa0KXLk7DOa+Ijz/epLFCum2CE2aUE/AOdi8GCYf7D0yMa472/buQRX1qWX5MYuH+sZI1py/unS8R5R4cytRr8dKJHmn3YtLuhEwQOuXiQ/mUK5PKj+xYp6b8ssVIXQjuLpXZnnT7i/KdZipxmTCf+OtXbAysBw2VaQ9+NmR8cufy8nUb/KgSNfcE3hTHTxIaBnhddhuHxvfR5oYIAzPK3NTq/S1qCEqxDJnBFapdnRcKfHEAlDwIB/KZyHgKdVBiu16pB9e+bxl840CW6vI/tILBbpww3rjvzKKQYZZ6uPu1oNLS2TeX7JsBJE3p0HJE2DPFLfmXLPVPSkHBMYHbMBMGCSqGSIb3DQEJFTEGBAQBAAAAMFcGCSqGSIb3DQEJFDFKHkgAZgAzADEAMwBlADQAYQA4AC0AMAA2ADMANwAtADQANAA1ADAALQBiAGMANAA5AC0AMwA2AGEAMABkAGIAOQAxADkAOABhAGQwawYJKwYBBAGCNxEBMV4eXABNAGkAYwByAG8AcwBvAGYAdAAgAEUAbgBoAGEAbgBjAGUAZAAgAEMAcgB5AHAAdABvAGcAcgBhAHAAaABpAGMAIABQAHIAbwB2AGkAZABlAHIAIAB2ADEALgAwMIIBzwYJKoZIhvcNAQcGoIIBwDCCAbwCAQAwggG1BgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBBjAOBAjWmEM3BmtPWwICB9CAggGIIxS2KaegZ8TDfdq1AP55giyOzgLOvd1LYA5M1QwRmYcM4IiJe5Z6yB6usrnMa/oAJ6suBw72UTO8lTGc/AXWtbrJg6KM0CuyI7lKdoShn36FRx35djx5plXpDxVrZtR2MbOxgSdUNyUCiuRWe/FUzpwE93IWQnfIleeziH1YXuZdvxy/vTLKT2VngeZh3BjyG25n7Fj44xgy7CQM/g/q+TgHBJjnY9qD36kPdaWxkxytadpJH3GgnKLjoQCvHhFN6NEVhErnvzZo63jPZIDWHxr7EYGkbVTzwtPwlocTDgm75gS/IwCMNdAxHP9ofMM4H+2g/UV88R4ABgUoP139Drz5LrfHFsnvPx3/twygMX6lUccnwyKZTVcphjADHU6FVsm2/xJ/nqxCkiUt7ciz150FqGxJ+vxg5zo533eHjViwdDBHTMIopyypOY69xNfN1VGPMKxfc/d5z6ayKKpi9lXQMIUumoz5Xqjnq4dyschqoUbGNW1LB+0Y3BNHxeXyGlYsTsr9nYowNzAfMAcGBSsOAwIaBBRgiHbVQmQbvNqXli2R3sBoa6AirAQUeAWzhwSRejw9yMIGB2GgBY76bbM=">
        <trustedCertificates>
            <certificateInfo thumbprint="64123DFA95F03AFB818EC61C874241B62E2A4886" subject="ServiceCertificate"/>
        </trustedCertificates>
    </certificateSection>

I have created a small windows application for generating certificates and getting it’s serialized value and thumbprint:

Now we will create a custom service behavior extension to take care of the service credentials:

using System;
using System.ServiceModel.Configuration;

namespace Certificate.Extensions
{
    public class CertificateExtensionBehavior : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(CertificateServiceCredentials); }
        }

        protected override object CreateBehavior()
        {
            return new CertificateServiceCredentials();
        }
    }
}

Here is the CertificateServiceCredentials class which inherits from ServiceCredentials:

using System.Configuration;
using System.Configuration;
using System.Linq;
using System.ServiceModel.Description;
using Certificate.Configuration;

namespace Certificate.Extensions
{
    public class CertificateServiceCredentials : ServiceCredentials
    {
        public CertificateServiceCredentials()
        {
            //get the information from our custom configuration section
            CertificatesSection certificateSection = (CertificatesSection)ConfigurationManager.GetSection("certificateSection");
            var trustedList = certificateSection.TrustedCertificates.Cast<TrustedCertificateInfo>().Select(x => x.Thumbprint);

            this.ServiceCertificate.Certificate = certificateSection.Certificate;
            //we use custom validation mode to check the response
            this.ClientCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.Custom;
            //and custom validator to validate if the response's certificate thumbprint is in the trusted thumbprints
            this.ClientCertificate.Authentication.CustomCertificateValidator =
                new CertificateValidator(trustedList);
        }

        protected override ServiceCredentials CloneCore()
        {
            return new CertificateServiceCredentials();
        }
    }
}

We use a custom certificate validation mode with Certificate validator who checks if the certificate in the response is in the current certificate trusted list. We get the certificate and the trusted list from our custom configuration section. And here’s the CertificateValidator:

using System;
using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Security;

namespace Certificate
{
    public class CertificateValidator : X509CertificateValidator
    {
        private readonly IEnumerable<string> trustedThumbprints;

        public CertificateValidator(IEnumerable<string> thumbprints)
        {
            this.trustedThumbprints = thumbprints;
        }

        public override void Validate(X509Certificate2 certificate)
        {
            //check if there is a certificate in the request
            if (certificate == null)
            {
                throw new SecurityException("Missing certificate");
            }
            //check if the certificate thumbprint is in the list of the trusted ones
            if (!trustedThumbprints.Any(thumbprint => thumbprint.Equals(certificate.Thumbprint)))
            {
                throw new SecurityException("The provided certificate is not trusted!");
            }
        }
    }
}

So after that we need to set the service to use this custom extension, so the web.config of the service should look like this:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="certificateSection" type="Certificate.Configuration.CertificatesSection, Certificate"/>
  </configSections>
  <certificateSection certificate="MIIExgIBAzCCBIYGCSqGSIb3DQEHAaCCBHcEggRzMIIEbzCCApgGCSqGSIb3DQEHAaCCAokEggKFMIICgTCCAn0GCyqGSIb3DQEMCgECoIIBjjCCAYowHAYKKoZIhvcNAQwBAzAOBAiqwSbxN4Q2IQICB9AEggFoaa40+yIrF2Wb3/L4rYE7UpzrhI5S2O8wx72gj41tudES+QiM8DGxC1YWaHx4+THXFkQs62A6eDTKYOZUc8oMUFyVbY70Joq8un6keunCz4xP26MB2vygpx1/ASA6CTdeN3r9JEYss7DGaFnvUJKPH44oyBagaecT3fo0CA+Qa7vfcrlrhcyyovVs5lfJNUm13IF8/bNMCcOdgUnjX/tlay53YDulZSD0kP3apd60zzBAtIr2GD/h3NjiIcjSauDUf7bdvEV0LHAC78mRB/6nUaYiwZhAphky8ufR3dMzZGt5bglbEb8WkEw4bh/qrUxofA5uDmRgjnusAVtOcm0BUvK458bzsyKaRwuw8wSK+Srii5ZYjE5DSTc3msu5jCKZ5pC03w8tdeXmc5Xqq5TziKpDXW1bCa9D/O8mRnz+IsRa1FirDV/Spp37wyucLJkluKHZTpOeTWXRGy1/8Ys5kDxeXAamJxSLMYHbMBMGCSqGSIb3DQEJFTEGBAQBAAAAMFcGCSqGSIb3DQEJFDFKHkgAZAAzADAAMwBkADQAZgA2AC0AYQBmADAANQAtADQANwBjAGUALQBiAGIAZgBjAC0AMwBhAGMANQBlADgAYQBiAGUAOAA3ADcwawYJKwYBBAGCNxEBMV4eXABNAGkAYwByAG8AcwBvAGYAdAAgAEUAbgBoAGEAbgBjAGUAZAAgAEMAcgB5AHAAdABvAGcAcgBhAHAAaABpAGMAIABQAHIAbwB2AGkAZABlAHIAIAB2ADEALgAwMIIBzwYJKoZIhvcNAQcGoIIBwDCCAbwCAQAwggG1BgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBBjAOBAgatfFYOA+7qAICB9CAggGIOL+SmdG5n6oummdHrr7u0LH7+VwF3rICFqQTncXX9iVTND6DXJArJfFsYGs1fwq4mzTxmrpBArsf0pCht37x5m7m9k/JL/LeXWlh5re+tZptnEl/l/45AUvN3/fMzoaG4rD5keA1POOoir9fVTiiJjvPfIYvriI8siMwx13fyuFYNZlF+T1pkR6WQbRKTYS49nSGxhIgsoUkxXkGm64CRgXRriHqhopDqUmzCgHhE68jjt78Ff9iYl/1KYBvpJfgBTnvV0dNcXcHhmOkOLqHA6ONBFeARH6ous1i2AUoXfTVoFptTb0eSQTrZkravx2uJrSSuMtPP2qOkGkVQNE2TsJdyFVEKwhXuVyhpuDFky56Q73RDzQCfFEhZHfmleUCaZSVJlUXY86b6/Qk4ebzmGyje7+7z29PARHJBKWHJi/759fKmpTMO27gYor+ylFhqz21crjX7uae0jLKg59CjdSgJocpZ5jOK+B4sWqFuEYUMpcUcN3pZ2jkFMqQcWzOinegbwKeMzgwNzAfMAcGBSsOAwIaBBS9S/16xb6qbDTK5fY6EyjfSc/nvgQU1/tVtjNCPOGmYwOUDNupoL7hlpI=">
    <trustedCertificates>
      <certificateInfo thumbprint="625C675C8C7FF2A4041573116211367DABA71969" subject="CallerCertificate"/>
    </trustedCertificates>
  </certificateSection>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <certificateExtension />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <services>
      <service name="Service.Service">
        <endpoint name="myService"
                  address=""
                  binding="wsDualHttpBinding"
                  contract="Service.IService"
                  bindingConfiguration="certificateBinding"/>
      </service>
    </services>
    <bindings>
      <wsDualHttpBinding>
        <binding name="certificateBinding">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsDualHttpBinding>
    </bindings>
    <extensions>
      <behaviorExtensions>
        <add name="certificateExtension" type="Certificate.Extensions.CertificateExtensionBehavior, Certificate"/>
      </behaviorExtensions>
    </extensions>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

And the app.config of the caller should look like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="certificateSection" type="Certificate.Configuration.CertificatesSection, Certificate"/>
    </configSections>
    <certificateSection certificate="MIIExgIBAzCCBIYGCSqGSIb3DQEHAaCCBHcEggRzMIIEbzCCApgGCSqGSIb3DQEHAaCCAokEggKFMIICgTCCAn0GCyqGSIb3DQEMCgECoIIBjjCCAYowHAYKKoZIhvcNAQwBAzAOBAgbm3IPSqU0BQICB9AEggFojvCBmeSJ6n4IlKxgSv1XgIB5LaD7tb06f/yTLsZRK+4rnqCaesmYFFHP889JTySdqPPyE6fNrpFXTcvcRC6lQQglLnxbRZQotPHvDv4MEzEdI67zkkfM7RsxxXRUQE+ex5H+oQxjScvVRWlKa0KXLk7DOa+Ijz/epLFCum2CE2aUE/AOdi8GCYf7D0yMa472/buQRX1qWX5MYuH+sZI1py/unS8R5R4cytRr8dKJHmn3YtLuhEwQOuXiQ/mUK5PKj+xYp6b8ssVIXQjuLpXZnnT7i/KdZipxmTCf+OtXbAysBw2VaQ9+NmR8cufy8nUb/KgSNfcE3hTHTxIaBnhddhuHxvfR5oYIAzPK3NTq/S1qCEqxDJnBFapdnRcKfHEAlDwIB/KZyHgKdVBiu16pB9e+bxl840CW6vI/tILBbpww3rjvzKKQYZZ6uPu1oNLS2TeX7JsBJE3p0HJE2DPFLfmXLPVPSkHBMYHbMBMGCSqGSIb3DQEJFTEGBAQBAAAAMFcGCSqGSIb3DQEJFDFKHkgAZgAzADEAMwBlADQAYQA4AC0AMAA2ADMANwAtADQANAA1ADAALQBiAGMANAA5AC0AMwA2AGEAMABkAGIAOQAxADkAOABhAGQwawYJKwYBBAGCNxEBMV4eXABNAGkAYwByAG8AcwBvAGYAdAAgAEUAbgBoAGEAbgBjAGUAZAAgAEMAcgB5AHAAdABvAGcAcgBhAHAAaABpAGMAIABQAHIAbwB2AGkAZABlAHIAIAB2ADEALgAwMIIBzwYJKoZIhvcNAQcGoIIBwDCCAbwCAQAwggG1BgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBBjAOBAjWmEM3BmtPWwICB9CAggGIIxS2KaegZ8TDfdq1AP55giyOzgLOvd1LYA5M1QwRmYcM4IiJe5Z6yB6usrnMa/oAJ6suBw72UTO8lTGc/AXWtbrJg6KM0CuyI7lKdoShn36FRx35djx5plXpDxVrZtR2MbOxgSdUNyUCiuRWe/FUzpwE93IWQnfIleeziH1YXuZdvxy/vTLKT2VngeZh3BjyG25n7Fj44xgy7CQM/g/q+TgHBJjnY9qD36kPdaWxkxytadpJH3GgnKLjoQCvHhFN6NEVhErnvzZo63jPZIDWHxr7EYGkbVTzwtPwlocTDgm75gS/IwCMNdAxHP9ofMM4H+2g/UV88R4ABgUoP139Drz5LrfHFsnvPx3/twygMX6lUccnwyKZTVcphjADHU6FVsm2/xJ/nqxCkiUt7ciz150FqGxJ+vxg5zo533eHjViwdDBHTMIopyypOY69xNfN1VGPMKxfc/d5z6ayKKpi9lXQMIUumoz5Xqjnq4dyschqoUbGNW1LB+0Y3BNHxeXyGlYsTsr9nYowNzAfMAcGBSsOAwIaBBRgiHbVQmQbvNqXli2R3sBoa6AirAQUeAWzhwSRejw9yMIGB2GgBY76bbM=">
        <trustedCertificates>
            <certificateInfo thumbprint="64123DFA95F03AFB818EC61C874241B62E2A4886" subject="ServiceCertificate"/>
        </trustedCertificates>
    </certificateSection>
    <system.serviceModel>
        <bindings>
            <wsDualHttpBinding>
                <binding name="certificatesBinfing">
                    <security mode="Message">
                        <message clientCredentialType="Certificate"/>
                    </security>
                </binding>
            </wsDualHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:9986/Service.svc" binding="wsDualHttpBinding"
                bindingConfiguration="certificatesBinfing" contract="IService"
                name="BasicHttpBinding_IService">
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

I have added a small WCF Extensions helper class from here.

using System;
using System.ServiceModel;

namespace Caller.Proxy
{
    public static class WcfExtensions
    {
        public static void Using<T>(this T client, Action<T> work)
            where T : ICommunicationObject
        {
            try
            {
                work(client);
                client.Close();
            }
            catch (CommunicationException)
            {
                client.Abort();
            }
            catch (TimeoutException)
            {
                client.Abort();
            }
            catch (Exception)
            {
                client.Abort();
                throw;
            }
        }
    }
}

Now the only thing we need to do is to call the service from the caller:

using System;
using System.Configuration;
using System.Linq;
using System.ServiceModel;
using Caller.Proxy;
using Certificate;
using Certificate.Configuration;

namespace Caller
{
    class Program
    {
        static void Main(string[] args)
        {
            new ServiceClient().Using(channel =>
            {
                //get the information from our custom configuration section
                CertificatesSection certificateSection = (CertificatesSection)ConfigurationManager.GetSection("certificateSection");
                var trustedList = certificateSection.TrustedCertificates.Cast().ToList();

                var endpointAddress = channel.Endpoint.Address.Uri;

                //get the first trusted certification. We assume that you will call only one service, so we will have only one item in the TrustedCertificates
                //this can be improved to select which service do you want to call an what is the response thumbprint that we expect
                string trustedSubject = trustedList.FirstOrDefault().Subject;

                //we create a dns identity from the trusted object to be able to authenticate with the service
                //
                //    
                //
                var identity = EndpointIdentity.CreateDnsIdentity(trustedSubject);

                channel.Endpoint.Address = new EndpointAddress(endpointAddress, identity);

                channel.ClientCredentials.ClientCertificate.Certificate = certificateSection.Certificate;
                //set custom validation mode
                channel.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.Custom;
                //trust results only from the certificate in the trusted list
                channel.ClientCredentials.ServiceCertificate.Authentication.CustomCertificateValidator = new CertificateValidator(trustedList.Select(x => x.Thumbprint));

                var data = channel.GetData(1);
                Console.WriteLine(data);
            });
        }
    }
}

And that’s it. We can create new certificate with the generator, set the serialized value in the configuration file of one of the sides and add the certificate subject and thumbprint in the other side’s trusted certificates and vice versa.

If you host the service and the site on IIS you need to set IIS Application Pool configuration (Application Pools > Advanced
Settings) to load the user profile for the application pool identity
user.

Otherwise the user may not be able to load the certificate.

 

Advertisements

How to use the NEST API using FirebaseSharp

This article demonstrates how to call Nest API from .NET using FirebaseSharp, an unofficial open source Firebase.NET client.

To follow along and test drive Nest API you do not need to own a Nest device, a simulator is available. Continue reading “How to use the NEST API using FirebaseSharp”

Get a list of databases from SQL Server

Option 1: SQL Connection

            Dim sqlsb As New SqlClient.SqlConnectionStringBuilder()
            sqlsb.ConnectionString = connString '_connectionString
            sqlsb.InitialCatalog = ""

            Using conDB As New SqlConnection(sqlsb.ToString())
                conDB.Open()
                dtDatabases = conDB.GetSchema("Databases")
                conDB.Close()
                '   *** cmbDatabase.Items.Clear()
                For Each r As DataRow In dtDatabases.Rows
                    Select Case r("database_name").ToString
                        Case "master", "tempdb", "msdb", "model"
                        Case Else
                            ' **** mbDatabase.Items.Add(r("database_name"))
                            names.Add(r("database_name"))
                    End Select
                Next
            End Using

Option 2: SQL Select:

SELECT DB_NAME(database_id) AS [Database], database_id
FROM sys.databases
WHERE database_id>4

Option 3: Microsoft SMO Objects

Install-Package Microsoft.SqlServer.SqlManagementObjects -Version 140.17199.0


var SDBLOC = new Microsoft.SqlServer.Management.Smo.Server("localhost").Datab‌​ases.Cast<Microsoft.‌​SqlServer.Management‌​.Smo.Database>().Whe‌​re(bs => !bs.IsSystemObject && bs.ID>6).ToList();

How to install .NET Framework 3.5 on Windows Server 2012 and Windows Server 2012 R2

If you have an application that you want to run on Windows Server 2012 that requires the .NET Framework 3.5, you will most likely run in to a problem when trying to install it. If you are trying to install .NET Framework 3.5 from the Server Manager GUI, you will see this when installing the feature:

“Do you want to specify an alternate source path? One or more installation selections are missing source files…”

To solve this, you can either:

Powershell (As Admin)

Install-WindowsFeature Net-Framework-Core -source \\network\share\sxs

Old Fashion Command Line (As Admin)

DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:d:\sources\sxs

Using Powershell you can verify the install by running Get-WindowsFeature from within PS, you will notice something similar to this;

[X] .NET Framework 3.5 Features NET-Framework-Features   Installed
[X] .NET Framework 3.5 (includes .NET 2.0 and 3.0)  NET-Framework-Core Installed

Note: Source should be the Windows installation disc. In my case, this was located on D:

Bug when adding .net framework 3.5 in Server 2012

2. Go down to “Specify an alternate source path” and enter “d:\sources\sxs” as the path.

Now you should see this under your Features list:

.NET Framework 3.5 feature installed on Windows Server 2012

How to check if a file is an image

You can always check the extension to be “jpg, jpeg, gif, tiff, png, bmp” but sometimes, malicious attackers can upload an exe file with the wrong extension and then use a series of commands to remove the extension/run the file on the server.

How to check extension:

public static readonly List ImageExtensions = new List { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };

private void button_Click(object sender, RoutedEventArgs e)
{
    var folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    var files = Directory.GetFiles(folder);
    foreach(var f in files)
    {
        if (ImageExtensions.Contains(Path.GetExtension(f).ToUpperInvariant()))
        {
            // process image
        }
    }
}

The other option would be .NET 4.5:
MimeMapping.GetMimeMapping Method

Or:

static Extension()
    {
        ImageTypes = new Dictionary();
        ImageTypes.Add("FFD8","jpg");
        ImageTypes.Add("424D","bmp");
        ImageTypes.Add("474946","gif");
        ImageTypes.Add("89504E470D0A1A0A","png");
    }

    /// 
    ///      Registers a hexadecimal value used for a given image type 
    ///      The type of image, example: "png" 
    ///      The type of image, example: "89504E470D0A1A0A" 
    /// 
    public static void RegisterImageHeaderSignature(string imageType, string uniqueHeaderAsHex)
    {
        Regex validator = new Regex(@"^[A-F0-9]+$", RegexOptions.CultureInvariant);

        uniqueHeaderAsHex = uniqueHeaderAsHex.Replace(" ", "");

        if (string.IsNullOrWhiteSpace(imageType))         throw new ArgumentNullException("imageType");
        if (string.IsNullOrWhiteSpace(uniqueHeaderAsHex)) throw new ArgumentNullException("uniqueHeaderAsHex");
        if (uniqueHeaderAsHex.Length % 2 != 0)            throw new ArgumentException    ("Hexadecimal value is invalid");
        if (!validator.IsMatch(uniqueHeaderAsHex))        throw new ArgumentException    ("Hexadecimal value is invalid");

        ImageTypes.Add(uniqueHeaderAsHex, imageType);
    }

    private static Dictionary ImageTypes;

    public static bool IsImage(this Stream stream)
    {
        string imageType;
        return stream.IsImage(out imageType);
    }

    public static bool IsImage(this Stream stream, out string imageType)
    {
        stream.Seek(0, SeekOrigin.Begin);
        StringBuilder builder = new StringBuilder();
        int largestByteHeader = ImageTypes.Max(img => img.Value.Length);

        for (int i = 0; i  img == builtHex);
            if (isImage)
            {
                imageType = ImageTypes[builder.ToString()];
                return true;
            }
        }
        imageType = null;
        return false;
    }

How to run a Windows Service in Console Mode

Run Windows Service as a console program

Visual Studio and the .NET framework make it really easy to create Windows Services. All you have to do is create a new project, select “Windows Service” as your project type and you’re all set. However, debugging Windows Services in Visual Studio can be a big pain. The recommended way is to use InstallUtil to install them, and then restart the service and attach the debugger everytime you want to debug it. I wanted to be able to debug it without the hassle, so here’s what I came up with:

using System;
using System.ServiceProcess;
 
public partial class DemoService : ServiceBase
{
    static void Main(string[] args)
    {
        DemoService service = new DemoService();
 
        if (Environment.UserInteractive)
        {
            service.OnStart(args);
            Console.WriteLine("Press any key to stop program");
            Console.Read();
            service.OnStop();
        }
        else
        {
            ServiceBase.Run(service);
        }
 
    }
    public DemoService()
    {
        InitializeComponent();
    }
 
    protected override void OnStart(string[] args)
    {
        // TODO: Add code here to start your service.
    }
 
    protected override void OnStop()
    {
        // TODO: Add code here to perform any tear-down
        //necessary to stop your service.
    }
}

This will allow you to use your program as either a normal console program or a windows service, with no special builds, #DEBUG directives, command line parameters or anything like that. What it does is in the Main method it checks the “Environment.UserInteractive” property. This will be true when it is run from Visual Studio, or when you just click on the .exe file, but false if it’s being run as a service. When it’s run from Visual Studio or as a standalone program it will keep running until you press a key, then it will call your OnStop method and then terminate.

Two things to watch out for:

  1. You’ll have to right click on your project in Visual Studio, choose Properties and select the Output type as “Console application” for this to work.
  2. If your Main method is not in your service class, you’ll have to add public methods to your class that can start and stop it, for instance add a public void StartConsole(string[] args) that just calls your OnStart, since OnStart and OnStop are protected methods and as such not accessible from other classes.