如何验证 ADFS SAML 令牌

2023-12-30

我目前正在从 ADFS 生成 SAML 令牌,如下所示:

 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 应用程序。据我所知,工作流程应该是这样的:

  • 生成代币
  • 客户端获取生成的令牌(有效登录后)
  • 客户端缓存令牌
  • 客户端使用 token 进行下次登录
  • Web应用程序验证令牌,不必调用ADFS

如何验证客户端提供的令牌是否有效?我是否需要 ADFS 服务器的证书来解密令牌?


在查看了优秀的thinktecture身份服务器代码之后(https://github.com/thinktecture/Thinktecture.IdentityServer.v2/tree/master/src/Libraries/Thinktecture.IdentityServer.Protocols/AdfsIntegration https://github.com/thinktecture/Thinktecture.IdentityServer.v2/tree/master/src/Libraries/Thinktecture.IdentityServer.Protocols/AdfsIntegration)我提取了解决方案:

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; }
    }

}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何验证 ADFS SAML 令牌 的相关文章

随机推荐

  • 监听滚动事件horizo​​ntalscrollview android

    我正在尝试监听事件HorizontalScrollView已滚动 尝试过这个 但它不打印任何内容 HorizontalScrollView headerScrollView new HorizontalScrollView this hea
  • Microsoft Windows 7 POSIX 实现目前处于什么位置?

    Windows 7 中是否有完整的 POSIX 实现可用 我正在考虑 Windows Services for UNIX 它在每个版本的操作系统中都可用吗 似乎不是 它如何在以前的 MS Windows POSIX 实现上添加 改进或破坏
  • TabLayout 文本重力

    我想在我的选项卡布局中设置文本的重力来开始 但我找不到任何有效的解决方案 下图显示了我想要实现的设计 下图显示了我的实际结果 My Code
  • 我可以从具有许多编译器标志的 C 程序中导出使用的代码吗?

    我想将您的 Linux 驱动程序代码压缩为仅在当前内核上运行的代码 它有一些被 if 语句忽略的部分 一直到内核 2 4 x 您是否听说过一种将代码编译为输出的方法 该输出将成为工作代码 而不会被 c 编译器 if else 语句忽略的所有
  • 将 MS Access 数据库导出到 SQL Server 2008 Express

    是否有一种简单的方法将 MS Access 数据库后端 表和关系 导出到 SQL Server 数据库 以便它可以用作使用实体框架用 C 编写的定制应用程序的后端 Access 数据库至少包含 50 个表 导出不应破坏其结构和关系 Micr
  • 如何在 Visual Studio C++ 2010 中将 BSTR 转换为 std::string?

    我正在研究 COM dll 我希望将 BSTR 转换为 std string 以传递给采用 const 引用参数的方法 看来使用 com util ConvertBSTRToString 来获取 BSTR 的 char 等效项是一种合适的方
  • 如何获取今天在 git 中提交的总行数?

    我发现了仓库存在以来 git 的一般统计数据 但我有兴趣做类似的事情 git today 并获取按作者细分的提交数 行数等内容 我最感兴趣的是当前用户的行数 我可以自己结合其他事情的结果 如果您想查看 git 存储库活动的图形表示 请使用g
  • 使用 PDFBox 从 PDF 文档中读取特定页面

    如何使用 PDFBox 从 PDF 文档中读取特定页面 给定页码 这应该有效 PDPage firstPage PDPage doc getAllPages get 0 如中所见教程的书签部分 http pdfbox apache org
  • 如何删除从网络服务返回的无法识别的字符?

    我正在开发一个调用休息网络服务的应用程序 有时 xml 响应包含电话无法显示的字符 显示这些字符时 会显示一个空框 我想过滤掉这些字符 如何检测某个字符是否能够显示在屏幕上 一些具体字符包括 http www fileformat info
  • iPhone Obj C -- 对可变字典数组进行排序 -- 显示字符串但按值排序

    我有一个 NSMutableArray 里面有 30 个字典 每个都包含一个名称和一个值 我目前已对名称进行排序 以便按字母顺序显示在表格视图中 但是 我想制作一个 UIButton 来提供仍然显示名称的选项 但按值排序 该值不需要显示 另
  • 从 TCP 套接字解析 XML 流

    我编写了一个 Ruby 脚本来通过 TCP 套接字连接到 XML 流 我想使用 LibXML 解析此 XML 流 我的问题是我不知道如何将此流传递给 LibXML 来自 LibXML 文档XML Document io io http li
  • 如何并排显示两个 Markdown 代码块

    我想并排显示源代码的两个块 重构之前和之后 是否可以并排创建两个代码块 如果不是那么替代解决方案是什么 无法使用纯 Markdown 语法在单个表格单元格中创建多行代码块 但您可以使用逐字 HTML 来完成此操作 下面是一个带有并排代码的两
  • Matplotlib 子图:imshow + 绘图

    我想创建一个如下图所示的图 图中有两个独特的情节 img1是使用生成的plt imshow while img2是使用生成的plt plot 下面提供了我用来生成每个图的代码 plt clf plt imshow my matrix plt
  • 带有输入组的引导面板

    我想做的是有一个引导面板 其左侧有一个按钮 右侧有一个按钮 有点像输入组 我希望这是有意义的 请原谅我的绘画技巧 但我想我应该附上一个例子来说明我的意思 面板可能不是最好的选择 所以如果有任何其他建议 请随时告诉我 Thanks 尝试这个c
  • MSBuild 和 TeamBuild - BuildInParallel 由于 MSB3021 文件权限冲突而失败

    我维护着一个相当大的软件的构建 其中包含大约 350 个 csharp 项目 我们的调试构建时间约为 17 分钟 我一直在寻找缩短构建时间的方法 BuildInParallel 属性确实看起来很有趣 特别是因为我们有一个四核服务器来进行构建
  • cordova - 多个 dex 文件定义 Lcom/google/android/gms/iid/zzc

    我正在尝试编译适用于 Android 的 cordova 应用程序 但收到此错误 有任何想法吗 这是我收到的错误 FAILURE Build failed with an exception What went wrong Executio
  • 如何对多态向量中包含的元素进行拆箱?

    看完之后这是 属于特征的对象的向量 的答案 https stackoverflow com a 25819164 129805 看起来 Rust 会自动拆箱 是这样吗 我的代码无法编译 我不明白该答案的代码如何编译 对包含装箱特征的多态向量
  • 如何查看Boto3 HTTPS请求字符串

    我已经能够查看 botocore 发送的PreparedRequest 的属性 但我想知道如何查看发送到AWS 的确切请求字符串 我需要确切的请求字符串才能将其与我正在测试 AWS 调用的另一个应用程序进行比较 您还可以在 boto3 中启
  • 如何组合和验证 swt 对话框的两个文本字段?

    我有另一个问题 我使用一个文本字段的修改侦听器来激活和停用 swt 对话框中的 确定 按钮 效果很好 现在我想为另一个文本字段添加修改侦听器 我希望仅当两个文本字段中都至少有一个字符时才激活 确定 按钮 这是两个字段的代码 descript
  • 如何验证 ADFS SAML 令牌

    我目前正在从 ADFS 生成 SAML 令牌 如下所示 WSTrustChannelFactory factory null try use a UserName Trust Binding for username authenticat