I've developed a simple AppEngine application for my Google Apps domain. Access is restricted to users in my domain, and the app is enabled in the admin console for the domain.
The authentication/authorization in the application is done using decorators, using the JSON client secrets downloaded from my API console. I've created the client secrets of type "Client ID for web applications".
My main handler, on the GET method, is as follows:
#decorator.oauth_aware
def get(self):
if decorator.has_credentials():
.... do stuff .....
else:
self.response.out.write("decorator doesn't have credentials")
The problem is that the application works well when I'm logged in my account. For all other users in the same domain, I get the "decorator doesn't have credentials" error.
any clue on why this is the case?
the problem was actually quite simple: the user was not logged in and, instead of presenting a login window, the app was crashing.
to present a login window we should use #decorator.oauth_required instead of simply oauth_aware, and put login: required in the app.yaml file
Related
I am trying to get the user who is logged in via. SAML Single Sign On.
I have already implemented SAML Single Sign On and it works.
The code I use for programmatic login is :
apps = gdata.apps.service.AppsService(email=username, domain=domain, password=password)
apps.ProgrammaticLogin()
logging.info("current user %s", users.get_current_user())
//Redirect to a Google mail page.
But users.get_current_user() returns None always even though correct username and password is provided. I have crosschecked it by redirecting the page to Google Mail page and it successfully redirects.
I have googled this issue for hours now nothing goes the right way.
Can anyone please guide me what I am doing wrong ?
There are three different things going on here, I just want to make sure are clear for my suggested answer to make sense:
Google App Engine users service: You, as the developer, delegate authentication and authorization responsibility to Google Accounts (or the selected OpenID provider). Google will act as the Identity Provider and you'll act as the Service Provider.
SAML single sign on: Google delegates to you the authentication and authorization responsibility, you'll act as the Identity Provider and Google will act as the Service Provider. You'll be using SAML SSO every time you try to login any Google service using you Google Apps account, that includes Google App Engine applications using the users service.
ClientLogin: It is one of the methods for authenticating to use a Google API by giving username and password. It's deprecated, it's hard to maintain and insecure since you are hard coding the credentials and the app could have access to everything. I'd recommend switching to OAuth instead. In the first two lines of code You are initializing the Google Apps provisioning API with gdata.apps.service.AppsService, if you are not going to retrieve or create users/groups/alias is useless to do that. If you are I'd also recommend switching to the Directory API part of the new AdminSDK
For your particular case I'd suggest checking if there is a current user logged in, if not redirect to the login URL using the GAE users service.
user = users.get_current_user()
if user:
logging.info("current user %s", user.email())
else:
return redirect(users.create_login_url(request.url))
In case you always require that the user is logged in you better set the handler as login: required
The user will be redirected to the SAML SSO page to log in to his Google Account in order to access the GAE app.
I am quite new to openID and GAE and there are lots of documentation that I get confused. So
I am building a Java web application.
I have GAE for Business.
As I understand GAE are automatically become openID providers. Can I in my Java web app identify only my GAE users using openID, like when user clicks login button it redirects to my GAE login page and identifies them? If user is not my GAE user my Java app rejects the access.
If something is not clear just tell me, because English is not my native language.
I am not really sure I got you right but if you want only the users you have invited the relevant emails to your application through appspot.com under permissions, you can include in your relevant handlers in your app.yaml file the login parameter like that.
handlers:
- url: /.*
login: admin
In case the user is trying to login is not under your application's permission list he will receive an unauthorized error.
Having just implemented this, I have a pretty basic question about how authentication and oauth work together. I have a sample web app client (ckclient) that accesses a REST API (commitapi) for managing their commitments. This follows the model of having an app like LinkedIn displaying a user's Tweets (via Twitter) as described in: http://www.slideshare.net/coldfumonkeh/oauth-demystified-hopefully
In my simple app, a user goes to the web app client and asks to see their commitments. I am using Restlet and the user is redirected to a page where they can choose their OpenId provider and login. They are they redirected to a page where they can approve access to their commitment resources. Everything works fine.
But, the web app client doesn't know who the user is! All the authentication is done with the REST API, not with the web app client.
So my first question is... is this a bug or a feature?
My guess at the answer is that this is a "feature" - that is the way Oauth works - you don't WANT the web app client to know the userid/email address stored with the resource server (commitkeeper in my case, Twitter in the slideshare above).
If that is correct, then if I want the web app client to know who the user is, the web app client should provide user authentication. Since I am using Google's UserService on the server side, I also implemented UserService based authentication on the web app client. And now, if the user also does the web app client authentication, then the web app client has the identity of the user. So that is all good.
Combining these two also works - but I can't quite understand why.
On the web app, I login through Google's userService (technically with a GaeAuthenticator, that only uses Google accounts). Now the web app knows who I am and can display my email address.
From the web app, I ask the server for my commitments. The server responds by giving me the login page where I can pick my OpenId provider.
2a. If I pick Google, the UserService seems to know that I have already logged in through the web app and shows me my commitments.
2b. If I pick Yahoo (or something else), I have to authenticate with Yahoo and then I am shown the commitments for that Yahoo user.
This all seems fine to me - except for how does the UserService know that I already logged in? The webclient is at x.appspot.com and the server is at y.appspot.com. Is the answer as simple as the UserService is integrated across all of appspot.com?
In any case, thanks to anyone who can answer these two questions - or just confirm that I am on the right path.
(Note: I am using Google's UserService to create the login urls, my web app client and resource server are on appspot, using Federated Authentication, and all this is Java).
Well, the answer to the first part of the question is "feature" - getting resources from a ResourceServer via OAuth is not supposed to expose any user related information to the web app client.
I will pose a more specific question regarding how the UserService does its magic.
I've set up an AppEngine account using Google Apps Authentication and I've resigned myself to the fact that it can't be changed. But can you switch the domain that it's bound to?
UPDATE
Forgot one point. We've already added users from the new domain as AppEngine administrators and we're able to log into the AppEngine console with them. But there are certain URLs in the app itself (e.g. cron jobs/task queues) that we've restricted to access by admins only. When we try to access them, we are directed to the domain-specific AppEngine page (i.e. http://appengine.google.com/a/myolddomain.com) to log in. When I update the URL to the new domain, I can log in but then I get a page saying "The page is requesting permission to access your Google account. Select an account you would like to use." And there are no options in the list to select. I can click Continue but then I'm redirected back to the login page for the old domain again.
No. If you created an app with Google Apps authentication, it is tied to that domain to authenticate against forever. This only matters if you're using the Users API, of course.
Yes you can switch to another domain. App Engine is a service in your apps domain. Because it is a service, I think you can add the same appspot service to multiple apps domains.
I refer here to that page you are redirected after you login to GAE app with your google account, which asks your permission to access your google account.
Put this toghether with custom domain and https and you get my problem.
Sorry for the lengthiness. I searched everywhere. Didn't find anything. Not sure it is an OAuth issue (think not).
My configuration:
developed myapp.appspot.com
configured custom domain myapp.mydomain.com to point to myapp
myapp is making use of GAE login service
need for https posts from custom domain (!), solved as follows:
page is loaded in HTTP from http://myapp.mydomain.com
some submit HTTPS URLs are hardcoded in the page, as https://myapp.appspot.com/someservice
same domain policy resolved server side by means of http headers
GAE login service applies both to http://myapp.mydomain.com handler AND https://myapp.appspot.com/someservice handler
The workflow is:
user not yet authenticated
user browse http://myapp.mydomain.com (not ssl)
user is redirected to google account login page
user logins
user is redirected to the abovementioned page: myapp is requesting permission to access user's google account
user grants his permission
user is in - OK
Now comes the problem:
user makes a submit to https://myapp.appspot.com/someservice (so that data is ssl transmitted), which is loginrequired decorated
login is ok, user is not again redirected to the login page,
I think this is because the google login is cross application (the same should appen if the user was already logged in into gmail, to say)
but now https://myapp.appspot.com/ is again requesting permission to access user's google account - and this is the problem
The user is prompted TWICE to grant permission to myapp to access his account:
once when he browse to http://myapp.mydomain.com
and another one when he submits data to https://myapp.appspot.com/someservice
My user doesn't like it and me too !!!
I suspect this is because the user answer (Allow or No Thanks) is saved server side with respect to the URL of the app
and not with respect to some other unique id of the app.
But I have no idea how to solve it or at least work it around.
Thank you for your patience in reading up to here.
Any help would be appreciated.
The cookie that is issued for the user's session is per-domain and per-protocol. As a result, the same session won't work on the appspot app and on your custom domain. This isn't an App Engine limitation - it's simply how HTTP works.
The best solution, currently, is to put the form itself on HTTPS as well (which is in general a good idea anyway).