locked
WCF - Specifying credentials in channel factory RRS feed

  • Question

  • I have my own custom STS. I am using the following code to obtain the token. (Note that I don't want to rely on WCF to make a call to STS so I am using WSTrustChannel). This works fine if I invoke STS over an endpoint that does not required any security. I want to use an endpoint that required username or certificate. How do I specify username or certificate in request here?

    trustChannelFactory.Credentials.UserName is read-only so I cannot use it.




    WS2007HttpBinding serviceBinding = new WS2007HttpBinding("STSBinding");
                EndpointAddress endpoint = new EndpointAddress(new Uri("http://epic9790.epicsys.com/EpicSTS/STS.svc/nosecurity"),
                EndpointIdentity.CreateDnsIdentity("epic9790.epicsys.com"));
                WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(serviceBinding, endpoint);
               
                trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;

                WSTrustChannel channel = null;

                try
                {
                    RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
                    rst.AppliesTo = new EndpointAddress("http://epic9790.epicsys.com/STSWcfServiceSaml/Service.svc");
                    channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
                    SecurityToken token = channel.Issue(rst);
                    ((IChannel)channel).Close();
                    channel = null;

                    trustChannelFactory.Close();
                    trustChannelFactory = null;

                    return token;
                }

    I have following configuration in my App.config file that contains binding information:

    <ws2007HttpBinding>
            <binding name="STSBinding"
                closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00"
                sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false"
                hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288"
                maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8"
                useDefaultWebProxy="true" allowCookies="false">
              <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                  maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <reliableSession ordered="true" inactivityTimeout="00:10:00"
                  enabled="false" />
              <!--<security mode="Message">
                <transport clientCredentialType="Windows" proxyCredentialType="None"
                    realm="" />
                <message clientCredentialType="UserName" negotiateServiceCredential="false"
                    algorithmSuite="Default" establishSecurityContext="false" />
              </security>-->
              <security mode="None">
                <transport clientCredentialType="Windows" proxyCredentialType="None"
                    realm="" />
                <message clientCredentialType="Windows" negotiateServiceCredential="true"
                    establishSecurityContext="true" />
              </security>
            </binding>
           
          </ws2007HttpBinding>

    MP
    Thursday, March 11, 2010 10:59 PM

Answers

  • It might be worth pointing out that the ClientCredentials become read-only after you create the first channel.

    You can add additional parameters to the RST directly by modifying the RST object. If you need to add custom elements, you can use a custom request serializer as well.
    Saturday, March 13, 2010 2:05 AM
    Moderator
  • GenericXmlSecurityToken has a TokenXml property - feed the OuterXml into an XmlReader and use the Saml2SecurityTokenHandler.ReadToken method to get a Saml2SecurityToken.
    Dominick Baier | thinktecture | http://www.leastprivilege.com
    • Marked as answer by Maulik Patel Thursday, March 17, 2011 1:15 AM
    Thursday, March 17, 2011 12:47 AM

All replies

  • WSTrustChannel has a ClientCredentials property.
    Dominick Baier | thinktecture | http://www.leastprivilege.com
    Friday, March 12, 2010 4:17 AM
  • I don't see ClientCrednetials property on WSTrustChannel. WSTrustChannelFactory has ClientCredentials property but it is read-only.

    Also, is it possible to add additional parameters to RST here? Notice that I am using WS2007HttpBinding (not WS2007FederationHttpBinding).


    MP
    • Proposed as answer by jcastellsg Friday, March 12, 2010 6:53 PM
    Friday, March 12, 2010 1:14 PM
  • channelFactory.Credentials.UserName.UserName = getUsername(); // "DOMAIN\UserName"
    channelFactory.Credentials.UserName.Password = getPassword(); // "Password"
    

    if you want pass username and password





     

    • Proposed as answer by jcastellsg Friday, March 12, 2010 6:59 PM
    Friday, March 12, 2010 6:56 PM
  • It might be worth pointing out that the ClientCredentials become read-only after you create the first channel.

    You can add additional parameters to the RST directly by modifying the RST object. If you need to add custom elements, you can use a custom request serializer as well.
    Saturday, March 13, 2010 2:05 AM
    Moderator
  • Thank Shiung..The problem was that I was trying to set credentials after creating the channel.

    Can you show me an example on how to modify RST by using custom request serializer? What methods do I need to override to customize RST?


    Now my following code is working. I tried exposing this functionality as a web service but it throws an exception because of the following error. Is there a way to serialize GenericXmlSecurityToken class? Also, it returns me 'GenericXmlSecurityToken'. Is it same as SamlSecurityToken? I want SamlSecurityToken.


    Type 'System.IdentityModel.Tokens.GenericXmlSecurityToken' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  See the Microsoft .NET Framework documentation for other supported types.

    WS2007HttpBinding serviceBinding = new WS2007HttpBinding("STSBinding");
    			
    			EndpointAddress endpoint = new EndpointAddress(new Uri("http://localhost/MySTS/STS.svc/username"), EndpointIdentity.CreateDnsIdentity("STSTestCert"));
    			WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(serviceBinding, endpoint);
    			trustChannelFactory.Credentials.UserName.UserName = "fdfsdafsd";
    			trustChannelFactory.Credentials.UserName.Password = "fdfsdfsdfsd";
    			trustChannelFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "0e 2a 9e b7 5f 1a fc 32 17 90 40 7f a4 b1 30 e0 e4 e2 23 e2");
    			trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
    			ChannelFactoryOperations.ConfigureChannelFactory(trustChannelFactory);
    
    			WSTrustChannel channel = null;
    			RequestSecurityTokenResponse response = null;
    			try
    			{
    				RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
    				rst.AppliesTo = new EndpointAddress("http://localhsot/STSWcfServiceSaml/Service.svc");
    
    				channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
    				SecurityToken issuedToken = channel.Issue(rst, out response);
    				((IChannel)channel).Close();
    				channel = null;
    
    				trustChannelFactory.Close();
    				trustChannelFactory = null;
    				return token;
    			}
    			catch (Exception ex)
    			{
    				return null;
    			}
    			finally
    			{
    				if (channel != null)
    				{
    					((IChannel)channel).Abort();
    				}
    
    				if (trustChannelFactory != null)
    				{
    					trustChannelFactory.Abort();
    				}
    			}



    MP
    Monday, March 15, 2010 12:40 PM
  • Take a look at the CustomRequestSecurityToken sample in the WIF SDK. It demonstrates how to use a custom request serializer to read an RST, you can use the custom serializer in the sample on the client to write a custom RST as well. You can set the custom request serializer on the WSTrustChannelFactory.

    The WSTrustChannel.Issue() call will always return a token of type GenericXmlSecurityToken. This is because in most cases, the STS is expected to issue an encrypted token that the client will be unable to decrypt.

    You can get to the raw token xml from the GenericXmlSecurityToken, and configure a set of handlers on the client side to consume this xml to create a strongly typed SamlSecurityToken object.

    Monday, March 15, 2010 10:04 PM
    Moderator
  • Thanks Shiung. The custom RST serializer is working now. But I am still having problem with converting GenericXmlSecurityToken to strongly typed tokens.


    How do I convert GenericXmlSecurityToken to SamlSecurityToken,Saml11SecurityToken or Saml2SecurityToken?
    MP
    Tuesday, March 16, 2010 12:33 PM
  • Anyone?
    MP
    Wednesday, April 21, 2010 7:47 PM
  • Do you have an answer?

    We also need to convert this GenericXmlSecurityToken to a SAML token, but we don't have the private key needed to decrypt the token... this is at the other service that consumes the token.

    Wednesday, August 25, 2010 12:09 PM
  • Hi,

    I have a Sharepoint website and a custom STS and using the same code as listed above by Maulik to get the token. Can anyone tell me how can I redirect back to the sharepoint site once my user is authenticated and I get the tokens.

    Friday, February 18, 2011 9:00 AM
  • Hi Maulik

    I need to convert GenericXmlSecurityToken to Saml2SecurityToken.  Have you figured out how to convert it and can you share the solution with me? 

    Thank you!

    Regards
    Pradeep

    Wednesday, March 16, 2011 3:43 PM
  • GenericXmlSecurityToken has a TokenXml property - feed the OuterXml into an XmlReader and use the Saml2SecurityTokenHandler.ReadToken method to get a Saml2SecurityToken.
    Dominick Baier | thinktecture | http://www.leastprivilege.com
    • Marked as answer by Maulik Patel Thursday, March 17, 2011 1:15 AM
    Thursday, March 17, 2011 12:47 AM
  • I am using code similar to the above code to get a SecurityToken which does work. However, when I attempt to create the XmlReader object feeding in the OuterXml of the TokenXml property I get an ArgumentException that says "Illegal characters in path". Here is the code I am using to create the reader:

    XmlReader reader = XmlReader.Create(((GenericXmlSecurityToken)token).TokenXml.OuterXml);

    Is there something that I am missing?


    GregP
    Friday, August 26, 2011 3:53 PM