Reputation: 420
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, HttpChannelFactory
1 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