Пример #1
0
def openid_end(return_url, request):
    """Step two of logging in; the OpenID provider redirects back here."""

    cons = Consumer(session=request.session, store=openid_store)
    params = request.params

    if 'return_key' in params and not key_from_request(request):
        # We've followed a return_key that has terminated at the OpenID request
        # i.e. this is a stashed OpenID request (or a bogus return_key); the
        # OpenID request will therefore NOT have the return_key in its
        # return_to URL, so strip it
        log.debug("OpenID check stripping stale or bogus return_key(s) '{0}'"
                  .format(params.getall('return_key')))
        # Janrain OpenID treats params as a normal dict, so it's safe to lose
        # the MultiDict here (AFAICT).
        params = dict((k, v) for k, v in params.iteritems() if k != 'return_key')

    res = cons.complete(params, return_url)

    if res.status == SUCCESS:
        pass

    elif res.status == FAILURE:
        # The errors are, very helpfully, plain strings.  Nevermind that
        # there's a little hierarchy of exception classes inside the openid
        # library; they all get squashed into homogenous goo in the return
        # value.  F*****g awesome.  Check for a few common things here and
        # assume the rest are wacky internal errors
        log.error('openid failure: ' + res.message)

        if res.message == 'Nonce already used or out of range':
            # You tend to get this if you hit refresh on login_finish
            raise OpenIDError("Sorry!  Your login attempt expired; please start over.")
        else:
            raise OpenIDError("Something has gone hilariously wrong.")

    elif res.status == CANCEL:
        raise OpenIDError("Looks like you canceled the login.")

    else:
        log.error("Unexpected OpenID return status '{0}' with message '{1}'"
                  .format(res.status, res.message))
        raise OpenIDError("Something has gone hilariously wrong.")

    identity_url = unicode(res.identity_url)
    identity_webfinger = request.session.pop('pending_identity_webfinger', None)

    sreg_res = SRegResponse.fromSuccessResponse(res) or dict()
    pape_res = PAPEResponse.fromSuccessResponse(res)
    auth_time = pape_res.auth_time

    return identity_url, identity_webfinger, auth_time, sreg_res
Пример #2
0
def account_login(context, request):
    # XXX worth mentioning on this page how to log in with SSL, and offer a
    # crypto link if they already hit cancel and want to try again

    # Auto-fill OpenID on re-auth
    return_key = key_from_request(request)
    openid = request.auth.openid_url if return_key else None

    # just_landed is imprecise, but should serve to reduce false positives
    just_landed = request.referrer is None
    just_landed = just_landed or (request.host not in request.referrer)
    if not request.cookies and not just_landed:
        request.session.flash(
                'It looks like you might not have cookies enabled in your '
                'browser.  Alas, cookies are required to log in.  If you '
                'think this message is in error, try refreshing the page.',
                icon='cookie--exclamation', level='warning')

    form = LoginForm(openid_identifier=openid, return_key=return_key)
    return {'form': form}
Пример #3
0
def account_login(context, request):
    # XXX worth mentioning on this page how to log in with SSL, and offer a
    # crypto link if they already hit cancel and want to try again

    # Auto-fill OpenID on re-auth
    return_key = key_from_request(request)
    openid = request.auth.openid_url if return_key else None

    # just_landed is imprecise, but should serve to reduce false positives
    just_landed = (request.referrer is None or
                   request.host not in request.referrer)
    if not request.cookies and not just_landed:
        request.session.flash(
                'It looks like you might not have cookies enabled in your '
                'browser.  Alas, cookies are required to log in.  If you '
                'think this message is in error, try refreshing the page.',
                icon='cookie--exclamation', level='warning')

    form = LoginForm(openid_identifier=openid, return_key=return_key)
    return {'form': form}
Пример #4
0
def account_login_browserid(context, request):
    return_key = key_from_request(request)

    def fail(msg=None):
        if msg:
            request.session.flash(msg, level=u'error', icon='key--exclamation')
        # XXX setting the status to 403 triggers Pyramid's exception view
        next_url = request.route_url('account.login')
        if return_key is not None:
            next_url = update_params(next_url, return_key=return_key)
        return {'next_url': next_url}

    ## Verify the identity assertion

    assertion = request.POST.get('assertion')
    try:
        data = verify_browserid(assertion, request)
    except BrowserIDError as e:
        flash_browserid_error(e, request)
        return fail()

    ## Attempt to resolve the identity to a local user

    email = data.get('email')
    if data.get('status') != 'okay' or not email:
        return fail("BrowserID authentication failed.")

    identity_email = model.session.query(IdentityEmail) \
        .filter_by(email=email) \
        .limit(1).first()

    if not identity_email:
        # New user or new ID
        request.session['pending_identity_email'] = email
        return {'next_url': request.route_url('account.register'),
                'post_id': 'postform'}

    ## Attempt to log in

    try:
        auth_headers = security.remember(
            request, identity_email.user, browserid_email=email)
        request.session.changed()

    except BrowserIDNotFoundError:
        return fail("The email address '{0}' is registered against the account "
                    "'{1}'.  To log in as '{1}', log out then back in."
                    .format(email, identity_email.user.name))

    except BrowserIDAuthDisabledError:
        return fail("Your BrowserID is no longer accepted as your account has "
                    "disabled BrowserID authentication.")

    # An existing user has logged in successfully.  Bravo!
    request.response.headerlist.extend(auth_headers)
    log.debug("User {0} logged in via BrowserID: {1}"
              .format(identity_email.user.name, identity_email))

    ## Handle redirection

    if identity_email.user == request.user:
        # Someone is just freshening up their cookie
        request.session.flash(u'Re-authentication successful', icon='user')

        if return_key is not None:
            old_url = fetch_stash(request, key=return_key)['url']
            if old_url:
                next_url = update_params(old_url, return_key=return_key)
                log.debug('Following Return Key \'{0}\' to URL: {1}'
                          .format(return_key, next_url))
                return {'next_url': next_url}

        return {'next_url': request.route_url('root')}

    # Existing user; new login
    request.session.flash(
            'Logged in with BrowserID', level=u'success', icon='user')

    return {'next_url': request.route_url('root')}
Пример #5
0
def account_login_xhr(context, request):
    return_key = key_from_request(request)
    next_url = request.route_url('account.login')
    if return_key is not None:
        next_url = update_params(next_url, return_key=return_key)
    return {'next_url': next_url}
Пример #6
0
def login_finish(context, request):
    """Step two of logging in; the OpenID provider redirects back here."""

    def retry():
        """Redirect to the login page, preserving the return key (if any)."""
        location = request.route_url('account.login')
        if return_key:
            location = update_params(location, return_key=return_key)
        return HTTPSeeOther(location=location)

    return_url = request.route_url('account.login_finish')

    return_key = key_from_request(request)
    if return_key is not None:
        return_url = update_params(return_url, return_key=return_key)

    try:
        identity_url, identity_webfinger, auth_time, sreg_res = openid_end(
            return_url=return_url,
            request=request)
    except OpenIDError as exc:
        request.session.flash(exc.message,
            level='error', icon='key--exclamation')
        return retry()

    # Find who owns this URL, if anyone
    identity_owner = model.session.query(User) \
        .filter(User.identity_urls.any(url=identity_url)) \
        .limit(1).first()

    if not identity_owner:
        if return_key:
            request.session.flash('Unknown OpenID URL.',
                level='error', icon='key--exclamation')
            return retry()
        # Someone is either registering a new account, or adding a new OpenID
        # to an existing account
        request.session['pending_identity_url'] = identity_url
        request.session.changed()

        # Try to pull a name and email address out of the SReg response
        username = re.sub(u'[^_a-z0-9]', u'',
            sreg_res.get('nickname', u'').lower())
        form = RegistrationForm(
            username=username,
            email=sreg_res.get('email', u''),
            timezone=sreg_res.get('timezone', u'UTC'),
        )
        return render_to_response(
            'account/register.mako',
            dict(
                form=form,
                identity_url=identity_url,
                identity_webfinger=identity_webfinger,
                identity_email=None),
            request=request)

    elif identity_owner == request.user:
        # Someone is just freshening up their cookie
        auth_headers = safe_openid_login(request, identity_owner, identity_url)
        if auth_headers is None:
            return retry()

        request.session.flash(u'Re-authentication successful', icon='user')

        if return_key:
            # Fetch a stashed request
            old_url = fetch_stash(request, key=return_key)['url']
            if old_url:
                location = update_params(old_url, return_key=return_key)
                log.debug('Following Return Key \'{0}\' to URL: {1}'
                          .format(return_key, location))
                return HTTPSeeOther(location, headers=auth_headers)
        return HTTPSeeOther(request.route_url('root'), headers=auth_headers)

    else:
        # Existing user; new login
        # Log the successful OpenID authentication, mindful of users that may
        # have OpenID logins disabled, for instance.
        # XXX should we deny a logged-in user to authenticate as another user?
        auth_headers = security.forget(request)
        headers = safe_openid_login(request, identity_owner, identity_url)

        if headers is None:
            return retry()

        auth_headers += headers

        # An existing user has logged in successfully.  Bravo!
        log.debug("User {0!r} logged in via OpenID: {1!r}"
                  .format(identity_owner.name, identity_url))

        request.session.flash(
            u"Welcome back, {0}!"
            .format(identity_owner.display_name or identity_owner.name),
            level=u'success', icon='user')

        # XXX this should ALSO probably do the return_key redirect, good grief
        return HTTPSeeOther(
            location=request.route_url('root'),
            headers=auth_headers)
Пример #7
0
def account_login_persona(context, request):
    return_key = key_from_request(request)

    def fail(msg=None, exc=None):
        if msg:
            request.session.flash(msg, level=u'error', icon='key--exclamation')
        # XXX setting the status to 403 triggers Pyramid's exception view
        next_url = request.route_url('account.login')
        if return_key is not None:
            next_url = update_params(next_url, return_key=return_key)
        return {
            'status': 'redirect',
            'redirect-to': next_url,
        }

    ## Verify the identity assertion

    assertion = request.POST.get('assertion')
    try:
        data = verify_persona(assertion, request)
    except PersonaError as e:
        flash_persona_error(e, request)
        return fail()

    ## Attempt to resolve the identity to a local user

    email = data.get('email')
    if data.get('status') != 'okay' or not email:
        return fail("Persona authentication failed.")

    identity_email = model.session.query(IdentityEmail) \
        .filter_by(email=email) \
        .limit(1).first()

    if not identity_email:
        # New user or new ID
        request.session['pending_identity_email'] = email
        return {
            'status': 'redirect',
            'redirect-to': request.route_url('account.register'),
        }

    ## Attempt to log in

    try:
        auth_headers = security.remember(
            request, identity_email.user, persona_addr=email)
        request.session.changed()

    except PersonaNotFoundError:
        return fail("The email address '{0}' is registered against the account "
                    "'{1}'.  To log in as '{1}', log out then back in."
                    .format(email, identity_email.user.name))

    except PersonaAuthDisabledError:
        return fail("Your Persona is no longer accepted as your account has "
                    "disabled Persona authentication.")

    # An existing user has logged in successfully.  Bravo!
    request.response.headerlist.extend(auth_headers)
    log.debug("User {0} logged in via Persona: {1}"
              .format(identity_email.user.name, identity_email))

    ## Handle redirection

    if identity_email.user == request.user:
        # Someone is just freshening up their cookie
        request.session.flash(u'Re-authentication successful', icon='user')

        if return_key is not None:
            old_url = fetch_stash(request, key=return_key)['url']
            if old_url:
                next_url = update_params(old_url, return_key=return_key)
                log.debug('Following Return Key \'{0}\' to URL: {1}'
                          .format(return_key, next_url))
                return {
                    'status': 'redirect',
                    'redirect-to': next_url,
                }

    else:
        # Existing user; new login
        request.session.flash(
                'Logged in with Persona', level=u'success', icon='user')

    # XXX this seems a mite fragile
    redirect = request.route_url('root')
    pathq = request.POST.get('pathq')
    if pathq and not pathq.startswith(request.route_path('account.login')):
        scheme, netloc = urlparse(redirect)[:2]
        redirect = urlunparse((scheme, netloc, pathq, '', '', ''))

    return {
        'status': 'redirect',
        'redirect-to': redirect,
    }
Пример #8
0
def account_login_xhr(context, request):
    return_key = key_from_request(request)
    next_url = request.route_url('account.login')
    if return_key is not None:
        next_url = update_params(next_url, return_key=return_key)
    return {'next_url': next_url}
Пример #9
0
def login_finish(context, request):
    """Step two of logging in; the OpenID provider redirects back here."""

    def retry():
        """Redirect to the login page, preserving the return key (if any)."""
        location = request.route_url('account.login')
        if return_key:
            location = update_params(location, return_key=return_key)
        return HTTPSeeOther(location=location)

    return_url = request.route_url('account.login_finish')

    return_key = key_from_request(request)
    if return_key is not None:
        return_url = update_params(return_url, return_key=return_key)

    try:
        identity_url, identity_webfinger, auth_time, sreg_res = openid_end(
            return_url=return_url,
            request=request)
    except OpenIDError as exc:
        request.session.flash(exc.message,
            level='error', icon='key--exclamation')
        return retry()

    # Find who owns this URL, if anyone
    identity_owner = model.session.query(User) \
        .filter(User.identity_urls.any(url=identity_url)) \
        .limit(1).first()

    if not identity_owner:
        if return_key:
            request.session.flash('Unknown OpenID URL.',
                level='error', icon='key--exclamation')
            return retry()
        # Someone is either registering a new account, or adding a new OpenID
        # to an existing account
        request.session['pending_identity_url'] = identity_url
        request.session.changed()

        # Try to pull a name and email address out of the SReg response
        username = re.sub(u'[^_a-z0-9]', u'',
            sreg_res.get('nickname', u'').lower())
        form = RegistrationForm(
            username=username,
            email=sreg_res.get('email', u''),
            timezone=sreg_res.get('timezone', u'UTC'),
        )
        return render_to_response(
            'account/register.mako',
            dict(
                form=form,
                identity_url=identity_url,
                identity_webfinger=identity_webfinger,
                identity_email=None),
            request=request)

    elif identity_owner == request.user:
        # Someone is just freshening up their cookie
        auth_headers = safe_openid_login(request, identity_owner, identity_url)
        if auth_headers is None:
            return retry()

        request.session.flash(u'Re-authentication successful', icon='user')

        if return_key:
            # Fetch a stashed request
            old_url = fetch_stash(request, key=return_key)['url']
            if old_url:
                location = update_params(old_url, return_key=return_key)
                log.debug('Following Return Key \'{0}\' to URL: {1}'
                          .format(return_key, location))
                return HTTPSeeOther(location, headers=auth_headers)
        return HTTPSeeOther(request.route_url('root'), headers=auth_headers)

    else:
        # Existing user; new login
        # Log the successful OpenID authentication, mindful of users that may
        # have OpenID logins disabled, for instance.
        # XXX should we deny a logged-in user to authenticate as another user?
        auth_headers = security.forget(request)
        headers = safe_openid_login(request, identity_owner, identity_url)

        if headers is None:
            return retry()

        auth_headers += headers

        # An existing user has logged in successfully.  Bravo!
        log.debug("User {0!r} logged in via OpenID: {1!r}"
                  .format(identity_owner.name, identity_url))

        request.session.flash(
            u"Welcome back, {0}!"
            .format(identity_owner.display_name or identity_owner.name),
            level=u'success', icon='user')

        # XXX this should ALSO probably do the return_key redirect, good grief
        return HTTPSeeOther(
            location=request.route_url('root'),
            headers=auth_headers)