Showing posts with label IIS. Show all posts
Showing posts with label IIS. Show all posts

0 comments

SCOM 2012 R2: Web Portal: 503 The Service is Unavailable

Published on Wednesday, August 13, 2014 in ,

The other day one of my customers mentioned that their SCOM Web Portal has been broken for a while now. As I like digging into web application issues I took a quick look. Here’s what I came up with. It seems that the portal itself was loading fine, but viewing All Alerts or Active Alerts showed a Service Unavailable (“HTTP Error 503: The service is unavailable”).

image

One of the things about IIS based errors is that in most cases the Event Log on the web server can help you a great deal. In the System Event Log I found the following:

clip_image001

A process serving application pool 'OperationsManagerMonitoringView' reported a failure trying to read configuration during startup. The process id was '6352'. Please check the Application Event Log for further event messages logged by the worker process on the specific error. The data field contains the error number.

Checking the IIS Management Console I could indeed see that the Application Pool was stopped. Starting it succeeded, but viewing the page made it crash again. Looking a bit further I found the following in the Application Event Log:

clip_image001[5]

The worker process for application pool 'OperationsManagerMonitoringView' encountered an error 'Configuration file is not well-formed XML

' trying to read configuration data from file '\\?\C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG\web.config', line number '14'. The data field contains the error code.

Now that seems pretty descriptive! Using notepad I checked the contents of the file and tried to see why the XML was not well-formed. I checked the XML tags and the closings and such but I couldn’t find anything at first sight. Looking a bit longer I saw that the quotes (“) were different from the other quotes in the file. Here’s a screenshot of the bad line and the fixed line. You can simply erase and retype the “ on that line and you should be good to go.

image

Personally I like taking a backup copy before I perform manual fixes. After saving the file I did an IISReset just to be sure. And after that we were able to successfully view our alerts through the Web Portal again!

0 comments

Troubleshooting Certificates and the Chain Build Process

Published on Monday, November 18, 2013 in ,

Recently I got a request of a customer to update the root certificates of several certificates they had in place. The problem was that one of the intermediate CA’s had an expiration date which was before the expiration date of the actual certificate. Here’s the information we got with this notification.

schema-brca2-server

The problem was the Belgium Root CA2. It’s valid until 27/01/2014 whilst several of the “your servercertificate (SSL)” are valid till the end of 2014. When clients would validate this chain after the 27th of January this would cause problems. With this news we received the new root and intermediate CA’s in a zip file.

Using certutil you can easily install them in the required stores on the server which has “your servercertificate (SSL)” configured for one or more services.

  • certutil -addstore -enterprise Root "C:\Temp\NewRootChain\Baltimore Cybertrust Root.crt"
  • certutil -addstore -enterprise CA "C:\Temp\NewRootChain\Cybertrust Global Root.crt"
  • certutil -addstore -enterprise CA "C:\Temp\NewRootChain\Belgium ROOT CA 2.crt"
  • certutil -addstore -enterprise CA "C:\Temp\NewRootChain\government2011.cer"

After performing these steps I could see the new chain reflected in my certificate on the server. Now I figured that the clients should retrieve this chain as well one way or another. Upon accessing https://web.contoso.com I could see that the certificate was trusted, but the path was still showing the old chain!

First thing I verified was that the “Baltimore Cybertrust Root” was in the trusted root certificate authorities of my client. Without me actually putting it there it was present. This makes sense as this probably comes with windows update or something alike. I assume the client has to retrieve the intermediate certificates himself. I thought that he would go externally for that. From the certificate I found the Authority Information Access URL which pointed to the (outdated) Belgium Root CA2 on an external (publicly available) URL. “AHAH” I figured, time to contact the issuers of these certificates. They kindly replied that if the server has the correct chain, the clients should reflect this. They also provided me an openssl command and requested more information.

This made me dig deeper. After a while I came to the following conclusion: my “bad” client showed different paths for these  kind of certificates… When visiting my ADFS service I saw the correct chain being build, but on my web server I had the old chain. Very odd. So something had to be wrong server side. From what I can tell here’s my conclusion:

The browser gets the intermediate certificates in the chain from the IIS server

  • IIS 8.0 on Windows 2012: update the stores and all is good (or the servers had a reboot somewhere in the last weeks that I’m unaware off)
  • IIS 7.5 on Windows 2008 R2: update the stores AND unbind/bind the certificate in the IIS bindings of your website(s).

For the IIS 7.5 I also tried an IIS reset, but that wasn’t enough. Perhaps a reboot would do too.  Here’s my source for the solution: http://serverfault.com/questions/238206/iis7-not-sending-intermediate-ssl-certificate

A usefull openssl command, even works for services like sldap. It will show you all certificates in the chain.

  • openssl.exe s_client -showcerts -connect contoso.com:636
  • openssl.exe s_client -showcerts -connect web.contoso.com:443

P.S. The new chain also has an oddity… Belgium Root CA2 is valid until 2025 whilst the Cybertrust Global Root expired 2020

Bonus tip #1: in the windows event log (of the client) you can enable CAPI2 logging. This will show you detailed information of all Certificate related operations. In my opinion the logging is often to detailed to tell you much, but it’s nice to know it’s there. You can find it under Application and Services\Microsoft\Windows\CAPI2 right-click Operational and choose enable.

Bonus tip #2: on Windows 2012/ Windows 8 you can easily open the certificates of both the current user and the current computer. In the past I often used mmc > add remove certificates > click some more > … Now there’s a way to open a certificates mmc for the local computer using the command line:

  • Current user: certmgr
  • Current computer: certlm

[Update 20/11/2013] forgot to mention the -enterprise switch in the certutil commands. This ensures the local computer certificate stores are used.

0 comments

Quick Tips: October Edition #1

Published on Monday, October 22, 2012 in ,

Tip #1 (IIS): appcmd and IIS bindings:

Some more IIS (configuration) awesomeness: you can easily view the bindings for an IIS site using the following command:

  • appcmd list site /site.name:”MySite”

Now obviously just viewing isn’t that cool, but you can also set them! This is extremely useful for those environment where you have work according to “Development –> Test –> Acceptance –> Production” or other variances. I hate doing the same task (manually) multiple times.

So here’s how you can “push” your bindings to a site called “MySite” in IIS.

Syntax option #1: just a host header available on all IP’s (*):

  • appcmd set site /site.name:”MySite” /bindings:”http://mysite.contoso.com:80”,”http://mysite:80”

Syntax option #2: a host header bound to one specific IP:

  • appcmd set site /site.name “MySiite” /bindings:”http/192.168.50.11:80:mysite.contoso.com”,”http/192.168.50.11:80:mysite”

Mind the difference in the bindings parameters syntax: e.g. http:// <> http/

Now what if you want to change one specific binding to an other value?

  • appcmd set site /site.name:"MySite" /bindings.[protocol='http',bindingInformation=':80:mysite.contoso.com'].bindingInformation:192.168.50.11:80:mysite.contoso.com

In this example I changed the binding which was listening on all IP address to only listen on a specific IP address.

Or what about adding a binding witouth modifying existing bindings?

  • appcmd set site /site.name:"MySite" /"+bindings.[protocol='https',bindingInformation='192.169.16.105:443:mysite.contoso.com’]

P.S. appcmd is an executable which you can find in the c:\windows\system32\inetsrv directory.

Tip #2 (SQL), is SQL Full Text Search installed?:

One of the prerequisites when installing the FIM Service is that the SQL Full Text Search feature is installed on the SQL Instance hosting your database. There’s two easy ways to see if this is the case:

  • Using the services.msc mmc: check if there’s a service name SQL Server FullText Search ([instance]) where [instance] will be the name of your instance
  • Using the following SQL query: IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled')) print 'INSTALLED' else print 'NOT INSTALLED'

My source: serverfault.com: How to detect if full text search is installed in SQL Server

Tip #3 (Visual Studio): auto-increment version info:

When you create a class in C# or your preferred language you might want to have some version information on the DLL you build. There’s an easy way to configure your solution/project to auto-increment the build version every time you compile your project.

You can do this by directly editing the AssemblyInfo.cs below the properties.

image_thumb

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.0")]

In words: make sure to set the AssemblyVersion to something like “1.0.*” or “1.0.0.*” and comment the AssemblyFileVersion line. As I tested around a bit I noticed the following things:

  • the AssemblyFileVersion does not work with the *
  • If the AssemblyFileVersion is not commented the AssemblyVersion is ignored and the AssemblyFileVersion “wins”.

Some more background information:

Tip #4 (Certificate Authority): RPC traffic check

Often when playing around with certificates I’m hitting gpupdate like hell in order to retrieve auto-enrollment. But if you want to make sure your CA is actually reachable from a given endpoint over RPC/DCOM you can easily check this using the certutil utility. This utility is available out of the box.

  • certutil -ping -config "ca-server-name\ca-name”
  • Example: certutil –ping –config “SRVCA01\Customer Root CA”

4 comments

Temporary Profiles and IIS Application Pool Identities

Published on Monday, September 24, 2012 in , ,

I’m a bit stumbled that I’ve only come across this now. Recently I discovered that there are some cases where you can end up with your service account using a temporary profile. Typically this is the case where your service account has very limited privileges on a Server. Like application pool identities which run as a regular AD user, which I consider a best practice. I myself saw this in the context of the application pool identities in a SharePoint 2010 farm or with SQL Server Reporting Services 2008 R2.

The phenomena is also described at: Todd Carter: Give your Application Pool Accounts A Profile So this does not apply to all Application Pool identities! Only those running with “load profile=true”.

In the Application event log you can find the following event:

Windows cannot find the local profile and is logging you on with a temporary profile. Changes you make to this profile will be lost when you log off.

How to fix it if you see those nasty “c:\users\TEMP” folders?

  1. Stop the relevant application pools
  2. Stop the IIS Admin Service (in services.msc)
  3. See that the TEMP folders are gone in c:\users
  4. Follow the next steps

How to make sure your accounts get a decent profile?

We will temporary add the service account to the local administrators group so they can create a profile. In fact all they need is the “logon locally” privilege. The second command will start a command prompt while loading a profile. This will ensure a proper profile is created.

  1. net localgroup administrators CONTOSO\AppPoolAccount /add
  2. runas /u:CONTOSO\AppPoolAccount /profile cmd
  3. net localgroup administrators CONTOSO\AppPoolAccount /del

As a side note: if the TEMP folders are not disappearing, or you are still getting a temporary profile, you can try to properly cleanup the temporary profile:

  1. Stop the application pools
  2. Stop the IIS Admin Service
  3. Using right-click properties on computer, choose advanced tab and then pick User Profiles. There you can properly delete them.

If you’re still having troubles you might need to delete the TEMP folders manually AND cleanup the following registry location: HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList Especially look if there aren’t any keys with .bak appended to it.

0 comments

Quick Tip: IIS Configuration Backups

Published on Thursday, April 26, 2012 in

Ever modified something in IIS and then wanted to revert but forgot what setting it actually was? Or ever been in a lot of trouble, you know somebody changed something, but not what? Well seems IIS keeps backups of the configuration files for you!

You can find them in c:\inetpub\history

clip_image002

I don’t think they’ll be created when you manually modify those xml configuration files. Might be interesting to check if performing modifications through appcmd make it here. I would guess so.

0 comments

Disable SSL 2.0 on IIS/TMG

Published on Tuesday, April 3, 2012 in ,

Just a quick tip: often after an IIS or TMG project security audits are performed. One of the remarks we often get is that SSL 2.0 is enabled on the web server. To disable this you can simply set the required reg key as explained in KB187498

4 comments

FIM 2010: Warm Up Your Portal (IIS)

Published on Monday, June 20, 2011 in ,

One of the typical things of a webapp deployed on IIS is that everyday the first visitor has a very slow loading page. This is due to the application pool recycling. Every night, somewhere between 2 and 4 (for default installs) the application pools are recycled. After this when the first visitor arrives certain code is loaded again which takes some time. Consequent visitors don’t suffer this phenomena.

In the IIS world there’s a known solution for this: "IIS Warm Up scripts”. There even was  a built-in module for this in IIS 7.5, however it was in beta state and currently has been removed from the web. With some PowerShell and Scheduled Task magic we can warm up IIS just as good. In my example the first user was experiencing a 15-20 seconds delay before the FIM Portal showed up. After applying the following solution that was more like 2 seconds.

Our script which will warm up the site will do this every time the application pool is recycled. The trigger for the scheduled task will be an event in the Application event log. Therefor we have to modify the default settings of the application pool so that it logs these events.

Open the IIS management console and locate the application pool responsible for the SharePoint site hosting your FIM portal

image

Righ-click and choose advanced settings, make sure to set “Specific Time” to True.

image

Every time the application pool is recycled by the schedule defined in the “Specific Times” array the following even will be logged:

image

A worker process with process id of '4420' serving application pool 'SharePoint - 80' has requested a recycle because it reached its scheduled recycle time.

Now the following script can be executed to warm up IIS. It will do this by visiting the page and performing a get. It’s very basic and probably can be improved or rewritten.

function get-webpageWithAuthN([string]$url,[System.Net.NetworkCredential]$cred=$null){
    write-host -foregroundcolor green "Warming up $url";
    $wc = new-object net.webclient;
    $wc.credentials = $cred;
    #$wc.Headers.Add("user-agent", "PowerShell");
    $html = $wc.DownloadString($url);
    #$html
}


#FIM
$website =
http://FIM.setspn.blogspot.com/IdentityManagement
$credentials = [System.Net.CredentialCache]::DefaultCredentials;
get-webpageWithAuthN -url $website -cred $credentials

Now we can create the Scheduled Task. I choose to run it as “local system”. This seems enough to warm up the portal. I think because this way the FIM Service is queried to see if “Local System” (my FIM server itself) is known in the portal. Obviously this is not the case and I will probably see a “Service not available” error. But the point is that the Portal is warmed up!

image

We will add some triggers:

  • Type: On an event
  • Log: System
  • Source: WAS
  • Resource ID: 5076

image

Then we will specify an action:

  • Action: Start a program
  • Program/Script: PowerShell.exe
  • Add arguments: c:\yourfolder\script.ps1
  • Start in: c:\yourfolder

image

If we also want to trigger the script when we an administrator recycles an Application Pool we have to add a trigger for event 5079 (System –> WAS: 5079)

image

If we also want to trigger the script when we perform an IISreset we can add a trigger for the following event 3201 (System > IIS-IISREeset: 3201)

image

image

Obviously this way of working could be applied for other websites too.

2 comments

Kerberos: Troubleshooting Diagram

Published on Thursday, May 20, 2010 in , , , ,

In the past year I’ve become more and more interested and familiar with Kerberos authentication. While I’m not saying that you should “Kerberize” everything, I think everyone installing and configuring apps on the Windows platform should have a basic understanding of it.

Below is a decision-based workflow I created to counter some simple pitfalls. Although some of it might seem easy, it gets forgotten a lot. In the example a user is browsing a web-based application which is reachable at “webapp.contoso.com”. In fact this website is hosted on a server called web01.contoso.com.

Important to note that ending up in the orange field (“client uses NTLM”) isn’t necessarily bad, but it might be when your web app does some form of delegation afterwards. On the other hand, if you end up in the “authentication impossible”, you will never-ever get granted access to the application.

This example is based on a web-based application, but the reasoning is exactly the same when the IE browser is a SQL client and the application pool for the website is a SQL Server service.

Perhaps the most common one to be encountered is the one where someone uses a service account for an application pool instead of the network service. If you then try to access the website with the name of the machine, you will always end up in the “authentication impossible”.

Any feedback or comments is highly appreciated. The chart, click the picture for a clearer view:

image

0 comments

Configuring Kerberos authentication pass through in an IIS 7 NLB setup

Published on Monday, January 19, 2009 in , , ,

Setting up IIS to work with Kerberos authentication might require extra steps when working with NLB configurations. Kerberos is highly dependent of SPN's (Service Principal Names) and DNS. SPN's are defined in Active Directory and are used by the KDC (Key Distribution Center) in the Kerberos authentication process.
When a user accesses a webservice hosted by a web server, for example http://server01.domain.local, the user will request a Kerberos ticket for the http service hosted on server01.domain.local. The KDC service in the domain will hand out such a ticket and the client will successfully retrieve the website content.
In the NLB scenario however, we could access http://server01.domain.local and http://server02.domain.local which would work fine, but when setting up a load balancing cluster users are supposed to access the web server at http://nlbweb.domain.local. If we do visit http://nlbweb.domain.local we will notice the kerberos single sign on we had for http://server01 and http://server02 is broken.
This can eassily be explained by the fact that there is no one responsible for the http://nlbweb.domain.local service in Active Directory. By default a computer will have two SPN's in AD: termsrv and Host. The Host SPN will be used for a services hosted by the computer which use the local system or network account. Therefore when someone accesses a service using the hostname, authentication will succeed.
Using the setspn tool, available in the Windows 2003 support tools, or built-in in Windows 2008, we can list the registered SPN's and add SPN's.
In a single web server setup, where we would like the users to access our site with a generic name, we could add a SPN for the dns alias:

"setspn -A http/web server01"
"setspn -A http/web.domain.local server01"

Though in a NLB setup, we cannot do this. There is a simple rule to follow: a SPN for a give service should only be registered once in AD! So never add a SPN for a given service on different AD accounts. If we can't add our http/nlbweb service to server01 and server02, we have to delegate it to a user. The following steps are required:
Create an AD user for kerberos delegation:


  • Create a dedicated user for this
  • Make sure to check trust for delegation on the user properties in aduc
  • Make this user member of the IIS_IUSR group on IIS nodes
  • Use this user as identity for the application pool used by the website
  • Add the spn's to the user AD account:  setspn -a http/nlbweb ADuser  setspn -a http/nlbweb.domain.local ADuser  Verify with setspn -l ADuser


  • Configuring the authentication on the IIS nodes:


  • open applicationhost.conf (c:\windows\system32\inetsrv\config\)
  • Locate the website you wish to configure
  • search something like <windowsAuthentication enabled="true" useKernelMode="true" />
  • change it to include useAppPoolCredentials="true": <windowsAuthentication enabled="true" useKernelMode="true" useAppPoolCredentials="true" />


  • And most important: configure the browser or the client


  • Add the URL to the local intranet zone (nlbweb and/or nlbweb.domain.local)
  • Enable windows integrated authtentication on the advanced tab (default is enabled)
  • Automatic logon only in intranet zone (default setting) (or even less restrictive: automatic logon with current username and password)


  • When testing:
    Access the website from a workstation and make sure the zone displayed is the intranet zone and not the internet. Testing the website from one of the nodes is pointless as it will use NTLM instead of kerberos.

    You might enable kerberos debug logging, though keep in mind this will give you a lot "safe to ignore" errors in your eventlogs. Set the following registry key to 1 to enable kerberos logging  (0 to disable again), a reboot is not required
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters
    Registry Value: LogLevel
    Value Type: REG_DWORD
    Value Data: 0x1
     
    Sources:


  • Rakkimk: Enabling Kerberos Delegation on a NLB scenario
  • Ken Schaefer: New in IIS 7 - Kernel Mode Authentication
  • Care, Share and Grow!: Kerberos troubleshooting from IIS perspective
  • Microsoft.com: kb 262177 (enbable kerberos logging)

  • 0 comments

    Display authentication used when accessing an IIS website

    Published on in , ,

    When playing around with web services and kerberos, the following might be usefull determine which authentication is actually being used.

    Copy past the code below in a test.asp file, put it in the root of your web server, make
    sure asp is enabled and it will tell you what kind of authentication your are using:
    * NTLM
    * Kerberos
    * Anonymous
    *...



    <%
    DIM userID
    Dim AuthMethod
    Dim AuthType
    Dim AuthLength
    Dim AuthOther
    ' Get the authentication method being used.
    userID= Request.ServerVariables("LOGON_USER")



    Response.Write "<br> User Id = " & userID
    ' Get the authentication method being used.
    AuthMethod = Request.ServerVariables("AUTH_TYPE")
    ' Get the length of the HTTP_Authorization header (to determine Kerberos or NTLM).
    AuthLength = Request.ServerVariables ("HTTP_Authorization")
    ' If some other authentication method (other than Negotiate) is used, call it "Other".
    If LTrim(RTrim(AuthMethod)) <> "Negotiate" Then AuthOtherMethod
    ' If Negotiate is used, go straight to the subroutine to handle it.
    If LTrim(RTrim(AuthMethod)) = "Negotiate" Then AuthNegotiateMethod

    Sub AuthOtherMethod()
    ' Because anonymous authentication will be blank, be sure that you realize that it is enabled to the following:
    If LTrim(RTrim(AuthMethod)) = "" Then AuthMethod = "Anonymous"
    Response.Write "<table width=500>The user was logged in using the <B>" & AuthMethod & "</B> authentication method."
    Response.Write "<P> If you were expecting a different method to be used,"
    Response.Write " please check the settings for the resource you are accessing. Remember, selecting"
    Response.Write " multiple authentication methods, or allowing anonymous access can result in a "
    Response.Write " different method being used.</table>"
    End Sub

    Sub AuthNegotiateMethod()
    ' Typically, NTLM yields a 150 - 300 byte header, and Kerberos is more like 5000 bytes.
    If LEN(AuthLength) > 1000 Then AuthType = "Kerberos"
    If LEN(AuthLength) < 1000 Then AuthType = "NTLM"
    Response.Write "<table width=500>The <B>Negotiate</B> method was used!<BR>"
    ' Indicate the authentication method that is used to authenticate the user (and show a warning about the script).
    Response.Write "The user was logged on using <B>" & AuthType & "</B>."
    Response.Write "<P><font color=#800000><B>Please do not refresh this page</B></font>.<BR>"
    Response.Write " If you do use refresh, <B>Kerberos</B> will always show up as <B>NTLM</B>."
    Response.Write " This is because the HTTP_Authorization header is being used to determine the authentication method used."
    Response.Write " Since the second request is technically unauthenticated, the length is zero. Please open a new browser"
    Response.Write " for any subsequent requests.</table>"
    End Sub

    %>