OpenWhisk (CloudFunction) binding to Watson Conversation and the use of username password in the SDK - ibm-watson

I have an IBM Cloud Function (OpenWhisk) that invokes a Watson Conversation Service.
We are using JAVA
The documentation of the JAVA SDK (https://github.com/watson-developer-cloud/java-sdk ) suggests that the credentials would be picked up from the binding.
When I list the bindig I get this:
>bx wsk action get talksmall parameters
ok: got action talksmall, displaying field parameters
[
{
"key": "__bx_creds",
"value": {
"conversation": {
"credentials": "Credentials-SmallTalk",
"instance": "<INSTANCE>",
"password": "<PASSWORD>",
"url": "https://gateway.watsonplatform.net/conversation/api",
"username": "<USERNAME>"
}
}
}
]
But when I use the SDK like this:
Conversation conversationService = new Conversation(Conversation.VERSION_DATE_2017_05_26);
I get an error
{
"error": "An error has occured while invoking the action (see logs for details): java.lang.IllegalArgumentException: apiKey or username and password were not specified"
}
When I add the line:
conversationService.setUsernameAndPassword(userName, password);
It works.
Maybe the VCAP_Service way of binding does not work with Cloud Functions ?
The Cloud Function runs in the same IBM Cloud organization and space.

I opened an issue against the SDK documentation which talks about "running in Bluemix". IBM Cloud offers infrastructure, OpenWhisk / Cloud Functions, Cloud Foundry and more. Bluemix originated from Cloud Foundry and the automatic binding via VCAP_SERVICE is a Cloud Foundry feature.
From my experience with using IBM Cloud Functions with Python and Node.js you need to call the API functions to set credentials explicitly. With the feature of service binding you can easily make credentials of provisioned services available to the context within IBM Cloud Functions as successfully shown in your code above.

Related

Cloud scheduler HTTP function "status": "UNAUTHENTICATED". Google app engine

We have a simple app in Google App Engine (python 3.6). We are trying to trigger a funciton (url) using Cloud scheduler. Using the console we have trigger that has the following frequency -
1 0 * * * (America/New_York)
The target is
URL : https://project-name.appspot.com/url
When we click "Run Now" on the console we get the following error in the logs -
"status": "UNAUTHENTICATED", "url": "https://project-name.appspot.com/url",
"#type": "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished",
"jobName": "projects/project-name/locations/us-central1/jobs/url", "targetType": "HTTP"
Please help.
I ensured that the service account service-project-id-number#gcp-sa-cloudscheduler.iam.gserviceaccount.com is added to IAM.
According to the documentation here we need to post the entire URL.
But in reality just post the relative url. That is just do /url_extension

How to specify replyUrlsWithType programmatically

I want to set the replyUrlsWithType programmatically on an app manifest within Azure AD. However, the REST API for updating the manifest only seems to support setting the replyUrls property, which does not enable the type property to be set. Is there a supported way to set the replyUrlsWithType programmatically?
The team I'm working with has used Fiddler to take a look at how the Azure portal sets the type property and have hacked the following to get it to work, but we are looking for a supported method if there is one:
$UpdateAppResponse = Invoke-WebRequest -Uri "https://graph.windows.net/myorganization/applications/$appId?api-version=2.0" `
-Method "PATCH" `
-Headers #{"Authorization"="$($Response.token_type) $($Response.access_token)"; "Accept"="*/*"; } `
-ContentType "application/json" `
-Body "{`"id`":`"$appId`",`"replyUrlsWithType`":[{`"url`":`"https://$HostName`",`"type`":`"Web`"},{`"url`":`"msauth://$ReversedHostName`",`"type`":`"InstalledClient`"}, {`"url`":`"msauth.$ReversedHostName://auth`",`"type`":`"InstalledClient`"}]}"
In the past, the application registered in Azure portal could only be one type. So, the Azure AD Graph API was able to set replyUrls.
However, new application registered in Azure portal could support both type at the same time. Based on the fiddler traces, the Azure AD Graph seems to updated to support that.
The url https://graph.windows.net/myorganization/applications/$appId?api-version=2.0 is a typical url of AAD Graph API. Maybe just the document has not been updated.
However, we suggest you use Microsoft Graph API. It is an unified center for managing lots of Microsoft Cloud Resources.
You can Get application and Update application with Microsoft Graph API.
For example, you can make a PATCH request with the following body:
{
"publicClient": {
"redirectUris": [
"myapp://auth"
]
},
"web": {
"redirectUris": [
"https://devchat.com/",
"http://localhost/",
"https://mytest.com/"
],
"implicitGrantSettings": {
"enableAccessTokenIssuance": false,
"enableIdTokenIssuance": false
}
}
}
Then all the platforms will be added:
For anybody who is looking to configure similarly as a SPA, you can set the property to "spa" instead of "web". This was a headache for me so hopefully helpful for others:
Instead of:
"web": {
"redirectUris": [
use
"spa": {
"redirectUris": [
A one liner for the Azure Cloud Shell (bash):
az rest --method PATCH --uri 'https://graph.microsoft.com/v1.0/applications/<APP REG OBJECT GUID (object ID not the App ID)>' --headers 'Content-Type=application/json' --body '{"spa":{"redirectUris":["https:<APP DOMAIN (and port if needed)>"]}}'

Get image from Google Cloud Storage in App Engine

I am trying to get an image in my App Engine backend and every time I try to get it I get the following error
com.google.api.client.googleapis.json.GoogleJsonResponseException: 503 Service Unavailable
{
"code": 503,
"errors": [
{
"domain": "global",
"message": "java.io.IOException: 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.",
"reason": "backendError"
}
],
"message": "java.io.IOException: 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."
}
Now it was my understanding that when making a request from App Engine backend that the Application Default Credentials was sufficient enough to do it.
The Application Default Credentials provide a simple way to get
authorization credentials for use in calling Google APIs.
They are best suited for cases when the call needs to have the same
identity and authorization level for the application independent of
the user. This is the recommended approach to authorize calls to
Google Cloud APIs, particularly when you're building an application
that is deployed to Google App Engine or Google Compute Engine virtual
machines.
taken from here
This is how I am trying to get the image using the Java API
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = GoogleCredential.getApplicationDefault();
if(credential.createScopedRequired()){
credential = credential.createScoped(StorageScopes.all());
}
Storage.Builder storageBuilder = new Storage.Builder(httpTransport,new JacksonFactory(),credential);
Storage storage = storageBuilder.build();
Storage.Objects.Get getObject = storage.objects().get("myBucket", name);
ByteArrayOutputStream out = new ByteArrayOutputStream();
getObject.getMediaHttpDownloader().setDirectDownloadEnabled(false);
getObject.executeMediaAndDownloadTo(out);
byte[] oldImageData = out.toByteArray();
out.close();
ImagesService imagesService = ImagesServiceFactory.getImagesService();
Image oldImage = ImagesServiceFactory.makeImage(oldImageData);
Transform resize = ImagesServiceFactory.makeResize(width, height);
return imagesService.applyTransform(resize, oldImage);
am I just using the credentials wrong or can I not use the application default credentials?
If you want to access your Google Cloud Storage data from App Engine. You should be using the Google Cloud Storage Client Library
Github Project

Is app_identity.get_access_token supposed to work in development environment?

I use this code to access Google APIs from my GAE app:
scope = "https://www.googleapis.com/auth/urlshortener"
authorization_token, _ = app_identity.get_access_token(scope)
It works well with production environment and doesn't work in development environment:
Using token InvalidToken:https://www.googleapis.com/auth/urlshortener:77.5780799389 to represent identity test#localhost
('Call failed. Status code %s. Body %s', 401L, '{\n "error": {\n "errors": [\n {\n "domain": "global",\n "reason": "authError",\n "message": "Invalid Credentials",\n "locationType": "header",\n "location": "Authorization"\n }\n ],\n "code": 401,\n "message": "Invalid Credentials"\n }\n}\n')
Is there any workaround I could apply (but not implementing OAuth from scratch)?
Upd. Another approach to access Google APIs from development environment also doesn't work:
credentials = AppAssertionCredentials(scope='https://www.googleapis.com/auth/analytics.readonly')
http = credentials.authorize(httplib2.Http(memcache))
service = build('analytics', 'v3', http=http)
response = service.management().accounts().list().execute()
logging.info(response)
Actually, dev_appserver.py recently added some arguments to make appidentity work during local testing. See Unable to access BigQuery from local App Engine development server for details.
The reason it works on appspot.com is because it uses the automatically created App Engine service account. Since the service account is associated with the app engine instance on which it is running, it's authority can be guaranteed. When you are running locally, there is no service account - how can they know you are debugging your own app as opposed to anyone else's?
If you want to run your code locally, you will need to implement OAuth, which actually is only a few lines of code anyway.

Using AppIdentityCredential with Google Drive API

I am using Google App Engine Identity to access Google Drive API of a Google Apps user.
I have inserted GAE URL in Manage API client access in Google Apps, with the right scope.
AppIdentityCredential credential = new AppIdentityCredential(Arrays.asList(DriveScopes.DRIVE_FILE));
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
Drive service = new Drive.Builder(httpTransport, jsonFactory, credential).build();
I get this error:
com.google.appengine.repackaged.org.apache.http.impl.client.DefaultRequestDirector handleResponse
WARNING: Authentication error: Unable to respond to any of these challenges: {authsub=WWW-Authenticate: AuthSub realm="https://www.google.com/accounts/AuthSubRequest" allowed-scopes="https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/docs,https://www.googleapis.com/auth/drive.file,https://www.googleapis.com/auth/drive.readonly,https://www.googleapis.com/auth/drive.metadata.readonly"}
An error occurred: com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 OK
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
Is it necessary to enable GAE application in API Client access in Google Apps? If not, how I authorise GAE app to gain acess to an API Scope?
Is possible to test GAE Identity in Local / Eclipse?
Summarizing, what is wrong or lack?
You can not debug AppEngine Credentials locally. The only way to debug is to use different credentials (AppEngine for production and Key-based service account locally). It will require to write different code for local and production environment.
You need to add your appengine service accounts to Team. If you use custom Google Apps domain for your project than you will need to create email group in your custom domain and add this group. All service accounts should be added to this group.
Consider adding the scopes it tries to authenticate against.
I had the same error in my code and ended up solving in by adding the drive.file scope.
Two important steps
Get the Application Default Credentials Service account JSON file.
Set GOOGLE_APPLICATION_CREDENTIALS environment variable with the path of the JSON file. Example: GOOGLE_APPLICATION_CREDENTIALS=c:/myFolder/my.jsonfile
FYI:
https://developers.google.com/identity/protocols/application-default-credentials

Resources