Аутентификация в SharePoint через .Net, но через Node.js

Вступление

Порой обожаю технологические эксперименты и реализацию безумных, как бы ни казалось, идей. Часто ловишь себя на мысли "А почему бы не сделать [вот так-то, как никто еще не делал]?", а потом понимаешь, что на одном дыхании и реализовал задуманное с восклицанием "Ничего себе! Работает! O_o". Примерно таким образом явились свету некоторые из моих Open Source проектов.

Вот таким образом не так давно пришлось покопаться с Edge.js. Edge.js - это библиотека, которая позволяет запускать CLR языки, такие как C# .Net из Node.js и, наоборот, Node.js из .Net.

Довольно давно хотелось синхронизировать sp-cmd-deploy (.Net модуль для получения CSOM контекста) c node-sp-auth-config (Node.js модуль для настроек аутентификации). Обе библиотеки разделяют общие подходы. И было бы неплохо, чтобы для Node.js и .Net в части настроек был общий слой.

Обсуждая эту идею кто-то сказал "А почему бы не переиспользовать node-sp-auth-config в наших .Net приложениях как есть?". Хм... сказано, сделано!

SPAuthN

Собсвтенно, SPAuthN - результат эксперимента и немного "Франкенштейн". SPAuthN является .Net библиотекой, устанавливаемой из NuGet'ов. Библиотека является оберткой для node-sp-auth и node-sp-auth-config. Данный монст позволяет аутентифицироваться в SharePoint с разнообразной поддержкой сценарией аутентификации и консольным мастером подключения и слоем конфигурационных файлов идентичных нашему Node.js стеку.

Предупреждение

Перед дальнейшим чтением, минутка внимания! Прежде всего это эксперимент направленный на решение очень узкой и специфичной задачи связки SharePoint, Node.js и .Net где нам нужно именно то, что нужно, а именно переиспользование практик Node.js в составе .Net приложений. Мы понимаем что и почему делаем и зачем. Использование самой же библиотеки может быть только целесообразно если штатных средств .Net не хватает для определенного аутентификационного сценария, но он есть и работает в node-sp-auth.

Для кого эта библиотека?

Предже всего для Node.js разработчиков, плотно использующих node-sp-auth и node-sp-auth-config, кому нужно в рамках .Net приложения переиспользовать имеющиеся возможности.

Для гиков, кому интересны нестандартные подходы изящно решающие необычные задачи.

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

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

  • context.Credentials = new SharePointOnlineCredentials("username", "securepass");
  • context.Credentials = new NetworkCredential("username", "password", "domain");
  • и другие.

Возможности

SPAuthN поддерживает аутентификацию с SharePoint Online, 2019б 2016, 2013. По сути дела, все в одном: Addin only разрешений, SAML, ADFS, NTLM, FBA, TMG и др.

Принцип работв

  • Edge.js оборачивает запуск Node.js скриптов с мастерами настройки, аутентифицакии и утилит
  • Edge.js предоставляет встроенную среду исполнения серверного JavaScript
  • Часть исполнения передается на сторону JS, результат в виде аутентификационных заголовков возвращается назад в управляемый код
  • Аутентификационные заголовки инжектятся в запросы уже на стороне .Net кода

Как использовать

Options options = SPAuth.GetAuth();

И это все, да, на самом деле так просто!

Теперь в объекте options.headers находят я Cookie или Authorization заголовки, которые нужно подставить в запрос к SharePoint. Однако, таймауты сессий нужно контролировать в ручную или получать авторизацию перед запросами, а внутреннее кеширование следит за сроком жизни токенов.

Параметры аутентификации

node-sp-auth-config отвечает за интерактивный ввод стратегии и соответствующих параметров аутентификации:

По умолчанию, параметры подключения сохраняются в ./config/private.json корневой директории подключения.

Метод GetAuth проверяет наличие и содержимое ./config/private.json и запрашивает недостающие параметры, либо продолжает работу, если все необходимое на месте.. Пароль хранится в зашифрованном виде и подлежит расшифровке только на той машине, где был создан.

Аргументы

Метод GetAuth так же может получать строку с параметрами, переопределяющими общее поведение. Параметры можно посмотреть в коде - AuthConfigSettings.

Options options = SPAuth.GetAuth("--encryptPassword=false --configPath='./config/private.uat.json'");

Сценарии использования параметров

Определение пути до файла с параметрами подключения

--configPath='./config/private.prod.json'

Переключение между разными тенантами, учетными данными и окружением.

Шифрование пароля

--encryptPassword=false

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

Блокировака записи файла параметров на диск

--saveConfigOnDisk=false

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

Принудительный запрос параметров

--forcePrompts=true

Переинициализация мастера ввода параметров.

Явная передача ауторизационных данных

--authOptions.siteUrl="http://sharepoint" --authOptions.username="user@contoso.com" --authOptions.password="p@ssw0rd" --saveConfigOnDisk=false

Примеры использования

WebRequest

ptions options = SPAuth.GetAuth("--configPath='./config/private.json'");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(options.SiteUrl + "/_api/web?$select=Title");
Request.ApplyAuth(request, options);
request.Method = "GET";
request.Accept = "application/json; odata=verbose";
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
  if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NoContent)
  {
    using (Stream dataStream = response.GetResponseStream())
    {
      using (StreamReader reader = new StreamReader(dataStream))
      {
        string strResponse = reader.ReadToEnd();
        dynamic results = JsonConvert.DeserializeObject(strResponse);

        Console.WriteLine("REST | Web title is: {0}", results.d.Title);
      }
    }
  }
}

CSOM

Options options = SPAuth.GetAuth("--configPath='./config/private.json'");
using (ClientContext clientContext = new ClientContext(options.SiteUrl))
{
  Request.ApplyAuth<WebRequestEventArgs>(clientContext, options);

  var web = clientContext.Web;
  clientContext.Load(web);
  clientContext.ExecuteQuery();

  Console.WriteLine("CSOM | Web title is: {0}", web.Title);
}

Заключение

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


Опубликовано: 19.11.2018
Автор: Андрей Кольтяков