Portfolio

Мое, типа, портфолио: наиболее интересные случаи с русского форума MS TechNet,  в решении которых мне пришлось непосредственно поучаствовать. Читать далее

О классах Program и Startup — инициализация ASP.NET приложения. Часть II: IWebHostBuilder и Startup

Введение

В первой части статьи был рассмотрен процесс инициализации, общий для любого приложения .NET на базе шаблона Generic Host. А в этой части будет рассмотрена инициализация, специфическая именно для веб-приложения. Именно в эту часть инициализации входят вызовы методов Startup-класса. Если вы не читали первую часть, то рекомендую в нее заглянуть. Причин для этого, минимум две. Во-первых, процесс инициализации, специфической именно для веб-приложения, существенно опирается на механизмы, рассмотренные в первой части: методы интерфейса построителя веб-приложения IWebHostBuilder в основном реализуются через вызовы методов интерфейса постороителя IHostBuilder, и процесс инициализации проходит, в целом, через те же стадии, общие для любого базирующегося на Generic Host приложения .NET Core. А во-вторых, там объяснено, для чего часть информации убрана под спойлеры, и какую информацию под какими спойлером можно увидеть (и решить — а стоит ли ее смотреть).

Читать далее

О классах Program и Startup — инициализация ASP.NET приложения. Часть I: Program и IHostBuilder

Введение. О чем эта статья.

Не так давно на Хабре я увидел статью с многообещающим названием «Что из себя представляет класс Startup и Program.cs в ASP.NET Core» . Меня всегда интересовало и интересует, что именно происходит под капотом той или иной библиотеки или фреймворка, с которыми мне доводится работать. И к веб-приложениям на ASP.NET Core это относится в полной мере. И я надеялся получить из этой статьи новую информацию о том, как работают упомянутые классы при запуске такого приложения. Та статья, к сожалению, меня разочаровала: в ней всего лишь в очередной раз был пересказан кусок руководства, никакой новой информации я оттуда не получил. И при чтении ее я подумал, что, наверное, есть и другие люди, которым, как и мне, интересно не просто знать, как применять тот или иной фреймворк (ASP.NET Core в данном случае), но и как он работает. А так как я по разным причинам последнее время довольно сильно углубился во внутреннее устройство ASP.NET Core, то я подумал, что теперь мне есть много что рассказать о нем из того, что выходит за рамки руководств. И вот потому я решил для начала написать статью про то, что действительно представляют из себя классы Startup и Program — так, чтобы рассказать не столько о том, как ими пользоваться (это есть в многочисленных руководствах, которые, как мне кажется, нет смысла дублировать), а, в основном, о том, как работают эти классы, причем — в контексте работы всего веб-приложения на ASP.NET Core. Однако поскольку необъятное объять нельзя, то предмет этот статьи ограничен. Прежде всего, она ограничивается рассказом только про веб-приложения, созданные с использованием нового типа шаблона приложения — Generic Host. Во-вторых, статья будет посвящена только тому, как происходит инициализация веб-приложения, потому что основная роль рассматриваемых классов именно такова — инициализация и запуск размещенного приложения. Итак, кому рассматриваемая тема, даже в столь ограниченном объеме, интересна — добро пожаловать под кат.

Читать далее

Доверие бывает излишним.

Свежий поучительный случай с русского форума MS TechNet.

Системный администратор  переносит с помощью ADMT объекты из, видимо, исторически сложившегося отдельного домена/леса (назовём его, как и автор поста на форуме, source.ru) в поддомен основного леса (назовём лес target.ru, а домен — branch.target.ru). Между отдельным и основным лесами существует отношение межлесного доверия.

Пользователей и группы он уже перенёс, а вот ресурсы — файловый и терминальный серверы — ещё нет. И чтобы дать пользователям, перенесённым в новый поддомен, возможность работы с ресурсами, оставшимися в старом, администратор, как полагается, перенёс их с сохранением SID пользователей/групп из старого домена в SIDHistory. А также — настроил внешнее отношение доверия домена source.ru домену branch.target.ru и отключил на этом отношении фильтрацию SID.

Однако, вопреки его ожиданиям, перенесённые пользователи не получили доступ к общим папкам файл-сервера через сохранённые в SIDHistory SID старого домена. Администратор предположил, что проблема может быть в фильтрации SID на межлесном отношении доверия. Но так как он не понимал, какое отношение имеет фильтрация SID на межлесном доверии к аутентификации при наличии прямого внешнего доверия, то он обратился с вопросом на форум: правильно ли он предположил причину.

Причиной действительно оказалась фильтрация SID на межлесном доверии. Но вот ответ на вопрос, почему — он, на мой взгляд, весьма поучителен. Вкратце, ответ заключается в том, что внешнее отношение доверия не совсем полноценно: оно не допускает аутентификацию по протоколу Kerberos (а только по протоколу NTLM).

Рассказываю, что там произошло, более подробно. Как известно, при доступе к общим папкам другого сервера в сети используется согласование протокола доступа (Negotiate), при котором предпочтительным является выбор протокола аутентификации Kerberos. Именно этот протокол выбирается, если есть возможность его использовать, а протокол NTLM используется только когда нет возможности использовать Kerberos. В данном случае, благодаря наличию межлесного доверия, использовать Kerberos можно: компьютеры в лесу target.ru могут узнать из AD своего леса, что доступ к ресурсам, полные имена DNS (FQDN) которых имеют суффикс source.ru, осуществляется через межлесное доверие между корнем леса клиента (target.ru) и корнем леса source.ru.

Поэтому клиент из домена branch.target.ru запрашивает у контроллера своего домена билет доступа к службе выдачи билетов (TGT)  корневого домена леса target.ru, а с помощью этого TGT у контроллера корневого домена леса target.ru — TGT для корневого домена леса source.ru. Т.к. внутри леса какая-либо фильтрация SID отсутствует, то оба эти TGT содержат (в поле PAC) SID, принадлежащие домену source.ru, из атрибута SIDHistory.

Далее клиент (который, как мы помним, находится в домене branch.target.ru) запрашивает у контроллера домена source.ru билет на доступ к файл-серверу, используя TGT, полученный от контроллера корневого домена своего леса. И вот на этом этапе контроллер домена source.ru исключает из билета службы SID, принадлежащие домену source.ru — потому что видит, что TGT получен для отношения доверия, для которого SIDHistory запрещена. И клиент (перенесённый из домена source.ru) в результате получает билет доступа к службе файл-сервера, в котором нет SID из атрибута SIDHistory, принадлежавших исходному пользователю/группам из домена source.ru. В результате, учётная запись клиента не получает разрешений для доступа к общим папкам, которые она имела до переноса.

Лечится это просто: разрешением использования SIDHistory для межлесного отношения доверия. Делается это всё той же командой netdom, что и для внешнего отношени доверия, только ключ другой — не /quarantine:NO, а /EnableSIDHistory:YES :

netdom trust source.ru  /domain:target.ru /EnableSIDHistory:YES

Поучительным же моментом является то, что в данном случае внешнее отношение доверия создавать было совсем не нужно. Более того, его наличие маскирует проблему, когда для аутентификации по тем или иным причинам используется NTLM: для NTLM используется аутентифкация через внешнее отношение доверия (на котором фильтрация SID отключена), а потому в целом возникает загадочная и сбивающая системного администратора с толку картина, что к одним ресурсам доступ после переноса учётных записей и групп сохраняется, а к другим (к которым он предоставляется через те же группы) — нет.

О переименовании контроллера домена обратно

Любят наши люди стабильность. Даже когда не слишком получается. Вот очередной случай с форума Microsoft Technet. Жил в некой маленькой конторке домен (в смысле — единственный контроллер домена) с именем SERVER на Windows Server 2003. Жил — не тужил, но вот настало время ему апгрейдиться. То ли потому что Windows Server 2003 уже давно как производителем с поддержки снята, то ли ещё по какой причине — это мне неведомо.
Админ тамошний, не долго думая, поднял второй контроллер — DC2 — на новой современной(почти) Windows 2012, а старый контроллер понизил. Затем, ради этой самой стабильности — чтобы не утруждать себя перенастройкой приложений — дал админ новому контроллеру IP старого и переименовал его в старое имя — SERVER — через свойства системы. И тут что-то пошло не так: сначала при переименовании Windows сообщила, что такое имя уже существует, а после перезагрузки стал недоступным домен, не получилось открыть консоль «AD Users and Computers»… Ну, такой факт, что резервной копии, чтобы вернуть всё взад, у этого админа не было, даже и упоминать не стоит: так всегда бывает в подобных случаях у подобных админов. Короче — печаль.
Читать далее

Новые возможности — новые проблемы: разрешение имён в Windows

Не секрет, что с течением времени появлением новых версий Windows расширяются возможности настройки подсистемы разрешения имён(resolver) в этой ОС. Становится возможным штатным образом делать такие вещи, которые раньше требовали хитрой настройки, если вообще были возможны. Но эти новые возможности несут в себе и потенциал новых проблем, вызванных неправильной их настройкой. И проблемы эти не так то просто обнаружить традиционными инструментами, к которым администраторы привыкли за долгие годы работы. Недавно я как раз занимался обсуждением на русском форуме Technet темы, которая служит хорошей иллюстрацией такого положения дел.

Дело обстояло следующим образом. У автора темы внезапно сервер-член домена (под управлением Windows Server 2012 R2) перестал находить контроллер домена через DNS. В журнале событий при этом имелась соответствующая случаю диагностика в виде довольно часто возникающих предупреждений с Event ID 1014 и источником Microsoft Windows DNS Client: «Разрешение имен для имени _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs… истекло после отсутствия ответа от настроенных серверов DNS», а также — ряда других событий,  в частности — сообщений о проблеме обработки групповой политики из-за невозможности найти контроллер домена. Читать далее

Web Application Proxy — товар скоропортящийся

У Web Application Proxy(WAP) в Widnows Server 2012 R2 есть нехорошая особенность: стоит серверу WAP постоять без дела (в выключенном состоянии или без связи с сервером AD Federation Services) пару недель — и он уже сам по себе не заработает. Симпотматика при этом наблюдается следующая: служба WAP не запускается, фиксируя в журнале событий System событие Event ID 7023 от источника Service Control Manager с ошибкой 401 (Unauthorized):
Читать далее

Публикация Sharepoint на нестандартном порту.

Сегодня встретил на форуме Techent cообщение с такой вот проблемой, касающейся публикации Sharepoint (для справки: автор заменил в URL реальное имя своего домена на слово domen):

Добрый день. Проблема с публикацией SP в интернет.
Задал адрес в альтернативном доступе для Интернет указал как http://sp.domen.ru
На шлюзе (Kerio Control) опубликовал по порту 8855 натом на внутренний адрес и порт 80.
При заходе спрашивает логин-пароль, а далее дико дико тупит. Через раз вываливается в 504 тайм аут. Это если заходить на адрес http://sp.domen.ru:8855/sites/sitename
через раз показывает в итоге сам сайт кое как подгружая страницу, но работать на сайте не получается, ибо как сказал выше постоянно 504 gateway time out.
Что ему нужно? )

Естественно, Sharepoint нужно, прежде всего, чтобы в сопоставлениях альтернативного доступа был указан внешний URL для выделенной под внешней доступ зоны (у автора вопроса это, как выяснилось позже — зона Интернет), содержащий этот самый нестандартный порт 8855. Но и это не всё. Когда я посоветовал автору вопроса добавить во внешний URL зоны Интернет номер порта, он ответил, что он это пробовал, но эффекта это не дало.
После моей просьбы показать настройку сопоставлений альтернативного доступа была получена следующая картинка (с замазанным именем реального домена)

sharepoint-publication

Конечно, предпочтительным вариантом показать сопоставления было получить выдачу команды Get-SPAlternateURL в Powershell (с текстом работать удобнее), но для понимания, кто виноват и что делать, этой картинки достаточно.
На картинке мы видим, что для зоны Интернет назначено единственное (создаваемое по умолчанию) сопоставление внешнего имени (http://sp.domen.ru:8855) самого на себя. Но так как у автора вопроса в реальности подключение на порт 8855 на шлюзе перенаправляется на порт 80 сервера Sharepoint, а не 8855, то это сопоставление не работает. Поэтому подключение извне воспринимается как относящееся к зоне По умолчанию, и в страницах ответа возвращаются URL, соответствующие зоне По умолчанию, но не зоне Интернет.
Чтобы сопоставление заработало, нужно добавить правильный внутренний URL (по которому перенаправляется запрос на шлюзе) в список внутренних URL для зоны Интернет.

Для этого на странице, скриншот который приведен выше, надо перейти по ссылке «Добавить внутренние URL-адреса».  На открывшейся странице в строке ввода «Добавить внутренний URL» следует написать для нашего случая http://sp.domen.ru. А в общем случае там нужно указать URL с именем хоста из внешнего имени (в нашем случае это sp.domen.ru), но с портом внутреннего сервера, на который реально перенаправляются внешние запросы (в нашем случае это — порт HTTP по умолчанию). А в  списке зон  ниже на этой странице нужно выбрать зону Интернет.
При такой настройке Sharepoint будет (в нашем случае) понимать, что если он получил запрос на 80-й порт с именем хоста sp.domen.ru (это имя передаётся в заголовке запроса HTTP), то все URL ссылок в ответе (на картинки, на ссылки для перехода и пр.) должны начинаться с внешнего URL зоны для внешнего доступа — http://sp.domen.ru:8855

После такой настройки публикация Sharepoint ожидаемо заработала.

PS Как сообщил автор, в данном случае публикация была чисто с целью протестировать саму возможность публикации. Ну, а для работы, конечно, в целях безопасности публиковать Sharepoint нужно исключительно по протоколу HTTPS. Но это уже другая история.

 

Windows Server — не для бедных

Была у меня мечта — сделать отказоустойчивое решение для запуска виртуальных машин под Hyper-V в варианте «для бедных» — только на обычных компьютерах, без использования общей дисковой памяти. Виделись мне возможными два варианта реализации. Первый вариант — собрать кластер из трёх хостов Hyper-V с общей памятью в виде кластерного Storage Spaces с зеркалированием, состоящего из трёх iSCSI-дисков,  а диски iSCSI — подключить с target’ов, размещёнными на тех же самых хостах Hyper-V, разместив при этом отдаваемые виртуальные диски (VHD) на встроенных в хосты физических дисках. Второй вариант — поднять некластерную виртуальную машину на одном узле кластера Hyper-V (разместив её на встроенном физическом диске), настроить её репликацию на второй узел и организовать переключение при необходимости на реплику и обратно скриптом, выполняемым как Generic script role. И оба варианта не удалось реализовать из-за искусственных ограничений, введённых Microsoft при работе некоторых ролей сервера на узлах кластера.

Подробности неудач описаны ниже.

Читать далее

На изолированной от Интернет машине обновления лучше отключать явно.

Ставил сегодня по некоторой, совершенно не важной для дальнейшего рассказа, надобности  .NET 4.0 из полного пакета установки на изолированную от всяческих сетей свежую виртуальную машину (Win2K8 x86 SP2 ) на стенде. Хотя пакет и полный, и формально из интернета ему выкачивать ничего не надо — установить не получилось: установщик вернул код ошибки 0x8024402c. Этот код ошибки, как известно,  относится к службе автоматического обновления (Windows Update) и означает, что эта служба не смогла установить связь с сервером обновлений (центральным в Microsoft или местным WSUS). Это хорошо было видно и по журналу этой службы (%WinDir%\WindowsUpdate.log): да, пыталась, да получила ошибку таймаута.

Ну, почему получила ошибку — это очевидно: машина-то к интернету не подключена, совсем. Интереснее другое: зачем она вообще туда полезла и, главное, — как сделать, чтобы не лазила, причём второе важнее. Поэтому у меня возникла идея всё-таки слазить в настройки Windows Update и явным образом указать не проверять обновления.

Идея сработала — после отключения обновлений пакет .NET 4.0 установился без проблем.