Problems with Google Cloud Platform authentication - c#

we are experiencing problems with API authentication of our project in asp-net core 3.1. Specifically we have integrated the text-to-speech service provided by Google. Locally everything works correctly, but this does not happen when the web-app is online.
try
{
var path = "C://GoogleVoice//food-safety-trainer-47a9337eda0f.json";
var credential = GoogleCredential.FromFile(path);
var storage = StorageClient.Create(credential);
TextToSpeechClient client = TextToSpeechClient.Create();
var test = client.GrpcClient;
// The input can be provided as text or SSML.
SynthesisInput input = new SynthesisInput
{
Text = text
};
VoiceSelectionParams voiceSelection = new VoiceSelectionParams();
voiceSelection.LanguageCode = "it-IT";
voiceSelection.Name = "it-IT-Wavenet-A";
voiceSelection.SsmlGender = SsmlVoiceGender.Female;
// The audio configuration determines the output format and speaking rate.
AudioConfig audioConfig = new AudioConfig
{
AudioEncoding = AudioEncoding.Mp3
};
SynthesizeSpeechResponse response = client.SynthesizeSpeech(input, voiceSelection, audioConfig);
var result = _mp3Helper.SaveFile(response);
if (result.Item1 == "Success")
return Json(new { Result = true, Value = result.Item2 });
else
return Json(new { Result = false, Error = result.ToString() });
}
catch(Exception ex)
{
return Json(new { Result = false, Error = ex.Message.ToString() });
}
The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.

Assuming you want to use the same service account for both Speech and Storage, you need to specify the credentials for the text-to-speech client. Options:
Set the GOOGLE_APPLICATION_DEFAULT_CREDENTIALS environment variable to refer to the JSON file. Ideally, do that as part of deployment configuration rather than in your code, but you can set the environment variable in your code if you want to. At that point, you can remove any explicit loading/setting of the credential for the Storage client.
Specify the CredentialPath in TextToSpeechClientBuilder:
var client = new TextToSpeechClientBuilder { CredentialPath = path }.Build();
This will load a separate credential.
Specify the credential's token access method via the TokenAccessMethod property in TextToSpeechClientBuilder:
var client = new TextToSpeechClientBuilder
{
TokenAccessMethod = credential.GetAccessTokenForRequestAsync
}.Build();

Related

Azure Blob how to properly create and consume a SAS token

Before I begin, allow me to say that I have scoured MSFTs docs, everything seems to imply that I need to manually handroll the GET request? Which seems wrong, given that the SDK handles that for us.
What I am experiencing from my Xamarin app is the following 403 error when I try to run my code to get a list of blobs.
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature.</Message></Error>
The way my workflow goes is as follows:
App Makes request to API to get Azure SAS token
API Responds using the following code to return the SAS token (blobServiceClient is defined using the default emulator storage connection string):
try
{
var client = blobServiceClient.GetBlobContainerClient(request.VenueId);
var permissions = BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List;
var sas = client.GenerateSasUri(permissions, DateTimeOffset.Now.AddHours(1));
var containerUri = "";
#if DEBUG
var temp = sas.AbsoluteUri;
var replaced = temp.Replace("http://127.0.0.1:10000/", "http://myngrokproxy.ngrok.io/");
containerUri = replaced;
#else
containerUri = sas.AbsoluteUri;
#endif
//var sas = containerUri + container.GetSharedAccessSignature(accessPolicy);
return new AzureSASResponse
{
SAS = containerUri
};
} catch (Exception e)
{
return null;
}
As you can see, the replace is there since localhost URL is meaningless for the emulator.
App side I try to consume it as follows:
try
{
var uri = new Uri(SAS);
var containerClient = new BlobContainerClient(uri);
var blobs = containerClient.GetBlobs().AsPages();
foreach(var blob in blobs)
{
Console.WriteLine(blob);
}
} catch (Exception e)
{
Console.WriteLine(e);
}
My resulting SAS token looks like so: "http://myngrokproxy.ngrok.io/devstoreaccount1/8dc9e4831d634629b386680ad7c9a324?sv=2020-08-04&se=2021-10-21T21%3A43%3A16Z&sr=c&sp=rl&sig=oncjUlSLMsOS3WbxUWqjXDp28WACYxxVqUElrK%2BYNlY%3D"
How can I go about A) setting the auth header on it, even the GET request that fails is the .GetBlobs method in the Xamarin app?
After much trial and error my ways to fix it were as follows:
Use latest version of azurite from Microsoft, I used the original old one (Arafuto/azurite)
change code to look as follows;
var sasBuilder = new BlobSasBuilder()
{
BlobContainerName = containerClient.Name,
Resource = "c",
StartsOn = DateTimeOffset.UtcNow.AddMinutes(-15),
ExpiresOn = DateTimeOffset.UtcNow.AddDays(7)
};
sasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.List);
var client = blobServiceClient.GetBlobContainerClient(request.VenueId);
var permissions = BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List;
var sas = client.GenerateSasUri(sasBuilder);
var containerUri = "";
#if DEBUG
var temp = sas.AbsoluteUri;
var replaced = temp.Replace("http://127.0.0.1:10000/", "http://myngrokproxy.ngrok.io/");
containerUri = replaced;
#else
containerUri = sas.AbsoluteUri;
#endif
return new AzureSASResponse
{
SAS = containerUri
};
The inspiration for the BlobSasBuilder came from this document: https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-dotnet#get-a-user-delegation-sas-for-a-container

Google Cloud Platforms Text To Speech API "'Error creating credential from JSON. Unrecognized credential type ."

using (var stream = new FileStream("C:/textToSpeech/client_secret.json", FileMode.Open, FileAccess.Read))
{
var credential = GoogleCredential.FromStream(stream).CreateScoped(LoggingServiceV2Client.DefaultScopes);
var channel = new Grpc.Core.Channel(
LoggingServiceV2Client.DefaultEndpoint.ToString(),
credential.ToChannelCredentials());
var client = await TextToSpeechClient.CreateAsync(channel.ShutdownToken);
//var client = TextToSpeechClient.Create();
var input = new SynthesisInput
{
Text = "This is Demo of the Google Cloud Text-to-Speech API"
};
VoiceSelectionParams voiceSelection = new VoiceSelectionParams
{
LanguageCode = "en-US",
SsmlGender = SsmlVoiceGender.Female,
};
var audioConfig = new AudioConfig
{
AudioEncoding = AudioEncoding.Mp3
};
var response = client.SynthesizeSpeech(input, voiceSelection, audioConfig);
using (var output = File.Create("output.mp3"))
{
response.AudioContent.WriteTo(output);
}
Console.WriteLine("Audio content written to file output.mp3");
}
I want to convert my text to audio text in a form application but I get an error while translating. I signed up for Google Cloud Platform and created my JSON file by doing the necessary actions. I am getting the following error while authorizing the API.You can see the screenshot of the error I got here. I added the necessary things to the environment variables. I tried every solution I found on the internet, but I could not get rid of this error. Error => System.InvalidOperationException: 'Error creating credential from JSON. Unrecognized credential type .'

Why DotNetBrowser not set permission granted in some site?

Create an Engine instance:
engine = EngineFactory.Create(new EngineOptions.Builder
{
RenderingMode = RenderingMode.HardwareAccelerated,
UserDataDirectory = folderBrowser,
LicenseKey = lic,
UserAgent = UA,
GoogleApiKey = "input key",
GoogleDefaultClientId = "put client id",
GoogleDefaultClientSecret = "put secret"
}
.Build());
Grant permission for all permission requests:
engine.Permissions.RequestPermissionHandler =
new Handler<RequestPermissionParameters, RequestPermissionResponse>(p =>
{
return RequestPermissionResponse.Grant();
});
When I check geolocation in https://browserleaks.com/geo or https://geolocation.com/
I see that the geolocation permissions are granted and I see my actual coordinates:
But if I open other web site like https://google.com or https://yandex.ru - I see that permission - denied and geolocation does not work.
To check permission I create the following JS:
string perm = #"
var res;
var test = function(e){res=e};
navigator.permissions.query({ name: 'geolocation' }).then(result => {
test(result.state)
})
res
";
When the Google or Yandex pages are downloaded, I execute this JS for check so:
string permiss = I.ActiveTab.browser.MainFrame.ExecuteJavaScript<string>(perm).Result;
string res = I.ActiveTab.browser.MainFrame.ExecuteJavaScript<string>("res").Result;
For https://browserleaks.com/geo or https://geolocation.com/ I have the "res" variable all time granted, but in Google or Yandex - I have "res" all time denied.
Why so? If I do not create filtr for URL when I create "engine.Permissions.RequestPermissionHandler".
I see that navigate not to page https://browserleaks.com/geo, DotNetBrowser does not go inside this code:
new Handler<RequestPermissionParameters, RequestPermissionResponse>(p =>
{
return RequestPermissionResponse.Grant();
});
and in page all permissions are denied.
What do I need to do to go into RequestPermissionHandler every time for every web page?
problem that geolocation not work in same page, becouse some page not send navigator.geolocation.getCurrentPosition(success, error, options); if navigator.permissions.query({ name: 'geolocation' }) - return denied and not send ask permission for this page, and in DotNetBrowser before sending request all permission is denied.
Now I make so string with js:
public static string askpermissiongeo = #"
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
var crd = pos.coords;
console.log('Your current position is:');
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
window.onload = navigator.geolocation.getCurrentPosition(success, error, options);
";
and inject this code, when need turn on geolocation in some page:
b.InjectJsHandler = new Handler<InjectJsParameters>(args =>
{
IJsObject askperm = args.Frame.ExecuteJavaScript<IJsObject>(askpermissiongeo).Result;
});
after this manipulation DotNetBrowser go to code:
engine.Permissions.RequestPermissionHandler =
new Handler<RequestPermissionParameters, RequestPermissionResponse>(p =>
{
return RequestPermissionResponse.Grant();
});
and all work

Using explicit credentials in a C# dialogflow application

I'm creating a C# application that uses DialogFlow's detectIntent. I need help passing the Google Cloud credentials explicitly.
It works with the GOOGLE_APPLICATION_CREDENTIALS environment variable. However I want to pass the credentials explicitly. I need a C# version of the solution provided here.
I'm using the following quick-start provided with the documentation:
public static void DetectIntentFromTexts(string projectId,
string sessionId,
string[] texts,
string languageCode = "en-US")
{
var client = df.SessionsClient.Create();
foreach (var text in texts)
{
var response = client.DetectIntent(
session: new df.SessionName(projectId, sessionId),
queryInput: new df.QueryInput()
{
Text = new df.TextInput()
{
Text = text,
LanguageCode = languageCode
}
}
);
var queryResult = response.QueryResult;
Console.WriteLine($"Query text: {queryResult.QueryText}");
if (queryResult.Intent != null)
{
Console.WriteLine($"Intent detected: {queryResult.Intent.DisplayName}");
}
Console.WriteLine($"Intent confidence: {queryResult.IntentDetectionConfidence}");
Console.WriteLine($"Fulfillment text: {queryResult.FulfillmentText}");
Console.WriteLine();
}
}
Currently you need to create a gRPC channel directly, and pass that into the client:
GoogleCredential credential = GoogleCredential.FromFile("...");
ChannelCredentials channelCredentials = credential.ToChannelCredentials();
Channel channel = new Channel(SessionsClient.DefaultEndpoint, channelCredentials);
var client = df.SessionsClient.Create(channel);
Very soon, this will be a lot easier via a builder pattern:
var client = new SessionsClientBuilder
{
CredentialsPath = "path to file",
}.Build();
... or various other ways of specify the credential. I'm hoping that'll be out in the next couple of weeks.

Awssdk works on .net dotnetcore (IAM and GatewayAPI) but throws Amazon.CognitoIdentity.Model.NotAuthorizedException on Xamarin Android APP

I have a problem with Awssdk lib from Amazon that I can't understand.
I made an easy Class to authorized and obtain resources from Amazon.
It uses the configuration from user sessionConfig: clientId, identitypoolId,userpoolId, username, password, secret.
And also the request config (signRequest) host, absolutpath, method, region.
var client = AmazonClient(sessionConfig, requestconfig);
With this I can easyly
client.GetClientTokens();
That makes a call to CognitoAuth userpools:
var cred = new CognitoAWSCredentials(_sessionConfig.IdentityPoolId,` RegionEndpoint.EUCentral1);
var provider = new AmazonCognitoIdentityProviderClient(cred, RegionEndpoint.EUCentral1);
CognitoUserPool userPool = new CognitoUserPool(_sessionConfig.UserPoolId, _sessionConfig.ClientId, provider);
CognitoUser user = new CognitoUser(_sessionConfig.UserPoolId, _sessionConfig.ClientId, userPool, provider, _sessionConfig.Secret, _sessionConfig.UserName);
var authRequest = new InitiateSrpAuthRequest()
{
Password = _sessionConfig.Password
};
AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Then I just call
client.GetApiResource(absolutpath);
And I can get with this auth info the resource from the api.
_requestConfig.AbsolutePath = absolutePath;
//Signmethod from Amazon
GetSignedRequest();
var responses = _webRequest.GetResponse();
var result = responses.GetResponseStream();
var data = string.Empty;
using (var sr = new StreamReader(result))
{
data = sr.ReadToEnd();
}
return data;
This code works like a charm on my dotnetcore console app, I become tokens access data and user or other api resources.
When I want to use it on a Xamarin.Android solution.
I become, when trying to get the credentials:
user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Amazon.CognitoIdentity.Model.NotAuthorizedException: Access to
Identity 'eu-central-1:xxxxxxxxxxxxxxxxxxxxx' is forbidden.
System.Net.HttpStatusCode.BadRequest
errorCode "NotAuthorizedException"
The only thing I could see it is different is the UserAgent from provider config:
console program:
aws-sdk-dotnet-coreclr/3.3.11.22 aws-sdk-dotnet-core/3.3.29.12 .NET_Core/4.6.26606.02 OS/Microsoft_Windows_10.0.14393
Xamarin.Android app:
aws-sdk-dotnet-pcl/3.3.4.3 aws-sdk-dotnet-core/3.3.29.13 Mono/5.10.1(tarball) OS/ANDROID_7.0 PCL/Xamarin.Android
Console works xamarin throw this exception. Any ideas?

Categories