Calling google cloud endpoint api from another google app engine web application servlet java - google-cloud-endpoints

I have a google cloud endpoint api application which i want to call it from another google app engine web application, say from a servlet. The cloud endpoint api is not secured.
I tried looking for examples but could not find one. I see example related to Android client.
When tried using URLConnection it does not work, am not sure whether am doing correctly as well, sample codes or pointers will be of great help. I also checked the logs of cloud endpoint api to see if any requests are coming through, but i don't see any errors in the logs.

I'm doing this as well, although with authentication. You can use the Jar generated by the endpoint API at MyAPI/build/libs/MyAPI-v1-SNAPSHOT.jar, just as you might in Android.
Once you depend on that JAR, your code to build an API client should look something like that below. Mine is using OAuth authentication with a service account, which I'll leave in there because it was the more complicated part which you might eventually need. But without authentication you should just be able to set the credential to null.
HttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
List<String> SCOPES = Arrays.asList(EMAIL_SCOPE);
String SERVICE_ACCCOUNT_ID = "my-account-id#my-app.iam.gserviceaccount.com";
String CREDENTIAL_FILE = "WEB-INF/my-file.p12";
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCCOUNT_ID)
.setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(new File(CREDENTIAL_FILE))
.build();
MyAPI.Builder builder = new MyAPI.Builder(
HTTP_TRANSPORT,
JSON_FACTORY, credential)
// options for running against local devappserver
// - 10.0.2.2 is localhost's IP address in Android emulator
// - turn off compression when running against local devappserver
.setRootUrl("http://localhost:8080/_ah/api/")
// .setRootUrl("https://my-appengine-url.appspot.com/_ah/api")
MyAPI myAPI = builder.build();

You cannot use URLConnection for making endpoint calls from App Engine. Use FetchURL instead. If you set doNotFollowRedirect, you will receive X-Appengine-Inbound-Appid as header in the called App Engine project. You can trust this header, as Google would strip it off if somebody off App Engine would use it. Make sure you target the yourproject.appspot.com domain, as it won't work with custom domains.
https://cloud.google.com/appengine/docs/java/appidentity/

Related

ADFS 2016 On behalf of flow : cannot get any user informations

I'm trying to implement the "on behalf of" flow in an application using ADFS 2016 as STS. As a reference, I look at this Microsoft tutorial (https://learn.microsoft.com/en-ca/windows-server/identity/ad-fs/development/ad-fs-on-behalf-of-authentication-in-windows-server). It's working as it should, I can login into my web application and then use my original access token in UserAssertion to generate a new access token with the proper audience to call my API BUT I found absolutely no way to include any user informations (sub, name, email, upn etc.) into the access token for my API, even if I set claim rules into my ADFS configurations for the API.
I checked the communication between my app and adfs using Fiddler and everything looks like the informations in the tutorial. See the screen shot of the "on behalf of" request below :
Here's the resulting access token :
Finally, here's the code I use to generate my new access token :
private async Task<string> GetAccessToken(ClaimsPrincipal user, string originalAccessToken)
{
var authority = "[authority]";
var context = new AuthenticationContext(authority, false);
string userName = user.FindFirstValue("upn");
var userAssertion = new UserAssertion(originalAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer",userName);
var cc = new ClientCredential("https://localhost:44387/", "[client_secret]");
var result = await context.AcquireTokenAsync("https://localhost:44339/", cc, userAssertion);
return result.AccessToken;
}
Have you struggle with that scenario and if yes, did you find a way to fix this ?
Thanks
I've only used the Microsoft On Behalf Of flow with Azure AD and not ADFS, but it looks like you need to send a more detailed scope in your User Info request.
Maybe try sending 'openid profile email', to indicate that you want that type of detail, as in Section 17 of my blog post. Of course this assumes that this type of data has been registered for all users.
TROUBLESHOOTING
Looks like one of these will be the cause:
A suboptimal Microsoft library that does not allow you to send the required scope
Or ADFS 2016 perhaps lacks the scope features that work correctly in Azure AD
I would concentrate on making extra sure you are sending the correct form URL encoded request message, using a tool such as curl, Postman or a plain C# HttpClient. Here is the code I used to send the correct scope - using an open source library rather than a Microsoft one:
Sample NodeJS Code
If you can get the scope sent correctly then you should have a resolution either way:
Either you get the correct data and can update your code
Or the behaviour you want is not supported by ADFS
Good luck ...

Send firebase storage authorization as url parameter from a flutter web app

I would like to know how to make an authorized request to firebase storage using the user Id Token as a parameter in the url. Right now with a firebase rule of 'request.auth != null' I receive a 403 network error (Failed to load video: You do not have permission to access the requested resource). Here is my GET request url:
https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media&auth=eyJh...<ID TOKEN>...Ll2un8ng
-WITHOUT the firebase rule in place I'm able to successfully get the asset with this request url https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media
-also tried token=, token_id=, tokenId=
-the reason for not using the firebase SDK to fetch the file is so that I can use the flutter video_player (https://pub.dev/packages/video_player#-example-tab-) package and use this with files in firebase, I mention this in case theres a better way to use the video_player library in flutter web right now:
_controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
closedCaptionFile: _loadCaptions(),
);
[EDIT] It appears that it's not possible to pass the auth in as a query parameter. After some exploring, I found an acceptable way to still use the video_player with your firebase assets that are protected (If you're not using rules to protect them, you can directly use the firebase url). I will post some general steps here and some sample code:
Use the Storage Firebase SDK package to get the Uint8List, the uri given by getDownloadURL has the correct header auth, for example
import 'package:firebase/firebase.dart';
final url = await storagePath.getDownloadURL();
final response = await http.get(url);
if (response.statusCode == 200) {
return response.bodyBytes;
}
use the Uint8List buffer to init a Blob object which you'll use to then create an ObjectURL which basically gives you the same interface as a file url to use as the network url for your video player
final blob = html.Blob([data.buffer], 'video/mp4');
final videoUrl = html.Url.createObjectUrl(blob);
videoPlayerController = VideoPlayerController.network(
videoUrl)
..initialize().then((_) {...
That's it.
Firebase Storage REST does not (rightly) support authorization from GET query string as you are trying to do. Instead, it uses the standard Authorization header (see here).
Firebase cloud storage internally uses Google Cloud Storage. Mentioned here
If the library you use doesn't support HTTP headers yet, you must consider an alternative. The issue you mentioned in the comment shows that the feature is still under development, so you can also wait for the library to come out with the support for headers.
Internally all this package does for flutter-web is create an HtmlElementView widget here for which it passes a VideoElement (ref here) from the package dart:html with the provided URL which translates to a <Video> tag inside a shadow dom element in your web page. The error 403 could also mean you are trying to access it from a different origin.
I would suggest following approach.
Check your console for any CORS related errors. If yes, then you will have to whitelist your ip/domain in the firebase storage. Check this post for possible approach and more details here.
Check if you are able to access the URL directly with the authorization token as a query parameter as you suggested. If not then, it is not the correct way to access the object and should be corrected. You could update the question with the exact error details.

How to use php sessions in AndroidStudio

I'm working in an android application that connects with the server ,
and i'm not allowed to change the web services ,
the web service works with sessions ,
how do i make my android app save sessions like a browser when i send a post or a get and the servers works with sessions from my application ?
The answer is using Http-client in apache library
the request is sent this way :
HttpGet post = new HttpGet(url);
post.setHeader("User-Agent", "Android");
HttpResponse httpResponse = httpclient.execute(post);
One way to save the sessions like php does :
is to use android sharedPreferences
here is an example :
https://www.androidhive.info/2012/08/android-session-management-using-shared-preferences/

Exception using Azure Managed Service Identity across tenants

I'm building an Azure web app for a client that will be provisioned into many other directories for their customers. This app will call a web API in my client's directory, which will then call back to another web API in the customer's directory. Something like this:
Other Customer AAD1 --------- My client AAD2
App --------------------------------> Web API 2
Web API 1 <-------------------------- Web API 2
We have been able to get the first call to work. This requires a corresponding App Registation for Web API 2 in AAD1. We figure that we could get the callback to work by following the same pattern, with a registration for Web API1 in AAD2. However, that might be a LOT of these 'proxy' registration in my client's AAD, so we're looking at alternatives.
We are exploring using Managed Service Identity, which we think will allow us to get tokens that are valid for resources in other tenants. If there's a better way, I'm certainly interested in knowing about it.
I've followed the code example from here using the Microsoft.Azure.Services.AppAuthentication library: https://learn.microsoft.com/en-us/azure/app-service/app-service-managed-service-identity#obtaining-tokens-for-azure-resources
// In Web API 2
using Microsoft.Azure.Services.AppAuthentication;
// ...
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync(
"https://<App ID URI for Web API1>");
Web API2 is configured to have a Managed Service Identity.
I'm currently running this on my local machine, and I've installed Azure CLI and I'm logged in. I've tried 'az account get-access-token', and I get a valid token.
When Web API2 tries to get the token to be able to call Web API1, I get an exception:
Parameters: Connectionstring: [No connection string specified], Resource: , Authority: . Exception Message: Tried the following 2 methods to get an access token, but none of them worked.
Parameters: Connectionstring: [No connection string specified], Resource: , Authority: . Exception Message: Tried to get token using Managed Service Identity. Unable to connect to the Managed Service Identity (MSI) endpoint. Please check that you are running on an Azure resource that has MSI setup.
Parameters: Connectionstring: [No connection string specified], Resource: , Authority: . Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. ERROR: Get Token request returned http error: 400 and server response: {"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID '04b07795-8ddb-461a-bbee-02f9e1bf7b46' named 'Web API 1'. Send an interactive authorization request for this user and resource.\r\nTrace ID: f5bb0d4d-6f92-4fdd-81b7-e82a78720a00\r\nCorrelation ID: 04f92114-8d9d-40c6-b292-965168d6a919\r\nTimestamp: 2017-10-19 16:39:22Z","error_codes":[65001],"timestamp":"2017-10-19 16:39:22Z","trace_id":"f5bb0d4d-6f92-4fdd-81b7-e82a78720a00","correlation_id":"04f92114-8d9d-40c6-b292-965168d6a919"}
What's interesting is that there's no application with ID '04b07795-8ddb-461a-bbee-02f9e1bf7b46' in either AAD1 or AAD2. Is this a known Azure app? I thought that it might be the Service Management API, but I'm not sure.
In any case, I'm not sure of the proper way to grant permission. I've tried building different content URLs like this into my browser, but none of them seem to have done the trick:
https://login.microsoftonline.com/(AAD1 ID)/adminconsent
?client_id=(App ID)
&redirect_uri=https://localhost:44341
&resource=(App ID URI for Web API1)
&prompt=admin_consent
https://login.microsoftonline.com/(AAD1 ID)/adminconsent
?client_id=04b07795-8ddb-461a-bbee-02f9e1bf7b46
&redirect_uri=https://localhost:44341
&resource=(App ID URI for Web API1)
&prompt=admin_consent
(This last one tells me that the reply URL is incorrect; since it's not one of my apps, I can't find the reply URL)
Note that the tenant is AAD1.
Am I missing something, or am I not using this feature correctly?
Thanks in advance.
AzureServiceTokenProvider uses Azure CLI (among other options) for local development. For a scenario where a service calls an Azure Service, this works using the developer identity from Azure CLI, since Azure services allow access to both users and applications.
For a scenario where a service calls another custom service (like your scenario), you need to use a service principal for local development. For this, you have two options:
Login to Azure CLI using a service principal.
First, create a service principal for local development
https://learn.microsoft.com/en-us/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest
Then login to Azure CLI using it.
az login --service-principal -u 25922285-eab9-4262-ba61-8083533a929b --password <<pwd>> --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47 --allow-no-subscriptions
Use the --allow-no-subscriptions argument since this service principal may not have access to any subscription.
Now, AzureServiceTokenProvider will get a token using this service principal for local development.
Specify service principal details in an environment variable. AzureServiceTokenProvider will use the specified service principal for local development. Please see the section Running the application using a service principal in local development environment in this sample on how to do that. https://github.com/Azure-Samples/app-service-msi-keyvault-dotnet
Note: Ths is only for local development. AzureServiceTokenProvider will use MSI when deployed to App Service.

BizTalk 2016: How to use HTTP Send adapter with API token

I need to make calls to a rest API service via BizTalk Send adapter. The API simply uses a token in the header for authentication/authorization. I have tested this in a C# console app using httpclient and it works fine:
string apiUrl = "https://api.site.com/endpoint/<method>?";
string dateFormat = "dateFormat = 2017-05-01T00:00:00";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("token", "<token>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
string finalurl = apiUrl + dateFormat;
HttpResponseMessage resp = await client.GetAsync(finalurl);
if (resp.IsSuccessStatusCode)
{
string result = await resp.Content.ReadAsStringAsync();
var rootresult = JsonConvert.DeserializeObject<jobList>(result);
return rootresult;
}
else
{
return null;
}
}
however I want to use BizTalk to make the call and handle the response.
I have tried using the wcf-http adapter, selecting 'Transport' for security (it is an https site so security is required(?)) with no credential type specified and placed the header with the token in the 'messages' tab of the adapter configuration. This fails though with the exception: System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
I have tried googling for this specific scenario and cannot find a solution. I did find this article with suggestions for OAUth handling but I'm surprised that even with BizTalk 2016 I still have to create a custom assembly for something so simple.
Does anyone know how this might be done in the wcf-http send adapter?
Yes, you have to write a custom Endpoint Behaviour and add it to the send port. In fact with the WCF-WebHttp adapter even Basic Auth doesn't work so I'm currently writing an Endpoint Behaviour to address this.
One of the issues with OAuth, is that there isn't one standard that everyone follows, so far I've had to write 2 different OAuth behaviours as they have implemented things differently. One using a secret and time stamp hashed to has to get a token, and the other using Basic Auth to get a token. Also one of them you could get multiple tokens using the same creds, whereas the other would expire the old token straight away.
Another thing I've had to write a custom behaviour for is which version of TLS the end points expects as by default BizTalk 2013 R2 tries TLS 1.0, and then will fail if the web site does not allow it.
You can feedback to Microsoft that you wish to have this feature by voting on Add support for OAuth 2.0 / OpenID Connect authentication
Maybe someone will open source their solution. See Announcement: BizTalk Server embrace open source!
Figured it out. I should have used the 'Certificate' for client credential type.
I just had to:
Add token in the Outbound HTTP Headers box in the Messages tab and select 'Transport' security and 'Certificate' for Transport client credential type.
Downloaded the certificate from the API's website via the browser (manually) and installed it on the local servers certificate store.
I then selected that certificate and thumbprint in the corresponding fields in the adapter via the 'browse' buttons (had to scroll through the available certificates and select the API/website certificate I was trying to connect to).
I discovered this on accident when I had Fiddler running and set the adapter proxy setting to the local Fiddler address (http://localhost:8888). I realized that since Fiddler negotiates the TLS connection/certificate (I enabled tls1.2 in fiddler) to the remote server, messages were able to get through but not directly between the adapter and the remote API server (when Fiddler WASN'T running).

Resources