Friday, May 24, 2013

Publishing encrypted connection strings in web.config


PROBLEM: You publish your website to a server (e.g. Stage or Production) and then have to manually run a command to encrypt the connectionStrings within the web.config (would be nice for the publish process to just take care of everything) - this guy on stackoverflow had the same issue: http://stackoverflow.com/questions/14838156/encrypting-webconfig/16728000

SOLUTION: Take the encrypted portion of the web.config (remember you'll need to be remoted on to your server to do the encryption) and add to your Web.[CONFIGURATION].config transformation file e.g. Web.Stage.config or Web.Release.config... since the encryption is based on machine keys you'll need to have a different transformation file for each server that you are deploying to.  This is all quite simple, I just never thought of doing it before - the hardest bit was finding the syntax for the web.config transformation file - the syntax I've got below works but the compiler will flag a warning about invalid syntax i.e.


Warning 15 The element 'connectionStrings' has invalid child element 'EncryptedData' in namespace 'http://www.w3.org/2001/04/xmlenc#'. List of possible elements expected: 'add, remove, clear'. C:\DevTFS\YourProject\Web.Stage.config 14 6 YourProject

 (I'm open to suggestions on how to make it compliant and still work).


Step 1.
Encrypt connectionStrings in the web.config as per: http://msdn.microsoft.com/library/dtkwfdky.aspx or http://stackoverflow.com/questions/8230864/how-can-i-safely-store-and-access-connection-string-details

I keep a batch file in the root of my website for this:


@ECHO OFF
echo "This will Encrypt or Decrypt the Connections section of web.config - it should be run after deploying to any publicly accessible version of the site e.g. production."

CHOICE /C:ed /M "Encrypt or Decrypt"

IF %errorlevel%==1 goto enc
IF %errorlevel%==2 goto dec

:enc
echo "Encrypting section connectionStrings"
c:\WINDOWS\Microsoft.net\Framework\v4.0.30319\aspnet_regiis -pef "connectionStrings" %CD%
goto EOF

:dec
echo "Decrypting section connectionStrings"
c:\WINDOWS\Microsoft.net\Framework\v4.0.30319\aspnet_regiis -pdf "connectionStrings" %CD%
GOTO EOF

:EOF
EXIT



Step 2.

Add the following to your Web.[Config].config file...


  <connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider"
  </connectionStrings>

And then copy and paste the <EncryptedData> elements from your encrypted web.config file on your server between these tags e.g.


  <connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider" xdt:Transform="Replace">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
      xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <KeyName>Rsa Key</KeyName>
          </KeyInfo>
          <CipherData>
           <CipherValue>t8p7aOZTjMon8B1qC4L4gmKasdfsdafasdfJHckY0fl9hfaasdffQWrpdX1jqF6vD3/X4Ejg+UeiCWujkx+dfvDOif3sodfsdfsd6kHAtah2o59UmzsfdasdfdfdKzUliSgMe01fRbjA/bxA6Bbq+sjzE6FAAI=</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>Vy1TZWY8ojpf343XQCQwK/r4lmp+vbJPS5sdfdfbv0YMTGEdGuCwdLND5ezMe9iLkuI5/fmvU1TSDzPgvKcAwNc1rXU5jiU0234234JtviOMe6vjU8FSkHilwLITGS9/XUDiacqccfuXsBcdBtcwAfBxIAwwCQxOQIFi6hN/cG2emFj1oSIU468O8ezOG+UMSd4HzaDS2jzZyrfsdfsdfyi0bg8OV5QVOlSUjjuh54Bt4t2pd0O2vsUbwsdfsdfVxB0KgIlL6Kqe53z2Ns6GHlRwJuMFRHQnQT234234SSVLLGkWdI1IGyl12JdlTrd5JItDHGgPNat+fe5FR5GNasdfsdfivft4YZV3iXgbPtZyiHm6aI7ccDuCTHJ+V78AwZAVlIGRKzVbqsic+Qg6T7U</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>


Credit goes to this guy for actually adding a useful comment to forums.asp.net (unfortunately they are few and far between) - http://forums.asp.net/post/5390287.aspx

Thursday, January 24, 2013

String Truncate

PROBLEM: The .NET framework doesn't have a truncate method for strings.  Substring will fail if you're not careful (i.e. if you don't check that the string has at least as many characters at the truncation length)

SOLUTION: Add a Truncate extension method for the string class that does the boring checks (length, null - some other examples don't include the null check, etc) for you each time.


        /// <summary>
        /// Ensure that a string is no longer than a specified maximum number of characters.
        /// This string extension method has been written because there is no string truncate method
        /// in the .NET framework and Substring will throw an exception if the length you enter is
        /// longer than the length of the string.
        /// </summary>
        /// <param name="originalString"></param>
        /// <param name="maximumLength"></param>
        /// <returns></returns>
        public static string Truncate(this String originalString, int maximumLength)
        {
            return (originalString == null || originalString.Length <= maximumLength) ? originalString : originalString.Substring(0, maximumLength);
        }

Example use:

          string newString = oldString.Truncate(10);

Credit goes to this guy and one of the people in his comments: http://jamesfricker.blogspot.com.au/2007/08/truncating-string-in-c-easy-huh.html

Friday, January 11, 2013

OnClientClick breaks validation


PROBLEM: Your validators (RequiredFieldValidator, RangeValidator, RegularExpressionValidator etc) are not being called/fired when you have some client side javascript in OnClientClick that asks a yes/no question e.g. Are you sure you want to delete this?


<asp:Button ID="btnConfirmDelete"
                    runat="server"
                    Text="Delete this Session"
                    ValidationGroup="vgDelete"
                    onclick="btnConfirmDelete_Click"
                    OnClientClick='return confirm("Are you sure you want to delete this session?")' />


SOLUTION:
When the page is rendered, the javascript for the onclick will look something like:


onclick="return confirm('Are you sure?');WebForm_DoPostBackWithOptions(...)"

As you can see, the validation doesn't even have a chance to fire (which happens when WebForm_DoPostBackWithOptions is called).

(this guy figured that out: http://vaultofthoughts.net/OnClientClickBreaksValidation.aspx)

Changing it to the below fixes that:

'if (!confirm("Are you sure you want to delete this session?")) return false;'

BUT then you realise that the validators are being called AFTER the prompt (ideally you don't want to prompt the user that they're sure until the last minute after everything is completed). So the this version takes care of that:

'if(Page_ClientValidate()) return confirm("Are you sure you want to delete this session?"); return false;'

Some more info here: http://alvinzc.blogspot.com.au/2006/10/aspnet-requiredfieldvalidator.html

BUT if you're using validation groups, remember to specify it when you call Page_ClientValidate to prevent fields being validated that you don't want validated. Therefore the final version in our case is:

OnClientClick='if(Page_ClientValidate("vgDelete")) return confirm("Are you sure you want to delete this session?"); return false;'

http://techbrij.com/client-side-validation-using-asp-net-validator-controls-from-javascript
http://programmer.webhostingdevelopment.com/index.php/2010/03/specifying-validationgroup-in-page_clientvalidate-function/