Issue with authenticating to google api or issue with app - google-api

So, just a heads up, this is my first time working with google's apis and developer console, so forgive me if I missed something obvious that a more seasoned google developer would deem common sense. That being said. I am trying to create an installed application which will upload a video to youtube under my account. I am writing the application in powershell, so I am importing the appropriate google .Net libraries when the script is launched. From there, I essentially used the sample located here and just converted the content to powershell:
Add-Type -AssemblyName mscorlib
Add-Type -AssemblyName System.Net.Http
Add-Type -AssemblyName System
Add-Type -AssemblyName System.Core
Add-Type -AssemblyName System.Numerics
Add-Type -AssemblyName System.Xml
Add-Type -AssemblyName System.Xml.Linq
Add-Type -AssemblyName System.Data
Add-Type -AssemblyName System.Runtime.Serialization
#the below command imports the following assemblies: Google.Apis.Auth.dll, Google.Apis.Auth.PlatformServices.dll, Google.Apis.Core.dll, Google.Apis.dll, Google.Apis.PlatformServices.dll, Google.Apis.YouTube.v3.dll
Get-ChildItem 'C:\Users\whiggs\Documents\SAPIEN\PowerShell Studio\Projects\youtube\*.dll' | % {[reflection.assembly]::LoadFrom($_.FullName)}
$vid = "C:\Users\whiggs\Documents\gery2.mp4"
#$file = [System.IO.File]::OpenRead("C:\Users\whiggs\Documents\SAPIEN\PowerShell Studio\Projects\youtube\client_id.json")
$filemode = [System.IO.FileMode]::Open
$fileaccess = [System.IO.FileAccess]::Read
$stream = New-object System.IO.FileStream -ArgumentList "C:\Users\whiggs\Documents\SAPIEN\PowerShell Studio\Projects\youtube\client_secret.json", $filemode, $fileaccess
$googlebroker = New-object Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker
$thing = [Google.Apis.Auth.OAuth2.GoogleClientSecrets]::Load($stream)
[string[]]$scope = [Google.Apis.YouTube.v3.YouTubeService+ScopeConstants]::YoutubeUpload
#$scope = [Google.Apis.YouTube.v3.YouTubeService+Scope]::YoutubeUpload
$cancellation = [System.Threading.CancellationToken]::None
$googlebroker = [Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker]::AuthorizeAsync($thing.Secrets, $scope, "<google_username>", $cancellation)
$googlebroker.Wait()
[Google.Apis.Auth.OAuth2.UserCredential]$cred = $googlebroker.Result
$baseclient = new-object Google.Apis.Services.BaseClientService+Initializer
$baseclient.HttpClientInitializer = $cred
$baseclient.ApplicationName = "Contacts Tool"
$service = New-Object Google.Apis.YouTube.v3.YouTubeService($baseclient)
$video = New-Object Google.Apis.YouTube.v3.Data.Video
$video.Snippet = New-Object Google.Apis.YouTube.v3.Data.VideoSnippet
$video.Snippet.Title = "test"
$video.Snippet.Description = "none"
$video.Status = New-Object Google.Apis.YouTube.v3.Data.VideoStatus
$video.Status.PrivacyStatus = "public"
$vidstream = New-Object System.IO.FileStream -ArgumentList $vid, $filemode
$request = $service.Videos.Insert($video, "public", $vidstream, "video/*")
$task = $request.UploadAsync()
$task.Wait()
$vidstream.close()
$vidstream.Dispose()
Don't really need to include the code, because I know it is written correctly as no exception is generated. When I run the above code, it runs to completion without generating an exception, but if I take a look at the object stored in $task (type System.Threading.Tasks.Task), while the overall object reports that it ran to completion, digging deeper into the object's "Result" property reveals the task actually failed, and digging even further into the "exception" property provides the below error message:
The service youtube has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Access Not Configured. YouTube Data API has not been used in project <snip> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=<snip> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry. [403]
Errors [
Message[Access Not Configured. YouTube Data API has not been used in project <snip> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=<snip> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.] Location[ - ] Reason[accessNotConfigured] Domain[usageLimits]
]
at Google.Apis.Upload.ResumableUpload`1.<InitiateSessionAsync>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Upload.ResumableUpload.<UploadAsync>d__70.MoveNext()
So, it is clear that there is some kind of issue with the app as it is configured or the way in which I am authenticating to it. However, I know that the app is at least receiving the requests, as you can see here. So, after doing so research, I have a couple of educated guesses as to what the problem might be, and need some input as to a) which of these (if any) is the actual problem and b) what needs to be done to correct it. My first educated guess involves the parameters I passed to the "AuthorizeAsync" method of the Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker class. According to this document:
"In this sample code a new UserCredential instance is created by calling the GoogleWebAuthorizationBroker.AuthorizeAsync method. This static method gets the client secret (or a stream to the client secret), the required scopes, the user identifier, the cancellation token for cancelling an operation, and an optional data store. If the data store is not specified, the default is a FileDataStore with a default Google.Apis.Auth folder. The folder is created in Environment.SpecialFolder.ApplicationData."
The part I want to focus on in the above statement is "the user identifier", as that is all the information that provided as to this parameter's description.
The value that I put in was a string containing the user name for the google account that the app is registered under and the account that would upload the youtube videos, but I don't know if that was the value that was needed, as I had to login to the account anyway via a web browser as part of this process. If this is indeed the problem, what is "the user identifier" as far as this parameter is concerned. A little more detail in the documentation can go a long way. My second educated guess as to what is causing this has to do with the configuration of the application, but more specifically, the generated oauth credentials. The scopes that the app would need access to are apparently considered sensitive, and, if I am understanding this correctly, I have to authenticate from a verified domain and configure a bunch of advanced settings that, as someone writing this project for myself and not a company, I just do not have access to. I just want to upload a youtube video to my account, so why do I need to authenticate from a verified domain? What can I do to get around this? Any info would be great.

Correcting error in your understanding
"<google_username>" is used by filedatastore to store the credeitals for the user once they have consented access to your client. If you want to understand more about this then you should try and read my tutorial on file datastore
$googlebroker = [Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker]::AuthorizeAsync($thing.Secrets, $scope, "<google_username>", $cancellation)
Answer for your issue
YouTube Data API has not been used in project before or it is disabled.
Means that you have not enabled the YouTube api in your project on google Developer console or you have not applied and been granted any quota to this api yet. In Google developer console go to API Library -> YouTube Data API v3 and enable it. Once you have done that click manage then go to Quota. If you have not previously enabled it which i suspect you hadn't then now you will have 0 quota.
click the penile icon and apply for a quota for this api. It can take a while to get a response.

That error message simply means that you have not enabled the API in the Cloud Console. Can you post the error message you get, after you enabled the API? Also, make sure you're running the script with the credentials for the right project. You can run glcoud config list to see which project you're using.

Related

How give trust to an external application accessing the Outlook Object Model (with all security options on)

I have a .NET application that interacts with Outlook like this:
Microsoft.Office.Interop.Outlook.Application app = new
Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem item = app.CreateItem((Microsoft.Office.Interop.Outlook.OlItemType.olMailItem));
item.PropertyAccessor.SetProperty(PsInternetHeaders + Foobar, 1031);
item.BodyFormat = Microsoft.Office.Interop.Outlook.OlBodyFormat.olFormatHTML;
item.To = "a#test.com;b#test.com;c#test.com";
item.BCC = "cc#test.com";
item.Body = "Hello There!";
item.Display();
Be aware that I need to access the "PropertyAccessor" property.
In a normal environment this runs fine, but in a "secure" enviroment with this registry keys in place it just fails with Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT)):
[HKEY_CURRENT_USER\Software\Policies\Microsoft\office\16.0\outlook\security]
"PromptOOMAddressBookAccess"=dword:00000000
"AdminSecurityMode"=dword:00000003
"PromptOOMAddressInformationAccess"=dword:00000000
Outlooks security model seems to have a "trustedaddins" list, but I'm not really sure if this applies to "external applications" as well and that exactly I need to register unter TrustedAddins (see here).
My main question would be: Can I just register and foobar.exe unter trustedaddins or is this not possible at all?
I know that I could lower or disable the security stuff, but this is not my choice ;)
Your only options are listed at How to avoid Outlook Security Alert when sending Outlook message from VBScript?
You also might want to set PsInternetHeaders properties to strings only, not ints.

BotFramework TurnContext SendActivityAsync "Object reference not set to an instance of an object"

I'm trying to use botframework v4 in Azure Functions Powershell. I have this working successfully by just calling the raw REST APIs and using the botframework types like Activity.
Now I'm trying to actually use the framework and adapters proper. However, when I call SendActivityAsync on the Turn Context, I get "Object reference not set to an instance of an object" and really no way to find out where that's coming from.
Is there anything obviously missing here, or perhaps another approach to using BotFrameWork adapter I'm missing? I'm trying to adapt the EchoBot sample to Powershell, as the ConsoleBot sample doesn't call http back to the bot framework.
Assume that Activity is real, I know that's not where my null is coming from(it wouldn't let me create the turncontext if it was)
$activity = [JsonConvert]::DeserializeObject(($QueueItem -replace '^---JSON---',''), [activity])
#Only Process Message Activities for now
if ($activity.Type -ne 'message') {return}
$reply = $activity.CreateReply("I got your message that says $($activity.text)")
$appCredentials = [MicrosoftAppCredentials]::new('c28d55e3-fb0b-4367-b4a6-f00959a54e5b','n=_y:3LsJo/MYAPPSECRETP5')
$botFrameworkAdapter = [BotFrameworkAdapter]::new($appCredentials, [AuthenticationConfiguration]::new())
$turnContext = [TurnContext]::new($botFrameworkAdapter, $Activity)
$turnContext.SendActivityAsync($reply).GetAwaiter().GetResult()

Issue with authenticating to google api or app misonfiguration

So, just a heads up, this is my first time working with google's apis and developer console, so forgive me if I missed something obvious that a more seasoned google developer would deem common sense. That being said. I am trying to create an installed application which will upload a video to youtube under my account. I am writing the application in powershell, so I am importing the appropriate google .Net libraries when the script is launched. From there, I essentially used the sample located here and just converted the content to powershell:
Add-Type -AssemblyName mscorlib
Add-Type -AssemblyName System.Net.Http
Add-Type -AssemblyName System
Add-Type -AssemblyName System.Core
Add-Type -AssemblyName System.Numerics
Add-Type -AssemblyName System.Xml
Add-Type -AssemblyName System.Xml.Linq
Add-Type -AssemblyName System.Data
Add-Type -AssemblyName System.Runtime.Serialization
#the below command imports the following assemblies: Google.Apis.Auth.dll, Google.Apis.Auth.PlatformServices.dll, Google.Apis.Core.dll, Google.Apis.dll, Google.Apis.PlatformServices.dll, Google.Apis.YouTube.v3.dll
Get-ChildItem 'C:\Users\whiggs\Documents\SAPIEN\PowerShell Studio\Projects\youtube\*.dll' | % {[reflection.assembly]::LoadFrom($_.FullName)}
$vid = "C:\Users\whiggs\Documents\gery2.mp4"
#$file = [System.IO.File]::OpenRead("C:\Users\whiggs\Documents\SAPIEN\PowerShell Studio\Projects\youtube\client_id.json")
$filemode = [System.IO.FileMode]::Open
$fileaccess = [System.IO.FileAccess]::Read
$stream = New-object System.IO.FileStream -ArgumentList "C:\Users\whiggs\Documents\SAPIEN\PowerShell Studio\Projects\youtube\client_secret.json", $filemode, $fileaccess
$googlebroker = New-object Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker
$thing = [Google.Apis.Auth.OAuth2.GoogleClientSecrets]::Load($stream)
[string[]]$scope = [Google.Apis.YouTube.v3.YouTubeService+ScopeConstants]::YoutubeUpload
#$scope = [Google.Apis.YouTube.v3.YouTubeService+Scope]::YoutubeUpload
$cancellation = [System.Threading.CancellationToken]::None
$googlebroker = [Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker]::AuthorizeAsync($thing.Secrets, $scope, "<google_username>", $cancellation)
$googlebroker.Wait()
[Google.Apis.Auth.OAuth2.UserCredential]$cred = $googlebroker.Result
$baseclient = new-object Google.Apis.Services.BaseClientService+Initializer
$baseclient.HttpClientInitializer = $cred
$baseclient.ApplicationName = "Contacts Tool"
$service = New-Object Google.Apis.YouTube.v3.YouTubeService($baseclient)
$video = New-Object Google.Apis.YouTube.v3.Data.Video
$video.Snippet = New-Object Google.Apis.YouTube.v3.Data.VideoSnippet
$video.Snippet.Title = "test"
$video.Snippet.Description = "none"
$video.Status = New-Object Google.Apis.YouTube.v3.Data.VideoStatus
$video.Status.PrivacyStatus = "public"
$vidstream = New-Object System.IO.FileStream -ArgumentList $vid, $filemode
$request = $service.Videos.Insert($video, "public", $vidstream, "video/*")
$task = $request.UploadAsync()
$task.Wait()
$vidstream.close()
$vidstream.Dispose()
Don't really need to include the code, because I know it is written correctly as no exception is generated. When I run the above code, it runs to completion without generating an exception, but if I take a look at the object stored in $task (type System.Threading.Tasks.Task), while the overall object reports that it ran to completion, digging deeper into the object's "Result" property reveals the task actually failed, and digging even further into the "exception" property provides the below error message:
The service youtube has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Access Not Configured. YouTube Data API has not been used in project <snip> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=<snip> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry. [403]
Errors [
Message[Access Not Configured. YouTube Data API has not been used in project <snip> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=<snip> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.] Location[ - ] Reason[accessNotConfigured] Domain[usageLimits]
]
at Google.Apis.Upload.ResumableUpload`1.<InitiateSessionAsync>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Google.Apis.Upload.ResumableUpload.<UploadAsync>d__70.MoveNext()
So, it is clear that there is some kind of issue with the app as it is configured or the way in which I am authenticating to it. However, I know that the app is at least receiving the requests, as you can see here. So, after doing so research, I have a couple of educated guesses as to what the problem might be, and need some input as to a) which of these (if any) is the actual problem and b) what needs to be done to correct it. My first educated guess involves the parameters I passed to the "AuthorizeAsync" method of the Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker class. According to this document:
"In this sample code a new UserCredential instance is created by calling the GoogleWebAuthorizationBroker.AuthorizeAsync method. This static method gets the client secret (or a stream to the client secret), the required scopes, the user identifier, the cancellation token for cancelling an operation, and an optional data store. If the data store is not specified, the default is a FileDataStore with a default Google.Apis.Auth folder. The folder is created in Environment.SpecialFolder.ApplicationData."
The part I want to focus on in the above statement is "the user identifier", as that is all the information that provided as to this parameter's description.
The value that I put in was a string containing the user name for the google account that the app is registered under and the account that would upload the youtube videos, but I don't know if that was the value that was needed, as I had to login to the account anyway via a web browser as part of this process. If this is indeed the problem, what is "the user identifier" as far as this parameter is concerned. A little more detail in the documentation can go a long way. My second educated guess as to what is causing this has to do with the configuration of the application, but more specifically, the generated oauth credentials. The scopes that the app would need access to are apparently considered sensitive, and, if I am understanding this correctly, I have to authenticate from a verified domain and configure a bunch of advanced settings that, as someone writing this project for myself and not a company, I just do not have access to. I just want to upload a youtube video to my account, so why do I need to authenticate from a verified domain? What can I do to get around this? Any info would be great.

Assigning Permission to Certificate's Private Key via Powershell (Win 2012 R2)

On a Windows Server 2012 R2 machine attached to a domain, I am running the following statements:
$target_machine_fqdn = [System.Net.Dns]::GetHostByName($env:computerName)
$certificate_request = Get-Certificate `
-Template 'AcmeComputer' `
-DnsName $target_machine_fqdn `
-CertStoreLocation 'Cert:\LocalMachine\My'
I'm requesting a certificate for the host from the domain's CA. The statement returns with no error. A certificate is generated for the machine and placed in it's "Cert:\LocalMachine\My" as requested.
Problem: I can't figure out how to grant a service account rights to the certificate's private key.
Now, there are about 1,000 articles instructing people how to grant permission by retrieving the UniqueKeyContainerName with code that starts like the following:
$certificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
That won't work here. While the certificate has a private key, the private key data member is null:
In the cases where the solution I just eluded to works, the private key is on the file system. However, in this case, the private key is in the registry at the following:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\MY\Keys
When using the Certificates MMC-snapin, I can see the certificate. I can manage permissions on the private key. So, I know it's there. Unfortunately, I need to automate the permission assignment so using the Certificates MMC-snapin isn't an option. I need to do this through Powershell some how.
I recently went through automating access to certificate private key myself. I too found a number of places telling me to modify the ACLs of the key data on the hard drive, but that was not satisfying since when I checked the permissions to the private key using PowerShell the user I added wasn't listed. So much web searching, a few articles, and a fair bit of trial and error led me to this.
I start by defining the user object, and the access that I want to grant them:
# Create NTAccount object to represent the account
$AccountName = 'Domain\UserName'
$User = New-Object System.Security.Principal.NTAccount($AccountName)
# Define AccessRule to be added to the private key, could use 'GenericRead' if all you need is read access
$AccessRule = New-Object System.Security.AccessControl.CryptoKeyAccessRule($User, 'FullControl', 'Allow')
Then I open the local machine certificate store as Read/Write, and find the certificate that I'm looking for:
# Define the thumbprint of the certificate we are interested in
$Thumb = '63CFDDE9A748345CD77C106DAA09B805B33951BF'
# Open Certificate store as read/write
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine")
$store.Open("ReadWrite")
# Look up the certificate's reference object in the store
$RWcert = $store.Certificates | where {$_.Thumbprint -eq $Thumb}
Then I make a new CSP (Crypto Service Provider) parameter set, based off the existing certificate, add the new access rule to the parameter set.
# Create new CSP parameter object based on existing certificate provider and key name
$csp = New-Object System.Security.Cryptography.CspParameters($RWcert.PrivateKey.CspKeyContainerInfo.ProviderType, $RWcert.PrivateKey.CspKeyContainerInfo.ProviderName, $RWcert.PrivateKey.CspKeyContainerInfo.KeyContainerName)
# Set flags and key security based on existing cert
$csp.Flags = "UseExistingKey","UseMachineKeyStore"
$csp.CryptoKeySecurity = $RWcert.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity
$csp.KeyNumber = $RWcert.PrivateKey.CspKeyContainerInfo.KeyNumber
# Add access rule to CSP object
$csp.CryptoKeySecurity.AddAccessRule($AccessRule)
Then we instantiate a new CSP, with those parameters, which will apply the new access rule to the existing certificate based off the flags we defined, and the key info we gave it.
# Create new CryptoServiceProvider object which updates Key with CSP information created/modified above
$rsa2 = New-Object System.Security.Cryptography.RSACryptoServiceProvider($csp)
Then we just close the certificate store, and we're all done.
# Close certificate store
$store.Close()
Edit: After looking around I realized that I had a couple certs that are the same. I believe that this is due to a non-RSA cipher being used to encrypt the private key. I used some of the info from this answer that explains how to work with a third party CNG crypto provider. I didn't like having to download an assembly to do the things in that answer, but I used a little bit of the code to get the path to the key (yes, there is a key on the drive), and added an ACL to the file, which did work for delegating rights to the private key. So here's what I did...
First, we verify that the certificate has a CNG based key:
[Security.Cryptography.X509Certificates.X509CertificateExtensionMethods]::HasCngKey($Certificate)
If that returns True then we're a go to move on past that. Mine did, I'm guessing yours will too. Then we find that key on the hard drive by reading the PrivateKey data (which is missing from $Certificate), and getting the UniqueName for it, and then searching the Crypto folder for that file.
$privateKey = [Security.Cryptography.X509Certificates.X509Certificate2ExtensionMethods]::GetCngPrivateKey($Certificate)
$keyContainerName = $privateKey.UniqueName
$keyMaterialFile = gci $env:ALLUSERSPROFILE\Microsoft\Crypto\*Keys\$keyContainerName
Then I grabbed the current ACLs for the file, made up a new AccessRule to give the desired user access to the file, added the rule to the ACLs I just grabbed, and applied the updated ACL back to the file.
$ACL = Get-Acl $keyMaterialFile
$AccountName = 'Domain\User'
$User = New-Object System.Security.Principal.NTAccount($AccountName)
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($User,'FullControl','None','None','Allow')
$ACL.AddAccessRule($AccessRule)
Set-Acl -Path $keyMaterialFile -AclObject $ACL
After that I was able to look in certlm.msc and verify that the user had rights to the private key.
Dependency Update: Looks like Microsoft now publishes Security.Cryptography.dll, so you don't have to compile it off GitHub. If you have the AzureRM module installed you can find the DLL in a number of the component modules (I grabbed it from AzureRM.SiteRecovery).
The TheMadTechnician answered this question like a mf'n champ. Should he ever need me to help him bury a body, he need only call. I am adding to his answer with details for folks that cannot build/deploy the assembly
NOTE: The clrsecurity project had been posted to CodePlex, which was shutdown in 2017. The project was moved to github where it can be downloaded. The clrsecurity assembly referenced in the post is no longer supported.
Also, credit to Vadims Podāns (Crypt32) who wrote the article
Retrieve CNG key container name and unique name, which helps readers access the CNG private key using unmanaged code in Powershell.
If you are like me and cannot use the clrsecurity assembly, the .NET 4.5.6 framework introduced a elements we can leverage. Consider the following:
## Identify the certificate who's private key you want to grant
## permission to
$certificate = $(ls 'cert:\LocalMachine\My\C51280CE3AD1FEA848308B764DDCFA7F43D4AB1A')
## Identify the user you'll be granting permission to
$grantee_name = 'foo\lordAdam'
$grantee = New-Object System.Security.Principal.NTAccount($grantee_name)
## Get the location and permission-of the cert's private key
$privatekey_rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($certificate)
$privatekey_file_name = $privatekey_rsa.key.UniqueName
$privatekey_path = "${env:ALLUSERSPROFILE}\Microsoft\Crypto\Keys\${privatekey_file_name}"
$privatekey_file_permissions = Get-Acl -Path $privatekey_path
## Grant the user 'read' access to the key
$access_rule = New-Object System.Security.AccessControl.FileSystemAccessRule($grantee, 'Read', 'None', 'None', 'Allow')
$privatekey_file_permissions.AddAccessRule($access_rule)
Set-Acl -Path $privatekey_path -AclObject $privatekey_file_permissions
We're using the GetRSAPrivateKey() method of the System.Security.Cryptography.X509Certificates.RSACertificateExtensions static class to return us the private key. We then grab the UniqueName (Key property has a UniqueName property). We use that to deduce the key file's location. The rest is granting file permissions.
If you want to see where private keys are stored, check out Key Storage and Retrieval.

"Insufficient permissions" on google calendar api's acl.list

I'm getting Insufficient permissions when trying to call the acl.list method of the google calendar api via python.
service.acl().list(calendarId='primary').execute();
*** HttpError: <HttpError 403 when requesting https://www.googleapis.com/calendar/v3/calendars/primary/acl?alt=json returned "Insufficient Permission">
I'm using the scope 'https://www.googleapis.com/auth/calendar' as recommended in the documentation. Additionally, other API methods do work, for example service.calendarList
service.calendarList().list(pageToken=page_token).execute()
What am I missing?
Here is the code I'm using based almost entirely on the sample they provide:
import sys
from oauth2client import client
from googleapiclient import sample_tools
def main(argv):
# Authenticate and construct service.
# import pdb;pdb.set_trace()
service, flags = sample_tools.init(
argv, 'calendar', 'v3', __doc__, __file__,
# scope='https://www.googleapis.com/auth/calendar.readonly')
scope='https://www.googleapis.com/auth/calendar')
try:
page_token = None
while True:
calendar_list = service.calendarList().list(pageToken=page_token).execute()
for calendar_list_entry in calendar_list['items']:
print calendar_list_entry['summary']
page_token = calendar_list.get('nextPageToken')
service.acl().list(calendarId='primary').execute();
if not page_token:
break
except client.AccessTokenRefreshError:
print ('The credentials have been revoked or expired, please re-run'
'the application to re-authorize.')
if __name__ == '__main__':
main(sys.argv)
You might have to delete existing credentials, in the form of .json files. I had a similar "Insufficient permissions" problem, and I had to delete stored credentials. I had the additional problem that because of trying out some of Google's scripts in their tutorials, unknowingly I had credentials stored in a hidden .credentials folder in my home directory (users/home). Since they were hidden, I had to look for them through Terminal (on Mac), and delete them there. Once deleted, the problem was solved, since I could create new and proper credentials, suitable for the scope of my new script.
Something is wrong with your authentication. Insufficent permissions means that you don't have access.
I can verify that the scope https://www.googleapis.com/auth/calendar is enough to display ACL.list on the primary calendar.
You have to find the location of "calendar-dotnet-quickstart.json" file and delete it. I used .NET example and I have to debug the following code the find exact location.
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json");
Then change scope as bellow and rebuild the solution.
string[] scopes = { CalendarService.Scope.Calendar};
You will notice that google will ask to confirm the access again.

Resources