Host-Named SiteCollections

В SharePoint 2013 без большого шума появилась новая best-practice, рекомендующая использовать так называемые Host-Named SiteCollection (HNSC). Как обычно это вызывает множество вопросов, на которые я попробую ответить.

Краткий экскурс в историю

Во времена x86 процессоров максимальный объем адресного пространства, которое могло занимать приложение – 2гб. Поэтому для масштабирования был выбран подход, когда вся ферма SharePoint разбивается на несколько “веб-приложений”, каждое из которых представляет один или несколько сайтов на IIS. Тем не менее создание сайтов на IIS – дорогое удовольствие. Каждый сайт запускает как минимум один процесс w3wp, который загружает сборки SharePoint и съедает немало памяти. Поэтому даже придумали лимит веб-приложений.

Еще один фактор, который подталкивает плодить веб-приложения в SharePoint – безопасность. Каждое веб-приложение содержит множество коллекций сайтов, все имеют общий hostname. Это значит что javascript из одной коллекции сайтов может обращаться к ресурсам другой коллекции с правами текущего пользователя (Cross-Site Scripting). А для добавления JavaScript достаточно иметь права хотя бы на одно узле.

Таким образом даже появление x64 версий SharePoint не изменило картину – все использовали веб-приложения и отдельные сайты IIS.

HNSC существовали еще в SharePoint 2003 (только назывались не так). Они позволяли иметь коллекции сайтов с разными hostname в рамках одного веб-приложения SharePoint. Но из-за ограничений и сложностей использования не прижились. В SharePoint 2010 произошло улучшение HNSC в первую очередь для Office 365.

В SharePoint 2013 снова улучшили HNSC и появились некоторые возможности\особенности платформы, которые делают HNSC лучшим выбором.

Для чего нужны HNSC

Обязательно нужно запомнить (ибо понять это сложно): Host-Named SiteCollection это альтернатива веб-приложениям, а не обычным коллекциям сайтов. При использовании HNSC обычные коллекции сайтов, официально называемые Path-Based SiteCollection, все так же доступны.

Как я писал выше, HNSC позволяют создавать коллекции сайтов с разными hostname в рамках одного веб-приложения. В SharePoint 2013 HNSC также научлись поддерживать несколько hostname в разных зонах и SSL Termination и разные режимы аутентификации на основе зон.

С точки зрения API обычные коллекции сайтов не отличаются от HNSC. Важно только помнить что SPSite.Url  может не совпадать ни с одним из Url в объекте SPSite.WebApplication.

Применять HNSC нужно по трем причинам:

  1. Экономия ресурсов.
    Все HNSC живут в одном веб-приложении, следовательно в одном процессе w3wp. Это означает, что загружена только одна копия сборок SharePoint, что уменьшает оверхед на пару сотен мегабайт на процесс.
  2. Совместимость с apps.
    Для того чтобы работали apps нужен wildcard-сайт, который принимает запросы на любой hostname, потому что AppWeb создается с уникальным hostname.
    Но AppWeb это все еще сайт SharePoint, поэтому требуется загрузка всех объектов SharePoint в процесс веб-сайта, обсуживающего apps.
    Если все коллекции сайтов находятся в одном сайте IIS, то это также уменьшает оверхед и упрощает, в итоге, настройку IIS.
  3. Новые фичи SharePoint 2013.
    В SharePoint 2013 появилась фича Request Management, позволяющая управлять WFE. Request Management позволяет задать какой WFE будет обрабатывать запросы какого типа. Конфигурация может быть динамической, учитывающей состояние сервера (нагрузка, ресурсы итд). Microsoft говорит что эта фича тестировалась только с HNSC и в будущем новые фичи будут работать в первую очередь с HNSC.

Недостатки HNSC

Увы использовать HNSC не так просто. Central administration сайт не умеет создавать HNSC, поэтому всю работу надо будет делать в PowerShell.

Тем не менее для любителей тикать мышкой есть проект на codeplex: https://hnsc.codeplex.com/https://hnsc.codeplex.com/.

Кроме того HNSC обеспечивают гораздо меньшую изоляцию ресурсов сервера, по сравнению с веб-приложениями. Все HNSC будут иметь общие настройки веб-приложения, такие как throttling, настройки корзины, настройки безопасности и аутентификации, общие managed paths, итд. У всех HNSC будет общий web.config и общий app pool. Это значит что установка приложений будет затрагивать все HNSC.

Как создавать HNSC

Я не буду писать множество PowerShell команд для создания и настройки HNSC. На MSDN есть прекрасный гайд по HNSC (даже с достойным переводом на русский язык), который описывает разные топологии, а также процесс перехода от Path-based sitecollections к HNSC.

Ссылка на гайд: http://technet.microsoft.com/ru-ru/library/cc424952.aspx.

Дополнительные материалы для тех, кто решит использовать HNSC:

Заключение

Для правильного развертывания SharePoint 2013 уже недостаточно просто воспользоваться визардом. Теперь требуется планирование, анализ требований, вариантов решений которые предлагает SharePoint и оценка всех tradeoffs. А это требует как минимум понимания возможностей SharePoint.



Как работает развертывание решений в SharePoint

Развертывание решений SharePoint - это нескончаемый источник ошибок, слухов и легенд. Причина этому простая – процесс деплоймента (и отката) решений практически никак не документирован. Начиная с SharePoint 2010 ситуация усложнилась появлением sandbox solutions и механизмом апгрейда фич.

Общая схема

(взято отсюда)

По пунктам:

  • WSP пакет сначала попадает в конфигурационную базу
  • При развертывании файлы из пакета попадают на компьютеры фермы, это касается фич, сборок и файлов приложения.
  • При активации фич на основе манифеста в контентной базе создаются записи, которые ссылаются на файлы на диске.

Такая схема была изобретена в ранних версиях SharePoint, чтобы экономить место в базе, если одна и та же функциональность используется на многих сайтах. Кроме того так очень удобно обновлять, достаточно развернуть новую версию пакета и все сайты получат изменения.

На практике такая схема работает плохо...

Проблемы

Когда артефакты (файлы, поля, типы контента, списки) создаются таким образом, как описано выше, они называются ghosted (в SharePoint 2007) или uncustomized (с SharePoint 2010).

Проблемы начинаются тогда, когда файлы\поля\типы\списки изменяются. Когда это происходит в базу записывается схема (XML определение) или сам обновленный файл, а связь с файлом на диске теряется. Это состояние называется unghosted или customized. Дальнейшее обновление путем обновления файлов на диске уже перестает работать.

Ситуация усугубляется тем, что деактивация фич не удаляет списки и файлы и не удаляет типы контента и поля, на которые ссылаются списки. Повторная активация фич, при наличии артефактов в контентной базе, работает совершенно непредсказуемо.

Это кстати одна из базовых ошибок дизайна feature framework, из-за которой весь деплоймент стал невероятно сложным. Если бы деактивация фич удаляла все артефакты и при удалении решения фичи деактивировались, то делать решения стало бы гораздо легче. Но в 2007 году об этом не подумали и сделали выбор в пользу сохранения данных, а не контролируемости развертывания.

Можно, конечно, все артефакты создавать с помощью XML, избегая кода, который вызывает кастомизацию. Но далеко не все решения можно делать таким образом. Многие вещи, вроде таксономии, audience targeting и metadata mavigation в XML описать очень сложно. Но самое главное, что кастомизация может быть вызвана пользователем. А если возможность кастомизации заблокировать, то теряется гибкость, которую дает SharePoint.

Еще одна проблема связана со списками и шаблонами (определениями) списков. Если список создан по шаблону и не кастомизирован, но шаблон отсутствует на диске, то появляется множество непонятных ошибок при использовании API и некоторых стандартных функций.

Из-за этих проблем многие полностью отказались от развертывания артефактов с помощью XML определений и начали делать создание артефактов с помощью кода. Этот подход гораздо более многословен и повышает вероятность ошибок, но при этом дает контролируемость процесса при создании, и самое важное, при обновлении артефактов.

SharePoint 2010 и Sandbox

Естественно в Microsoft обо всех этих проблемах знали и в 2010 версии сделали некоторые изменения, которые должны были улучшить ситуацию.

Первое изменение – добавление флагов Overwrite в определениях полей и типов контента. С этим флагом поля и типы при активации фичи записываются в контентную базу, без создания привязки к файлам на диске. Кроме того стала возможна повторная активация фич при наличии артефактов в контентной базе данных. Это частично решает проблему, но только частично, так как проблема со списками, созданными из шаблонов, не решается.

Второе изменение – добавление возможности апгрейда фич. Теперь можно не удалять решение и не переактивировать фичи для получения новой функциональности.

Третье изменение – появление Sandbox решений, которые не используют файлы в файловой системе и создают все артефакты сразу в контентной базе. При этом откат Sandbox решения вызывает деактивацию всех фич, а для FullTrust такого не происходит.

Казалось бы теперь можно сделать то что нужно, используя правильные возможности. Но вышла еще одна промашка – все изменения почти никак не документированы и процесс развертывания стал еще более непредсказуемый и вообще сложилась ситуация когда никто не знает как делать правильно.

В SharePoint 2013 кстати тоже произошли небольшие улучшения, но снова почти не документированные.

Что же делать

Вариант первый – делать все кодом. К сожалению кода получается очень много и писать его очень муторно. Некоторые вещи сделать кодом сложно, некоторые вообще невозможно.

Вариант второй – делать развертывание в XML, не деактивировать фичи (особенно если ведет к потерям данных или к нарушению работоспособности), не откатывать решение, использовать feature upgrade. Это тоже требует написания кода, но в гораздо меньшем объеме.

Кстати использовать активацию фич для поставки функционала пользователю – тоже не лучший вариант. Гораздо лучше:

  1. Создание сайтов по шаблону.
  2. Создание списков по шаблону.
  3. Дополнительными пунктами в меню администрирования (для сайтов, списков, типов контента).
  4. Расширением существующего функционала.

Сам фичи лучше всего делать скрытыми, активировать их автоматически при развертывании решения или скриптом установки.

Если же делаете фичу видимой, то нужно всегда тестировать возможность её многократной активации\деактивации, в том числе на разных сайтах и коллекциях сайтов.

Заключение

Если вы работаете с SharePoint, то вам в любом случае необходимо знать как работает развертывание артефактов. Узнать это можно типовым для SharePoint способом – ковырянием сборок в ILSpy или Reflector. Большую часть из того, что я описал в этом посте я узнал именно из сборки Microsoft.SharePoint.

В следующий раз расскажу как пользоваться работает feature upgrade и как быстро создавать решения в SharePoint.



SPTypeScript Release 1.3

TypeScript неумолимо приближается к релизу, недавно вышла версия 0.9.5.

Вместе с этим мы продолжаем развивать наши определения типов JavaScript Object Model в SharePoint, чтобы вам было комфортно писать клиентский код для решений и приложений SharePoint.

На сайте проекта http://sptypescript.codeplex.com/ опубликован новый релиз, в который вошли:

  • Определения для Chrome Control для apps.
  • Определения для SPClientPeoplePicker для создания кастомных форм с контролом выбора людей.
  • Полные определения типов для пространств имен SP.Publishing и SP.DocumentManagement из файлов sp.publishing.js и sp.documentManagement.js соответственно. Они вам очень пригодятся для ECM\WCM сценариев.
  • Reputation object model – для социальных приложений.
  • Множество примеров и мелкие улучшения существующих определений.

Ссылка на релиз - http://sptypescript.codeplex.com/releases/view/115896

Также последнюю версию определений можно получить с помощью NuGet -http://www.nuget.org/packages/sharepoint.TypeScript.DefinitelyTyped/

Как использовать TypeScript для приложений SharePoint

Для начала установите последнюю версию TypeScript (0.9.5).

Создаете новый App для SharePoint в VisualStudio 2013

image

Теперь самое неприятное – надо поправить .csproj файл, чтобы включить компиляцию TypeScript. Для этого надо:

  • В контекстном меню проекта нажать Unload Project
  • На выгруженном проекте нажать Edit
  • В самом конце, перед закрывающим тегом Project надо добавить одну строчку:

    <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" />

  • На выгруженном проекте нажать Reload Project
  • Верить что к релизу не придется исполнять эти танцы с бубном...

После этого надо выставить настройки проекта в свойствах проекта
image

Далее переименовываете App.js в _App.js. Удалять не надо, он еще пригодится.

image

Добавляете App.ts файл

image

Добавляете дефинишены для SharePoint и JQuery с помощью NuGet

image

Копируете содержимое _App.js в App.ts и удаляете _App.js и сразу получаете типизацию в .ts файле. Можно также сделать небольшой рефакторинг в стандартном шаблоне, чтобы максимально использовать типизацию:

image

Последний штрих – скомпилировать проект и добавить сгенерированные App.js и App.js.map в решение.

image

Теперь можно запускать приложение и будет работать отладка в .ts файле

image

Планы на будущее

Сейчас дефинишенами покрыто почти все API для которого можно хоть как-то найти документацию. К релизу TypeScript 1.0 мы выпустим версию SPTypeScript 1.5 (или 2.0). Если есть какой-то API SharePoint, для которого вы хотите видеть дефинишены в нашем проекте, пишите на CodePlex в раздел Discussions - http://sptypescript.codeplex.com/discussions.

Будем рады любому фидбеку.



SharePoint Day: 14 декабря, Москва

14 декабря 2013 года состоится встреча встреча Russinan SharePoint User Group (RUSUG) в новом формате. Встреча будет проходить в субботу в офисе Microsoft в Крылатском. Вместо обычных двух докладов будет целых шесть в два потока. Начало в 10.00. Как всегда будет вестись трансляция для тех, кто не сможет приехать.

Внимание. Регистрация обязательна. Зарегистрироваться можно по ссылке http://rusug.timepad.ru/event/95901/. Выбирайте правильный тип регистрации.

Программа мероприятия:

Время / Поток

Поток 1

Поток 2

10:00 - 11:00

Все что вы хотели узнать про Office Web Apps Server 2013, но боялись спросить

Илья Бойко

Yammer для разработчика

Михаил Бондаревский

Перерыв

11:15 - 12:15

Как улучшить качество решений для SharePoint. Пособие для владельцев ферм и разработчиков

Стас Выщепан (это я)

Планирование в Excel + PowerShell = Готовый портал SharePoint 2013

Сергей Слукин

Перерыв

12:30 - 13:30

SharePoint 2013. Поиск в корпоративной среде

Виталий Жуков

Новая прадигма брендинга в SharePoint 2013

Александр Романов

Перерыв

13:45 - 14:30

Круглый стол

Страница мероприятия на facebook - https://www.facebook.com/events/183651665162179/

Описания докладов можно найти по ссылке - http://www.gotdotnet.ru/blogs/sharepoint/14107/

Присоединяйтесь все желающие, до встречи в субботу.

PS. Формат субботних встреч по SharePoint (SPSaturday) очень популярен в мире - https://www.google.ru/#q=spsaturday. Надеюсь и у нас приживется.



Безопасность приложений SharePoint 2013

Система разрешений в новой архитектуре приложений в SharePoint 2013 (о которых я писал ранее) до сих пор вызывает много вопросов. Попробую прояснить некоторые из них:

Введение

Когда вы создаете решение код работает под учетной и с правами того пользователя, который этот код запустил. Это сильно повышает безопасность платформы, но усложняет написание кода.

В FullTrust возможно повышение привилегий путем создания объекта SPSite с токеном более привилегированного пользователя (SPUserToken.SystemAccount). Код с повышенными привилегиями может делать всё (вообще всё). Поэтому любое решение или опасно, или почти бесполезно. Еще одна проблема повышения привилегий – невозможно отследить какой пользователь и какие действия вызвали изменения, потому что везде будет один и тот же пользователь даже для разных решений.

App Principals

Для решения проблем обозначенных выше, приложения решили сделать участниками системы безопасности (principal), также как и пользователей. Это означает что у каждого приложения есть свой App Principal, которому назначаются права.

Пользователь сопоставляется со своим principal в процессе аутентификации, то есть при передаче логина\пароля (или токена) от пользователя к SharePoint.

А как же происходит аутентификация приложений, ведь нету логинов и паролей у приложений...

Этот процесс описывает простая схема:

image

Схема не совсем точная, но в общем описывает процесс правильно.

Если не вдаваться в детали, то выполняются такие условия:

  1. Если пользователь аутентифицирован и происходит запрос к AppWeb, то используется App Principal + User Principal (внутренняя аутентификация).
  2. Если пользователь не аутентифицирован, но в запросе указан access token (внешняя аутентификация), то
    • Если в access token указан user identity, то то используется App Principal + User Principal.
    • Если в access token не указан user identity, то то используется App Principal  с App Only-Policy.
  3. Во всех остальных случаях аутентификация для приложения не происходит.

Внутренняя аутентификация

Скриншот манифеста свежесозданного SharePoint-hosted app, обратите внимание на элемент AppPrincipal.

image

Внутренняя аутентификация называется так, потому что все процессы аутентификации приложения происходят внутри SharePoint. Вам для этого не надо ничего писал и\или настраивать (только DNS для AppWeb).

Внутренняя аутентификация используется именно для SharePoint-hosted app и JavaScript кода. В других случаях сложно повторить условия для внутренней аутентификации. Чтобы нельзя было обойти внутреннюю аутентификацию и проверку прав приложения AppWeb создается на уникальном домене. Это позволяет блокировать JavaScipt обращения, используя same origin policy, которая встроена в браузер.

Есть еще возможность размещать клиентский JavaScript внешнем сайте, и он будут обращаться к AppWeb и будет работать аутентификация приложения.

Внешняя аутентификация

Если же поменять тип приложения на Provider-hosted , то можно увидеть такой манифест:

image

В элементе AppPrincipal появилось RemoteWebApplication. ClientId="*" заменяется на идентификатор приложения при отладке или публикации.

access token должен содержать идентификатор приложения, чтобы SharePoint мог привязать AppPrincipal. Для формирования Access token используется oauth или s2s trust. Оба доступны только в серверном коде внешнего приложения и не доступны в клиентском JavaScript.

Основная проблема в том, что нельзя одновременно указать внутреннюю и внешнюю аутентификацию. То есть нормально обращаться к SharePoint сможет или серверный код на внешнем сайте или JavaScript на AppWeb. Учитывая что многие стандартные компоненты SharePoint используют JSOM, то они не будут работать при внешней аутентификации. Это делает AppWeb почти бесполезным для Provider-hosted приложений.

OAuth

OAuth это протокол (правильнее сказать фреймворк), который описывает протоколы и сценарии аутентификации приложений в вебе. В Office 365 используется схема с тремя действующими лицами:

  • Приложение
  • Access Control Service (ACS)
  • SharePoint

SharePoint и приложение доверяют ACS, SharePoint не доверяет приложению напрямую (и правильно делает :) ).

Процесс аутентификации выглядит так:

  1. Пользователь нажимает на плитку приложения.
  2. SharePoint запрашивает у ACS так называемый context token по ClientId приложения и отдает context token клиенту (браузеру). Context token подписан с помощью ClientSecret, который известен ACS и приложению.
  3. Браузер делает POST запрос на адрес приложения и передает context token.
  4. Приложение проверяет context token с помощью ClientSecret и извлекает refresh token.
  5. Далее по refresh token приложение может получить access token от ACS и обращаться с ним к SharePoint.

Описание на MSDN: http://msdn.microsoft.com/en-us/library/office/fp142382.aspx

Параметры ClientId и ClientSecret вы получаете при регистрации в Office Store или при добавлении нового app principal на странице /_layouts/15/appregnew.aspx.

Важные моменты:

  •  Context token передается приложению POST запросом. При переходе н другую страницу в приложении context token не сохранится. Само приложение должно это делать. В Visual Studio 2013 включили класс SharePointContext, который управляет сохранением токенов в сессии.
  • Из-за использования POST нельзя реализовать OAuth на клиентском JavaScript. Даже не пытайтесь.
  • SharePoint и ACS напрямую не обращается к вашему приложению, кроме случаев использования Remote Event Receiver или Workflow. Поэтому SharePoint абсолютно все равно где и на чем работает ваше приложение. Это например позволяет отлаживать облачные приложения на локальной машине.

OAuth полагается на SSL, так как все токены передаются незащищенными от перехвата. Любое приложение SharePoint для Office 365 должно иметь SSL сертификат.

Как я писал ранее, в onprem по-умолчанию не работает OAuth и используется его расширение S2STrust. Можно интегрировать onprem ферму с тенантом office365, тогда появится возможность устанавливать provider-hosted приложения из маркета. Подробнее тут: http://msdn.microsoft.com/en-us/library/office/dn155905.aspx

S2S Trust

В onprem варианте вместо “трехногого” OAuth используется “двуногий” вариант, называемый Server-to-Server Trust. Суть в том что SharePoint доверяет серверу приложения. Для установления факта доверия в SharePoint должен быть добавлен Trusted Token Issuer, а это требует сертификата. Приложение этим сертификатом подписывает запросы на получение access token пользователя.

В “двуногой” схеме никаких context token и refresh token не используется. Приложение должно само аутентифицировать пользователя и передавать данные о текущем пользователе в SharePont. Да, это позволяет приложению притворяться любым пользователем.

Такие приложения называются приложением с высоким доверием (High trust), в отличие от full trust права приложения все-таки ограничиваются.

Подробнее тут: http://msdn.microsoft.com/en-us/library/office/fp179901.aspx

Права приложений

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

  • Требуемые права задаются в манифесте.
  • Права приложению даются при установке по принципу “все или ничего”.
  • Права приложений не используют иерархию объектов SharePoint.

Вот так выглядит запрос прав манифесте, указываются области и требуемые права:

image

Полный список возможных разрешений: http://msdn.microsoft.com/en-us/library/office/fp142383.aspx

Для вычисления эффективных разрешений права пользователя и права приложения пересекаются. Porvider-hosted app может также получить app-only access token, если в манифесте приложения было указано app-only policy.

image

Надо учитывать что все это работает только для CSOM и REST вызовов. Обычные (устаревшие) веб-сервисы не поддерживают аутентификацию с помощью access token.

Права – основной источник проблем для приложений. Если вы дадите приложению недостаточно прав, то ошибки буду очень непонятными. Иногда сочетание прав для некоторой операции крайне неочевидно, например:

  • Публикация в социальную ленту требует Social Write, Tenant Write, User Profiles Read, если не дадите одно из них вам скажут “Social list not found” или что-то в этом роде.
  • Добавление типов контента на подсайт требует sitecollection read, хотя если вы будете тестировать приложение на корневом сайте, то прав web manage может хватить.

Есть еще возможность запрашивать права “на лету”, но это тема для отдельной статьи. Пока можете прочитать описание на MSDN: http://msdn.microsoft.com/en-us/library/office/jj687470.aspx

Заключение

Большая часть сложностей аутентификации приложений скрыто от глаз программистов, с помощью внутренних механизмов SharePoint и классов хелперов SharePointContext и TokenHelper. Тем не менее надо хорошо понимать внутренние механизмы, особенно разграничения доступа, чтобы успешно создавать приложения.

С появлением модели apps нагрузка на SharePoint разработчиков сильно возросла, надо изучать много новых технологий и подходов, чтобы эффективно применять возможности платформы.

Изучайте, развивайтесь.