Saturday, June 18, 2016

WCF Security Notes


SYMMETRIC BINDING (WHEN ONLY SERVER HAS THE X509 CERT)









In case of derived key scenario –

2 keys are generated from symmetric key (derived keys). 1 key is used for encryption, while the other is used for signing. The client encrypt both derived keys.



      ASYMMETRIC BINDING ( BOTH CLIENT AND SERVER HAVE X509 CERT)




Although Derived keys can be used for Asymm binding as well, it will be of no use as Encryption and Signing are already happening with different keys.

If you want to use Asymmetric binding, you can ONLY do it via code. Only configuration will not suffice.
First create a custom binding inheriting from Binding class. Then add a BindingExtension and use that bindingextension in the endpoint binding configuration.


WCF by default uses SYMMETRIC KEY with DERIVED KEYS on. You cannot switch to make DERIVED KEYS off UNLESS you make a ‘custom binding’.


                                                     Best of both worlds – 





If negotiateServiceCredential=”true”, then the public key is given to the Client in the beginning of the transaction, however note that IT IS NOT INTEROPERABLE.
To make it interoperable, public key has to given to client by out-of-band mechanism.
Since client has the public key part of the certificate, it can verify the service (by the checking the trusted CA store). Client authenticates the server by using the <identity> element inside <client> element.

Note – Even if the ProtectionLevel of a operation is set to None, its body will be in clear text BUT its message header will have an encrypted section as client credentials are being passed.

Even if client has its own pvk key for authentication to service, WCF defaults to Symmetric binding with DERIVED keys. If you want to override this behavior (i.e use asymmetric binding), you have programmatically create a custom binding and use it client and service end.


Sunday, May 15, 2016

Using Reflexil with ILSpy to add Debug lines in a deployed DLL/EXE. (without recompiling/redeploying)



Using Reflexil with ILSpy to add Debug lines in a deployed DLL/EXE. (without recompiling/redeploying)






This can be done by directly editing the IL.
For example – In the beginning of method “func1” we want to record the parameters using Debug.WriteLine to see in DbgView or by adding some other listeners.
Do the following steps –
         1)      Unzip IlSpy and Reflexil  (both latest version, so that they are compatible) in the same folder.
         2)      Open ILSpy, open the dll/exe and click on the ‘gear’ icon on the top right to open reflexil.
         3)      Navigate to the required method, in this case “func1”.
         4)      Go to “Instructions” tab.
         5)      Right-click to add instructions. (Ignore the offset, focus on inserting the instruction at the right            place).
         6)      Most of the instruction to add Debug lines are done using ldstr (load string to stack), ldarg.0              (load the 0th (first) argument to stack), box (if it is value type/integer), call to Concat and                    WriteLine.
         7)      To load nth argument, use ldarg.s (as shown above in the above diagram).
         8)      nop is no instruction (probably ‘enter’).
         9)      If you are unclear of any instruction, just write the code and see it in Ilspy+Reflexil.
         10)   To load any property say “LastName” of any object say “Person”, use ‘callvirt’ (shown above).



Saturday, April 16, 2016

Advanced Quartz.NET scenarios


To enable Quartz.NET internal logging, add the following to Quartz.Server.exe.config - 


1) Use the following <common> config section
  <common>
     <logging>
      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net1213">
        <arg key="configType" value="INLINE"/>
      </factoryAdapter>
    </logging>
  </common>

2) <appender name="QuartzInternalLog" type="log4net.Appender.RollingFileAppender">
            <file type="log4net.Util.PatternString" value="Trace/QuartzInternalLogFile_%date{yyyyMMdd}.txt"/>
            <appendToFile value="true"/>
            <maximumFileSize value="1024KB"/>
     <maxSizeRollBackups value="1000" />
            <rollingStyle value="Size"/>
   <datePattern value="yyyyMMdd" />
   <staticLogFileName value="true" />
   <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%d{HH:mm:ss} [%t] %-5p %c - %m%n"/>
            </layout>
    </appender>


3) <logger name="Quartz">
<level value="DEBUG" />
<appender-ref ref="QuartzInternalLog" />
    </logger>

(NO NEED TO ADD QUARTZINTERNALLOG TO ROOT LEVEL LOGGER. THIS IS TO KEEP QUARTZ INTERNAL LOG SEPARATE).



To enable clustering in Quartz.NET, add the following to Quartz.Server.exe.config - 

<quartz>
<add key="quartz.checkConfiguration" value="false"/>
  <add key="quartz.server.serviceName" value="ABC-Project-QuartzServer-UAT"/>
  <add key="quartz.server.serviceDisplayName" value="ABC-Project-QuartzServer-UAT"/>
  <add key="quartz.server.serviceDescription" value="ABC-Project-QuartzServer-UAT"/>
  <add key="quartz.scheduler.instanceName" value="ABCProjectScheduler"/>
  <add key="quartz.scheduler.instanceId" value = "AUTO"/>
  <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz"/>
  <add key="quartz.threadPool.threadCount" value="20"/>
  <add key="quartz.threadPool.threadPriority" value="Normal"/>
  <add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz"/>
  <add key="quartz.plugin.xml.fileNames" value="~/quartz_jobs.xml"/>
  <add key="quartz.scheduler.exporter.type" value="Quartz.Simpl.RemotingSchedulerExporter, Quartz"/>
  <add key="quartz.scheduler.exporter.port" value="555"/>
  <add key="quartz.scheduler.exporter.bindName" value="QuartzScheduler"/>
  <add key="quartz.scheduler.exporter.channelType" value="tcp"/>
  <add key="quartz.scheduler.exporter.channelName" value="httpQuartz"/>
  <add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"/>
  <add key="quartz.jobStore.dataSource" value="default"/>
  <add key="quartz.jobStore.tablePrefix" value="QRTZ_"/>
  <add key="quartz.jobStore.clustered" value="true"/>

  <add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"/>
  <add key="quartz.dataSource.default.provider" value="SqlServer-20"/>
  <add key="quartz.jobStore.useProperties" value="true"/>
  <add key="quartz.jobStore.misfireThreshold" value="600000" />
 
  <add key="quartz.dataSource.default.connectionStringName" value="QuartzStore"/>
  <add key="quartz.dataSource.default.connectionString" value="Data Source=MyServer;Initial Catalog=ABC_Project_quartz_scheduler;User ID=MyUser;Password=MyPass"/>
</quartz>


NOTE THE ABOVE SETTINGS CAN ALSO BE DONE IN Quartz.Config file but Quartz.Server.exe.config WILL TAKE THE PRECEDENCE. I personally like keeping all the settings in one place i.e. Quartz.Server.exe.config.

To prevent concurrent execution of the job, do the following steps - 



       1) Use the following attribute – [DisallowConcurrentExecution] in the job class


 2) Use the following misfire instruction:
<trigger>
      <cron>
        <name>LongRunningJobTrigger</name>
        <group>CronTriggerGroup</group>
        <description>CronTrigger description</description>
        <job-name>LongRunningJob</job-name>
        <job-group>QuartzJobLib</job-group>
        <misfire-instruction>DoNothing</misfire-instruction>
        <cron-expression>0 0/1 * 1/1 * ? *</cron-expression>
      </cron>
    </trigger>



     3) Default behavior would fire new job instance in a separate thread. We need to avoid that.

4) With the above approach, the below output is produced –  (with trigger every minute (60 sec), and each job taking 90 seconds)

[13396] 10/15/2015 1:16:00 AM 635804487114616685 Main Job Process - Start
[13396] 10/15/2015 1:16:00 AM 635804487114616685 Internal Job Process - Start
[13396] 10/15/2015 1:17:30 AM 635804487114616685 Internal Job Process - End
[13396] 10/15/2015 1:17:30 AM 635804487114616685 Main Job Process - End
[13396] 10/15/2015 1:18:00 AM 635804487114616723 Main Job Process - Start
[13396] 10/15/2015 1:18:00 AM 635804487114616723 Internal Job Process - Start
[13396] 10/15/2015 1:19:30 AM 635804487114616723 Internal Job Process - End
[13396] 10/15/2015 1:19:30 AM 635804487114616723 Main Job Process - End
[13396] 10/15/2015 1:20:00 AM 635804487114616724 Main Job Process - Start
[13396] 10/15/2015 1:20:00 AM 635804487114616724 Internal Job Process - Start
[13396] 10/15/2015 1:21:30 AM 635804487114616724 Internal Job Process - End
[13396] 10/15/2015 1:21:30 AM 635804487114616724 Main Job Process - End
[13396] 10/15/2015 1:22:00 AM 635804487114616725 Main Job Process - Start
[13396] 10/15/2015 1:22:00 AM 635804487114616725 Internal Job Process – Start



Note  from the above output
a)      The new job (ID) does not starts until the previous job is finished.
b)     The new job did not start at 1:17:30, instead it started at 1:18:00 (Because of the misfire instruction “DoNothing”)

5) Note misfire-instruction property is available only with CronTrigger (not with SimpleTrigger). My suggestion is to always use CronTrigger instead of SimpleTrigger.




Sunday, March 13, 2016

Common Gotchas

                                                                   
                                                               Common Gotchas



1)   Extra character in Certificate Thumbprint – Go to Windows MMC, add the certificates snap-in (Ctrl M), select any certificate properties and copy-paste its thumbprint in notepad to see it.


2)     Enterprise library Semantic logging (out-of-process) service not logging anything – Restart the service.

3)     Enterprise library Semantic logging will not write anything if any one of the parameter passed is null. Example  -
this.WriteEvent(2, FirstName, LastName, EncSSN, City);
will not write if anything if just “City” is null. 

4) While configuring Quartz.NET scheduler with AdoNetJobStore (needed for clustered scenario), make sure no other instance of Quartz.NET scheduler is pointing to the same job store (database). Example - SIT Env Quartz.NET jobstore might be pointing to UAT Env. jobstore.

5) Sharing a folder in Windows will update the existing ACL list of the children folder. For example - Sharing the inetpub > "wwwroot" folder with read-only permissions for some colleagues removed "NetworkService" and "IIS_IUSRS" users from all its virtual directories physical folders. 

ReSubmitting messages from ServiceBus Deadletter queue



ReSubmitting messages from ServiceBus Deadletter queue


Resubmitting messages, which do not require any change, from deadletter queue is straightforward and can be done using Service Bus Explorer tool.

However if the messages need change (say for example – because of bug – there is a special character which needs to be stripped off from the messages), ServiceBusExplorer would not do it. This can be done by using a custom tool/program to retrieve the messages from deadletter queue, store it somewhere, do the necessary modification and push the message back to the service bus. (Note – The earlier deadletter messages should be deleted (received)).
The sample code for reading messages from deadletter queue can be taken the open source ServiceBusExplorer tool itself. Program below –


class Program
    {
        private static int MaxBufferSize = 262144; // 256 KB

        static void Main(string[] args)
        {

            Uri uri = new Uri(@"sb://" + ConfigurationManager.AppSettings["SbHost"] + "." + ConfigurationManager.AppSettings["Domain"] + "/" + ConfigurationManager.AppSettings["Namespace"]);
            TokenProvider tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(ConfigurationManager.AppSettings["KeyName"], ConfigurationManager.AppSettings["SharedAccessKey"]);
            MessagingFactory factory = MessagingFactory.Create(uri, tokenProvider);

            SubscriptionClient subsClient = factory.CreateSubscriptionClient(ConfigurationManager.AppSettings["Topic"], ConfigurationManager.AppSettings["Subscription"] + "/$DeadLetterQueue");

            var listMessages = subsClient.PeekBatch(Convert.ToInt32(ConfigurationManager.AppSettings["PeekMessageCount"]));           

            foreach (var bm in listMessages)
            {
                string messageText = null;
                Stream stream = bm.GetBody<Stream>();
                var element = new BinaryMessageEncodingBindingElement
                {
                    ReaderQuotas = new XmlDictionaryReaderQuotas
                    {
                        MaxArrayLength = int.MaxValue,
                        MaxBytesPerRead = int.MaxValue,
                        MaxDepth = int.MaxValue,
                        MaxNameTableCharCount = int.MaxValue,
                        MaxStringContentLength = int.MaxValue
                    }
                };
                var encoderFactory = element.CreateMessageEncoderFactory();
                var encoder = encoderFactory.Encoder;
                var stringBuilder = new StringBuilder();
                var message = encoder.ReadMessage(stream, MaxBufferSize);
                using (var reader = message.GetReaderAtBodyContents())
                {
                    var settings = new XmlWriterSettings { Indent = true };
                    using (var writer = XmlWriter.Create(stringBuilder, settings))
                    {
                        writer.WriteNode(reader, true);
                    }
                }
                messageText = stringBuilder.ToString();
                Console.WriteLine(messageText);
                stream.Dispose();
                File.WriteAllText(ConfigurationManager.AppSettings["PathToStoreMessages"] + bm.MessageId + ".txt", messageText);
            }



        }


    }

Thursday, February 11, 2016

Exception handling while using Entity Framework

Taken from - https://blogs.infosupport.com/improving-dbentityvalidationexception/

Use the code snippet below either by applying in each dataaccess method or via partial class for DBEntites -


public partial class NorthwindEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            // Retrieve the error messages as a list of strings.
            var errorMessages = ex.EntityValidationErrors
                    .SelectMany(x => x.ValidationErrors)
                    .Select(x => x.ErrorMessage);

            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);

            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

if the above approach is not used - simply printing ex.Message will not give the full error information and will make diagnosing tougher.

Disposing WCF clients


Taken from

http://web.archive.org/web/20100703123454/http://old.iserviceoriented.com/blog/post/Indisposable+-+WCF+Gotcha+1.aspx


OrderServiceClient proxy = null;
bool success = false;
try
{
  proxy = new OrderServiceClient();
  proxy.PlaceOrder(request);
  proxy.Close();
  success = true;
}
finally
{
  if(!success)
  {
    proxy.Abort();
  }
}



If you do not want to clutter your code with the above code all the places, use the following approach-

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
}

=====================Implementation of Service class========

public delegate void UseServiceDelegate<T>(T proxy);

public static class Service<T>
{
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");

    public static void Use(UseServiceDelegate<T> codeBlock)
    {
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
        bool success = false;
        try
        {
            codeBlock((T)proxy);
            proxy.Close();
            success = true;
        }
        finally
        {
            if (!success)
            {
                proxy.Abort();
            }
        }
    }
}