Google Mapsengine responding insufficient permissions to service account - node.js

I am trying to create tables for a google map in the maps engine. I have added the service account to the access list in the mapsengine admin panel for the map and gave it "can edit" permissions. I also gave it edit permissions in the developer console for the project.
this is where I am sending off for the access token which is sending back a token:
var googleapis = require('googleapis');
function connect() {
var authClient = new googleapis.auth.JWT(
'216755859529-1s2o9qofhd9ea65ang9clpd1936ldfcr#developer.gserviceaccount.com',
'../bin/googleoauth2.pem',
'notasecret',
['https://www.googleapis.com/auth/mapsengine'],
// User to impersonate (leave empty if no impersonation needed)
''
);
authClient.authorize(function(err, tokens) {
if (err) {
console.log(err);
return;
}
else {
console.log(tokens);
}
googleapis.discover('mapsengine', 'v1').execute(function (err, client) {
if (err) {
console.log('Problem during the client discovery.', err);
return;
}
createNewTable();
client.mapsengine.tables.create(mapengine_table_body).withAuthClient(authClient).execute(function (err, response) {
if (err) {
console.log(err);
return;
} else {
console.log(response);
return;
}
});
});
});
}
This is where I am creating the table and sending it:
function createNewTable() {
mapengine_table_body = {
"projectId": projectID,
"name": "World Famous Mountains",
"description": "A partial list of famous mountains in the world.",
"draftAccessList": "Map Editors",
"tags": [
"mountain",
"high places"
],
"schema": {
"columns": [
{
"name": "geometry",
"type": "points"
},
{
"name": "mountain_name",
"type": "string"
},
{
"name": "height",
"type": "integer"
}
]
}
}
}
function start() {
'use strict';
var pck, program;
pck = require('../package.json');
program = require('commander');
program
.version(pck.version)
.option('-r, --run', 'Run')
.parse(process.argv);
console.log('running:');
if (program.run) {
connect();
}
}
The ProjectId I am getting from the url when viewing the project. I have looked through as much documentation as I can find, but I haven't been able to figure this one out. Thanks.

Without your error response I can't give you an exact answer, but here are a couple of pointers.
Check the contents of err in the execute block. The API will return something in err.errors that should explain what the problem is, if it's occurring on the API side.
It's not clear what the scope of the mapengine_table_body variable is, try logging it right in the connect() call right after calling createNewTable() to make sure you have the actual data.
The third argument in the googleapis.auth.JWT constructor (at least according to this) is not the key password, it's an alternative way to provide the actual key inline (as opposed to using the file location in argument #2).
Project IDs in Maps Engine may look like large numbers but treating them as large numbers in JavaScript will very likely result in rounding, meaning that you give the API a different number than is in your code. To prevent this, make sure your project ID is "quoted", so that its treated as a string.
Hopefully something here helps! If not, please share the output from suggestion #1.

Related

Azure Static Web App Role Functions Not Working

I've made an attempt to get Azure Static Web Apps with customized Roles function to work in my environment just as specified by: https://learn.microsoft.com/en-us/azure/static-web-apps/assign-roles-microsoft-graph
Everything seems to work as expected but when visiting the page restricted by a specific role the API doesn't seem to be assigning the expected role.
I've modified the API and removed all the logic to assign a role to everyone logging in and still doesn't work. Here's the modified code:
const fetch = require('node-fetch').default;
module.exports = async function (context, req) {
const user = req.body || {};
const roles = [];
roles.push('superuser');
context.res.json({
roles
});
}
Here's my staticwebapp.config.json file:
{
"auth": {
"rolesSource": "/api/GetRoles",
"identityProviders": {
"azureActiveDirectory": {
"userDetailsClaim": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"registration": {
"openIdIssuer": "https://login.microsoftonline.com/44263d43-a2f0-45a8-8f55-9b100ecfb4dc",
"clientIdSettingName": "AAD_CLIENT_ID",
"clientSecretSettingName": "AAD_CLIENT_SECRET"
},
"login": {
"loginParameters": ["resource=https://graph.microsoft.com"]
}
}
}
},
"routes": [
{
"route": "/secured/*",
"allowedRoles": ["superuser"]
},
{
"route": "/admin/*",
"allowedRoles": ["administrator"]
},
{
"route": "/contributors/*",
"allowedRoles": ["contributor", "Contributor"]
}
],
"responseOverrides": {
"401": {
"redirect": "/.auth/login/aad?post_login_redirect_uri=.referrer",
"statusCode": 302
}
}
}
I've tried changing the order of the config file. My last attempt before posting was to remove all logic and just assign everyone the 'superuser' role.
Everyone can login successfully & pre-defined roles work like a charm but no one ever gets the 'superuser' role.
I'm trying to figure out what I'm doing wrong or has Azure Static Web Apps changed so that this code just won't work like it did a year ago?
Thank you help in advance.

Why can't Clarifai validate model output request with API key generated in the Clarifai Portal or with the Personal Access token?

Update
I'm able to get my original code, and the suggestions as well working when running it in isolation. However, what I need to do is call it from within a Firebase onRequest or onCall function. When this code gets wrapped by these, the malformed headers and request for authorization are still an issue. We use many other APIs this way so it's puzzling why the Clarifiai API is having these issues. Any suggestions on using it with Firebase?
Original
New to Clarifai and having some authentication issues while attempting to retrieve model outputs from the Food Model.
I've tried two different keys:
API key generated from an app I created in the Portal
API key - the Personal Access Token I generated for myself
In both cases I encounter an Empty or malformed authorization header response.
{
"status":{
"code":11102,
"description":"Invalid request",
"details":"Empty or malformed authorization header. Please provide an API key or session token.",
"req_id":"xyzreasdfasdfasdfasdfasf"
},
"outputs":[
]
}
I've following the following articles to piece together this code. This is running in a Node 10 environment.
Initialization
Food Model
Prediction
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key xyzKey");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
resolve(JSON.stringify(response));
}
);
});
}
Update: There was an issue in versions prior to 7.0.2 where, if you had another library using #grpc/grpc-js with a different version, the grpc.Metadata object wasn't necessarily constructed from the library version that clarifai-grpc-nodejs was using.
To fix the issue, update the clarifai-grpc-nodejs library, and require the grpc object like this:
const {ClarifaiStub, grpc} = require("clarifai-nodejs-grpc");
Previously, the grpc object was imported directly from #grpc/grpc-js, which was the source of the problem.
There are two ways of authenticating to the Clarifai API:
with an API key, which is application-specific, meaning that an API key is attached to an application and can only do operations inside that application,
with a Personal Access Token (PAT), which is user-specific, which means you can assess / manipulate / do operations on all the applications the user owns / has access to (and also create/update/delete applications themselves).
When using a PAT, you have to specify, in your request data, which application you are targeting. With an API key this is not needed.
I've tested your example (using Node 12, though it should work in 10 as well) with a valid API key and it works fina (after putting it into an async function). Here's a full runnable example (replace YOUR_API_KEY with your valid API key).
function predict() {
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key YOUR_API_KEY");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
resolve(JSON.stringify(response));
}
);
});
}
async function main() {
const response = await predict();
console.log(response);
}
main();
If you want to use a PAT in the above example, two things must change. Firstly, replace the API key with a PAT:
...
metadata.set("authorization", "Key YOUR_PAT");
...
To the method request object, add the application ID.
...
stub.PostModelOutputs(
{
user_app_id: {
user_id: "me", // The literal "me" resolves to your user ID.
app_id: "YOUR_APPLICATION_ID"
},
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
...
Make sure that you have respected the format to pass the key in your code as such:
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {YOUR_CLARIFAI_API_KEY}");
Make sure that "Key" is present.
Let me know.
EDIT: So looks like Firebase doesn't support custom headers. This is likely impacting the 'Authorization' header. At least this is my best guess. See the comments in the following ticket.
Firebase hosting custom headers not working
The following code works for me:
{
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {APP API KEY}");
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
console.log(JSON.stringify(response));
resolve(JSON.stringify(response));
}
);
});
}
There was a missing { although I'm not sure if that is what is reflected in the actual code you are running. I'm using in this case an APP API Key (when you create an App, there will be an API Key on the Application Details page.
It sounds like you might be using a Personal Access Token instead, which can be used like this:
{
const { ClarifaiStub } = require('clarifai-nodejs-grpc');
const grpc = require('#grpc/grpc-js');
const stub = ClarifaiStub.json();
const metadata = new grpc.Metadata();
metadata.set("authorization", "Key {Personal Access Token}"); // Sounds like you've made the personal access token correctly - go into settings, then authentication, then create one. Make sure it has proper permissions (I believe all by default).
return new Promise((resolve, reject) => {
stub.PostModelOutputs(
{
user_app_id: {
user_id: "{USER ID}", // I used my actual ID, I did not put 'me'. You can find this under your profile.
app_id: "{APP NAME}" // This is the app ID found in the upper left corner of the app after it is created - not the API Key. This is generally what you named the app when you created it.
},
model_id: 'bd367be194cf45149e75f01d59f77ba7',
inputs: [{ data: { image: { url: 'https://samples.clarifai.com/metro-north.jpg' } } }],
},
metadata,
(err, response) => {
if (err) {
return reject(`ERROR: ${err}`);
}
console.log(JSON.stringify(response));
resolve(JSON.stringify(response));
}
);
});
}
Make sure to fill out the: {Personal Access Token}, {USER ID} and {APP NAME}. I used my actual user id (found in the profile), and the app name is not the API Key for the app, but the name in the upper left corner when you're on the Application details page. This call worked for me.

"One or more parameter values were invalid: Missing the key studentId in the item"

I'm using serverless to expose HTTP request in getwayapi, lambda function and dynamodb but got an error "One or more parameter values were invalid: Missing the key studentId in the item".
Please help me!
Here my code in app.js
app.post('/students', function (req, res) {
const body = req.body;
const params = {
TableName: STUDENTS_TABLE,
Item: {
"studentId": body.studentId,
"address": body.address,
"birth": body.birth,
"class": body.class,
"mail": body.mail,
"name": body.name,
"phone": body.phone,
"sex": body.sex,
}
}
dynamoDb.put(params, function (err, data) {
if (err) {
res.send({
success: false,
message: err
});
} else {
res.send({
success: true,
message: 'Created!'
});
}
});
});
As user mailtobash said, we are missing a little bit of context to answer your question accurately. Can you add what is inside req.body when you send a request to your POST /students endpoint?
You can get that value printed in your terminal when you send a request if you use console.log(req.body) in the code of your endpoint. If you can't see logs in your development environment, you can have the lambda return req.body before executing the rest of your code like so:
return res.send({
success: false,
requestBody: req.body
})
You will then be able to inspect that response in Postman (https://www.getpostman.com/) or in your client (if you it's a web-based application, you can go into the dev tools of your browser and look at the details of the request in the Network tab). Knowing what is in requestBody will be very helpful.
In any case, the error message indicates that studentId is the partition key of STUDENTS_TABLE and it is missing. Partition keys are required and must be unique in a DynamoDB table. Additionally, if you are using an existing value, dynamoDB.put will overwrite the existing record (but that behavior wouldn't trigger an error).
It seems very likely that the reason why you get that error message from DynamoDB is because req.body.studentId is either undefined, an empty string (.ie., ""), or any other value that DynamoDB would consider as "missing" when it comes to set the value of a partition key.
Don't hesitate to take a look at AWS documentation on primary keys: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey

how to add update multiple response of a dialog node in IBM watson assistant with Nodejs

I have a node application which is interacting with IBM watson assistant.
I need to update the response output of a dialog node and I'm using the following watson api
var params = {
workspace_id: //,
dialog_node: 'greeting',
new_dialog_node: 'greeting',
new_output: {
text: 'Hello! What can I do for you?'
//add more than one text
}
};
assistant.updateDialogNode(params, function(err, response) {
if (err) {
console.error(err);
} else {
console.log(JSON.stringify(response, null, 2));
}
});
the API only accepts object type text:'Hello! What can I do for you?' this also overwrites the previous response
the error [ { message: 'output should be of type Object', path: '.output' } ]
How can I update the Dialog and add multiple responses at the same time or update the existing one?
thanks in advance!
Have you tried the following format for new_output?
{
"text": {
"values": [
"first response",
"second response"
],
"selection_policy": "sequential"
}

Inserting Google Analytics Content Experiments using the Node.JS Client Library

I'm trying to configure a content experiment using the Node.js Client Library, and have not been able to work out the syntax. Where do I put the body (an Experiment resource) as described here?
https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtExperimentsGuide#insert
This code, for listing existing experiments, works as expected:
var listExperiments = function(){
googleapis
.discover('analytics', 'v3')
.execute(function(err, client) {
var request = client
.analytics.management.experiments.list({
accountId : accountId,
webPropertyId : webPropertyId,
profileId : profileId
})
.withApiKey(browserAPIKey)
.withAuthClient(oauth2Client)
request.execute(function(err,result){
if (err){
console.log(err);
res.send(402);
} else {
console.log(result);
res.send(200);
}
});
});
}
However, when I try to insert a new experiment thusly, I receive a "Field resource is required" error.
var body = {
"name": "myExperimentName",
"status": "READY_TO_RUN",
"objectiveMetric":"ga:bounces",
"variations": [
{ "name": "text1", "url":"http://www.asite.net", "status":"ACTIVE" },
{ "name": "text2", "url":"http://www.asite.net", "status":"ACTIVE" }
]
};
var insertExperiment = function(){
googleapis
.discover('analytics', 'v3')
.execute(function(err, client) {
var request = client
.analytics.management.experiments.insert({
accountId : accountId,
webPropertyId : webPropertyId,
profileId : profileId,
resource : body
})
.withApiKey(browserAPIKey)
.withAuthClient(oauth2Client)
request.execute(function(err,result){
if (err){
console.log(err);
res.send(402);
} else {
console.log(result);
res.send(200);
}
});
});
}
I've tried a few configurations. Management API writes are in limited beta, but I have beta access, so that's not the problem. I've tried inserting the new experiment information directly into the insert() object, calling the experiment info object "body : body " instead of "resource : body", JSON.stringifying the body, and a few other configurations. No luck.
Any help would be great!
I'm aware of this answer, but it uses the Javascript Client Library and makes RESTful requests, whereas I'd like to use the Node Library.
EDIT: Thanks to Burcu Dogan at Google. Here's the correct syntax:
.analytics.management.experiments.insert({
accountId : accountId,
webPropertyId : webPropertyId,
profileId : profileId
}, body)

Resources