Access Denied Signed URL Python3 using cloud front - python-3.x

I am trying to create signed urls for my s3 bucket to which only select people will have access to until the time expires.
I am not able to find the issue in my code. Please help
import boto
from boto.cloudfront import CloudFrontConnection
from boto.cloudfront.distribution import Distribution
import base64
import json
import rsa
import time
def lambda_handler(event, context):
url = "https://notYourUrl.com/example.html"
expires = int(time.time() + 36000)
pem = """-----BEGIN RSA PRIVATE KEY-----
myKey
-----END RSA PRIVATE KEY-----"""
Cloudfront console
key_pair_id = 'myKey'
policy = {
"Statement": [
{
"Resource":url,
"Condition":{
"DateLessThan":{"AWS:EpochTime":expires},
}
}
]
}
policy = json.dumps(policy)
private_key = rsa.PrivateKey.load_pkcs1(pem)
policy = policy.encode("utf-8")
signed = rsa.sign(policy, private_key, 'SHA-1')
policy = base64.b64encode(policy)
policy = policy.decode("utf-8")
signature = base64.urlsafe_b64encode(signed)
signature = signature.decode("utf-8")
policy = policy.replace("+", "-")
policy = policy.replace("=", "_")
policy = policy.replace("/", "~")
signature = signature.replace("+", "-")
signature = signature.replace("=", "_")
signature = signature.replace("/", "~")
print("%s?Expires=%s&Signature=%s&Key-Pair-Id=%s" % (url,expires, signature, key_pair_id))
When I test the file on lambda I am able to produce and print a URL but when I access the URL I receive an access denied error message from the XML file.
I am not sure what I am doing wrong at this point. To test if I am able to generated any SignedUrl I created a node.js lambda in which I am successfully able to generate the URL and even access my page.
<Error>
<Code>AccessDenied</Code>
<Message>Access denied</Message>
</Error>

After many failed tries to make my code work I decided to go with a different approach and used node.js to fullfill my needs. The code below works perfectly and I am able to generate signed url's
For now I used a hardcoded time value to test my code and will later on work on getting that dynamically using datetime.
var AWS = require('aws-sdk');
var keyPairId = 'myKeyPairId';
var privateKey = '-----BEGIN RSA PRIVATE KEY-----' + '\n' +
'-----END RSA PRIVATE KEY-----';
var signer = new AWS.CloudFront.Signer(keyPairId, privateKey);
exports.handler = function(event, context) {
var options = {url: "https://notYourUrl.com/example.html", expires: 1621987200, 'Content-Type': 'text/html'};
//console.log(options);
const cookies = signer.getSignedCookie(options);
const url = signer.getSignedUrl(options);
console.log("Printing URL "+url);
console.log(cookies);
};

Related

ValueError: Invalid password or PKCS12 data when retrieving certificate with a password from azure key vault

I'm writing code to retrieve certificate (as key, cert) from Azure Key Vault. The code runs perfectly when i remove the password from the certificate. How can i make it work with a password for example: abc()^WER123.
I've already tried several methods for decoding the password, transforming to bytes, using hashes.SHA256 as kdf algorithm. Nothing works.. It gives me this error:
"ValueError: Invalid password or PKCS12 data"
Here my latest code:
import base64
from azure.identity import ClientSecretCredential
from azure.keyvault.certificates import CertificateClient
from azure.keyvault.secrets import SecretClient
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.serialization import pkcs12
def get_keyCert_fromKeyVault():
TENANT_ID = ''
CLIENT_ID = ''
CLIENT_SECRET = ''
KEYVAULT_NAME = ''
KEYVAULT_URI = f"https://{KEYVAULT_NAME}.vault.azure.net/"
credential = ClientSecretCredential(
tenant_id=TENANT_ID,
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET
)
#get certificate from vault
certificate_client = CertificateClient(vault_url=KEYVAULT_URI, credential=credential)
certificate = certificate_client.get_certificate("cert_name")
#get certificate from secret id of the cert.
secret_client = SecretClient(vault_url=KEYVAULT_URI, credential=credential)
certificate_secret = secret_client.get_secret(name=certificate.name)
cert_bytes = base64.b64decode(certificate_secret.value)
password_provided =b'abc()^WER123'
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA1(),
length=64,
salt=salt,
iterations=480000,
backend=default_backend()
)
password = base64.urlsafe_b64encode(kdf.derive(password_provided))
private_key, public_certificate, additional_certificates =
pkcs12.load_key_and_certificates(
data=cert_bytes,
password=password
)
return private_key, public_certificate
Please Help!
Thanks in advance
I have followed the below steps to retrieve the certificate from the Azure key vault.
Step 1: Create Azure key vault and upload certificates to it.
Step 2: Setup python and run below code to retrieve certificates.
import os
import base64
import requests
import json
KEY_VAULT_URL = "https://<keyvault-name>.vault.azure.net"
TENANT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CERT_NAME = "testcert010203"
def get_access_token():
auth_url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token"
auth_data = {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"grant_type": "client_credentials",
"scope": f"https://vault.azure.net/.default"
}
response = requests.post(auth_url, data=auth_data)
response.raise_for_status()
return response.json()["access_token"]
def get_certificate(access_token):
"""Get the certificate from Azure Key Vault."""
cert_url = f"{KEY_VAULT_URL}/certificates/{CERT_NAME}?api-version=7.0"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
response = requests.get(cert_url, headers=headers)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
access_token = get_access_token()
cert_data = get_certificate(access_token)
print("Certificate data:")
print(json.dumps(cert_data, indent=4))
Step 3: Verify the certificate in the output.

Microsoft AD JWT Won't Decode

I've used the python code sample below from Microsoft to try and decode access and identity tokens (JWT) from Microsoft AD. I've tried every method I can find online for doing this and no matter what I keep getting this error:
File "C:\Users\Connor Johnson\AppData\Local\Programs\Python\Python37\lib\site-packages\jwt\api_jwt.py", line 92, in decode
jwt, key=key, algorithms=algorithms, options=options, **kwargs
File "C:\Users\Connor Johnson\AppData\Local\Programs\Python\Python37\lib\site-packages\jwt\api_jws.py", line 156, in decode
key, algorithms)
File "C:\Users\Connor Johnson\AppData\Local\Programs\Python\Python37\lib\site-packages\jwt\api_jws.py", line 223, in _verify_signature
raise InvalidSignatureError('Signature verification failed')
jwt.exceptions.InvalidSignatureError: Signature verification failed
I've tried different encoding-centered solutions to no avail, and at this point all I can figure is that it's an AD configuration issue. If I need to provide specific AD settings, let me know.
import jwt
import sys
import requests
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend
PEMSTART = '-----BEGIN CERTIFICATE-----\n'
PEMEND = '\n-----END CERTIFICATE-----'
# get Microsoft Azure public key
def get_public_key_for_token(kid):
response = requests.get(
'https://login.microsoftonline.com/common/.well-known/openid-configuration',
).json()
jwt_uri = response['jwks_uri']
response_keys = requests.get(jwt_uri).json()
pubkeys = response_keys['keys']
public_key = ''
for key in pubkeys:
# found the key that matching the kid in the token header
if key['kid'] == kid:
# construct the public key object
mspubkey = str(key['x5c'][0])
cert_str = PEMSTART + mspubkey + PEMEND
cert_obj = load_pem_x509_certificate(str.encode(cert_str), default_backend())
public_key = cert_obj.public_key()
return public_key
# decode the given Azure AD access token
def aad_access_token_decoder(access_token):
header = jwt.get_unverified_header(access_token)
print(header['kid'])
public_key = get_public_key_for_token(header['kid'])
# the value of the databricks_resource_id is as defined above
databricks_resource_id=<APP ID>
decoded=jwt.decode(access_token, key = public_key, algorithms = 'RS256',
audience = databricks_resource_id)
for key in decoded.keys():
print(key + ': ' + str(decoded[key]))
aad_access_token_decoder(<JWT BEARER TOKEN IN STRING>)
You have a misconfiguration on your app registration. You issuer url, audience, or something, is set up wrong. I can't tell you more without knowing a lot more about the app registration and code setup.
I'm pretty sure that "common" in the oidc config url only works for multi-tenant apps. If your app is not multi tenant you might try substituting your tenant id right there.

How to get access_token from fyers API?

I'm looking to get access_token from fyers API
I'm able to get authorization_code and build authorization_url to open it in browser to enter user credentials. access_token is displayed in browser's address when user enters credentials but my program is unable to retrieve the access_code.
Your help is much appreciable.
My code is as follows:
from fyers_api import accessToken
from fyers_api import fyersModel
import requests
import webbrowser
import urllib.request as ur
app_id = "XXXXXXXXX"
app_secret = "XXXXXXXXX"
app_session = accessToken.SessionModel(app_id, app_secret)
response = app_session.auth()
if response['code'] != 200:
print('CODE=' + str(response['code']))
print('MESSAGE=' + str(response['message']))
print('Exiting program...')
exit(0)
authorization_code = response['data']['authorization_code']
app_session.set_token(authorization_code)
authorization_url=app_session.generate_token('XXXXXX')
token = webbrowser.open(authorization_url)
#Following authorization url is opened in browser:
#https://api.fyers.in/api/v1/genrateToken?authorization_code=xxxxxxxxxxxxx&appId=xxxxxxxxx&user_id=xxxxxx
#User is redirected to following url after successful log-in:
#https://trade.fyers.in/?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=&user_id=xxxxxx
print(token)
#token=”your_access_token”
#is_async = False #(By default False, Change to True for asnyc API calls.)
#fyers = fyersModel.FyersModel(is_async)
#fyers. get_profile(token = token)
Instead of writing the mentioned code, it is better to directly call Fyers Api.
import requests
url = 'https://api.fyers.in/api/v1/token'
requestParams = {
"fyers_id":"Your Client ID",
"password":"Your Password",
"pan_dob":"Your PAN card or DOB(DD-MM-YYYY)",
"appId":"YOur APP ID",
"create_cookie":False}
response = requests.post(url, json = requestParams )
print (response.text)
from fyers_api import accessToken
from fyers_api import fyersModel
app_id = "xxxxxxxxxx"
app_secret = "xxxxxxxxxx"
app_session = accessToken.SessionModel(app_id, app_secret)
response = app_session.auth()
print(app_session)
print(response)
authorization_code = response['data']['authorization_code']
app_session.set_token(authorization_code)
gen_token = app_session.generate_token()
print("token url is copy paste this url in browser and copy access
token excluding your id at Last ")
print(gen_token)
print("tokent printed thanks")
token="gAAAAABeTWk7AnufuuQQx0D0NkgABinWk7AnufuuQQx0DQ3ctAFWk7AnufuuQQx0DMQQwacJ-
_xUVnrTu2Pk5K5QCLF0SZmw7nlpaWk7AnufuuQQx0DG4_3EGCYw92-iAh8="
is_async = False
fyers = fyersModel.FyersModel(is_async)
print(fyers. get_profile(token = token))
fyers.funds(token = token)
print(fyers.funds(token = token))

AWS Secrets Manager password issue in python3 and pystfp

Currently trying to connect sftp server using user credential from AWS secret manager, and password contains double quote special character, which causing the issue. Below is sample code,
import sys
import boto3
import base64
from botocore.exceptions import ClientError
import hashlib
import pysftp
secret_name = "SFTP_TEST"
region_name = "eu-central-1"
_SFTP_DETAILS = {}
pass1= "E?%/?s\"N1sS#OnXN"
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
cnopts.log = True
basepath ='/test/'
def get_connect(secret_name,region_name):
session = boto3.session.Session()
client = session.client(service_name='secretsmanager', region_name=region_name.strip())
if secret_name.strip() not in _SFTP_DETAILS:
try:
get_secret_value_response = client.get_secret_value(SecretId=secret_name.strip())
except Exception as e:
raise e
else:
if 'SecretString' in get_secret_value_response:
secret = get_secret_value_response['SecretString']
print("Secret value Original ==>",secret)
secretValue = json.loads(secret)
awsValue = secretValue.get(secret_name.strip())
sftpStrValue = awsValue.replace("“","\"").replace("”","\"")
print("Secrete Value After JSON loader ==>",sftpStrValue)
sftpValues = json.loads(sftpStrValue)
_HOST_NAME = sftpValues.get("url")
_USER_NAME = sftpValues.get("username")
_PASSWORD = sftpValues.get("password")
print("Secrete Password:::" + _PASSWORD)
_PORT = sftpValues.get("port")
with pysftp.Connection(_HOST_NAME, username=_USER_NAME, password=_PASSWORD, port=int('22'), cnopts=cnopts) as sftp:
print("I am in SFTP SERVER")
for attr in sftp.listdir_attr(basepath):
print("listdir is",attr)
_SFTP_DETAILS[secret_name] = [_HOST_NAME.strip(),_USER_NAME.strip(),_PASSWORD.strip(),_PORT.strip()]
return _SFTP_DETAILS[secret_name.strip()]
get_connect()
Here we are fetching password (_PASSWORD) from AWS secret manager and passing to pysftp.Connection function, but unable to connect.
Here if I am hard coded password i.e. pass1 in above code then its working fine and able connect. Unable to get the issue is from python or AWS Secrets Manager.
Could you please let me know why password from AWS secret manager is not working while hard coded is working correctly. Here requirement to keep password in AWS Secrets Manager.
Any help on this appreciated.
I have this as my secret in AWS Secret Manager Console:
Secret Key | Secret Value
TEST_KEY | afgvbq3tg"afsvgqag"af.qw/asffq3gvd13
If I get the secret_value by:
secret = client.get_secret_value(SecretId="test_secret_ron")
and print the secret["SecretString"], the result will look like:
'{"TEST_KEY":"afgvbq3tg\\"afsvgqag\\"af.qw/asffq3gvd13"}'
once you turn this string to dictionary by:
json.loads(secret["SecretString"])
the expected dictionary will reflect the correct format of the string:
{'TEST_KEY': 'afgvbq3tg"afsvgqag"af.qw/asffq3gvd13'}
enter image description here

Create RSA Token in nodejs

I'm trying to authenticate to a REST API using encryption.
First I need to call the API to get an encryptionKey and a timestamp.
The encryptionKey is in Base 64 format.
Then I need to create a RSAToken using the key and finaly encrypt the password using password + "|" + timestamp.
This is some sample code using python to authenticate to the API
key, timestamp = get_encryption_key()
decoded_key = key.decode('base64')
rsa_key = RSA.importKey(decoded_key)
encrypted = rsa_key.encrypt(password + '|' + str(timestamp), 'x')
encrypted_password = encrypted[0]
and
import base64
from Crypto.PublicKey import RSA
r = requests.get(my_url, headers=headers)
myData = r.json()
decoded = base64.b64decode(myData['encryptionKey'])
key = RSA.importKey(decoded)
enc = key.encrypt(password + '|' + str(myData['timeStamp']), 'x')
encryptedPassword = enc[0]
session = "/session"
my_url = url + session
payload = {"identifier": identifier,
"password": encryptedPassword,
"encryptedPassword": "True"
}
Any hints to achieve this under Node?
You can use crypto.publicEncrypt to encrypt your password. Notice the padding, you might want to use the right padding that is being used in your Python script.
const crypto = require('crypto');
const constants = require('constants');
const decodedKey = Buffer(encriptionKey, 'base64').toString();
const encryptedPassword = crypto.publicEncrypt({
key: decodedKey,
padding : constants.RSA_PKCS1_OAEP_PADDING
} , Buffer(`${password}|${timestamp}`));
Check out this node.js test to find out more examples for different padding.

Resources