Workround:
Since I only need access to spreadsheets , I used gspread instead , oauth2 is much simpler with it
Im trying to download a file using pydrive (python google drive api)
My code worked for me ,I didn't change anything but now it wont work
I made sure to make the file public (even though it worked even when it was private)
This is the relevant part of the code:
gauth = GoogleAuth()
gauth.GetFlow()
# Try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")
if gauth.credentials is None:
# Authenticate if they're not there
gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
# Refresh them if expired
gauth.flow.params.update({'access_type': 'offline'})
gauth.Refresh()
else:
# Initialize the saved creds
gauth.Authorize()
drive = GoogleDrive(gauth)
# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")
file1 = drive.CreateFile({'id': '1naQ4crE04nBmsj7yz4GNtmp-PKrCtfTHjl_AfGoTaws'})
file1.GetContentFile('Hello.csv', mimetype='text/csv')
This is the error I get in the console :
pydrive.files.ApiRequestError: <HttpError 404 when requesting https://www.googleapis.com/drive/v2/files/1naQ4crE04nBmsj7yz4GNtmp-PKrCtfTHjl_AfGoTaws?alt=json returned "File not found: 1naQ4crE04nBmsj7yz4GNtmp-PKrCtfTHjl_AfGoTaws">
And this is what the link above shows:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded.
Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued
use requires signup."
}
}
Any help appreciated , thanks
Edit : these is what I see inside the credentials of my gauth object , anything missing?
I think you can try hitting the files.get api from postman using an active access token from your credentials file.
If it gives 401, that means your access token is not correct.
If it gives 404, it means you don't have access to the file or the file is deleted.
Related
I'm implementing (in Python with the Microsoft Graph API) the creation of Azure AD application based on the AWS template. I'm stuck when implementing the automatic role provisioning like describe in this documentation : https://learn.microsoft.com/fr-fr/graph/application-provisioning-configure-api?tabs=http#step-3-authorize-access
When I call the servicePrincipals/{id}/synchronization/secrets API for the first time just after the creation of the synchronization job, I receive a HTTP error (400 - Bad Request) with the following body :
{
"error": {
"code": "BadRequest",
"message": "The credentials could not be saved. This is due to an internal storage issue in the Microsoft Azure AD service. For information on how to address this issue, please refer to https://go.microsoft.com/fwlink/?linkid=867915",
"innerError": {
"code": "CredentialStorageBadRequest",
"details": [],
"message": "The credentials could not be saved. This is due to an internal storage issue in the Microsoft Azure AD service. For information on how to address this issue, please refer to https://go.microsoft.com/fwlink/?linkid=867915",
"target": null,
"innerError": {
"code": "CredentialStorageBadRequest",
"details": [],
"message": "Message:The credentials could not be saved. This is due to an internal storage issue in the Microsoft Azure AD service. For information on how to address this issue, please refer to https://go.microsoft.com/fwlink/?linkid=867915",
"target": null
},
"date": "2021-01-05T15:53:59",
"request-id": "---",
"client-request-id": "---"
}
}
}
When a do a second same call (with MS Graph Explorer, Postman or directly in Python), it works, the second call returns an HTTP 204 like expected ! So I think my request is correct.
This is my implementation (which works because I retry the call a second time…) :
# Default value :
GRAPH_API_URL = "https://graph.microsoft.com/beta/{endpoint}"
class Azure:
# […]
# self._http_headers contains my token to access to MS Graph API
# self._aws_key_id and self._aws_access_key contains AWS credentials
def _save_sync_job_auth(self, principal_id):
self._put(
f"servicePrincipals/{principal_id}/synchronization/secrets",
{"value": [
{"key": "ClientSecret", "value": self._aws_key_id},
{"key": "SecretToken", "value": self._aws_access_key},
]},
retry=1 # If I put 0 here, my script fail
)
# […]
def _put(self, endpoint, json, retry=0):
return self._http_request(requests.put, endpoint, retry, json=json)
# […]
def _http_request(self, func, endpoint, retry=0, **kwargs):
url = GRAPH_API_URL.format(endpoint=endpoint)
response = func(url, headers=self._http_headers, **kwargs)
try:
response.raise_for_status()
except requests.HTTPError as e:
if retry:
logging.warning(f"Error when calling {func.__name__.upper()} {url}")
return self._http_request(func, endpoint, retry - 1, **kwargs)
else:
raise e
return response
Am I missing something ? Have you a solution to remove this "retry hack" ?
I'm creating an application in Azure AD as a daemon to get user phone
authentication methods using the python msal library and calling the following following endpoint GET https://graph.microsoft.com/beta/users/{id | UPN}/authentication/phoneMethods but i get the following error
{
"error": {
"code": "accessDenied",
"message": "Request Authorization failed",
"innerError": {
"message": "Request Authorization failed",
"date": "2020-11-19T19:26:28",
"request-id": "11975e07-ee6b-4bd2-9a74-7c175c5da560",
"client-request-id": "11975e07-ee6b-4bd2-9a74-7c175c5da560"
}
}
}
My app has the required application permissions to get the info i'm looking for, which are UserAuthenticationMethod.Read.All and UserAuthenticationMethod.ReadWrite.All and it already works with different end points such as GET https://graph.microsoft.com/beta/users/{id | UPN}, this is the code i'm using in order to get the access token required and call the graph api
import json
import logging
import requests
import msal
config = {
"authority": "https://login.microsoftonline.com/TENANT_NAME",
"client_id": "APP_ID",
"scope": ["https://graph.microsoft.com/.default"],
"secret": "APP_SECRET",
"endpoint": "https://graph.microsoft.com/beta/users/{USER_ID}/authentication/phoneMethods"
}
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"],
)
result = None
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=config["scope"])
if "access_token" in result:
graph_data = requests.get(
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']}, ).json()
print("Graph API call result: ")
print(json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id"))
i tried to do the same thing using curl or postman and i get the exact same error, so i'm guessing it's an access token issue maybe ?
Thanks in advance
The api call does not support application permissions. You need to grant delegated permissions to the application, and then use the auth code flow to obtain the token.
My security event receiver is set up and I'm at this step trying to test that it actually works. I've copied the code from the example almost exactly, but my script is resulting in an error.
Here's my code:
import requests
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
credentials = service_account.Credentials.from_service_account_file(
'token.json',
scopes=[
'https://www.googleapis.com/auth/risc.verify',
])
authed_session = AuthorizedSession(credentials)
stream_verify_endpoint = 'https://risc.googleapis.com/v1beta/stream:verify'
state = {'state': 'Test token requested.'}
try:
response = authed_session.post(stream_verify_endpoint, json=state)
response.raise_for_status() # Raise exception for unsuccessful requests
except requests.HTTPError as e:
print(e.response.text)
And here's the response text:
{
"error": {
"code": 403,
"message": "The caller does not have permission",
"status": "PERMISSION_DENIED",
"details": [
{
"#type": "type.googleapis.com/google.rpc.DebugInfo",
"detail": "[ORIGINAL ERROR] generic::permission_denied: com.google.apps.framework.request.ForbiddenException: RISC disabled for project number [my project number]"
}
]
}
}
"The caller does not have permission" is not listed as a possible 403 response in the error response reference. The RISC API is absolutely enabled for the given project ID. The service account for token.json is brand new and has Editor permissions. The receiver is able to be registered just fine. Why can I not send test/verify security events?
This was my mistake, I had disabled my receiver endpoint and forgotten about doing so.
If anyone is having the same issue, simply re-enable the endpoint as described here: https://developers.google.com/identity/risc#stop_and_resume_the_event_stream
I'm trying to make a data partition refresh (post) following this azure documentation : https://learn.microsoft.com/en-us/azure/analysis-services/analysis-services-async-refresh
Either with post or get I got 401 Unauthorized (Even when the service is Off !).
I got the token from azure AD (ServicePrincipalCredential).
I added the AD as Analysis Services Admins (https://learn.microsoft.com/en-us/azure/analysis-services/analysis-services-server-admins)
I gave the owner role to AD in Analysis Services IAM.
it worked with Analysis Services management rest api (https://learn.microsoft.com/en-us/rest/api/analysisservices/operations/list) With the same authentification (got code response 200)
My python code :
from azure.common.credentials import ServicePrincipalCredentials
import requests
credentials = ServicePrincipalCredentials(client_id="ad_client_id",
secret="ad_secret",
tenant="ad_tenant")
token = credentials.token
url = "https://westeurope.asazure.windows.net/servers/{my_server}/models/{my_model}/refreshes"
test_refresh = {
"Type": "Full",
"CommitMode": "transactional",
"MaxParallelism": 1,
"RetryCount": 1,
"Objects": [
{
"table": "my_table",
"partition": "my_partition"
}
]
}
header={'Content-Type':'application/json', 'Authorization': "Bearer {}".format(token['access_token'])}
r = requests.post(url=url, headers=header, data=test_refresh)
import json
print(json.dumps(r.json(), indent=" "))
Response I got :
{
"code": "Unauthorized",
"subCode": 0,
"message": "Authentication failed.",
"timeStamp": "2019-05-22T13:39:03.0322998Z",
"httpStatusCode": 401,
"details": [
{
"code": "RootActivityId",
"message": "aab22348-9ba7-42c9-a317-fbc231832f75"
}
]
}
I'm hopeless, could you please give me somes help to make this clear ?
Finally I resolved the issue.
I had wrong token. The api expect an OAuth2.0 authentification token (The Azure analysis services rest api documentation ins't very clear about the way to get one)
For thoses will encounter the same issu there is the way to get one.
from adal import AuthenticationContext
authority = "https://login.windows.net/{AD_tenant_ID}"
auth_context = AuthenticationContext(authority)
oauth_token = auth_context.acquire_token_with_client_credentials(resource="https://westeurope.asazure.windows.net", client_id=AD_client_id, client_secret=AD_client_id)
token = oauth_token['accessToken']
Documentation about this :
https://learn.microsoft.com/en-us/python/api/adal/adal.authentication_context.authenticationcontext?view=azure-python#acquire-token-with-client-credentials-resource--client-id--client-secret-
https://github.com/AzureAD/azure-activedirectory-library-for-python/wiki/ADAL-basics
Most likely your token is not right.
Have you tried validating your token? Use something like http://calebb.net/
I see some examples of ServicePrincipalCredentials that stipulate the context or resource like this:
credentials = ServicePrincipalCredentials(
tenant=options['tenant_id'],
client_id=options['script_service_principal_client_id'],
secret=options['script_service_principal_secret'],
resource='https://graph.windows.net'
Good samples here:
https://www.programcreek.com/python/example/103446/azure.common.credentials.ServicePrincipalCredentials
I think the solution is try a couple more things that make sense and follow the error details.
You need token which has resource (audience) set to https://*.asazure.windows.net
For token validation I like https://jwt.io
Also if you want to automate this properly you have two options
Either by Logic Apps
or with Azure Data Factory
Both of which I have very detailed posts on if you want to check them out
https://marczak.io/posts/2019/06/logic-apps-refresh-analysis-services/
https://marczak.io/posts/2019/06/logic-app-vs-data-factory-for-aas-refresh/
I created a web app in python to copy files between my Google Drive accounts. Public shared files to my account.
I got the following error
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
I tried everything, change scopes, enable SDK in Google Console, etc. The problem is that this error seems to appear only when I am copying some files, and the app works properly for other files, even files in the same account.
I am using pydrive to handle the authentication, following how I am doing it:
def LogIn(self):
extDataDir = os.getcwd()
ext_config = os.path.join(extDataDir, 'client_secrets.json')
dir_path = extDataDir
temp_folder = extDataDir
gauth = GoogleAuth(os.path.join(extDataDir,'settings.yaml'))
gauth.DEFAULT_SETTINGS['client_config_file'] = ext_config
gauth.settings['save_credentials_file'] = os.path.join(temp_folder, "cred_copyfiles.txt")
gauth.LoadCredentialsFile(os.path.join(temp_folder, "cred_copyfiles.txt"))
if gauth.credentials is None:
# Authenticate if they're not there
gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
# Refresh them if expired
try:
gauth.Refresh()
except:
gauth.LocalWebserverAuth()
else:
gauth.Authorize()
return GoogleDrive(gauth)
This is my settings.yaml
client_config_backend: settings
client_config:
client_id: my_clent_di
client_secret: my_client_secret
save_credentials: True
save_credentials_backend: file
save_credentials_file: cred_copyfiles.txt
get_refresh_token: True
oauth_scope:
- https://www.googleapis.com/auth/drive
I copy the files using as example in Google's drive API documentation
drive.auth.service.files().copy(fileId=f['id'],body={"parents": [{"kind": "drive#fileLink","id": save_folder_id}]}).execute()
Again, It seems it is not a problem with authentication, since it works for some files and not for others. Even files in the same account. Does anyone know a solution for this problem?
EDIT: Following the suggestion, I build the authentication using the DriveAPI, by passing the pydrive, and I got the same error.
I found out how to get the request:
drive.auth.service.files().copy(fileId=f['id'],body={"parents": [{"kind": "drive#fileLink","id": save_folder_id}]}).to_json()
Here the request
{"resumable_uri": null, "resumable": null, "uri": "https://www.googleapis.com/drive/v2/files/file_id/copy?alt=json", "body_size": 79, "response_callbacks": [], "body": "{\"parents\": [{\"id\": \"file_id\", \"kind\": \"drive#fileLink\"}]}", "resumable_progress": 0, "_in_error_state": false, "method": "POST", "methodId": "drive.files.copy", "headers": {"user-agent": "google-api-python-client/1.6.1 (gzip)", "content-type": "application/json", "accept-encoding": "gzip, deflate", "accept": "application/json"}}
The most likely explanation for that error message is that you are making a Drive request without an Authorization http header. I suggest try to capture the http request/response that is failing and paste that into your question.