Consume WSDL that requires action level authorization in C# - c#

I'm attempting to consume a 3rd party WSDL. I have added it as a service reference. I initalize the client and query paramaters like this:
var ltRequest = new SearchEmailAddressStatus
{
EmailAddress = emailAddressList.ToArray()
};
var ltClient = new CommunicationPreferenceServiceClient
{
ClientCredentials =
{
UserName =
{
UserName = ltProperties.CompanyCredential.UserName,
Password = ltProperties.CompanyCredential.Password
}
}
};
var ltResponse = ltClient.searchEmailAddressStatusWS(ltRequest);
After watching the packets in Fiddler, I've noticed the Auth header is never sent to the server. Is there any way to manually insert an authorization header in my request?

Okay, after a lot of digging I found the answer. After declaring the client, I used the following code:
using (var scope = new OperationContextScope(ltClient.InnerChannel))
{
var reqProperty = new HttpRequestMessageProperty();
reqProperty.Headers[HttpRequestHeader.Authorization] = "Basic "
+ Convert.ToBase64String(Encoding.ASCII.GetBytes(
ltClient.ClientCredentials.UserName.UserName + ":" +
ltClient.ClientCredentials.UserName.Password));
OperationContext.Current
.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = reqProperty;
var ltResponse = ltClient.searchEmailAddressStatusWS(ltRequest);
}
I believe this is the least-dirty means of getting a customized header inside wsdl request. If someone has a better method, I'd love to hear it.

Related

DocuSign ListRecipients() not working, but other calls OK

I am using the Docusign eSign API for an integration. My integration key works fine with building and sending envelopes, and with checking envelope status (using GetEnvelope()). But ListRecipients() doesn't work. I have been following the documentation from here: https://developers.docusign.com/docs/esign-rest-api/how-to/get-envelope-recipients/.
My recipient-checking code is:
apiClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + authToken.access_token.ToString()); // I am suspicious of this line
var envelopesApi = new EnvelopesApi(apiClient);
foreach (var envelope in envelopes)
{
List<SignerModel> listSigners = new List<SignerModel>();
Recipients results = envelopesApi.ListRecipients(_apiAccountId, envelope.envelopeId.ToString());
// Do something with it...
}
When I run this with the suspicious line in place (un-commented) I get this error message at that line:
GetSigners error: Object reference not set to an instance of an object.
When I comment it out I get the same error message at the ListRecipients() call.
This is how I am getting my access token:
List<string> docusignScopes = new List<string> { "impersonation", "signature" };
apiClient = new ApiClient(_restBasePath);
authToken = apiClient.RequestJWTUserToken(
_clientId,
_impersonatedUserId,
_authServer,
privateKeyBytes, 1, docusignScopes);
Why is the listRecipients call not working?
I tested this code and it works just fine. Make sure to put your envelopeID in there. Try this basic code and let me know:
var apiClient = new ApiClient(basePath);
apiClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
var rec = envelopesApi.ListRecipients(accountId, "4f925c10-xxxxxx-xxx-xxxx-xxxxxx");

CreateEnvelope() throws exception. No message

I am trying to create and send an envelope on the demo environment using the docusign C# API. I am using JWT as my OAuth2 flow. I am able to properly grab the access code needed to authorized my embedded signing.
The function CreateEnvelope fails and throws an exception. The exception shows no information other than that the function failed.
Image of Exception
Has anyone encountered a similar situation before? I have provided a snippet of the code below. Is there anything clearly wrong with how I may be trying to create the envelope?
public static void DocusignFormatter()
{
EnvelopeDefinition envDef = new EnvelopeDefinition();
Document doc = new Document();
doc.DocumentBase64 = System.Convert.ToBase64String(pdfFileInfo.fileBytes);
doc.Name = pdfFileInfo.DocName;
doc.DocumentId = "1";
envDef.Documents = new List<Document>();
envDef.Documents.Add(doc);
envDef.Recipients = new Recipients();
envDef.Recipients.Signers = new List<Signer>();
for (int i = 0; i < signatureFields.Count; i++)
{
Signer signer = new Signer();
signer.Email = docRegistrant.Email;
signer.Name = docApplicants[i].FirstName + " " + docApplicants[i].LastName;
signer.RecipientId = $"{i+1}";
signer.Tabs = new Tabs();
signer.Tabs.SignHereTabs = new List<SignHere>();
List<MyPdfSignatureField> fields;
signatureFields.TryGetValue(i, out fields);
foreach (MyPdfSignatureField field in fields)
{
SignHere signHere = new SignHere();
signHere.DocumentId = "1";
signHere.PageNumber = field.PageNum.ToString();
signHere.RecipientId = i.ToString();
signHere.XPosition = field.XLocation.ToString();
signHere.YPosition = field.YLocation.ToString();
signer.Tabs.SignHereTabs.Add(signHere);
}
envDef.Recipients.Signers.Add(signer);
}
envDef.Status = "created";
ApiClient apiClient = new ApiClient(DocusignHelpers.OAuthBasePath);
Configuration cfi = new Configuration(apiClient);
cfi.AddDefaultHeader("Authorization", "Bearer " + DocusignHelpers.AccessToken);
cfi.AccessToken = DocusignHelpers.AccessToken;
cfi.Password = DocusignHelpers.Password;
EnvelopesApi envelopesApi = new EnvelopesApi(cfi);
EnvelopeSummary envelopeSummary = envelopesApi.CreateEnvelope(DocusignHelpers.AccountId, envDef);
Caught Exception values
you are missing this line:
envDef.EmailSubject = "Test, please sign.";
But that's not the reason for the exception, since you created it as "created" (draft) mode, but it would be the issue once you try to send it.
You may want to confirm the values of all your recipients and ensure you're not sending something that's not an email (for example) in an email field etc.
I solved this friends.
My api url was incorrect.
My key confusion was that the auth endpoints have a separate base url than the rest of the RESTful API.
Authorization url for the demo was: https://account-d.docusign.com
The API client object actually has static fields that contain the urls for the different platforms demo, prod, staging.
I ended up using
ApiClient.Demo_REST_BasePath = "https://demo.docusign.net/restapi"
Thank you all for the replies and help

How to create CallCredentials from SslCredentials and token string

I am porting a gRPC client from python to c#. Both the python client and the c# client are using the gRPC Framework from grpc.io.
The python client uses the following code to open a secure, non-authenticated channel, which it then uses to procure a token string, which it then uses to create call credentials with the grpc.composite_channel_credentials() function:
channel = grpc.secure_channel(url_server_address, ssl_creds)
stub = gateway.GatewayStub(channel)
# Acquire access token via password authentication
pw_cmd = gateway.PasswordAuthenticateCmd(account_name=url.username, password=url.password)
auth_rsp = stub.PasswordAuthenticate(pw_cmd)
# Open a secure, authenticated channel
auth_creds = grpc.access_token_call_credentials(auth_rsp.access_token)
composite_creds = grpc.composite_channel_credentials(ssl_creds, auth_creds)
channel = grpc.secure_channel(url_server_address, composite_creds)
stub = gateway.GatewayStub(channel)
In c#, I have been able to compile the protocol buffer definitions, and connect with the generated client to successfully acquire the access token:
SslCredentials secureChannel = new SslCredentials(File.ReadAllText(SSLCertificatePath));
Channel channel = new Channel(ServerURL, PortNum, secureChannel);
var client = new GrpcClient(new Grpc.Gateway.GatewayClient(channel));
var response = client.client.PasswordAuthenticate(new PasswordAuthenticateCmd() { AccountName = UserName, Password = UserPassword });
Console.WriteLine(response.AccessToken);
From here, however, I can't find the c# analog to the grpc.composite_channel_credentials() function to take the SslCredentials and the access token string to create combined credentials.
None of the examples here https://grpc.io/docs/guides/auth.html here use a token string, and I haven't been able to find any other examples out there.
What you're looking for is:
https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Core/CallCredentials.cs#L49 and https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Core/ChannelCredentials.cs#L67.
Feel free to also look at:
https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs#L58
I solved my problem using CallCredentials.FromInterceptor().
The grpc.access_token_call_credentials() python call adds an authorization entry to the metadata, and sets its value to "Bearer " + AccessToken, so I just had to do the same:
SslCredentials secureCredentials = new SslCredentials(File.ReadAllText(SSLCertificatePath));
Channel secureChannel = new Channel(ServerURL, PortNum, secureCredentials);
var client = new GrpcClient(new Grpc.Gateway.GatewayClient(secureChannel));
var response = client.client.PasswordAuthenticate(new PasswordAuthenticateCmd() { AccountName = UserName, Password = UserPassword });
var accessTokenCredentials = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) =>
{
metadata.Add("authorization", "Bearer " + passwordResponse.AccessToken);
return TaskUtils.CompletedTask;
}));
var authenticatedCredentials = ChannelCredentials.Create(secureCredentials, accessTokenCredentials);
Channel authenticatedChannel = new Channel(hostURL, hostPort, authenticatedCredentials);
As Jan pointed out in his answer, there is a function in the Grpc.Auth namespace that does the same thing as the function that I wrote: https://github.com/grpc/grpc/blob/c5311260fd923079637f5d43bd410ba6de740443/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs#L58

Overriding the default User-Agent header for Exchange request

I am sending a request to EWS as below:
var service = new ExchangeService(exchangeVersion)
{
KeepAlive = true,
Url = new Uri("some autodiscovery url"),
Credentials = new NetworkCredential(username, password),
UserAgent = "myClient"
};
var subscription = service.SubscribeToPushNotifications(
new[] { inboxFolderFoldeID },
new Uri("some post back url"),
15,
null,
EventType.NewMail,
EventType.Created,
EventType.Deleted,
EventType.Modified,
EventType.Moved,
EventType.Copied);
But, it would result into a request having the User-Agent header as myClient (ExchangeServicesClient/15.00.0913.015) where the rest of the string is coming from the EWS library where it is using this default value. Is there a way to remove the default part of the header and just have it as myClient?
Edit: I can see that EWS library seems to be simply prefixing the value passed in the request: https://github.com/OfficeDev/ews-managed-api/blob/master/Core/ExchangeServiceBase.cs
You will need to recompile the library from GitHub as the scope of the existing variables won't allow you to change them any other way. eg all you need to do is modify UserAgent
public string UserAgent
{
get { return this.userAgent; }
set { this.userAgent = value + " (" + ExchangeService.defaultUserAgent + ")"; }
}
and get rid of the prefix then when you set the property on the ExchangeService class it will only be your custom value.

PayPal Express Checkout SOAP API: Refunds

I use the PayPal Express Checkout SOAP service. For example here's a trimmed down version of the code to redirect the user to PayPal Sandbox when checking out:
var client = new PayPalAPIAAInterfaceClient();
var credentials = new CustomSecurityHeaderType() {
Credentials = new UserIdPasswordType() { ... }
};
var paymentDetails = new PaymentDetailsType() {
OrderTotal = new BasicAmountType() {
Value = string.Format("{0:0.00}", 100m)
}
};
var request = new SetExpressCheckoutReq() {
SetExpressCheckoutRequest = new SetExpressCheckoutRequestType() {
SetExpressCheckoutRequestDetails = new SetExpressCheckoutRequestDetailsType() {
PaymentDetails = new PaymentDetailsType[] { paymentDetails },
CancelURL = "http://www.mysite.com" + Url.Action("Cancelled", "PayPalCheckout"),
ReturnURL = "http://www.mysite.com" + Url.Action("Index", "PayPalCheckout")
},
Version = "60.0"
}
};
var response = client.SetExpressCheckout(ref credentials, request);
return Redirect(string.Format("{0}?cmd=_express-checkout&token={1}", "https://www.sandbox.paypal.com/cgi-bin/webscr", response.Token));
I then handle the data when the user is returned to the ReturnUrl. This was taken from some code I found on another website.
I now need to add a refund facility to my site. I was wondering if anyone else has done this? I've tried searching online but can't seem to find anything that helps. I also tried doing it myself but the API isn't very intuitive.
I'd appreciate the help. Thanks
It would just need to be a RefundTransaction API call that you would need to execute. Are you trying to have your return page issue a refund based on a condition, or are you trying to create a GUI type of interface to allow someone to issue a refund for a transaction? Have you looked at the code samples for this within the SDK's that PayPal offers? You should be able to use this code.

Categories