GCP - App Engine Endpoints - Performance ISSUE - java

Do you guys use the Google Cloud Platform, specifically the APP ENGINE ENDPOINTs for professional/production purposes? Asking because I am not comfortable with response time. It´s taking too long to perform simple http POST requests like registering an users with only e-mail and password (saving in a DATASTORE). In this URL you will find the register form, let me know what you guys thing about the response time, is it acceptable?
https://filiperebollo1986.appspot.com/register.html
My Java code is quite simple. Only instantiate an user object with email and password which does´t have any special encrypting algorithm. Naturally for the registering purpose I need to check if the user already exists and after that save the object in the DATASTORE. I can ensure that the problem is not in my front-end apps because takes too long in the iOS e Android apps too.
POST:
https://filiperebollo1986.appspot.com/_ah/api/igardenendpoints/v12/saveProfile.
{
"userEmail": "response_time",
"password": "123"
}
Response:
200
Show headers
{
"messageText": "User successfully created!",
"messageNumer": 0,
"kind": "igardenendpoints#resourcesItem",
"etag": "\"9e-bXvBAIkMzDxg9PvVcUBMIXB0/_RzWmXdehTtOTMg1Y7MhIvXy5-k\""
}
public Message saveProfile(ProfileForm profileForm) {
Message message;
String userEmail = profileForm.getUserEmail();
String password = profileForm.getPassword();
String displayName = profileForm.getDisplayName();
Profile profile = ofy().load().key(Key.create(Profile.class, profileForm.getUserEmail())).now();
if (profile == null) {
if (displayName == "") {
displayName = extractDefaultDisplayNameFromEmail(profileForm.getUserEmail());
}
profile = new Profile(userEmail, password, displayName);
message = new Message("User successfully created!", 0);
} else {
message = new Message("User already exists!", 1);
}
ofy().save().entity(profile).now();
return message;
}

Related

Sending email using ClientCredentialProvider is failing to find tenant guid

I am using Microsoft Identity's OAuth 2.0 support to send email using Microsoft Graph.
Created a personal email account as XXXX#outlook.com. Using this account I login to Azure AD and create a tenant there. Used ClientCredentialProvider (From msgraph-sdk-auth-java) as authorizer trying to send an email to myself.
Steps:
Created a Tenant account.
Created an application and given permission in Graph>Application->Send.email etc
Created a Secret key
Below is the error I am getting:
POST microsoft.graph.sendMail
SdkVersion : graph-java/v1.5.0 Authorization : Bearer
_xv1yPye...
{
"message": {
"subject": "Test",
"body": {
"contentType": "text",
"content": "The new cafeteria is open bujji."
},
"toRecipients": [
{
"emailAddress": {
"address": "xxxxx#outlook.com"
}
}
]
},
"saveToSentItems": true
}401: UnauthorizedStrict-Transport-Security: max-age=31536000Cache-Control: privatex-ms-ags-diagnostic: {
"ServerInfo": {
"DataCenter": "South India",
"Slice": "SliceC",
"Ring": "3",
"ScaleUnit": "001",
"RoleInstance": "AGSFE_IN_1"
}
}client-request-id: 01565263-11b4-45f7-b089-06f57fdd8241request-id: 2e0cac3b-dc32-4dab-bb30-769590fc156eContent-Length: 361Date: Tue,
16Jun202007: 14: 42GMTContent-Type: application/json{
"error": {
"code": "OrganizationFromTenantGuidNotFound",
"message": "The tenant for tenant guid \u002706841624-5828-4382-b0a0-XXXXXX87b08f\u0027 does not exist.",
"innerError": {
"requestId": "01565263-11b4-45f7-b089-06f57fdd8241",
"date": "2020-06-16T07:14:43",
"request-id": "2e0cac3b-dc32-4dab-bb30-769590fc156e"
}
}
}
private static void sendEmail() {
ClientCredentialProvider authProvider = new ClientCredentialProvider(
"fb7f0ecc-b498-XXXX-XXXX-b016f252ea7d",
Arrays.asList("https://graph.microsoft.com/.default"),
"8-rpF8sOwV.CWF~7gK.XXXXXXXX.SSScxj0",
"06841624-5828-4382-b0a0-XXXXXXe87b08f",
NationalCloud.Global);
IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
Message message = new Message();
message.subject = "Test";
Ite * mBody body = new ItemBody();
body.contentType = BodyType.TEXT;
body.content = "The new cafeteria is open.";
message.body = body;
LinkedList < Recipient > toRecipientsList = new LinkedList < Recipient > ();
Recipient toRecipients = new Recipient();
EmailAddress emailAddress = new EmailAddress();
emailAddress.address = "xxxxx#outlook.com";
toRecipients.emailAddress = emailAddress;
toRecipientsList.add(toRecipients);
message.toRecipients = toRecipientsList;
graphClient.me()
.sendMail(message, true)
.buildRequest()
.post();
}
I guess you want to use Microsoft Graph API to send email from your personal account email XXXX#outlook.com.
But when you use this account to login to Azure AD and create a tenant, and use ClientCredentialProvider in your code, the account will be treated as a work account (not personal account) of your tenant.
So when a work account wants to send an email, it will requires an Exchange online license of O365 subscription. You don't have O365 subscription with Exchange online license. That is why you get this error: The tenant for tenant guid \u002706841624-5828-4382-b0a0-XXXXXX87b08f\u0027 does not exist.
If you want to send email from your personal account, it's unnecessary to create an AAD tenant. And you should use Authorization code provider rather than Client credentials provider. Another thing is that personal account requires Delegated permission rather than Application permission based on Send mail permissions. Create an application and give permission in Graph > Delegated > Mail.Send.
Please note it may require the scopes as https://graph.microsoft.com/mail.send instead of https://graph.microsoft.com/.default.
Thanks, Allen for your help. I am able to send and receive emails from my outlook account. Using Authorization code provider
1. Login to Azure AD create an Application in "Application from Personl account".
2. Give permission Graph > Delegated > Mail.Send.
3. Provided Redirect URL as http://localhost:8080/muapp".Note Down all appId,Create a secret Key.
4.Now hit the below URL with the details
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=40fcd457-1807-49e3-8bce-XXXXXX40ca194&response_type=code&redirect_uri=https://localhost/myapp/&response_mode=query&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.send%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read&state=12345
5. Acquire the code.This code we need to pass in Authorization code provider.
6.Scope "https://graph.microsoft.com/mail.send"
7. Authority "https://login.microsoftonline.com/consumers"
I have one question every time send an email I have to Acquire the code. Is there any Way this will have expiry date etc.???

How do I authenticate with my Google Cloud Function when using my Firebase App with Google Sign In?

I am a newbie (6 months going or so) and creating an app on Android (Java) that utilizes FireBase Auth with Google Sign In. (with only a few days of NodeJS exposure now) In other words my end user signs in with the Google Account. That part (I think) works pretty well so far. I use the Firestore Database heavily for a lot of things in the app.
So now I've gotten to the point where I want to use (Callable) Cloud Functions with HTTP Triggers. (never having done any of this before) I'm trying to get a proof of concept working at this time. The actual function works and I can trigger it from my app.
It appears that I cannot figure out how to make the function "private" though; as in "adding proper Members" to the Cloud function who have the right to invoke the function.
I have tried a few different things by trial error, but first let me show what I have.
This is the Cloud Function and I'm passing in an arbitrary String as a test, works nicely: (as long as "allUsers" have the role/right to invoke the function; in other words when the function is public.
exports.createTest = functions.https.onCall((data, context) => {
const text = data.text;
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const email = context.auth.token.email || null;
console.log('UID: ', uid);
console.log('Name: ', name);
console.log('Email: ', email);
console.log('Message: ', text);
});
The above function gets triggered in my Android/Java code like this: (I think this code came from Google Doc/Sample/Example
private FirebaseFunctions mFunctions;
...
private void testing() {
mFunctions = FirebaseFunctions.getInstance();
Log.e(LOG_TAG, "Testing executed!");
String testMessage = "Hello Hello Testing 123 Mic Check";
createTest(testMessage)
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
Log.e(LOG_TAG, "FFE: " + ffe.getMessage() );
Log.e(LOG_TAG, "Code: " + code);
Log.e(LOG_TAG, "Details:" + details);
}
// ...
}
// ...
}
});
}
private Task<String> createTest(String text) {
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("text", text);
data.put("push", true);
return mFunctions
.getHttpsCallable("createTest") //this is the function name
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
String result = (String) task.getResult().getData();
if (result != null) {
Log.e(LOG_TAG, "Result: " + result);
}
return result;
}
});
}
Only when I have "allUsers" added with the role/right to "invoke Cloud Function" then I get this working. My understanding of HTTP Requests and such is pretty limited, which is not making things easier.
I tried using the "allAuthenticatedUsers" options, which I figured would do the trick, because I actually authenticate my Users in the app through Firebase/Google Sign In. This Cloud Function shall only be available to either a) authenticated users or b) users of a specific domain. (I have a domain, let's say #testorganization.com) Or if I can identify my particular app (api key?) then that would work, too.
The moment I add a member "allAuthenticatedUsers" with role to invoke the function (and remove "allUsers) nothing happens. I also tried adding the entire domain, but that wouldn't work. (duh) Also tried adding my service account (trial and error at this point) and didn't seem to work.
In my Node JS code I am actually receiving the UID of the authenticated user, so it appears that some kind of user authentication information is already being exchanged.
With that knowledge, I can (successfully tried this) get the UID and cross check that against my database and verify a user that way, but seems unnecessary and I should be able to make the permissions work. (lock the function down entirely) Plus this took a really long time just finish this cross check. Or is this pretty standard procedure to do?
Like this-->
const usersRef = admin.firestore().collection('users').doc(uid)
usersRef.get()
.then((docSnapshot) => {
if (docSnapshot.exists) {
usersRef.onSnapshot((doc) => {
console.log('User Type logged in: ', doc.data().userCategory)
console.log('User Title: ', doc.data().userTitle)
});
} else {
console.log('User does not exist')
}
});
Edit:
So while not having figured out how to shut down the function entirely, I did discover that instead of cross checking my users, I can simple check for auth like this:
if (context.auth){
//user is auth'd
} else {
//no auth
}
That's a little bit better, I guess. (but still doesn't technically prevent access to the function?!)
Thank you so much for any help. Much appreciated.
Edit2:
Here is a screensshot of the area in the cloud console (for cloud function roles/privileges) that I am referring to:
https://imgur.com/cBsjaaL
With a Callable Cloud Function, if you want to ensure that only authenticated users can trigger it's business logic, you actually don't need to configure any extra "cloud function roles/privileges" as shown at the bottom of your question.
By default, with a Callable Cloud Function you will get, when available, "Firebase Authentication and FCM tokens automatically included in requests" and it will "automatically deserializes the request body and validates auth tokens", as explained in the doc.
So you just have to follow the doc and use the context parameter. As you have mentioned in your question, you can check the user is authenticated by doing:
if (context.auth) {
//...
}
If you want to verify the user email, you would do:
exports.addMessage = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
return admin.auth().getUser(uid)
.then(userRecord => {
const userEmail = userRecord.email;
//....
})
.catch(function(error) {
console.log('Error fetching user data:', error);
// Send back an error to the front end
// See https://firebase.google.com/docs/functions/callable#handle_errors
});
});
You will find more examples on how to "work with" users with the Admin SDK here in the doc.

Using RestFB along side a JavaFX WebView, how can I post to Facebook?

I've been trying a number of ways to achieve a way to post to Facebook from within my JavaFX application using a WebView to manage login.
I have read Facebook's documentation but continue to get lost with user_key, codes, access_code, tokens and what not.
What I have so far is this:
My WebView loads this URL.
public static String userLogin() {
String state = UUID.randomUUID().toString();
return String.format(AUTHORIZATION_URL, CLIENT_ID, REDIRECT_URI, state);
}
User logs in and authorises my Facebook application and I capture the response
System.out.println("Response: " + response);
if (response.contains("code=")) {
String[] finalCode = response.split("code=");
Facebook.CODE = finalCode[1];
System.out.println("Access Key:" + finalCode[1]);
}
}
My webview displays the following:
SECURITY WARNING: Please treat the URL above as you would your password and do not share it with anyone. See the Facebook Help Centre for more information.
I also see my code returned:
https://www.facebook.com/connect/login_success.html?code=AQA4w...
I then try to get my User Token, by directing my webView here:
public static String getUserToken() {
return String.format(ACCESS_TOKEN_URL, CLIENT_ID, REDIRECT_URI, CLIENT_SECRET, CODE);
}
At which point my webview displays the following:
{
"error": {
"message": "Missing authorization code",
"type": "OAuthException",
"code": 1,
"fbtrace_id": "D/0gXWRYkx4"
}
}
How can I solve this?

Google app engine entities are not being created

I am developing an android application using google endpoints and google app engine. My backend does not seem to actually be doing anything. It appears as if nothing is being saved to the datastore and therefore nothing can be retrieved from it.
Here are some of the Api methods I have written in endpoints that are not working:
private static String getUserId(User user) {
String userId = user.getUserId();
if (userId == null) {
AppEngineUser appEngineUser = new AppEngineUser(user);
ofy().save().entity(appEngineUser).now();
// Begin new session for not using session cache.
Objectify objectify = ofy().factory().begin();
AppEngineUser savedUser = objectify.load().key(appEngineUser.getKey()).now();
userId = savedUser.getUser().getUserId();
}
return userId;
}
#ApiMethod(name = "saveProfile", path = "profile", httpMethod = ApiMethod.HttpMethod.POST)
public Profile saveProfile(final User user, final ProfileForm profileForm) throws UnauthorizedException {
if(user == null) {
throw new UnauthorizedException("Authorization required.");
}
String firstName = profileForm.getFirstName();
String surname = profileForm.getLastName();
String userEmail = user.getEmail();
int year = profileForm.getYear();
int month = profileForm.getMonth();
int day = profileForm.getDay();
Profile profile = ofy().load().key(Key.create(Profile.class, getUserId(user))).now();
if (profile == null) {
// the user does not have a profile and is creating one for the first time
profile = new Profile(getUserId(user), firstName, surname, userEmail, year, month, day);
} else {
profile.update(firstName, surname, userEmail, year, month, day);
}
ofy().save().entity(profile).now();
return profile;
}
#ApiMethod(name = "getProfile", path = "profile", httpMethod = ApiMethod.HttpMethod.GET)
public Profile getProfile(User user) throws UnauthorizedException {
if (user == null) {
throw new UnauthorizedException("Authentication required.");
}
return ofy().load().key(Key.create(Profile.class, getUserId(user))).now();
}
}
The profile class has the #Entity annotation and is registered with objectify in a static block like so:
static {
factory().register(AppEngineUser.class);
factory().register(Profile.class);
}
The userId is generated by GAE through
com.google.appengine.api.users.User
and the userId property is a String with the #Index annotation.
I am also confused by the api explorer and how it is responding to these methods. Whenever I call the saveProfile api method, a profile object is returned with a userId of 0 and an email of "example#example.com" although I believe this is the default email when running on localhost.
I am also running api explorer over HTTP,Google says this "can cause problems." Is this the reason why nothing is working. I have had to load unsafe scripts just for me to use my api, but maybe it does not work as it is hosted over HTTP instead of HTTPS.
Is this entire problem of not being able to fully test my methods due to a fundamental flaw in my understanding of GAE or is due to me running on localhost. If it is the latter perhaps I should deploy to Appspot and things may run smoother.
If there is anything extra you need to help, please just ask.
Thank you!
Check your logs in the developers console. It records all API methods that you execute and will show if any have any errors.
Since you are getting example#example.com as the email of the User this leads me to believe the User is not being injected by GAE. This is probably because you are doing something wrong client side (e.g. in Android). Make sure your Android app correctly asks to log a user in with Google and pass those credentials to your builder object in Android.
If you are executing your API method via the api explorer, you need to be logged in as a google user first for that User object to be populated in your method (I think you already know that).
In short, check your logs and your client code.

How to send verification code back to my application from Parse Cloud after success?

So I'm building a signup procedure that needs the user to verify their phone number by receiving a code by sms. I'm using Parse as the backend system and I'm using Twilio service which comes included in Parse to take care of the sms function. I have been successful in sending the verification code to user's number.
This is my parse cloud code:
var client = require('twilio')('ACb3....', '2b3....');
//Send an SMS text message
Parse.Cloud.define("sendVerificationCode", function(request, response) {
var verificationCode = Math.floor(Math.random()*999999);
client.sendSms({
From: "+61437877758",
To: request.params.phoneNumber,
Body: "Your verification code is " + verificationCode + "."
}, function(err, responseData) {
if (err) {
response.error(err);
} else {
response.success("Success");
}
});
});
This is the code from the app:
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("phoneNumber", userNumber);
ParseCloud.callFunctionInBackground("sendVerificationCode", params, new FunctionCallback<String>() {
public void done(String result, ParseException e) {
if (e == null) {
Log.d("Parse", result);
Intent i = new Intent(SignupActivity.this, PhoneVerificationActivity.class);
startActivity(i);
} else {
Toast.makeText(SignupActivity.this, "there was a problem with connection", Toast.LENGTH_LONG).show();
}
}
});
Now I would like to know how can I send that verification code back to my android app from Parse Cloud after success, so tat I can check the verification code against the code user puts in the EditText
if (err) {
response.error(err);
} else {
*//So the code for sending the verification code back goes here:*
response.success("Success");
}
Do I need to use Json and Rest API?, how can I call and grab this verification code from the app?.
I would really appreciate your help. Thanks.
One way would be to return it in response.success...
response.success({ status: "success", verificationCode: ... });
Another way, a better way, is to not trust the client with this. Store a record of it on an object on the server... When the user enters the validation code, call back into another function to check if it is valid. An example of this type of system can be seen in this old out-dated GitHub login example: https://github.com/ParsePlatform/CloudCodeOAuthGitHubTutorial/blob/master/cloud/main.js#L116

Categories