I'm having trouble using the meteor slingshot component with the S3 with temporary AWS Credentials component. I keep getting the error Exception while invoking method 'slingshot/uploadRequest' InvalidClientTokenId: The security token included in the request is invalid.
Absolutely no idea what I'm doing wrong. If I use slingshot normally without credentials it works fine.
import { Meteor } from 'meteor/meteor';
import moment from 'moment';
const cryptoRandomString = require('crypto-random-string');
var AWS = require('aws-sdk');
var sts = new AWS.STS();
Slingshot.createDirective('UserProfileResumeUpload', Slingshot.S3Storage.TempCredentials, {
bucket: 'mybuckname', // change this to your s3's bucket name
region: 'ap-southeast-2',
acl: 'private',
temporaryCredentials: Meteor.wrapAsync(function (expire, callback) {
//AWS dictates that the minimum duration must be 900 seconds:
var duration = Math.max(Math.round(expire / 1000), 900);
sts.getSessionToken({
DurationSeconds: duration
}, function (error, result) {
callback(error, result && result.Credentials);
});
}),
authorize: function () {
//Deny uploads if user is not logged in.
if (!this.userId) {
const message = 'Please login before posting files';
throw new Meteor.Error('Login Required', message);
}
return true;
},
key: function () {
return 'mydirectory' + '/' + cryptoRandomString(10) + moment().valueOf();
}
});
Path: Settings.json
{
"AWSAccessKeyId": "myAWSKEYID",
"AWSSecretAccessKey": "MyAWSSeceretAccessKey"
}
I've done it in server side like this :
Slingshot.createDirective("UserProfileResumeUpload", Slingshot.S3Storage, {
AWSAccessKeyId: Meteor.settings.AWS.AccessKeyId,
AWSSecretAccessKey: Meteor.settings.AWS.SecretAccessKey,
bucket: 'mybuckname', // change this to your s3's bucket name
region: 'ap-southeast-2',
acl: 'private',
...
}
and in settings.json
{
"AWS": {
"AccessKeyId": "myAWSKEYID",
"SecretAccessKey": "MyAWSSeceretAccessKey"
}
}
Related
I my next.js blog app I have been trying to setup a global API call:
import { createClient } from "contentful";
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_KEY,
});
const auth_data = await client.getEntries({ content_type: "author" });
export function getAuthors() {
var authors = [];
var auth_len = auth_data.items.length;
for (var i = 0; i < auth_len; i++) {
authors.push({
authorSlug: auth_data.items[i].fields.name
.toString()
.replace(/ /g, "-")
.toLowerCase(),
authorContent: auth_data.items[i].fields.description,
authorFrontMatter: {
title: auth_data.items[i].fields.name,
image: "https:" + auth_data.items[i].fields.image.fields.file.url,
},
});
}
return authors;
}
I keep getting TypeError: Expected parameter accessToken because the environment variable will not be reached from the /lib foleder where this getAuthor() function is located. If I prefix the variable with NEXT_PUBLIC_ I could reach the environment variable from the /lib, but at the same time I would expose the variables to the browser.
Is there a way to reach the environment variable from the /lib WITHOUT exposing them to the browser?
We are using Office.context.ui.displayDialogAsync for authentication with OAUTH library (Oidc-client) and below are the findings. Kindly help on the same.
As per attached code we were able to get access token in taskpane.ts file as args in messageHandler...
But when i logged in fresh browser that time only Secure Token Service (STS) login window getting opening.
If i logged out and cleared access token then again trying to logged in that time directly getting in as logged user without opening Secure Token Service (STS) window.
Once i cleared browser cache and all then only i am able to get Secure Token Service (STS) window again... Can you please advise about the scenario to handle? Do we need anything.
Current Scenario
displayDialogAsync getting opened as STS login very first time and able to login successfully. But for the subsequent login it is not getting popup and directly loading the data with tokens.
Expected Scenario
displayDialogAsync should not only open in first time login but also it should open for subsequent login which means if user logged out and trying to login again that time also it should popup.Is there anything need to clear cache for displayDialogAsync? Kindly help.
auth.ts
Office.initialize = function () {
var settings = {
authority: "https://xxxxxx.com/xxxx/xx",
client_id: "https://xxxxxxx.com/",
redirect_uri: "https://localhost:3000/taskpane.html",
// silent_redirect_uri:"https://localhost:3000/taskpane.html",
post_logout_redirect_uri: "https://xxxxxxx.com/",
response_type: "id_token token",
scope: "openid read:xxxx read:xxxxxx read:xxxxxxx",
state: true,
clearHashAfterLogin: false,
filterProtocolClaims: true,
loadUserInfo: true,
nonce:true,
};
Oidc.Log.logger = console;
var mgr = new Oidc.UserManager(settings);
mgr.signinRedirect();
mgr.signinRedirectCallback().then((user) => {
if (user) {
console.log(user);
} else {
mgr.signinPopupCallback().then(function (user) {
window.location.href = '../';
}).catch(function (err) {
console.log(err);
});
throw new Error('user is not logged in');
}
});
};
taskpane.ts
const loginpopup = function () {
if (OfficeHelpers.Authenticator.isAuthDialog())
return;
Office.context.ui.displayDialogAsync(
url,
{ height: 60, width: 60, /*displayInIframe:true*/ },
dialogCallback);
function dialogCallback(asyncResult) {
if (asyncResult.status == "failed") {
switch (asyncResult.error.code) {
case 12004:
console.log("Domain is not trusted");
break;
case 12005:
console.log("HTTPS is required");
break;
case 12007:
console.log("A dialog is already opened.");
break;
default:
console.log(asyncResult.error.message);
break;
}
}
else {
dialog = asyncResult.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived, messageHandler);
}
}
function messageHandler(arg: any) {
if (arg != "jsonMessage") {
$(".loader").show();
var test = JSON.parse(arg.message).value.split("#")[1].split("&")[1].split("=");
dialog.close();
};
}
}
logout.ts
Office.initialize = () => {
var settings = {
authority: "https://xxxxxx.com/xxxxxx/v1",
client_id: "https://xxxxxxx.com/",
redirect_uri: "https://localhost:3000/logout.html",
post_logout_redirect_uri: "https://localhost:3000/logout.html",
metadata: {
issuer: 'https://xxxxxx.com/xxxxxx/v1',
authorization_endpoint: "https://xxxxxx.com/xxxxxxx/v1/xxxxx"
}
};
var mgr = new Oidc.UserManager(settings);
mgr.signoutRedirect();
mgr.removeUser();
mgr.revokeAccessToken();
mgr.clearStaleState();
$("document").ready(function () {
localStorage.removeItem('accessToken');
localStorage.clear();
});
This is my first question ever here:-)
I need to list users in our Cognito use pool. Seems this can be done only using the aws-sdk CognitoIdentityServiceProvider APIs. I got the below code to work perfectly from my local node.js. It lists all users as expected.
However, the same code behaves differently when put into an AWS lambda function. It still runs, but it never waits for the Cognito listUsers() call to return. It just simply completes, like the "await" is not waiting at all. None of the console.log() is invoked from the client.listUsers(params, function(err, data)..._ block.
I tested this inside Lambda directly as well as from AWS API gateway. The same null is return. The call itself is successful, just no data is returned.
See log at the end.
BTW, I did create a role and add a policy giving the role full access to the cognito user pool.
What did I miss? Appreciate your help!
Martin C.
-----------------code------------------------
async function getUserList() {
console.log("enter LAMDA function**********");
var aws = require('aws-sdk');
aws.config.update({accessKeyId: 'xxxxxxxx', secretAccessKey: 'xxxxxxxxxxx'});
var CognitoIdentityServiceProvider = aws.CognitoIdentityServiceProvider;
var client = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region: 'us-east-2' });
var params = {
UserPoolId: 'us-east-xxxxxxxx', /* required */
AttributesToGet: [
'given_name','family_name','phone_number','email','profile'
],
Filter: null,
Limit: 0,
PaginationToken: null
};
console.log("Right before call the listUser method");
let result = await client.listUsers(params, function(err, data) {
console.log("call back reached!");
if (err) {
console.log(err, err.stack); // an error occurred
const response = {
statusCode: 500,
body: JSON.stringify('An error occurred.'),
}
return response;
}
else {
console.log(data);
var count = data.Users.length;
// successful response
const response = {
statusCode: 200,
body: JSON.stringify("sucessful list users! User count="+count)
}
return response;
}
});
console.log("no waiting here. async!!!")
}
getUserList();
***************Lambda log*****************
**************Log when called from node.js****************
getUserList is your lambda function? I don't know why you call it by your self getUserList().
I see, you are using lambda runtime is nodejs version > 8, you use await keyword with a callback function(fail) => you not wait anything.
When a function call by Lambda, the function (async function) will finish when get a return or run to end of function (without return), in your case the function finish when console.log("no waiting here. async!!!") has been executed. In local environment, the funciton finishs when callstack has been clear (do not have any callback function in callstack).
Right way, you have use promise version of aws-sdk then use await syntax to get a result. Relate to How to use Async and Await with AWS SDK Javascript
async function getUserList() {
console.log("enter LAMDA function**********");
var aws = require('aws-sdk');
aws.config.update({ accessKeyId: 'xxxxxxxx', secretAccessKey: 'xxxxxxxxxxx' });
var CognitoIdentityServiceProvider = aws.CognitoIdentityServiceProvider;
var client = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region: 'us-east-2' });
var params = {
UserPoolId: 'us-east-xxxxxxxx', /* required */
AttributesToGet: [
'given_name', 'family_name', 'phone_number', 'email', 'profile'
],
Filter: null,
Limit: 0,
PaginationToken: null
};
console.log("Right before call the listUser method");
try {
let result = await client.listUsers(params).promise(); // use Promise style
console.log(data);
var count = data.Users.length;
// successful response
const response = {
statusCode: 200,
body: JSON.stringify("sucessful list users! User count=" + count)
}
return response; // return to finish function
} catch (err) {
console.log(err, err.stack); // an error occurred
const response = {
statusCode: 500,
body: JSON.stringify('An error occurred.'),
}
return response;
}
}
getUserList(); // remove this line when deploy funtion to Lambda.
When I call try to call a Meteor server from an Ionic app, the user ID is not recognized on the server, despite having successfully logged in.
In the index.html of the Ionic app, before the meteor-client-side.bundle.js is included, the server URL is set:
SERVER_URL = "http://localhost:3000"; // Changes a lot. Run ipconfig. Look for Virtual Box???
window.__meteor_runtime_config__ = {
DDP_DEFAULT_CONNECTION_URL: SERVER_URL,
ACCOUNTS_CONNECTION_URL: SERVER_URL
};
Then, the user logins which is successful and I Meteor.user() looks good.
Meteor.loginWithPassword($scope.credentials.username,
$scope.credentials.password,
function (err) {
if (err) {
alert(err);
} else {
console.log('login success:' + JSON.stringify(Meteor.user()));
But, when the client code, tries to insert:
self.addOwnedProduct = function () {
var newOwnedProduct = {
productID: "ZZZZZZ" + Math.random(),
userID: Meteor.userId()
};
OwnedProducts.insert(newOwnedProduct);
};
The server code, sees the userId as null:
OwnedProducts = new Mongo.Collection("ownedProduct");
OwnedProducts.allow({
insert: function (userId, ownedProduct) {
console.log("Meteor.isServer:" + Meteor.isServer);
console.log("userId:" + userId);
return true || (userId && ownedProduct.userID === userId);
},
Here is a repo that replicates the problem
https://github.com/kokokenada/ionicToMeteorLogin
I need get data from external service. It has API. This is example:
http://portal.example.com/portal.api?l=username&p=keyphrase&act=brand_by_nr&nr=kl2&alt
Parameters are:
"l" - login, "p" - password, "act" - function to execute, "nr" - part number
I try connect by Meteor http.This is my server code:
var sources = {
mskv: {
url: "http://portal.example.com/portal.api",
auth: { l: "mylogin", p: "cBKoTyalCgbOQb37NG6sbb0qv2I0Q4PmWRJIJMWpOhCPFombqeDv7fBhdkjsdhkjah" },
params: { act: "brand_by_nr", nr: null }
}
};
Meteor.methods({
doRequest: function(partNumber) {
for (var key in sources) {
var url = sources[key].url;
var authData = sources[key].auth;
var paramsData = sources[key].params;
paramsData.nr = partNumber;
HTTP.call("POST", url, { auth: authData, params: paramsData }, function(err, res) {
if (err) {
throw new Meteor.Error("not-response", "Remote server not responding");
}
return res;
});
}
}
});
This is my client code:
Template.search.events({
"click .search": function(event) {
var partNumber = document.getElementsByClassName("input")[0].value;
Meteor.call("doRequest", partNumber, function(err, res) {
if(err === "not-response") return;
console.log(res);
});
}
});
I have error:
> Exception while invoking method 'doRequest' TypeError: Object
> #<Object> has no method 'indexOf' I20150227-00:01:35.455(3)? at Object._call (packages/http/httpcall_server.js:42:1)
> I20150227-00:01:35.455(3)? at Object._.extend.wrapAsync [as call]
> (packages/meteor/helpers.js:118:1) I20150227-00:01:35.455(3)? at
> [object Object].Meteor.methods.doRequest (app/server/server.js:19:18)
Can you help me, where is my error?
Try
var paramsData = [sources[key].params];
I suspect it's looking for an array there.
In my case auth field is not correct. The true way is auth:"login: password", look as simply string. Second error - auth field is not need. For this service login and password send as parameters { params: {l:"login", p: "password", act: "brand_by_nr" ....} }