Search code examples
c#web-servicesadfswif

SecurityNegotiationException - Retrieving token from web service


I'm attempting to move from WIF 3.5 and onto WIF 4.5. However, the conversion is proving to be more difficult than I anticipated. The questions will correspond to the comments in the code.

Full error message:

System.Web.Services.Protocols.SoapException: 'System.Web.Services.Protocols.SoapException: Authentication Failed --->

System.ServiceModel.Security.SecurityNegotiationException: Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.

Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.

#1. Which username/password combination is needed and which is not?

#2. This is where SecurityNegotiationException is thrown. What am I missing exactly?

So, am I way off or is it something simple I'm missing? Do I need to entirely rewrite how the WSTrustChannelFactory is being created?

Code:

public string GetToken(string url, string domain, string realm, string username, string password)
{
    string rp = realm;
    string token = "";

    WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory
    (
        new WSHttpBinding(SecurityMode.TransportWithMessageCredential),
        new EndpointAddress(new Uri(url))
    );
        
    trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
    trustChannelFactory.Credentials.Windows.ClientCredential.Domain = domain;
    trustChannelFactory.Credentials.Windows.ClientCredential.UserName = username; // #1; not sure which pair is needed?
    trustChannelFactory.Credentials.Windows.ClientCredential.Password = password;

    trustChannelFactory.Credentials.UserName.Password = password;
    trustChannelFactory.Credentials.UserName.UserName = username;

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

    try
    {
        RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue, KeyTypes.Bearer);
        rst.AppliesTo = new EndpointReference(rp);
        rst.TokenType = SecurityTokenTypes.Saml;

        WSTrustChannel channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
        GenericXmlSecurityToken token = channel.Issue(rst) as GenericXmlSecurityToken; // #2; Exception thrown here
        token = token.TokenXml.OuterXml;
    }
    catch (SecurityNegotiationException e)
    {
        LogError("Authentication Failed", e);
    }
    catch (TimeoutException e)
    {
        LogError("Unable to authenticate", e);
    }
    catch (CommunicationException e)
    {
        LogError("Communication exception", e);
    }
    catch (Exception e)
    {
        LogError("Unknown exception", e);
    }
    return token;
}

Solution

  • We decided to continue to use WIF 3.5 for now and will have an entire rewrite for WIF 4.5 instead of trying to do something that isn't possible.

    There was simply too much change and not enough documentation to "shoehorn" our existing code from WIF 3.4 to WIF 4.5