Аутентификация Sharepoint. Как получить cookie SharePoint из ADFS

Мы кодируем приложение Sharepoint, расширяем его как размещенное у провайдера, используя сертификат, и привязываем к нему наш проект MVC. Разверните все это на том же IIS, на котором была расширена Sharepoint.

Задача №1: пользователь входит в Sharepoint, запускает наше приложение; приложение запускается без какого-либо запроса авторизации и получает пользователя из Sharepoint, в который он вошел.

Задача № 2: Если запрос службы Sharepoint необходим, наше приложение регистрируется в Sharepoint под тем же именем пользователя, что и пользователь, вошедший в Sharepoint.

Мы пробовали:

1) Создание приложения, размещенного у поставщика, написание в нем нашего MVC, создание самоподписывающегося сертификата, настройка высокого уровня доверия между сайтом Sharepoint и нашим MVC.

Мы получили: если наш MVC использует аутентификацию Windows, то при передаче в наше приложение имя пользователя и пароль запрашиваются повторно; при их вводе мы можем получить от ClientContext до TokenHelper, используя метод GetS2SClientContextWithWindowsIdentity.

Если проверка подлинности Windows отключена, то пользователь не вошел в запрос, и этот метод отвечает Исключение, что пользователь не вошел в систему.

2) Мы установили и настроили ADFS, настроили Sharepoint для работы с ADFS, записали адреса Sharepoint и нашего приложения в Relaying Party Trusts (в Identifiers andWS-Federtation` Passive Endpoints)

Мы получили: пользователь входит в Sharepoint, и при переходе в наше приложение последнее получает данные пользователя (претензии)

Таким образом, первая задача выполнена. После этого возникла проблема получения доступа к сервисам Sharepoint под авторизованным пользователем.

Мы пытались получить AccessToken для Sharepoint через полученные Заявки. Мы пытались передать следующие Заявки:

nii":"trusted:adfs
nii":"urn:office:idp:forms:adfs201 //adfs201 - name of our ADFS service
upn:UserLogin
emailaddress:[email protected]

После этого мы вызвали метод, отвечающий AccessToken на введенные претензии.

    string issuer = string.IsNullOrEmpty(sourceRealm) ? issuerApplication : string.Format("{0}@{1}", issuerApplication, sourceRealm);
    string nameid = string.IsNullOrEmpty(sourceRealm) ? sourceApplication : string.Format("{0}@{1}", sourceApplication, sourceRealm);
    string audience = string.Format("{0}/{1}@{2}", targetApplication, targetApplicationHostName, targetRealm);

    List<JsonWebTokenClaim> actorClaims = new List<JsonWebTokenClaim>();
    actorClaims.Add(new JsonWebTokenClaim(JsonWebTokenConstants.ReservedClaims.NameIdentifier, nameid));
    if (trustedForDelegation && !appOnly)
    {
        actorClaims.Add(new JsonWebTokenClaim(TokenHelper.TrustedForImpersonationClaimType, "true"));
    }       

    if (addSamlClaim)
        actorClaims.Add(new JsonWebTokenClaim(samlClaimType, samlClaimValue));

    // Create token
    JsonWebSecurityToken actorToken = new JsonWebSecurityToken(
        issuer: issuer,
        audience: audience,
        validFrom: DateTime.UtcNow,
        validTo: DateTime.UtcNow.AddMinutes(TokenLifetimeMinutes),
        signingCredentials: SigningCredentials,
        claims: actorClaims);

    string actorTokenString = new JsonWebSecurityTokenHandler().WriteTokenAsString(actorToken);

    if (appOnly)
    {
        // App-only token is the same as actor token for delegated case
        return actorTokenString;
    }

    List<JsonWebTokenClaim> outerClaims = null == claims ? new List<JsonWebTokenClaim>() : new List<JsonWebTokenClaim>(claims);
    outerClaims.Add(new JsonWebTokenClaim(ActorTokenClaimType, actorTokenString));

    //****************************************************************************
    //SPSAML
    if (addSamlClaim)
        outerClaims.Add(new JsonWebTokenClaim(samlClaimType, samlClaimValue));
    //****************************************************************************

    JsonWebSecurityToken jsonToken = new JsonWebSecurityToken(
        nameid, // outer token issuer should match actor token nameid
        audience,
        DateTime.UtcNow,
        DateTime.UtcNow.AddMinutes(10),
        outerClaims);

    string accessToken = new JsonWebSecurityTokenHandler().WriteTokenAsString(jsonToken);

Затем мы попытались получить ClientContext, используя метод:

GetClientContextWithAccessToken(targetApplicationUri.ToString(), accessToken);

Но мы получили отчет об ошибке:

401 Unauthorized

ClientID и IssureID были написаны справа, в нижнем регистре

После этого мы решили запросить SecurityToken из ADFS с помощью username и password. Получив его, мы запросили авторизацию в SharepointSTS с помощью SecurityToken. Затем наше приложение получило Cookie Sharepoint, которые были привязаны к запросу (добавленному в CookieContainer FedAuth) к сервисам Sharepoint. При активации ExecutingWebRequest += ClientContext_ExecutingWebRequest происходит вышеупомянутое.

Но для этого нужно использовать username и password для повторного запроса.

Если мы не отправляем username и password, тогда ADFS отвечает SecurityToken данными пользователя, под именем которого был запущен пул приложений. И нам нужно SecurityToken из пользователей, выполнивших вход в SharePoint. Мы также пытались испустить SecurityToken

var session = System.IdentityModel.Services.FederatedAuthentication.SessionAuthenticationModule.CreateSessionSecurityToken(ClientPrincipals, "context", DateTime.UtcNow, System.DateTime.UtcNow.AddHours(1), true);
System.IdentityModel.Services.FederatedAuthentication.SessionAuthenticationModule.AuthenticateSessionSecurityToken(session, true);

Но ответ был не тот, который нам нужен для авторизации SharePoint.

В ADFS в Endpoints настраиваем URL; тот самый SecurityToken (wresult), который нам нужен для авторизации SharePoint, отправляется ему по запросу POST. Проблема в том, что мы не можем получить этот запрос в приложении, поскольку он транслируется в статусе 302 и перенаправляется в наше приложение методом GET, без SecurityToken с нашим Cookie.

Вопрос в следующем: как мы можем получить SecurityToken пользователей, выполнивших вход в SharePoint?


person Korshikov Denis    schedule 05.05.2014    source источник


Ответы (1)


Здесь все по прихоти, но похоже, что вам нужно создать поставщика утверждений, который является классом, наследуемым от SPClaimProvider.

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

Из коробки существуют следующие поставщики утверждений:

AllUsersClaimProvider FormsClaimsProvider ActiveDirectoryClaimsProvider

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

http://msdn.microsoft.com/en-us/library/office/ee537299(v=office.15).aspx

По сути, FillClaimsForEntity - это то место, где вы можете выдавать новые заявки на имя участника.

Две Resolve Overloads - это то место, где вы видите, есть ли совпадение с утверждением для ввода.

Например. скажем, вы набираете "Боб" в сборщике людей. Затем средство выбора людей использует SPClaimsOperationManager * (забудьте точное написание) для вызова Resolve (строковый ввод ...) для каждого поставщика утверждений, зарегистрированного в ферме.

Скажем, мы говорим о Поставщике претензий по формам. Он проверит, есть ли пользователь с именем или адресом электронной почты, совпадающим с Бобом. Для каждого сопоставления пользователя bob он создает объект выбора и устанавливает для него тип утверждения FormsLogonUser со значением bob и т. Д. И добавляет каждое из них к результату.

Итак, когда это будет сделано, вы либо увидите, что Боб в средстве выбора людей был выбран, либо вы увидите Боба с красным подчеркиванием, что означает, что их совпадений было несколько, и вам нужно выбрать.

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

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

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

Поэтому я сделал претензию типа «http://blah.com/schema/claims/product "(это может быть любая уникальная строка, которую вы хотите) И значения были такими, как" pd.1234.0 ". Теперь в FillClaimsForEntities я нашел пользователя по параметру сущности в нашей базе данных, чтобы получить все их продукты. Затем я создал заявление о продукте для каждого продукта и добавил их в список требований.

Затем в Resolve я бы посмотрел, существует ли продукт с идентификатором или отображаемым именем, сопоставленным с вводом разрешения, и создал бы объект выбора, если он существует.

То же самое и в Поиске.

Затем я зашел на страницы наших продуктов и предоставил доступ к странице любому, у кого есть претензия на этот продукт, с помощью средства выбора людей. «работает как выбор ролей при проверке подлинности с помощью форм».

Также вы можете кодировать поддержку иерархии утверждений, и у вас может быть несколько деревьев в средстве выбора людей, по одному дереву для каждого типа утверждения, с которым вы работаете.

Например. скажем: «Боб» возвращает человека, книгу и менеджера. У вас может быть 3 иерархии: 1 для людей, 1 для книг, 1 для менеджеров и т. Д. И сделать так, чтобы утверждения этого типа отображались в этом дереве.

Я сделал еще один шаг и создал обработчик отказа в доступе, чтобы, если пользователь получал отказ в доступе из-за того, что он не участвует в заявленном продукте, он перенаправлял его на страницу покупки этого продукта.

person Ryan Mann    schedule 29.08.2014