I am trying to test my code in localhost before pushing to production. It's quite basic
def post(self):
user = users.get_current_user()
if user:
logging.warning('User nickname %s', user.nickname())
logging.warning('User email %s', user.email())
email = user.email()
else:
logging.warning('Go login again?')
users.create_login_url("/")
I am using a browser where I am already login into my gmail account. So I figure that should be sufficient, but it is not. In any case, it always takes me to the else block. But then the method users.create_login_url("/") does not seem to be doing anything: it never takes me to a login page; of course I am already logged in. So it's all confusing. How do I get this to work? Do I have to add something in my app.yaml? But this is for Google Accounts not for OpenID, which is the one that needs app.yaml attention I think.
users.create_login_url("/") will return the URL where the user will be ask to login. Your code must send/redirect the user to this URL.
Related
I used gaesessions on Google App Engine with Python to handle user login sessions. The following are some of my codes:
When a user logs in:
from gaesessions import get_current_session
...
session = get_current_session()
if session.is_active():
session.terminate()
session['account'] = account
# Do some stuff to log the user in
When the user logs out:
session = get_current_session()
account = session['account']
# Do some stuff to log the user out
The above codes worked just fine most of the time, except that sometimes (very rarely, maybe once in a month) GAE complained about the statement account = session['account'] when the user logs out with the error message: KeyError: 'account' I wonder if anybody has encountered the same problem?
BTW, I also clean up expired sessions as below. Is it necessary? (I have no idea when a session goes expired) Or could it be the cause of the problem? Thanks.
while not delete_expired_sessions():
pass
Your session dictionary doesn't have the account key set to anything. This could be that a request runs your logout method without being logged in. This could happen by someone who is not logged in, yet visits your logout handler.
Eg. A user requests yourwebsite.com/logout without being actually logged in yet.
My understanding when reading AppEngine Users Service documentation https://developers.google.com/appengine/docs/python/users/userobjects is that if we initialize a user with a valid email address, the created user should have a valid user_id. However, when I tried this code
from google.appengine.api import users
user = users.User('valid_email#gmail.com')
print user.user_id()
on both development server and real AppEngine environment, I always get
None
Is this a bug? Or do I misunderstand the document?
If the object is instantiated as you do above, it will actually return None. Per the docs:
Note: If your application constructs the User instance, the API will
not set a value for user_id and it returns None
In order to use the user_id method, I would suggest using the user = users.get_current_user() structure, and if the user is not logged in, allowing them to authenticate with their Google account. For example:
user = users.get_current_user()
if user:
self.response.out.write(user.user_id())
else:
self.response.out.write(
"Sign in." % users.create_login_url("/"))
You can find similar examples in the documentation, but after authentication, you will be able to access the user_id method.
I am running a Google App Engine project where everytime the user takes an action I want to check to see if the user is 1)logged in 2)an admin. This is the code I have for the appuser:
class AppUser
{
private UserService userService;
private User user;
public AppUser()
{
userService = UserServiceFactory.getUserService();
user = userService.getCurrentUser();
}
public IsAdministrator()
{
if(IsLoggedIn())
{
return userService.IsUserAdmin();
}
return false;
}
public IsLoggedIn()
{
return user == null;
}
}
When I log out with my app this works fine. However, if I log out on another page (like on google calendars or something) the app still thinks I'm logged in. Is there another better way to check if the user is still logged in?
Also I know that this can be done with security-constraint in the web.xml however that will not work in this case as I need to take certain actions if the user has logged off.
I am using App Engine SDK 1.7 and GWT SDK 2.4
Two ways to notify app about user logging out:
Synchronously - server actively notifies client (browser) about log-out. Use Channels API to send push notification to client. There is a GWT wrapper.
Asynchronously - server notifies client about log-out when client makes communication to server, i.e. in every RPC call add authentication check. If user id logged-out, raise an exception, which can be handled by GWT.
I ran into this today, though it was worse: I'd logged out as user A (from a Google Sites page), and logged in as user B, but my GAE app still thought I was logged in as user A. Argh.
The reason for this is that there are two cookies involved, one for tracking which Google user is logged into Google, and another for tracking which GAE application user is logged into my GAE application. Recall that a GAE could be using any federated authentication service, not just Google's. My application has no access to the google.com cookies, so I can't directly check whether user A is still logged in (or which user is currently logged in).
Unfortunately, I've not yet found a straight forward "federated logOUT" mechanism, though it is possible that Google Identity Toolkit can be used for detecting that the expected user is no longer logged in.
I found others discussing this issue:
How to manage multiple accounts login and logout in different browser pages?
UserService retrieves wrong user after logout
Update
I came up with a solution that works for my application, where I have a page that redirects the user, a student, to his or her classroom's home page. Since this is accessed infrequently by any one student (a few times a day), but which needs to know which student is logged in, I took the following approach which works for me:
User goes to page A, which clears the ACSID and SACSID cookies, and redirects to Google for the user to login.
User is probably already logged in, so Google (with several redirects) updates the ACSID and SACSID cookies to the currently logged in user, and redirects back to my application at page B.
Page B finally takes action on behalf of the logged in user, "confident" that the correct user is logged in (to the extent that pages are confident). ;-)
Here's a code sketch of the approach:
# My BaseHandler has a clear_cookie
class LoginAndRedirectHandler(base_handler.BaseHandler):
def get(self):
self.clear_cookie('ACSID')
self.clear_cookie('SACSID')
self.clear_cookie('dev_appserver_login')
if 'continue' in self.request.params and \
self.request.params['continue'].startswith('/'):
url = self.request.params['continue']
else:
# Whatever your page is that needs an up to date logged in user
url = users.create_login_url('/PageB')
if isinstance(url, unicode):
url = url.encode('utf8')
logging.info('Redirecting to ' + url)
self.redirect(url)
return
The reason I said infrequently above is that this process is expensive in time, with at least 4 or 5 redirects involved.
i am using SimpleAuth by Alex (https://github.com/crhym3/simpleauth) in my GAE application. I have a Jquery Powered Login box in my base template which means users can login from any url inside the application. I want the users to be redirected back to the page they requested to login from. Is there any way we can achieve this with Oauth2 or can we just redirect users back to only a specific url ??
If you're using SimpleAuth I assume you're probably with webapp2, so #jmort253 examples are not exactly how I would do it (e.g. webapp2 has built-in sessions, so why use yet another library for sessions handling).
Though, conceptually it is correct: what you need is store original URL somewhere in a session before starting authentication process. Then use that stored URL for a final redirect, after successful authentication.
Starting from the example app code of SimpleAuth, what you basically need to change is the last line of _on_signin() to redirect users to that original URL they came from (instead of '/profile').
To store the original request URL you could use a simple wrapper, e.g.
def simpleauth_login_required(handler_method):
"""A decorator to require that a user be logged in to access a handler.
To use it, decorate your get() method like this:
#simpleauth_login_required
def get(self):
user = self.current_user
self.response.out.write('Hello, ' + user.name())
"""
def check_login(self, *args, **kwargs):
if self.request.method != 'GET':
self.abort(400, detail='The login_required decorator '
'can only be used for GET requests.')
if self.logged_in:
handler_method(self, *args, **kwargs)
else:
self.session['original_url'] = self.request.url
self.redirect('/my-login-page-where-users-can-choose-auth-method')
return check_login
Now, going back to that _on_signin() redirect line, instead of self.redirect('/profile') you'd do something like this:
target = self.session['original_url']
self.redirect(target)
A couple notes:
the example above assumes you have a logged_in method which indicates whether the current request is made by an already authenticated user or not;
you'll probably want to clear 'original_url' from the session (if they successfully authenticated)
The above example's credits go to webapp2_extras.appengine.users module.
When your user attempts to log in, your app first requests an access token then builds the Google OAuth2 URL. Your app redirects the user to google.com where your user must login. This login URL contains the access token from your server's request to Google. It's tied to that redirect URL for security purposes.
This redirect URL is designed to finalize the login process by returning a successful login operation to your app so that you can then finish logging in the user, registering that user, or doing whatever it is that your app would need to do.
After that, the ball is in your court, and you can program your app to do whatever you want. In other words, Google just cares about getting the request to your secure endpoint. Once that's done, Google no longer cares what you do; it's your app.
Therefore, to redirect your user back to the page he/she was on before logging in, which is an awesome usability improvement, is to do the following:
Steps to Redirect user:
1 Before the user logs in, store the page he/she is on in a session.
session = appengine_utilities.sessions.Session()
session["target_url"] = "/example_page.html" # sets keyname to current page
2 Next, go ahead and log the user in as normal.
3 After Google redirects the user to your authentication redirect URL, retrieve the target URL from the session:
target_url = session['target_url']
4 Lastly, redirect the user to this URL.
In short, you can accomplish the goal of redirecting your user to any target URL, so long as you first accept the redirect from Google to a single, established redirect URL.
The session examples came from the Beaker website. Additionally, Nick Johnson's Webapps on Appengine Part 5 Blog article dives into sessions with Beaker.
In app engine I am using
username= users.get_current_user()
query = gdata.contacts.service.ContactsQuery()
query.max_results = 10000
feed=gd_client.GetContactsFeed(query.ToUri())
to access the contacts of the user who is logged in.
I want to access another users contacts who users my app. This other user has given authsub and I have saved the token.
What do I do to access the other user, changing the username is obviously not enough because I must have to point it to the correct token.
How do I do this?
See http://code.google.com/apis/accounts/docs/OAuth2WebServer.html#offline. You have to get a contacts client authenticated using your stored token, and connect to the service that way. This is less of a GAE and more of a Google Apps API question btw.