I've been bagging my head for over a week with this. I've requested help from several Microsoft friends, but still no luck.
We are developing an online conference registration portal which requires online payments.
Unfortunately our Customer does not accept any other payment method other than a local (Chilean) payment Gateway (Transbank's WebPay Plus).
We tried to get them onboard with PayPal and several other's, but they would not accept for several reasons. So...we are stuck with WebPay Plus (WPP).
WPP accepts a SOAP request to initiate the transaction. But the request has to be digitally signed.
We have created the web reference and we are able to reach the server end, but we have not figured out how to digitally sign the request.
WPP requires us to créate a certificate with OpenSSL, which we did (oneclick.crt).
This is our code:
System.ServiceModel.Channels.Binding _binding = new BasicHttpBinding();
EndpointAddress _endpointAddress = new EndpointAddress("http://201.238.207.131:7003/WSWebpayTransaction/cxf/WSWebpayService");
ServiceReference3.WSWebpayServiceClient ws3 = new ServiceReference3.WSWebpayServiceClient(_binding, _endpointAddress);
ws3.Endpoint.Behaviors.Add(new CustomEndpointBehavior());
var _certificatePath = "~/oneclick.crt".ToAbsolutePath();
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(_certificatePath);
apiTransbank.ClientCertificates.Add(cert);
ws3.ClientCredentials.ClientCertificate.Certificate = cert;
var tI = new ServiceReference3.wsInitTransactionInput();
tI.wSTransactionType = ServiceReference3.wsTransactionType.TR_NORMAL_WS;
tI.sessionId = "xmsbs_calculate";
tI.returnURL = "http://www.test.cl";
tI.finalURL = "http://www.test.cl/final";
tI.transactionDetails = new[] {
new ServiceReference3.wsTransactionDetail()
{
amount = 1,
commerceCode = "XXXXXXXXXX",
buyOrder = "1000"
}
};
var _output = ws3.initTransaction(tI);
This request gives me the following response: "An error was discovered processing the header".
I have talked to WPP Support and the only thing they are wiling to say is that the request is not digitally signed.
So now we need to digitally sign this request and I cannot find anywhere how to do this (at least in a way I can understand, with clear code examples).
Related
I am new to Web Services in general, and we are using .Net Framework 4.5.2, anyway I am trying to consume a web service that requires a certificate and a password.
I added the certificate gained from the providers in the project properties --> Resources --> file --> add, I also tried to use the SetCertificate() function but It seems to be a little complicated for me so I stick with loading the certificate from the properties as mentioned, however I already set all the binding setting as wanted, but somehow I am missing something, Here is my code:
string clientUrl = "some wsdl URL goes here";
BasicHttpsBinding binding = new BasicHttpsBinding
{
MaxReceivedMessageSize = Int32.MaxValue,
MaxBufferSize = Int32.MaxValue,
SendTimeout = new TimeSpan(0, 15, 0),
MessageEncoding = WSMessageEncoding.Text,
Security = {
Mode = BasicHttpsSecurityMode.Transport,
Transport = {
ClientCredentialType = HttpClientCredentialType.Certificate
}
}
};
ClientsClient testClient = new ClientsClient(binding, new EndpointAddress(new Uri(clientUrl)));
testClient.ClientCredentials.ClientCertificate.Certificate = LoadCertification();
private X509Certificate2 LoadCertification()
{
byte[] bytes = Properties.Resources.publicCert;
return new X509Certificate2(bytes, "password");
}
Note 1: The certificate extenstion is '.p12', It may be a list of certifications, if that is the case!, is it possible to pass them all?.
In the code I presented I am always getting The exception:
System.ServiceModel.ProtocolException: The 'Security' header from the namespace 'Some Http url goes here' not was understood by the recipient of the message. The message was not processed. The error usually indicates that the sender of the message has enabled a communication protocol that cannot be processed by the recipient. Verify that the client binding configuration is consistent with the service binding.
I tried to test the web service with "SOAP UI" and it worked, which made me sure that I am doing something wrong with the code, So I appreaciate any possible help that explains how to associate the certifcate in the code in the right way!.
EDIT:
in the .p12 file there are 3 certifications, which I tried to add also like this:
X509Certificate2Collection coll = LoadCertification();
int count = 0;
foreach (X509Certificate2 cert in coll)
{
testClient.ClientCredentials.ClientCertificate.Certificate = cert;
count++;// this variable is just to check the number of certificates
}
And I modified the loadCertification() method to look like this:
private X509Certificate2Collection LoadCertification()
{ string certPath = "C:/Users/ISA/Desktop/Progetti/Certificato e password/name.p12";
X509Certificate2Collection coll = new X509Certificate2Collection();
coll.Import(certPath , "password", X509KeyStorageFlags.DefaultKeySet);
return coll;
}
I am trying to connect from a client to the service. The service is configurated to use a self signed Ssl certificate and I am trying to configurate the client with the client certificate. I am using this code:
string cacert = System.IO.File.ReadAllText("certificados/ca.crt");
string cert = System.IO.File.ReadAllText("certificados/client.crt");
string key = System.IO.File.ReadAllText("certificados/client.key");
KeyCertificatePair keypair = new KeyCertificatePair(cert, key);
SslCredentials sslCreds = new SslCredentials(cacert, keypair);
var channel = GrpcChannel.ForAddress("https://x.x.x.x:5001", new GrpcChannelOptions { Credentials = sslCreds });
var client = new Gestor.GestorClient(channel);
But I am getting the following error: using SslCredentials with non-null arguments is not supported by GrpcChannel.
I don't understand very good the message error. SslCredentials is ChannelCredentials? type, and SslCreds is Grpc.Core.SslCredentials. It can be compiled, so the type I guess it is correct.
What I would like to know it is how I can configure the client to use the self signed certificate that I have created.
Thanks.
The SslCredentials support in only available grpc-dotnet is to provide some level of compatibility with Grpc.Core in the most common use case, it doesn't expose all the functionality though. In grpc-dotnet, only SslCredentials() (parameterless which uses the default roots) is supported. If you want to provide your self-signed creds, you can certainly do that, you'll need to use a different API for configuring GrpcChannel:
See example here (creating a GrpcChannel with custom credentials).
https://github.com/grpc/grpc-dotnet/blob/dd72d6a38ab2984fd224aa8ed53686dc0153b9da/testassets/InteropTestsClient/InteropClient.cs#L170
I spend a fair bit of time googling around for solutions to this problem, and didn't find a concise answer. Here is ultimately how I was able to configure a dotnet client to use mutual SSL authentication:
MyService.MyServiceClient GetClient(){
var httpClientHandler = new HttpClientHandler();
// Validate the server certificate with the root CA
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => {
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(new X509Certificate2("ca.crt"));
return chain.Build(cert);
};
// Pass the client certificate so the server can authenticate the client
var clientCert = X509Certificate2.CreateFromPemFile("client.crt", "client.key");
httpClientHandler.ClientCertificates.Add(clientCert);
// Create a GRPC Channel
var httpClient = new HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress("https://localhost:8080", new GrpcChannelOptions{
HttpClient = httpClient,
});
return new MyService.MyServiceClient(channel);
}
I m developing an App which has to write on google spreadsheet.
My application used to work fine until Google changed is Auth API two months ago.
Following the link with the new process.
Google.GData.Client.GDataRequestException - Authentication suddenly fails in old code
I have a google account me#company.com which is managed by my boss account company#gmail.com.
I want to write in a spreadsheet named "Bank Details" shared to me from my boss account.(the onwer is "mycompany")
I generated a key.p12 from my account and it works fine, I can write.
Now the strange things is when i create a spreadsheet by myself (the owner is "me", my app doesn t find the file and return an error message.
I generated a key.p12 from my boss account and it still doesn't find the spreadsheet created by my boss, so from his point of view the owner is "me".
In conclusion:
I find the spreadsheet shared by my boss with my key and I can write in it.
I don't find the file created by me with my key.
My app doesn't find the file created by my boss with his key.
Here my code but i don't think the problem comes from here.
string keyFilePath; // found in developer console
string serviceAccountEmail;
if (test == true)
{
keyFilePath = #"C:\keyTEST.p12";
serviceAccountEmail = "me#developer.gserviceaccount.com";// found in developer console
}
else
{
keyFilePath = #"C:\key.p12";
serviceAccountEmail ="company#developer.gserviceaccount.com";
}
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) //create credential using certificate
{
Scopes = new[] { "https://spreadsheets.google.com/feeds/" } //this scopr is for spreadsheets, check google scope FAQ for others
}.FromCertificate(certificate));
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(); //request token
var requestFactory = new GDataRequestFactory("Some Name");
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
SpreadsheetsService myService = new SpreadsheetsService("Bank Details"); //create your old service
myService.RequestFactory = requestFactory; //add new request factory to your old service
myService.setUserCredentials(email, password);
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = myService.Query(query);
SpreadsheetEntry fileEntry = feed.Entries.Cast<SpreadsheetEntry>().FirstOrDefault(entry => entry.Title.Text == spreadSheetName);
SpreadsheetEntry spreadsheet = (SpreadsheetEntry)fileEntry;
if (feed.Entries.Count == 0)
{
Console.WriteLine("None");
}
...
You need share in your sheet the e-mail "company#developer.gserviceaccount.com" or "me#developer.gserviceaccount.com".
I'm trying to access our MailChimp account via the new 3.0 REST API. I've done the following:
using(var http = new HttpClient())
{
var creds = Convert.ToBase64String(Encoding.ASCII.GetBytes("username:mailchimpapikey-us1"));
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", creds);
string content = await http.GetStringAsync(#"https://us1.api.mailchimp.com/3.0/lists");
Console.WriteLine(content);
}
However, when I run this code, I get a 401 error with the following json details:
{"type":"http://kb.mailchimp.com/api/error-docs/401-api-key-invalid","title":"API Key Invalid","status":401,"detail":"Your API key may be invalid, or you've attempted to access the wrong datacenter.","instance":"a9fe4028-519e-41d6-9f77-d2caee4d4683"}
The datacenter I'm using in my URI (us1 in this example) matches the dc on my API key. My API key works if I use the MailChimp SDK so I know my key isn't invalid. Also, using Fiddler, I can see that the MailChimp SDK is calling the same dc as I'm doing in my URI.
Any Ideas as to why I am having trouble Authenticating?
EDIT
As noted in the question, I'm asking specifically about accessing the new 3.0 REST API. I'm trying to do this directly as opposed to using a third party wrapper.
The new API is composed of http calls so it should be pretty straight forward. I'm simply having trouble with the authentication piece.
So I was able to finally chat with a super tech support person at MailChimp.
The MailChimp docs state the following
The easiest way to authenticate is using HTTP Basic Auth. Enter any string
as the username and supply your API Key as the password.
Your HTTP library should have built-in support for basic authorization.
Their documentation is a bit misleading. Typically the Auth header for Basic Auth would look like what I was sending:
Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
where the row of x would represent the base64 encoded username:password.
However, talking with the support tech, the actual implementation they use is:
Authorization: username keyid
No base64 encoding, no Basic keyword. Username doesn't even have to be your username.
So, here is the working code:
using(var http = new HttpClient())
{
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", mailchimpapikey-us1);
string content = await http.GetStringAsync(#"https://us1.api.mailchimp.com/3.0/lists");
Console.WriteLine(content);
}
EDIT
Note the comments. TooMuchPete was correct in that the normal HTTP Basic Auth headers do work. Apparently I was hitting some old code or something on the MailChimp side.
I'm leaving the post as a reference for anyone who is trying to call the new 3.0 API.
I wrote an article on a simple way up adding subscribers to a list using:
Dim mailchimp As New ZmailChimp
Dim ListId$ = "9b2e63f0b9" 'List Sage' List
Dim email$ = "samsmith20#anymail.com" '"sam19#postcodelite.com"
Dim fieldListOnAdd = "FNAME,Sam,LNAME,Smith,MTYPE,User,MID,631637"
Dim fieldListOnUpdate = "FNAME,Sam,LNAME,Smith,MID,631637" 'Don't change MTYPE
'Put on 'Sage One' and 'Sage 50' group
Dim groupList = "407da9f47d,05086211ba"
With mailchimp
.API$ = "46cMailChimpAPIKeyd1de-us14" 'MailChimp API key
.dataCenter$ = "us14" 'Last 4 letters of API key
.password$ = "Password!"
MsgBox(.addSubscriber(ListId$, email, fieldListOnAdd, fieldListOnUpdate, groupList))
End With
mailchimp = Nothing
see:http://www.codeproject.com/Tips/1140339/Mail-Chimp-Add-Update-e-mail-to-List-and-Subscribe
this may save someone some time
Mailchimp Ecommerce
var mcorder = new Standup.Ecomm.MailChimpManager(ConfigurationManager.AppSettings["MailChimpApiKey"]);
var orders = new MailOrder();
orders.CampaignId = ConfigurationManager.AppSettings["MailChimpCampaignId"];
orders.EmailId = ConfigurationManager.AppSettings["MailChimpEmailId"];
orders.Id = orderNumber;
orders.StoreId = "abcde";
orders.StoreName = "E-Commerce Store";
orders.Total = Convert.ToDouble(orderTotal);
orders.Tax = Convert.ToDouble(tax);
orders.Items = new List<MailOrderItem>();
foreach (var orderItem in orderItemList)
{
var item = new MailOrderItem();
item.ProductId = orderItem.OrderNumber;
item.ProductName = orderItem.Title;
item.SKU = orderItem.Sku;
item.CategoryId = 0;
item.CategoryName = " ";
item.Quantity = orderItem.Quantity;
item.Cost = Convert.ToDouble(orderItem.ProductCost);
orders.Items.Add(item);
}
mcorder.AddOrder(orders);
I developed a web app using ASP .NET MVC3.
I'm trying to get book info using Amazon AWS based on ASIN.
This is the code snippet that should to that:
AsinRequest req = new AsinRequest();
req.asin = "0596158106";
req.type = "lite";
req.tag = "webservices-20";
req.devtag = "XXXXXXXXXXXX";
req.mode = "books";
req.locale = "US";
req.offer = "1";
req.offerpage = "1";
AmazonSearchPortClient amazonWS = new AmazonSearchPortClient();
ProductInfo prod = amazonWS.AsinSearchRequest(req);
Debug.WriteLine(prod.Details);
Every time I try to run it I get a HTTP 417 Expectation failed saying that it's a ProtocolException.
Instead of the X's I used the Access Key ID found in the Security Credentials section. I also tried using the Secret Access Key but it didn't make any difference.
I used this tutorial as a starting point:
http://channel9.msdn.com/coding4fun/articles/Using-the-Amazon-Web-Service
Does anyone know what could be causing it ?