【发布时间】:2014-10-12 20:45:57
【问题描述】:
场景如下:我需要对用户(使用他的大学帐户)执行联合身份验证到他大学的 Sharepoint 站点并获取 FedAuth 和 rtFa cookie(我必须将其传递给 SharePoint REST Web 服务才能访问资源)。
我做了一些尝试,但至少每个都有一个问题:
1) 使用 Microsoft.SharePoint.Client 库
ClientContext context = new ClientContext(host);
SharePointOnlineCredentials creds = new SharePointOnlineCredentials(user, passw);
context.Credentials = creds;
Uri sharepointuri = new Uri(host);
string authCookie = creds.GetAuthenticationCookie(sharepointuri);
Web web = context.Web;
context.Load(web, w=>w.Lists);
context.ExecuteQuery();
fedAuthString = authCookie.Replace("SPOIDCRL=", string.Empty);
这样我设法获得了 FedAuth cookie,但 我无法获得 rtFa cookie。
此时我如何获取 rtFa cookie? 我可以拦截此类操作中涉及的 HTTP 请求(即 context.ExecuteQuery())——它可能在标头中包含 rtFa cookie? 或者,我可以仅通过利用 FedAuth cookie 来获取 rtFa cookie 吗?
2) 使用 MsOnlineClaimsHelper
这是一个可以在 Internet 上找到的辅助类(例如,这里是 http://blog.kloud.com.au/tag/msonlineclaimshelper/)。
这个类在正常的身份验证下工作,但在联合身份验证下失败。
所以我对其进行了调整以使其在这种情况下工作。 据我了解,步骤如下:
- 使用大学的 STS ADFS 服务(“联合方”或 ISSUER)的用户名和密码进行身份验证 -- 这里的依赖方是 Sharepoint O365 STS ("https://login.microsoftonline.com/extSTS.srf")
- 如果身份验证成功,我会返回一个包含声明和安全令牌的 SAML 断言
- 现在,我通过传递安全令牌对 SharePoint 网站进行身份验证
- 如果令牌被识别,我会返回一个包含两个 cookie(FedAuth 和 rtFa)的响应
我不是这方面的专家,我出来的代码如下:
这是调用上述方法并尝试分两步从凭据中获取 FedAuth 和 rtFa 的代码(步骤 1:从 Federated Party 获取 SAML 令牌;第 2 步:将令牌从 Federated Party 传递到 Sharepoint):
private List<string> GetCookies(){
// 1: GET SAML XML FROM FEDERATED PARTY THE USER BELONGS TO
string samlToken = getResponse_Federation(sts: "https://sts.FEDERATEDDOMAIN.com/adfs/services/trust/13/usernamemixed/",
realm: "https://login.microsoftonline.com/extSTS.srf");
// 2: PARSE THE SAML ASSERTION INTO A TOKEN
var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;
SecurityToken token = handlers.ReadToken(new XmlTextReader(new StringReader(samlToken )));
// 3: REQUEST A NEW TOKEN BASED ON THE ISSUED TOKEN
GenericXmlSecurityToken secToken = GetO365BinaryTokenFromToken(token);
// 4: NOW, EASY: I PARSE THE TOKEN AND EXTRACT FEDAUTH and RTFA
...............
}
private string getResponse_Federation(string stsUrl, string relyingPartyAddress)
{
var binding = new Microsoft.IdentityModel.Protocols.WSTrust.Bindings.UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential);
binding.ClientCredentialType = HttpClientCredentialType.None;
var factory = new WSTrustChannelFactory(binding, stsUrl);
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";
factory.Credentials.SupportInteractive = false;
factory.TrustVersion = TrustVersion.WSTrust13;
IWSTrustChannelContract channel = null;
try
{
var rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(relyingPartyAddress), //("urn:sharepoint:MYFEDERATEDPARTY"),
ReplyTo = relyingPartyAddress,
KeyType = WSTrust13Constants.KeyTypes.Bearer,
TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0",
RequestDisplayToken = true,
};
channel = (WSTrustChannel)factory.CreateChannel();
RequestSecurityTokenResponse response = null;
SecurityToken st = channel.Issue(rst, out response);
var genericToken = st as GenericXmlSecurityToken;
return genericToken.TokenXml.OuterXml;
}
catch (Exception e)
{
return null;
}
}
private GenericXmlSecurityToken GetO365BinaryTokenFromToken(SecurityToken issuedToken)
{
Uri u = new Uri("https://login.microsoftonline.com/extSTS.srf");
WSHttpBinding binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.IssuedToken;
Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory channel =
new Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory(
binding, new EndpointAddress("https://login.microsoftonline.com/extSTS.srf"));
channel.TrustVersion = TrustVersion.WSTrust13;
channel.Credentials.SupportInteractive = false;
GenericXmlSecurityToken token = null;
try
{
RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue, WSTrust13Constants.KeyTypes.Bearer)
{
};
rst.AppliesTo = new EndpointAddress("urn:sharepoint:MYFEDERATEDPARTY");
channel.ConfigureChannelFactory();
var chan = (Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel)channel.CreateChannelWithIssuedToken(issuedToken);
RequestSecurityTokenResponse rstr = null;
token = chan.Issue(rst, out rstr) as GenericXmlSecurityToken;
return token;
}
catch (Exception ex){
Trace.TraceWarning("WebException in getO365BinaryTokenFromADFS: " + ex.ToString());
throw;
}
}
我设法从大学 STS 取回了 SAML 令牌。但是,在解析时,生成的 SecurityToken 没有安全密钥(即 SecurityKeys 集合为空)
在没有密钥的情况下,我使用 GetO365BinaryTokenFromToken() 但是当我尝试将令牌发送到 SharePoint 身份验证服务时 - 我收到以下错误: “签名令牌 Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityToken 没有密钥。安全令牌在需要它执行加密操作的上下文中使用,但令牌不包含加密密钥。令牌类型不支持加密操作, 或特定令牌实例不包含加密密钥。检查您的配置以确保未在需要加密操作的上下文(例如,背书支持令牌)中指定加密禁用的令牌类型(例如,UserNameSecurityToken)。“
我认为在双方(大学 STS ADFS 和 Sharepoint STS)上也存在一些我无法直接控制的配置问题。
我希望更多的专家能够澄清这个过程,甚至提供建议以使这个场景真正发挥作用。
文件下载功能
使用以下函数,我可以通过发出 BOTH FedAuth 和 rtFa cookie 来下载文件(给定一个 URL,例如 https://myfederatedparty.sharepoint.com/sites/MYSITE/path/myfile.pdf)。如果我没有通过 rtFa cookie,我会收到“未经授权”的响应。
public static async Task<byte[]> TryRawWsCall(String url, string fedauth, string rtfa, CancellationToken ct, TimeSpan? timeout = null) {
try {
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = new System.Net.CookieContainer();
CookieCollection cc = new CookieCollection();
cc.Add(new Cookie("FedAuth", fedauth));
cc.Add(new Cookie("rtFa", rtfa));
handler.CookieContainer.Add(new Uri(url), cc);
HttpClient _client = new HttpClient(handler);
if (timeout.HasValue)
_client.Timeout = timeout.Value;
ct.ThrowIfCancellationRequested();
var resp = await _client.GetAsync(url);
var result = await resp.Content.ReadAsByteArrayAsync();
if (!resp.IsSuccessStatusCode)
return null;
return result;
}
catch (Exception) { return null; }
}
【问题讨论】:
标签: c# authentication sharepoint claims-based-identity ws-federation