I am working on a Google App Engine web app which exploits the Api Client Library (Python) to access drive and calendars.
When the user enters the app it is asked to log in with a Google Account. After that a second form is shown in which the Application is said to be not affiliated to Google and the user shall authorize it to access his data. In this second form the user can change the account (if it is logged with several).
This sometimes lead to inconsistencies in the app as the users.get_current_user() returns the former Account while the services accessed through the library refer to the second account.
I have been strugling on this for a long time Managing users authentication in Google App Engine
A solution would be to avoid the second account selection and forcing the user to authorize the application against the account which is currently logged.
Is there any way of doing so?
I am using the Python decorator oauth_required() and oauth_aware()
Related
My flask application is deployed to App Engine and it seems to be functional and we are able to view it fine. We want to share the application with some HR folks for trying it out, but they are unable to view it - it is asking them to select a google account. Is there a way to disable this or remove user login so that those without GCP access can view the app?
I guess that your app engine is protected by IAP. For checking this, go to Security -> Identity Aware Proxy. You should have this page:
With the IAP slider in green to the right. For allowing the unauthenticated users on your service, you have to select your AppEngine service name, go to the right panel, click on AddMember. Now select allUsers and add the role IAP web app user
And save. If you want to allow on some Google accounts and/or user groups, do the same thing but not on allUsers but with the appropriate email accounts.
HOWEVER, if the IAP has been activate on the project, it's for a good reason. Be sure that you do not enforce your company policy by doing this. You also have to be authorized to perform this operation, all depends of your roles on the project.
I'm creating a Google App Engine project which is going to automatically trigger a function each 5 minutes to analyze a Google sheet.
OAuth authorization
The to-be-analyzed sheet is a G Suite sheet, public to only company members. So I need OAuth2 to authorize the access. How do I do this?
I think I need a Service Account client ID, because as this is going to run automatically in the server, there cannot be a OAuth2 flow, right? Who is going to click the buttons if the function is ran in the server?
I need some directions.
Thanks
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
Yes, it is an OAuth2 flow, but not one involving a manual user operation - the actions are performed by the servers, automatically, based on pre-configured information. From the very document you mentioned:
The Google OAuth 2.0 system supports server-to-server interactions
such as those between a web application and a Google service. For this
scenario you need a service account, which is an account that belongs
to your application instead of to an individual end user. Your
application calls Google APIs on behalf of the service account, so
users aren't directly involved. This scenario is sometimes called
"two-legged OAuth," or "2LO." (The related term "three-legged OAuth"
refers to scenarios in which your application calls Google APIs on
behalf of end users, and in which user consent is sometimes required.)
Basically you need:
on the GAE side to locate an existing (or create a new) service account for your app (in the cloud project's IAM & Admin Service Accounts page). One service account is automatically created when your app is created.
on the G Suite side to allow access by Delegating domain-wide authority to the service account:
To delegate domain-wide authority to a service account, first enable
domain-wide delegation for an existing service account in the Service
accounts page or create a new service account with domain-wide
delegation enabled.
Then, an administrator of the G Suite domain must complete the
following steps:
Go to your G Suite domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom
of the page, then select Security from the list of controls. If you
can't see the controls, make sure you're signed in as an administrator
for the domain.
Select Show more and then Advanced settings from the list of options.
Select Manage API client access in the Authentication section.
In the Client Name field enter the service account's Client ID. You can find your service account's client ID in the Service accounts
page.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example, if your
application needs domain-wide access to the Google Drive API and the
Google Calendar API, enter: https://www.googleapis.com/auth/drive,
https://www.googleapis.com/auth/calendar.
Click Authorize.
Your application now has the authority to make API calls as users in
your domain (to "impersonate" users). When you prepare to make
authorized API calls, you specify the user to impersonate.
Finally I solved it this way:
Setup a new App Engine service account (I don't know if a "new" one was neccesary really)
Take note of that new service account email
Share the Sheet with that service account mail (I've not yet tested it without this step)
Download its service secrets as a JSON.
Use this code(inspired in (1) and (2))
class analysisHandler(Handler):
def get(self):
credentials = ServiceAccountCredentials.from_json_keyfile_name('service-secrets.json',
["https://www.googleapis.com/auth/spreadsheets"])
http = httplib2.Http()
#if credentials are still valid
if not credentials.invalid:
logging.info("Valid credentials, entering main function")
http = credentials.authorize(http)
main(http)
else:
credentials.refresh(http)
main(http)
Then in main():
sheetService = discovery.build('sheets', 'v4', http=authorized_http)
logging.info("Reading Google Sheet")
result = sheetService.spreadsheets().values().get(spreadsheetId=spreadsheet_id, range=range_name).execute(http=authorized_http)
urlfetch.set_default_fetch_deadline(45)
logging.info("Printing in Google Sheet")
sheetService.spreadsheets().values().append(spreadsheetId=spreadsheet_id, range="Log", body=body, valueInputOption="USER_ENTERED").execute(http=authorized_http)
Where the authorized_http parameter is the one built before with credentials.authorize()
I think this can be improved however.
(1) How to use "Service account" authorization (rather than user based access refresh tokens)
(2) Creating and sharing Google Sheet spreadsheets using Python
I migrated away from Google App Engine several months ago. But I am still relying on it for authentication, because my users are identified by their user_id attribute on GAE.
For this purpose my (now external) applications redirect the user to a Google App Engine application using a encrypted, signed and timestamped login request. The GAE application then performs the login using GAE's "Users" service. After successfully being logged-in on GAE, the user is again redirected using a encrypted, signed and timestamped response to my external application.
The rudimentary implementation can be found here and here. As you can see, this is very basic and relies on heavy crypto that leads to bad performance.
My external applications, in this case Django applications, are storing the user_id inside the password field of the user table. Besides the user_id, I only get the email address from GAE to store username and email in Django.
Now I would like to remove the dependency on the GAE service. The first approach which comes to mind would probably be to send an email to each user requesting him to set a new password and then perform my own authentication using Django.
I would prefer a solution which relies on Google's OpenID service so that there is actually no difference for the user. This is also preferred, because I need to send the user to Google anyway to get AuthSub tokens for the Google Calendar API.
The problem is that I couldn't find a way to get the GAE user_id attribute of a given Google Account without using GAE. OpenID and all the other authentication protocols use different identifiers.
So now the question is: Does Google provide any API I could use for this purpose which I haven't seen yet? Are there any other possible solutions or ideas on how to migrate the user accounts?
Thanks in advance!
The best way to do this is to show users a 'migration' interstital, which redirects them to the Google OpenID provider and prompts them to sign in there. Once they're signed in at both locations, you can match the two accounts, and let them log in over OpenID in future.
AFAIK, the only common identifier between Google Accounts and Google OpenID is the email.
Get email when user logs into Google Account via your current gae setup. Use User.email(). Save this email along with the user data.
When you have emails of all (most) users, switch to Google OpenID. When user logs in, get the email address and find this user in the database.
Why don't you try a hybrid approach:
Switch to OpenId
If your application already knows the userId, you are done
If not ask the user, if he has an account to migrate
If yes, log him in with the old mechansim and ttransfer the acount
If not create a new account
Google has a unique identifier that's returned as a parameter with a successful OpenID authentication request - *openid.claimed_id* . If you switch to using OpenID you could essentially exchange the user_id for this parameter the first time a user logs in using the new method without the user noticing anything different about their login experience.
Documentation for the authentication process is outlined here. I'd recommend using the hybrid OpenID+OAuth approach so that you can associate your request token with a given id, then, upon return, verify that the openid.claimed_id matches your original request token.
I am looking for some suggestions to implement authentication (and authorization) in our GAE app. Assuming that our app is called someapp, our requirement is as follows:
someapp is primarily for google apps users of the domain its installed for but can also authenticate users from other google apps domains.
For example, lets say google apps is configured on domainX.com and domainY.com. Additionally the admin for domainX.com has added someapp to their domain from the apps marketplace. The admin for domainX.com invites userA#domainX.com and userB#domainY.com log on to the application. Both google app domain users should be able to use their SSO (single sign-on) functionality.
As far as we know, current authentication options in the app engine allow either domain login, which allows only the users of one domain to log in to the app or federated/openid login which would allow the users of any domain to log in to the app. There is no in-between option which would allow only the users of previously authorized domains to log on to the app. Does that mean our only option is to leave aside google apps authentication and implement our own custom authentication?
Also in our sample scenario above, what if domainX.com and domainY.com have both added someapp. If userA#domainX.com navigates to someapp.appspot.com, which installation of the app will be used, the one installed on domainX.com or the one installed on domainY.com.
Authentication does not imply authorisation. All that the federated ID system does for your application is give you a username/userid that you can trust. So you can setup your user accounts tied to this infomation and rely on the fact that whenever you see that userid you are talking to the same user. Or in the case of domain-wide applications, whenever you see someone with that domain in their userid.
It is completely up to your application to decide if that userid has any meaning on your application. If I login to your app now with my google account, it should say "Oh I haven't seen you before, would you like to join?" ... it should (depending on your app) not just assume I'm authorised to use your application, just because I told you my name.
I'm not sure where you got the "domain login model" from? The only two choices are Google Account and Open/FederatedID neither of those attempt to restrict user access.
In your final example, users spanning multiple google accounts will see different results depending on if they have enable multiple-signin or not. Most users will be presented with a screen to choose which google account they mean before continuing.
I have a Python App Engine application where a user can log in using foursquare, then they must log in using Hunch. This all works fine but now I am trying to allow the user to authenticate on the android device. I don't want the user to have to log in to both 4sq & hunch on the phone so I want them to be able to authenticate with my backend and from there this would log on on their behalf. Is there anywhere where I could find tutorials on something like this? Should I create a custom authentication on my app or allow the user to sign on using their Google Account?
If they've already authenticated with your app, and set up oauth tokens with foursquare and Hunch, you can use this pattern to authenticate with your app.
There's no way to authenticate 'on their behalf' with your app short of asking the user for their credentials. If there were, any app would be able to impersonate you to any service you use.