Cody Hicks
Cody Hicks

Reputation: 420

First Data API Service reference throws The HTTP request is unauthorized with client authentication scheme 'Anonymous'

I am integrating the API for First Data payment gateway service into my project. Up until about 3 weeks ago, the my integration was working. We rebooted the server and now the integration no longer works. When publishing my application onto a development machine, it works but something about our production environment is disagreeing with the service at this point.

Researching into the error message leads me to Service issues with authentication but there are no server credentials to be sent to the service that my application is calling. I think; more or less, this is an issue with IIS but I am having a time trying to figure it out.

My integration is as follows...

Class

public class Merchant
{
    private readonly string _gatewayId;
    private readonly string _password;
    private readonly string _keyId;
    private readonly string _hmac;
    private readonly bool _isDemo;

    // POST URLs
    private const string ProdUrl = "https://api.globalgatewaye4.firstdata.com/transaction/v14";
    private const string TestUrl = "https://api.demo.globalgatewaye4.firstdata.com/transaction/v14";


    public Merchant(string gatewayId, string password, string hmac, string keyId, bool isDemo = true)
    {
        _gatewayId = gatewayId;
        _password = password;
        _hmac = hmac;
        _keyId = keyId;
        _isDemo = isDemo;
    }

    public MerchantResponse Charge(
        string orderId,                // Order ID / Reference Number
        string cardHoldersName,        // Card Holder Name
        string cardNumber,             // Card number
        string amount,                 // Payment amount
        string expirationMonth,        // Card Exp. Month
        string expirationYear,         // Card Exp. Year
        string ccv,                    // CCV code
        string address,                // Address
        string zip)                    // Zip
    {
        var client = new ServiceSoapClient(new BasicHttpBinding(BasicHttpSecurityMode.Transport), new EndpointAddress(_isDemo ? TestUrl : ProdUrl));

        client.ChannelFactory.Endpoint.Behaviors.Add(new HmacHeaderBehaivour(_hmac, _keyId));

        TransactionResult result = client.SendAndCommit(new Transaction
        {
            ExactID = _gatewayId,
            Password = _password,
            Transaction_Type = "00",
            Card_Number = cardNumber,
            CardHoldersName = cardHoldersName,
            DollarAmount = amount,
            Expiry_Date = string.Format("{0:D2}{1}", expirationMonth, expirationYear),
            Customer_Ref = orderId.ToString(),
            //VerificationStr1 = address + "|" + zip + "|" + "US",
            //VerificationStr2 = ccv
        });
        var response = new MerchantResponse
        {
            IsTransactionApproved = result.Transaction_Approved,
            IsError = result.Transaction_Error
        };
        if (!result.Transaction_Approved && !result.Transaction_Error)
        {
            // Format Response String
            response.Message =
            result.Authorization_Num + "|" +                // Authorization Number
            result.Transaction_Tag + "|" +                  // Transaction Tag (Transaction ID)
            result.CardHoldersName + "|" +                  // Cardholder's Name
            result.DollarAmount + "|" +                     // Transaction Amount
            result.Customer_Ref + "|" +                     // Cust. Reference Number
            result.EXact_Message + "|" +                    // Response Message
            result.Bank_Message + "|" +                     // Bank Response Message
            result.Card_Number + "|" +                      // Card Number
            result.CardType + "|" +                         // Card Type
            result.ZipCode                                  // Zip Code
            ;
        }
        if (!result.Transaction_Approved && result.Transaction_Error)
        {
            // Format Response String
            response.Message =
            result.Authorization_Num + "|" +                // Authorization Number
            result.Transaction_Tag + "|" +                  // Transaction Tag (Transaction ID)
            result.CardHoldersName + "|" +                  // Cardholder's Name
            result.DollarAmount + "|" +                     // Transaction Amount
            result.Customer_Ref + "|" +                     // Cust. Reference Number
            result.EXact_Message + "|" +                    // Response Message
            result.Bank_Message + "|" +                     // Bank Response Message
            result.Card_Number + "|" +                      // Card Number
            result.CardType + "|" +                         // Card Type
            result.ZipCode                                  // Zip Code
            ;
        }
        if (result.Transaction_Approved)
        {
            // Format Response String
            response.Message =
            result.Authorization_Num + "|" +                // Authorization Number
            result.Transaction_Tag + "|" +                  // Transaction Tag (Transaction ID)
            result.CardHoldersName + "|" +                  // Cardholder's Name
            result.DollarAmount + "|" +                     // Transaction Amount
            result.Customer_Ref + "|" +                     // Cust. Reference Number
            result.EXact_Message + "|" +                    // Response Message
            result.Bank_Message + "|" +                     // Bank Response Message
            result.Card_Number + "|" +                      // Card Number
            result.CardType + "|" +                      // Card Type
            result.ZipCode                                  // Zip Code
            ;

        }
        return response;
    }

    class HmacHeaderBehaivour : IEndpointBehavior
    {
        private readonly string _hmac;
        private readonly string _keyId;

        public HmacHeaderBehaivour(string hmac, string keyId)
        {
            _hmac = hmac;
            _keyId = keyId;
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new HmacHeaderInspector(_hmac, _keyId));
        }
    }


    class HmacHeaderInspector : IClientMessageInspector
    {
        private readonly string _hmac;
        private readonly string _keyId;

        public HmacHeaderInspector(string hmac, string keyId)
        {
            _hmac = hmac;
            _keyId = keyId;
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
            request = buffer.CreateMessage();
            Message msg = buffer.CreateMessage();
            ASCIIEncoding encoder = new ASCIIEncoding();

            var sb = new StringBuilder();
            var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings
            {
                OmitXmlDeclaration = true
            });
            var writer = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter);
            msg.WriteStartEnvelope(writer);
            msg.WriteStartBody(writer);
            msg.WriteBodyContents(writer);
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
            writer.Flush();

            string body = sb.ToString().Replace(" />", "/>");

            byte[] xmlByte = encoder.GetBytes(body);
            SHA1CryptoServiceProvider sha1Crypto = new SHA1CryptoServiceProvider();
            string hash = BitConverter.ToString(sha1Crypto.ComputeHash(xmlByte)).Replace("-", "");
            string hashedContent = hash.ToLower();

            //assign values to hashing and header variables
            string time = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
            string hashData = "POST\ntext/xml; charset=utf-8\n" + hashedContent + "\n" + time + "\n/transaction/v14";
            //hmac sha1 hash with key + hash_data
            HMAC hmacSha1 = new HMACSHA1(Encoding.UTF8.GetBytes(_hmac)); //key
            byte[] hmacData = hmacSha1.ComputeHash(Encoding.UTF8.GetBytes(hashData)); //data
            //base64 encode on hmac_data
            string base64Hash = Convert.ToBase64String(hmacData);

            HttpRequestMessageProperty httpRequestMessage;
            object httpRequestMessageObject;

            if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
            {
                httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
                httpRequestMessage.Headers["X-GGe4-Content-SHA1"] = hashedContent;
                httpRequestMessage.Headers["X-GGe4-Date"] = time;
                httpRequestMessage.Headers["Authorization"] = "GGE4_API " + _keyId + ":" + base64Hash;
            }
            else
            {
                httpRequestMessage = new HttpRequestMessageProperty();
                httpRequestMessage.Headers["X-GGe4-Content-SHA1"] = hashedContent;
                httpRequestMessage.Headers["X-GGe4-Date"] = time;
                httpRequestMessage.Headers["Authorization"] = "GGE4_API " + _keyId + ":" + base64Hash;
                request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
            }
            return null;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }
    }
}

Client Service Reference Address

https://api.globalgatewaye4.firstdata.com/transaction/v14/wsdl

Configuration for the service reference

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="ServiceSoap">
      <security mode="Transport" />
    </binding>
    <binding name="ServiceSoap1" />
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="https://api.globalgatewaye4.firstdata.com/transaction/v14"
    binding="basicHttpBinding" bindingConfiguration="ServiceSoap"
    contract="FirstDataReference.ServiceSoap" name="ServiceSoap" />
</client>
</system.serviceModel>

The full stack trace

The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was ''.

Server stack trace:

The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was ''.

at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory1 factory) at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory1 factory, WebException responseException, ChannelBinding channelBinding) at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at MyApplication.FirstDataReference.ServiceSoap.SendAndCommit(SendAndCommitRequest request) at MyApplication.FirstDataReference.ServiceSoapClient.MyApplication.FirstDataReference.ServiceSoap.SendAndCommit(SendAndCommitRequest request) at MyApplication.FirstData.Merchant.Charge(String orderId, String cardHoldersName, String cardNumber, String amount, String expirationMonth, String expirationYear, String ccv, String address, String zip) at MyApplication.controls.Confirmation.Step2SubmitButton_Click(Object sender, EventArgs e)

I want to believe there is a problem when my application is attempting to use the service reference vs. the endpoint its self.

Upvotes: 2

Views: 592

Answers (0)

Related Questions