如何验证ADFS SAML令牌 [英] How to validate ADFS SAML token
问题描述
我目前从这样的ADFS产生SAML令牌:
I am currently generating SAML tokens from ADFS like this:
WSTrustChannelFactory factory = null;
try
{
// use a UserName Trust Binding for username authentication
factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress("https://adfs.company.com/adfs/services/trust/13/usernamemixed"));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = "user";
factory.Credentials.UserName.Password = "pw";
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference(relyingPartyId),
KeyType = KeyTypes.Bearer
};
IWSTrustChannelContract channel = factory.CreateChannel();
GenericXmlSecurityToken genericToken = channel.Issue(rst)
as GenericXmlSecurityToken;
}
finally
{
if (factory != null)
{
try
{
factory.Close();
}
catch (CommunicationObjectFaultedException)
{
factory.Abort();
}
}
}
现在让我们说我建一个使用这些令牌身份验证的Web应用程序。据我知道的工作流程应该是这样的:
Now let's say I build a web application that uses these tokens for authentication. As far as I know the workflow should be like this:
- 生成令牌
- 客户端获取生成令牌(有效登录后)
- 客户端缓存标记
- 客户端使用令牌下次登录
- Web应用程序验证带道理,不必调用ADFS
- Generate token
- client gets generated token (after valid login)
- client caches token
- client uses token for next login
- web application validates token, does not have to call ADFS
我如何可以验证客户出示令牌是有效的?我需要的ADFS服务器解密令牌的证书?
How can I validate that the token the client presents is valid? Do I need the certificate of the ADFS server to decrypt the token?
推荐答案
看优秀thinktecture身份服务器代码(后< A HREF =https://github.com/thinktecture/Thinktecture.IdentityServer.v2/tree/master/src/Libraries/Thinktecture.IdentityServer.Protocols/AdfsIntegration> https://github.com/thinktecture/Thinktecture.IdentityServer .V2 /树/主/ src目录/库/ Thinktecture.IdentityServer.Protocols / AdfsIntegration )我提取的解决方案:
After looking at the excellent thinktecture identity server code ( https://github.com/thinktecture/Thinktecture.IdentityServer.v2/tree/master/src/Libraries/Thinktecture.IdentityServer.Protocols/AdfsIntegration ) I extracted the solution:
using Newtonsoft.Json;
using System;
using System.IdentityModel.Protocols.WSTrust;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.Text;
using System.Xml;
using Thinktecture.IdentityModel.Extensions;
using Thinktecture.IdentityModel.WSTrust;
namespace SimpleWebConsole
{
internal class ADFS
{
public static void tokenTest()
{
string relyingPartyId = "https://party.mycomp.com";
WSTrustChannelFactory factory = null;
try
{
// use a UserName Trust Binding for username authentication
factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress("https://adfs.mycomp.com/adfs/services/trust/13/usernamemixed"));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = "test";
factory.Credentials.UserName.Password = "test";
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointReference(relyingPartyId),
KeyType = KeyTypes.Bearer
};
IWSTrustChannelContract channel = factory.CreateChannel();
GenericXmlSecurityToken genericToken = channel.Issue(rst) as GenericXmlSecurityToken; //MessageSecurityException -> PW falsch
var _handler = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
var tokenString = genericToken.ToTokenXmlString();
var samlToken2 = _handler.ReadToken(new XmlTextReader(new StringReader(tokenString)));
ValidateSamlToken(samlToken2);
X509Certificate2 certificate = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
certificate = store.Certificates.Find(X509FindType.FindByThumbprint, "thumb", false)[0];
var jwt=ConvertSamlToJwt(samlToken2, "https://party.mycomp.com", certificate);
}
finally
{
if (factory != null)
{
try
{
factory.Close();
}
catch (CommunicationObjectFaultedException)
{
factory.Abort();
}
}
}
}
public static TokenResponse ConvertSamlToJwt(SecurityToken securityToken, string scope, X509Certificate2 SigningCertificate)
{
var subject = ValidateSamlToken(securityToken);
var descriptor = new SecurityTokenDescriptor
{
Subject = subject,
AppliesToAddress = scope,
SigningCredentials = new X509SigningCredentials(SigningCertificate),
TokenIssuerName = "https://panav.mycomp.com",
Lifetime = new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddMinutes(10080))
};
var jwtHandler = new JwtSecurityTokenHandler();
var jwt = jwtHandler.CreateToken(descriptor);
return new TokenResponse
{
AccessToken = jwtHandler.WriteToken(jwt),
ExpiresIn = 10080
};
}
public static ClaimsIdentity ValidateSamlToken(SecurityToken securityToken)
{
var configuration = new SecurityTokenHandlerConfiguration();
configuration.AudienceRestriction.AudienceMode = AudienceUriMode.Never;
configuration.CertificateValidationMode = X509CertificateValidationMode.None;
configuration.RevocationMode = X509RevocationMode.NoCheck;
configuration.CertificateValidator = X509CertificateValidator.None;
var registry = new ConfigurationBasedIssuerNameRegistry();
registry.AddTrustedIssuer("thumb", "ADFS Signing - mycomp.com");
configuration.IssuerNameRegistry = registry;
var handler = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(configuration);
var identity = handler.ValidateToken(securityToken).First();
return identity;
}
public class TokenResponse
{
[JsonProperty(PropertyName = "access_token")]
public string AccessToken { get; set; }
[JsonProperty(PropertyName = "token_type")]
public string TokenType { get; set; }
[JsonProperty(PropertyName = "expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty(PropertyName = "refresh_token")]
public string RefreshToken { get; set; }
}
}
}
这篇关于如何验证ADFS SAML令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!