主动授权场景。如何使用来自 partner/users ADFS 的令牌在 home/resource ADFS 上发行令牌
Active auth scenario. How to issue token on home/resource ADFS using token from partner/users ADFS
使用 this approach 我可以在 home/resource ADFS 和 partner/users 上为我的应用程序获取授权令牌。我也有自己的声明感知 WCF 服务。它配置为与 home/resource ADFS 一起使用。自然地,它接受来自 home/resource ADFS 的令牌并拒绝来自 partner/users ADFS 的令牌。
我可以让我的 WCF 服务信任令牌由 partner/users ADFS 颁发,但从体系结构的角度来看这似乎是错误的。我应该使用 home/resource ADFS 和 partner/users ADFS 之间建立的信任以某种方式从 home/resource ADFS 获取令牌。
因此我必须 1) 使用来自 partner/users ADFS 的令牌在 home/resource ADFS 上发行令牌或 2) 以某种方式直接在 home/resource 上授权来自 partner/users AD 的用户ADFS 使用他的登录名和密码。仅考虑主动身份验证方案。
你能帮我解决第一个or/and第二个问题的代码示例吗?
我找了两个星期的解决方案,终于找到了答案。正确的流程是流程编号 1,您在其中授权合作伙伴的用户针对合作伙伴的 ADFS,然后使用收到的令牌针对资源 ADFS 授权它。工作代码示例如下
using System;
using System.IdentityModel.Tokens;
using System.ServiceModel;
using System.ServiceModel.Security;
using Microsoft.IdentityModel.Protocols.WSTrust;
using WSTrustChannel = Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel;
using WSTrustChannelFactory = Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory;
namespace SOS.Tools.AdfsConnectionChecker
{
/// <summary> Parameters to get token from partner's ADFS
/// using his domain user credentials </summary>
public class AdfsIdentityProviderTokenRequest
{
/// <summary>Domain user from identity provider domain.
/// E.g. Name.FamalyName@ipDomainName.local or ipDomain2kName\Name.FamalyName </summary>
public string IpDomainUserName { get; set; }
/// <summary>Domain user password</summary>
public string IpDomainUserPassword { get; set; }
/// <summary> Identyty provider token issuer server, i.e your partner adfs server.
/// E.g. adfs.partnerdomain.com</summary>
public string IpTokenIssuerServer { get; set; }
/// <summary>Resources token issuer server, i.e. your company adsf server.
/// E.g. adfs.resourcedomain.com</summary>
public string ResourcesTokenIssuerServer { get; set; }
}
/// <summary> Parameters to get token for your application from resource ADFS
/// using token from partner's ADFS</summary>
public class AdfsResourceProviderTokenForAppRequest
{
/// <summary>Token recieved from identity provider. </summary>
public SecurityToken IpToken { get; set; }
/// <summary>Resources token issuer server, i.e. your company adsf server.
/// E.g. adfs.resourcedomain.com</summary>
public string ResourcesTokenIssuerServer { get; set; }
/// <summary>Apllication you want token for. In terms of ADFS its Relying Party.
/// E.g. https://myAppServer.MyAppDomain.com/MyWcfService1 </summary>
public string AppUrl { get; set; }
}
public class AdfsTokenFactory
{
public SecurityToken GetIpToken(AdfsIdentityProviderTokenRequest request)
{
//string username, string password, string tokenIssuer, string appliesTo, out
var binding = new WS2007HttpBinding();
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
var tokenIssuerUrlFormat = "https://{0}/adfs/services/trust/13/usernamemixed";
var tokenIssuerUrl = string.Format(tokenIssuerUrlFormat, request.IpTokenIssuerServer);
using (var factory = new WSTrustChannelFactory(binding, new EndpointAddress(tokenIssuerUrl)))
{
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = request.IpDomainUserName;
factory.Credentials.UserName.Password = request.IpDomainUserPassword;
factory.ConfigureChannelFactory();
var trustUrlFromat = "http://{0}/adfs/services/trust";
var trustUrl = string.Format(trustUrlFromat, request.ResourcesTokenIssuerServer);
var requestToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
requestToken.AppliesTo = new EndpointAddress(trustUrl);
var tokenClient = (WSTrustChannel) factory.CreateChannel();
RequestSecurityTokenResponse rsts;
var token = tokenClient.Issue(requestToken, out rsts);
return token;
}
}
public SecurityToken GetResourceTokenForApp(AdfsResourceProviderTokenForAppRequest request)
{
var binding = new WS2007FederationHttpBinding();
binding.Security.Message.IssuedKeyType = SecurityKeyType.SymmetricKey;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Mode = WSFederationHttpSecurityMode.TransportWithMessageCredential;
var tokenIssuerUrlFormat = "https://{0}/adfs/services/trust/13/IssuedTokenMixedSymmetricBasic256";
var tokenIssuerUrl = string.Format(tokenIssuerUrlFormat, request.ResourcesTokenIssuerServer);
using (var factory = new WSTrustChannelFactory(binding, new EndpointAddress(new Uri(tokenIssuerUrl))))
{
var rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(request.AppUrl),
KeyType = WSTrust13Constants.KeyTypes.Symmetric,
};
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = false;
factory.ConfigureChannelFactory();
var channel = factory.CreateChannelWithIssuedToken(request.IpToken);
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
return token;
}
}
}
}
你这样称呼它
var factory = new AdfsTokenFactory();
var ipTokenRequest = new AdfsIdentityProviderTokenRequest
{
//or "ipDomain2kName\Name.FamalyName"
IpDomainUserName = "Name.FamalyName@ipDomainName.local",
IpDomainUserPassword = "userDomainPassword",
IpTokenIssuerServer = "adfs.partnerdomain.com",
ResourcesTokenIssuerServer = "adfs.resourcedomain.com"
};
var ipToken = factory.GetIpToken(ipTokenRequest);
var appTokenRequest = new AdfsResourceProviderTokenForAppRequest
{
IpToken = ipToken,
ResourcesTokenIssuerServer ="adfs.resourcedomain.com",
AppUrl = "https://myAppServer.MyAppDomain.com/MyWcfService1"
};
var appToken = factory.GetResourceTokenForApp(appTokenRequest);
使用 this approach 我可以在 home/resource ADFS 和 partner/users 上为我的应用程序获取授权令牌。我也有自己的声明感知 WCF 服务。它配置为与 home/resource ADFS 一起使用。自然地,它接受来自 home/resource ADFS 的令牌并拒绝来自 partner/users ADFS 的令牌。
我可以让我的 WCF 服务信任令牌由 partner/users ADFS 颁发,但从体系结构的角度来看这似乎是错误的。我应该使用 home/resource ADFS 和 partner/users ADFS 之间建立的信任以某种方式从 home/resource ADFS 获取令牌。
因此我必须 1) 使用来自 partner/users ADFS 的令牌在 home/resource ADFS 上发行令牌或 2) 以某种方式直接在 home/resource 上授权来自 partner/users AD 的用户ADFS 使用他的登录名和密码。仅考虑主动身份验证方案。
你能帮我解决第一个or/and第二个问题的代码示例吗?
我找了两个星期的解决方案,终于找到了答案。正确的流程是流程编号 1,您在其中授权合作伙伴的用户针对合作伙伴的 ADFS,然后使用收到的令牌针对资源 ADFS 授权它。工作代码示例如下
using System;
using System.IdentityModel.Tokens;
using System.ServiceModel;
using System.ServiceModel.Security;
using Microsoft.IdentityModel.Protocols.WSTrust;
using WSTrustChannel = Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel;
using WSTrustChannelFactory = Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory;
namespace SOS.Tools.AdfsConnectionChecker
{
/// <summary> Parameters to get token from partner's ADFS
/// using his domain user credentials </summary>
public class AdfsIdentityProviderTokenRequest
{
/// <summary>Domain user from identity provider domain.
/// E.g. Name.FamalyName@ipDomainName.local or ipDomain2kName\Name.FamalyName </summary>
public string IpDomainUserName { get; set; }
/// <summary>Domain user password</summary>
public string IpDomainUserPassword { get; set; }
/// <summary> Identyty provider token issuer server, i.e your partner adfs server.
/// E.g. adfs.partnerdomain.com</summary>
public string IpTokenIssuerServer { get; set; }
/// <summary>Resources token issuer server, i.e. your company adsf server.
/// E.g. adfs.resourcedomain.com</summary>
public string ResourcesTokenIssuerServer { get; set; }
}
/// <summary> Parameters to get token for your application from resource ADFS
/// using token from partner's ADFS</summary>
public class AdfsResourceProviderTokenForAppRequest
{
/// <summary>Token recieved from identity provider. </summary>
public SecurityToken IpToken { get; set; }
/// <summary>Resources token issuer server, i.e. your company adsf server.
/// E.g. adfs.resourcedomain.com</summary>
public string ResourcesTokenIssuerServer { get; set; }
/// <summary>Apllication you want token for. In terms of ADFS its Relying Party.
/// E.g. https://myAppServer.MyAppDomain.com/MyWcfService1 </summary>
public string AppUrl { get; set; }
}
public class AdfsTokenFactory
{
public SecurityToken GetIpToken(AdfsIdentityProviderTokenRequest request)
{
//string username, string password, string tokenIssuer, string appliesTo, out
var binding = new WS2007HttpBinding();
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
var tokenIssuerUrlFormat = "https://{0}/adfs/services/trust/13/usernamemixed";
var tokenIssuerUrl = string.Format(tokenIssuerUrlFormat, request.IpTokenIssuerServer);
using (var factory = new WSTrustChannelFactory(binding, new EndpointAddress(tokenIssuerUrl)))
{
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = request.IpDomainUserName;
factory.Credentials.UserName.Password = request.IpDomainUserPassword;
factory.ConfigureChannelFactory();
var trustUrlFromat = "http://{0}/adfs/services/trust";
var trustUrl = string.Format(trustUrlFromat, request.ResourcesTokenIssuerServer);
var requestToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
requestToken.AppliesTo = new EndpointAddress(trustUrl);
var tokenClient = (WSTrustChannel) factory.CreateChannel();
RequestSecurityTokenResponse rsts;
var token = tokenClient.Issue(requestToken, out rsts);
return token;
}
}
public SecurityToken GetResourceTokenForApp(AdfsResourceProviderTokenForAppRequest request)
{
var binding = new WS2007FederationHttpBinding();
binding.Security.Message.IssuedKeyType = SecurityKeyType.SymmetricKey;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Mode = WSFederationHttpSecurityMode.TransportWithMessageCredential;
var tokenIssuerUrlFormat = "https://{0}/adfs/services/trust/13/IssuedTokenMixedSymmetricBasic256";
var tokenIssuerUrl = string.Format(tokenIssuerUrlFormat, request.ResourcesTokenIssuerServer);
using (var factory = new WSTrustChannelFactory(binding, new EndpointAddress(new Uri(tokenIssuerUrl))))
{
var rst = new RequestSecurityToken
{
RequestType = WSTrust13Constants.RequestTypes.Issue,
AppliesTo = new EndpointAddress(request.AppUrl),
KeyType = WSTrust13Constants.KeyTypes.Symmetric,
};
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = false;
factory.ConfigureChannelFactory();
var channel = factory.CreateChannelWithIssuedToken(request.IpToken);
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
return token;
}
}
}
}
你这样称呼它
var factory = new AdfsTokenFactory();
var ipTokenRequest = new AdfsIdentityProviderTokenRequest
{
//or "ipDomain2kName\Name.FamalyName"
IpDomainUserName = "Name.FamalyName@ipDomainName.local",
IpDomainUserPassword = "userDomainPassword",
IpTokenIssuerServer = "adfs.partnerdomain.com",
ResourcesTokenIssuerServer = "adfs.resourcedomain.com"
};
var ipToken = factory.GetIpToken(ipTokenRequest);
var appTokenRequest = new AdfsResourceProviderTokenForAppRequest
{
IpToken = ipToken,
ResourcesTokenIssuerServer ="adfs.resourcedomain.com",
AppUrl = "https://myAppServer.MyAppDomain.com/MyWcfService1"
};
var appToken = factory.GetResourceTokenForApp(appTokenRequest);