• Care, Share and Grow!

    IIS ADMIN service fail to start?

    • 15 Comments

     

    An issue that causes a lot of headache to Web Admins is when IISADMIN service does not start up for no reason.

    Here are a quick troubleshooting steps you can do before you look around and yell for help or call into Microsoft Product Support services and shell out some $$.

    -- Check and Make sure we have a Metabase.bin file (in IIS 5/5.1) or Metabase.xml file (in IIS 6) in C:\<%Windows%>\system32\inetsrv folder.

    -- Check and make sure that we have a Machinekey starting with “C23” in the C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys folder.

    -- Make sure that the MachineKeys folder has Full Control for both Administrators and System. Make sure that the “C23” key has "Administrators" and "System" Full Control permissions set on it.

    IIS depends upon this key for encryption/decryption of metabase keys. If we do not have the required permissions IISADMIN won't be able to read the configuration from the metabase without this key and hence will fail to start.
    (Just out of topic but, remember even for SSL you should have the above permissions because it too depends upon a machinekey in the same folder for cryptographic computations).

    Ensure you have the necessary permissions according to the following KB http://support.microsoft.com/kb/278381/en-us

    If the issue doesn't get resolved after checking the permissions continue reading further.

    -- Check and see if you have multiple instances of the “C23” key identified above in the MachineKeys folder.

    a. If you have only one instance, then check and make sure that the date on that key matches the date from the time when IIS was installed on the server. If the date is newer than the last IIS Install date, then the MachineKey that was used to encrypt the Metabase got lost and you would have to re-Install IIS (if you don’t have the MachineKey backed up anywhere).

    b. Or else you can look at the suffix of the C23 key (the entire length that follows ‘_” in the C23 key) and check if it is different from any of the suffixes for other keys in the container. This means that the MachineKey (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGUID) for the machine
    has changed since IIS was last installed on the machine. If you don’t have a second instance of the “C23” key (with an earlier date with a different Suffix) at this point, then you have lost the original MachineKey and would have to reinstall IIS. If you do have the earlier (older) key, then replace the suffix of the older key with the MachineGUID value found in the registry and delete the newer key. You should be able to restart IISADMIN at this point. For IIS 5 you can apply this fix (http://support.microsoft.com/default.aspx?scid=KB;EN-US;884872)
    Remember that this does not fix the IISADMIN service startup problem, but prevents the C23 duplicate issue from happening again (which might be the cause of IISADMIN startup issue).

    "When IIS starts it uses the registry value HKLB\software\microsoft\cryptography\MachineGUID to build the filename identifying the keyset file:
    <%allusersprofile%\Application Data\Microsoft\Crypto\RSA\MachineKeys\c23***********************_machineGUID>
    This keyset is then used to validate the SessionKey in the metabase(.bin\.xml) and later to En/Decrypt the applicable metabase entries.
    These parts need to be in synchronization to get a successful IISAdmin startup"

    -- Finally if the above steps do not help you can use MSCONFIG (Start->Run->MSCONFIG) to disable all the third party (Non-Microsoft) services and see if that helps in starting the IIS Services. If you can, then you need to start enabling the third party services one by one to figure out which one is the culprit here. If a 3rd party service is the cause you may get in touch with the vendors to get this addressed.

    Additional Recommendations:

    Ensure that you backup the metabase.xml (or metabase.bin) on a regular basis. A better way is to keep a transferable copy of the IIS 6.0 metabase backed up with a password. This allows the encrypted information to be decrypted and stored in a manner that allows for portability. The full procedure can be
    found here:
    http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/131b609d-ff3a-488f-a8dd-13044fa623a1.mspx?mfr=true

    Ensure that the machine keys are also backed up in the full system backup jobs.
    http://support.microsoft.com/kb/246459/en-us

    Hope this helps....

  • Care, Share and Grow!

    Client Certificate revisited....How to troubleshoot client certificate related issues

    • 22 Comments

    Well, I am back to Client certificate again, guess the reason being a lot of support calls that we getting off late are related to any of the following four errors, especially the first two.

    403.7

    403.13

    403.16

    403.17 ( I will cover .16 and .17 very briefly since they are very self-explanatory and easy to troubleshoot)

     

    Earlier I had discussed the setup of the client certificate with IIS and AD for authentication mapping etc.

    Here I will discuss the troubleshooting strategies on client certificate related errors that are listed above.

    To understand how Client certificate is used while accessing a resource on the server, you may prefer to look at this brief but quite explanatory KB by David Dietz from IIS support.

    http://support.microsoft.com/kb/907274/en-us

     

    So here we go...

    1) 403.7

    We see that 403.7 can be thrown by IIS when Client certificate is required and the browser is not sending the client certificate details to the web server (IIS). Either the client did not send the certificate for some reason or else the client did not have a certificate issued by a CA that was also trusted by IIS server. If the client sends a certificate which is not mutually trusted by both client and the server you may see this error.

    You may get a meaningful error like this in the browser:

    HTTP Error 403 403.7 Forbidden: Client certificate required
    This error occurs when the resource you are attempting to access requires your browser to have a
    client Secure Sockets Layer (SSL) certificate that the server recognizes. This is used for authenticating you as a valid user of the resource.
    Please contact the Web server's administrator to obtain a valid
    client certificate.

     

    To start with, follow this KB http://support.microsoft.com/kb/332077/en-us

    • You need to make sure that the client certificate is issued by a CA which is in the trusted root CA store on both the server and the client machine. Confirm whether the trusted root CA is part of CTL. The reason being that if your certificate's CA is not in the CTL; although present in the trusted root CA store in the server machine, you may still see the error.

     

    A CTL is a list of trusted certification authorities (CAs) that can be used for client authentication for a particular Web site . You can use CTLs to configure your Web server to accept certificates from a specific list of CAs, and automatically verify client certificates against this list. Only users with a client certificate that is issued by a CA in the CTL can gain access to the server.
    Each Web site on your server can be configured to accept certificates from a different CTL. You may want to do this if you need a different list of trusted CAs for each Web site.

    If CTL is present, this is the list which is actually used to check for CA's which can issue client certificate to a user. If it is disabled then root CA store will be used for the above. Also make sure that the certificate is a valid client certificate. Make sure it is intended for user authentication.

    Check the certificate for "Ensures the identity of a remote computer" and Enhanced Key usage says Client Authentication.

    Also Using >Certutil -verify -urlfetch should show:

    Verified Application Policies:
    1.3.6.1.5.5.7.3.2 Client Authentication

    • You may also see 403.7 due to an update to the trusted Root CA list. This creates a list that is too large based on the size limit we enforce, the result being truncation of the list when this is sent to the client during the client certificate handshake. The limit is based on data size not CA count so there is no way to say this happens at a certain count of trusted CA’s.
      To resolve this we need to delete some of the expired and unused/unknown trusted root certificates from the Trusted Root Certification Authorities list until it is working again.

    The problem can also be identified when the following entry is logged on the Web server. It is quite explanatory in itself.


    Event Type: Warning
    Event Source: Schannel
    Event Category: None
    Event ID: 36885
    Date: 2/9/2007
    Time: 9:32:44 AM
    User: N/A
    Computer: USMASVGDOIM259
    Description:
    When asking for
    client authentication, this server sends a list of trusted
    certificate authorities to the client. The client uses this list to choose a client
    certificate that is trusted by the server. Currently, this server trusts so many
    certificate authorities that the list has grown too long. This list has thus been
    truncated. The administrator of this machine should review the
    certificate
    authorities trusted for client authentication and remove those that do not really
    need to be trusted.

    Related articles:

    Trusted root certificates that are required by Windows Server 2003, by Windows XP,
    and by Windows 2000
    http://support.microsoft.com/kb/293781
    931125 Microsoft root certificate program members (January 2007)
    http://support.microsoft.com/default.aspx?scid=kb;EN-US;931125

     

     

    2) 403.13

    The error you may see in the browser will be as shown below:

    HTTP 403.13 Forbidden: Client certificate revoked
    The page requires a valid client certificate

    For an understanding of this error message check KB 248058.

    This error message means that the client sent a certificate, but either the certificate shows up as revoked in the issuing authority's Certificate Revocation List or the server could not retrieve a CRL from the issuing authority.

    • You need to crosscheck whether the client certificate is revoked or not with the respective CA.
    • If CA confirms the certificate as valid and not revoked then the issue could be with IIS being unable to retrieve CRL from the CA.

    IIS , by default retrieves a CRL whenever it receives a client cert to make sure that cert is not revoked as long as local cache is expired. For this it contacts the CA to get the CRL which is a list of revoked certificates and compares the list with the presented client cert. If for any reason it cannot retrieve the CRL, it will go ahead and throw error message as 403.13 even if cert is valid and not revoked.  This can happen in cases where some Proxy/firewall may block access to CDP to get the CRLs.

     

    If a CDP extension is present in a certificate that is part of the certification path, IIS must be able to download at least one of the CRLs. If IIS is unable to resolve the CRL, it returns the HTTP 403.13 error. In this case, we cannot access the above CDP so we fail. Prior to MS04-011 Win2k did not limit validation based on this. However, we now require that the CDP be reachable when validating a certificate chain.
    To work around this we must either use a reachable CDP in the client certificate or disable CertCheckMode on the IIS server, thus preventing it from doing any revocation checking.

    So, if we are getting Client certificate revoked errors, then check to see if the server can get to the CRL distribution point specified in the client certificate and if it can and is still giving this error, then download the Root and Subordinate CA CRLs and install them on the IIS server so that it can get to it locally.

    Also there is a metabase key in IIS called certcheckmode, which if disabled will stop IIS from trying to retrieve CRL checking. In such a case client cert will be accepted even if the cert is revoked. Disabling CRL checking is a quick way to test the cause.

    The CertCheckMode property enables or disables Certificate Revocation List (CRL) checking. When CertCheckMode is set to a value greater than 0 (CertCheckMode>0), the CRL does not search for certificates that have been revoked. When CertCheckMode is equal to 0 (CertCheckMode=0), the CRL searches for certificates that have been revoked.

    With CertCheckMode disabled, IIS will no longer try to verify revocation of incoming client certificate requests. The client certificates will still need to be within their valid dates and still must be trusted by the IIS server (the IIS server must trust the issuing CA).

    We disable the Certcheckmode key by setting it to 1.

    >C:\Inetpub\Adminscript\cscript.exe adsutil.vbs Set W3SVC/<Website identifier>/CertCheckMode 1 

    I had seen an interesting case where 2 of the websites were accepting the same client cert whereas another one was not accepting it on the same web server.

    Checking the metabase.xml for the server showed this:

    Non-Working site:

    =================

    <IIsWebServer Location ="/LM/W3SVC/690402"

    AuthFlags="0"

    LogPluginClsid="{FF160663-DE82-11CF-BC0A-00AA006111E0}"

    SSLCertHash="8bcfc28e346bb9ec49374d87479021354349cf85"

    SSLStoreName="MY"

    SecureBindings="XX.XX.XX.X:443:"

    ServerAutoStart="TRUE"

    ServerBindings="XX.XX.XX.X:80:"

    ServerComment="CDB"

    >

    </IIsWebServer>

    Working Site:

    =============

    <IIsWebServer Location ="/LM/W3SVC/90326589"

    AuthFlags="0"

    CertCheckMode="1"

    LogPluginClsid="{FF160663-DE82-11CF-BC0A-00AA006111E0}"

    SSLCertHash="a640634e38ff20ebd8c29c32aae635e5575e57f6"

    SSLStoreName="MY"

    SecureBindings="XX.XX.XX.Y:443:"         

    ServerAutoStart="TRUE"

    ServerBindings="XX.XX.XX.Y:80:wcdb"

    ServerComment="WCDB"

    >

    </IIsWebServer>

     

    Look at the difference between them. You see CertCheckMode is absent in the Non-working site, and absence of this key is equivalent to it being enabled. So once we put the CertCheckMode set to "1" for non-working site we should be able to resolve the issue. But this means that CRL chekcing is disabled. You may downlaod the CRL on to the server or else open up the relevant ports in order to allow CRL to be retrieved.

    Check the KB 294305.

    You may also check KB 841632 if IIS 5.0 is in picture.

    There was an interesting case, where users were getting 403.13 even when client cert was not revoked and we were able to access the get the CRL from the CDP for the client cert by accessing it through a browser. Yet after a lot of tracing and monitoring we found that there was a 4-level hierarchy in the certificate chain, with let's say Root CA1 ->Subordinate Root CA2->Subordinate Root CA3 -> Client certificate and one of the subordinate root CA's crl was not accessible. There are tools like certutil or SSLspy that can come handy. We ran certutil.exe -verify -urlfetch <location of the client cert.cer> on the IIS server and found that CRL retrieval for Subordinate Root CA2 was failing, and hence the issue.

    So remember that we need to make sure that the CDPs for all the subordinate CAs certifcates in the chain should also be reachable.

    Let's say for my client certificate, the Certification path shows:

    Microsoft Corporate Root CA

       |-->        Microsoft Corp Enterprise CA 2

             |-->          Saurabh Singh

    Here is the information for certificate "Saurabh singh"

    CRL Distribution Points (Under Details->Field) shows:

    [1]CRL Distribution Point
    Distribution Point Name:
    Full Name:
    URL=ldap:///CN=Microsoft%20Corp%20Enterprise%20CA%202(4),CN=CRL,CN=CDP,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=corp,DC=microsoft,DC=com?certificateRevocationList?base?objectClass=cRLDistributionPoint
    URL=http://corppki/crl/Microsoft%20Corp%20Enterprise%20CA%202(4).crl
    URL=http://crl.microsoft.com/pki/mscorp/crl/Microsoft%20Corp%20Enterprise%20CA%202(4).crl

    Authority Information Access shows:

    [1]Authority Info Access
    Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
    Alternative Name:
    URL=http://corppki/aia/Microsoft%20Corp%20Enterprise%20CA%202(4).crt
    [2]Authority Info Access
    Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
    Alternative Name:
    URL=http://www.microsoft.com/pki/mscorp/Microsoft%20Corp%20Enterprise%20CA%202(4).crt

    Here is the information for certificate  "Microsoft Corp Enterprise CA 2":

    CRL Distribution Points (Under Details->Field) shows:

    [1]CRL Distribution Point
    Distribution Point Name:
    Full Name:
    URL=http://corppki/crl/mscrca.crl
    URL=http://crl.microsoft.com/pki/mscorp/crl/mscrca.crl

    Authority Information Access shows:

    [1]Authority Info Access
    Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
    Alternative Name:
    URL=http://corppki/aia/mscrca.crt
    [2]Authority Info Access
    Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
    Alternative Name:
    URL=http://www.microsoft.com/pki/mscorp/mscrca.crt

    Now runnning the Certutil.exe as shown below:

    cmd prompt> certutil.exe -verify -urlfetch cert.cer    <-------the client certificate

    Here is the output:

    Issuer:
    CN=Microsoft Corp Enterprise CA 2
    Subject:
    CN=Saurabh Singh
    Cert Serial Number: 258a555c0004008b1c42

    dwFlags = CA_VERIFY_FLAGS_DUMP_CHAIN (0x40000000)
    ChainFlags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT (0x40000000)
    HCCE_LOCAL_MACHINE
    CERT_CHAIN_POLICY_BASE
    -------- CERT_CHAIN_CONTEXT --------
    ChainContext.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
    ChainContext.dwRevocationFreshnessTime: 176 Days, 6 Hours, 5 Minutes, 17 Seconds

    SimpleChain.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
    SimpleChain.dwRevocationFreshnessTime: 176 Days, 6 Hours, 5 Minutes, 17 Seconds

    CertContext[0][0]: dwInfoStatus=102 dwErrorStatus=0
    Issuer: CN=Microsoft Corp Enterprise CA 2
    Subject: CN=Saurabh Singh
    Serial: 258a555c0004008b1c42
    Template: AutoEnrolled Client Auth
    48 b7 48 da 00 51 21 77 b3 e1 3a ce 98 7d 35 2f b7 e8 0c 1c
    Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
    Element.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
    ---------------- Certificate AIA ----------------
    Verified "Certificate (0)" Time: 1
    [0.0]
    http://corppki/aia/Microsoft%20Corp%20Enterprise%20CA%202(4).crt

    Verified "Certificate (0)" Time: 1
    [1.0]
    http://www.microsoft.com/pki/mscorp/Microsoft%20Corp%20Enterprise%20CA%202(4).crt

    ---------------- Certificate CDP ----------------
    Verified "Base CRL (821)" Time: 0
    [0.0] ldap:///CN=Microsoft%20Corp%20Enterprise%20CA%202(4),CN=CRL,CN=CDP,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=corp,DC=microsoft,DC=com?certificateRevocationList?base?objectClass=cRLDistributionPoint

    Verified "Base CRL (821)" Time: 0
    [1.0]
    http://corppki/crl/Microsoft%20Corp%20Enterprise%20CA%202(4).crl

    Verified "Base CRL (821)" Time: 1
    [2.0]
    http://crl.microsoft.com/pki/mscorp/crl/Microsoft%20Corp%20Enterprise%20CA%202(4).crl

    ---------------- Base CRL CDP ----------------
    No URLs "None" Time: 0
    --------------------------------
    CRL 821:
    Issuer: CN=Microsoft Corp Enterprise CA 2
    fd 19 3c 2f 0c 24 ea 1c 4a 5d df c4 26 2a b0 1b 98 48 ef 99
    Application[0] = 1.3.6.1.5.5.7.3.2 Client Authentication

    CertContext[0][1]: dwInfoStatus=102 dwErrorStatus=0
    Issuer: CN=Microsoft Corporate Root CA, O=Microsoft Corporation
    Subject: CN=Microsoft Corp Enterprise CA 2
    Serial: 610d1de0000000000019
    Template: SubCA
    17 0a 7b 9d 52 85 07 7e 74 1a f5 a0 6b db 05 78 9e bc f1 8d
    Element.dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER (0x2)
    Element.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
    ---------------- Certificate AIA ----------------
    No CRL "Certificate (0)" Time: 0
    [0.0]
    http://corppki/aia/mscrca.crt

    No CRL "Certificate (0)" Time: 1
    [1.0]
    http://www.microsoft.com/pki/mscorp/mscrca.crt

    ---------------- Certificate CDP ----------------
    Verified "Base CRL (18)" Time: 0
    [0.0]
    http://corppki/crl/mscrca.crl

    Verified "Base CRL (18)" Time: 0
    [1.0]
    http://crl.microsoft.com/pki/mscorp/crl/mscrca.crl

    ---------------- Base CRL CDP ----------------
    No URLs "None" Time: 0
    --------------------------------
    CRL 18:
    Issuer: CN=Microsoft Corporate Root CA, O=Microsoft Corporation
    0e 70 65 69 a7 4c f9 7d 9f 50 7b db 9c e1 b8 27 9e 53 ba f4

    CertContext[0][2]: dwInfoStatus=10c dwErrorStatus=0
    Issuer: CN=Microsoft Corporate Root CA, O=Microsoft Corporation
    Subject: CN=Microsoft Corporate Root CA, O=Microsoft Corporation
    Serial: 443c2a54b59cd69d4c09b18a9b02eb55
    d2 d3 8e ba 60 ca a1 c1 20 55 a2 e1 c8 3b 15 ad 45 01 10 c2
    Element.dwInfoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER (0x4)
    Element.dwInfoStatus = CERT_TRUST_IS_SELF_SIGNED (0x8)
    Element.dwInfoStatus = CERT_TRUST_HAS_PREFERRED_ISSUER (0x100)
    ---------------- Certificate AIA ----------------
    No URLs "None" Time: 0
    ---------------- Certificate CDP ----------------
    No URLs "None" Time: 0
    --------------------------------

    Exclude leaf cert:
    8a cf e9 23 e2 d7 cd d1 f0 bb 05 6e 63 b5 31 95 6e 46 0d ad
    Full chain:
    5b fa 04 32 34 21 49 11 92 56 b3 ee 41 94 b4 b8 f3 f6 44 f2
    ------------------------------------
    Verified Issuance Policies: None
    Verified Application Policies:
    1.3.6.1.5.5.7.3.2 Client Authentication
    Leaf certificate revocation check passed
    CertUtil: -verify command completed successfully.

    If you notice the Certutil.exe tries to check the CRL accessibility by accessing the CRL Distribution points. The above command ouptput should give you an idea regarding the cause. You may see an error in accessing the CRL in the output above in cases where you get the above errors.

    Here is something similar when you get an error:

     

    ----------------  Certificate CDP  ----------------

      Failed "CDP" Time: 0

        Error retrieving URL: The specified network resource or device is no longer available. 0x80070037 (WIN32: 55)

        ldap:///CN=CRL1, CN=xxxx, OU=xxxx, OU=xxxx. by ref. (limits liab.), O=xxxx, C=US?certificateRevocationList;binary,authorityRevocationList;binary,deltaRevocationList;binary

     

      Failed "CDP" Time: 0

        Error retrieving URL: The server name or address could not be resolved 0x80072ee7 (WIN32: 12007)

        http://www.some_company.net/CRL/net1.crl

     

      --------------------------------

      Application[0] = 1.3.6.1.5.5.7.3.4 Secure Email

      Application[1] = 1.3.6.1.5.5.7.3.1 Server Authentication

      Application[2] = 1.3.6.1.5.5.7.3.2 Client Authentication

      Application[3] = 1.3.6.1.5.5.7.3.3 Code Signing

     

    Exclude leaf cert:

      14 4c 46 42 11 66 a4 a9 42 70 ad b6 e0 1e 23 ca d4 9b 24 0e

    Full chain:

      fe 37 4a cf 76 3e 01 14 21 a6 c7 25 35 14 97 e5 91 87 e3 b7

      Issuer: CN=A company, OU=PKI, DC=company, DC=com

      Subject: OID.0.9.2342.19200300.100.1.1=ZALDI001, OU=People, OU=SAP, DC=company, DC=com

      Serial: 42c550de

      6e 33 5f 13 e1 67 ad 41 71 02 96 17 c7 57 c9 91 ea cb 1d 24

    The revocation function was unable to check revocation because the revocation server was offline. 0x80092013 (-2146885613)

    ------------------------------------

    Revocation check skipped -- server offline

    Cert is an End Entity certificate

     

    ERROR: Verifying leaf certificate revocation status returned The revocation function was unable to check revocation because the revocation server was offline. 0x80092013 (-2146885613)

    CertUtil: The revocation function was unable to check revocation because the revocation server was offline.

     

     

    Ensure that the necessary firewall/network configuration changes to allow the IIS server to access ALL of the external CDP’s listed in the client cert’s revocation chain, or download the CRL(s) to the IIS server manually and set CertCheckMode to MD_CERT_CACHE_RETRIEVAL_ONLY (see this link http://technet2.microsoft.com/windowsserver/en/library/173427fd-eb90-44ef-8a9c-d7bb4ff41ab81033.mspx?mfr=true ).  That will tell IIS to look at the CRL in its local store and not try to attempt to access the CRL via the CDP entries specified in the client cert. 

    One more confusing point that should be clarified here:

    If you have a certificate chain, let's say: Root CA -> Intermediate CA1 -> Intermediate CA2 ->..... -><Your Client ceritficate>, then CRL checking will be done for all the Certificates in the hierarchy except the Root CA.

    If you are really interested to dig further as to how Certificate Revocation etc. works at a lower level, here is a real exhaustive link to check it out. 

    http://technet.microsoft.com/en-us/library/af1e419e-ede5-8c4b-bf6e-1fb17658a99d.aspx

    Another issue that pops up from time to time is: 

    "Choose a digital certificate" popup window in Internet Explorer is blank when attempting to use client certificates to authenticate against IIS.

    • This can happen in situations as explained earlier too in cases where:

    The total size of the certificates in the Trusted Root Certification Authorities store on the IIS server was too large to send to the client. The list was truncated as a result.

    The following event was written to the System log:
    Event Type: Warning
    Event Source: Schannel
    Event ID: 36885
    Description: When asking for client authentication, this server sends a list of trusted certificate authorities to the client. The client uses this list to choose a client certificate that is trusted by the server. Currently, this server trusts so many certificate authorities that the list has grown too long. This list has thus been truncated. The administrator of this machine should review the certificate authorities trusted for client authentication and remove those that do not really need to be trusted.

    Resolution would be to Remove unused certificates from the Trusted Root Certification Authorities store on the IIS server, reducing the number of certificates. 

    • Also another cause may be when the any of the Subordinate CAs->certificate->Details->Edit Properties button has Client Authentication disabled in the intended purposes.

    Also this should be of help at times http://support.microsoft.com/kb/285069/ 

    • Also if we have certificate trust list(CTL) enabled, CTL that IIS sends is what the client uses to know if it has a client cert it can use.
    • Also there is a <12kb> limit on this and if the customer has applied the Trusted Root CA update, then we may not send the full list of trusted CA’s. Make sure that CA is in CTL as well as the size limit. You may want to revisit the article http://support.microsoft.com/kb/933430. Either install the hotfix if it is applicable or try deleting/moving to other store some of the unused/junk CAs from the Trusted Root Certificate Authority Store on the IIS server. That could do the trick for you!

    Refer to one of our finest Escalation engineer (Andreas Klein)'s blog which talks about limiting the list of CA's allowed for Client authentication, without deleting the CAs from the store.

    http://blogs.msdn.com/andrekl/archive/2005/04/19/409682.aspx

    Also while you may have the certificate in your personal store (using the mmc snap-in it shows up properly), you may not see it in the IE browser. If you go through Internet Options->Content and click Certificates, it doesn’t show up at all. Open the certificate MMC and check whether the cert has a Private key or not.

    If the General tab on the cert properties does not say at the bottom that you have a Private Key corresponding to this cert then you don’t, and this may lead to the above problem.


    403.16 - Client certificate is untrusted or invalid.

    This error message is primarily generated when the certificate that the client provided is improperly formed. It can also be generated if there are intermediate certification authorities in the certificate chain that are not trusted by the Web server.

    403.17 - Client certificate has expired or is not yet valid

    This error message is fairly self-explanatory. It means that the current date on the server is not within the valid date ranges that are presented in the client certificate. You may also want to ensure that the client certificate and its issuing CAs (including Intermediate CAs) are not expired or invalid.

  • Care, Share and Grow!

    Wildcard SSL certificate in IIS 6.0, Windows 2003 Sp1 and above

    • 89 Comments

    Here I will be talking about configuring SSL wildcard certificates in IIS 6.0 on Win2k3 SP1 and above.

    You may have a scenario wherein you want to have the same certificate installed for multiple Websites. Now in a normal scenarios this is not possible.

    What I mean is you cannot have the same certificate installed on multiple Websites. To achieve a similar functionality you need to get a wildcard certificate from a Certificate Authority.

    A wildcard certificate can be applied when you have the same end-domain name for all your Websites wherein you want to install the certificate.

    Let's say you have Websites like www.test.com, mail.test.com and hrweb.test.com. Here the same end-domain name is present which is test.com.

    Also remember that you can install the certificate for all such Websites when all of them are running under the same IP/Port combination. Here host headers will be the identifying criteria for Websites.

    So let's say you have the following configuration:

    WebSite                   Host Header Value                  IP Address                Port             SSL Port
    ==================================================================
    Test1                          www.test.com                      10.0.1.1                     80                  443
    Test2                          mail.test.com                        10.0.1.1                     80                  443

    Test3                          hrweb.test.com                    10.0.1.1                     80                  443

    and you want to use the same certificate for all the above Websites, Wildcard certificate is a viable option.

    Here are the steps to obtain a wildcard certificate through IIS manager:

    -In IIS Manager, expand the local computer, and then expand the Web Sites folder.

    -Right-click the Web site for which you want to obtain a wildcard server certificate, and then click on Properties.

    -On the Directory Security tab, under Secure communications Button, click Server Certificate.

    -In the Web Server Certificate Wizard, click Create a new certificate.

    -Follow the Web Server Certificate Wizard, which will guide you through the process of requesting a new server certificate. You can have any name in the Wizard which shows Name and Security Settings. On the 'Your Site's Common Name' page, type a name in the Common name box, using the following format:
    *.<sitename> for example, *.test.com (as in our scenario).

    By default, the certificate request file is saved as C:\Certreq.txt, but the wizard allows you to specify a different location of your choice.

    -Click Finish to complete the wizard.

    After you receive the wildcard server certificate from the Certification Authority, assign the same certificate on all Web sites that have the same IP/port binding and are distinguished only by the host header name.

    Here is a Screenshot of the wildcard certificate that we got for our *.test.com sites.

    image

    Now at this point if you try to access any of the Websites you will see that all of the HTTPS responses come from one specific site.

    What I mean is that if you access https://www.test.com, https://mail.test.com or https://hrweb/test.com you will get the response from one site only.

    You won't get the corresponding web pages from different Websites depending upon the site in URL. You will  also see that only one of the Websites will be running. Other Websites will be in stopped state because we cannot have multiple Websites running with same IP and same SSL port binding (without of course some extra settings). If you try to start the other Websites you may see something like this below:

    image

    Now, the next most important thing is to follow the script below:

    Go to Start Menu, click Run, type "cmd", and then click OK.

    Type the following command at the command prompt:

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/<site identifier>/SecureBindings ":443:<host header>"                       <--- [It's not case sensitive]

    where host header is the host header for the Web site, for example, www.test.com or mail.test.com.

    e.g.

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/1/SecureBindings ":443:www.test.com"

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/2/SecureBindings ":443:mail.test.com"

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/3/SecureBindings ":443:hrweb.test.com"

    Now once we have these settings in place for the Websites you should be able to browse to the Websites. You will also be able to start all the Websites without any issues.

    Ensure that you do not modify any of the SSL related settings in the IIS manager like host header etc. after doing the changes in the metabase.

    Finally have SSLDiag handy in case you get into issues for any general SSL related troubleshooting :-)

  • Care, Share and Grow!

    Troubleshooting SSL related issues with IIS

    • 39 Comments

    In this post I am going to discuss troubleshooting SSL server certificate related issues in IIS. Please remember I am no SSL expert...I am an IIS Asp.Net guy and will discuss issues with regard to SSL with IIS.

    We have seen a lot many times that the issues could have been resolved by our customers if they were aware of some targeted troubleshooting techniques.

    Here I will be walking through the steps which you can follow yourself before requiring to call Microsoft PSS.

    Problem Description

    The most common error associated with SSL not working for an IIS website is "The page cannot be displayed" or "Cannot find server or DNS Error".

    Troubleshooting steps to be followed:

    First thing first: You notice the above error when you browse to your website over SSL (HTTPS). Do you also see the same behavior when you access the website over HTTP? If yes then there is a different problem you need to address first. SSL doesn't come into picture when we access a site over HTTP.
    So if you are facing the problem in both the scenarios ensure you first troubleshoot why the request is not reaching the IIS server...maybe a DNS configuration etc.

    My topic today is SSL with IIS so I won't be focusing on HTTP.

    We have the SSL port listed in IIS mmc as shown below. By default it's 443. You can configure it to listen on a different port.

    image

    Now, also check whether the issue is happening for all the users, i.e. External and internal users to the network. If the issue is happening only for let's say external users check whether the requests are coming over a firewall like ISA etc. At times Firewalls may block the SSL port. You may want to check the firewall settings to unblock the SSL port. Also firewalls like ISA requires certificate to be published on it as well apart from IIS server. Ensure that the certificate that we have installed on ISA is valid. In case of ISA, if you have renewed the cert on IIS server but not on ISA users will still see the old certificate and not the new certificate. Ensure that you replace the old certificate on ISA with the new certificate. Also you may want to check if the security gateway (if any) such as NFUSE (Citrix) controllers is still referencing the old certificate.

    Also at times if you see a wrong certificate being displayed for your Web Site, ensure that you do not have kernel-mode SSL enabled on your web server.Although this improves the performance but I recommend to have it disabled when you have multiple SSL enabled-websites on your server. Kernel-mode SSL is only recommended if you have just one site, mostly static content and no client certificates. In all other cases you should use User-mode SSL.

    Please find this link to enable/disable kernel-mode SSL. If it is set to 1 it means Kernel-mode SSL is enabled, if absent or set to 0 it means disabled and user-mode SSL will be used. Ensure that you stop and restart http service as shown below after doing the changes. No reboot is required for the above change.

    >net stop http

    >net start http

    >net start w3svc

    [There has been few concerns from people as to why this is suggested. I do not have a proper answer to it at this point, but I have seen such issues in some support incidents where disabling Kernel mode SSL had resolved the above problem]

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Now once you have isolated the issue to be only with HTTPS and all users let's proceed with the following steps:

    Run netstat -an (or fport.exe) for IIS 5 (and netstat -ano for IIS 6) and verify whether IIS is listening on the SSL port.

    When you start Internet Information Services (IIS) 6.0 on Microsoft Windows Server 2003, IIS binds to all IP addresses on the server, not just the IP addresses that are assigned to Web sites. This is because of socket pooling enabled for IIS by default.

    On IIS 6.0, if the website is listening on "All unassigned" IP address or some specific IP address (like 192.134.123.209 etc) and SSL port 443, verify that Local address entry is 0.0.0.0:443 in netstat output.

    > netstat -ano

    Active Connections

      Proto  Local Address          Foreign Address        State           PID
      TCP    0.0.0.0:21             0.0.0.0:0              LISTENING       2396
      TCP    0.0.0.0:25             0.0.0.0:0              LISTENING       2396
      TCP    0.0.0.0:80           0.0.0.0:0            LISTENING       4
      TCP    0.0.0.0:81             0.0.0.0:0              LISTENING       4
      TCP    0.0.0.0:83             0.0.0.0:0              LISTENING       4
        ...................

      TCP   0.0.0.0:443          0.0.0.0:0             LISTENING       4
      TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
      TCP    0.0.0.0:446            0.0.0.0:0              LISTENING       4

    Here the PID should show you which process is listening on that port.
    Now let's say I have configured my website to run on a specific SSL port and that port is being used by a different process, then website will not start up.

    Also you won't see the netstat output showing anything like this depending upon the port being used:

    TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       4

    TCP    0.0.0.0:443           0.0.0.0:0              LISTENING       4

    You can run netstat -ano again and see the PID corresponding to the process which is listening on that port. Stopping or disabling that service/process should allow Websites to be up and listening on the desired port. For IIS 5.x you can run Fport.exe to find out which process is listening on a specific port.

    The first thing that I check for (strictly my personal preference) when we have issues with SSL is MACHINEKEYS. Yes, this is a very important (I prefer to call strategic) part of your checklist while dealing with SSL issues. In my personal experience it has resolved a lot of issues for our customers. By default machinekeys folder should have permission for Administrator, System and Everyone according to this KB278381. Ensure that we inherit the above permission for all child objects under the machinekeys folder, that way all the machine keys have the necessary permissions.

    This is done by clicking the "Advanced" button on the security settings page, Clicking the check box "Replace permissions entries on all child objects...." and
    Apply. This will propagate the settings to the contents in the folder.

    Another reason for the above error ('The page cannot be displayed') can be if you do not have a private key corresponding to the SSL server certificate. You can check that by opening the IIS mmc -> <<YourWebSite>> ->Properties ->Directory Security ->Secure Communications ->View certificate ->General -> "You have a private key that corresponds to this certificate" as shown below.

    image

    If you do not see the above then SSL won't work for your website.
    You can try running the following command to recover the private key from the certificate thumbprint.

    To associate the certificate with its private key, we run the following command:

    > certutil -repairstore my "c9 66 67 68 49 97 88 7f 05 b8 89 b7 b3 f7 37 c8 c4 da 5f 16"

    Note: "c9 66 67 68 49 97 88 7f 05 b8 89 b7 b3 f7 37 c8 c4 da 5f 16" is the Thumbprint of the missing certificate. You can see this if you double-click on the .cer file, choose the Details tab and select Thumbprint.

    image

    Make sure you use the 2003 version of certutil.exe (with the associated certadm.dll and certcli.dll), or you will not have access to the repairstore command.

    If the above command does not get back the private key or for some reason it still does not work you may prefer to get a new certificate from the CA.

    One of the best tools that Microsoft has come up with is SSL Diagnostics to troubleshoot SSL related issues. Just download it to the IIS server and run it and if there is an error due to configuration of IIS or certificate it will show up. You can also use this tool to issue a test certificate for your website to check whether the problem was occurring because of your server certificate or some other IIS configuration related issues. Things that can be shown quickly through this tool includes on "no private key", "SSL port being used by a different process", "machine keys not having enough permission", "IP address conflicts" etc.

    Another scenario can be wherein if you view the certificate, it will state that "You have a private key that corresponds to this certificate," and if you run SSL Diagnostics, you'll get the error as below:

    #WARNING: You have a private key that corresponds to this certificate but CryptAcquireCertificatePrivateKey failed

    When you initially go through the IIS Certificate Wizard to create a new certificate, a file is added to the MachineKeys folder. This is the private key.

    If you add permissions to the new file in the MachineKeys folder before you process the pending request in the IIS certificate wizard, the certificate will work properly. If you've already gone past that point and got a new certificate, then necessary permissions should be added to the MachineKeys folder and a new certificate request must again be submitted.

    Now consider a scenario wherein you are able to access the site through SSL Diagnostics tool (through 'Simulate SSL Handshake') for the same certificate but not through IE. What I mean is your SSL handshake gives no error etc in SSL Diagnostics although when you access the website through IE over SSL it still fails. In that case there could be an IE setting that you may want to check for such a behavior. Check this out KB811834.

    Now one last scenario. At times we see customers coming up with requests wherein they want to use the same server certificate for multiple websites.

    This is not possible. You cannot use the same certificate for multiple websites on the same server. Check this KB187504.

    Now there is a workaround in IIS 6.0 Windows 2003 SP1, wherein you can use Wildcard certificates to get a similar functionality. Here is the link.

    If you have a Load balanced or clustered environment you can export the same certificate to all the servers and install them on the related websites. It should work fine.

    Hope this helps....let me know if there are any questions around the topic.

    Cheers!!!

  • Care, Share and Grow!

    You get a Security Alert when you try to access an SSL enabled web site when certificate has been issued by an internal root CA...

    • 11 Comments

    Let's say you have your own internal Root Certificate Authority (CA) and you use it to grant server certificates to your Web sites.

    You are able to browse to your web site over SSL and can access the page. Things look good so far.

    However you get an unwanted security alert all the time while accessing the page, stating the following:

     

    "The security certificate was issued by a company you have not chosen to trust.

    View the certificate to determine whether you want to trust the certifying authority"

    or,

    "This certificate cannot be verified up to a trusted certification authority" in the Certificate ->General tab.

     

    And if you have mobile access users they won't be able to access the page at all :-(, forget the Security alert.

    Also if your Web site is Internet-facing, that means both internal as well as external users should be able to access the web site, then you will see a little different behavior.

    What does it mean? Well, as the message description above clearly states we do not have information about the Root CA to verify whether it can be trusted for SSL transactions. Since you are using an internal Root CA for your Web site certificates, IE on the external client has no way to verify whether the root CA is trusted or not. IE has a list of default trusted root CA's.

    If you check IE->Tools->Internet Options->Content->Certificates->Trusted Root Certification Authorities, you will see a list of all the public Root CA's that are trusted by IE client like VeriSign, Go Daddy, Thawte etc.

     

    image

    image

    From an external IE (here assuming IE7) client, If you go to the Certificate Error->View certificates->"Certification Path" as in the above screenshot you should only see the Web site certificate listed.

    If you check the above from an intranet client you will see an hierarchy showing both the Root CA and the Web site certificates.

     

    Resolution:

    Why the above difference?

    Since Intranet client has access to the Internal Root CA they (IE) see the hierarchy of Root CA and the Web site certificate in the Certificate->"Certification Path",

    image

    You will be able to see both the root CA and the Web site certificate as above.

    But since root CA is not accessible for the Internet users they will only see the Web site certificate and not the Root CA certificate in the tree in the "Certification Path". Root CA will be absent altogether in the tree. Or else you will see an entry for the root CA but with a RED X meaning that CA Root certificate is not trusted as it is not in the Trusted Root Certification Authorities store on the client.

    image

    You get "This certificate cannot be verified up to a trusted certification authority" when the Certificate Authority is not running or is not visible to the client (IE). This generally happens when client cannot access CA for e.g. running your internal CA and users accessing the web site over Internet.

    We will have to install the root CA certificate on to the client computer in order to get rid of the security alert.

    For intranet users downloading and installing the .cer of the Root CA into the Trusted Root Certification Authority MAY resolve the issue.

    Else, here are the steps to successfully install the root certificate authority on to the client's trusted CA store:

    • On the IIS or Certificate Server, open MMC (Start->Run and type MMC) and add the Certificates snap-in using the Computer Account.
      -- Expand Certificates

    -- Expand Trusted Root Certification Authority.
    -- Right click on the correct Root Certification Authority -> Click Export, which opens the wizard. Choose the following in the wizard:
              a) Check "Cryptographic Message Syntax Standard - PKCS #7 Certificates (.P7B)"
              b) Check "Include all certificates in the certification path if possible" --> click Next
              c) Give it a relevant file name (in our case, say RootCAFileName) and choose the location --> Click Next
              d) Click Finish

    This will create RootCAFileName.p7b.
    -- Copy RootCAFileName.p7b to the client.
    -- It can be installed on the client machine in two ways: 

    By Right click on the RootCAFileName.p7b file or by using IE via Import.

    a)

    - Right-click on RootCAFileName.p7b -> Click "Install Certificate" -> Next
    - Click "Place all certificates in the following store" -> Browse
    - Select "Trusted Root Certification Authorities" -> Ok -> Next

    - Click Finish
    b)

    - Open IE -> Tools menu -> Internet Options
    - Go to the Content tab -> Click Certificates
    - Go to the "Trusted Root Certification Authorities" tab -> Click Import
    - Follow steps in the wizard to browse to the RootCAFileName.p7b file and place it in "Trusted Root Certification Authorities" -> Next
    - Finish

     

    Hope this helps...

  • Care, Share and Grow!

    Getting fatal error LNK1181: cannot open input file 'kernel32.lib'

    • 17 Comments

    I was a happy man until a few hours back when I was playing with some C, C++ programs built using Visual Studio 2008 on my work and home machines. I could write some program on my workstation, copy the solution to my personal laptop at home and thereby continue from where I left in office. Things  were good until I installed the latest Windows SDK v6.1 on my Vista laptop while trying my hands on Windows PowerShell.

    I realized a day or so later after installing SDK v6.1 that now I could not build my application written in C or C++. I could compile it but not link it during build process from within Visual Studio. Funny though I realized I could not even build a very basic Win32 console application.

    I started getting the following error:

    fatal error LNK1181: cannot open input file 'kernel32.lib' 

    I did something while troubleshooting it and now also started seeing:

    Error spawning 'rc.exe'. Project myProject

    I did check on the Internet and found all sorts of reasoning around this. One thing looked clear that installing the latest SDK v6.1 had caused me all these headaches. Some links suggested rebooting the server, some talked about  low system  memory, some said remove the latest SDK v6.1, and some also suggested to reinstall Visual Studio. But somehow I felt this can be fixed without reinstallation of VS2008 or un-installation of SDK v6.1 or etc etc and etc.

    I opened the cool Process Monitor tool and found the following:

    28836    11:51:31.5538847    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\VC\lib\kernel32.lib    NAME NOT FOUND    
    28837    11:51:31.5539987    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\VC\lib\kernel32.lib    NAME NOT FOUND    
    28839    11:51:31.5542065    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\lib\kernel32.lib    NAME NOT FOUND    
    28841    11:51:31.5543630    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\lib\kernel32.lib    NAME NOT FOUND    
    28842    11:51:31.5544705    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\lib\i386\kernel32.lib    PATH NOT FOUND    
    28844    11:51:31.5545935    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\lib\i386\kernel32.lib    PATH NOT FOUND    
    28846    11:51:31.5547253    devenv.exe    5528    QueryOpen    D:\Program Files\Microsoft SDKs\Windows\v6.1\lib\kernel32.lib    PATH NOT FOUND    
    28847    11:51:31.5548633    devenv.exe    5528    QueryOpen    D:\Program Files\Microsoft SDKs\Windows\v6.1\lib\kernel32.lib    PATH NOT FOUND    
    28848    11:51:31.5550927    devenv.exe    5528    QueryOpen    D:\Program Files\Microsoft SDKs\Windows\v6.1\lib\kernel32.lib    PATH NOT FOUND    
    28849    11:51:31.5552863    devenv.exe    5528    QueryOpen    D:\Program Files\Microsoft SDKs\Windows\v6.1\lib\kernel32.lib    PATH NOT FOUND    
    28850    11:51:31.5556190    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\kernel32.lib    NAME NOT FOUND    
    28851    11:51:31.5559045    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\kernel32.lib    NAME NOT FOUND    
    28852    11:51:31.5561361    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\lib\kernel32.lib    PATH NOT FOUND    
    28853    11:51:31.5563280    devenv.exe    5528    QueryOpen    E:\Program Files\Microsoft Visual Studio 9.0\lib\kernel32.lib    PATH NOT FOUND    

    It was crystal clear that while trying to link Visual Studio was encountering a file not found kind of error and hence could be the resulting failure.

    ------ Build started: Project: aa, Configuration: Debug Win32 ------
    Linking...
    LINK : fatal error LNK1104: cannot open file 'kernel32.lib'
    Build log was saved at "file://xxxxxxxxxxx\Visual Studio 2008\Projects\myProject\myProject\Debug\BuildLog.htm"
    myProject - 1 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    Similarly rc.exe showed NOT FOUND.

    It looked simple yet intriguing as to why the default path was changed for Visual Studio.

    I realized that the path it was trying to look at for these files did not even exist, lest I could just have copied these files to the corresponding location.

    Looked at the Environment variables from Visual Studio 2008 command prompt and found that WindowsSdkDir environment variable was pointing to D:\Program Files\Microsoft SDKs\Windows\v6.1\ which did not exist.

    Tried changing this to the path where I did find the above files on my box which was pointing to C:\program files\microsoft sdks\windows\v6.0A\ (So yes it pretty much looked like after installing SDK v6.1 my environment variable WindowsSdkDir had changed). Tried logging off/rebooting, no luck.

    Finally figured out that in order to get things back to normal I had to update the following registry key:

    HKEY_CURRENT_USER\SOFTWARE\Microsoft\MicrosoftSDKs\Windows\CurrentInstallFolder

    I changed this value to point to the original location which was C:\Program Files\Microsoft SDKs\Windows\v6.0A\ in my case.

    I wasted a lot of time on this, so thought of sharing with a wider audience.

    bye!

  • Care, Share and Grow!

    How to setup IIS and AD for Client certificate authentication

    • 17 Comments

    Hi All,

    This post talks about how Client certificates are configured on websites. I have seen a lot of incidents where people get into issues with client certificate in particular, although server (website) certificates can give a scare at times.

    Here I will be walking you through the steps of configuring client certificates in your Windows 2003 environment (although there is not much of a difference in Windows 2000).

    Environment

    Windows 2003 (Web server) IIS6.0

    Windows 2000/XP/2003 (Client)

    Windows 2003 (Microsoft Certificate server)

    Walkthrough

    1. To enable SSL transaction between the server and the client, you need to have a server certificate installed on IIS website. Websites can get the server certificate from a trusted root Certificate Authority (CA). We will be focusing on the steps for acquiring client certificates and setting them in IIS for user authentication.

    2. Here I will show the screenshot of the steps that one needs to follow with brief explanation of the steps.

    Client Workstation: WIN2kIIS-VPC

    CA server: WIN2K3DC

    IIA Web Server: WIN2K3OWA

    DC: WIN2K3DC

    Domain: Anjenya.local

    Requesting a client certificate from a Trusted root Certificate Authority (CA):

    Access the CA Website from your client machine as http://Win2k3dc/certsrv

    image

     

    There are two ways of obtaining client certificate.

    Click on the link: Request a Certificate.

    image

     

    Click on “Select a certificate type: User certificate”.

    You can also obtain the certificate by clicking on “advanced certificate request” to add more specific details about the client certificate.

    image

    Click on More Options >>

    image

    Go ahead and hit Submit >

    image

    Click on “Yes”

    image

    Go ahead and click on the link to install the certificate. You might get the certificate directly as above or through email etc when in case of a 3rd party after verification.

    image

    Click on “Yes”

    image

    Now the User certificate is successfully installed on your client machine.

    You can check the certificate in two ways:

    1. Goto IE->Tools->Internet Options->Content->Certificates.

    You should see the certificate there under Personal store, which was installed on your client machine.

    image

    1. Or else you can open the Certificate snap-in through Start->Run->Mmc->Console->Add/Remove Snap-in->Add… -> Certificates.

    image

    Go ahead and add the certificates snap-in.

    image

    Double click on the certificate and you should see the details about it:

    image

    Enhanced Key usage will show you the purpose of this certificate.

    image

    The above picture shows that this certificate is meant for Client Authentication.

    image

    So here we finish the process of acquiring the client certificate.

    Now the next step is to map the client certificate in IIS manager, depending upon one’s requirements. It can be one of the following:

     

    • Option to accept the client certificate from the user by the IIS website (with no mapping enabled).
    • Option to have 1-to-1 mapping for client certificate.
    • Option to have Many-to-one mapping for client certificate.
    • Option to have Active Directory Mapping for client certificate.

    1-to-1 and Many-to-1 mapping are simple to setup.

    Here I will walk you through the process of setting up the above configuration for 1-to-1 mapping and Active directory mapping.

    Let’s say that you have a website in IIS for which you want to enable client certificate.

    You need to go to IIS Manager->Default Website-> right click and go to Properties->Directory Security->Under Secure Communications section, click on Edit.

    image

    image

    Here in the picture above, you have three options for Client Certificates:

    • Ignore client certificates: IIS will ignore client certificate when a request reaches IIS website, even though web request has the certificate in it.
    • Accept Client certificates: IIS website will accept any client certificate from the user, if it is along with the web request.
    • Require Client certificates: IIS website will check for client certificate along with web request. If no client certificate is in the web request, users shall see 403.7 – Client certificate required, as the error message in the web page response.

    Now in the next section in the same picture above, if you want your website to be configured such that a client certificate is mapped to a user account, you can check on “Enable client certificate mapping”. What it means is that request will be executed in the context of an account.

    image

    Now, when you enable 1-to -1 Mapping, an individual client certificate will be mapped to a specific Windows account. So in case you don’t want any of the IIS authentication methods to be used, like Anonymous, Basic, Digest or Windows Integrated authentication, you can rely upon client certificate authentication based on 1-to -1 or Many-to-1 mappings.

    We will first go ahead with 1-to-1 mapping:

    Click on “Add…” in the Account Mappings window shown above.

    Now before you map a client certificate with a windows account, you need to have the corresponding client certificate on the server.

    Export the client certificate from the CA or the client machine (where you have the certificate installed) as follows:

    1) From Client machine: Open Certificate snap-in as earlier and go to Certificates – Current User -> Personal -> Certificates.

    image

    Double click on the selected certificate and Click on Details and go to “Copy to File…”.

    Follow the Export wizard.

    image

    image

    You can either Export the private key or not export it. You should know the meaning of exporting the private key.

    image

    Go ahead and save the client certificate somewhere on your workstation (client).

    image

    2) From CA:

    Go to the Certificate Authority Snap-in and check the following location:

    image

    image

    Double click to display the certificate. Click on “Copy to File...” and follow the Certificate Export Wizard, and save the file to the server as shown below:

    image

    Now copy the saved certificate from any of the above location to the IIS server, where we need to map it a windows account.

    Back to IIS manager console for certificate mapping:

    image

    Now map a specific windows account with this certificate as shown below:

    image

    image

    Once the 1 to 1 mapping is set in place go ahead and try browsing the site.

    Here I have used an ASP script to render the server variables pertaining to the web request.

    This script will display the logged on user name and the authentication type used along with some other information.

    Also when you want to use Client certificate authentication you can clear all other authentication options in the IIS manager Directory Security setting as show below:

    image

    Here you won’t get 401.2 server configuration error because we are using some sort of authentication mechanism (client certificate mapping) to authenticate the user. Had we been not using client certificate mapping we would have got 401.2 if we try to access the site with no authentication method selected in IIS manager.

    Had there not been Client cert mapping and we had tried to browse to the web page with all the options cleared as shown above, you would have got error 401.2.

    Here is the sample logoninfo.asp page which displays server variables. Try accessing this page.

    <%

    response.write ("LOGON_USER: ")

    response.write (request.servervariables("LOGON_USER"))

    response.write ("<BR>")

    response.write ("AUTH_USER: ")

    response.write (request.servervariables("AUTH_USER"))

    response.write ("<BR>")

    response.write ("AUTH_TYPE: ")

    response.write (request.servervariables("AUTH_TYPE"))

    response.write ("<BR>")

    response.write ("CERT_COOKIE: ")

    response.write (request.servervariables("CERT_COOKIE"))

    response.write ("<BR>")

    response.write ("CERT_ISSUER: ")

    response.write (request.servervariables("CERT_ISSUER"))

    response.write ("<BR>")

    response.write ("CERT_KEYSIZE: ")

    response.write (request.servervariables("CERT_KEYSIZE"))

    response.write ("<BR>")

    response.write ("CERT_SERIALNUMBER: ")

    response.write (request.servervariables("CERT_SERIALNUMBER"))

    response.write ("<BR>")

    response.write ("CERT_SERVER_ISSUER: ")

    response.write (request.servervariables("CERT_SERVER_ISSUER"))

    response.write ("<BR>")

    response.write ("CERT_SERVER_SUBJECT: ")

    response.write (request.servervariables("CERT_SERVER_SUBJECT"))

    response.write ("<BR>")

    response.write ("CERT_SUBJECT: ")

    response.write (request.servervariables("CERT_SUBJECT"))

    %>

    Now in our example we try accessing the above script and we get the following response:

    image

    In the above step, if you disable Client cert and enable windows integrated authentication only, you should see something similar to the one shown below:

    Check the Authentication type.

    image

    Similarly you can try Many-to-1 mapping, please read MSDN/KB articles that talk about how to set it up…it’s very similar to 1 to 1 mapping.

    I would like to discuss Active Directory Mapping in particular here:

    We need to have Client certificate enabled, we can remove 1-to-1 and many-to-1 mapping from IIS Manager since we need to enable AD mapping.

    In AD mapping we need to follow the following steps:

    Go to the IIS Manager, right click on root level WEBSITES->Properties->Directory Security.

    Select “Enable the windows directory service mapper”.

    image

    Now go to Active directory, open Active directory users and computers, go to Users, and then select the user for which you want to map the certificate.

    Right click on the user name, go to Name Mappings. Add the client certificate. Now we have a mapping for that certificate to a user account in the AD.

    Go to the client machine and logon with the user credentials , and then try accessing the site now, and now you should be able to access the page and you should see the Logon name in the webpage, here the logon name will correspond to the same user with which we have associated the client certificate in the AD.

    Now you should see something like this:

    image

    Remember this:

    Here is an excerpt from a TechNet article:

    In Active Directory mapping, when the IIS server receives a certificate from the user, it passes it on to Active Directory, which maps it to a Windows 2000/2003 user account. The IIS server then logs this account on.

    Active directory mapping is most useful when the account mappings are the same on all IIS servers. Administration is simplified because the mapping is done in only one place.

    Mapping in Active Directory can happen in one of two ways. The administrator can explicitly map a certificate to a user's account. This certificate can come from any source--as long as the root CA for that certificate is trusted for client authentication.

    UPN mapping can also be used. A UPN is automatically put into a certificate issued by an enterprise CA. If a certificate is passed to Active Directory for mapping, it is first examined for UPN mapping. If UPN mapping is not possible, the mapping set by the administrator is used.

    UPNs are in the form of userid@domain. If the certificate contains a UPN, the domain is within the hierarchy of the directory, and the CA that issued the certificate is trusted to put UPNs in the certificate, then the user's account is retrieved from the directory and logged on. All these conditions must be true before the user's account is retrieved. If any of these conditions is false, the directory is searched for a mapping set by the administrator.

    In Active Directory mapping, when the IIS server receives a certificate from the user, it passes it on to Active Directory, which maps it to a Windows 2000 or Windows Server 2003 user account. The IIS server then logs on the account.

    You can create an Active Directory mapping in one of two ways. You can rely on UPN mapping, or, if UPN mapping is not possible, you can manually map a certificate to the account of a user.

    Use Active Directory mapping when the account mappings are identical on all IIS servers. Active Directory mapping is easier to maintain than IIS mapping because you only have to create the mapping in one location.

    NOTE: Let’s assume that the user account with which we are trying to access the site doesn’t have a UPN name in the AD (this might happen in the case where the logged on user is a local user and not a Domain user) then in that case the logon credentials for the request will be the mapped user account for the certificate in the AD. Else, if the client certificate’s “Issued to” is a domain user account, then logon credentials will use that Account and not the mapped account associated with certificate. Also it will not respect user’s logged on credentials or server authentication method in IIS manager.

  • Care, Share and Grow!

    Troubleshooting Anonymous authentication failures in IIS

    • 33 Comments

    Recently I was checking MSDN and KBs for a quick check on troubleshooting anonymous authentication, and sadly I could not find a single article devoted to it (that's strictly my personal experience). We often get calls on issues related to Anonymous authentication failures and this is something which I feel a user can fix oneself without requiring our support. My aim in this post is to ensure people have a good troubleshooting strategy for anonymous authentication failures.

    As with all my posts I won't get into much of concept building stuffs here on anonymous authentication in IIS; reason again being the same, you will find tonnes of articles on the Net talking about it and I don't want to be another one.

    So in brief Anonymous authentication in IIS is a type of access wherein any user can freely access the site. It's like a public website open to all.

     

    So let's get started....

    Anonymous authentication uses a local or domain account when user tries to access a webpage in IIS (By default it is of the form IUSR_<machinename>).

    All the webpages which have anonymous authentication will use an account in order to access a page, and depending upon whether the account has permission or not the page will be rendered. Typically if anonymous authentication fails, you will see 401.1 in the error page shown by IIS. This means that Anonymous user account for that page doesn't have necessary permissions to the page or else some other settings like Domain or local policy is restricting the access.

    If you have set only anonymous authentication for your web resource (that means no other authentication like Windows integrated or Basic ), and it fails then you will be shown 401.1 directly without any challenge which generally prompts to enter credentials.

    Wanna know how IIS negotiates an authentication, check this.

    If you want to check the anonymous username being used for a website or a virtual directory, type in this command at the following location:

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs get w3svc/anonymoususername

    or,

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs get w3svc/<Website Identifier>/Anonymoususername

    or,

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs get w3svc/<Website Identifier>/<Virtual directory>/anonymoususername

    [If you get the result like: The parameter "anonymoususername" is not set at this node, it means it is inheriting the settings from its parent level.]

    If you want to check where all Anonymous username is set at a webserver level, you can type in:

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs find anonymoususername

    Typically the Anonymous username is in the form of IUSR_<machinename>, wherein machinename is the server name.

    Although you can set it to a different value by manually changing it. It can be a local account to the server or a domain account.

    A caveat here, it's a security risk if you make anonymous username as part of an Administrator group (remember it allows access to everyone on the net without asking for credentials).

    To set an anonymous username at a website level, you can type in:

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs set w3svc/anonymoususername <your desired username> (Remember to include quotes around the username). [This setting is at the global level, i.e. for all the websites in the server provided you don't manually override the settings at a specific website or Virtual directory level]

    or

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs set w3svc/<Website Identifier>/anonymoususername <your desired username> [At a specific website level]

    or

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs set w3svc/<Website Identifier>/<Virtual directory>/anonymoususername <your desired username>  [At a specific Virtual directory level in a specific website]

     

    I will move forward with specific issues one by one:

    Anonymous user account is locked out:

    Ensure that the account is not locked, disabled or expired.

    Password Synchronization issues:

    I have seen a lot of support calls (I mean a LOT) where password synchronization has been the issue, and this is very very simple to fix.

    Anonymous username's password are stored in two places in IIS 6.0: In the IIS metabase and in the SAM database.

    If the password at these places are not synchronized (not same), anonymous authentication will fail. They have to be same.

    So do this as the first step in troubleshooting:

    1) Find out how many places we have the anonymousername set by following the command I mentioned above. Here I mention it again:

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs find anonymoususername

    2) If you have it set at multiple places, find out the specific site you are having problem with. Check the anonymous username for it and then check the password.

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs get w3svc/<Website Identifier>/anonymoususerpass

    [You may find the password in encrypted format like ************. In such a case you need to modify the adsutil.vbs file to get the exact password. Open Adsutil.vbs in notepad from the above location and search for the function "IsSecureProperty(ObjectParameter,MachineName)".

    In this function IsSecureProperty(ObjectParameter,MachineName), you will find the following code:

     

    Function IsSecureProperty(ObjectParameter,MachineName)

    On Error Resume Next
    Dim PropObj,Attribute
    Set PropObj = GetObject("IIS://" & MachineName & "/schema/" & ObjectParameter)
    If (Err.Number <> 0) Then
    ReportError ()
    WScript.Echo "Error trying to get the property: " & err.number
    WScript.Quit (Err.Number)
    End If
    Attribute = PropObj.Secure
    If (Attribute = True) Then
    IsSecureProperty = True              <--------
    Else
    IsSecureProperty = False
    End If
    End Function

     

    In the highlighted line above, change the value to False, save and now rerun the adsutil.vbs command and you should see the actual password]

    or if you have it set at the global level only, check this:

    <Systemdrive>\Inetpub\Adminscripts>cscript.exe adsutil.vbs get w3svc/anonymoususerpass

    Copy the password from here and go to Computer management->System Tools->Local Users and Groups->Users

    You should find the username (By default, IUSR_<machinename> is used by IIS) [Unless you have Domain controller and Web server running on the same box. In such a case you need to look for the domain user name under Active Directory Users and Computers. I will talk about DC and IIS running on the same box later, this is really important!]

    Change the password for Username (or, IUSR_<machinename>), by pasting the password that you got from metabase.

    Ideally, if the issue was with Password synchronization your problem should get resolved at this point :) If not, then move on....

     

    NTFS permission for the requested web resource:

    NTFS permissions not set properly for the content can also cause 401.1 (although you should typically see 401.3 Access denied due to ACL). Ensure that the page we are trying to access has necessary NTFS permissions for Anonymous username (or the group that anonymous username belongs to). Ensure that Anonymous user account is part of the Users group.

    Policy settings:

    If your issue did not get resolved by Password synchronization, then Local security policy (or, Domain security policy) can be a very probable reason. Please follow the following articles religiously.

    Default permissions and user rights for IIS 6.0  (IIS 6.0)

    How to set required NTFS permissions and user rights for an IIS 5.0 Web server (IIS 5.x)

    Check this too.

    Error message when you try to view a Web site that is hosted on Internet Information Server 6.0 by using anonymous access: "401.1 Unauthorized: Logon failed"

    Typical reasons being:

    - Anonymous username being a part of Guests group (During IIS installation, IUSR_<machinename> is added to the Guests group by default), and Guests group being denied access to some web folders and/or denied access because of local/domain policy).

    Suggestion: Make sure that either you remove the anonymous username from the Guests group and/or remove the Anonymous username from any of the Deny policy settings (You can do this by going to the Local Security policy->Local Policies-> User rights assignment).

    - The account is corrupted because of some reason like corrupted SID, moving the server from one domain to another etc.

    Suggestion: First try adding the Anonymous username to the Administrators group to check whether you can access the web page or not. If it works it means it's an issue most likely with the permission for that account. If it still does not work, then there is some thing wrong..may be Policy settings or a corrupted account. Change the Anonymous user account to a different account and see if it works (be sure to make that account part of IIS_WPG group). If it works then it's a corrupted account. Recreate the IUSR and IWAM accounts (you can recreate by deleting existing IUSR_machine and IWAM _machine and then doing an IISRESET. IISRESET will recreate the IUSR and IWAM accounts for you) or manually creating a new user.

    - Check this The account that is used for anonymous access may be unexpectedly locked out in IIS 6.0 or in IIS 5.0

    At times you may see that HTML pages are running fine but not ASP pages. They might throw error like 401.3 etc. Check whether Users group has permission on ASP.dll at the <systemdrive>\wind*\system32\inetsrv folder.

    Account Lockout:

    Now something that creates confusion among a lot of people. At times people see their anonymous account getting locked intermittently and there seems to be no valid explanations for it.

    Scenario: You have set anonymous username at multiple levels in IIS.

    Let's say you have different usernames at the following level:

    Global Web Sites level  {IUSR_m1}

              Website 1   {IUSR_m2}

            VD1    {IUSR_m3}

            VD2    {IUSR_m2}

            VD3    {IUSR_m2}

     

    Website 2  {IUSR_m2}

    Now, let's assume you have different passwords at different levels. Now in the SAM database you can have only one instance of an account and hence only one password for it. Let's say you accidentally change the password for IUSR_m2 in the metabase at Website1 ->VD2 level and forget to change the password at the Website1, Website1->VD3 and/or Website2 level. Now since the password has to match in the SAM metabase too, only one of these will work. Also by mistake a wrong password can be set at a given level.

    1) If you changed IUSR_m2's password in the SAM database to reflect Website1->VD2, then Anonymous authentication works fine when you access a resource from Website1->VD2. Although now, anonymous authentication will fail when you access a resource from any of Website1, Website1->VD3 or Website2 levels.

    2) If you have the IUSR_m2's password in the SAM metabase reflecting the password set at any of Website1, Website1->VD3 and Website2 (assuming all of them have same password for simplicity sake), then anonymous authentication will succeed when you access a resource from any of the above levels, but will fail when you access a resource from Website1->VD2 level.

    Now most servers have an Account lockout policy after certain invalid logon attempts. So if users try to access the Web resources from different levels, at one point of time because of multiple attempts Anonymous user account will get locked out and this will block access from all the levels irrespective of the matching passwords in Metabase and SAM database.

    So IUSR_m2 might get locked intermittently because of the above scenario and will give unpredictable results. That's why I recommend to use a single Anonymous username at the global level only and let all the websites inherit from there,or else use completely distinct accounts at various levels (it again finally depends upon your requirement specific to the system).

     

    IIS and Domain Controller (DC) on the same server:

    Also, if your IIS server is a DC then you need to check:

    <Anonymous useraccount>-->Properties-->Account-->Logon Hours..., [Ensure we have Logon Hours permitted for the account]

    and <Anonymous useraccount>-->Properties-->Account-->Log On To..., [Ensure we have Logon to the machine enabled]

    Please keep this handy when you are troubleshooting issues on a DC for IIS authentication.

    Generally, DCs are very restricted when it comes to Permissions and access policies. Hence we have seen a lot of issues related to anonymous authentication failures on DCs. Microsoft recommends not to use a machine both as a DC and an IIS server from Security and Performance perspective.

  • Care, Share and Grow!

    New features in SETSPN.EXE on Windows Server 2008

    • 4 Comments

    The version of Setspn.exe that came with Microsoft Windows Server 2000/2003 Support Tools did not have features to detect duplicate SPNs. The new version of Setspn.exe that comes bundled with Windows Server 2008 utilities has some really cool features. For someone dealing with the dreaded Kerberos authentication failure issues on a daily basis like me it's a sigh of relief.

    If you try the following command on the Windows Server 2008 you will see the various new options (or switches) available.

    image

    Notice the modifiers/switches:

    -F = perform the duplicate checking on forestwide level

    -S = add arbitrary SPN after verifying no duplicates exist

    -Q = query for existence of SPN

    -X = search for duplicate SPNs

     

    Searching for duplicate SPNs using Setspn.exe:

    D:\>setspn -X http/www.test.com
    Processing entry 0
    http/www.test.com is registered on these accounts:
        CN=mstest,CN=Users,DC=<some-DC-primary>,DC=<some-DC-secondary>
        CN=<IIS-servername>,OU=Domain Controllers,DC=<some-DC-primary>,DC=<some-DC-secondary> 
    
    found 1 group of duplicate SPNs.
    

    Searching for the existence of an SPN in the domain:

    D:\>setspn -Q http/www.test.com
    CN=<IIS-servername>,OU=Domain Controllers,DC=<some-DC-primary>,DC=<some-DC-secondary>
        http/www.test.com
        ldap/2334590-45566-113f....
        HOST/<IIS-servername>
        HOST/<IIS-servername.<some-DC-primary>.<some-DC-secondary>
        .......
        .......
    CN=mstest,CN=Users,DC=<some-DC-primary>,DC=<some-DC-secondary>
        http/www.test.com 
    
    Existing SPN found!
    

    Adding an arbitrary SPN after verifying no duplicates exist in the domain:

    D:\>setspn -S http/www.test.com <IIS-servername>
    CN=mstest,CN=Users,.<some-DC-primary>.<some-DC-secondary>
        http/www.test.com 
    
    Duplicate SPN found, aborting operation!
    
    

    Adding an arbitrary SPN after verifying no duplicates exist in the forest:

    D:\>setspn -F -S http/www.test.com <IIS-servername>
    Operation will be performed forestwide, it might take a while.
    CN=mstest,CN=Users,DC=<some-DC-primary>,DC=<some-DC-secondary>
        http/www.test.com
    CN=mstest1,CN=Users,DC=<some-DC-primary>,DC=<some-DC-secondary>
        http/www.test.com 
    
    Duplicate SPN found, aborting operation! 
    

    So what does this mean? It means you no longer have to depend upon boggling commands using LDIFDE or your own custom scripts to find out the duplicate SPNs. This is a good news indeed!

    *Prior to this using Windows Server 2000/2003 Support Tools we could use commands using LDIFDE to find duplicate SPNs as below:

    Syntax:

    ldifde -f <filename> -d "<dc=domain-netbiosname,dc=primary-domain>" -l serviceprincipalname -r "(serviceprincipalname=<serviceprincipalname-to-check-for-duplicates>)" -p subtree

    For example, if the domain name is test.abcd.com and the site URL is http//test.abcd.com command should be as shown below:

    ldifde –f C:\log.txt -d "dc=test, dc=abcd, dc=com"-l serviceprincipalname –r "(serviceprinicpalname=http/test.abcd.com)" -p subtree

    With the newer version of Setspn hopefully the dependency on the above command should reduce drastically.

    Till next time,

    Cheers!

  • Care, Share and Grow!

    Troubleshooting TS Gateway connectivity on Windows 2008, IIS 7.0

    • 10 Comments

    Here is something which is not my domain but had to learn the hard way. I recently encountered an issue while enabling Terminal Services Gateway (TSG) on Windows 2008 server. TSG is coupled with IIS 7.0 hosted on Windows 2k8 server and that's how I came into picture. TSG in simple terms is a feature using which one can connect remotely to an internal network over secure HTTPS port 443 from the Internet. Earlier Remote Desktop Protocol (RDP) connections used TCP port 3389. In many corporate environment this port may be blocked by the firewall. However now with TSG connecting on port 443 (common SSL port for http traffic) user should not get into the common issues of port being blocked. In my case we had the TSG installed as one of the roles on the server. The setup was fine.
    The only concern was that we already were using the Default Web site for some application. It can also happen otherwise, you have the TSG setup on an IIS 7 web site and if you go ahead and install let's say Exchange on top of it under the same site it may break the TSG functionality.

    When you install TSG, it creates two virtual directories called Rpc and RpcWithCert under the web site as shown below.

    image

    Under the hood it appears a call is made for

    http://<server-name>:443/rpc/rpcproxy.dll?localhost:3388 when you try to connect through TSG. So yes IIS is very much involved here.

    Now what can you do to fix this, perhaps you can install your web application (say Exchange) on some other web site and a different SSL port like 444 and have TSG site listening on port 443. Or else just the opposite.

    In my case we went with the 2nd option since we didn't want Exchange to be reinstalled again.
    But even if you use either of the above options it may not go that smoothly as it looks to be.

    You may see the error as shown below when you try to use terminal service through TSG.

    image Click on OK...

    image

    If you are seeing something like this, as a workaround create a new web site and copy the settings for the Virtual directories /Rpc and /RpcwithCert from the previous site to the the new web site. You can do this easily by copying the configuration in the applicationHost.config file.

    Here are the steps:

    1. Copy the following configuration (in the ApplicationHost.config file from C:\<Windows>\System32\inetsrv\config) from the previous site to the new site to add the virtual directories for your new web site.

    <site name="<new-web-site>" id=...>
    ...
    <application path="/Rpc" applicationPool="SomeAppPool">
           <virtualDirectory path="/" physicalPath="C:\Windows\System32\RpcProxy" />
    </application>
    <application path="/RpcWithCert" applicationPool="SomeAppPool">
            <virtualDirectory path="/" physicalPath="C:\Windows\System32\RpcProxy" />
    </application> 
    ...
    </site>

    So this will create two virtual directories in your new web site called Rpc and RpcWithCert.

    image

    Add an SSL binding for the new Web site on port 443 as well. Ensure no other site is listening on port 443.

    2. Copy the following for the previous web site in the ApplicationHost.config file to the new web site.

    This is the section contained in the Location tag for the Virtual directories /Rpc and /RpcWithCert. You need to copy this section from the location tag for the <previous-web-site> and add it to the location tag for the <new-web-site>.

    <location path="<previous-web-site>/Rpc">
            <system.webServer>
                <directoryBrowse enabled="false" showFlags="Date, Time, Size, Extension" />
                <handlers accessPolicy="Execute">
                    <add name="RPCPROXY" path="*" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\system32\RpcProxy\RpcProxy.dll" requireAccess="Execute" />
                </handlers>
                <serverRuntime uploadReadAheadSize="0" />
                <defaultDocument enabled="true" />
                <modules>
                    <add name="PasswordExpiryModule" />
                </modules>
                <security>
                    <requestFiltering>
                        <requestLimits maxAllowedContentLength="2147483648" />
                    </requestFiltering>
                    <authentication>
                        <anonymousAuthentication enabled="false" />
                        <basicAuthentication enabled="false" />
                        <windowsAuthentication enabled="true" useKernelMode="false" />
                    </authentication>
                    <access sslFlags="Ssl, Ssl128" />
                </security>
                <httpErrors>
                    <remove statusCode="401" />
                    <error statusCode="401" path="C:\Windows\system32\RpcProxy\Error401.txt" responseMode="File" />
                </httpErrors>
            </system.webServer>
        </location>
    <location path="<previous-web-site>/RpcWithCert">
            <system.webServer>
                <directoryBrowse enabled="false" showFlags="Date, Time, Size, Extension" />
                <handlers accessPolicy="Execute">
                    <add name="RPCPROXY" path="*" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\system32\RpcProxy\RpcProxy.dll" requireAccess="Execute" />
                </handlers>
                <defaultDocument enabled="true" />
                <security>
                    <authentication>
                        <anonymousAuthentication enabled="false" />
                        <basicAuthentication enabled="false" />
                        <clientCertificateMappingAuthentication enabled="true" />
                        <digestAuthentication enabled="false" />
                        <windowsAuthentication enabled="false" useKernelMode="false" />
                        <iisClientCertificateMappingAuthentication enabled="true" />
                    </authentication>
                    <access sslFlags="Ssl, SslNegotiateCert, SslRequireCert, Ssl128" />
                    <requestFiltering>
                        <requestLimits maxAllowedContentLength="2147483648" />
                    </requestFiltering>
                </security>
                <serverRuntime uploadReadAheadSize="0" />
                <modules>
                    <add name="PasswordExpiryModule" />
                </modules>
                <httpErrors>
                    <remove statusCode="401" />
                    <error statusCode="401" path="C:\Windows\system32\RpcProxy\Error401.txt" responseMode="File" />
                </httpErrors>
            </system.webServer>
        </location> 


    3. Ensure that we replace <previous-web-site> with the <new-web-site> in the following tags above:

    <location path="<previous-web-site>/RpcWithCert"> -----> <location path="<new-web-site>/RpcWithCert">

    <location path="<previous-web-site>/Rpc">  -----> <location path="<new-web-site>/Rpc">

    4. Run iisreset from the cmd prompt. Or it may also work with just restarting W3SVC service (net stop w3svc, net start w3svc).

    Go ahead and test RDP over TSG from the client. If it still doesn't work you may have to try the 5th step as below.

    5. Add the following registry entry. Run this from the cmd prompt:
    > reg add HKLM\Software\Microsoft\RPC\RpcProxy /v Website /t REG_SZ /d  <new-web-site>

    One last thing, ensure that the certificate issued to the TS server gateway is trusted on the client from where we are doing a terminal login.

    Happy troubleshooting!

    Cheers Martini Glass

  • Care, Share and Grow!

    Export SQL table records to XML form

    • 1 Comments

    I am not a SQL guy. But while working on something I found this which seemed cool to me. So thought of sharing it with folks in case you are not aware. Using SQL Management studio and running T-SQL command we can export the Database table entries into an XML form.

    Let's say you run this SQL command in the SQL editor.

    SELECT * from Saurabh.dbo.Customers

    And we get the following output in the table.

    clip_image001

    Now in order to export the table content into an XML form we need to use FOR XML PATH as below:

    SELECT * from Saurabh.dbo.Customers

    FOR XML AUTO

    clip_image002

    Or

    SELECT * from Saurabh.dbo.Customers

    FOR XML RAW

    clip_image003

    Or

    SELECT * from Saurabh.dbo.Customers

    FOR XML PATH

    Or

    clip_image004

    …..

    Or

    SELECT * from Saurabh.dbo.Customers

    FOR XML PATH('Customer')

    clip_image005

    …….

    If you want to wrap the content under a specific ROOT node use the following:

    clip_image006

    ….

    ….

    clip_image007

    It may not be something new for the SQL folks but this was something new to me.

    Reference:

    http://msdn.microsoft.com/en-us/library/ms189885.aspx

    http://theengineroom.provoke.co.nz/archive/2007/04/27/using-for-xml-path-a-primer.aspx

    till next time….

  • Care, Share and Grow!

    Troubleshooting FTP related issues on IIS 6.0

    • 9 Comments

    Troubleshooting FTP related issues on IIS can be a real pain. If you have not encountered so far you are lucky:-)

    What I do generally is to create a new FTP site and make it to work rather than working on the already corrupted site. It depends on your personal choice depending upon how much you want to invest.

    Here I will be talking about some issues and relevant troubleshooting that you can do to resolve the issue.

    To start with, there are three modes in IIS 6.0 using which you can setup an FTP site. Now these modes are different isolation levels for FTP users such that they can access only restricted folders within their dedicated home directory and sub-directories.

    These are:

    1. Do not isolate users (This is same as the only mode available in IIS 5.0)

    2. Isolate users (This is applicable for local as well as domain users, and is not integrated with Active Directory (AD))

    3. Isolate users using Active Directory (Also called Active directory user isolation mode, applicable only for AD users, integrated with AD)

     

    Here is the Screen shot of the options available when you create a new FTP site.

    image

     

    1. Do not isolate users (Users can access the FTP home directory of other users)

    Now in the first mode (Do not isolate users) there is a security risk wherein unauthorized access is possible since FTP do not provide any mechanism to isolate users by itself. You will have to make sure the NTFS permissions (ACLs) are properly set to deny unauthorized users. The wizard clearly shows that users can access the FTP home directory of other users.

    ***In IIS 6.0 with an FTP site running in the above mode, users may not be able to logon directly to the root folder of the FTP site. Instead they may be automatically routed a folder created just for them under the FTP root. Now this is by design and it may happen when there is a sub-folder inside the FTP Root folder that matches the users' alias (logged-on username). In such a case they will automatically be placed into that folder upon logon.

    To work around this behavior, it is necessary to place another folder level between the users and the Root folder of the FTP site.

    2. Isolate users

    image

    This is one of the new FTP modes available in IIS 6.0 (not available in IIS 5.0) wherein users can be isolated from each other by FTP itself and they will be taken directly to their home directory instead of the FTP root directory. This mode can be set for local as well as domain user accounts. However you need to ensure that we have proper directory hierarchy maintained for each user from the FTP root onwards. I will shortly show you how. Any user who has logged on to his/her FTP home directory won't be able to access the home directory of other users provided you restrict them using NTFS permissions.

    If you want to have an FTP site for local user accounts and want isolation such that users should be taken directly to their home directory here is the hierarchy you need to follow:

    Let's assume the root directory for the FTP site is C:\FTPRoot (You may change it to whatever location you want). Now you need to have a folder named "LocalUser" just underneath the FTP root directory. And under this folder (LocalUser) you need to add sub-folders for different users. Remember to have the name of the sub-folder same as the local user account. And for domain users you need to create a folder with the same name as the <domain> and under it you need to create sub-folders for every domain user.

    Pictorially it should be like this:

    Here I have the domain name as Saurabh1.com.

    image

    So I have the following folders for my FTP site based on the users.

    ftpuser1 and ftpuser2 are local user accounts and saurabh1\domainuser1 and saurabh1\domainuser2 are domain user accounts.

    Also notice that if you allow anonymous access to the site you need to have a public folder inside the LocalUser folder as shown above.

    Also you can have as many virtual directories as you want under the FTP site for various users. Whenever the user logs on to the site with their credentials they will be taken to their own respective folders.

    image

    If you look into the screen capture below a user cannot go above his/her home directory. User will be confined to their own folder or sub-folders.

    image

    Also it is recommended to ensure we have proper NTFS permissions set in place. Do not allow access to any other account except administrator/System to the user's folder. Obviously user should have the necessary permissions dedicated to him/her on that folder. If you have Anonymous account enabled users will be taken directly to the public folder (to be more precise it depends upon the FTP client in use. FTP.exe will prompt you to enter the username/password whereas IE will directly take you to the public folder).

     

    3. Isolate users using Active Directory (AD) isolation mode

    Here are the steps for AD isolation mode. It is not meant for local users account and only for Active directory users. Please follow the steps carefully since AD isolation mode issues can be a bit tricky to resolve :-)

    image

    Here below add the domain admin account and make sure you click on Browse to select the user account and not just manually type it.. I have a reason for asking that.

    image

    Create Virtual directories for each of the domain accounts that will be used for accessing the FTP site. Be sure to name the virtual directory identical to the
    username of the user who will be logging in. For instance, the user account of User1 will need a virtual directory named User1. Please remember that it is not a must to have a separate virtual directory for all the users under the root FTP site. Based on the commands mentioned below, users will be automatically taken to their respective folders and they need not have a Virtual directory created under the FTP site.

    Then, Run the IISFTP.vbs script as below:

    In a command prompt, navigate to C:\windows\system32 and run the VBScript iisftp.vbs twice (with different arguments shown below) for each user that will need access to the FTP site. This will do the necessary changes to the user account in AD's LDAP database.

    [Words underlined are your variables]

    For user1:

    C:\windows\system32> Cscript iisftp.vbs /setadprop domainuser1 ftproot C:\ftproot\adroot

    Microsoft (R) Windows Script Host Version 5.6

    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

    The value of ftproot for user domainuser1 has been set to C:\ftproot\adroot

    C:\windows\system32> Cscript iisftp.vbs /setadprop domainuser1 ftpdir  folder1

    Microsoft (R) Windows Script Host Version 5.6

    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

    The value of ftpdir for user domainuser1 has been set to folder1

    [Remember in the above command for ftpdir you need to set the folder name for the user account and not the complete path i.e. although the user's directory is set to C:\ftproot\adroot\folder1, you should mention "folder1" in the command as mentioned above and not the complete path].

    ftproot specifies the complete path for the parent folder (root) and ftpdir specifies the name of the user's folder. Here if you had a remote UNC share for the FTP contents you can change the command to, Cscript iisftp.vbs /setadprop domainuser1 ftproot \\ftpserver\ftproot\adroot

     

    Similarly for user2:

    C:\windows\system32> Cscript iisftp.vbs /setadprop domainuser2 ftproot C:\ftproot\adroot    <--- [It can be a different location other than the ftproot for user1]

    Microsoft (R) Windows Script Host Version 5.6

    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

    The value of ftproot for user domainuser2 has been set to C:\ftproot\adroot

    C:\windows\system32> Cscript iisftp.vbs /setadprop domainuser2 ftpdir folder2

    Microsoft (R) Windows Script Host Version 5.6

    Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

    The value of ftpdir for user domainuser2 has been set to folder2

    Now before you try accessing the site using account domain\username ensure that you have the necessary folder hierarchy in place as set up in the above commands, i.e. if you do not have an existing path C:\ftproot\adroot\folder1 you will get the following error message:

    User Saurabh1\domainuser1 cannot log in, home directory inaccessible.

    Login failed.

     

    Also in an AD isolation mode you won't see the option to allow anonymous connections. Check the difference between an AD isolated site and a non-AD isolated site. Notice the number of tabs in each.

    image          image

     

    If you already have an FTP site and you don't know the isolation mode for it you can open the metabase.xml file from C:\windows\system32\inetsrv and search for the tag UserIsolationMode and check its value.

    FTP site having mode as:

    • Do not isolate users (this is same as the only mode available in IIS 5.0) ---------> will have UserIsolationMode set to 0
    • Isolate users (this is applicable for local as well as domain users)   -----------> will have UserIsolationMode set to 1
    • Isolate users using Active Directory (also called Active directory user isolation mode, applicable only for Active directory users)  -----> will have UserIsolationMode set to 2.

     

    Checklist:

    When you try to visit an AD isolated FTP site from a command prompt, you may receive the following error message:

    530 User <Domain>\<UserName> cannot log in, home directory inaccessible.
    Login failed.

    This problem can occur because of any one of the following reasons:

    • The msIIS-FTPDir or msIIS-FTPRoot properties for the User Account that is trying to access the FTP site are not configured in the Active Directory.
      Make sure that msIIS-FTPDir and msIIS-FTPRoot properties for the user account are configured properly. To do this, open up a command prompt on the IIS server and browse to C:\Windows\system32 folder. Run the following commands:

    C:\WINDOWS\system32>cscript iisftp.vbs /GetADProp <username> FTPRoot
    C:\WINDOWS\system32>cscript iisftp.vbs /GetADProp <username> FTPDir

    If you get a valid FTPDir and FTPRoot returned as a result of this command, which means these properties are set correctly. The actual path of the user's folder will be <FTPRoot>\<FTPDir>. If the result of either of the commands is something like

    The value of FTPDir for user <username> is:
    null

    This means that the FTPDir and FTPRoot are not set correctly. You can set them as mentioned some way above.

    • The account that is set in the IIS Metabase as the ADConnectionsUserName key for the FTP site is having some issues.

    It may have been locked out or is not having enough permissions to query the Active Directory. The password for account connecting to AD in ADConnectionsPassword may be incorrect.

    Make sure that the password is correct and that the account is not locked out. Also ensure that the account that is configured here has enough permissions to query the Active Directory.

    To check the username and password set in the metabase, run the following commands:

    C:\Inetpub\AdminScripts> Cscript adsutil.vbs get msftpsvc/<FTP site identifier>/ADConnectionsUserName

    C:\Inetpub\AdminScripts> Cscript adsutil.vbs get msftpsvc/<FTP site identifier>/ADConnectionsPassword

    [You may find the password in encrypted format like ************. In such a case you need to modify the adsutil.vbs file to get the exact password. Open Adsutil.vbs in notepad from the above location and search for the function "IsSecureProperty(ObjectParameter,MachineName)".

    In this function IsSecureProperty(ObjectParameter,MachineName), you will find the following code:

    Function IsSecureProperty(ObjectParameter,MachineName)

    On Error Resume Next
    Dim PropObj,Attribute
    Set PropObj = GetObject("IIS://" & MachineName & "/schema/" & ObjectParameter)
    If (Err.Number <> 0) Then
    ReportError ()
    WScript.Echo "Error trying to get the property: " & err.number
    WScript.Quit (Err.Number)
    End If
    Attribute = PropObj.Secure
    If (Attribute = True) Then
    IsSecureProperty = True              <--------
    Else
    IsSecureProperty = False
    End If
    End Function

    In the highlighted line above, change the value to False, save and now rerun the adsutil.vbs command and you should see the actual password]

     

    • IIS server is not able to contact the Active Directory.

    =================================================XXXXX=====================================================

    We have seen a lot of confusion among people related to Active and Passive modes in an FTP site. I was intending to write a post on it but luckily though I found a very good article on the net. You can check this if you have some confusion on Active versus Passive FTP modes.

    Ftp.exe in Windows is an active mode FTP client and IE by default is a Passive mode FTP client. You can change the settings for IE as per this KB323446

  • Care, Share and Grow!

    Required permissions when calling a Web service using client certificate for authentication in an ASP.NET Web application

    • 10 Comments

    A Web service requiring Client certificate authentication is a common scenario.

    You may have a client application which needs to send the Client certificate as part of the web request for accessing the web service.

    This client application may be a Windows/Console application or another Web application.

    Often you will get into issues wherein you are able to send Client certificate as part of the web request from a windows/console app but not from another web app. The primary reason for this could often be around Web app not being able to send the client cert to the target Web service.

    This can happen for multiple reasons, in particular account under which Web app is running doesn't have enough permissions to access the Client cert in its local certificate store.

    Refer to this excellent kb for this for more details.

    In this post I want to highlight ways in which you can grant access to the Web application account to access the Client certificate in its local machine store.

     

    When we have to send client cert as part of the web service call from a web app we need to ensure that the client cert is installed in the Local Computer -> Personal Store on the local box (where Web app is running). By default you will see the client cert installed in the Local User Store for the user who requested and installed the cert on the machine. You need to ensure first that the client cert is installed on the Local Computer Store instead of the Local User Store and then follow any of the methods below to grant access to the private key for the account (under which your web app is running).

     

    Method 1:

    The above article kb gives an example of granting access using the Microsoft Windows HTTP Services Certificate Configuration Tool

     

    > WinHttpCertCfg.exe -g -c LOCAL_MACHINE\MY -s " IssuedToName " -a " AccountName "

    for e.g.

    > WinHttpCertCfg.exe -g -c LOCAL_MACHINE\MY -s " IssuedToName " -a "Network Service"

     

    There are other ways in which you can achieve the same result. This feature is in fact built in on Windows Server 2008 within the Certificate mmc console.

     

    Method 2:

    Using the WSE X509 Certificate tool (This tool has features that can be used to check certificate properties).

    You need to download Web Services enhancements (WSE) 2.0+ SP3 for Microsoft.Net and in the install wizard ensure you select Tools as shown below:

     

    image

    Once installed go ahead and launch the tool. It has a clean UI. You have the option to check certificates in the Local Computer/Current user for the available stores like Personal/Trusted/Intermediate Root CA etc. If you click on View Private Key File Properties (shown below) you can directly modify the permission for private key associated with the certificate. Basically this is just a file under C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys on Win2k3 server and  C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys on Win2k8 server.

     

    image

    You may want to go ahead and give the Service account under which the web app is running Full permission on this file (modify the permissions from the Security tab).

     

    Method 3:

    If you are running the web app on Windows Server 2008/Vista there is a far simpler way built in the Certificate mmc.

    image

    Right click on the certificate and go to All Tasks -> Manage Private Keys and then give Full permission for the associated account.

     

    Till next time..

    Cheers!

  • Care, Share and Grow!

    HTTP to HTTPS (SSL) Web Request Redirection

    • 13 Comments

    We often get requests from our customers asking how they can seamlessly redirect web requests from HTTP to HTTPS, i.e. how they can redirect a non-SSL request to an SSL based request. Recently a colleague of mine got a similar issue and we decided to use some existing scripts that we had in our database. Unfortunately none could meet the requirement.

    Basically the existing scripts redirected an HTTP request to another URL and that URL was not the original request user had asked for. It took us to let's say the homepage of the site and from there one again has to click on specific links to reach the desired page. So this will be a problem for users who have book-marked their desired web page.

    Here are the steps you can try for your website such that all HTTP requests get translated to HTTPS requests and have the original URL intact.

    Here are two sample codes which one can try. Both of them should *hopefully* work. First one uses VBScript in an ASP page and second one uses Javascript in an HTML page.

    a).

    redirectSSL.asp

    <%@ Language=VBScript %>
    <% 
    strQueryString = Request.QueryString
    sslPort = null
    PlainURL = Right(strQueryString, len(strQueryString) - 4)
    FindLastCOlon = InStrRev(PlainURL, ":")
    FirstPart = Mid(PlainURL, 1, FindLastColon - 1)
    LastPart = Mid(PlainURL, FindLastColon)
    LastPart = (Mid(LastPart, InStr(LastPart, "/")))
     
    'If the SSL Port is not the default 443, you need to uncomment the line below, by default SSL port is 443.
    'sslPort = ":449"
    if (sslPort = null) then
        url= FirstPart & LastPart
    else
        url = FirstPart & sslPort & LastPart
    end if 
    strSecure = Replace(url, "http:", "https:", 1, 1)
    Response.Redirect strSecure
    %> 

    Steps:

    -- Copy the above code and put in a file redirectSSL.asp under your Website root directory for which you want redirection to work.

    -- Force SSL on the web site. To do that follow the steps mentioned below:
          - Go to --> <Your_Web_Site> -> Properties -> Directory Security -> Edit (Secure Communications)
          - Select Require secure channel (SSL).

    -- Uncheck "Require secure channel (SSL)" option for the redirectSSL.asp page. To achieve that:
         - Go to --> <Your_Web_Site> -> redirectSSL.asp -> Properties -> File Security -> Edit (Secure Communications)
         - Uncheck Require secure channel (SSL).

    So now we are forcing SSL to be used for all of the website contents except the redirectSSL.asp page which can be accessed over non-SSL (HTTP).

    -- In the IIS manager -> <Your_Web_Site> -> Properties -> Custom Errors, modify the entry for 403;4 to look like this:

    image

    Now if you try to browse to some URL, let's say http://www.abc.com/asp/test/ssl/iistsart.htm, you will be redirected to https://www.abc.com/asp/test/ssl/iistsart.htm, without you requiring to modify HTTP to HTTPS.

    If your SSL port is not the default port 443 then you need to un-comment a line in the code as mentioned in there and it will redirect the request to the appropriate URL with corrected SSL port embedded in it.

    b).

    redirectSSL.html

    <html>
    <head>
     
    <script language="javascript">
     
    var currentURL=location.href.substring(0,5)
     
    if(currentURL.toLowerCase()!="https")
    {
    currentURL = location.href.substring(4,location.href.lastIndexOf(''))
    var portStartPos = currentURL.lastIndexOf(':')
    var sslPort = null
    if(portStartPos!=0)
    {
    var relativeURL = currentURL.substring(portStartPos)
    var postPortURL = relativeURL.substring(relativeURL.indexOf('/'))
    var URL = currentURL.substring(0,portStartPos)
    // If you are running your SSL site on a non default port other than 443 then uncomment the next line and add the right Port number.
    //sslPort = ":447"
    if(sslPort == null)
        currentURL = URL + postPortURL
    else
        currentURL = URL + sslPort + postPortURL
    }
     
    var targetURL = "https" + currentURL
    window.location = targetURL
    }
    </script> 
     
    </head>
    </html>

    Steps:

    -- Copy the above code and put in a file redirectSSL.html under your Website root directory for which you want redirection to work.

    -- Force SSL on the web site. To do that follow the steps mentioned below:
          - Go to --> <Your_Web_Site> -> Properties -> Directory Security -> Edit (Secure Communications)
          - Select Require secure channel (SSL).

    So now we are forcing SSL to be used for all of the Website contents.

    -- In the IIS manager -> <Your_Website> -> Properties -> custom Errors, modify the entry for 403;4 to look like this:

    image

    You need not follow the step below since we are using File Type for custom error page and not a URL as shown above in the picture. If you select URL as Type above then you will need to follow the step below.

    "-- Uncheck "Require secure channel (SSL)" option for the redirectSSL.html page. To achieve that:
          - Go to --> <Your_Web_Site> -> redirectSSL.asp -> Properties -> File Security -> Edit (Secure Communications)
          - Uncheck Require secure channel (SSL).
    "

     

    This is all you need and you should see your URL changing automagically from HTTP to HTTPS (SSL).

    Hope this helps...

  • Care, Share and Grow!

    Kerberos troubleshooting from IIS perspective

    • 6 Comments

    Hi All,

    This is my first posting in the blog.

    I really had to take enough courage to start blogging, but with some help from one of my mentors in MS, I am finally here.

    I hope people really get benefitted from the articles that I post in here.

    Today, I am going to talk about how to implement Kerberos authentication for IIS. I have chosen this topic after a lot of consideration. This topic has always evoked a state of anxiety and fear among Web administrators and MS PSS support engineers alike. Also this has been a pain for us since a lot of calls that we receive are related to Kerberos authentication failure and causes a lot of labor and revenue loss to MS and customers.

    So here it goes...

    So what exactly is this Kerberos, first time when I heard of it I thought it must be some mystical word related to enchantment and what not. I went and looked into the dictionary and found something similar. It meant a fierce three-headed dog figure from Greek mythology that guarded the gates of the underworld. Kerberos protocol, similar to the dog figure has three main sections: client, server and an intermediary called Key distribution centre (KDC).

    So how exactly is this Kerberos protocol work:

    There are numerous articles that you can find which will give you an insight as to how Kerberos protocol works, so instead of explaining some redundant stuffs here which might confuse you a bit more (like the way it did to meJ), I will be very lucid and straight in my explanation, and concentrate more on troubleshooting than getting into various jargons associated with it. Let me know if you need articles on the topic and I can post it here.

    Simply speaking, a client requests a ticket (or token) from an Intermediary called Key Distribution centre (KDC) for accessing any service registered with it. In our case to access a web service, it looks for an authenticated token to access the web services, and once getting a unique short-term session key from the KDC, directly contacts the IIS server hosting the web service. IIS in turn receives the token its own session key and since it is authenticated by the KDC with which the IIS service has been registered authenticates the client to access the application running on it. Remember authentication and authorization are two different terms. A client might be authenticated still might not be able to access the resource because of lack of authorization to access it.

    To understand the details of how a Kerberos protocol works, I recommend reading MS knowledge base or Technet.

    Before you configure Kerberos authentication for your site, I recommend having these tools handy:

    SETSPN (For adding, listing, deleting SPN entries for a domain)

    KERBTRAY (For checking the Kerberos ticket used by the client to access a web server. It gives you information as to which ticket is being used by the client to access the IIS server, and whether the ticket is capable of delegation).

    I will take up a scenario where you want to implement Kerberos delegation to work in this architecture. It is also called double-hop since client's credentials are hopped twice from the client to the IIS web server to the backend SQL server to access a resource. I suggest there are very good articles present elsewhere on Microsoft site where you can get in depth information on how Kerberos authentication works. I have concentrated more on troubleshooting, so you can skip to the next section J.

    We assume client, IIS server and the backend SQL server in the same domain. The same scenario will also work if you have the components in different domains but they are mutually trusted both ways.

    As a troubleshooting process, start with only Basic authentication enabled on IIS server and then test from a client machine to see if that works successfully. If it works, we are good to proceed further with Windows integrated authentication as the only enabled authentication on IIS (make sure that we do not have Anonymous authentication selected in the IIS mmc console).

    The following checklist gives you an insight of the basic configuration required for Kerberos to work in double hop scenario from IIS perspective.

    Non-NLB Scenario

    IE : IIS : SQL Server
    ===============================
    IE-IIS-Share
    {All using default accounts, for eg. In IIS 6.0, app pool running under Network service or Local system.}
    --------------------------------------------------------
    IE:
    - Add the URL to "Local Intranet Zone"
    - Enable Windows Integrated Authentication
    - Automatic logon with current username and password or, Automatic logon only in Intranet Zone
    --------------------------------------------------------
    IIS:
    - Only "Windows Integrated Authentication" is checked.
    Type in > cscript adsutil.vbs get w3svc/ntauthenticationproviders (You need to run this from <system drive>/inetpub/adminscripts)
    - Make sure that this command shows > Negotiate, NTLM; or there is no value set.
    Else type in > cscript adsutil.vbs set w3svc/ntauthenticationproviders Negotiate, NTLM
    - Make sure to cross check the same at individual website/virtual directory level by using the command > cscript adsutil.vbs find ntauthenticationproviders.
    SPN:
    -          http/<computer-name>:<port> <iis-computer-name>
                http/<FQDN> <iis computer-name>
    CAUTION: Putting the <port> has been dicey. At times it works and at times it doesn't (only my own experienceJ). I will recommend not using it when you set the SPN.
    Domain Controller (DC):
    -    Under Active Directory Users and Computers -> <Domain> -> Computers, Select the IIS server, right click ->Properties->Delegation tab
         Make sure that "Trust this Computer for delegation to any service (Kerberos only) is selected, or else "Trust this computer for delegation to specified services only" is selected.
        (You will get this option if the Domain functional level is Windows Server 2003 only).
        The 1st option is more generic and is good while you are implementing it for testing the first time.
        When the 2nd option is checked, you can go ahead with any of the options: "Use Kerberos only" or "Use any authentication protocol". In such a case make sure that you are selecting the right service Type running on the backend service for which you need delegation. Let's say if you have SQL server running at the backend to which you want the IIS to delegate the credentials, we need to add service type as "MSSQLSVC" and default port as 1433.
    <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
    IE-IIS-Share
    {App Pool running under Domain account}
    --------------------------------------------------------
    Domain account configuration:
    - Account is trusted for delegation
    - Is a member of IIS_WPG group on the local IIS computer
    - Has "Act as a part of Operating System"/"Impersonate a client after authentication" privileges.
    IE:
    - Add the URL to "Local Intranet Zone"
    - Enable Windows Integrated Authentication
    - Automatic logon with current username and password or, Automatic logon only in Intranet Zone.
    IIS:
    - Only "Windows Integrated Authentication" is checked.
    Type in > cscript adsutil.vbs get w3svc/ntauthenticationproviders (You need to run this from <system drive>/inetpub/adminscripts)
    - Make sure that this command shows > Negotiate, NTLM; or there is no value set.
    Else type in > cscript adsutil.vbs set w3svc/ntauthenticationproviders Negotiate, NTLM
    - Make sure to cross check the same at individual website/virtual directory level by using the command > cscript adsutil.vbs find ntauthenticationproviders.
    SPN:
    -          Add the following:
                            http/<computer-name>:<port> <domain user account>
                            http/<FQDN> <domain user account>
                Remove the following:
                            http/<computer-name>:<port> <iis-computer-name>
                            http/<FQDN> <iis-computer-name>
    CAUTION: Putting the <port> has been dicey. At times it works and at times it doesn't. I will recommend not using it when you set the SPN.
    Domain Controller (DC):
    -    Under Active Directory Users and Computers -> <Domain> -> Computers , Select the IIS server, right click ->Properties->Delegation tab
        Make sure that "Trust this Computer for delegation to any service (Kerberos only) is selected, or else "Trust this computer for delegation to specified services only" is selected.
        (You will get this option if the Domain functional level is Windows Server 2003 only).
        The 1st option is more generic and is good while you are implementing it for the first time.
        When the 2nd option is checked, you can go ahead with any of the options: "Use Kerberos only" or "Use any authentication protocol". In such a case make sure that you are selecting the right service Type running on the backend service for which you need delegation. Let's say if you have SQL server running at the backend to which you want the IIS to delegate the credentials, we need to add service type as "MSSQLSVC" and default port as 1433.
    If you still encounter problems try checking for duplicate SPNs.
    - To find duplicate SPNs
      Use command prompt to execute this command on dc:
           ldifde -f <filename> -d "<dc=domain-netbiosname,dc=primary-domain>" -l serviceprincipalname -r "(serviceprincipalname=<serviceprincipalname-to-check-for-duplicates>)" -p subtree
    e.g. if the domain name is test.abcd.com:
           ldifde –f C:\log.txt -d "dc=test, dc=abcd, dc=com"-l serviceprincipalname –r "(serviceprinicpalname=http/test.abcd.com)" -p subtree

     

    NLB Scenario
    --------------------------------------------------------
    Now we will talk about a scenario where IIS server is a part of Network load balancer (NLB). First thing, make sure that Kerberos is supported by your NLB (hardware or software). The settings for Kerberos are a bit different when you configure it for IIS servers running as NLB nodes. Here you don't have to set SPNs for individual IIS nodes; rather you need to set an SPN entry for the Virtual IP or alias of the Load balancer. It can be hardware or software.

    IE-IIS-Share
    --------------------------------------------------------
    {All using default accounts}
    --------------------------------------------------------
    IE:
    - Add the URL (here the URL is the NLB's virtual URL or alias) to "Local Intranet Zone"
    - Enable Windows Integrated Authentication (Internet Options->Advanced->Security)
    - "Automatic logon with current username and password" or "Automatic Logon only in Intranet Zone"

    IIS:
    Type in > cscript adsutil.vbs get w3svc/ntauthenticationproviders (You need to run this from <system drive>/inetpub/adminscripts)
    - Make sure that this command shows > Negotiate, NTLM; or there is no value set.
    Else type in > cscript adsutil.vbs set w3svc/ntauthenticationproviders Negotiate, NTLM
    - Make sure to cross check the same at individual website/virtual directory level by using the command > cscript adsutil.vbs find ntauthenticationproviders.
    - Setup the IIS Servers for delegation as mentioned in the above steps.
    - Only "Windows Integrated Authentication" is used in IIS.
    - If it's an NLB environment, we need to run the IIS application under an App pool running with domain user account.
    - The domain user account should be trusted for delegation in the Active Directory.
       From Active Directory Users and Computers, go to the properties of the IIS User (Domain user account). On the Delegation Tab, select "Trust this user for delegation to any service (Kerberos only)"
    - The domain user account should be a part of IIS node's IIS_WPG group.
    - We need to set the above settings for all the IIS nodes in the NLB.
    - Also add the same host header entry for the NLB URL in all the IIS nodes in the IIS manager console -><website>->Properties->Web Site-> Advanced tab.

    SPN:
    - For IIS:
                 http/<Netbios name of the NLB>  <Domain user account>
                 http/<FQDN of the NLB>  <Domain user account> (If we are running the site on port 80, otherwise http/<FQDN of the NLB>:<Port>  <Domain user account>
        CAUTION: Putting the <port> has been dicey. At times it works and at times it doesn't. I will recommend not using it when you set the SPN even when your site is running under a different port other than the default 80.

    We need to make sure that we do NOT have SPN entries set for http/<FQDN>  <iis computer-name> for any of the IIS nodes.

    Command: >Setspn –A http/<FQDN of the NLB>  <Domain user account>
    When we are using Constrained delegation make sure that the backend service is listed in list of services, for e.g. in case we are connecting to SQL server at the backend add MSSQLSVC in the Machine/user properties->Delegation tab.
    Note: When we are accessing the web application from a client machine, I suggest installing Kerbtray on the client machine and checking for the "OK as Delegate" option in the attributes section for the corresponding SPN. If it is selected it means the ticket can be used for delegating credentials from the IIS server to the backend server. If it is not then it means there are some issues with the settings in IIS or somewhere else. Using Netmon trace is always a good idea to figure out what tickets are being used or looked for by the Client when accessing the Web application.

    In case you face any issues related to Kerberos authentication failure, do the following to understand more from the event logs
    - Make sure that we have enabled Kerberos logging according to http://support.microsoft.com/default.aspx?scid=kb;EN-US;262177 on all the IIS nodes.
    - Apart from that, you also need to make sure that on all the IIS servers, these two settings are enabled.

    Start->Programs->Administrative tools->Local security Policy->Security settings->Local Policies->Audit Policy->Audit account logon events->"Success, Failure".

    Start->Programs->Administrative tools->Local security Policy->Security settings->Local Policies->Audit Policy->Audit logon events->"Success, Failure".

    NOTE:

    At times making sure all the above changes are done properly doesn't help, and in such cases make sure that we purge all the kerberos tickets using Klist or Kerbtray. In fact if possible logoff and re-login to the client machine from where you are testing the web application for kerberos authentication so that the client is issued a fresh ticket.

    Additional Info:
    ================

    You might see this error in the event logs in DC:
    Event Type: Error
    Event Source: KDC
    Event Category: None
    Event ID: 11
    Date: 4/1/2002
    Time: 1:40:14 PM
    User: N/A
    Computer: ComputerName Description:
    There are multiple accounts with name host/mycomputer.mydomain.com of type 10.

    This might be because of Duplicate SPNs. There are two or more computer accounts that have the same service principal names (SPNs) registered. Please refer to KB 321044 for further info. Remember, you can use Ldifde to check for duplicate SPNs as mentioned above.
    Few Links:
    For configuring backend SQL server to accept Kerberos authentication go through this link: http://support.microsoft.com/kb/319723/en-us
    Also a good article on IIS Kerberos authentication http://support.microsoft.com/kb/907272/en-us and http://support.microsoft.com/?id=929650
    How to configure an Asp.Net application for a delegation scenario: http://support.microsoft.com/kb/810572/
    PS: Remember to test whether delegation is working fine, you need to access the website URL from a workstation (client) browser and not from IIS server itself.

    Reason: IIS uses NTLM credentials when accessing the backend when request reaches it from the local server if, Kerberos fails and there is only single hop involved. NTLM will work with single hop and hence if you access a site locally from the IIS web server it is a single hop and not a double hop scenario.

    One simple mantra to be remembered always: You can have multiple different SPNs registered under an account but not the other way, i.e. you should not have the same SPN registered under multiple accounts because it leads to duplicate SPN issue.

    ***************************************************** Addition to the blog


    Think about a scenario where http://server/app1 and http://server/app2 are running inside a network service & a domain user identity respectively .
    The SPNs requested will be http/server in both the cases, and since we can’t have duplicated SPNs it won’t work. We need to then either use the same server process identity or dedicated host headers.

    Again,if you are using two websites with same name but different ports like http://server:80 and http://server:81; by default IE will request a ticket for the same SPN HTTP/server.

    We would then need an hotfix for the client machines, http://support.microsoft.com/kb/908209.

    If you have two websites http://application1 and http://application2 that are both DNS aliases (CNAMEs) of say myserver DNS host, IE will request the ticket for SPN HTTP/myserver for both the above websites. By default IE does't use port for sending the ticket and just the SPN name like, http/mysite:99, It ignores the port part of it.
    Then you would need client fix http://support.microsoft.com/kb/911149, or use a different DNS HOSTs rather than CNAMEs.You might well go ahead with using a host headers for the websites.

    [Something to add here with regard to using IP Addresses to access a site...

    There is another confusion that people have while dealing with Kerberos authentication. At times you may want to use IP addresses to access a website and still want Kerberos authentication to work. Now in a general scenario this will not work because Kerberos requires SPN's to recognize a service like HTTP etc. You can however make it work by adding SPN's in the form: http/10.0.1.25 (website's IP) etc. This may or may not work.

    However we do not recommend the above way to make Kerberos work for your site using IP addresses. The reason being that SPN's should ideally be names like http/<somename> and not http/<some IP address>.

    Let's consider a scenario wherein users belong to domain2 and the Web server is part of domain1. Also let's assume we have mutual trust between domain1 and domain 2. When using IP addresses, client will look for SPN HTTP/10.0.1.25 (assuming this is website's IP on domain1) in domain2 (client's local domain).

    Now you may get into an issue wherein domain2 will not give any referral back to to the client to look into domain1 for the SPN. This can occur if IP address is being used to look for a service. In such a case even after adding SPN's for IP addresses, Kerberos won't work and will fall back to NTLM.

    ]

    ***Update: Regarding confusion around Port entry in SPNs, check this http://technet.microsoft.com/en-us/library/cc263449.aspx#section4

    Happy troubleshooting…and in case you still face issues, Microsoft Product Support Services (PSS) is always there to help you!

    Feel free to shoot me a question if you have any confusion or need some assistance.

    *Check the following link for my other posts related to Kerberos.

     

  • Care, Share and Grow!

    Case Study: Host header, IP and Port combinations within IIS

    • 16 Comments

     

    Talking about IIS website configurations when it comes to IP Address, Port, Host headers cause a lot of confusion to many Web Administrators. Here I will be going (a bit of unnecessary details though) to explain how the configuration resolves to Websites when a web request comes to IIS.

    Environment

    IIS6.0

    I have multiple IP addresses for my demo server (assuming you have multiple NIC cards).

    Here is a list:

    10.0.1.1

    10.0.1.2

    10.0.1.3

    10.0.1.4

    Here is a screenshot of how IIS manager section looks like which I will talk about later.

    In the IIS manager console you may have the following scenarios:

    Scenario 1:

    There are multiple Websites (for our example we will take 2 here) running with following configuration:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                                --                                All Unassigned                        80
    Test2                                --                                All Unassigned                        80

    Scenario 2:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                                --                                10.0.1.2                        80
    Test2                                --                                10.0.1.2                        80

    Will this Websites run? No, only one of them can be in started mode. Rest of them will be in stopped state.
    Reason: For HTTP sites one cannot have multiple sites running with the same IP/Port/HostHeader combination. For HTTPS sites you cannot have the same IP/Port combination. More specifically you cannot have the same port/IP combination for the “SecureBindings” setting (SSL settings). Technically, you could have an entirely different IP address for the SSL portion of a web site. If you mess up the SSL part, the HTTP part of the site will still start.

     

    If you try to start any of the other Websites you will get an error popup like this:

    Scenario 3:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                                --                                     10.0.1.1                             80
    Test2                                --                                All Unassigned                        80

    Test3                                --                                     10.0.1.3                             80 

    Test4                                --                                     10.0.1.4                             80

    Will these Websites start: Yes. All of the Websites will be up and running. Remember you can have only one website which can have "All Unassigned" and port XX (when there are no host headers in picture and you have all the sites running on same port XX). No two website can have exactly the same combination of Host header, IP Address and Port.

    Here remember you can access the site Test1 only with the IP address 10.0.1.1. If you try to use http://localhost (or http://127.0.0.1) , it will go to some other site (discussed soon). Now using http://servername is a bit tricky. Request will actually go to the site to which your servername resolves from the user's machine. If you do a ping servername and if the IP that it resolves to is set for a specific site like Test3, Test3 will serve the page. If http://servername doesn't resolve to any of the IP addresses on which some sites are specifically configured to listen to, the request will be served by a site which is listening on "All Unassigned" (I know it may be confusing but I am giving an example before coming to theory). If none of the Websites are listening on the resolved IP or "All unassigned" then you will see a "Bad Request (Invalid Hostname)" in the browser (You may check the httperr log to confirm the same).

    Let's take for our example that ping servername resolves to 10.0.1.2

    So seeing the Websites configuration of Scenario 3 above, which site will should serve the page for the following URLs:

    http://servername (remember servername resolves to 10.0.1.2) ?        Ans: Test2

    http://10.0.1.2 ?              Ans: Test2 

    http://10.0.1.3 ?              Ans: Test3

    http://10.0.1.4 ?              Ans: Test4

    http://10.0.1.1 ?              Ans: Test1

    http://localhost ? (Remember it refers to 127.0.0.1)           Ans: Test2

    I assume you are getting the logic.

    So here comes the explanation:

    IIS by default listens on all the IP addresses on the server on a specific port (By default 80).

    If you run the command netstat -ano from the command prompt you will see an entry like 0.0.0.0:80. This means that IIS process listens on all IP addresses associated with the server on port 80. Now when you associate a website with a specific IP address and port combination it will listen only on that IP address on that port. It won't accept any request on any other IP address or port associated with the server. When you use "All Unassigned" for a website it means that this website listens on all the IP addresses associated with the server on the specified port. Hence as you may assume from above scenario any web request that is sent to the server on a specific IP address will be served by the website following the above rule...let me clear it again with the above example:

    http://servername (remember servername resolves to 10.0.1.2) ?       

    Ans: Test2 , Reason: When the request reaches IIS server, http.sys driver redirects the request to website Test2 because all other Websites are listening on specific IP's which do not match 10.0.1.2.

    http://10.0.1.2 ?             

    Ans: Test2, Reason: It will be sent to and served by Test2 because this is the website which is set to "All unassigned" which means Website is listening on all IP addresses associated with the server. Also this request won't be served by any other site because they are listening on IP's which are different from 10.0.1.2. 

    http://10.0.1.3 ?              

    Ans: Test3 , Reason: As expected from explanations so far this will be served by Test3 because Test3 is configured to listen to any request directed on IP 10.0.1.3.

    http://10.0.1.4 ?             

    Ans: Test4 , Reason: Again the same reason as above, Test4 is configured to listen on IP 10.0.1.4.

    http://10.0.1.1 ?             

    Ans: Test1 , Reason: Same logic as above.

    http://localhost ? (Remember it refers to 127.0.0.1)          

    Ans: Test2, Reason: Served by Website Test2, because the request is sent on IP 127.0.0.1 and none of the other Websites are listening on 127.0.0.1. Test2 has "All unassigned" which means it is listening on all IPs on the server including 127.0.0.1 and hence can serve the request. If for testing you change the IP configuration for a website to 127.0.0.1 then all new requests like http://localhost will be served by this specific website.

    So the above scenario shows how every request will be served by some site provided we have the configuration like "All unassigned" or specific IP for the sites.

    Now let's assume what will happen if we have this scenario:

    Scenario 4:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                                --                                     10.0.1.1                             80
    Test2                                --                                     10.0.1.2                             80

    Test3 (Stopped)               --                                     10.0.1.3                             80 

    Test4                                --                                     10.0.1.4                             80

    Here we do not have any site configured with "All unassigned". Now if you try to access http://localhost or http://10.0.1.3 what should happen?

    You should see "Bad Request (Invalid Hostname) in the browser. This happens because now none of the Websites are capable of serving your requests http://localhost (127.0.0.1) or http://10.0.1.3 

    We have just 3 Websites (running) and they are listening on IPs 10.0.1.1, 10.0.1.2 and 10.0.1.4. Had there been a website listening on "All Unassigned" these requests would have been served by this website.

    I am pretty sure you might have got rid of some of your doubts by now :) If not it's my bad.

    -------------------------------------------------------------------------------------------------------------------------------------------------------

    So far I had been talking about scenarios where Host header was not in picture.

    Now let's assume you have host headers as well in above scenarios. Let's first see what's the use of a Host header.

    IIS identifies Websites on the basis of 3 parameters: IP address, Port and Host header (if present).

    Any combination of the above parameters should be able to uniquely identify a website. If there is an ambiguity IIS will throw error.

    A host header is of the form www.abcd.com or abcd or abcd.com or abcd.co.in etc....

    To create and host multiple Web sites, you must configure a unique identity for each site on the server. To assign a unique identity, distinguish each Web site with at least one of three unique identifiers: a host header name, an IP address, or a TCP port number.

    One method for providing each site with a unique identifier is to use IIS Manager to assign multiple host header names.

    Typically Host headers are set in IIS manager and its mapping to an IP is set in the DNS entry or hosts file (I assume you know hosts file is a limited simulation of DNS for a client). Users access the sites using their host headers.

    A “Host” header is one header out of multiple headers that are included in an HTTP request. The headers are things like User-Agent, Accept, If-Modified-Since, Content-Length, Host, etc. As a request comes in, IIS looks at one particular header… “Host” and uses its value to decide which web site to route the request. “Host Headers” are not an IIS technology. They are an HTTP technology. Browsers typically put into the “Host” header whatever the user put into the “Address” line of the browser. If you put “http://192.25.109.11/Default.aspx” into the address line then the browser will extract the “host name” from that address and put “192.25.109.11” as the value for the “Host” header. Or maybe there is no header at all named “Host” (which makes it an HTTP/0.9 request).

    Here is a screenshot of an http request for http://test1.com

    and this one for http://10.0.1.1

    Scenario 5:

    Website                  Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                        test1.com                               10.0.1.1                             80
    Test2                        test2.com                               10.0.1.1                             80

    and in the DNS or hosts file you have mapping like:

    10.0.1.1                test1.com

    10.0.1.1                test2.com

    Will these two Websites run simultaneously? Yes they will.

    They will run even when they have same IP and same port because now IIS has a way of distinguishing the Websites using a 3rd parameter called host header. So it knows that when a request comes for http://test1.com and http://test2.com it can direct them to the right Websites on the basis of host headers present in the request headers.

    When you access a site with host header the request is resolved to the website corresponding to DNS/Hosts mapping for the host header and not the IP address mentioned in the IIS manager. This is IMPORTANT. The request then reaches the IIS server and goes to the website which is listening on that resolved IP.

    Let's see here.

    DNS/Hosts setting:

    10.0.1.1              test1.com                                    10.0.1.3           test3.com

    10.0.1.2              test2.com                                    10.0.1.4           test4.com

    Scenario 6:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                          test1.com                              10.0.1.1                             80
    Test2                          test2.com                              10.0.1.2                             80

    Test3                          test3.com                              10.0.1.3                             80 

    Test4                          test4.com                              10.0.1.4                             80

    Now when you try to browse to http://test3.com which site should serve the page from the above IIS configuration? Obviously Test3, now this is simple:). what happens if you try to access any of these Websites with their IP addresses? You will see "Bad Request (Invalid Hostname)". So use judiciously as to how users should access the site. If you have host header set use it instead of IP address in the URL.

    If you really want to use an IP address along with an alias (a friendly name) for a website (like http://abcd.com, or http://wxyz ) , then just don’t assign the host header value in the IIS manager. And have an entry in DNS or hosts file mapping abcd.com or wxyz to the IP address for the website (there are other ways to but this neat).

    Scenario 7:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                          test1.com                              10.0.1.1                             80
    Test2                          test2.com                              10.0.1.2                             80

    Test3                          test3.com                              10.0.1.1                             80 

    Test4                          test4.com                              10.0.1.4                             80

    Which site should serve the content when accessed with http://test3.com in the URL..............?

    "Bad Request (Invalid Hostname)" in the browser. Reason being that http://test3.com resolves to IP 10.0.1.3 through DNS/Hosts and then in IIS mmc it is configured to listen on IP 10.0.1.1. Rest of the Websites work fine because both the DNS/host entry and IP in IIS mmc for the Websites match.

    Scenario 8:

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================
    Test1                          test1.com                              10.0.1.1                             80
    Test2                          test2.com                              10.0.1.2                             80

    Test3                          test3.com                              10.0.1.1                             80 

    Test4                          test4.com                              All unassigned                   80

     

    What site should http://test4.com resolve to..............? Test4, because it is listening on All Unassigned (which means all the IP addresses on the server) which includes DNS/hosts mapping for the site (here 10.0.1.4).

    Similarly if we have       

    Website                   Host Header Value                  IP Address                         Port
    ================================================================================

    Test3                           test3.com                        All Unassigned                        80 

    It should still work fine for http://test4.com and also http://test3.com

    Let us consider another scenario

    If you have multiple entries for a website in the IIS manager->Web Site->Advanced, you may have different host headers but should have same IP (and/or All unassigned) and TCP Port.

    If you use a different port for the entries you need to add the port entry after the host header like: http://testX:port.

    If you use a different IP address for the 2nd host header you may again see the blunt "Bad Request (Invalid Hostname)" error when you use this host header to access the website.

    So all these explanations and pain for one reason: Avoid setting a specific IP address for the Websites in IIS mmc to avoid any conflicts or confusion with the DNS/Hosts mapping. Instead use "All unassigned" and if really required to use an IP make sure that IP address in IIS mmc and DNS/Hosts entry is same. There is no benefit to “over configuring” the IP and host header settings. It is “unnecessary administrative overhead”. For any site that don’t use SSL, assign one or more host headers and leave the IP at "All unassigned". For anything with SSL, give it a specific IP and leave the host header field blank. Leave port alone because that confuses most end users.

    Hope this helps!                                                                                                              

  • Care, Share and Grow!

    Are you seeing 401’s too often for HTTP web requests?

    • 4 Comments

    We often hear concerns from our customers saying that they are seeing performance issues because of extra round trips being made to the Web server while requesting for web pages. Where they expected just one sequence of 401.2/401.1/200 (NTLM) or 401.2/200 (Kerberos) they are seeing the sequence more often for the subsequent page requests. They would like a way to avoid making extra round trips from the client to the server for an already authenticated page request.

    Why such a behaviour?? Read on…

    Before we proceed let’s clear the two terminologies.

    Connection-based authentication: Client that is authenticated after an initial HTTP request stays authenticated for the duration of the HTTP Keep-Alive session. This means that the server will assume subsequent requests coming on the same connection without an authorization header, to be executed as the last authenticated user. Subsequent requests on the same connection will not be challenged to send the authorization headers as part of their HTTP requests.

    Clients only have to re-authenticate if they make another HTTP request by using a different client TCP port. This scenario occurs when a new HTTP Keep-Alive session must be established.

    Request-based authentication: This means that the client has to be re-authenticated for each HTTP request. This behaviour causes an increase in the network traffic because of the extra round trips made to the server from the client.

    So with that clear in mind here are the scenarios you may encounter for the IIS versions when using Windows Integrated authentication for your web application.

    Authentication method: NTLM
    IIS 6.0

    NTLM on IIS 6.0 uses Connection-based authentication. This behaviour is governed by a metabase property called AuthPersistSingleRequest. By default this value is set to false which means when using NTLM authentication you should see lesser round trips for every page requests. The default value of FALSE is applicable to all versions of IIS, i.e. IIS 5.0, 6.0 and 7.0/7.5.

    Here is how IIS log will look like when it is set to the default value of FALSE.

    1st request
    GET /iisstart.htm - 401 2 2148074254  
    GET /iisstart.htm - 401 1 0  
    GET /iisstart.htm DOMAIN1\User1 200 0 0  
    GET /pagerror.gif DOMAIN1\User1 200 0 0  
    GET /magnifyingglass.ico - 401 2 2148074254  
    GET /magnifyingglass.ico - 401 1 0  
    GET /magnifyingglass.ico DOMAIN1\User1 200 0 0  
    
    2nd request (refresh)  
    
    GET /iisstart.htm DOMAIN1\User1 304 0 0  
    GET /magnifyingglass.ico DOMAIN1\User1 304 0 0  
    GET /pagerror.gif DOMAIN1\User1 304 0 0  

    You may see some requests showing additional 401.2/401.1/200(or 304) here because they are initiating the request on a different client socket and hence a new connection is being established. 

    If we have the AuthPersistSingleRequest value set to TRUE then each request will have to be authenticated irrespective of the previous request on the same connection. Consequently requests will require authorization headers to be sent. Here is the step you need to follow to enable the setting in such a case.

    > cscript.exe adsutil.vbs set w3svc/<Website ID>/AuthPersistSingleRequest TRUE  

    Here is how the IIS log looks like after setting AuthPersistSingleRequest to TRUE.

    1st request  
    
    GET /iisstart.htm - 401 2 2148074254  
    GET /iisstart.htm - 401 1 0  
    GET /iisstart.htm DOMAIN1\User1 200 0 0  
    GET /pagerror.gif - 401 2 2148074254  
    GET /pagerror.gif - 401 1 0  
    GET /magnifyingglass.ico - 401 2 2148074254  
    GET /magnifyingglass.ico - 401 1 0  
    GET /pagerror.gif DOMAIN1\User1 200 0 0  
    GET /magnifyingglass.ico DOMAIN1\User1 200 0 0  
    
    2nd request (refresh)  
    
    GET /iisstart.htm - 401 2 2148074254  
    GET /iisstart.htm - 401 1 0  
    GET /iisstart.htm DOMAIN1\User1 304 0 0  
    GET /pagerror.gif - 401 2 2148074254  
    GET /pagerror.gif - 401 1 0  
    GET /magnifyingglass.ico - 401 2 2148074254  
    GET /magnifyingglass.ico - 401 1 0  
    GET /pagerror.gif DOMAIN1\User1 304 0 0  
    GET /magnifyingglass.ico DOMAIN1\User1 304 0 0  
    Check this link and this link for other possible settings when proxies are involved.

    IIS 7.0

    AuthPersistSingleRequest in IIS 7 is set as an attribute under windowsAuthentication in applicationhost.config file.

    <windowsAuthentication
       enabled="True|False"
       authPersistSingleRequest="True|False"
       UseKernelMode
    >
       <providers>...</providers>
    </windowsAuthentication>  
    http://msdn.microsoft.com/en-us/library/aa347472.aspx

    This completes our discussion on NTLM.

    Authentication method: KERBEROS
    IIS 6.0

    Kerberos used to be Connection-based in IIS 5.0. Starting IIS 6.0+ Kerberos is by default Request-based authentication instead of Connection-based as in NTLM. You may see performance hit because of this behaviour because of the extra round trips.
    So, if we have Kerberos instead of NTLM being used for your web application then we need to ensure that the following hotfix is applied (This hotfix requires the prerequisite as Win2k3 Sp1. If you are already running on SP2 you don’t need to install this hotfix.). Ensure the Registry key EnableKerbAuthPersist is set as per the KB article 917557.

    Here is how the IIS log will look like when this hotfix/key is not set.

    GET /iisstart.htm - 401 2 2148074254 
    GET /iisstart.htm DOMAIN1\User1 200 0 0 
    GET /pagerror.gif - 401 2 2148074254 
    GET /magnifyingglass.ico - 401 2 2148074254 
    GET /pagerror.gif DOMAIN1\User1 200 0 0 
    GET /magnifyingglass.ico DOMAIN1\User1 200 0 0

    After adding the registry key EnableKerbAuthPersist and restarting IIS services we should see something like this:
    GET /iisstart.htm - 401 2 2148074254 
    GET /iisstart.htm DOMAIN1\User1 200 0 0 
    GET /magnifyingglass.ico - 401 2 2148074254 
    GET /pagerror.gif DOMAIN1\User1 200 0 0 
    GET /magnifyingglass.ico DOMAIN1\User1 200 0 0 
    GET /iisstart.htm DOMAIN1\User1 304 0 0 
    GET /pagerror.gif DOMAIN1\User1 304 0 0 
    GET /magnifyingglass.ico DOMAIN1\User1 304 0 0 
    GET /iisstart.htm DOMAIN1\User1 304 0 0 
    GET /magnifyingglass.ico DOMAIN1\User1 304 0 0 
    GET /pagerror.gif DOMAIN1\User1 304 0 0

    IIS 7.0

    EnableKerbAuthPersist is no more applicable in IIS 7. Instead use the attribute AuthPersistNonNTLM in the applicationhost.config file.

    <windowsAuthentication
       enabled="True|False"
       AuthPersistNonNTLM="True | False"
       UseKernelMode
    >
       <providers>...</providers>
    </windowsAuthentication>

    http://msdn.microsoft.com/en-us/library/aa347472.aspx

    The above article seems to have incorrect wording. Ensure we set the attribute to true to have connection-based authentication.

    <location path="Default Web Site"> 
            <system.webServer> 
                <security> 
                    <authentication> 
                        <anonymousAuthentication enabled="false" /> 
                        <windowsAuthentication enabled="true" authPersistNonNTLM="true" /> 
                    </authentication> 
                </security> 
            </system.webServer> 
    </location>

    Caveat: If we are going via a Proxy server IIS will only persist requests per request and that is by by design.

    Going forward if we have Win2k8 R2+ as the web server using Windows Integrated Authentication (user mode) and Win7+IE8 as the client, Nego2 schema based authentication can be feasible.
    Improvements in Win7+IE8 will further reduce the unnecessary traffic for Kerberos based requests.

    Cheers to life!!

  • Care, Share and Grow!

    SSL Bindings are randomly getting deleted for a website with error "SSL Certificate Settings deleted for Port : X.X.X.X:443" in the event logs (IIS 7.0/7.5)

    • 6 Comments

    Symptoms

    Are you getting into a scenario wherein randomly your Website loses or changes the SSL certificate bindings from within the IIS manager? And you realize it only when users complain that they are unable to reach the HTTPS site, or that they get a certificate warning. They are able to access the website over HTTP but not over HTTPS because the certificate binding is lost for the website, or they may be prompted that the certificate is expired, or the site name is incorrect. At this point of time you also notice that System Event log entry shows the following:

    Log Name:      System
    Source:        Microsoft-Windows-HttpEvent
    Date:          3/31/2010 2:43:28 PM
    Event ID:      15300
    Task Category: None
    Level:         Warning
    Keywords:      Classic
    User:          N/A
    Computer:      myMachine
    Description:
    SSL Certificate Settings deleted for Port : 0.0.0.0:443 .

    If you go to the IIS manager and check the bindings for the Website in question you will see either the certificate binding is lost or some other certificate is listed.

    You can also crosscheck the registry entry below for your IP/Port binding associated with your website and you may find it deleted.

    HKLM\System\CurrentControlSet\SERVICES\HTTP\Parameters\SslBindingInfo\X.X.X.X:443

    Here is how it looks if you have the proper binding set at the http.sys level in the Registry.

    clip_image002

    Note:  Should the certificate be changed, the binding will look the same.

    Assessment

    If you are experiencing the above problem it could be related to the following <customMetadata> tag in your ApplicationHost.config.

    <key path="LM/W3SVC/X">

    <property id="5506" dataType="Binary" userType="1" attributes="None" value="oXiHOzFAMOF0YxIuI7soWvDFEzg=" />

    </key>

    The above property is used to store a SSL certificate hash. It is specifically the ID 5506 entry you need to check for. That ID is the legacy property for certificate hash. Whenever any application/service which depends upon the ABO mapper runs/starts, it tries to initialize the ABO tree structure which includes generating custom nodes and properties. During this process it reads from this custom metadata section and tries to map the properties in the ABO tree structure. During mapping it deletes the current SSL mapping(s) at the http.sys level and recreates a new one using the above hash value. If this value is invalid for some reason it fails to add the new entry for SSL binding at the http.sys level. So in such a case the above registry key does not have an entry for the website’s IP:Port combination corresponding to the SSL setting in the UI like below:

    clip_image004

    Call stack output

    If you use the Debugging Tools for Windows and the Microsoft symbol server to attach to the process Inetinfo.exe, you will notice a call stack that resembles the following below:

    abocomp!UpdateSSLProperty
    abocomp!SITE_CUSTOM_PROVIDER::MapSetData+0x371
    abocomp!ABO_NODE::MapSetData+0xd9
    abocomp!ABO_NODE::SetData+0xbd
    abocomp!ABO_TREE::SetCustomProperty+0x34a
    abocomp!ABO_TREE::GenerateCustomNodesAndProperties+0x1ad
    abocomp!ABO_TREE::GenerateTree+0x28d
    abocomp!ABO_WRAPPER::InitializeTreeAndState+0xad
    abocomp!ABO_WRAPPER::GetCurrentAboTree+0xc7
    abocomp!ABO_WRAPPER::OpenKey+0x154
    COADMIN!CADMCOMW::OpenKeyHelper+0x172
    COADMIN!CADMCOMW::OpenKey+0x53
    RPCRT4!Invoke+0x65
    RPCRT4!NdrStubCall2+0x348
    RPCRT4!CStdStubBuffer_Invoke+0x9a
    ole32!SyncStubInvoke+0x5d
    ole32!StubInvoke+0xdf
    ole32!CCtxComChnl::ContextInvoke+0x19f
    ole32!AppInvoke+0xc2
    ole32!ComInvokeWithLockAndIPID+0x407
    ole32!ThreadInvoke+0x1f0
    RPCRT4!DispatchToStubInCNoAvrf+0x14
    RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x100
    RPCRT4!RPC_INTERFACE::DispatchToStub+0x62
    RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0x5b
    RPCRT4!LRPC_SCALL::DispatchRequest+0x436
    RPCRT4!LRPC_SCALL::HandleRequest+0x200
    RPCRT4!LRPC_ADDRESS::ProcessIO+0x44a
    RPCRT4!LOADABLE_TRANSPORT::ProcessIOEvents+0x24a
    RPCRT4!ProcessIOEventsWrapper+0x9
    RPCRT4!BaseCachedThreadRoutine+0x94
    RPCRT4!ThreadStartRoutine+0x24
    kernel32!BaseThreadInitThunk+0xd
    ntdll!RtlUserThreadStart+0x1d

    We break into the function which calls into the HTTP.sys at the kernel mode to delete the SslBindingInfo Registry key.

    Steps to reproduce

    We can reproduce this issue at will by adding the following under <CustomMetadata> section of your applicationhost.config file

    <key path="LM/W3SVC/X">

    <property id="5506" dataType="Binary" userType="1" attributes="None" value="oXiHOzFAMOF0YxIuI7soWvDFEzg=" />

    </key>

    and then launching any application which requires ABO Mapper, for e.g. launching Inetmgr6.exe or enumerating using ADSUTIL VBscript.

    Resolution

    This property is a legacy feature from IIS 6 days and ported onto IIS 7+. If we have correctly added the certificate in the IIS manager this specific property with id 5506 is not needed. Search for the above entry in your ApplicationHost.config file and remove the property in case you are seeing the above issue.

    PS: I have got the above issue/resolution recently documented as a fast-publish KB article 2025598.

    till next time

  • Care, Share and Grow!

    Unable to correctly display Chinese (Unicode) characters in Excel when opened through ASP.Net page

    • 9 Comments

    Recently I was working on an issue wherein one of our customers was trying to stream data from their web application in CSV format for it to be recognizable and opened through Excel on the client's end. Basically they were setting content-type and content-disposition to open the file outside the browser and open it in MS-Excel. Everything would have worked had they not used Chinese characters as data in this case.

    Something like this:

    Page.Response.Clear()
    Page.Response.ContentType = "application/vnd.ms-excel"
    Page.Response.ContentEncoding = System.Text.Encoding.UTF8
    Page.Response.AddHeader("Content-Disposition", "attachment; filename=ExportData.xls")

    And later in the code they were reading the column headers and column row in CSV format into a string which will get flushed as a response output.

    Something like this:

    'Output Column Headers as 

            columnHeaders = "HEADER1" + Chr(9) + "HEADER2"             
            columnHeaders = columnHeaders & Chr(13) & Chr(10)

    [Here, Chr(9), Chr(10) and Chr(13) correspond to Tab, Linefeed and Carriage Return characters in ASCII respectively to adhere to CSV format]

    Page.Response.Write(columnHeaders)
    Page.Response.Write(Chr(10))

    and

    'Output Column Row as
    columnRow = ""

    After populating the columns in various strings we do this to adhere to CSV format:

    columnRow = coulmn1 + Chr(9) + column2

    columnRow = columnRow & Chr(13) & Chr(10)

    ...............

    Page.Response.Write(columnRow)        ' Finally display the data

    Now if you see above this should work if we try to open the file using Excel. Although if we are sending the data in UTF-8 encoding (let's say for Chinese characters), Excel doesn't recognize it correctly and opens it in ASCII. In normal scenarios the above functionality will not cause issues but if we are using any Unicode characters like Chinese the data will be wrongly displayed in Excel. You may see "???????" etc. Although it may display perfectly fine in the webpage control , let's say in a datagrid.

    The resolution to such an issue is to switch from UTF-8 to Unicode and add Unicode byte leader
    to the start of the file. Excel will recognize the byte-leader as an indication of Unicode data coming in, and correctly read the file as Unicode. This way Unicode characters like Chinese can be preserved when opened through Excel.

    Here is something you can try:

    Dim rgByteLeader(1) As Byte
            rgByteLeader(0) = &HFF
            rgByteLeader(1) = &HFE

            Page.Response.Clear()
            Page.Response.ContentType = "application/vnd.ms-excel"
            Page.Response.ContentEncoding = System.Text.Encoding.Unicode
            Page.Response.AddHeader("Content-Disposition", "attachment; filename=ExportData.xls")

    ' Write out the Unicode header FFFE so that Excel recognizes the file as Unicode()
            Page.Response.BinaryWrite(rgByteLeader)

    'Output Column Headers as before

            columnHeaders = "HEADER1" + Chr(9) + "HEADER2"             
            columnHeaders = columnHeaders & Chr(13) & Chr(10)

            Page.Response.Write(columnHeaders)
            Page.Response.Write(Chr(10))

     

    'Output Column Rows as before
            columnRow = ""

            .............

           columnRow = coulmn1 + Chr(9) + column2
           columnRow = columnRow & Chr(13) & Chr(10)

           Page.Response.Write(columnRow)

           .....

           Page.Response.End()

     

    I am no Globalization/MS-Excel expert but I had a tough time researching on this issue so thought of sharing it with others. Hope this helps!

  • Care, Share and Grow!

    Certificate Trust List not being honored by IIS 5.0/6.0/7.0?

    • 8 Comments

    Something one should be aware of if one is dealing with Client certificate and assuming Certificate Trust List (CTL) will limit the list of Trusted Certificate Authorities (CA's) being sent to the client during the initial SSL handshake.

    In IIS 5.0 Post MS04-011 update and IIS 6.0/7.0 using CTL's you cannot limit the list of CA's sent back to the client during the SSL/TLS handshake. i.e. you can't use CTL's to limit the list of certificates that Internet Explorer is showing. IE will show all the certificates irrespective of whether the issuing CA is a part of the CTL or not.

    This however is not applicable to Apache web server. Apache will send the list of CA's which are part of the CTL. The above behavior was implemented in IIS as a security design feature. You can use OpenSSL to check the behavior:

    Let's assume we have a web site www.test.com which accepts client certificates. OpenSSL will show the following transaction. Note that it sends the list of all the CA's even if you have configured CTL to allow specific CA's.

     

    C:\>OpenSSL s_client -connect www.test.com:443 -prexit
    Loading 'screen' into random state - done
    CONNECTED(00000790)
    depth=0 /C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 /C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 /C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    verify error:num=21:unable to verify the first certificate
    verify return:1
    ---
    Certificate chain
    0 s:/C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
       i:/DC=com/DC=Saurabh1/CN=Microsoft
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIE3DCCA8SgAwIBAgIKEfew+wAAAAAANTANBgkqhkiG9w0BAQUFADBDMRMwEQYK
    CZImiZPyLGQBGRYDY29tMRgwFgYKCZImiZPyLGQBGRYIU2F1cmFiaDExEjAQBgNV
    BAMTCU1pY3Jvc29mdDAeFw0wNzExMTYyMzE1MjFaFw0wOTExMTUyMzE1MjFaMGgx
    CzAJBgNVBAYTAkNBMRIwEAYDVQQIEwlLYXJuYXRha2ExEjAQBgNVBAcTCUJhbmdh
    bG9yZTEMMAoGA1UEChMDYWJjMQwwCgYDVQQLEwNJSVMxFTATBgNVBAMTDHd3dy50
    ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyHwhBcSOgyfAe2WJ
    2m391qWNTEKj9ScSKrbrzxEFWqEKIReH5pkabxG188vX1uQoo5MUCGd3WIEAb3Xa
    T+mY7P/nA3fwMEUjF1apwXPwQf8hpx5GXhPM6YjyizFGxq06qgNTG3+gCh8arwhu
    u8f9zKOEUicGDOJaQHIK1ofp4G8CAwEAAaOCAi8wggIrMAsGA1UdDwQEAwIFoDBE
    BgkqhkiG9w0BCQ8ENzA1MA4GCCqGSIb3DQMCAgIAgDAOBggqhkiG9w0DBAICAIAw
    BwYFKw4DAgcwCgYIKoZIhvcNAwcwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0O
    BBYEFBi8sz9sklijc8tObd/kfYp13IQXMB8GA1UdIwQYMBaAFAVRxGOV1iHL6wJC
    f2vFzSTt5QFwMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9sYXhtaW5iLnNhdXJh
    YmgxLmNvbS9DZXJ0RW5yb2xsL01pY3Jvc29mdC5jcmwwggEVBggrBgEFBQcBAQSC
    AQcwggEDMIGpBggrBgEFBQcwAoaBnGxkYXA6Ly8vQ049TWljcm9zb2Z0LENOPUFJ
    QSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25m
    aWd1cmF0aW9uLERDPVNhdXJhYmgxLERDPWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/
    b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBVBggrBgEFBQcwAoZJ
    aHR0cDovL2xheG1pbmIuc2F1cmFiaDEuY29tL0NlcnRFbnJvbGwvTEFYTUlOQi5T
    YXVyYWJoMS5jb21fTWljcm9zb2Z0LmNydDAhBgkrBgEEAYI3FAIEFB4SAFcAZQBi
    AFMAZQByAHYAZQByMA0GCSqGSIb3DQEBBQUAA4IBAQAPf48JnKDC5qnGUOwzPsVY
    iz454kHCa6hWxO4L8Lf4uZ/iTwhjvG+LsPZpsijxAkpa/Me2YAtTJS8HaKa0l+on
    VAsDl4AJLK0epH7iQUfahe5BH3DxYcXFi2uAZeSFa12STxa5Ywtknrlxelimzak+
    CgEZTSUDTtSDAOxwIpIXlmsPzBmaI7Cx6+R0Kul3H+DPRP/iE/Qh7yzlXbDqcAsA
    i91ungRcHtiFxkLSwfRbV/qyr2OszKa+7SM9GJ6R0lJC5oRBy/JkQqWiAYvRaf5J
    iTdC7eourVL+TH+GhXnFpmCs+YlotkWLj7EsLKwKiEuX8mm8T6UXKzis2OazfHfh
    -----END CERTIFICATE-----
    subject=/C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    issuer=/DC=com/DC=Saurabh1/CN=Microsoft
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1384 bytes and written 324 bytes
    ---
    New, TLSv1/SSLv3, Cipher is RC4-MD5
    Server public key is 1024 bit
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : RC4-MD5
        Session-ID: B21A0000950C415B75F380724109AE354A29437F77C62FCEF493BD823C62C616
        Session-ID-ctx:
        Master-Key: 6A2F53DBE5ED1565D1E7CB218B4D1B7AF7CFE07594469D69772C26232BBB0253326ACC25A106D3A6B452
    1B3B0989D57D
        Key-Arg   : None
        Start Time: 1197061986
        Timeout   : 300 (sec)
        Verify return code: 21 (unable to verify the first certificate)
    ---
    GET /test.asp
    depth=0 /C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 /C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 /C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    verify error:num=21:unable to verify the first certificate
    verify return:1
    read R BLOCK
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <HTML><HEAD><TITLE>The page requires a client certificate</TITLE>
    <META HTTP-EQUIV="Content-Type" Content="text/html; charset=Windows-1252">
    <STYLE type="text/css">
      BODY { font: 8pt/12pt verdana }
      H1 { font: 13pt/15pt verdana }
      H2 { font: 8pt/12pt verdana }
      A:link { color: red }
      A:visited { color: maroon }
    </STYLE>
    </HEAD><BODY><TABLE width=500 border=0 cellspacing=10><TR><TD>

    <h1>The page requires a client certificate</h1>
    The page you are attempting to access requires your browser to have a Secure Sockets Layer (SSL) cli
    ent certificate that the Web server will recognize. The client certificate is used for identifying y
    ou as a valid user of the resource.
    <hr>
    <p>Please try the following:</p>
    <ul>
    <li>Contact the Web site administrator if you believe you should be able to view this directory or p
    age without a client certificate, or to obtain a client certificate.</li>
    <li>If you already have a client certificate, use your Web browser's security features to ensure tha
    t your client certificate is installed properly. (Some Web browsers refer
    to client certificates as browser or personal certificates.)</li>
    </ul>
    <h2>HTTP Error 403.7 - Forbidden: SSL client certificate is required.<br>Internet Information Servic
    es (IIS)</h2>
    <hr>
    <p>Technical Information (for support personnel)</p>
    <ul>
    <li>Go to <a href="http://go.microsoft.com/fwlink/?linkid=8180">Microsoft Product Support Services</
    a> and perform a title search for the words <b>HTTP</b> and <b>403</b>.</li>
    <li>Open <b>IIS Help</b>, which is accessible in IIS Manager (inetmgr),
    and search for topics titled <b>About Certificates</b>, <b>Using Certificate Trust Lists</b>, <b>En
    abling Client Certificates</b>, and <b>About Custom Error Messages</b>.</li>
    </ul>

    </TD></TR></TABLE></BODY></HTML>

    read:errno=0
    ---
    Certificate chain
    0 s:/C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
       i:/DC=com/DC=Saurabh1/CN=Microsoft
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIE3DCCA8SgAwIBAgIKEfew+wAAAAAANTANBgkqhkiG9w0BAQUFADBDMRMwEQYK
    CZImiZPyLGQBGRYDY29tMRgwFgYKCZImiZPyLGQBGRYIU2F1cmFiaDExEjAQBgNV
    BAMTCU1pY3Jvc29mdDAeFw0wNzExMTYyMzE1MjFaFw0wOTExMTUyMzE1MjFaMGgx
    CzAJBgNVBAYTAkNBMRIwEAYDVQQIEwlLYXJuYXRha2ExEjAQBgNVBAcTCUJhbmdh
    bG9yZTEMMAoGA1UEChMDYWJjMQwwCgYDVQQLEwNJSVMxFTATBgNVBAMTDHd3dy50
    ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyHwhBcSOgyfAe2WJ
    2m391qWNTEKj9ScSKrbrzxEFWqEKIReH5pkabxG188vX1uQoo5MUCGd3WIEAb3Xa
    T+mY7P/nA3fwMEUjF1apwXPwQf8hpx5GXhPM6YjyizFGxq06qgNTG3+gCh8arwhu
    u8f9zKOEUicGDOJaQHIK1ofp4G8CAwEAAaOCAi8wggIrMAsGA1UdDwQEAwIFoDBE
    BgkqhkiG9w0BCQ8ENzA1MA4GCCqGSIb3DQMCAgIAgDAOBggqhkiG9w0DBAICAIAw
    BwYFKw4DAgcwCgYIKoZIhvcNAwcwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0O
    BBYEFBi8sz9sklijc8tObd/kfYp13IQXMB8GA1UdIwQYMBaAFAVRxGOV1iHL6wJC
    f2vFzSTt5QFwMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9sYXhtaW5iLnNhdXJh
    YmgxLmNvbS9DZXJ0RW5yb2xsL01pY3Jvc29mdC5jcmwwggEVBggrBgEFBQcBAQSC
    AQcwggEDMIGpBggrBgEFBQcwAoaBnGxkYXA6Ly8vQ049TWljcm9zb2Z0LENOPUFJ
    QSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25m
    aWd1cmF0aW9uLERDPVNhdXJhYmgxLERDPWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/
    b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlvbkF1dGhvcml0eTBVBggrBgEFBQcwAoZJ
    aHR0cDovL2xheG1pbmIuc2F1cmFiaDEuY29tL0NlcnRFbnJvbGwvTEFYTUlOQi5T
    YXVyYWJoMS5jb21fTWljcm9zb2Z0LmNydDAhBgkrBgEEAYI3FAIEFB4SAFcAZQBi
    AFMAZQByAHYAZQByMA0GCSqGSIb3DQEBBQUAA4IBAQAPf48JnKDC5qnGUOwzPsVY
    iz454kHCa6hWxO4L8Lf4uZ/iTwhjvG+LsPZpsijxAkpa/Me2YAtTJS8HaKa0l+on
    VAsDl4AJLK0epH7iQUfahe5BH3DxYcXFi2uAZeSFa12STxa5Ywtknrlxelimzak+
    CgEZTSUDTtSDAOxwIpIXlmsPzBmaI7Cx6+R0Kul3H+DPRP/iE/Qh7yzlXbDqcAsA
    i91ungRcHtiFxkLSwfRbV/qyr2OszKa+7SM9GJ6R0lJC5oRBy/JkQqWiAYvRaf5J
    iTdC7eourVL+TH+GhXnFpmCs+YlotkWLj7EsLKwKiEuX8mm8T6UXKzis2OazfHfh
    -----END CERTIFICATE-----
    subject=/C=CA/ST=Karnataka/L=Bangalore/O=abc/OU=IIS/CN=www.test.com
    issuer=/DC=com/DC=Saurabh1/CN=Microsoft
    ---
    Acceptable client certificate CA names
    /DC=com/DC=Saurabh1/CN=Microsoft
    /DC=com/DC=Saurabh1/CN=Saurabh CA
    /C=US/O=VeriSign, Inc./OU=Class 1 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign,
    Inc. - For authorized use only/OU=VeriSign Trust Network
    /C=US/O=VeriSign, Inc./OU=Class 4 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign,
    Inc. - For authorized use only/OU=VeriSign Trust Network
    /C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting/OU=Certification Services Division/CN=Thawte P
    ersonal Freemail CA/emailAddress=personal-freemail@thawte.com
    /C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting/OU=Certification Services Division/CN=Thawte P
    ersonal Premium CA/emailAddress=personal-premium@thawte.com
    /C=US/O=First Data Digital Certificates Inc./CN=First Data Digital Certificates Inc. Certification A
    uthority
    /C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting/OU=Certification Services Division/CN=Thawte P
    ersonal Basic CA/emailAddress=personal-basic@thawte.com
    /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
    /C=US/O=VeriSign, Inc./OU=Class 2 Public Primary Certification Authority
    /C=US/O=VeriSign, Inc./OU=Class 1 Public Primary Certification Authority
    /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign,
    Inc. - For authorized use only/OU=VeriSign Trust Network
    /C=HU/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Uzleti (Class B) T
    anusitvanykiado
    /C=US/O=GTE Corporation/CN=GTE CyberTrust Root
    /C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root
    /C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Li
    mited/CN=Entrust.net Secure Server Certification Authority
    /C=HU/ST=Hungary/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Kozjegy
    zoi (Class A) Tanusitvanykiado
    /C=US/O=VeriSign, Inc./OU=Class 2 Public Primary Certification Authority - G2/OU=(c) 1998 VeriSign,
    Inc. - For authorized use only/OU=VeriSign Trust Network
    /C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Root
    /C=HU/L=Budapest/O=NetLock Halozatbiztonsagi Kft./OU=Tanusitvanykiadok/CN=NetLock Expressz (Class C)
    Tanusitvanykiado
    /OU=Copyright (c) 1997 Microsoft Corp./OU=Microsoft Corporation/CN=Microsoft Root Authority
    /DC=com/DC=microsoft/CN=Microsoft Root Certificate Authority

    ---
    SSL handshake has read 7991 bytes and written 740 bytes
    ---
    New, TLSv1/SSLv3, Cipher is RC4-MD5
    Server public key is 1024 bit
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : RC4-MD5
        Session-ID: 7F0A00002D0024D14CCB9D959D185669A22B6F9ECF613E75C0B9A7DD75DD436A
        Session-ID-ctx:
        Master-Key: A17E388F8744B03CAA268418A700F92B5BABDBD09908F8E5503B299579CA4C09A93CCEC5BBCB7BD2F39A
    2C64EF36F674
        Key-Arg   : None
        Start Time: 1197061993
        Timeout   : 300 (sec)
        Verify return code: 21 (unable to verify the first certificate)
    ---

    This is the default behavior for IIS 5.0 (Post MS04-011), IIS 6.0 and to my knowledge will remain so going forward with IIS 7.0 as well.

  • Care, Share and Grow!

    Automate client certificate one-to-one mapping in IIS 6.0 using C#

    • 32 Comments

    In PSS, we occasionally get requests from our customers wherein they want to automatically add entries for client certificate mapping in IIS or Active Directory (AD). That is either a 1-to-1, Many-to-1 or AD mapping for the client certificate authentication for the web site. I recommend going with AD mapping because that eases the management but it finally depends upon one's need.

    I am not sure but I feel there is a security breach plus annoyance when an administrator has to laboriously enter the mappings for all the accounts/certificates (I am being specific to 1-to-1/Many-to-1 here).

    The concern I feel when dealing with the administrator doing it for 1-to-1 and Many-to-1 are:

    a. If there are hundreds of users you need to do this manually for everyone of those accounts and it's a pain.

    b. Yes, the above can be automated using a script but then the second concern that arises is that whoever is running the script has to know the passwords for all these accounts to be mapped. I think this doesn't sound good.

    I have written a sample application using which users can enter the mappings themselves in the IIS's Client certificate setting, i.e. entries having the client certificate mapped to a windows account (either a local IIS or AD account) and the corresponding password.

    So this is how it works:

    • User accesses this web page from their workstation which already has the client certificate installed.
    • They are authenticated over Basic with SSL.
    • Browser sends across the client certificate as part of the HTTP web request.
    • This application gathers the user account, password plus the client certificate from the incoming HTTP web request and does the mapping in IIS.

     

    image

    I am adding the code here in case someone may want to extract the section for automated scripting instead of using it as a web app.

    This code is also attached to this post as well.

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.DirectoryServices;
     
    /* This sample application is to automate One-to-One Client certificate mapping in IIS 6.0.
     * User should be able to access this site from the browser and select the client certificate
     * in their machine which will be mapped to their account on the IIS server for 1-to-1 mapping. 
     * You need to deploy this application on the IIS server which is hosting the website(s) which 
     * needs client certificate mapping, preferably under its own virtual directory.
     *
     * Important:
     * - Have the authentication for this web application configured to use Basic along with SSL.
     * - Have the "Accept client certificates" or "Require client certificates" selected under 
     *   <Website> -> Properties -> Directory Security -> Secure communications -> Edit -> Client certificates
     * - Ensure the website that we want the mapping for is mentioned in the web.config file associated with
     *   this application under <appSettings>
     * - In the Web.config file we are impersonating an Administrator account for this application. 
     *   <identity impersonate="true" userName="Administrator" password="myadminpassword"/>
     *   This is done because non-admin users cannot modify the IIS metabase. If you do not want users to map
     *   entries themselves through web page you can change this to <identity impersonate="true" />.
     *   In such a case only admins can add the mappings for their user accounts. Non-admins won't be able to 
     *   add the client mapping entries.
     *   This is valid for both domain or local Windows NT accounts.
     * - This app is written using .Net 2.0, ASP.Net 2.0 and above in mind. You should be able to make it work
     *   with ASP.Net 1.1 as well.
     * - You may prefer to run this application under its own dedicated application pool to ensure stability and security.
     * 
     * DISCLAIMER: The code is not tested for production scenarios so use it at your own risk. 
     *             In case one wants to use batch scripting etc or some kind of console app instead 
     *             of web app you can extract the code section from this page which should work fine for the job.
     */
     
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
          {
            Response.Write("<B>Client Certificate One-to-One Mapping Application:</B><BR><HR>");
            Response.Write("Serial number: " + Request.ClientCertificate.SerialNumber + "</BR><HR>");
            Response.Write("Issuer: " + Request.ClientCertificate.Issuer + "</BR><HR>");
            Response.Write("Subject Name: " + Request.ClientCertificate.Subject + "</BR><HR>");
            if (Request.ClientCertificate.IsPresent)
            {
                Response.Write("Validity<BR>");
                Response.Write("&nbsp;&nbsp;&nbsp;&nbsp;Not before: " + Request.ClientCertificate.ValidFrom + "</BR>");
                Response.Write("&nbsp;&nbsp;&nbsp;&nbsp;Not after: " + Request.ClientCertificate.ValidUntil + "</BR><HR>");
            }
            else
                Response.Write("<B>There is no client certificate sent along with the request!</B><HR>");
     
            Response.Write("Authenticated User: " + Request.ServerVariables["AUTH_USER"] + "</BR><HR>");
            Response.Write("Authentication Type: " + Request.ServerVariables["AUTH_TYPE"] + "</BR><HR>");
        }
        protected void Button1_Click(object sender, EventArgs e)
        {
            string user = Request.ServerVariables["AUTH_USER"];
            string password = Request.ServerVariables["AUTH_PASSWORD"];
            string clientCertMappingName = "Mapping for " + user;  // <--- Our One-to-One Mapping name for the entry
            HttpClientCertificate cert = Request.ClientCertificate;
            /*
              If you want to map a client certificate located on the disk instead of the one as part of the 
              HTTP Web request try the code below.
              
              X509Certificate certificate = X509Certificate2.CreateFromCertFile(@"c:\cert.cer");
              X509Certificate certificate = cert.Certificate;
              byte[] certHash = certificate.GetRawCertData();
            */
            byte[] certHash = Request.ClientCertificate.Certificate;
            try
            {
            //Get the name of the Web site for which mapping has to be done from the App settings in the web.config file.
            string friendlyWebsiteName = ConfigurationManager.AppSettings["websitename"].ToString();
     
            //Get the Site Identifier based on the friendly name of the Web Site.
            string siteId = getsiteid(friendlyWebsiteName);
     
            if (siteId != null)
                {
                string sitePath = "IIS://localhost/W3SVC/" + siteId + "/IIsCertMapper";
                using (DirectoryEntry de = new DirectoryEntry(sitePath))
                {
                    de.Invoke("CreateMapping", new object[] { certHash, user, password, clientCertMappingName, true });
                }
                Response.Write("Account Mapped: <B>" + Request.ServerVariables["AUTH_USER"] + "</B></BR>");
                Response.Write("Mapping Name: <B>" + "Mapping for " + Request.ServerVariables["AUTH_USER"] + "</B></BR>");
                Response.Write("Web Site: <B>" + friendlyWebsiteName + "</B></BR>");
                }
            else
                {
                Response.Write("<B>Web Site does not have a valid Site ID. Ensure we have the correct site name in the config file for this app.</B>");
                }
            }
            
            catch (System.Runtime.InteropServices.COMException)
            {
                Response.Write("A COM exception occurred while setting up the mapping.");
            }
            catch (SystemException)
            {
                Response.Write("An error occurred while setting up the mapping.");
            }
            catch (Exception)
            {
                Response.Write("An error occurred while setting up the mapping.");
            }
           
        }
     
        public string getsiteid(string websitename)
        {
            DirectoryEntry root = new DirectoryEntry("IIS://localhost/W3SVC");
            try
            {
                string siteid = null;
                foreach (DirectoryEntry de in root.Children)
                {
                    if (de.SchemaClassName == "IIsWebServer")
                    {
                        if (websitename.ToUpper() == de.Properties["ServerComment"].Value.ToString().ToUpper())
                            siteid = de.Name;
                    }
                }
                if (siteid == null) return null;
                return siteid;
            }
            catch
            {
                return null;
            }
            finally
            {
                root.Close();
            }
        }
    }

     

    Ciao

    Nice weekend!

  • Care, Share and Grow!

    Getting little deeper: How ASP.Net Forms based authentication flows...

    • 6 Comments

    I have been recently supporting Asp.Net apart from IIS in the role of a Microsoft GTSC Developer Support Engineer.

    I had been a programmer earlier, but had more expertise on C, C++ and other unmanaged non-web stuffs. I am new to Web technology as per the programming background is concerned. I started working on specific topics which we regularly encounter in our daily support calls, and found Forms based authentication to be one of the most interesting and challenging topics to troubleshoot.

    Here i take a moment to dig deep in explaining the forms authentication. The below analysis helped me in a big way to understand how the HTTP traffice flows and what are the headers we need to concentrate upon.

    I will show a series of Web request/response flows when a user tries to access a website which is configured for Forms based authentication.

    Let's say, a user requests for accessing a protected web page on a site.

    So accordingly he should be redirected to a login page where he needs to enter the credentials and once validated against a user data store, he should be taken to the requested page.

    For our example I have written a very generic code as shown below:

     

    Default.aspx page, which checks whether user is authenticated or not. If yes, then it displays webpage content. If user is not authenticated he will be redirected to the login page. You can copy paste and try it for yourself.

    Default.aspx

    <%@Page Language="VB" %>
    <%@Import Namespace="System.Web.Security" %>

    <script language="vb" runat="server">

    Sub SignOut(objSender As Object, objArgs As EventArgs)
    'delete the users auth cookie and sign out
    FormsAuthentication.SignOut()
    'redirect the user to their referring page
    Response.Redirect(Request.UrlReferrer.ToString())
    End Sub

    Sub Page_Load()
    'verify authentication
    If User.Identity.IsAuthenticated Then
    'display Credential information
    displayCredentials.InnerHtml = "Current User : <b>" & User.Identity.Name & "</b>" & _
    "<br><br>Authentication Used : <b>" & User.Identity.AuthenticationType & "</b>"
    session("Name") = User.Identity.Name
    Else
    'Display Error Message
    displayCredentials.InnerHtml = "Sorry, you have not been authenticated."
    End If
    End Sub

    </script>

    <html>
    <head>
    <title>Forms Authentication</title>
    </head>
    <body bgcolor="#FFFFFF" text="#000000">
    <span class="Header">Forms Based Authentication using standard method</span>
    <br>
    <br>
    <div id="displayCredentials" runat="server" />
    <br>
    <br>
    <form runat="server" method="POST">
    <asp:TextBox id="TextBox1" runat="server" />
    <asp:Button id="cmdSignOut" text="Sign Out" runat="server" onClick="SignOut" />
    <asp:Button id="Button1" runat="server" text="Submit"/><br>
    <asp:TextBox id="TextBox2" runat="server" />
    </form>
    </body>
    </html>

    Login.aspx

    <%@Page Language="VB" %>
    <%@Import Namespace="System.Web.Security" %>

    <script language="VB" runat="server">

    Sub ProcessLogin(objSender As Object, objArgs As EventArgs)

    If FormsAuthentication.Authenticate(txtUser.Text, txtPassword.Text) Then
    FormsAuthentication.RedirectFromLoginPage(txtUser.Text, chkPersistLogin.Checked)
    Else
    ErrorMessage.InnerHtml = "<b>Something went wrong...</b> please re-enter your credentials..."
    End If

    End Sub

    </script>

    <html>
    <head>
    <title>Standard Forms Authentication Login Form</title>
    </head>

    <body bgcolor="#FFFFFF" text="#000000">
    <form runat="server">
    <table width="400" border="0" cellspacing="0" cellpadding="0">
    <tr>
    <td width="80">Username : </td>
    <td width="10"> </td>
    <td><asp:TextBox Id="txtUser" width="150" runat="server"/></td>
    </tr>
    <tr>
    <td>Password : </td>
    <td width="10"> </td>
    <td><asp:TextBox Id="txtPassword" width="150" TextMode="Password" runat="server"/></td>
    </tr>
    <tr>
    <tr>
    <td></td>
    <td width="10"> </td>
    <td><asp:CheckBox id="chkPersistLogin" runat="server" />Remember my credentials<br>
    </td>
    </tr>
    <tr>
    <td> </td>
    <td width="10"> </td>
    <td><asp:Button Id="cmdLogin" OnClick="ProcessLogin" Text="Login" runat="server" /></td>
    </tr>
    </table>
    <br>
    <br>
    <div id="ErrorMessage" runat="server" />
    </form>
    </body>
    </html>

    For demonstration purpose I have added users to the web.config files instead of using any other store like a SQL server or Active Directory store for storing user's credentials.

    Here is the web.config file section of our interest:

    <configuration>
    <system.web>
    <customErrors mode="Off"/>

    <authentication mode="Forms">
    <forms name="FormsAuthCookie" path="/" loginUrl="login.aspx" protection="All" timeout="1" slidingExpiration="false">
    <credentials passwordFormat="Clear">
    <user name="john" password="test1" />
    <user name="Randy" password="test2" />

    ....
    </credentials>
    </forms>
    </authentication>

    <authorization>
    <deny users="?" />
    </authorization>

    <sessionState
    mode="InProc"
    stateConnectionString="tcpip=127.0.0.1:42424"
    stateNetworkTimeout="10"
    sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
    sqlCommandTimeout="30"
    cookieless="UseCookies"
    cookieName="AppSessionCookie"
    timeout="2">
    </sessionState>

    </system.web>
    </configuration>

    Here if you notice, I have set the SlidingExpiration to False, which mean users will be logged out after a specific interval from the time they logged in, in our case it is set to timeout= "1" min.

    If you want you can encrypt the user's credentials using hash algorithm like SHA1 etc. but it is not in the agenda of this blog.

    I won't go much into the details about the settings here since you will get tonnes of articles on implementing forms based authentication on the net.

    I will basically show you how Request/Response flow occurs between the server and the client during Forms based authentication.

    Here we go:

    Step 1: Client sends a web request for the Default.aspx (or any page of your choice in the website except the login page; who would prefer to go through a login page to access one's desired webpage if given a chance :-)) page to the server.

    [You can focus only on the bold headers for our purpose]

    You type in the following url in the IE browser, http://saurabsi-sec/FormsAuthentication/default.aspx and hit Go!

    From Client

    GET /FormsAuthentication/default.aspx HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
    Accept-Language: en-us
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)
    Host: saurabsi-sec
    Proxy-Connection: Keep-Alive

    Step 2: Server sends a response back to the Client with a status 302 Object Moved:

    From Server

    HTTP/1.1 302 Found
    Date: Thu, 19 Apr 2007 07:11:43 GMT
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    MicrosoftOfficeWebServer: 5.0_Pub
    X-AspNet-Version: 2.0.50727
    Location: /FormsAuthentication/login.aspx?ReturnUrl=%2fFormsAuthentication%2fdefault.aspx
    Cache-Control: private
    Content-Type: text/html; charset=utf-8
    Content-Length: 196

    Notice the Response status code and the Location in the response header. Server says to the client that it (client) needs to resend a request to the url mentioned in the Location header.

    Step 3: Client then resends a new request for a /FormsAuthentication/login.aspx?ReturnUrl=%2fFormsAuthentication%2fdefault.aspx
    page. Now here since the client has to first get to the login.aspx page it will send a GET request first and not a POST request. Remember the first request to any site will be a GET and not POST.

    From Client

    GET /FormsAuthentication/login.aspx?ReturnUrl=%2fFormsAuthentication%2fdefault.aspx HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
    Accept-Language: en-us
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)
    Host: saurabsi-sec
    Proxy-Connection: Keep-Alive

    Remember the querystring ReturnUrl shows the original requested page. Client is supposed to send a request later after authentication is done to this page. This is the way how the request/response maintains a track of the requested page throughout the transaction.

    Step 4: Server sends back the requested login.aspx page with a 200 OK Response.

    From Server

    HTTP/1.1 200 OK
    Date: Thu, 19 Apr 2007 07:11:43 GMT
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    MicrosoftOfficeWebServer: 5.0_Pub
    X-AspNet-Version: 2.0.50727
    Set-Cookie: AppSessionCookie=vtd2qg55mkcypqnn53obxm45; path=/; HttpOnly
    Cache-Control: private
    Content-Type: text/html; charset=utf-8
    Content-Length: 1427

    Notice that Session ID gets created at this stage by the server and is sent along with the response to the client. From now onwards Server will keep track of a user's session using this cookie. Note the session ID gets created at this stage and not the authentication cookie. Remember Session key gets created the moment a successful transaction occurs like a 200 OK between the server and the client.

    Step 5: Now the client has recieved the login.aspx page. It enters the credentials for username and password and sends it across to the server again. Notice that this is a POST request to the login.aspx page now and this time it also sends credentials like username and password. We are sending the username and password as part of the Body of the request and not as part of the header.

    From Client

    POST /FormsAuthentication/login.aspx?ReturnUrl=%2fFormsAuthentication%2fdefault.aspx HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
    Referer:
    http://saurabsi-sec/FormsAuthentication/login.aspx?ReturnUrl=%2fFormsAuthentication%2fdefault.aspx
    Accept-Language: en-us
    Content-Type: application/x-www-form-urlencoded
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)
    Proxy-Connection: Keep-Alive
    Content-Length: 277
    Host: saurabsi-sec
    Pragma: no-cache
    Cookie: AppSessionCookie=vtd2qg55mkcypqnn53obxm45

    You have the option of sending it as a querystring too, in such a case it will form a part of the request header and not body.

    If you check the Queystring here, it shows ReturnUrl=/FormsAuthentication/default.aspx

    Also checking the forms body, we find:

    txtUser=john
    txtPassword=test1
    cmdLogin=Login

    Step 6: Server receives the credentials and then goes ahead and authenticates the user. Once the user has been authenticated server responds back with a 302 Found response ,asking the client to send another request for the originally requested page, i.e. Default.aspx. How it determines the original requested page as default.aspx? You are right, it's through the querystring that we just discussed above.

    From Server

    HTTP/1.1 302 Found
    Date: Thu, 19 Apr 2007 07:11:50 GMT
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    MicrosoftOfficeWebServer: 5.0_Pub
    X-AspNet-Version: 2.0.50727
    Location: /FormsAuthentication/default.aspx
    Set-Cookie:
    FormsAuthCookie=82A747623272A0A3A0C36EC6AD1FBA35A47592B1CFB38E54A1A7C5BC24ECAA2563715D4225EAE8927B98EC3DAD6FB9875E67FCA344AECCA19837A40B2311E373; path=/; HttpOnly
    Cache-Control: private
    Content-Type: text/html; charset=utf-8
    Content-Length: 1590

    Notice the FormsAuthCookie here, this has been set by the server once it authenticates the user. Server goes ahead and sends back this authentication cookie along with the response back to the client. Now next time the client sends back any request in the same session it should have the authentication cookie as well apart from the Session Cookie that was set earlier. Server will recognize the user and the ongoing session with the client based on the cookies sent to it in future requests.

    Step 7: Now is the final round wherein Client after done with all the validation process etc, goes ahead and sends request for the Default.aspx page (remember it was also the very first request sent by the client in the whole process).

    From client

    GET /FormsAuthentication/default.aspx HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
    Referer:
    http://saurabsi-sec/FormsAuthentication/login.aspx?ReturnUrl=%2fFormsAuthentication%2fdefault.aspx
    Accept-Language: en-us
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; InfoPath.2)
    Proxy-Connection: Keep-Alive
    Host: saurabsi-sec
    Pragma: no-cache
    Cookie: AppSessionCookie=vtd2qg55mkcypqnn53obxm45; FormsAuthCookie=82A747623272A0A3A0C36EC6AD1FBA35A47592B1CFB38E54A1A7C5BC24ECAA2563715D4225EAE8927B98EC3DAD6FB9875E67FCA344AECCA19837A40B2311E373

    Notice the cookies here. You will see there are two cookies being sent to the server separated by ";". One for the server to recognize the ongoing session with the client and the other one to recongize the authenticated user.

    Step 8: Server has nothing else to do much but send back the response to the client for the requested web page.

    From Server

    HTTP/1.1 200 OK
    Date: Thu, 19 Apr 2007 07:11:50 GMT
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    MicrosoftOfficeWebServer: 5.0_Pub
    X-AspNet-Version: 2.0.50727
    Cache-Control: private
    Content-Type: text/html; charset=utf-8
    Content-Length: 1111

    You might notice something here, in the web.config file we had set the timeout value for Forms authentication cookie to be 1 minute, and session cookie to be 2 minutes. So, you might see a scenario wherein let's say a user gets logged out because of expired authentication cookie. In our example let's say a user gets logged out after 1 minute (authentication cookie timeout value being set to 1 minute), and he is redirected to login page. He logs in back this time after entering the credentials in the login page. But this time he uses a different credentials to login.

    So what should happen, should the new user (with a different credentials this time) have access to all the original session variables (assuming session timeout has still not expired for the earlier user session) of the previous user when the same browser instance is running?

    Answer is Yes, the new user with a different credentials this time will have access to all the session variables for the previous user, provided the same browser session is being used this time. Resaon being that the authentication cookie has expired but not the session cookie, so browser sends the vaild session cookies to the server and hence is able to access the session variables.

    If we use a different browser session, of course a new session cookie has to be obtained which will invalidate session variables for the prevoius user.

    Here I haven't gone into troubleshooting session loss issues, rather i have focused on how forms authentication process occurs between client and the server. In case your eyes are looking for some good logical reading on troubleshooting Session loss issues in ASP.Net, a must READ here http://aspalliance.com/1182_Troubleshooting_Session_Related_Issues_in_ASPNET

  • Care, Share and Grow!

    Service Principal Name (SPN) checklist for Kerberos authentication with IIS 7.0/7.5

    • 3 Comments

    In continuation to one of my earlier posts which focused on IIS 6.0 this post is more about the confusion that may arise around SPNs for setting up Kerberos authentication in IIS 7.0. IIS 7.0 has a new Kernel-mode authentication feature using which the ticket for the requested service is decrypted using Machine account (Local system) of the IIS server. It no longer depends upon the application pool Identity for this purpose by default and in turn improves the performance.

    Here is how it looks like.

    image

    image

    So what does this mean?

    You no longer need to worry about the correlation between HTTP SPNs and the Application pool Identity that was required in the earlier version i.e. IIS 6.0. But that's not blindly true. There has been some confusion whether we don't have to care at all about SPNs or may have to depending upon the settings. Here is a checklist to give more clarity for different scenarios that you may fall under:

    SCENARIO 1a

    IIS 7.0 Web Site/Application  
    Authentication Integrated Windows authentication
    Application Pool Identity NETWORK SERVICE
    Kernel-Mode authentication Enabled (<attribute name="useKernelMode" type="bool" defaultValue="true" /> in the ApplicationHost.config file)
    Site URL Accessed with the NetBIOS name, like http://<myIISserver-NetBIOS-name>/Default.aspx

    SPNs will be required ONLY for the IIS machine account:

    HOST/<myIISserver-NetBIOS-name>
    HOST/<myIISserver-NetBIOS-name.fully-qualified-domainname> for e.g. HOST/myIISserver.mydomain.com

    ***Note: By default HOST/<myIISserver-NetBIOS-name> and HOST/<myIISserver-NetBIOS-name.fully-qualified-name> is already added for the machine account when a machine is added to a domain and HTTP forms a part of HOST. So you may not have to do anything special here for SPNs. Everything should be set by default.

    You can check the set of existing SPNs for the machine account by running the following command:

    > Setspn.exe -L <myIISserver-NetBIOS-name> or directly using a Snap-in like Adsiedit.msc.

    SCENARIO 1b

    IIS 7.0 Web Site/Application  
    Authentication Integrated Windows authentication
    Application Pool Identity Custom account for e.g. Domain1\Username1
    Kernel-Mode authentication Enabled (<attribute name="useKernelMode" type="bool" defaultValue="true" /> in the ApplicationHost.config file)
    Site URL Accessed with the NetBIOS name, like http://<myIISserver-NetBIOS-name>/Default.aspx

    The SPN requirements remain the same as above. You don't have to add SPNs like http/<myIISserver-NetBIOS-name> for the Domain1\Username1 unlike in IIS 6.0 (where we had to add an SPN of the form http/<myIISserver-NetBIOS-name> for the Application Pool identity).

    SPNs will be required ONLY for the IIS machine account:

    HOST/<myIISserver-NetBIOS-name>
    HOST/<myIISserver-NetBIOS-name.fully-qualified-domainname> for e.g. HOST/myIISserver.mydomain.com

    ***Note: By default HOST/<myIISserver-NetBIOS-name> and HOST/<myIISserver-NetBIOS-name.fully-qualified-name> is already added for the machine account when a machine is added to a domain and HTTP forms a part of HOST. So you may not have to do anything special here for SPNs. Everything should be set by default.

    You can check the set of existing SPNs for the machine account by running the following command:

    > Setspn.exe -L <myIISserver-NetBIOS-name> or directly using Snap-in like Adsiedit.msc.

     

    SCENARIO 2a

    IIS 7.0 Web Site/Application  
    Authentication Integrated Windows authentication
    Application Pool Identity NETWORK SERVICE
    Kernel-Mode authentication Enabled (<attribute name="useKernelMode" type="bool" defaultValue="true" /> in the ApplicationHost.config file)
    Site URL Accessed with a Custom Host name, like http://www.mysite.com


    SPNs will be required ONLY for the IIS machine account in the following format:

    HTTP/<site-custom-name> for e.g. HTTP/www.mysite.com

    You can add an SPN using Setspn.exe like

    > Setspn -a http/<site-custom-name> <myIISserver-NetBIOS-name> 

    where <myIISserver-NetBIOS-name> is the IIS machine account and <site-custom-name> is the custom host/host header name for the Web Site URL.

    e.g. > Setspn -a http/www.mysite.com <myIISserver-NetBIOS-name>
    *The command is NOT case sensitive

    You can check the existing set of SPNs for the machine account by running the following command:

    > Setspn.exe -L <myIISserver-NetBIOS-name>

    SCENARIO 2b

    IIS 7.0 Web Site/Application  
    Authentication Integrated Windows authentication
    Application Pool Identity Custom account for e.g. Domain1\Username1
    Kernel-Mode authentication Enabled (<attribute name="useKernelMode" type="bool" defaultValue="true" /> in the ApplicationHost.config file)
    Site URL Accessed with a Custom host/Host header name, like http://www.mysite.com


    SPNs will be required ONLY for the IIS machine account and NOT for Domain1\Username1 account unlike in IIS 6.0.

    HTTP/<site-custom-name> for e.g. HTTP/www.mysite.com

    You can add an SPN using Setspn.exe like

    > Setspn -a http/<site-custom-name> <myIISserver-NetBIOS-name> where <myIISserver-NetBIOS-name> is the IIS machine account and <site-custom-name> is the custom host/host header name for the Web Site URL.

    e.g. > Setspn -a http/www.mysite.com <myIISserver-NetBIOS-name>
    *The command is NOT case sensitive  

    You can check the existing set of SPNs for the machine account by running the following command:

    > Setspn.exe -L <myIISserver-NetBIOS-name>

    Special case of running IIS 7.0 in a WEB FARM

    If you are running IIS 7.0 server in a Web farm the KDC will not know in advance which individual server the request may go to and hence ticket decryption may fail. Hence in such a scenario instead of registering SPNs under a specific machine account use a domain account. I am not a SharePoint guy but based on what I have read on the Web this scenario is also applicable to a single SharePoint server configuration.

    There are two ways to go:

    Either

    Disable Kernel mode authentication and follow the general steps for Kerberos as in the previous IIS 6.0 version. Refer this

    Or,

    [Recommended for Performance reasons]

    Let Kernel mode authentication be enabled and the Application pool's identity be used for Kerberos ticket decryption. The only thing you need to do here is:

    1. Run the Application pool under a common custom domain account.

    2. Add this attribute "useAppPoolCredentials" in the ApplicationHost.config file.

    <system.webServer>
       <security>
          <authentication>
             <windowsAuthentication enabled="true" useKernelMode="true" useAppPoolCredentials="true" />
          </authentication>
       </security>
    </system.webServer>

    Remember there is no GUI setting for this. You need to modify the ApplicationHost.config file from

    <%SystemDrive%>/Windows/System32/inetsrv/config folder on the IIS 7.0 machine.

    3. Add the SPNs in the form:

    http/<virtualhost-name> and

    http/<virtualhost-name.fully-qualified-name>  for the Application Pool Identity.

    Ensure that we don't have such an entry for SPNs for any other account including IIS server machine account.

    ***If we have the same SPN mapped to multiple accounts (be it a machine or an user account) it leads to Duplicate SPNs and will break Kerberos.

    Hope this helps!

  • Care, Share and Grow!

    Unable to load DLL 'bcrypt.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

    • 2 Comments

    I recently had the privilege to get access to a machine from a colleague of mine. It was a Windows server 2003 server and I had to test some ASP.Net application for one of my pet projects. I was focusing completely on the project at hand before I was completely taken off by a surprise, although not a pleasant one.

    I found that my application was throwing the following exception, in fact forget my own application even a test Asp.Net 2.0 page having just a one word was failing. Also this happened for web resources hosted directly in IIS. If you run this app from within Cassini (ASP.Net Web server) you may not see this issue at all. This happened for both Website as well as WAP based applications hosted in IIS.

    Server Error in '/' Application.
    --------------------------------------------------------------------------------
    
    Unable to load DLL 'bcrypt.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E) 
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 
    
    Exception Details: System.DllNotFoundException: Unable to load DLL 'bcrypt.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
    
    Source Error: 
    
    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  
    
    Stack Trace: 
    
    
    [DllNotFoundException: Unable to load DLL 'bcrypt.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
       Microsoft.Win32.Win32Native.BCryptGetFipsAlgorithmMode(Boolean& pfEnabled) +0
       System.Security.Cryptography.Utils.get_FipsAlgorithmPolicy() +140
       System.Security.Cryptography.RijndaelManaged..ctor() +13
       System.Web.Configuration.MachineKeySection.ConfigureEncryptionObject() +232
       System.Web.Configuration.MachineKeySection.EnsureConfig() +156
       System.Web.Configuration.MachineKeySection.GetEncodedData(Byte[] buf, Byte[] modifier, Int32 start, Int32& length) +37
       System.Web.UI.ObjectStateFormatter.Serialize(Object stateGraph) +166
       System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Serialize(Object state) +4
       System.Web.UI.Util.SerializeWithAssert(IStateFormatter formatter, Object stateGraph) +37
       System.Web.UI.HiddenFieldPageStatePersister.Save() +79
       System.Web.UI.Page.SavePageStateToPersistenceMedium(Object state) +105
       System.Web.UI.Page.SaveAllState() +236
       System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1099
    
     
    
    
    --------------------------------------------------------------------------------
    Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053 

    This was quite perplexing as I couldn't find much information on this across the net. One incident I found talked about un-installation of  MS07-040 security update. I was running on .Net framework 2.0 Sp2, Windows Server 2003 SP2. No luck with it. I had no clues about this dll which was missing as in the exception and why the heck it was looking for it in the first place.

    The interesting part here was that the call stack looked like having some encryption/decryption algorithm (RijndaelManaged) being used perhaps related to viewstate. I finally had to disable the attribute EnableViewStateMac="false" for the web page to make it work, but well that may not be an option all the time for everyone.

    If you face such a scenario just don't go ahead with reinstallation of .Net framework 2.0, it may not help you but only drain your precious time.

     

    Analysis/Resolution

    From this KB article this is what RijndaelManaged is all about.

    "ASP.NET 2.0 uses the RijndaelManaged implementation of the AES algorithm when it processes view state data. The ReindaelManaged implementation has not been certified by the National Institute of Standards and Technology (NIST) as compliant with the Federal Information Processing Standard (FIPS). Therefore, the AES algorithm is not part of the Windows Platform FIPS validated cryptographic algorithms."

    To work around this either set EnableViewStateMac to false or else add the following entry as mentioned in the kb under <system.web> section for the web application.

    <machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey="AutoGenerate,IsolateApps" validation="3DES" decryption="3DES"/>

    ASP.NET use the Triple Data Encryption Standard (3DES) algorithm to process view state data instead of the AES (Rijndael) algorithm. Remember this is comparatively weaker than Rijndael based encryption and hence your application will be comparatively insecure.

     

    *Note that the error message in the above article is not exactly the same as what I saw here for this post but the resolution remains the same :-).

     

    Till next time..Beer mug

  • Care, Share and Grow!

    Increase the concurrent connections limit for IIS FTP site if you see server reset

    • 1 Comments

    If you have a FTP site hosted on IIS which receives a burst of client connections at specific intervals and you see the connections getting reset from server-end please read on.

    Let's say you have over 1500 concurrent FTP client connections being made at every 'n' minute you may see that the IIS FTP server is resetting many of those client connections. From a FTP client (the typical ftp.exe from the command prompt) you may see the following:

    "Connection closed by remote host"

    At other times when there is less load on the server things will look good.

    Capturing a network trace may show you that a 3-way handshake between the client and the server is taking place and after that server resets the connection. You don't even get to a point wherein you can enter your credentials to access the FTP site. FTP site's maximum concurrent connections property (MaxConnections) is well above this value.

    If you are in a similar scenario wherein a sudden bursts of concurrent client connections is leading to the FTP server resetting the requests you may want to play with some combinations of the settings mentioned below. It may be that you are hitting some connection limit for your server. It may not be the total number of connections being made but the total number of simultaneous connections that is causing the problem.

    You will have to play with the following settings on the IIS 6.0 server:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\InetInfo\Parameters
        ListenBacklog = xxx (Range: 1 -250, Default: 25)
        MaxPoolThreads = xx (Range: 0 - 4,294,967,295 (unlimited), Default: 4)
        DisableBacklogMonitor=1

    And in the metabase, under /LM/MSFTPSVC/
        ServerListenBacklog=”xxx”

    * The ServerListenBacklog property specifies the number of outstanding sockets that can be queued. The value is based on the AcceptEx operating system parameter, and the server size specified in the ServerSize property. Valid values for this property range from 5 to 500.

    Reset IIS after making the above changes.

    See this link for more details on the Global registry entries for IIS 6.0.   

    The ListenBacklog setting in the registry controls how many active connections are queued by winsock if IIS is unable to service new requests.  ServerListenBacklog is used by IIS to proactively create sockets to handle incoming requests. This setting adjusts the number of outstanding sockets that your Web server can queue. Setting ServerListenBacklog to a higher value allows IIS to handle a larger number of requests, while ListenBacklog helps the system buffer the connection spikes if the number of new connections briefly exceeds what IIS can service immediately.

    Although the range for ListenBacklog  & ServerListenBacklog is given I had seen a scenario wherein we had to adjust the value to a higher number than the given range. You may need to tweak the combination yourself!

    *I give credit to Rob Patrick from PSS IIS Escalation team for this post

Page 1 of 3 (71 items) 123