294 lines
12 KiB
Plaintext
294 lines
12 KiB
Plaintext
import sys, os, datetime, hashlib, hmac
|
|
from StringIO import StringIO
|
|
import gzip
|
|
import urllib
|
|
import urllib2
|
|
import json
|
|
|
|
def get_filters_2(**kwargs):
|
|
filter_stack = []
|
|
canonical_querystring = ""
|
|
url_encoding = kwargs.get("url_encoding")
|
|
|
|
sources = kwargs.get("sources")
|
|
if sources:
|
|
source_string = "SourceId=" + ",".join(sources)
|
|
filter_stack.append(source_string)
|
|
|
|
devices = kwargs.get("devices")
|
|
if devices:
|
|
device_string = "Device=" + ",".join(devices)
|
|
filter_stack.append(device_string)
|
|
|
|
priorities = kwargs.get("priorities")
|
|
if priorities:
|
|
priority_string = "Priority=" + ",".join(str(item) for item in priorities)
|
|
filter_stack.append(priority_string)
|
|
|
|
types = kwargs.get("types")
|
|
if types:
|
|
type_string = ("Type=" + ",".join(str(item) for item in types))
|
|
filter_stack.append(type_string)
|
|
|
|
time_from = kwargs.get("start")
|
|
if time_from:
|
|
time_from_string = "StartTimestamp=" + str(time_from)
|
|
filter_stack.append(time_from_string)
|
|
|
|
time_to = kwargs.get("end")
|
|
if time_to:
|
|
time_to_string = "EndTimestamp=" + str(time_to)
|
|
filter_stack.append(time_to_string)
|
|
|
|
duration = kwargs.get("duration")
|
|
if duration:
|
|
duration_string = "MinimumDuration=" + str(duration)
|
|
filter_stack.append(duration_string)
|
|
if filter_stack:
|
|
if url_encoding:
|
|
canonical_querystring += "Filter="
|
|
for i, j in enumerate(filter_stack):
|
|
if i == len(filter_stack)-1 and url_encoding == True:
|
|
canonical_querystring += urllib.quote(j, "")
|
|
elif i == len(filter_stack)-1:
|
|
canonical_querystring += j
|
|
elif url_encoding == True:
|
|
canonical_querystring += urllib.quote(j + "&", "")
|
|
else:
|
|
canonical_querystring += (j + "&")
|
|
|
|
return canonical_querystring
|
|
|
|
def get_filters(**kwargs):
|
|
#Build filter string, filters are passed as key word arguments into the function
|
|
#Check if any of the filters have been passed means we need to add Filter=.
|
|
#Each filter is then converted using the urllib_parse.
|
|
canonical_querystring = ""
|
|
sources = kwargs.get("sources")
|
|
devices = kwargs.get("devices")
|
|
priorities = kwargs.get("priorities")
|
|
types = kwargs.get("types")
|
|
time_from = kwargs.get("start")
|
|
time_to = kwargs.get("end")
|
|
duration = kwargs.get("duration")
|
|
url_encoding = kwargs.get("url_encoding")
|
|
filter_list = [sources, devices, priorities, types, time_from, time_to, duration]
|
|
if any(filter_list):
|
|
canonical_querystring = "Filter="
|
|
if sources:
|
|
source_string = ("SourceId=" + ",".join(sources))
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote(source_string + "&","")
|
|
else:
|
|
canonical_querystring += source_string + "&"
|
|
if devices:
|
|
device_string = ("Device=" + ",".join(devices))
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote(device_string + "&","")
|
|
else:
|
|
canonical_querystring += device_string +"&"
|
|
if priorities:
|
|
priority_string = ("Priority=" + ",".join(str(item) for item in priorities))
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote(priority_string + "&", "")
|
|
else:
|
|
canonical_querystring += priority_string +"&"
|
|
if types:
|
|
type_string = ("Type=" + ",".join(str(item) for item in types))
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote(type_string + "&","")
|
|
else:
|
|
canonical_querystring += type_string +"&"
|
|
if time_from:
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote("StartTimestamp=" + str(time_from) + "&","")
|
|
else:
|
|
canonical_querystring += "StartTimestamp=" + str(time_from) +"&"
|
|
if time_to:
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote("EndTimestamp=" + str(time_to) + "&","")
|
|
else:
|
|
canonical_querystring += "EndTimestamp=" + str(time_to) +"&"
|
|
if duration:
|
|
if url_encoding == True:
|
|
canonical_querystring += urllib.quote("MinimumDuration=" + str(duration) + "&","")
|
|
else:
|
|
canonical_querystring += "MinimumDuration=" + str(duration) +"&"
|
|
system.perspective.print("filtered string = " + canonical_querystring )
|
|
canonical_querystring = canonical_querystring.rstrip("&")
|
|
return canonical_querystring
|
|
|
|
def get_response(response):
|
|
if response.info().get('Content-Encoding') == 'gzip':
|
|
buf = StringIO(response.read())
|
|
f = gzip.GzipFile(fileobj=buf)
|
|
data = f.read()
|
|
return (response.getcode(), data)
|
|
else:
|
|
buf = StringIO(response.read())
|
|
return(response.getcode(), buf.read())
|
|
|
|
def build_url(credentials, **kwargs):
|
|
# ************* REQUEST VALUES *************
|
|
method = 'GET'
|
|
service = 'lambda'
|
|
|
|
# This is a lookup in secrets to a return the function url for the lambda that needs called.
|
|
# This allows beta and prod to be dynamically retrived.
|
|
whid = kwargs.get("fc")
|
|
region = kwargs.get("region")
|
|
API_ID, STAGE, ACC_ID, FUNC_URL = AWS.secrets_manager.get_secret(str(whid), 'scada/api/endpoint')
|
|
api_id = FUNC_URL
|
|
host = "%s.%s-url.%s.on.aws" % (api_id, service, region)
|
|
endpoint = "https://%s" % (host)
|
|
|
|
|
|
# Key derivation functions. See:
|
|
# http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python
|
|
def sign(key, msg):
|
|
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
|
|
|
|
def getSignatureKey(key, dateStamp, regionName, serviceName):
|
|
kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
|
|
kRegion = sign(kDate, regionName)
|
|
kService = sign(kRegion, serviceName)
|
|
kSigning = sign(kService, 'aws4_request')
|
|
return kSigning
|
|
|
|
# Read AWS access key from env. variables or configuration file. Best practice is NOT
|
|
# to embed credentials in code.
|
|
# access_key = os.environ.get('AWS_ACCESS_KEY_ID')
|
|
# access_key= 'ASIATVSVCYSV2JJJMDPP'
|
|
# secret_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
|
# secret_key= 'Hc0G/0eACBlgplGSBnfsB98Y6DPqwpvyb4nc1Rvs'
|
|
# session_token = os.environ["AWS_SESSION_TOKEN"]
|
|
# session_token= 'IQoJb3JpZ2luX2VjEJr//////////wEaCWV1LXdlc3QtMSJHMEUCIQCbrPQoj4OM0SXIo6QtcNAblnplgXfvSYIcA+k8xkXmZwIgN1Pi7Nyc66T8p0HkZSMmuW8pu1qPEVJii41YgYCuiBYqngIIo///////////ARAAGgwyNTI1MDc3Njc5NzkiDKGV69tLNcKNVcoeryryARkU2Lmnj0aa+ilLOrg35FIb81jvmj6bpPR3+5zJ3Wna+vOBgz6cqphyn28+Q8Ryw/lzM6gM0vWH+gV26CuQZtKd1U4ETo9eL9QuluLBqLnZYfT5q+F9hzJy3OQQl0c3VvwcaCjOPrMdbvWnJGEoEZTKe7Xm5v3ok3huJDgKLEIVlE6Z4c2kKNy/N/JfbxB5a33A2eaE9YaGj1V0cQgUFCCkn9uDq8W4TzOPZ3NgKAyj8RoBR6KAC8gEtWXFEwwZR3ZMwYIXryEepcU7HQSHpp66JAFm/X5+HNxRe7WUwTETAveYMNi5ssFzl3rneKh9+U37MPW58psGOp0B11BghSma0KZHgCfXqdsgfGyD7/sBEyYE9wdnzmi8fOpel5EDQoUoYilRSXod2E9wlaXj3h8S+dtBJjGVqsIbHEIrW7WKOEYELxoW4VSDw5hDjZaUuZ5fA3z59c4CEeAz3v5EA6NN6+ulEb7/4pbWF8s3fezNk9T73NpmKnjaMFukcBX8DofesZGJFpfGij2Sx4hQ3qlmG91uac8kMw=='
|
|
access_key = credentials["AccessKey"]
|
|
secret_key = credentials["SecretKey"]
|
|
session_token = credentials["SessionKey"]
|
|
|
|
|
|
|
|
if access_key is None or secret_key is None:
|
|
system.perspective.print('No access key is available.')
|
|
sys.exit()
|
|
|
|
# Create a date for headers and the credential string
|
|
t = datetime.datetime.utcnow()
|
|
amz_date = t.strftime('%Y%m%dT%H%M%SZ') # Format date as YYYYMMDD'T'HHMMSS'Z'
|
|
datestamp = t.strftime('%Y%m%d') # Date w/o time, used in credential scope
|
|
system.perspective.print("creating header")
|
|
system.perspective.print("datestamp = " + str(datestamp) + " region = " + str(region) + "service = " + str(service))
|
|
|
|
# ************* TASK 1: CREATE A CANONICAL REQUEST *************
|
|
# http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
|
|
|
# Because almost all information is being passed in the query string,
|
|
# the order of these steps is slightly different than examples that
|
|
# use an authorization header.
|
|
|
|
# Step 1: Define the verb (GET, POST, etc.)--already done.
|
|
|
|
# Step 2: Create canonical URI--the part of the URI from domain to query
|
|
# string (use '/' if no path)
|
|
fc = kwargs.get("fc")
|
|
canonical_uri = "/history/%s" % (fc)
|
|
|
|
# Step 3: Create the canonical headers and signed headers. Header names
|
|
# must be trimmed and lowercase, and sorted in code point order from
|
|
# low to high. Note trailing \n in canonical_headers.
|
|
# signed_headers is the list of headers that are being included
|
|
# as part of the signing process. For requests that use query strings,
|
|
# only "host" is included in the signed headers.
|
|
canonical_headers = 'host:' + host + '\n'
|
|
signed_headers = 'host'
|
|
|
|
# Match the algorithm to the hashing algorithm you use, either SHA-1 or
|
|
# SHA-256 (recommended)
|
|
algorithm = 'AWS4-HMAC-SHA256'
|
|
|
|
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
|
|
|
|
# Step 4: Create the canonical query string. In this example, request
|
|
# parameters are in the query string. Query string values must
|
|
# be URL-encoded (space=%20). The parameters must be sorted by name.
|
|
#canonical_querystring = 'Action=CreateUser&UserName=NewUser&Version=2010-05-08'
|
|
#canonical_querystring = 'NextToken=' + urllib.parse.quote("1669217267.5230844/PLC09/T00049",'') + '&PageSize=50'
|
|
#canonical_querystring = 'PageSize=50&PreviousToken=' + urllib.parse.quote('1669217267.5824845/PLC09/T00099','')
|
|
canonical_querystring = ""
|
|
#Build filter string, filters are passed as key word arguments int the function
|
|
#Check if any of the filters have been passed means we need to add Filter=.
|
|
#Each filter is then converted using the urllib_parse.
|
|
#Including client id for timestream api.
|
|
client_id = kwargs.get("client_id")
|
|
if client_id:
|
|
canonical_querystring += 'ClientId=' + client_id + '&'
|
|
PAGE_SIZE = "200"
|
|
filters= kwargs.get("filters","")
|
|
if filters != "":
|
|
canonical_querystring += filters + "&"
|
|
|
|
next_token = kwargs.get("next_token")
|
|
|
|
previous_token = kwargs.get("previous_token")
|
|
if next_token != None:
|
|
canonical_querystring += 'NextToken=' + urllib.quote(next_token,'') + '&'
|
|
system.perspective.print("created string " + canonical_querystring)
|
|
|
|
if previous_token != None:
|
|
canonical_querystring += 'PreviousToken=' + urllib.quote(previous_token,'') + '&'
|
|
|
|
else:
|
|
canonical_querystring += 'X-Amz-Algorithm=AWS4-HMAC-SHA256'
|
|
canonical_querystring += '&X-Amz-Credential=' + urllib.quote_plus(access_key + '/' + credential_scope)
|
|
canonical_querystring += '&X-Amz-Date=' + amz_date
|
|
#canonical_querystring += '&X-Amz-Expires=30'
|
|
canonical_querystring += "&X-Amz-Security-Token=" + urllib.quote_plus(session_token)
|
|
canonical_querystring += '&X-Amz-SignedHeaders=' + signed_headers
|
|
|
|
|
|
# Step 5: Create payload hash. For GET requests, the payload is an
|
|
# empty string ("").
|
|
payload_hash = hashlib.sha256(('').encode('utf-8')).hexdigest()
|
|
|
|
# Step 6: Combine elements to create canonical request
|
|
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
|
|
|
|
|
|
# ************* TASK 2: CREATE THE STRING TO SIGN*************
|
|
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
|
|
|
|
# ************* TASK 3: CALCULATE THE SIGNATURE *************
|
|
# Create the signing key
|
|
signing_key = getSignatureKey(secret_key, datestamp, region, service)
|
|
|
|
# Sign the string_to_sign using the signing_key
|
|
signature = hmac.new(signing_key, (string_to_sign).encode("utf-8"), hashlib.sha256).hexdigest()
|
|
|
|
|
|
# ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
|
|
# The auth information can be either in a query string
|
|
# value or in a header named Authorization. This code shows how to put
|
|
# everything into a query string.
|
|
canonical_querystring += '&X-Amz-Signature=' + signature
|
|
|
|
|
|
# ************* SEND THE REQUEST *************
|
|
# The 'host' header is added automatically by the Python 'request' lib. But it
|
|
# must exist as a header in the request.
|
|
request_url = endpoint + canonical_uri + "?" + canonical_querystring
|
|
|
|
system.perspective.print('\nBEGIN REQUEST++++++++++++++++++++++++++++++++++++')
|
|
system.perspective.print('Request URL = ' + request_url)
|
|
# r = requests.get(request_url)
|
|
request = urllib2.Request(request_url)
|
|
request.add_header('Accept-encoding', 'gzip')
|
|
try:
|
|
response = urllib2.urlopen(request)
|
|
except urllib2.HTTPError as e:
|
|
return(e.code, None)
|
|
except urllib2.URLError as e:
|
|
return(e.reason, None)
|
|
return get_response(response)
|
|
|