def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # Check if http referrer and given client id match a registered client if ('client_id' in request.values and 'session' in request.values and request.referrer): client_cred = AuthClientCredential.get(request.values['client_id']) if client_cred is not None and get_scheme_netloc( client_cred.auth_client.website) == get_scheme_netloc( request.referrer): if UserSession.authenticate( buid=request.values['session']) is not None: return f(*args, **kwargs) # If we didn't get a valid client_id and session, maybe there's a user? if current_auth.is_authenticated: return f(*args, **kwargs) # If user is not logged in, check for client credentials in the request authorization header. # If no error reported, call the function, else return error. result = _client_login_inner() if result is None: return f(*args, **kwargs) else: return result
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) if not current_auth.is_authenticated: flash(_(u"You need to be logged in for that page"), 'info') session['next'] = get_current_url() return redirect(url_for('login')) return f(*args, **kwargs)
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) if not current_auth.is_authenticated: flash(_("You need to be logged in for that page"), 'info') session['next'] = get_current_url() return redirect(url_for('login')) return f(*args, **kwargs)
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) if not current_auth.is_authenticated: session['next'] = get_current_url() if 'message' in request.args and request.args['message']: flash(request.args['message'], 'info') return redirect(url_for('login')) return f(*args, **kwargs)
def login_internal(user): add_auth_attribute('user', user) usersession = UserSession(user=user) usersession.access() add_auth_attribute('session', usersession) current_auth.cookie['sessionid'] = usersession.buid current_auth.cookie['userid'] = user.buid session.permanent = True autoset_timezone(user) user_login.send(user)
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # Check for user first: if current_auth.is_authenticated: return f(*args, **kwargs) # If user is not logged in, check for client result = _client_login_inner() if result is None: return f(*args, **kwargs) return result
def test_invalid_auth_attribute(self): for attr in ( 'actor', 'anchors', 'is_anonymous', 'not_anonymous', 'is_authenticated', 'not_authenticated', ): with pytest.raises(AttributeError): add_auth_attribute(attr, None)
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # Check for user first: if current_auth.is_authenticated: return f(*args, **kwargs) # If user is not logged in, check for client result = _client_login_inner() if result is None: return f(*args, **kwargs) else: return result
def test_currently_available_transitions(self): """State managers indicate the currently available transitions (using current_auth)""" assert self.post.state.DRAFT assert 'submit' not in self.post.state.transitions() add_auth_attribute( 'user', 'author' ) # Add a user using the string 'author' (see MyPost.roles_for) assert 'submit' in self.post.state.transitions() self.post.state.transitions()['submit']() assert not self.post.state.DRAFT assert self.post.state.PENDING
def test_currently_available_transitions(self): """State managers indicate the currently available transitions (using current_auth)""" self.assertTrue(self.post.state.DRAFT) self.assertNotIn('submit', self.post.state.transitions()) add_auth_attribute( 'user', 'author' ) # Add a user using the string 'author' (see MyPost.roles_for) self.assertIn('submit', self.post.state.transitions()) self.post.state.transitions()['submit']() self.assertFalse(self.post.state.DRAFT) self.assertTrue(self.post.state.PENDING)
def _client_login_inner(): if request.authorization is None or not request.authorization.username: return Response('Client credentials required', 401, {'WWW-Authenticate': 'Basic realm="Client credentials"'}) credential = ClientCredential.get(name=request.authorization.username) if credential is None or not credential.secret_is(request.authorization.password): return Response('Invalid client credentials', 401, {'WWW-Authenticate': 'Basic realm="Client credentials"'}) if credential: credential.accessed_at = db.func.utcnow() db.session.commit() add_auth_attribute('client', credential.client, actor=True)
def login_listener(self, userinfo, token): user = self.load_user_userinfo(userinfo, token['access_token'], update=True) user.lastuser_token = token['access_token'] user.lastuser_token_type = token['token_type'] user.lastuser_token_scope = token['scope'] add_auth_attribute('user', user) g.user = user # XXX: Deprecated, for backward compatibility only add_auth_attribute('lastuserinfo', self.make_userinfo(user)) self.update_teams(user) signal_user_looked_up.send(current_auth.user) return user
def logout_internal(): add_auth_attribute('user', None) if current_auth.session: current_auth.session.revoke() add_auth_attribute('session', None) session.pop('sessionid', None) session.pop('userid', None) session.pop('merge_userid', None) session.pop('merge_buid', None) session.pop('userid_external', None) session.pop('avatar_url', None) current_auth.cookie.pop('sessionid', None) current_auth.cookie.pop('userid', None) session.permanent = False
def logout(): code = LoginCode(next_url=get_next_url(external=False, referrer=True), return_url=url_for('logout_return', _external=True)) session.pop('userid', None) signal_logout.send(eventapp, user=current_auth.user) add_auth_attribute('user', None) g.user = None db.session.add(code) db.session.commit() if app.config.get('USE_SSL'): scheme = 'https://' else: scheme = 'http://' return redirect(urljoin(scheme + app.config['LOGIN_HOST'], '/logout?code=' + code.code))
def login_internal(user, user_session=None, login_service=None): """ Login a user and create a session. If the login is from funnelapp, reuse the existing session. """ add_auth_attribute('user', user) if not user_session or user_session.user != user: user_session = UserSession(user=user, login_service=login_service) user_session.views.mark_accessed() add_auth_attribute('session', user_session) current_auth.cookie['sessionid'] = user_session.buid current_auth.cookie['userid'] = user.buid session.permanent = True autoset_timezone_and_locale(user) user_login.send(user)
def test_other_actor_authenticated(self): assert current_auth.is_anonymous assert not current_auth.is_authenticated assert not current_auth assert current_auth.user is None client = Client() add_auth_attribute('client', client, actor=True) assert not current_auth.is_anonymous assert current_auth.is_authenticated assert current_auth assert current_auth.user is None # It's not the user assert current_auth.client == client # There's now a client attribute assert current_auth.actor == client # The client is also the actor
def test_other_actor_authenticated(self): self.assertTrue(current_auth.is_anonymous) self.assertFalse(current_auth.is_authenticated) self.assertFalse(current_auth) self.assertIsNone(current_auth.user) client = Client() add_auth_attribute('client', client, actor=True) self.assertFalse(current_auth.is_anonymous) self.assertTrue(current_auth.is_authenticated) self.assertTrue(current_auth) self.assertIsNone(current_auth.user) # It's not the user self.assertEqual(current_auth.client, client) # There's now a client attribute self.assertEqual(current_auth.actor, client) # The client is also the actor
def test_class_is_available(self): doc = ViewDocument(name='test1', title="Test") self.session.add(doc) self.session.commit() # First, confirm we're working with the correct view assert isinstance(doc.views.main(), ModelDocumentView) assert isinstance(doc.views.gated(), GatedDocumentView) # Since ModelDocumentView.view is not gated, ModelDocumentView is always # available. This is not the case for GatedDocumentView assert doc.views.main().is_always_available is True assert doc.views.main().is_available() is True assert doc.views.gated().is_always_available is False assert doc.views.gated().is_available() is False # If we add access permissions, the availability changes add_auth_attribute('user', 'this-is-the-owner') # See ViewDocument.permissions assert doc.views.gated().is_available() is True
def test_url_dict_current_roles(self): doc1 = ViewDocument(name='test1', title="Test 1") assert set(doc1.urls) == { 'view', # From ModelDocumentView 'edit', # From ModelDocumentView 'by_perm', # From GatedDocumentView (`urls` can't handle permission gating) } # Adding acess permissions changes the URLs available add_auth_attribute('user', 'this-is-the-owner') # See ViewDocument.permissions assert set(doc1.urls) == { # From ModelDocumentView 'view', 'edit', # From GatedDocumentView 'by_perm', 'by_role_perm', 'by_perm_role', 'by_role', }
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # Check if http referrer and given client id match a registered client if 'client_id' in request.values and 'session' in request.values and request.referrer: client_cred = ClientCredential.get(request.values['client_id']) if client_cred is not None and get_scheme_netloc(client_cred.client.website) == get_scheme_netloc(request.referrer): if UserSession.authenticate(buid=request.values['session']) is not None: return f(*args, **kwargs) # If we didn't get a valid client_id and session, maybe there's a user? if current_auth.is_authenticated: return f(*args, **kwargs) # If user is not logged in, check for client credentials in the request authorization header. # If no error reported, call the function, else return error. result = _client_login_inner() if result is None: return f(*args, **kwargs) else: return result
def before_request(self, access_token=None): if access_token == 'owner-admin-secret': add_auth_attribute('permissions', InspectableSet({'siteadmin'})) add_auth_attribute('user', 'this-is-the-owner') # See ViewDocument.permissions if access_token == 'owner-secret': add_auth_attribute('user', 'this-is-the-owner') # See ViewDocument.permissions return super(ModelDocumentView, self).before_request()
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # If the user is not logged in, require login first if not current_auth.is_authenticated: flash(_("You need to be logged in for that page"), 'info') session['next'] = get_current_url() return redirect(url_for('login')) # If the user has not authenticated in some time, ask for the password again if not current_auth.session.has_sudo: # If the user doesn't have a password, ask them to set one first if not current_auth.user.pw_hash: flash( _( "This operation requires you to confirm your password. However," " your account does not have a password, so you must set one" " first" ), 'info', ) session['next'] = get_current_url() return redirect(url_for('change_password')) # A future version of this form may accept password or 2FA (U2F or TOTP) form = PasswordForm(edit_user=current_auth.user) if form.validate_on_submit(): # User has successfully authenticated. Update their sudo timestamp and # reload the page with a GET request, as the wrapped view may need to # render its own form current_auth.session.set_sudo() db.session.commit() return redirect(request.url, code=303) return render_form( form=form, title=_("Confirm with your password to proceed"), formid='password', submit=_("Confirm"), ajax=False, template='account_formlayout.html.jinja2', ) return f(*args, **kwargs)
def test_requires_permission(self): with self.app.test_request_context(): assert permission1.is_available() is False assert permission2.is_available() is False with pytest.raises(Forbidden): permission1() with pytest.raises(Forbidden): permission2() add_auth_attribute('permissions', set()) assert permission1.is_available() is False assert permission2.is_available() is False with pytest.raises(Forbidden): permission1() with pytest.raises(Forbidden): permission2() current_auth.permissions.add( 'allow-that' ) # FIXME! Shouldn't this be a frozenset? assert permission1.is_available() is False assert permission2.is_available() is True with pytest.raises(Forbidden): permission1() assert permission2() == 'allowed2' current_auth.permissions.add('allow-this') assert permission1.is_available() is True assert permission2.is_available() is True assert permission1() == 'allowed1' assert permission2() == 'allowed2'
def before_request(self, access_token=None): if access_token == 'owner-secret': add_auth_attribute('user', 'this-is-the-owner') # See ViewDocument.permissions if access_token == 'editor-secret': add_auth_attribute('user', 'this-is-the-editor') # See ViewDocument.permissions if access_token == 'another-owner-secret': add_auth_attribute('user', 'this-is-another-owner') # See ViewDocument.permissions return super(GatedDocumentView, self).before_request()
def test_requires_permission(self): with self.app.test_request_context(): with self.assertRaises(Forbidden): permission1() with self.assertRaises(Forbidden): permission2() add_auth_attribute('permissions', set()) with self.assertRaises(Forbidden): permission1() with self.assertRaises(Forbidden): permission2() current_auth.permissions.add( 'allow-that') # FIXME! Shouldn't this be a frozenset? with self.assertRaises(Forbidden): permission1() assert permission2() == 'allowed2' current_auth.permissions.add('allow-this') assert permission1() == 'allowed1' assert permission2() == 'allowed2'
def test_requires_permission(self): with self.app.test_request_context(): assert permission1.is_available() is False assert permission2.is_available() is False with self.assertRaises(Forbidden): permission1() with self.assertRaises(Forbidden): permission2() add_auth_attribute('permissions', set()) assert permission1.is_available() is False assert permission2.is_available() is False with self.assertRaises(Forbidden): permission1() with self.assertRaises(Forbidden): permission2() current_auth.permissions.add('allow-that') # FIXME! Shouldn't this be a frozenset? assert permission1.is_available() is False assert permission2.is_available() is True with self.assertRaises(Forbidden): permission1() assert permission2() == 'allowed2' current_auth.permissions.add('allow-this') assert permission1.is_available() is True assert permission2.is_available() is True assert permission1() == 'allowed1' assert permission2() == 'allowed2'
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # Is there a user? Go right ahead if current_auth.is_authenticated: return f(*args, **kwargs) # Check if http referrer and given client id match a registered client if ( 'client_id' in request.values and 'session' in request.values and request.referrer ): client_cred = AuthClientCredential.get( abort_null(request.values['client_id']) ) if client_cred is not None and get_scheme_netloc( client_cred.auth_client.website ) == get_scheme_netloc(request.referrer): user_session = UserSession.authenticate( buid=abort_null(request.values['session']) ) if user_session is not None: # Add this user session to current_auth so the wrapped function # knows who it's operating for. However, this is not proper # authentication, so do not tag this as an actor. add_auth_attribute('session', user_session) return f(*args, **kwargs) # If we didn't get a valid client_id and session, and the user is not logged in, # check for client credentials in the request authorization header. # If no error reported, call the function, else return error. result = _client_login_inner() if result is None: return f(*args, **kwargs) return result
def lookup_current_user(user=None): add_auth_attribute('user', None) g.user = None add_auth_attribute('lastuserinfo', None) if 'userid' in session: if user is None: user = User.query.filter_by(userid=session['userid']).first() add_auth_attribute('user', user) g.user = user if user: add_auth_attribute('lastuserinfo', LastuserInfo(token=user.lastuser_token, token_type=user.lastuser_token_type, token_scope=user.lastuser_token_scope, userid=user.userid, username=user.username, fullname=user.fullname, email=user.email, permissions=user.userinfo.get('permissions', ()), organizations=user.userinfo.get('organizations')))
def before_request(self, access_token=None): if access_token == 'owner-secret': # NOQA: S105 # nosec add_auth_attribute( 'user', 'this-is-the-owner') # See ViewDocument.permissions if access_token == 'editor-secret': # NOQA: S105 # nosec add_auth_attribute( 'user', 'this-is-the-editor') # See ViewDocument.permissions if access_token == 'another-owner-secret': # NOQA: S105 # nosec add_auth_attribute( 'user', 'this-is-another-owner') # See ViewDocument.permissions return super(GatedDocumentView, self).before_request()
def _load_user(self): if has_request_context(): add_auth_attribute('user', self.user) if self.user: add_auth_attribute('username', self.user.username)
def _load_user(self): """ If there's a buid in the session, retrieve the user object and add to the request namespace object g. """ add_auth_attribute('user', None) add_auth_attribute('session', None) lastuser_cookie = {} lastuser_cookie_headers = {} # Ignored for now, intended for future changes # Migrate data from Flask cookie session if 'sessionid' in session: lastuser_cookie['sessionid'] = session.pop('sessionid') if 'userid' in session: lastuser_cookie['userid'] = session.pop('userid') if 'lastuser' in request.cookies: try: lastuser_cookie, lastuser_cookie_headers = lastuser_oauth.serializer.loads( request.cookies['lastuser'], return_header=True) except itsdangerous.BadSignature: lastuser_cookie = {} if 'sessionid' in lastuser_cookie: add_auth_attribute('session', UserSession.authenticate(buid=lastuser_cookie['sessionid'])) if current_auth.session: current_auth.session.access() db.session.commit() # Save access add_auth_attribute('user', current_auth.session.user) # Transition users with 'userid' to 'sessionid' if not current_auth.session and 'userid' in lastuser_cookie: add_auth_attribute('user', User.get(buid=lastuser_cookie['userid'])) if current_auth.is_authenticated: add_auth_attribute('session', UserSession(user=current_auth.user)) current_auth.session.access() db.session.commit() # Save access if current_auth.session: lastuser_cookie['sessionid'] = current_auth.session.buid else: lastuser_cookie.pop('sessionid', None) if current_auth.is_authenticated: lastuser_cookie['userid'] = current_auth.user.buid else: lastuser_cookie.pop('userid', None) add_auth_attribute('cookie', lastuser_cookie) # This will be set to True downstream by the requires_login decorator add_auth_attribute('login_required', False)
def _load_user(self): """ If there's a buid in the session, retrieve the user object and add to the request namespace object g. """ add_auth_attribute('user', None) add_auth_attribute('session', None) lastuser_cookie = {} lastuser_cookie_headers = { } # Ignored for now, intended for future changes # Migrate data from Flask cookie session if 'sessionid' in session: lastuser_cookie['sessionid'] = session.pop('sessionid') if 'userid' in session: lastuser_cookie['userid'] = session.pop('userid') if 'lastuser' in request.cookies: try: lastuser_cookie, lastuser_cookie_headers = lastuser_oauth.serializer.loads( request.cookies['lastuser'], return_header=True) except itsdangerous.BadSignature: lastuser_cookie = {} if 'sessionid' in lastuser_cookie: add_auth_attribute( 'session', UserSession.authenticate(buid=lastuser_cookie['sessionid'])) if current_auth.session: current_auth.session.access() db.session.commit() # Save access add_auth_attribute('user', current_auth.session.user) # Transition users with 'userid' to 'sessionid' if not current_auth.session and 'userid' in lastuser_cookie: add_auth_attribute('user', User.get(buid=lastuser_cookie['userid'])) if current_auth.is_authenticated: add_auth_attribute('session', UserSession(user=current_auth.user)) current_auth.session.access() db.session.commit() # Save access if current_auth.session: lastuser_cookie['sessionid'] = current_auth.session.buid else: lastuser_cookie.pop('sessionid', None) if current_auth.is_authenticated: lastuser_cookie['userid'] = current_auth.user.buid else: lastuser_cookie.pop('userid', None) lastuser_cookie['updated_at'] = utcnow().isoformat() add_auth_attribute('cookie', lastuser_cookie) # This will be set to True downstream by the requires_login decorator add_auth_attribute('login_required', False)
def _load_user(): """ If there's a buid in the session, retrieve the user object and add to the request namespace object g. """ add_auth_attribute('user', None) add_auth_attribute('session', None) lastuser_cookie = {} lastuser_cookie_headers = {} # Ignored for now, intended for future changes # Migrate data from Flask cookie session if 'sessionid' in session: lastuser_cookie['sessionid'] = session.pop('sessionid') if 'userid' in session: lastuser_cookie['userid'] = session.pop('userid') if 'lastuser' in request.cookies: try: ( lastuser_cookie, lastuser_cookie_headers, ) = lastuser_serializer().loads( request.cookies['lastuser'], return_header=True ) except itsdangerous.exc.BadSignature: lastuser_cookie = {} add_auth_attribute('cookie', lastuser_cookie) # We are dependent on `add_auth_attribute` not making a copy of the dict if 'sessionid' in lastuser_cookie: try: add_auth_attribute( 'session', UserSession.authenticate( buid=lastuser_cookie['sessionid'], silent=False ), ) if current_auth.session: add_auth_attribute('user', current_auth.session.user) else: # Invalid session. This is not supposed to happen unless there's an # error that is (a) setting an invalid session id, or (b) deleting # the session object instead of revoking it. current_app.logger.error( "Got an unknown user session %s; logging out", lastuser_cookie['sessionid'], ) logout_internal() except UserSessionExpired: flash( _( "Looks like you haven’t been here in a while." " Please login again" ), 'info', ) current_app.logger.info("Got an expired user session; logging out") add_auth_attribute('session', None) logout_internal() except UserSessionRevoked: flash( _( "Your login session was revoked from another device." " Please login again" ), 'info', ) current_app.logger.info("Got a revoked user session; logging out") add_auth_attribute('session', None) logout_internal() # Transition users with 'userid' to 'sessionid' if not current_auth.session and 'userid' in lastuser_cookie: add_auth_attribute('user', User.get(buid=lastuser_cookie['userid'])) if current_auth.is_authenticated: add_auth_attribute('session', UserSession(user=current_auth.user)) current_auth.session.views.mark_accessed() if current_auth.session: lastuser_cookie['sessionid'] = current_auth.session.buid else: lastuser_cookie.pop('sessionid', None) if current_auth.is_authenticated: lastuser_cookie['userid'] = current_auth.user.buid else: lastuser_cookie.pop('userid', None) # Stop tracking updated_at as it's unused and the session has its own timestamp lastuser_cookie.pop('updated_at', None) # This will be set to True downstream by the requires_login decorator add_auth_attribute('login_required', False)
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) if not current_auth.is_authenticated: session['next'] = get_current_url() return redirect(url_for('login')) return f(*args, **kwargs)
def test_invalid_auth_attribute(self): for attr in ('actor', 'anchors', 'is_anonymous', 'not_anonymous', 'is_authenticated', 'not_authenticated'): with self.assertRaises(AttributeError): add_auth_attribute(attr, None)