Мы кодируем приложение 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 and
WS-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?