Example #1
0
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())
Example #2
0
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))
Example #3
0
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)
Example #4
0
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)
Example #5
0
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'))
Example #6
0
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())
Example #7
0
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)
Example #8
0
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")
Example #9
0
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())