One domain, one codebase, unlimited sub-domains and databases - google-app-engine

I want to host a marketing site and a demo app using GAE.
http://mysite.com => Marketing site
http://demo.mysite.com => Demo site
http://client.mysite.com => Client site
...
Each time a client signs up I need to be able to dynamically add a datastore for said client.
Is this something doable using GAE??? Do the Cloud SQL instances have an API I can call to add a DB and beging installing a client account???
Regards,
Alex

You can set up *.mysite.com to point to your app, by setting your CNAME records accordingly. See App Engine's Using a Custom Domain documentation for details on how to set this up properly.
Then, within your servlet/request handler, filter the domain in the request URI to find out what the subdomain is. After that, many of the services (datastore, memcache, etc.) have "multitenancy" support, where you can specify what namespace you're doing operations in. You can set that to the subdomain.
I don't know what language you're using, but here are the docs for multitenancy:
https://developers.google.com/appengine/docs/go/multitenancy/multitenancy
https://developers.google.com/appengine/docs/java/multitenancy/multitenancy
https://developers.google.com/appengine/docs/python/multitenancy/multitenancy

Related

How to add Single sign-on support for bots to existing application?

Currently we have an application in production that allows for Single sign-on in tabs, we followed https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-aad-sso and this works well.
For this to work an Application ID URI is set, like so: api://www.domainusedintab.com/378271d1-b8e4-4f01-a9bb-e724dbec43c8, where 378271d1-b8e4-4f01-a9bb-e724dbec43c8 is some application ID.
We now want to add Single sign-on support for bots, like described in https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots. To make this work a change is needed to the Application ID URI, api://botid-5d417275-b104-462e-9998-2b2b0ec4244f, where 5d417275-b104-462e-9998-2b2b0ec4244f is the ID of the bot service.
The problem is that it's not clear on how to combines these two into a single Application ID URI, based on the previous documentation pages it seems it's one way or the other.
We tried to just tack on /botid-5d417275-b104-462e-9998-2b2b0ec4244f after our current Application ID URI, to make api://www.domainusedintab.com/378271d1-b8e4-4f01-a9bb-e724dbec43c8/botid-5d417275-b104-462e-9998-2b2b0ec4244f. This seems to work fine... But it also seems like a bit of a hack that might break at any time.
Are there any resources on how to properly solve this?
We can add the existing bots to the existing application to work on SSO. We need to add the web applcation info in the manifest to view the changes in the application. For more information please check Single sign-on (SSO) support for bots
As it turns out, it is possible to provide multiple Application ID URIs for an App registration. This is not available through the Expose an API interface, you need to change it directly in the manifest. The identifierUris field holds the Application ID URIs — the current one from the Expose an API interface should be the only item here.

Google MBA Service Account get all locations

My company owns several (verified) facilities and using my company's email i can see those locations (business.google.com).
Now, my company would like to fetch the reviews in each location and present it in our company website. Before we're using the Google Place API but since it only returns the latest 5 reviews we opt to using Google My Business API to retrieve a location's complete reviews. We'd like our backend (PHP) to retrieve the reviews so using the same email I created a service account (console.developers.google.com/apis/credentials) because we don't need the end user to allow/interact anything when browsing our website.
Using postman (with my signed JWT) I have managed to get a valid access token
...that I use to retrieve the lists of accounts (mybusinessaccountmanagement.googleapis.com/v1/accounts) I could see the service account itself alone in the response.
Now, I tried calling the account locations api (mybusiness.googleapis.com/v4/accounts/{MY_ACCOUNT_ID_HERE}/locations) but it only returns and empty object response.
Can someone help me resolve this issue. Why my service account can't see the verified locations under my company's email. Is this even possible? Thank you.
Even that this is an older question - I run into the same issue calling the new Google My Business Information v1 API (getting empty results) using a service account.
It seems, that it is not recommended to use Service Accounts, I found this support article on Google: https://support.google.com/business/thread/8281160/cannot-get-access-to-gmb-locations-with-service-account-with-nodejs?hl=en
The "official" recommendation is to use OAuth.
But we finally made it using Service Account. The following steps are necessary to resolve it (at least for us it is working now):
Add a project in Google Cloud Platform
Add and enable the Account Management and Business Information API's.
Add the service account and generate a key (https://developers.google.com/identity/protocols/oauth2/service-account#creatinganaccount)
Make the Business Profile API request (you need the approval made by Google to be able to make requests against the two API's; otherwise you may run into quota exceeds as "Request per minute" is set to 0 by default). Important: It may take up to 2 weeks until, but we received the approval within about 5 days
Enable domain-wide delegation for the service account using the scope "https://www.googleapis.com/auth/business.manage". More about domain-wide-delegation: https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority)
Add a user identity in GCP. This user also needs to be added in Google My Business for editing locations. When creating your ServiceAccountCredential object, impersonate this user.
Security concerns:
Domain-wide-delegation enables that everyone knowing/having the credentials of the service account could impersonate any person (identity) from withing GCP. At least in this case only for Business Profile API, but anyway, keep this in mind.
Also using private keys for authenticating the service account is not recommended, you should be aware to regularly change / create a new private key or there would be a solution with Identity Workload.
Hope this helps everyone facing the challenge with GMB / GCP / service accounts :-)

How to forward domain requests to gae url

I have different customers who own each their own hosted saas page on my gae app. for example:
myapp.appspot.com/customer/123
myapp.appspot.com/customer/456
each of the customers may want his domain name for example theBigDomain.com to "invisibilly" forward to myapp.appspot.com/customer/123
Please notice I want theBigDomain.com/myservlet?id=theId#aBookmarkUrl to be transmitted to the target url as myapp.appspot.com/customer/123/myservlet?id=theId#aBookmarkUrl
I searched for the google documentation and I can't find a way to do that.
Note: I don't want a redirect where the person who types theBigDomain.com finds he's not there anymore, and I don't want a frame to include my url in the theBigDomain.com since I want the user to be able to click on the back button.
In short, I want the domains to work as proxies, knowing that from what I know, proxies are not good for some content, for exampe, if my target link has a youtube video, this might not work. So I'm asking if there is a way to do a dns redirect for a url and not a domain???
Using subdomains is also limited: creating a subdomain for each customer will be a tedious work...
Using subdomains is also limited: creating a subdomain for each customer will be a tedious work...
How so? This could actually be a lot easier for you/your customers since your customers wouldn't have to deal with domain verification/DNS settings and all you would need to do is add one * (wildcard) host to your main domain pointing to ghs.googlehosted.com and adding *.yourdomain.com in your GAE apps's settings. In your app, in your framework of choice you would then see what subdomain the request came to and and handle it as the customer's unique id (instead of 123/456). See here how you would determine the subdomain on python/webapp2. If you're using a different combination of language/framework - there are alternatives functions as well.
If you still want the customers to use their own domains then it gets a little more complicated. First, they need to provide the full domain name to you, you then add it to your GAE app's settings. Next, you and your customers need to follow one of the verifications steps listed on this page: https://support.google.com/a/answer/60216?hl=en and once that is complete you would need to ask your customers to create a CNAME record on their domains/subdomains pointing to ghs.googlehosted.com. Once the CNAME record is created, you would handle this just like the if these were subdomains on your own domain, i.e. in your framework determine what domain the request came to and handle it as a customer's unique ID to serve that customer's app.

send email on Google App Engine from custom domain

What I have done:
I have added my domain app.mydomain.com to my app engine project, and can successfully visit id.appspot.com using app.mydomain.com.
I have registered mydomain.com on google app for business.
The problem:
The problem is -- I am NOT able to send emails using #mydomain.com address. If I register an info#mydomain.com as an developer, this will probably solve the problem, but we need to send from more than one address, and I don't think registering a new developer for each address is reasonable.
Anybody knows how to solve this? Thanks!
You have two options:
Register all emails that you want to use as administrators/developers but as you mentioned in your post you don't want to do that.
Use SendGrid (or any other email services like Mandrill, Mailgun, etc.) which will give you a lot more features comparing to what GAE offers, including 25k free emails instead of GAE's 100.
According to the docs, the sender would need to be an administrator on the project (called "owner" in the new Developers Console). Another route would be to just use a separate email sending service like SendGrid or Postmark.
You can use the GMail API to send emails as users of your domain. Note that the emails need to be aliases, groups or users of your domain.
You shouldn't have any problem adding and verifying your domain, adding the necessary permissions to send emails. Then, every email address in your domain can be used. See here in the docs: https://developers.google.com/appengine/docs/java/mail/#Java_Sending_mail

Accessing Gmail emails through google app engine

How to get the e-mail contents by getting the user's login details in google app engine?
Try taking a look at the GMail API. You'll probably want to use OAuth.
https://developers.google.com/gmail/
This is exactly what I'm doing in my current project. Google App Engine Blog introduced a company named "Context.IO" and they provide very easy API to access GMail. I've implemented it in my project successfully.
Links
GAE Blog
Demo (You can look for a contact, and get all its emails...)
My Experience
They also provide a Explore feature that allow you to post and get json data from your gmail accounts.
However, if you registered for a free API key here, they will limit to 3 mailboxes per day. You can run a cron job to delete it daily. The nice thing is that you can contact them to get more mailboxes for development purposes :)
Hope my experience can help you
You can also use google service account. https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount
Then you can use it in order to get access to account under your domain.
$client = new Google_Client();
$client->setApplicationName('My App');
$client->setAuthConfigFile('path/to/service_account.json');
$client->useApplicationDefaultCredentials();
// account that we want to check
$client->setSubject('account#mydomain.com');
$client->setAccessType('offline');
$client->setScopes([Google_Service_Gmail::GMAIL_READONLY]);
$service = new Google_Service_Gmail($client);
$messagesResponse = $service->users_messages->listUsersMessages('me');

Resources