How to fix "attribute xmlns:wsse invalid" error where calling SOAP web service in NodeJS using node-soap - node.js

I am trying to call a web service that requires authetication via X509 certificate. I'm using Node.js and node-soap module, getting successfully the WSDL.
But when I try to build the SOAP envelope with the Signature tag inside, I get the following error from the server:
The value of the attribute "prefix="xmlns",localpart="wsse",rawname="xmlns:wsse"" is invalid. Prefixed namespace bindings may not be empty.
I've tried to modify the existingPrefixes that are passed to the underlying library (xml-crypto).
This is my code:
var privateKey = fs.readFileSync(process.env.KEYFILE);
var publicKey = fs.readFileSync(process.env.CERTFILE);
var password = ''; // optional password
var options = {
mustUnderstand: 1,
signerOptions: {
existingPrefixes: {
'wsse': "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
}
},
};
var wsSecurity = new soap.WSSecurityCert(privateKey, publicKey, password, options);
const endpoint = process.env.ENDPOINT;
soap.createClientAsync(endpoint).then(client => {
client.setSecurity(wsSecurity);
return client.wiOperationAsync({ ... })
})
However, the error persists and I get a SOAP request body with something like this:
<KeyInfo>
<wsse:SecurityTokenReference
xmlns:wsse="">
<wsse:Reference URI="#x509-1639ca80191641b9bd804497cfcef0b5" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</KeyInfo>
Any idea to avoid that empty mlns:wsse attribute?

Related

Mobile app performing an HTTP Post to Azure Function using Bearer Token and Function Key returns Unauthorized

I'm using a mobile app and am receiving an Unauthorized response when attempting to post to an Azure Function and providing a function key.
Error:
StatusCode: 401, ReasonPhrase: 'Unauthorized'
Code:
let postToAsync (baseAddress:string) (resource:string) (payload:Object) =
async {
let tokenSource = new CancellationTokenSource(TimeSpan(0,0,30));
let token = tokenSource.Token;
try
let tokens = resource.Split("?code=")
let functionKey = tokens.[1]
use client = httpClient baseAddress
client.DefaultRequestHeaders.Add("x-functions-key", functionKey)
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"))
let json = JsonConvert.SerializeObject(payload)
let content = new StringContent(json, Encoding.UTF8, "application/json")
let! response = client.PostAsync(resource.Replace($"?code={functionKey}",""), content, token) |> Async.AwaitTask
Debug.WriteLine $"\n\n{baseAddress}{resource}\nSuccess: {response.IsSuccessStatusCode}\n\n"
return response
with ex -> ...
} |> Async.StartAsTask
Note:
My Azure Function's AuthorizationLevel is set to Function.
I can call the function successfully when I publish it manually from Visual Studio.
However, when I deploy the function using Pulumi, I receive an Unauthorized response. I believe this is because Pulumi constrains me to add access policies for each Function App.
Versioning:
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
oauth2/v2.0:
I think the following link provides a clue to why I'm observing the issue. However, I still don't know how to resolve it.
Connectivity
I launched Log Stream and observed that the URL is correct:
Access Control:
Please note that the difference between the Function App that I created without using Pulumi, which lets me post successfully, versus the Function App that was generated using Pulumi, is an Access Policy per Function App with Pulumi.
public static class AccessPolicies
{
public static void Build(string policyName, string functionName, Dictionary<string, CustomResource> registry)
{
var resourceGroup = registry[nameof(ResourceGroup)] as ResourceGroup;
var keyVault = registry[nameof(KeyVault)] as KeyVault;
var functionApp = registry[functionName] as FunctionApp;
var result = new AccessPolicy(policyName, new AccessPolicyArgs {
KeyVaultId = keyVault.Id,
TenantId = TenantId.Value,
ObjectId = functionApp.Identity.Apply(v => v.PrincipalId ?? "11111111-1111-1111-1111-111111111111"),
KeyPermissions = new[] { "Get", },
SecretPermissions = new[] { "Get", },
});
registry.Add($"{policyName}-{functionName}", result);
}
}
}
I tried to reproduce the same in my environment via Postman and got below results:
I have one function app with http function named srifunction like below:
I generated one bearer token with same scope as you like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://management.azure.com/.default
Response:
When I used the above token to call function, I got 401 Unauthorized error same as you like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <token>
If you pass function key in token value, you will still get 401 Unauthorized error like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <function key>
To call function using function key, you need to include key value
in x-functions-key header instead of Bearer token.
When I included the above header, I am able to call the function successfully like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
x-functions-key: <function key>

core.js:478 Uncaught Error: Malformed UTF-8 Data When Decrypting Url Query Param in Angular

I have a crypto encrypt and decrypt service below and I use it throughout my application to encrypt and decrypt localstorage items. While it works perfectly fine for the localstorage items, when I try to decrypt an encrypted object sent through queryparams, I get the following error:
core.js:478 Uncaught Error: Malformed UTF-8 data
my encrypt/decrypt service is:
export class AESEncryptDecryptService {
secretKey = 'My secret string';
constructor() { }
encrypt(value? : string) : string{
if(!isNil(value)) {
return CryptoJS.AES.encrypt(value, this.secretKey.trim()).toString();
}
}
decrypt(textToDecrypt?){
if(!isNil(textToDecrypt)) {
return CryptoJS.AES.decrypt(textToDecrypt, this.secretKey.trim()).toString(CryptoJS.enc.Utf8);
}
}
}
How I encrypt the object before I sent it:
const user= new User();
this.qrUrl = `${environment.someurl}` +'currentUser=' +this._AESEncryptDecryptService.encrypt(JSON.stringify(user).toString()).toString();
How I decrypt the object:
const url_string = window.location.href;
const url = new URL(url_string);
if(url.searchParams.get('user')) {
this.qrDevice = JSON.parse(this._AESEncryptDecryptService.decrypt(url.searchParams.get('user')));
}
I tried it without the string and by debugging. The same code works fine for other uses but gives this error on url query decrypt.
One thing I noticed is that the query string is replacing the + in the string with a space. How can I fix this and preserve the + sign? the expected and actual of the encrypted objects are posted below.
Expected after object parse from url:
U2FsdGVkX1+8y4FZ0cDq5ikapUndRA+tE5BAVqYPH9NnhBWeea1asYo5zCU80s/6FWKnFU8FghXv7JxPWwnPpJtCR+eXIGpiGBWq4gpq00PoeIuU2jPsDeifSu8aDrFr+D8abcdkIil5WmsHiND5TwVfWHhaBDSSlYMSXbiUXx9DQgRipEAtXXgMEO/r7G5wpuJ9ekEzUfkgXIO3eM/tP6dMu2iWZwbXTDvBZl93J8XZ259YRtIkRXgolSGS2t9yvQOn9I7fobRI1NSCIAftQtGdj/k9pu4B9reicnw9wiNR4dmp8+cpI/3TQSevhwp
Actual after object parse from url:
U2FsdGVkX1 8y4FZ0cDq5ikapUndRA tE5BAVqYPH9NnhBWeea1asYo5zCU80s/6FWKnFU8FghXv7JxPWwnPpJtCR eXIGpiGBWq4gpq00PoeIuU2jPsDeifSu8aDrFr D8abcdkIil5WmsHiND5TwVfWHhaBDSSlYMSXbiUXx9DQgRipEAtXXgMEO/r7G5wpuJ9ekEzUfkgXIO3eM/tP6dMu2iWZwbXTDvBZl93J8XZ259YRtIkRXgolSGS2t9yvQOn9I7fobRI1NSCIAftQtGdj/k9pu4B9reicnw9wiNR4dmp8 cpI/3TQSevhwp
Issue was resolved by changing the qrurl to the following:
this.qrUrl = `${environment.qrOrderURL}user=`+encodeURIComponent(this._AESEncryptDecryptService.encrypt(JSON.stringify(user)));

DocuSign.eSign.Client.ApiException {"error":"consent_required"}" / Response Type Not Supported when attempting to grant consent

I tried to receive a token with the code below. Unfortunatelly I get the error:
DocuSign.eSign.Client.ApiException
HResult=0x80131500
Nachricht = Error while requesting server, received a non successful HTTP code with response Body: {"error":"consent_required"}
I tried with set TLS 12 and without. We run it in dev mode with base path https://demo.docusign.net/restapi
and oAuthBasePath =account-d.docusign.com
I tried also to set the consens manually with the URL below. But I receive the error in (Login Window) invalid Authorization: RequestType is not supported.
https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=a5ed47d5-xxxx-xxxx-8a19-756da64391de&redirect_uri=https://www.docusign.com
Is the something wrong with my account setting?
byte[] privateKey=DSHelper.ReadFileContent(DSHelper.PrepareFullPrivateKeyFilePath(privateKeyFilename));
var scopes = new List<string>
{
"signature",
"impersonation",
};
var basePath = ApiClient.Production_REST_BasePath;
var oAuthBasePath = OAuth.Production_OAuth_BasePath;
if (!production)
{
basePath = ApiClient.Demo_REST_BasePath;
oAuthBasePath = OAuth.Demo_OAuth_BasePath;
}
var _apiClient = new ApiClient(basePath);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var authToken = _apiClient.RequestJWTUserToken(
clientId,
ImpersonatedUserId,
oAuthBasePath,
privateKey,
1,
scopes);
I found the solution. instead of reponse_type= code I have to use token
What response_type is supported for an integration key depends on how the key is configured. In the Authentication section of the key's configuration panel, Auth Code Grant allows the response type of code, while Implicit Grant allows the response type of token.
DocuSign's authentication docs assume you have "Auth Code Grant" selected, but either is technically acceptable to allow JWT consent.

How to configure client for access with authsecret?

I'm using the client and I need to call a service using authsecret parameter.
If I ad this param to the base url it give me a serialization error.
String baseUrl = AppConfig.GetAppApiUrl();
var client = new JsonServiceClient(baseUrl.AddQueryParam("authsecret","secretz123!"));
var c = client.Send(new ComuneRequest { Id = "A001" });
Using Fiddler I discovered that the request that the client generate is incorrect:
POST
http://192.168.0.63:820/?authsecret=secretz123%21/json/reply/ComuneRequest
So, what I have to do to make the client create a request in a correct format?
It needs to be sent as a Request Parameter (i.e. QueryString or FormData) which you can do using HTTP Utils with:
var url = baseUrl.CombineWith(requestDto.ToUrl()).AddQueryParam("authsecret", secret);
var res = url.GetJsonFromUrl().FromJson<MyResponse>();
Otherwise since AuthSecret is not a property on your Request DTO you wont be able to send it as a Request Parameter in the Request Body, but you should be able to send the param in the Request Headers with:
var client = new JsonServiceClient(baseUrl) {
RequestFilter = req => req.Headers[HttpHeaders.XParamOverridePrefix+"authsecret"] = secret
};

Post Go Live issue with Docusign using node.js

Here is my issue:
We integrated docusign in our application, server side with nodejs using this tutorial https://github.com/docusign/docusign-node-client ("OAuth JSON Web Token (JWT) Grant" section)
We have done the "Go Live Process": our application is registered in our production account
We have replaced the test config to the production config.
When we try to create an envelope, we get the following error:
PARTNER_AUTHENTICATION_FAILED: The specified Integrator Key was not found or is disabled. Invalid account specified for user
What am I doing wrong ?
async function docusignInit() {
var options;
var env = [40077,50077].indexOf(config.main.port) != -1 ? 'test' :'prod';
if (env == "test") {
options = {
basePath: restApi.BasePath.DEMO,
oAuthBasePath: oAuth.BasePath.DEMO
}
} else {
options = {
oAuthBasePath: "account.docusign.com",
// We called https://account.docusign.com/oauth/userinfo to found the uri
basePath:"https://eu.docusign.net/restapi/"
}
}
// in production, We must do
// var apiClient = new docusign.ApiClient(options.basePath);
// Otherwise, we get "Error: getaddrinfo ENOTFOUND undefined undefined:443"
var apiClient = new docusign.ApiClient(options.basePath);
var privateKeyFile = fs.readFileSync(`./server/docusign/keys/${env}/private.PEM`);
var res = await apiClient.requestJWTUserToken(config.docusign.integratorKey, config.docusign.userName, [oAuth.Scope.IMPERSONATION, oAuth.Scope.SIGNATURE], privateKeyFile, 3600)
var token = res.body.access_token;
apiClient.addDefaultHeader('Authorization', 'Bearer ' + token);
docusign.Configuration.default.setDefaultApiClient(apiClient);
await sendDocusign({
userId: 1,
firstName: 'foor',
lastName: 'bar',
email:'foo#bar;'
})
}
async function sendDocusign(role) {
var envDef = new docusign.EnvelopeDefinition();
envDef.emailSubject = 'Please signe this';
envDef.templateId = config.docusign.templateId;
var role = new docusign.TemplateRole();
role.roleName = "roleName";
role.clientUserId = role.userId;
role.name = role.firstName + " " + role.lastName;
role.email = role.email;
envDef.allowReassign = false;
envDef.templateRoles = [role];
envDef.status = 'sent';
var envelopesApi = new docusign.EnvelopesApi();
return await envelopesApi.createEnvelope(config.docusign.userAccountId, {
'envelopeDefinition': envDef
})
}
As you are able to generate AccesToken properly in PROD with PROD RSA KeyPair, so please check the endpoint which you using to make API calls to create an envelope. In demo it is always demo.docusign.net but in PROD it will be a different value depending on where you PROD account exists in the DocuSign data center. For instance if your PROD account is in NA1, then hostname will be will be www.docusign.net; if it is NA2 then hostname will be na2.docusign.net etc.
So it is recommended to make a /userinfo API call with the Access token to know the baseURI to make calls related to envelope. To get the base URI, call the /oauth/userinfo endpoint, supplying your application’s access token as a header.
For the developer sandbox environment, the URI is
https://account-d.docusign.com/oauth/userinfo
For the production environment, the URI is
https://account.docusign.com/oauth/userinfo
Documentation related to /userinfo API call is available here. Once you know you BaseURI then append this baseURI with envelopes related endpoint like below:
{base_uri} + "/restapi/v2.1/accounts/" + {account_id}
considering your error seems that you're missing the integratorKey or you're writing it in the wrontg way. According to that LINK is possible that you miss the brackets inside the intregrator key?
The integrator key must be placed in front of the user ID that is in
the Username node of the UsernameToken. The integrator key must be
wrapped with brackets, “[ and ]”.
An example of the api in the above documentation:
<soap:Header>
<wsa:Action>http://www.docusign.net/API/3.0/GetRecipientEsignList</wsa:Action>
<wsa:MessageID>uuid:3f9d7626-c088-43b4-b579-2bd5e8026b17</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To>http://demo.docusign.net/api/3.0/api.asmx</wsa:To>
<wsse:Security soap:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-8838aa24-9759-4f85-8bf2-26539e14f750">
<wsu:Created>2006-04-14T14:29:23Z</wsu:Created>
<wsu:Expires>2006-04-14T14:34:23Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-7c7b695e-cef7-463b-b05a-9e133ea43c41">
<wsse:Username>[Integrator Key Here]2988541c-4ec7-4245-b520-f2d324062ca3</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
<wsse:Nonce>SjlScsL5q3cC1CDWrcMx3A==</wsse:Nonce>
<wsu:Created>2006-04-14T14:29:23Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>

Resources