Accessing user token in IBM Cloud Functions serverless app secured with OAuth user authentication - ibm-cloud-functions

I am creating a serverless app using IBM Cloud Functions. My Cloud Functions API is secured with OAuth user authentication using an IBM Cloud App ID service. When a user logs into my app, an access token is generated by this service. I want to extract user data from that access token so that I can customize the user experience.
How do I access that token from within a Cloud Functions action that is coded for Node.js 10?
Example
The openwhisk webaction doc
https://github.com/apache/openwhisk/blob/master/docs/webactions.md
states that the following code
function main(params) {
return { response: params };
}
generates the following response
{
"response": {
"__ow_method": "get",
"__ow_headers": {
"accept": "*/*",
"connection": "close",
"host": "172.17.0.1",
"user-agent": "curl/7.43.0"
},
"__ow_path": ""
}
}
From that data I should be able to get HTTP request details. Specifically, I should be able to get the Authorization header value off the "__ow_headers" property of the action argument (params).
However, the same code inside an IBM Cloud Functions web action generates nothing. Nothing exists on the params object.

Related

What is the correct way to add a Custom Authentication strategy to a Feathers application?

My Feathers application needs to be able to have two JWT authentication strategies. For the users service, I need to have, for example, all: [authenticate('carrier')] instead of all: [authenticate('jwt')] in my hooks. For the rest of the services, authenticate['jwt'] is needed.
For this, I have registered a custom strategy in authentication.js called CarrierStrategy as following:
module.exports = function auth(app) {
const authentication = new AuthenticationService(app)
// register all of the strategies with authentication service
authentication.register('carrier', new CarrierStrategy())
authentication.register('jwt', new JWTStrategy())
// register the authentication service with your app
app.use('/api/authentication', authentication)
}
In config/default.json, I have also registered this strategy as following:
authStrategies: ["carrier", "jwt"]
The CarrierStrategy needs to handle the incoming Authorization header a little differently with some custom logic.
When I use Postman to send requests for this service, i.e., localhost:3030/users with a JWT token in the header, I get the following error.
Invalid authentication information (strategy not allowed in authStrategies)'
Please guide me if this is the right way to add a custom strategy to the application.
I had a similar problem to this. I wanted both Stateful and Stateless JWT authentication. The problem being that if you just do this in authentication.js
authentication.register('jwt', new JWTStrategy());
authentication.register('jwt-stateless', new JWTStrategy());
Then when you submit a request with a JWT token it will match on either one and you'll end up with a problem in one of your services somewhere.
I ended up creating a custom strategy like this in authentication.js:
class StatelessJWTStrategy extends JWTStrategy {
get configuration () {
const authConfig = this.authentication.configuration;
const config = super.configuration;
return {
...config,
entity: authConfig.entity,
service: authConfig.service,
header: 'Authorization',
schemes: [ 'STATELESS' ]
};
}
}
which is basically a slightly modified JWTStrategy that uses STATELESS in the Authorization header instead of Bearer or JWT. It's not a great solution, but it works.
Then I did this also in authentication.js
authentication.register('jwt', new JWTStrategy());
authentication.register('jwt-stateless', new StatelessJWTStrategy());
Then you need to modify your config.json file. In the authentication section add this:
"jwt-stateless": {
"entity": null
},
"jwt": {
"entity": "user",
"service": "users"
},
"entity": "user",
"service": "users",
"authStrategies": [
"jwt-stateless",
"jwt",
"local"
],
Now you should be able to use the jwt-stateless auth mechanism in your hooks like this:
authenticate('jwt-stateless')
Head over to here to create your stateless JWT. Fill in iss with the issuer and aud with audience details from your config.json, and add a user ID to the sub field. Pop your secret from config.json in the bottom signature verification field and the token on the left should authenticate.

how can i call HTTP callable cloud function from postman?

I want to know that can i call cloud function from postman software .When i'm calling CF from postman it always give me
"error": {
"status": "INVALID_ARGUMENT",
"message": "Bad Request"
}
In Postman make post request, header Content-Type should be application/json and then in raw make json in this format
{
"data": {
"text":"hi how are you",
"phoneNumbers":"+92123455679"
}
}
Using #Vaaljan's answer I was able to authenticate a GCP cloud function that I created using the HTTP trigger method with authentication required:
gcloud auth print-identity-token
Then added it to the request Authorization header:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6I ... bnRzLmdvb2dsZS5jb20i
In Postman:
Could possibly also be that the cloud function is protected and can be invoked by adding Authorization header with the identity token as the Bearer.
You get the identity token by running
gcloud auth print-identity-token

Trigger a cloud build pipeline using Cloud Function

I'm trying to create a cloud function listening to cloudbuilds topic and making an API call to trigger the build. I think I'm missing something in my index.js file (I'm new to Node.js). Can you provide a sample example of a Cloud Function making an API call to the Cloud Build API?
Here is my function:
const request = require('request')
const accessToken = '$(gcloud config config-helper --format='value(credential.access_token)')';
request({
url: 'https://cloudbuild.googleapis.com/v1/projects/[PROJECT_ID]/builds',
auth: {
'bearer': accessToken
},
method: 'POST',
json: {"steps": [{"name":"gcr.io/cloud-builders/gsutil", "args": ['cp','gs://adolfo-test-cloudbuilds/cloudbuild.yaml', 'gs://adolfo-test_cloudbuild/cloudbuild.yaml']}]},
},
module.exports.build = (err, res) => {
console.log(res.body);
});
I was executing the command gcloud config config-helper --format='value(credential.access_token)', copying the token, and putting it as a value to the variable accessToken. But this didn't work for me.
Here is the error: { error: { code: 403, message: 'The caller does not have permission', status: 'PERMISSION_DENIED' } }
I had the same exact problem and I have solved it by writing a small package, you can use it or read the source code.
https://github.com/MatteoGioioso/google-cloud-build-trigger
With this package you can run a pre-configured trigger from cloud build.
You can also extend to call other cloud build API endpoints.
As my understanding cloud build API requires either OAuth2 or a service account. Make sure you gave the right permission to cloud build in the gcp console under IAM. After that you should be able to download the service-account.json file.

How to determine why an Azure Function App is not triggered by a webhook

I have:
An JavaScript Azure Function in an HTTP webhook configuration; the Function provides a URL; the Function performs an action
A webhook configured in the software I hope to receive notifications from
An Azure Logic App with an HTTP/webhook step that provides a URL for the webhook notification to go to
My goal is that the Azure Function's URL receives notifications from the software's webhook and performs an action. The Azure Logic App is for testing only.
What works
When the the Azure Logic App's URL is used in the software's webhook configuration, the desired action is performed. All works as expected.
The Azure Logic App's logging shows the JSON output from the incoming webhook. I expect (but believe this may be where I am going wrong) that this is the JSON the webhook is sending to the Azure Logic App's URL. When this JSON is used in the Azure Function UI's "Test" tab > "Request body" field, the desired action is performed. All works as expected.
When the Azure Function's URL and the JSON is in a Postman request, the desired action is performed. All works as expected.
What doesn't work
When the Azure Function's URL is used in the software's webhook configuration, no action is performed. This is of course my goal. From everything I have read, I understand that this URL as a webhook endpoint should work.
Azure Function's URL
This is from Get function URL > default (Function key).
https://<app_name>.azurewebsites.net/api/content?code=<api_key>
Other Azure Function config settings
Allowed HTTP methods: GET, POST
Authorization level: Function
The JSON I believe to be coming over the webhook
{
"headers": {
"Expect": "100-continue",
"Host": "redacted",
"X-Telligent-Webhook-Sender": "redacted",
"Content-Length": "16908",
"Content-Type": "application/json; charset=utf-8"
},
"body": {
"events": [{
"TypeId": "ec9da4f4-0703-4029-b01e-7ca9c9ed6c85",
"DateOccurred": "2018-12-17T22:55:37.7846546Z",
"EventData": {
"ActorUserId": 9999,
"ContentId": "redacted",
"ContentTypeId": "redacted",
"ForumReplyId": 9999,
"ForumThreadId": 9999,
"ForumId": 9999
}
}]
}
}
I also tried with the following test code for the same results. It aligns more closely with the sample payload data provided by the software company:
What I tried
{
"events": [{
"TypeId": "ec9da4f4-0703-4029-b01e-7ca9c9ed6c85",
"DateOccurred": "2018-12-17T22:55:37.7846546Z",
"EventData": {
"ActorUserId": 9999,
"ContentId": "redacted",
"ContentTypeId": "redacted",
"ForumReplyId": 9999,
"ForumThreadId": 9999,
"ForumId": 9999
}
}]
}
Sample payload data
{
"events": [
{
"TypeId": "407ad3bc-8269-493e-ac56-9127656527df",
"DateOccurred": "2015-12-04T16:31:55.5383926Z",
"EventData": {
"ActorUserId": 2100,
"ContentId": "4c792b81-6f09-4a45-be8c-476198ba47be"
}
},
{
"TypeId": "3b75c5b9-4705-4a97-93f5-a4941dc69bc9",
"DateOccurred": "2015-12-04T16:48:03.7343926Z",
"EventData": {
"ActorUserId": 2100,
"ContentId": "4c792b81-6f09-4a45-be8c-476198ba47be"
}
}
]
}
I do not know how to determine why the Azure Function is not triggered by the webhook. The software's API documentation does not seem to provide a way to look at the JSON being sent over the webhook, although in my inexperience I may be wrong.
Is there a mechanism within Azure, or Postman, or another tool that lets me see what JSON is being sent over the webhook? Or perhaps is there another approach to determining the cause of the issue?
Thank you for any help.
This is how I got the JSON file from Azure alerts.
Install Ruby on the server
Install Sinatra with following command gem install sinatra
Create file webhook.rb and paste code bellow
require 'sinatra'
set :port, 80
set :bind, '0.0.0.0'
post '/event' do
status 204 #successful request with no body content
request.body.rewind
request_payload = JSON.parse(request.body.read)
#append the payload to a file
File.open("events.txt", "a") do |f|
f.puts(request_payload)
end
end
Run the web service with command ruby webhook.rb
JSON fill be written to file events.txt

"Insufficient Permission" when trying to authenticate to cloud-storage via apps-script

I am about to give up on this as I can't find out what I am doing wrong.
I have a cloud-storage bucket with our companies billing data (json file objects written by google) that I am supposed to process into spreadsheets.
As there is no apps script API for oauth2, I am using the custom OAuth2 library provided by google with the key "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", and have setup the auth request as shown in this example for service accounts:https://github.com/googlesamples/apps-script-oauth2/blob/master/samples/GoogleServiceAccount.gs
The token is being created and put into the scripts property store, where I can view it. So far so good.
I have this code for requesting the token and then I am trying to list the contents of the bucket in the function "getFilesList()":
function getService() {
return OAuth2.createService('CloudStoreGrab-Service')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(creds_private_key)
.setIssuer(creds_client_email)
.setSubject(creds_user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setScope(['https://www.googleapis.com/auth/drive','https://www.googleapis.com/auth/script.external_request','https://www.googleapis.com/auth/script.storage','https://www.googleapis.com/auth/spreadsheets']);
}
function getFilesList() {
var service = getService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/storage/v1/b/'+bucket+'/o';
var response = UrlFetchApp.fetch(url, {
method: "GET",
muteHttpExceptions: true,
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
}
Logger.log("Response:", response.getContentText())
}
No matter what I seem to try, the request always returns "403 Insufficient Permission". The service account has all necessary roles and permissions activated though (DwD, Storage-Administrator, Project-Owner). When I authenticate with the same credentials from gcloud and then browse the bucket with gsutils I can see the listing. This leads me to believe, that I am still requesting the auth token incorrectly. I tried using the generated token with curl and am getting the same Insufficient Permission response.
What am I doing wrong, while requesting the token?
Are the requested scopes too narrow?
Are the requested scopes too narrow?
That they are. You can find the OAuth scopes for Google's Cloud Storage API listed below (you won't need to use all of them, pick the ones best suited to your use-case, the 1st and 5th scopes in the list should be sufficient):
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/cloud-platform.read-only
https://www.googleapis.com/auth/devstorage.full_control
https://www.googleapis.com/auth/devstorage.read_only
https://www.googleapis.com/auth/devstorage.read_write
In future, you can find the required OAuth scopes for any Google API you need at the following link:
https://developers.google.com/identity/protocols/googlescopes