def login(): # If user is already logged in, send them back if g.user: return redirect(get_next_url(referrer=True), code=303) loginform = LoginForm() openidform = OpenIdForm(csrf_session_key='csrf_openid') if request.method == 'GET': openidform.openid.data = 'http://' formid = request.form.get('form.id') if request.method == 'POST' and formid == 'openid': if openidform.validate(): return oid.try_login(openidform.openid.data, ask_for=['email', 'fullname', 'nickname']) elif request.method == 'POST' and formid == 'login': if loginform.validate(): user = loginform.user login_internal(user) if loginform.remember.data: session.permanent = True else: session.permanent = False flash('You are now logged in', category='info') return render_redirect(get_next_url(), code=303) if request.is_xhr and formid == 'login': return render_template('forms/loginform.html', loginform=loginform) else: return render_template('login.html', openidform=openidform, loginform=loginform, oiderror=oid.fetch_error(), oidnext=oid.get_next_url())
def logout_client(): """ Client-initiated logout """ client = Client.query.filter_by(key=request.args['client_id']).first() if client is None: # No such client. Possible CSRF. Don't logout and don't send them back flash(logout_errormsg, 'error') return redirect(url_for('index')) if client.trusted: # This is a trusted client. Does the referring domain match? clienthost = urlparse.urlsplit(client.redirect_uri).hostname if request.referrer: if clienthost != urlparse.urlsplit(request.referrer).hostname: # Doesn't. Don't logout and don't send back flash(logout_errormsg, 'error') return redirect(url_for('index')) # else: no referrer? Either stripped out by browser or a proxy, or this is a direct link. # We can't do anything about that, so assume it's a legit case. # # If there is a next destination, is it in the same domain? if 'next' in request.args: if clienthost != urlparse.urlsplit(request.args['next']).hostname: # Doesn't. Assume CSRF and redirect to index without logout flash(logout_errormsg, 'error') return redirect(url_for('index')) # All good. Log them out and send them back logout_internal() return redirect(get_next_url(external=True)) else: # We know this client, but it's not trusted. Send back without logout. return redirect(get_next_url(external=True))
def login_twitter_authorized(resp): next_url = get_next_url() if resp is None: flash(u'You denied the request to login via Twitter.') return redirect(next_url) # Try to read more from the user's Twitter profile try: twinfo = json.loads(urlopen('http://api.twitter.com/1/users/lookup.json?%s' % urlencode({'user_id': resp['user_id']})).read())[0] return_url = config_external_id(service='twitter', service_name='Twitter', user=None, userid=resp['user_id'], username=resp['screen_name'], fullname=twinfo.get('name', '@' + resp['screen_name']), avatar=twinfo.get('profile_image_url').replace("normal.", "bigger."), access_token=resp['oauth_token'], secret=resp['oauth_token_secret'], token_type=None, next_url=next_url) if return_url is not None: next_url = return_url except URLError: twinfo = {} # Redirect with 303 because users hitting the back button # cause invalid/expired token errors from Twitter return redirect(next_url, code=303)
def login_github(): next_url = get_next_url(referrer=False) try: return redirect(github['auth_url'] % (github['key'], url_for('login_github_authorized', _external=True, next=quote(next_url)))) except OAuthException, e: flash(u"GitHub login failed: %s" % unicode(e), category="error") return redirect(next_url)
def login_twitter(): next_url = get_next_url(referrer=False) try: return twitter.authorize(callback=url_for('login_twitter_authorized', next=next_url)) except OAuthException, e: flash("Twitter login failed: %s" % unicode(e), category="error") return redirect(url_for('login'))
def logout_user(): """ User-initiated logout """ if not request.referrer or (urlparse.urlsplit(request.referrer).hostname != urlparse.urlsplit(request.url).hostname): # TODO: present a logout form flash(logout_errormsg, 'error') return redirect(url_for('index')) else: logout_internal() flash('You are now logged out', category='info') return redirect(get_next_url())
def profile_edit(): form = ProfileForm(obj=g.user) form.edit_obj = g.user if form.validate_on_submit(): form.populate_obj(g.user) db.session.commit() next_url = get_next_url() if next_url is not None: return render_redirect(next_url) else: flash("Your profile was successfully edited.", category='info') return render_redirect(url_for('profile'), code=303) return render_form(form, title="Edit profile", formid="profile_edit", submit="Save changes", ajax=True)
def login_github_authorized(): next_url = get_next_url() if request.args.get('error'): if request.args['error'] == 'user_denied': flash(u"You denied the GitHub login request", category='error') else: flash(u"GitHub login failed", category="error") return redirect(next_url, code=303) code = request.args.get('code', None) params = urlencode({ 'client_id': github['key'], 'client_secret': github['secret'], 'code': code }) # Try to read more from the user's Github profile try: response = urlopen(github['token_url'], params).read() respdict = parse_qs(response) access_token = respdict['access_token'][0] token_type = respdict['token_type'][0] ghinfo = json.loads(urlopen(github['user_info'] % access_token).read()) md5sum = get_gravatar_md5sum(ghinfo['avatar_url']) user = None if md5sum: # Look for an existing user account useremail = UserEmail.query.filter_by(md5sum=md5sum).first() if useremail: user = useremail.user return_url = config_external_id(service='github', service_name='GitHub', user=user, userid=ghinfo.get('login'), username=ghinfo.get('login'), fullname=ghinfo.get('name'), avatar=ghinfo.get('avatar_url'), access_token=access_token, secret=github['secret'], token_type=token_type, next_url=next_url) if return_url is not None: next_url = return_url except URLError, e: ghinfo = {} flash(u"GitHub login failed" % unicode(e), category="error")
def login_openid_success(resp): """ Called when OpenID login succeeds """ openid = resp.identity_url if openid.startswith('https://profiles.google.com/') or openid.startswith('https://www.google.com/accounts/o8/id?id='): service = 'google' else: service = 'openid' extid = UserExternalId.query.filter_by(service=service, userid=openid).first() if extid is not None: login_internal(extid.user) session['userid_external'] = {'service': service, 'userid': openid} flash("You are now logged in", category='info') return redirect(get_next_url()) else: firsttime = True username = None if resp.email: useremail = UserEmail.query.filter_by(email=resp.email).first() if openid.startswith('https://profiles.google.com/') or openid.startswith('https://www.google.com/accounts/o8/id?id='): # Google id. Trust the email address. if useremail: # User logged in previously using a different Google OpenID endpoint # Add this new endpoint to the existing user account user = useremail.user firsttime = False else: # No previous record for email address, so register a new user user = register_internal(None, resp.fullname or resp.nickname or openid, None) user.add_email(resp.email, primary=True) else: # Not a Google id. Do not trust an OpenID-provided email address. # This must be treated as a claim, not as a confirmed email address. # Step 1. Make a new account user = register_internal(None, resp.fullname or resp.nickname or openid, None) # Step 2. If this email address is not already known, register a claim. # If it is an existing registered email address, ignore it. OpenID metadata # cannot be trusted; anyone can setup an OpenID server that will allow the user # to claim any email address. if not useremail: emailclaim = UserEmailClaim(user=user, email=resp.email) db.session.add(emailclaim) send_email_verify_link(emailclaim) else: # First login and no email address provided. Create a new user account user = register_internal(None, resp.fullname or resp.nickname or openid, None) # Set username for Google ids if openid.startswith('https://profiles.google.com/'): # Use profile name as username parts = openid.split('/') while not parts[-1]: parts.pop(-1) username = parts[-1] elif openid.startswith('https://www.google.com/accounts/o8/id?id='): # Use email address as username username = resp.email # Record this OpenID/Google id for the user extid = UserExternalId(user=user, service=service, userid=openid, username=username, oauth_token=None, oauth_token_secret=None) db.session.add(extid) db.session.commit() login_internal(user) session['userid_external'] = {'service': service, 'userid': openid} if firsttime: flash("You are now logged in. This is your first time here, so please fill in a few details about yourself", category='info') return redirect(url_for('profile_edit', _external=True, next=get_next_url())) else: flash("You are now logged in.", category='info') return redirect(get_next_url())