Windows-Authentifizierung zeigt ständig Anmelde-Bildschirm

Heute habe ich bei einem Kunden den Fall gehabt, dass trotz dass Windows-Anmeldung im IIS 7 konfiguriert war, und im korrekt angezeigten Browser-Anmelde-Dialog die richtigen Anmeldedaten eingegeben wurden, keine Anmeldung möglich war.

Vielmehr ist 3 mal der Anmelde-Dialog erschienen und danach kam die HTTP-Fehlermeldung 401.2 (oder war’s 401.1?).

Die Lösung wurde dann von einem wirklich kompetenten Administrator beim Kunden geliefert: Die Authentifizierungsprovider waren in der Reihenfolge „Negotiate“ und dann „NTLM“.

Als wir NTLM ganz nach oben geschoben haben, ging alles.

windows-authentication-not-working
windows-authentication-successfully-working

OMG!

CryptographicException bei Verwendung von Oracle.ManagedDataAccess lösen

Gestern hatte ein Kollege beim Aufsetzen einer Website ASP.NET MVC 4 auf einem IIS unter Windows Server 2008 R2 eine Fehlermeldung:

[CryptographicException: Unbekannter Fehler -1073741766.]
   System.Security.Cryptography.ProtectedData.Protect(Byte[] userData, Byte[] optionalEntropy, DataProtectionScope scope) +504
   Oracle.ManagedDataAccess.Client.ConnectionString.Secure() +493
   OracleInternal.ConnectionPool.PoolManager`3.Initialize(ConnectionString cs) +1760
   OracleInternal.ConnectionPool.OraclePoolManager.Initialize(ConnectionString cs) +21
   OracleInternal.ConnectionPool.OracleConnectionDispenser`3.GetPM(ConnectionString cs, PM conPM, ConnectionString pmCS, Byte[] securedPassword, Byte[] securedProxyPassword, Boolean& bAuthenticated, Boolean& newPM) +296
   OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, Byte[] securedPassword, Byte[] securedProxyPassword) +1576
   Oracle.ManagedDataAccess.Client.OracleConnection.Open() +3756
   OracleInternal.EntityFramework.EFOracleProviderServices.GetDbProviderManifestToken(DbConnection connection) +274
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +91

[ProviderIncompatibleException: Der Anbieter hat keine ProviderManifestToken-Zeichenfolge zurückgegeben.]
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +10947809
   System.Data.Entity.ModelConfiguration.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection) +48

[ProviderIncompatibleException: An error occurred while getting provider information from the database. This can be caused by Entity Framework using an incorrect connection string. Check the inner exceptions for details and ensure that the connection string is correct.]
   System.Data.Entity.ModelConfiguration.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection) +242
   System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) +82
   System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) +88
   System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input) +248
   System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +524
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +26
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +71
   System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator() +21
   System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +446
   System.Linq.Enumerable.ToList(IEnumerable`1 source) +80

Zunächst war es eine Herausforderung, statt den „normalen“ Oracle.DataAccess-Klassen die Oracle.ManagedDataAccess-Klassen zum Laufen zu bringen. Hier haben uns zwei Artikel geholfen:

Wir haben dann zum Lösen des eigentlichen Fehlers lange rumgesucht, viel ausprobiert und schließlich beim Weblog-Artikel „SOLVED: Windows Identity Foundation – “The system cannot find the file specified”“ fündig geworden.

Die Lösung bestand dann schlicht darin, im Anwendungspool (App Pool) für die Anwendung die Option „Benutzerprofil laden“ auf „True“ zu stellen:

IIS App Pool - Benutzerprofil laden

Danach lief alles wie gewünscht.

Automatically restart Microsoft IIS if website is not available

To automatically restart the Microsoft Internet Information Services (IIS) web server if a website is not available, you need:

  • Administrative access to your web server.
  • The WGET command line utility.
  • A text editor like Notepad to create a batch script file.
  • the Task Scheduler to make the batch script run every n Minutes (e.g. every 10 Minutes)

The batch file I created for one of my own web servers looks like:

@REM ==============================================
@REM Automatically restart IIS if website is not available.
@REM (Checks for a sub string in a page of the website).
@REM
@REM Created 2011-10-28, Uwe Keim uk@zeta.li
@REM ==============================================

@REM Remove any existing previous downloads.
del d:\scripts\index.html

@REM Change drive and folder so that WGET stored in a
@REM well-defined location.
D:
cd d:\scripts

@REM Download file.
D:\scripts\wget.exe ^
    --timeout=30 ^
    --tries=1 ^
    http://www.my-server.com/index.html 

@REM Search for the term in the previously downloaded file.
find /I /C "Some String On Website" d:\scripts\index.html

@REM Restart IIS if string is not found.
IF ERRORLEVEL 1 iisreset /RESTART /TIMEOUT:120 /REBOOTONERROR

Please note the following:

  • WGET downloads the URL to a file with the same file name („index.html“ in my above example)
  • The scheduled task must be created to run with an administrative user.
  • The scheduled task must have the „Run with highest privileges“ checkbox set, because IISRESET only runs with administrative privileges.

Apache und IIS 7 auf derselben Maschine

Hier gibt es eine kleine Anleitung. Auszüge:

There was a question on http://forums.iis.net about having Apache and IIS7 on the same box.  here are the instructions I tested on Vista RTM and Windows Server 2008 B3.  This assumes you have two ip addresses on the box, 192.168.0.90 and 192.168.0.91.  It can be any ip’s.

1) Added or make sure your machine has two ip’s
2) Open a command prompt
3) Type netsh
4) Type http
5) Type sho iplisten.  It should be blank
6) Type add iplisten ipaddress=192.168.0.90
You should get IP address successfully added
7) Type sho iplisten again
It should sho 192.168.0.90 in the list
8) Type exit to get out of netsh
9) Type type netstat -an. See if you notice 192.168.0.90:80 in the list.  If you see 0.0.0.0:80, do an iisreset

10) Download and install Apache ( I did it with 2.2.4)
http://mirror.nyi.net/apache/httpd/binaries/win32/apache_2.2.4-win32-x86-no_ssl.msi
11) Do a default install,
12) Open httpd.conf and adjust the ip listen to 192.168.0.91:80

# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses (0.0.0.0)
#
#Listen 12.34.56.78:80
#Was 80
#Change to

Listen 192.168.0.91:80

12) Restart the Apache service.  (for some reason the start / stop thing didn’t work for me, I used net stop apache2 net start apache2.)
13) Type netstat -an
14) You should see 192.168.0.90:80 and 192.168.0.91:80.  Open a browser and test both IP’s to see if IIS7 and Apache come up.
15) Test restarting Apache service to see if it works after that.
16) Turn off Apache, browse IIS, turn of IIS, browse Apache. Test it every which way to see if it works.

Geht übrigens auch mit mehreren IP-Adressen für den IIS. Dann einfach mehrfach das „add iplisten ipaddress=…“ aufrufen. Geschickt, wenn z.B. mehrere SSL-Websites auf dem IIS installiert werden sollen.

Ergänzung August 2018

Wichtig ist auch, auf der Server-lokalen Firewall auf dem Windows-Server, eine eingehende Regel für Apache einzurichten.

Bei mir sah die Regel grob so aus:

  • Name: Apache HTTP Server
  • Enabled: Ja
  • Action: Allow the connection
  • Program: %ProgramFiles%\Apache24\bin\httpd.exe
  • Profiles: Domain, Private, Public

Es ist also eine Regel auf ein Programm, nämlich „httpd.exe“, das in allen Profilen aktiv ist. Extra Ports habe ich nicht angegeben.

Weiterhin war wichtig, dass der Apache-Dienst als Starttyp „Automatisch (Verzögerter Start)“ eingerichtet hat. Ansonsten kam es bei mir vor, dass der IIS seine Sites deaktiviert hatte, und auch Apache nicht lief. Keine Ahnung, ob das Korrelation oder Kausalität war.

Using UrlRewriter.NET in IIS7

When migrating an IIS6 website to IIS7 you probably want to keep an existing UrlRewriter.NET configuration and migrate to the official Microsoft URL Rewriter Module for IIS 7 later on.

Here is the important excerpt from „Web.config“:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="UrlRewriter"
            type="Intelligencia.UrlRewriter.RewriterHttpModule" />
    </modules>
</system.webServer>

Thanks to Rainer who figured this out from this posting.

Another good discussion can be found in the article „Wildcard script mapping and IIS 7 integrated pipeline“ on the IIS website and the article „Use a Single Web.Config for IIS6 and IIS7„.

Vorsicht bei „Debug.Assert“-Aufrufen in ASP.NET (2.0)-Webanwendungen!

Über vier Manntage hat mich insgesamt das folgende (in meinen Augen falsche) Verhalten von ASP.NET gekostet.

Beschreibung

  • Eine ASP.NET 2.0-Webanwendung läuft in der Testumgebung ganz normal und auch im Echtbetrieb.
  • Zu nicht-vorhersehbaren Zeiten „hängt“ die Anwendung auf einmal. D.h. die Anwendung reagiert für den Benutzer einfach nicht und der Browser lädt ewig.
  • Wenn ich dann den entsprechenden „w3wp.exe“ kille (ich habe extra einen AppPool nur für die eine Webanwendung gemacht), dann wird sofort automatisch ein neuer w3wp.exe gestartet und die Anwendung läuft wieder normal.

Ursache

Ein Aufruf von Debug.Assert in einer von der Webanwendung verwendeten DLL hat den Prozess zum Hängen gebracht.

  • Debug.Assert direkt in einer
    Webanwendung ausgeführt hält den „w3wp.exe“ nicht an, sondern wird
    schlicht ignoriert.
  • Debug.Assert indirekt
    in einer DLL, die von der Webanwendung verwendet wird, hält den
    w3wp.exe an und kann nur durch killen des „w3wp.exe“ beendet werden.

Lösung

Als schnellen Workaround habe ich jetzt alle Debug.Assert-Aufrufe in der DLL auskommentiert. Natürlich könnt Ihr auch schlicht alles im Release-Modus kompilieren, das ist aber in meinem Fall nicht nötig gewesen (keine Performance-Verbesserungen).