MaxTokenSize und seine Freunde
Hallo, hier wieder mal Rol mit einem Beitrag zum Troubleshooting und Verständnis von Kerberos MaxTokensSize.
Hintergrund ist ein relativ aktueller Case, welchen wir in unserem Team arbeitet haben. Ein Sharepoint Kollege hatte uns hinzugezogen, da er für einen Benutzer (in unserem Beispiel ganz zufällig der FABIAN) beim Kunden kein gültiges Ticket vom KDC bekommen konnte. Für die entsprechenden IIS Webseite konnte der SPN HTTP/SPSite.contoso.com im Tool KerbTray nicht entdeckt werden, andere Tickets waren aber vorhanden. Bei anderen Usern klappte das gleiche aber tadellos.
Ein Netzwerk Trace konnten wir bekommen. Das haben wir uns angesehen, und zwar mit dem Netmon 3.3 unter Verwendung der Menü Funktion “Reassemble” (welche dann eine neues Analyse-Fenster öffnet), damit der Parser alle zusammenhängende Pakete verarbeitet und nicht nur das erste Paket untersucht.
Das ist übrigens generell für viele Protokolle eines wichtiges Vorgehen, wenn der Protokollheader hehr als das erste Paket umfassen kann. Bei Kerberos z.B. wird nur so der angeforderte SPN sichtbar.
Im Trace konnte man den Ticket Request von User FABIAN schon sehen:
Client TGS Request
202 15:40:15 14.05.2010 10.10.10.1 10.20.20.1 KerberosV5 KerberosV5:TGS Request Realm: CONTOSO.COM Sname: HTTP/spsite.contoso.com
KDC TGS Response
204 15:40:15 14.05.2010 10.20.20.1 10.10.10.1 KerberosV5 KerberosV5:TGS Response Cname: FABIAN
Eine Antwort hatte er also bekommen, nur war diese nicht in den Ticket Cache gewandert. Interessant ist noch, daß in der TGS Response die Gesamtlänge der Antwort in Frame 204 schon recht groß ist:
Kerberos: TGS Response Cname: FABIAN
Length: Length = 10699
Vergleicht man das mit den funktionieren Zugriff von Benutzer FLORIAN, dann sieht das bei dem ganz anders aus:
292 15:42:15 14.05.2010 10.10.10.2 10.20.20.1 KerberosV5 KerberosV5:TGS Request Realm: CONTOSO.COM Sname: HTTP/spsite.contoso.com 294 15:42:15 14.05.2010 10.20.20.1 10.10.10.2 KerberosV5 KerberosV5:TGS Response Cname: FLORIAN Length: Length = 2880
Noch interessanter wird es, wenn man sich dann noch den HTTP GET Request des Benutzers FABIAN ansieht. Hier fehlt jeglicher Authorization Teil im HTTP Header in Frame 210:
210 15:40:15 14.05.2010 10.20.20.1 10.30.30.3 HTTP HTTP:Request, GET /
211 15:40:15 14.05.2010 10.30.30.3 10.20.20.1 HTTP HTTP:Response, HTTP/1.1, Status: Unauthorized, URL: / Using Multiple Authentication Methods
StatusCode: 401, Unauthorized
Im Gut-Fall von FLORIAN kann man hingegen beim HTTP GET den Authorization Teil mit Negotiate für Kerberos deutlich sehen:
301 15:42:15 12.05.2010 10.20.20.2 10.30.30.3 HTTP HTTP:Request, GET / , Using GSS-API Authorization Authorization: Negotiate
Das erhaltene Ticket konnte also nicht im Ticket Cache gehalten und somit auch nicht vom Internet Explorer für den Zugriff auf die Webseite verwendet werden. Ausschlaggebend ist offensichtlich die Größe des vom KDC erhaltenen Tickets.
Kerberos Client Setting MaxTokenSize
Spätestens zu diesem Zeitpunkt kommt jetzt das Setting MaxTokenSize ins Spiel. Aber was steckt eigentlich hinter dieser Einstellung?
MaxTokenSize definiert hierbei den Empfangspuffer für die Antworten vom KDC über direkte und vererbte Gruppenmitgliedschaften (SIDs). Aus diesem Puffer wiederum bezieht LSASS über den Kerberos Client die Ticket Informationen für den entsprechenden User oder Computer Kontext. Paßt die KDC Antwort nicht in den Puffer, kann LSASS das entsprechende Ticket dann auch nicht für einen Ressourcenzugriff zur Verfügung stellen. Warum der Registry Wert nicht “MaxTicketSize” heißt, liegt an einer gewollten Entscheidung unserer Entwickler. Der Empfangspuffer hat eine bestimmte Struktur, also kein flacher Speicherbereich, bei dem intern schon von Token gesprochen wird. Diese Struktur ist auch dafür verantwortlich, daß man MaxTokenSize nicht auf das Byte genau berechnen kann. Daher sind die Vorgehen zur Bestimmung von MaxTokenSize, wie sie z.B. sehr gut im Artikel
327825 New resolution for problems with Kerberos authentication when users belong to many groups
https://support.microsoft.com/default.aspx?scid=kb;EN-US;327825
dargestellt werden, nur als grober Richtwert zu verstehen. Ansonsten ist der Artikel aber mit die beste Referenz zu MaxTokenSize.
In unserem Beispiel hatten jedenfalls die erhalten Gruppenmitgliedschaften (über SID Informationen) in der 10699 Bytes KDC Antwort nicht in den Default Puffer von 12000 Bytes gepaßt.
Im Anschluß haben wir dann auf dem Client MaxTokenSize auf den empfohlenen Maximalwert von 65535 gesetzt:
HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters, MaxTokenSize (REG_DWORD) = 65535 (dezimal)
Und siehe da, nach dem Neustarten des Clients - ging’s immer noch nicht! Hmm…
Serverseitige Anpassung an MaxTokenSize
Warum jetzt das? Nun, ein Blick in ein neues Netmon Trace hat es gezeigt! Diesmal ist im HTTP GET “Authorization: Negotiate” enthalten, jedoch kommt nun der IIS nicht damit zurecht:
314 13:14:37 18.05.2010 10.10.10.1 10.20.20.1 HTTP HTTP:Request, GET / , Using GSS-API Authorization PayloadHeader: Reassembled Protocol=TCP, FrameCount=12,Length=17343 318 13:14:37 18.05.2010 10.20.20.1 10.10.10.1 HTTP HTTP:Response, HTTP/1.1, Status: Bad request, URL: /
HtmlElement: Bad Request (Request Header Too Long)
Hier ist die IIS Antwort nun relativ aussagekräftig. Der GET Request Header ist dem IIS mit 17343 Bytes zu groß. Er kann per Default nur 16k annehmen.
Nach Rücksprache mit unseren IIS Kollegen und der Referenz aus Artikel
920862 Error message when an Outlook Web Access user tries to access a mailbox in Exchange Server 2003: “HTTP 400 Bad Request (Request header too long)”
https://support.microsoft.com/default.aspx?scid=kb;EN-US;920862
For IIS 6.0 (Microsoft Windows Server 2003), the MaxFieldLength entry and the MaxRequestBytes entry are found under the following registry subkey. Configure them as shown in the following table.
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\HTTP\Parameters]
(DWORD)"MaxFieldLength"= 65534
(DWORD )"MaxRequestBytes"=500000
haben wir dann die Anpassung für IIS vorgenommen. Nach dem Stoppen und Starten des IIS Dienstes konnte nun der IIS den großen Ticket Blob aus FABIANs HTTP GET Request erst verarbeiten und ein valides Token für den Zugriff bilden.
MaxTokenSize sollte im übrigen immer konsistent auf allen potentiellen Kerberos Clients im Forest gesetzt werden, also auch auf Servern und DCs. Der optimale Weg ist über Policies, gemäß
938118 How to use Group Policy to add the MaxTokenSize registry entry to multiple computers
https://support.microsoft.com/default.aspx?scid=kb;EN-US;938118
Ich hoffe der Blog macht deutlich wie Kerberos mit MaxTokenSize auf der Clientseite funktioniert, aber auch wie es sein kann, daß auch die Serverseite angepaßt werden muß. IIS ist hier meines Wissens schon fast eine Ausnahme. Andere Server Applikationen können per Default problemlos mit dem empfohlenen Maximalwert von 65535 Bytes umgehen. Sollten Applikationen nicht damit zurechtkommen, so wird dies Microsoft intern als Design Problem angesehen.
Damit einen guten Start in den hoffentlich deutlich sonnigeren Juni!
Euer Rol
Comments
Anonymous
January 01, 2003
Hallo, nach der Fehlermeldung "Bad Request (Request Header Too Long)" ist die Ursache weiter auf der IIS Seite zu suchen. Es scheint als ob der IIS die neuen Werte nicht gezogen hätte. Evtl hilft ein Reboot. Grüße, RolAnonymous
November 16, 2012
Ich knauple gerade an dieser Problematik, allerdings will es bei meinem Testuser mit etwa 300 Gruppen und dem MaxTokenSize 65534 per GP auf Client verteilt und Neustart des Selbigen und MaxFieldLength"= 65534 | MaxRequestBytes"=500000 auf IIS6 (inkl. IISRESET) trotzdem nicht funtzen. Das was passiert ist zeigt die Aufschrift "", vorher konnte die Seite einfach nicht angezeigt werden. Ich hatte auch mal 210 Gruppen zugewiesen, da hat es auch funktioniert, bei der aussage die Defaultwerte lassen nur 70/80 Gruppenmitgleidschaften zu, müsste ich annehmen, auch da wird ein grösserer Wert gezogen. Allerdings sollen 65534 für ca. 900 Gruppen reichen, da bin ich mit den 300 noch eine Weile weg von. Vielleicht noch eine Idee? Mit freundlichen GrüßenAnonymous
November 16, 2012
Habe vergessen einzutragen, das die Meldung jetzt lautet "Bad Request (Request Header Too Long)"