I have a use case wherein, I need to connect to an API for data request.
The API requires a valid token to process the requests.
To generate the token, I have a accountCode & secret key
Assume BaseURL as
BaseURL - http://api.xxxxx.com/{accountCode}/data (Value of account needs to be passed)
**Below script in Python/Java needs to be run to fetch the dateToken & token
If we use Python 3.6 or above. Below is the code -**
--START-- {
import time
import requests
from hashlib import md5
account_code = "<account_name>"
key = "<api_key>"
actual_unix_time = int(time.time_ns() / 1000) # in milliseconds
TTL = 31536000000 # for 1 year
expiration_time = actual_unix_time + TTL
base_url = "https://api.xxxxx.com"
url = f"/{account_code}/data?fromDate=last6Hours&granularity=minute&type=ALL%2CVOD%2CLIVE&operation=reduceJoin&metrics=bufferratio"
pre_url = f"{url}&dateToken={expiration_time}"
token_generated = md5(f"{pre_url}{key}".encode('utf-8'))
token_value = token_generated.hexdigest()
request_url = f"{base_url}{pre_url}&token={token_value}"
response = requests.get(request_url)
print(response)
print(response.text)
} --END--
- If we use Java. Below is the code -
--START-- {
var key = pm.environment.get("NPAW-API-KEY");
var base_url = "https://api.xxxxx.com";
var url = pm.request.url.toString();
var path = url.replace(base_url, '');
var pre_url = pm.variables.replaceIn(path);
var moment = require('moment');
var actual_unix_time = moment().unix()*1000;
var TTL = 31536000000
var expiration_time = (actual_unix_time + TTL);
var pre_url = pre_url+"&dateToken="+expiration_time;
var token_generated = CryptoJS.MD5(pre_url + key).toString();
var token_value = token_generated;
var request_url = (base_url+pre_url+'&token='+token_value).toString();
}--END--
Example of how the final URL - https://api.xxxxx.com/kb-vivek/data?fromDate=today&granularity=hour&type=ALL,VOD,LIVE&operation=reduceJoin&metrics=views,playtime&dateToken=1699016056000&token=7a9c97a4d4f108d1d32be2f7f8d00731
I tried to use Postman, wherein, I could pass the above script in the Pre-Request script and set environment variables for accountCode & Secret Key and I was able to achieve the result as desired.
Question: How can I achieve this in Azure Data Factory?
To achieve the requirement, we need to use a combination of set variables and dataflows (to generate md5 hex string and store final url in a file).
First, I have created 4 parameters with values as shown below:
base_url: https://api.xxxxx.com
account_code: <account_name>
key: <api_key>
TTL: 31536000000
First, I have created a variable to build url. I used the following dynamic content:
/#{pipeline().parameters.account_code}/data?fromDate=last6Hours&granularity=minute&type=ALL%2CVOD%2CLIVE&operation=reduceJoin&metrics=bufferratio
Next, I have built the pre_url with the following dynamic content:
#{variables('url')}&dateToken=#{add(div(sub(ticks(utcNow()), ticks('1970-01-01')),10),31536000000)}
Now, to encode the string and convert it to md5 hex string, I have used dataflow. I have passed base_url, pre_url and key to the dataflow from the pipeline.
I have taken a sample csv file with only one row from blob storage (the data in this file does not matter but make sure it has 1 row only).
I have created a derived column to create final URL by concatenating base_url, pre_url and encoded md5 hex string. Use the following content:
$base_url+$pre_url+'&token='+md5(encode(concat($pre_url,$key)))
Now I am writing this data to a file by using output to single file option in the sink settings.
When I debug the pipeline, the file will be written to my storage account. The contents of the file will be as shown below:
NOTE:
Now since you want to generate date token once and use it for a year, I have written the data to a file.
You run this pipeline once and generate a file with required URL (as above). Anytime you want to access this URL, you can use look up activity to access the URL anywhere required.
I have used utcNow() to generate dateToken. But if you have any specific date in mind, you can simply use that in the correct format (in place of utcNow()).
Related
I'll try to explain this best I can. I'm trying to perform a simple GET against the NetSuite "employees" API (using PowerShell). As you can see in the $query below, this variable needs to be URL encoded (spaces in the query) which I am doing on line 20 of the below snippet. I'm then taking that encoded URL along with a couple other variables and building the $base_string. I use the $base_string to create the Base64 OAuth signature and, on line 36, URL encode the signature. My response from NetSuite is always Invalid Signature.
When I perform any sort of "standard" query (like the one immediately below, without spaces... meaning no changes to the URL after encoding) I do not get an Invalid Signature response. This leads me to believe the problem is entirely related to the more unique query I am attempting and, possibly, the fact that it is being "double-encoded."
I'd appreciate any feedback as I would really benefit from being able to perform a query against the "custentity" variable in the below snippet.
$query = "/services/rest/record/v1/employee/$($netsuite_id)" # This query will find a user via their NetSuite ID.
$url = "https://$($realm.ToLower().Replace("_","-")).suitetalk.api.netsuite.com"
$query = "/services/rest/record/v1/employee?q=custentity_coupa_emp_id IS $($employee_id)" # This query will find a user via a custom entity --- their Coupa ID.
$oauth_nonce = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.DateTime]::Now.Ticks.ToString()))
$oauth_timestamp = [int64](([datetime]::UtcNow)-(Get-Date "1970-01-01")).TotalSeconds
# BUILD THE BASE STRING VARIABLE
$oAuthParamsForSigning = #{}
$oAuthParamsForSigning.Add("oauth_consumer_key",$oauth_consumer_key)
$oAuthParamsForSigning.Add("oauth_token",$oauth_token)
$oAuthParamsForSigning.Add("oauth_signature_method",$oauth_signature_method)
$oAuthParamsForSigning.Add("oauth_nonce",$oauth_nonce)
$oAuthParamsForSigning.Add("oauth_timestamp",$oauth_timestamp)
$oAuthParamsForSigning.Add("oauth_version",$oauth_version)
$oAuthParamsString = ($oAuthParamsForSigning.Keys | Sort-Object | % {
"$_=$($oAuthParamsForSigning[$_])"
}) -join "&"
$encodedOAuthParamsString = [uri]::EscapeDataString($oAuthParamsString)
# BUILD THE ENCODED FULL URL VARIABLE
$encodedUrl = [uri]::EscapeDataString($url+$query)
# BUILD THE OAUTH SIGNATURE VARIABLE: KEY (CONSUMER SECRET + TOKEN SECRET) + BASE STRING
$base_string = $HTTP_method + "&" + $encodedUrl + "&" + $encodedOAuthParamsString
$key = $oauth_consumer_secret + "&" + $oauth_token_secret
$hmacsha256 = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha256.Key = [System.Text.Encoding]::ASCII.GetBytes($key)
$oauth_signature = [System.Convert]::ToBase64String($hmacsha256.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($base_string)))
# BUILD THE HEADERS VARIABLE
$authHeaderString = ($oAuthParamsForSigning.Keys | Sort-Object | % {
"$_=`"$([uri]::EscapeDataString($oAuthParamsForSigning[$_]))`""
}) -join ","
$authHeaderString += ",realm=`"$([uri]::EscapeDataString($realm))`""
$authHeaderString += ",oauth_signature=`"$([uri]::EscapeDataString($oauth_signature))`""
$authHeaders = #{
"Content-Type"="application/json"
;"Prefer"="transient"
;"Authorization"="OAuth $authHeaderString"
;"Accept"="*/*"
;"Cache-Control"="no-cache"
;"Host"="3489459-sb1.suitetalk.api.netsuite.com"
;"Accept-Encoding"="gzip, deflate, br"
;"Cookie"="NS_ROUTING_VERSION=LAGGING"
}
I have no background with PowerShell but I've had this issue previously with Python and it's tricky without using libraries. I found out that:
Your Base URL cannot contain query params. Meaning your base url should be:
"https://$($realm.ToLower().Replace("_","-")).suitetalk.api.netsuite.com/services/rest/record/v1/employee"
Since you're only doing GET request, just throw your query into a payload (JSON formatted). At least with my SuiteQL this is how I did it. Moving the query to payload worked for me.
For POST Request, the parameters will need to be included in the Base String Creation, sorted alphabetically or by value if keys are the same name.
My query for example for SuiteQL was query = json.dumps({ q: SELECT FROM WHERE })
I want to use customer managed key for the sql server. For that I need to load the key from the keyvault but I cannot get the version of the key, which is required according to the pulumi documentation:
:param pulumi.Input[str] key_name: The name of the server key to be
operated on (updated or created). The key name is required to be in
the format of 'vault_key_version'. For example, if the keyId is
https://YourVaultName.vault.azure.net/keys/YourKeyName/YourKeyVersion,
then the server key name should be formatted as:
YourVaultName_YourKeyName_YourKeyVersion
Relevant code:
def create_tde_key(self, key: keyvault.Key, vault_name: str):
key_name = "{}_{}_{}".format(vault_name, key.name, key.version ) // here I need the version but there is only key.key_uri_with_version
tde_key = sql.ServerKey('tde-key-' + self.location_flag,
key_name = key_name,
resource_group_name = self.resource_group_name,
server_name = self.sql_server,
server_key_type = sql.ServerKeyType.AZURE_KEY_VAULT,
uri = key.key_uri_with_version
)
tried to disassemble key.key_uri_with_version this way:
key_version = key.key_uri_with_version[key.key_uri_with_version.rfind('/') + 1:]
but then I got TypeError: 'Output' object is not callable
I tried to use lambdas to get the string Output from key.key_uri_with_version but got the same TypeError as before.
I tried hardcoding the version and it is working so somehow I need to get the keyversion.
Any idea what should I do?
I have an offline signing code to which I need to pass the digest or the binary blob to get the signature. Looks like the digest I have produced is not right as when I try to submit the serialized signature, it complains of "fails local checks: Invalid signature." Here are the steps, I am doing to generate the digest/binary blob
STTx noopTx(ttPAYMENT,
[&](auto& obj)
{
// General transaction fields
obj[sfAccount] = id;
obj[sfFee] = STAmount(XRPAmount(fee));
obj[sfFlags] = tfFullyCanonicalSig;
obj[sfSequence] = sequence;
obj[sfSigningPubKey] = pub_key.slice();
// Payment-specific fields
obj[sfAmount] = STAmount(XRPAmount(amount));
obj[sfDestination] = *to_account;
obj[sfSendMax] = STAmount(XRPAmount(amount));
});
ripple::uint256 hash256 = noopTx.getSigningHash();
output:
0861970E8AAC8539600E2FB9169774F303A29C3B8CA98FF9206C9B958C681ACF
Please can someone tell me if I am missing any field that is needed?.
I have:
Raw xml filled by a select query.This xml transformed into a HL7
message
One of the tags of this xml represents a clob column from a table in
the database
I mapped this data (from edit transformer section) as a variable.
Now I am trying to convert this variable into a base64 string then
replace it in my transformed hl7 message.
5.I tried this conversion on a destination channel which is a javascript writer.
I read and tried several conversion methods like
Packages.org.apache.commons.codec.binary.Base64.encodeBase64String();
I have got only error messages like :
EvaluatorException: Can't find method org.apache.commons.codec.binary.Base64.encodeBase64String(java.lang.String);
Code piece:
var ads=$('V_REPORT_CLOB');
var encoded = Packages.org.apache.commons.codec.binary.Base64.encodeBase64String(ads.toString());
It is pretty clear that I am a newbie on that.How can I manage to do this conversion ?
Here is what I use for Base64 encoding a string with your var substituted.
//Encode Base 64//
var ads = $('V_REPORT_CLOB');
var adsLength = ads.length;
var base64Bytes = [];
for(i = 0; i < adsLength;i++){
base64Bytes.push(ads.charCodeAt(i));
}
var encodedData = FileUtil.encode(base64Bytes);
We are developing a REST web service with the WS security headers to be passed through as header parameters in the REST request.
I am testing this in SoapUI Pro and want to create a groovy script to generate these and then use them in the REST request.
These parameters include the password digest, encoded nonce and created dateTime and password digest which is created from encoding the nonce, hashed password and created date and time, i.e. the code should be the same as that which generates these from using the Outgoing WS Security configurations in SoapUI Pro.
I have created a groovy test script in Soap UI Pro (below). However when I supply the created values to the headers I get authorisation errors.
I am able to hash the password correctly and get the same result a my python script.
Groovy code for this is ..
MessageDigest cript = MessageDigest.getInstance("SHA-1");
cript.reset();
cript.update(userPass.getBytes("UTF-8"));
hashedpw = new String(cript.digest());
This correctly hashes the text 'Password2451!' to í¦è~µ”t5Sl•Vž³t;$.
The next step is to create a password digest of the nonce the created time stamp and the hashed pasword. I have the following code for this ...
MessageDigest cript2 = MessageDigest.getInstance("SHA-1");
cript2.reset();
cript2.update((nonce+created+hashedpw).getBytes("UTF-8"));
PasswordDigest = new String(cript2.digest());
PasswordDigest = PasswordDigest.getBytes("UTF-8").encodeBase64()
This converts '69999998992017-03-06T16:19:28Zí¦è~µ”t5Sl•Vž³t;$' into w6YA4oCUw6nDicucw6RqxZMIbcKze+KAmsOvBA4oYu+/vQ==.
However the correct value should be 01hCcFQRjDKMT6daqncqhN2Vd2Y=.
The following python code correctly achieves this conversion ...
hashedpassword = sha.new(password).digest()
digest = sha.new(nonce + CREATIONDATE + hashedpassword).digest()
Can anyone tell me where I am going wrong with the groovy code?
Thanks.
changing my answer slightly as in original I was converting the pasword digest to a string value which caused the request to not validate some of the time as certain bytes did not get converted into the correct string value.
import java.security.MessageDigest;
int a = 9
nonce = ""
for(i = 0; i < 10; i++)
{
random = new Random()
randomInteger= random.nextInt(a)
nonce = nonce + randomInteger
}
Byte[] nonceBytes = nonce.getBytes()
def XRMGDateTime = new Date().format("yyyy-MM-dd'T'HH:mm:ss", TimeZone.getTimeZone( 'BTC' ));
Byte[] creationBytes = XRMGDateTime.getBytes()
def password = testRunner.testCase.testSuite.getPropertyValue( "XRMGPassword" )
EncodedNonce = nonce.getBytes("UTF-8").encodeBase64()
MessageDigest cript = MessageDigest.getInstance("SHA-1");
cript.reset();
cript.update(password.getBytes());
hashedpw = cript.digest();
MessageDigest cript2 = MessageDigest.getInstance("SHA-1");
cript2.update(nonce.getBytes());;
cript2.update(XRMGDateTime.getBytes());
cript2.update(hashedpw);
PasswordDigest = cript2.digest()
EncodedPasswordDigest = PasswordDigest.encodeBase64();
def StringPasswordDigest = EncodedPasswordDigest.toString()
def encodedNonceString = EncodedNonce.toString()
testRunner.testCase.setPropertyValue( "passwordDigest", StringPasswordDigest )
testRunner.testCase.setPropertyValue( "XRMGDateTime", XRMGDateTime )
testRunner.testCase.setPropertyValue( "XRMGNonce", encodedNonceString )
testRunner.testCase.setPropertyValue( "Nonce", nonce )