Exemplo n.º 1
0
def process_response(response):
    if request.endpoint in ('static', 'baseframe.static'):
        if 'Access-Control-Allow-Origin' not in response.headers:
            # This is required for webfont resources
            # Note: We do not serve static assets in production, nginx does.
            # That means this piece of code will never be called in production.
            response.headers['Access-Control-Allow-Origin'] = '*'

    # If Babel was accessed in this request, the response's contents will vary with
    # the accepted language
    if ctx_has_locale():
        response.vary.add('Accept-Language')
    # If current_auth was accessed during this request, it is sensitive to the lastuser
    # cookie
    if request_has_auth():
        response.vary.add('Cookie')

    # Prevent pages from being placed in an iframe. If the response already
    # set has a value for this option, let it pass through
    if 'X-Frame-Options' in response.headers:
        frameoptions = response.headers.get('X-Frame-Options')
        if not frameoptions or frameoptions == 'ALLOW':
            # 'ALLOW' is an unofficial signal from the app to Baseframe.
            # It signals us to remove the header and not set a default
            response.headers.pop('X-Frame-Options')
    else:
        if request_has_auth() and getattr(current_auth, 'login_required',
                                          False):
            # Protect only login_required pages from appearing in frames
            response.headers['X-Frame-Options'] = 'SAMEORIGIN'

    # In memoriam. http://www.gnuterrypratchett.com/
    response.headers['X-Clacks-Overhead'] = 'GNU Terry Pratchett'

    return response
Exemplo n.º 2
0
def update_user_session_timestamp(response):
    """Mark a user session as accessed at the end of every request."""
    if request_has_auth() and current_auth.session:
        # Setup a callback to update the session after the request has returned a
        # response to the user-agent. There will be no request or app context in this
        # callback, so we create a closure containing the necessary data in local vars
        user_session = current_auth.session
        ipaddr = request.remote_addr
        user_agent = str(request.user_agent.string[:250])

        @response.call_on_close
        def mark_session_accessed_after_response():
            # App context is needed for the call to statsd in mark_accessed()
            with app.app_context():
                # 1. Add object back to the current database session as it's not
                # known here. We are NOT using session.merge as we don't need to
                # refresh data from the db. SQLAlchemy will automatically load
                # missing data should that be necessary (eg: during login)
                db.session.add(user_session)
                # 2. Update user session access timestamp
                user_session.views.mark_accessed(ipaddr=ipaddr, user_agent=user_agent)
                # 3. Commit it
                db.session.commit()

    return response
Exemplo n.º 3
0
def lastuser_cookie(response):
    """
    Save lastuser login cookie and hasuser JS-readable flag cookie.
    """
    if request_has_auth() and hasattr(current_auth, 'cookie'):
        expires = utcnow() + timedelta(days=365)
        response.set_cookie(
            'lastuser',
            value=lastuser_oauth.serializer.dumps(current_auth.cookie,
                                                  header_fields={'v': 1}),
            max_age=31557600,  # Keep this cookie for a year.
            expires=expires,  # Expire one year from now.
            domain=current_app.config.get(
                'LASTUSER_COOKIE_DOMAIN'),  # Place cookie in master domain.
            secure=current_app.
            config['SESSION_COOKIE_SECURE'],  # HTTPS cookie if session is too.
            httponly=True)  # Don't allow reading this from JS.

        response.set_cookie(
            'hasuser',
            value='1' if current_auth.is_authenticated else '0',
            max_age=31557600,  # Keep this cookie for a year.
            expires=expires,  # Expire one year from now.
            secure=current_app.
            config['SESSION_COOKIE_SECURE'],  # HTTPS cookie if session is too.
            httponly=False)  # Allow reading this from JS.

    return response
Exemplo n.º 4
0
def lastuser_cookie(response):
    """
    Save lastuser login cookie and hasuser JS-readable flag cookie.
    """
    if request_has_auth() and hasattr(current_auth, 'cookie'):
        expires = datetime.utcnow() + timedelta(days=365)
        response.set_cookie('lastuser',
            value=lastuser_oauth.serializer.dumps(current_auth.cookie, header_fields={'v': 1}),
            max_age=31557600,                                         # Keep this cookie for a year.
            expires=expires,                                          # Expire one year from now.
            domain=current_app.config.get('LASTUSER_COOKIE_DOMAIN'),  # Place cookie in master domain.
            httponly=True)                                            # Don't allow reading this from JS.

        response.set_cookie('hasuser',
            value='1' if current_auth.is_authenticated else '0',
            max_age=31557600,              # Keep this cookie for a year.
            expires=expires,               # Expire one year from now.
            httponly=False)                # Allow reading this from JS.

    return response
Exemplo n.º 5
0
def set_lastuser_cookie(response):
    """Save lastuser login cookie and hasuser JS-readable flag cookie."""
    if request_has_auth() and hasattr(current_auth, 'cookie'):
        expires = utcnow() + timedelta(days=365)
        response.set_cookie(
            'lastuser',
            value=lastuser_serializer().dumps(
                current_auth.cookie, header_fields={'v': 1}
            ),
            # Keep this cookie for a year.
            max_age=31557600,
            # Expire one year from now.
            expires=expires,
            # Place cookie in master domain.
            domain=current_app.config.get('LASTUSER_COOKIE_DOMAIN'),
            # HTTPS cookie if session is too.
            secure=current_app.config['SESSION_COOKIE_SECURE'],
            # Don't allow reading this from JS.
            httponly=True,
            # Don't allow lastuser cookie outside first-party use
            samesite='Strict',
        )

        response.set_cookie(
            'hasuser',
            value='1' if current_auth.is_authenticated else '0',
            # Keep this cookie for a year.
            max_age=31557600,
            # Expire one year from now.
            expires=expires,
            # HTTPS cookie if session is too.
            secure=current_app.config['SESSION_COOKIE_SECURE'],
            # Allow reading this from JS.
            httponly=False,
            # Allow this cookie to be read in third-party website context
            samesite='Lax',
        )

    return response
Exemplo n.º 6
0
def process_response(response):
    if request.endpoint in ('static', 'baseframe.static'):
        if 'Access-Control-Allow-Origin' not in response.headers:
            # This is required for webfont resources
            # Note: We do not serve static assets in production, nginx does.
            # That means this piece of code will never be called in production.
            response.headers['Access-Control-Allow-Origin'] = '*'

    if 'Vary' in response.headers:
        vary_values = [
            item.strip() for item in response.headers['Vary'].split(',')
        ]
        if 'Accept-Language' not in vary_values:
            vary_values.append('Accept-Language')
        if 'Cookie' not in vary_values:
            vary_values.append('Cookie')
        response.headers['Vary'] = ', '.join(vary_values)
    else:
        response.headers['Vary'] = 'Accept-Language, Cookie'

    # Prevent pages from being placed in an iframe. If the response already
    # set has a value for this option, let it pass through
    if 'X-Frame-Options' in response.headers:
        frameoptions = response.headers.get('X-Frame-Options')
        if not frameoptions or frameoptions == 'ALLOW':
            # 'ALLOW' is an unofficial signal from the app to Baseframe.
            # It signals us to remove the header and not set a default
            response.headers.pop('X-Frame-Options')
    else:
        if request_has_auth() and getattr(current_auth, 'login_required',
                                          False):
            # Protect only login_required pages from appearing in frames
            response.headers['X-Frame-Options'] = 'SAMEORIGIN'

    # In memoriam. http://www.gnuterrypratchett.com/
    response.headers['X-Clacks-Overhead'] = 'GNU Terry Pratchett'

    return response
Exemplo n.º 7
0
 def test_has_current_auth(self):
     """request_has_auth indicates if current_auth was invoked during a request"""
     assert not request_has_auth()
     # Invoke current_auth
     current_auth.is_anonymous  # skipcq: PYL-W0104
     assert request_has_auth()
Exemplo n.º 8
0
 def test_has_current_auth(self):
     """request_has_auth indicates if current_auth was invoked during a request"""
     self.assertFalse(request_has_auth())
     current_auth.is_anonymous  # Invoke current_auth
     self.assertTrue(request_has_auth())
Exemplo n.º 9
0
 def test_has_current_auth(self):
     """request_has_auth indicates if current_auth was invoked during a request"""
     self.assertFalse(request_has_auth())
     current_auth.is_anonymous  # Invoke current_auth
     self.assertTrue(request_has_auth())