Azure Python SDK - code only fails when debugging in VS Code - python

VS Code 1.14.0, Python 3.8.0 (in venv).
When I run the following code in VS Code, it works. When I run it in the debugger even with no breakpoints, it fails. This might be something to do with venvs, but I don't know. Ideas? BTW - I am referencing the other packages for what I will be building.
From the Bash shell, I have the following environment variables:
export AZURE_TENANT_ID = "tenant ID"
export AZURE_CLIENT_ID = "client ID"
export AZURE_CLIENT_SECRET = "client secret"
export AZURE_SUBSCRIPTION_ID = "subscription ID"
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from azure.keyvault.keys import KeyClient
from azure.mgmt.keyvault import KeyVaultManagementClient
from azure.core.exceptions import HttpResponseError
import datetime
import os
credential = DefaultAzureCredential()
secret_client = SecretClient(vault_url="https://blahblahblah.vault.azure.net/", credential=credential)
print(os.environ["AZURE_TENANT_ID"])
print(os.environ["AZURE_CLIENT_ID"])
print(os.environ["AZURE_CLIENT_SECRET"])
print(os.environ["AZURE_SUBSCRIPTION_ID"])
try:
print("\n.. Get a Secret by name")
secret = secret_client.get_secret("mySecret")
print("Secret with name '{0}' was found with value '{1}'.".format(secret.name, secret.value))
except HttpResponseError as e:
print("\nThis sample has caught an error. {0}".format(e.message))
When I run this in DEBUG in VS Code, this is the error:
This sample has caught an error.
No credential in this chain provided a token.
Attempted credentials:
EnvironmentCredential: Incomplete environment configuration
ImdsCredential: IMDS endpoint unavailable
SharedTokenCacheCredential: The shared cache contains no signed-in accounts. To authenticate with SharedTokenCacheCredential, login
through developer tooling supporting Azure single sign on
What I have learned is the printed OS environ variables are accurate when I Run Python File in Terminal, but when I run the file in debug, it errors printing the first OS environ variable saying it doesn't exist.
This is my ignorance on setting debug correctly. Any pointers will help (and thank you for your responses)!**

To make the answer visible to others, I'm summarizing the answer shared in comment:
This issue occurred because of the missing of environment variables under debugger mode. Add the environment variables to the launch.json file solved this issue.

From my experience, BASH does not like spaces, when declaring variables;
export AZURE_TENANT_ID="tenant ID"
export AZURE_CLIENT_ID="client ID"
export AZURE_CLIENT_SECRET="client secret"
export AZURE_SUBSCRIPTION_ID="subscription ID"
Might do the trick.

Related

AttributeError: 'DefaultAzureCredential' object has no attribute 'signed_session'

I'm using python sdk to query application insights using azure-applicationinsights==0.1.1.
Here is my code:
from azure.identity import DefaultAzureCredential
from azure.applicationinsights import ApplicationInsightsDataClient
from azure.applicationinsights.models import QueryBody
def query_app_insights():
query = 'myEvents | take 10'
application = 'my-app'
creds = DefaultAzureCredential()
client = ApplicationInsightsDataClient(creds)
result = client.query.execute(application, QueryBody(query=query))
I get this error:
AttributeError: 'DefaultAzureCredential' object has no attribute 'signed_session'
also tried:
creds = ClientSecretCredential(tenant_id='something',
client_id='something',
client_secret='something')
client = ApplicationInsightsDataClient(creds)
It gives me the same error.
also I tried:
from azure.identity import DefaultAzureCredential
from azure.applicationinsights import ApplicationInsightsDataClient
from azure.applicationinsights.models import QueryBody
from azure.common.credentials import ServicePrincipalCredentials
def query_app_insights():
query = 'myEvents | take 10'
application = 'my-app'
creds = ServicePrincipalCredentials(tenant='something',
client_id='something',
secret='something')
client = ApplicationInsightsDataClient(creds)
result = client.query.execute(application, QueryBody(query=query))
It complaints about my secret, but it is correct.
Any ideas?
AttributeError: 'DefaultAzureCredential' object has no attribute 'signed_session':
This error occurs frequently these days and I've also faced this couple of times. It actually means that "no signed session available for the given tenant".
After I've done a workaround, I found there is some issue addressed here with the SDK management libraries.
The DefaultAzureCredential class has been modified, and it no longer has the'signed session' attribute in few versions. To handle this, the most recent versions of the management libraries should be upgraded.
Need to check & resolve:
Installed the latest versions of the modules when you are importing in Python code.
azure-identity 1.12.0
azure-applicationinsights 0.1.1
Selected python 3.10 interpreter in visual studio code and ran the same code as yours in a virtual environment.
Created a virtual env and ran the project.
py -m venv env
.\env\Scripts\activate
Sometimes requirements.txt file will not get properly configured, In that scenario also you may face this error.
To avoid that, Freeze the requirements by using terminal:
pip freeze requirements.txt
After meeting all the above conditions, I tried in my environment and was able to proceed without any attribute errors.
Output:
Alternatively, I tried connecting with clientsecretcredential by registering to a new Application in AzureAD.
Note: Prefer to create a new registration instead of using old registrations as client_secrets might be expired.
TENANT_ID = '<TENANT_ID>'
CLIENT_ID = '<CLIENT_ID>'
CLIENT_SECRET = '<CLIENT_SECRET>'
SUBSCRIPTION_ID = '<SUBSCRIPTION_ID>'
from azure.identity import ClientSecretCredential
from azure.mgmt.keyvault import KeyVaultManagementClient
credentials = ClientSecretCredential(tenant_id=TENANT_ID, client_id=CLIENT_ID, client_secret=CLIENT_SECRET)
credentialskeyvault = KeyVaultManagementClient(credentials, SUBSCRIPTION_ID)
print ("Logged")
Output:
To determine the precise status:
I simply deleted specific "rights/permissions" from my application in AzureAD and tested whether it threw an error when logged in.
Why because?
This error is usually thrown only after the user logged in. It states that the defaultazurecredential object was running without problem.
If the issue still persists, then you can wrap credentials by installing msrestazure module and create a credentialwrapperclass detailed by #lmazuel.

Sendgrid Introduction Throws Forbidden Error

I'm running through Sendgrid's intro material for Python but executing the example code throws a 403-Forbidden error.
Steps I took:
Create API Key & sendgrid.env file as instructed.
Create a conda environment with python 3.5: conda create -n sendgrid python=3.5
Install sendgrid: (sendgrid) pip install sendgrid
Run example: (sendgrid) python main.py
Where main.py contains the exact code copied from the example page linked above.
Issue: Running main.py throws the error HTTP Error 403: Forbidden.
Things I've tried:
I tried switching out the to and from emails in that example, but doesn't change the result.
I also tried the same flow but using NodeJS but same result.
Any ideas on what I'm doing wrong?
Give API Key its full access, follow steps:
Settings
API Keys
Edit API Key
Full Access
Update
Whitelist your domain, follow steps:
Settings
Sender Authentication
Domain Authentication
Select DNS Host
Enter your domain name
Copy all records and put them in your Advanced DNS management console
NOTE: When adding records, make sure not to have domain name in the host. Crop it out.
If you do not want to authenticate domain, you can try with Single Sender Verification as well.
Note: It might take some time for records to start functioning.
If you're using pylinter, e.message will say
Instance of 'Exception' has no 'message' member
This is because message attribute is generated dynamically by sendgrid which pylinter is unable to access as it doesn't exists before runtime.
So, to prevent that, at the top of your file or above print(e.message) line, you need to add either one of the below, they mean the same thing-
# pylint: disable=no-member
E1101 is code to no-member, fine more here
# pylint: disable=E1101
Now the code below should work for you. Just make sure you have SENDGRID_API_KEY set in environment. If not, you may also directly replace it with os.environ.get("SENDGRID_API_KEY") which is not a good practice though.
# pylint: disable=E1101
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
message = Mail(
from_email="from_email#your-whitelisted-domain.com",
to_emails=("recipient1#example.com", "recipient2#example.com"),
subject="Sending with Twilio SendGrid is Fun",
html_content="<strong>and easy to do anywhere, even with Python</strong>")
try:
sg = SendGridAPIClient(os.environ.get("SENDGRID_API_KEY"))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(e.message)

Sendgrid working from terminal but not in pycharm

I am trying to connect a basic mail sender sendgrid function to my program's pipeline. Problem is when I do necessery commands from terminal it works fine like :
echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env
echo "sendgrid.env" >> .gitignore
source ./sendgrid.env
python3 sendgrid_mail.py
but when I try to run it from PyCharm it gives me HTTP Error 401: Unauthorized
error.
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
def mail_sender():
message = Mail(
from_email='from_mail',
to_emails='to_mail',
subject='hello pycharm',
html_content='<strong>and easy to do anywhere, even with Python</strong>')
try:
sg = SendGridAPIClient(os.environ.get('my_api_key'))
response = sg.send(message)
print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(e)
mail_sender()
It's unclear how you're running in PyCharm. I'm guessing your environment variable is not actually set while you are in PyCharm. Try looking at the API key and see if it's what you're expecting (Either just print or use the debugger)
You can modify the environment variables in your run configuration
Run | Edit Configurations... | Select the run configuration you're using | Environment variables ....
You could also try setting the environment variable prior to starting PyCharm and it might pick it up, but that depends on a-lot of other things.
You're getting the environment variable my_api_key, but you're setting your environment variable as SENDGRID_API_KEY in the sendgrid.env. These two names need to match.
I'm assuming YOUR_API_KEY in your sendgrid.env file is the api key you've created. If not, that would need to be replaced with a real value.

How do I explicitly pass my authentication key into Google's text to speech engine?

I'm trying to use Google Cloud's text to speech engine for my robot, and I cannot understand the reference page for passing the key explicitly in Python as mentioned here.
I spent several hours yesterday exploring different options on how to set the environment variable GOOGLE_APPLICATION_CREDENTIALS needed for implicit authorization including an export command in the shell script I use to start the robot, using os.environ commands in Python, and using os.system to call an export command.
client = texttospeech.TextToSpeechClient()
voice = robot_config.get('google_cloud', 'voice')
keyFile = robot_config.get('google_cloud', 'key_file')
hwNum = robot_config.getint('tts', 'hw_num')
languageCode = robot_config.get('google_cloud', 'language_code')
voice = texttospeech.types.VoiceSelectionParams(
name=voice,
language_code=languageCode
)
audio_config = texttospeech.types.AudioConfig(
audio_config=texttospeech.enums.AudioEncoding.LINEAR16
)
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = keyFile
Logging in via SSH shows that I have successfully set the environment variable since it shows up in env; however a DefaultCredentialsError is thrown with the following message
Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, pease see https://cloud.google.com/docs/authentication/getting-started
Logging in and setting the environment variable manually will allow the script to run and work, but this is not a long term solution.
This works for me:
import os
from google.cloud import texttospeech
os.environ ["GOOGLE_APPLICATION_CREDENTIALS"]= "/home/pi/projectx-17f8348743.json"
client=texttospeech.TextToSpeechClient()
The correct answer lies in the google.oath2 library. The client object is not looking for a json key, and is instead looking for a service account object.
from google.oath2 import service_account
from google.cloud import texttospeech
client = texttospeech.TextToSpeechClient(
credentials=service_account.Credentials.from_service_account_file(keyFile)
)

How do I connect to a kerberos authenticated REST service in Python on Windows

I am trying to create a very simple Python script to download the contents of an internal service at my company that sits within our firewall and authenticates using kerberos.
When I installed the requests_kerberos module I first edited the import kerberos in it to use import kerberos_sspi as kerberos instead after having installed the kerberos_sspi module.
Thus I have the following Python script
import requests
from requests_kerberos import HTTPKerberosAuth
response = requests.get('http://service.internaldomain',auth=HTTPKerberosAuth())
print response
While trying to process the 401 it crashes out with the error.
error: (-2146893053, 'InitializeSecurityContext', 'The specified target is unknown or unreachable')
While looking into seeing if I could do this with curl instead I ran kinit and noticed that it asked me for the password to authorisation with the following prompt:
Password for username#additionalInternalDomain.internaldomain
Thus I wondered if this might be what is causing the issue.
I have tried multiple libraries on python and failed when trying to authenticate from a windows machine.There is no easy way. The Kerberos libraries mainly work on Linux. The workarounds for Windows do not work. So what can be the solution to this.
Well... be a Roman while in Rome. Try the windows native libraries from Python.
import sys
import clr
from System.Net.Http import *
myClienthandler = HttpClientHandler()
myClienthandler.UseDefaultCredentials = True
myClient = HttpClient(myClienthandler)
x = myClient.GetStringAsync("putyourURLwithinthequoteshere")
myresult = x.Result
print(myresult)
Note that the this python script will have to run by the user who has access to the URL you are trying to access. By setting UseDefaultCredentials property as True, you are passing the Kerberos tickets for the logged in user.
The server is giving you a 401 challenge - and the client (usually a browser or even curl) provides the credentials in a subsequent call. If you are already logged in at your domain - try forcing a pre-emptive hop, i.e. you’d carry your Kerberos ticket with your call and the server will not give you a 401 challenge:
kerberos_auth = HTTPKerberosAuth(force_preemptive=True)
r = requests.get("http://myhost/DXAPIGraphQL/api/graphql", auth=kerberos_auth)
If the above doesn't help look into the:
principal and hostname_override arguments of the HTTPKerberosAuth class.
I had to connecto to a REST API who's in a keberized environment just now.
After some reading, i came to this (and it worked):
tk = 'long_kerberos_token'
headers = {'Authorization': 'Negotiate' + tk}
r = requests.get(url=PING_URL, headers=headers)

Categories

Resources