简体   繁体   English

使用WIF 4.5从WS-Trust STS请求SAML 2.0安全令牌

[英]Requesting a SAML 2.0 security token from a WS-Trust STS using WIF 4.5

I am able to request a SAML 1.1 token using by specifying TokenType=SecurityTokenTypes.Saml in the RequestSecurityToken message. 我可以通过在RequestSecurityToken消息中指定TokenType = SecurityTokenTypes.Saml来请求SAML 1.1令牌。 I am able to convert this to a ClaimsPrincipal and view the claims. 我可以将其转换为ClaimsPrincipal并查看索赔。

However, when I want to request a SAML 2.0 token by changing TokenType to the namespace " http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0 ", I get an exception that includes the following. 但是,当我想通过将TokenType更改为名称空间“ http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0 ”来请求SAML 2.0令牌时,我获取包含以下内容的异常。

System.Xml.XmlException: 'Cannot read KeyIdentifierClause from element 'Reference' with namespace ' http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd '. System.Xml.XmlException:'无法从命名空间为' http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd的元素'Reference'中读取KeyIdentifierClause' 。 Custom KeyIdentifierClauses require custom SecurityTokenSerializers, please refer to the SDK for examples.' 自定义KeyIdentifierClauses需要自定义SecurityTokenSerializer,请参阅SDK以获得示例。

I was wondering if SAML 2.0 tokens are support when being requested from a WS-Trust 1.3 security token service, and if so, how is it requested? 我想知道从WS-Trust 1.3安全令牌服务请求时是否支持SAML 2.0令牌,如果是,如何请求? The SecurityTokenTypes constants class provided by Microsoft only contains a single "Saml" that doesn't specify the version, and funny enough, references a Microsoft-specific namespace. Microsoft提供的SecurityTokenTypes常量类仅包含一个未指定版本的“ Saml”,并且很有趣,它引用了Microsoft特定的名称空间。

I know that Microsoft has provided supporting classes for SAML 2.0 tokens, such as Saml2SecurityTokenHandler, but I seem to be unable to actually request one from the STS. 我知道Microsoft已经为SAML 2.0令牌提供了支持类,例如Saml2SecurityTokenHandler,但是我似乎无法实际从STS请求一个。

Here is my code below. 这是下面的代码。

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.ServiceModel;
using System.ServiceModel.Security;
using System.Xml;

namespace WsTrustActiveSTSClient
{
    internal class Program
    {
        private const string relyingPartyId = "http://localhost/myApp";
        private const string stsEndpoint = "https://localhost:9443/services/wso2carbon-sts";

        private static void Main(string[] args)
        {
            WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);

            binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
            binding.Security.Message.EstablishSecurityContext = false;


            EndpointAddress endpoint = new EndpointAddress(stsEndpoint);

            WSTrustChannelFactory factory = new WSTrustChannelFactory(binding, endpoint);
            factory.TrustVersion = TrustVersion.WSTrust13;

            factory.Credentials.UserName.UserName = "admin";
            factory.Credentials.UserName.Password = "admin";

            WSTrustChannel channel = (WSTrustChannel) factory.CreateChannel();

            RequestSecurityToken rst = new RequestSecurityToken
            {
                RequestType = RequestTypes.Issue,
                KeyType = KeyTypes.Bearer,
                AppliesTo = new EndpointReference(relyingPartyId),              
                Claims =
                {
                    new RequestClaim("http://wso2.org/claims/givenname"),
                    new RequestClaim("http://wso2.org/claims/emailaddress")
                },
                //TokenType = SecurityTokenTypes.Saml
                TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"
            };

            GenericXmlSecurityToken genericXmlSecurityToken = (GenericXmlSecurityToken) channel.Issue(rst, out RequestSecurityTokenResponse rstr);          

            Console.WriteLine("{0}\n{1}\n\n", genericXmlSecurityToken, genericXmlSecurityToken.TokenXml.OuterXml);

            SecurityTokenHandlerCollection tokenHandlers = new SecurityTokenHandlerCollection(
                new SecurityTokenHandler[]
                {
                    new SamlSecurityTokenHandler(), 
                    new Saml2SecurityTokenHandler()
                }
            );
            tokenHandlers.Configuration.AudienceRestriction = new AudienceRestriction();
            tokenHandlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri(relyingPartyId));

            TrustedIssuerNameRegistry trustedIssuerNameRegistry = new TrustedIssuerNameRegistry();
            tokenHandlers.Configuration.IssuerNameRegistry = trustedIssuerNameRegistry;

            SecurityToken token =
                tokenHandlers.ReadToken(
                    new XmlTextReader(new StringReader(genericXmlSecurityToken.TokenXml.OuterXml)));

            ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(tokenHandlers.ValidateToken(token).First());

            Console.WriteLine("Name : " + claimsPrincipal.Identity.Name);
            Console.WriteLine("Auth Type : " + claimsPrincipal.Identity.AuthenticationType);
            Console.WriteLine("Is Authed : " + claimsPrincipal.Identity.IsAuthenticated);
            foreach (Claim c in claimsPrincipal.Claims)
                Console.WriteLine("{0}:{1}", c.Type, c.Value);

            Console.ReadLine();
        }

        public class TrustedIssuerNameRegistry : IssuerNameRegistry
        {
            public override string GetIssuerName(SecurityToken securityToken)
            {
                return "Trusted Issuer";
                // throw new SecurityTokenException("Untrusted issuer.");
            }
        }
    }
}

When I don't specify a TokenType in the RST this is the SOAP message that gets sent to the WS-Trust STS. 当我未在RST中指定TokenType时,这是发送到WS-Trust STS的SOAP消息。

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
   <s:Header>
      <a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
      <a:MessageID>urn:uuid:bb24c76a-b737-4a9b-8526-26b84a28bbe8</a:MessageID>
      <a:ReplyTo>
         <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
      </a:ReplyTo>
      <a:To s:mustUnderstand="1">https://localhost:9443/services/wso2carbon-sts</a:To>
      <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
         <u:Timestamp u:Id="_0">
            <u:Created>2017-10-17T14:50:01.517Z</u:Created>
            <u:Expires>2017-10-17T14:55:01.517Z</u:Expires>
         </u:Timestamp>
         <o:UsernameToken u:Id="uuid-b6a803fc-b1fe-4186-8c3e-dcf4b1a647e5-1">
            <o:Username>admin</o:Username>
            <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">admin</o:Password>
         </o:UsernameToken>
      </o:Security>
   </s:Header>
   <s:Body>
      <trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
         <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
            <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
               <wsa:Address>http://localhost/myApp</wsa:Address>
            </wsa:EndpointReference>
         </wsp:AppliesTo>
         <trust:Claims xmlns:i="http://schemas.xmlsoap.org/ws/2005/05/identity" Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity">
            <i:ClaimType Uri="http://wso2.org/claims/givenname" Optional="false"/>
            <i:ClaimType Uri="http://wso2.org/claims/emailaddress" Optional="false"/>
         </trust:Claims>
         <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
         <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
      </trust:RequestSecurityToken>
   </s:Body>
</s:Envelope>

And here is the response from WSO2 Identity Server. 这是WSO2 Identity Server的响应。

   <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
      <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
         <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="true">
            <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-1">
               <wsu:Created>2017-10-17T14:50:02.407Z</wsu:Created>
               <wsu:Expires>2017-10-17T14:55:02.407Z</wsu:Expires>
            </wsu:Timestamp>
         </wsse:Security>
         <wsa:Action>http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/Issue</wsa:Action>
         <wsa:RelatesTo>urn:uuid:bb24c76a-b737-4a9b-8526-26b84a28bbe8</wsa:RelatesTo>
      </soapenv:Header>
      <soapenv:Body>
         <wst:RequestSecurityTokenResponseCollection xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
            <wst:RequestSecurityTokenResponse>
               <wst:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</wst:TokenType>
               <wst:RequestedAttachedReference>
                  <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                     <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_d8c5ef71f6665284b3ba5f7aca69f08b</wsse:KeyIdentifier>
                  </wsse:SecurityTokenReference>
               </wst:RequestedAttachedReference>
               <wst:RequestedUnattachedReference>
                  <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                     <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_d8c5ef71f6665284b3ba5f7aca69f08b</wsse:KeyIdentifier>
                  </wsse:SecurityTokenReference>
               </wst:RequestedUnattachedReference>
               <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
                  <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
                     <wsa:Address>http://localhost/myApp</wsa:Address>
                  </wsa:EndpointReference>
               </wsp:AppliesTo>
               <wst:Lifetime>
                  <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-10-17T14:50:02.236Z</wsu:Created>
                  <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-10-17T14:55:02.236Z</wsu:Expires>
               </wst:Lifetime>
               <wst:RequestedSecurityToken>
                  <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" AssertionID="_d8c5ef71f6665284b3ba5f7aca69f08b" IssueInstant="2017-10-17T14:50:02.282Z" Issuer="https://localhost" MajorVersion="1" MinorVersion="1">
                     <Conditions NotBefore="2017-10-17T14:50:02.236Z" NotOnOrAfter="2017-10-17T14:55:02.236Z">
                        <AudienceRestrictionCondition>
                           <Audience>http://localhost/myApp</Audience>
                        </AudienceRestrictionCondition>
                     </Conditions>
                     <AuthenticationStatement AuthenticationInstant="2017-10-17T14:50:02.236Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password">
                        <Subject>
                           <NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin</NameIdentifier>
                           <SubjectConfirmation>
                              <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</ConfirmationMethod>
                           </SubjectConfirmation>
                        </Subject>
                     </AuthenticationStatement>
                     <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                        <ds:SignedInfo>
                           <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                           <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                           <ds:Reference URI="#_d8c5ef71f6665284b3ba5f7aca69f08b">
                              <ds:Transforms>
                                 <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                                 <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                    <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="code ds kind rw saml samlp typens #default xsd xsi"/>
                                 </ds:Transform>
                              </ds:Transforms>
                              <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                              <ds:DigestValue>8w9YHsb+YIyUCzGjqh6q0JrjxTI=</ds:DigestValue>
                           </ds:Reference>
                        </ds:SignedInfo>
                        <ds:SignatureValue>Evm0H2+hOMWdsrK0Rp8HPCDDldMJ+AHPgv4hrqKW6IuPGFT25DhTRoIc+cPuerFOABYX5B1Om0v4VlmqsalpK2V7tdzHlrDbrOCiENL4FhdATd48o/IiRjde8XM0B7gHAIJoMSimg3Fc/jPXH4kyMsLAWM+l0GdK8VxKVLPtrhY=</ds:SignatureValue>
                        <ds:KeyInfo>
                           <ds:X509Data>
                              <ds:X509Certificate>MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTousMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQIDAQABoxIwEDAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEAW5wPR7cr1LAdq+IrR44iQlRG5ITCZXY9hI0PygLP2rHANh+PYfTmxbuOnykNGyhM6FjFLbW2uZHQTY1jMrPprjOrmyK5sjJRO4d1DeGHT/YnIjs9JogRKv4XHECwLtIVdAbIdWHEtVZJyMSktcyysFcvuhPQK8Qc/E/Wq8uHSCo=</ds:X509Certificate>
                           </ds:X509Data>
                        </ds:KeyInfo>
                     </ds:Signature>
                  </Assertion>
               </wst:RequestedSecurityToken>
            </wst:RequestSecurityTokenResponse>
         </wst:RequestSecurityTokenResponseCollection>
      </soapenv:Body>
   </soapenv:Envelope>

As you can see, WSO2 Identity Server is returning a mixture of SAML 1.0 and SAML 1.1 namespaces. 如您所见,WSO2 Identity Server返回的是SAML 1.0和SAML 1.1命名空间的混合体。

I've never used WSO Identity Server but this code worked fine with Thinktecture IdentityServer. 我从未使用过WSO Identity Server,但此代码在Thinktecture IdentityServer上运行良好。 I've replaced the endpoint address and realm with the information from your example. 我已经用示例中的信息替换了端点地址和领域。

public static SecurityToken GetToken(string userName, string password)
{
    const string stsEndpoint = "https://localhost:9443/services/wso2carbon-sts";
    const string realm = "http://localhost/myApp";

    var factory = new WSTrustChannelFactory(
        new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
        stsEndpoint) { TrustVersion = TrustVersion.WSTrust13 };

    factory.Credentials.UserName.UserName = userName;
    factory.Credentials.UserName.Password = password;

    var rst = new RequestSecurityToken
    {
        AppliesTo = new EndpointReference(realm),
        RequestType = RequestTypes.Issue,
        KeyType = KeyTypes.Bearer
    };

    var channel = factory.CreateChannel();
    var token = channel.Issue(rst);
    return token;
}

You can get SAML2.0 tokens from a WS-Trust 1.3 STS, but remember that: 您可以从WS-Trust 1.3 STS获得SAML2.0令牌,但请记住:

  1. It is up to the STS to honor your request. STS可以满足您的要求。 For instance, it might always generate a specific type of token, regardless of what was requested. 例如,无论请求什么,它都可能总是生成特定类型的令牌。
  2. Not all STS's can generate SAML2.0 tokens. 并非所有STS都能生成SAML2.0令牌。 I know WIF 4.5 allows that, but does your STS use it? 我知道WIF 4.5允许这样做,但是您的STS会使用吗? I'm not sure that the older version (WIF 1.0/3.5) can generate SAML2.0 tokens. 我不确定较旧的版本(WIF 1.0 / 3.5)是否可以生成SAML2.0令牌。

Assuming that your specific STS does honor these requests and can generate SAML2.0 tokens, then try this: 假设您的特定STS确实满足了这些请求并可以生成SAML2.0令牌,那么请尝试以下操作:

TokenType = "urn:oasis:names:tc:SAML:2.0:assertion"

or, if it still doesn't work, maybe: 或者,如果仍然无法正常工作,则可能是:

AuthenticationType = "urn:oasis:names:tc:SAML:2.0:assertion"

I occasionally found out setting the tokenType of RST to saml2.0 URL will make STS returning SAML 2.0 assertion. 我偶尔发现将RST的tokenType设置为saml2.0 URL会使STS返回SAML 2.0断言。 The most interesting thing is nowhere from Microsoft documents this. 最有趣的是,Microsoft对此文件一无所知。

Try something like this: 尝试这样的事情:

        ServicePointManager.ServerCertificateValidationCallback =
            ((sender, certificate, chain, sslPolicyErrors) => true);
        var rst = new RequestSecurityToken(RequestTypes.Issue);
        rst.AppliesTo = new EndpointReference("https://RelyingParty/*");
        rst.KeyType = KeyTypes.Bearer;
        rst.TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0";

        using (var trustChannelFactory = new WSTrustChannelFactory("WS2007HttpBinding_IWSTrust13_Saml20Sync"))
        {
            trustChannelFactory.Credentials.UserName.UserName = userName;
            trustChannelFactory.Credentials.UserName.Password = userPassword;

            var channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
            try
            {
                _authToken = channel.Issue(rst);
            }
            catch (MessageSecurityException ex)
            {
                channel.Abort();
                throw new SecurityTokenException(ex.InnerException.Message, ex);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            UserIdenity = CreateUserIdentityFromSecurityToken(_authToken);
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM