Sharepoint身份验证。如何从ADFS获取SharePoint cookie

时间:2014-05-05 04:22:44

标签: c# asp.net-mvc sharepoint adfs2.0

我们编写一个Sharepoint应用程序,使用证书将其扩展为Provider-hosted,并将我们的MVC项目锚定到它 在扩展Sharepoint的同一IIS上展开所有这些。

任务#1:用户登录Sharepoint,启动我们的应用程序;应用程序在没有任何授权请求的情况下启动,并从登录的Sharepoint获取用户。

任务#2:如果需要Sharepoint服务请求,我们的应用程序使用用户登录Sharepoint的相同用户名登录Sharepoint。

我们尝试过:

1)构建提供商托管的应用程序,在其中编写MVC,创建自唱歌证书,调整Sharepoint站点和MVC之间的高可信度。

我们得到了: 如果我们的MVC使用Windows身份验证,那么在转移到我们的应用程序时,会再次请求用户名和密码;输入时,我们可能会使用ClientContext方法TokenHelper通过GetS2SClientContextWithWindowsIdentity

如果禁用了Windows身份验证,则用户不会登录请求,并且此方法会响应用户未登录的异常。

2) 我们安装并调整了ADFS,配置了Sharepoint以便与ADFS一起工作,写了Sharepoint的地址和我们在中继方信任中的应用(在Identifiers and WS-Federtation`被动端点中)

我们得到了: 用户登录Sharepoint,当转移到我们的应用程序时,后者获取用户数据(声明)

因此,第一项任务已经解除。 之后,出现了在授权用户下获得对Sharepoint服务的访问权的问题

我们尝试通过收到的声明获取Sharepoint的AccessToken 我们试图转移以下声明:

nii":"trusted:adfs
nii":"urn:office:idp:forms:adfs201 //adfs201 - name of our ADFS service
upn:UserLogin
emailaddress:UserEmail@domain.kz

之后,我们根据输入的声明调用了一个响应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

ClientIDIssureID写得正确,小写

之后,我们决定在SecurityTokenusername的帮助下从ADFS请求password。收到后,我们使用SecurityToken在SharepointSTS中请求授权。然后,我们的应用程序获得了Cookie Sharepoint,它被锚定到查询(在CookieContainer FedAuth中添加)到Sharepoint服务。激活ExecutingWebRequest += ClientContext_ExecutingWebRequest时,会发生上述情况。

但是为此,应该再次使用usernamepassword

如果我们不提交usernamepassword,则ADFS会以SecurityToken响应用户的数据,其名称为启动应用程序池。我们需要{strong>登录SharePoint的用户 SecurityToken。 我们还尝试发出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中,我们调整URL;我们对SharePoint授权所需的SecurityToken (wresult)非常SecurityToken通过POST查询发送给它。问题是我们无法在应用程序中接收此查询,因为它在状态302中广播并通过GET方法重定向到我们的应用程序,而SecurityToken没有我们的Cookie。

问题是:我们如何获得登录SharePoint的用户{{1}}?

1 个答案:

答案 0 :(得分:0)

在这里突发奇想,但听起来你需要创建一个声明提供程序,它是一个继承自SPClaimProvider的类。

sharepoint中的人物选择器,即用于选择人员和群组的控件,可以从声明提供商那里获得所有人和群组。

开箱即用,存在以下声明提供商,

AllUsersClaimProvider FormsClaimsProvider ActiveDirectoryClaimsProvider

如果你需要额外的索赔解决方案,你必须写一个,这不是很糟糕。

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

基本上,您可以在FillClaimsForEntity向身份主体发出新的声明。

您可以在两个Resolve Overloads中查看输入是否存在Claim匹配。

E.g。说你输入&#34; Bob&#34;在人民选择器。然后,人员选择器使用SPClaimsOperationManager *(忘记确切的拼写),在服务器场中注册的每个声明提供程序上调用Resolve(字符串输入...)。

所以说我们正在讨论Forms声明提供程序。它会检查是否有用户的用户名或电子邮件地址与Bob匹配。对于映射bob的每个用户,它将创建一个选择器实体,并将其声明类型设置为FormsLogonUser,其值为bob等。并将每个实体添加到结果中。

所以当它完成后,你会看到人物选择器中的Bob被选中,或者你会看到Bob有一个红色下划线意味着他们是多个匹配你需要选择。

在我看来,你需要建立一个让人们选择器能够处理你的新声明。

一旦您建立并注册了声明提供程序,您就可以使用人员选择器使用您的声明授予对该网站的访问权限。

对于一个示例场景,我曾经让一个声明提供商根据用户购买的产品发布了声明。

所以我提出了一个声明类型&#34; http://blah.com/schema/claims/product&#34; (这可以是您想要的任何唯一字符串)并且值类似于&#34; pd.1234.0&#34;。现在在FillClaimsForEntities中,我在数据库中的实体参数上查找用户以获取他们的所有产品。然后,我为每个产品创建了产品声明,并将其添加到声明列表中。

然后在Resolve中,我会查看具有ID或显示名称的产品是否存在解析输入,如果有,则创建一个选择器实体。

搜索中也是如此。

然后,我进入了我们的产品页面,并使用人员选择器授予任何拥有该产品声明的人访问该页面的权限。 &#34;就像在表单身份验证中挑选角色一样#34;那种。

此外,您可以为声明Heirarchy编写支持,并且您可以在人员选择器中拥有多个树,您正在使用的每种声明类型都有一棵树。

E.g。说&#34; Bob&#34;带回一个人,一本书和一位经理。你可以有3个heirarchies,1个用于人,1个用于书籍,1个用于管理者等。并且使该类型的声明显示在该树中。

我更进了一步并制作了一个拒绝访问权限的处理程序,这样如果用户因未申请该产品而被拒绝访问,则会将其重定向到该产品购买页面。