Author: tmckay
Date: 2012-03-23 17:52:00 +0000 (Fri, 23 Mar 2012)
New Revision: 5269
Modified:
branches/roles/cumin/bin/cumin-admin
branches/roles/cumin/model/access/usergrid.xml
branches/roles/cumin/python/cumin/account/widgets.py
branches/roles/cumin/python/cumin/account/widgets.strings
branches/roles/cumin/python/cumin/authorize.py
branches/roles/cumin/python/cumin/widgets.py
branches/roles/wooly/python/wooly/__init__.py
branches/roles/wooly/python/wooly/pages.py
Log:
Multiple changes:
* Added add-role command to cumin-admin (probably needs remove-role, too, which also needs
to scan users)
* Added a few widgets to the user role in usergrid.xml. There are many items missing.
* Experimented with a do_authorize flag on Widgets, default to False. Currently ignored.
This allowed turning on
authorization checks just on HtmlPage widgets.
* Added checks for valid roles on user at login, with message on failure
* Redirect "automatic" login to the login page when there are no valid roles
* Fix redirection on missing object to go to the fallback page, not index.html
* Fix PageError to store exceptions rather than just calling print_exc()
Modified: branches/roles/cumin/bin/cumin-admin
===================================================================
--- branches/roles/cumin/bin/cumin-admin 2012-03-23 00:06:59 UTC (rev 5268)
+++ branches/roles/cumin/bin/cumin-admin 2012-03-23 17:52:00 UTC (rev 5269)
@@ -125,6 +125,7 @@
lines.append("User commands:")
lines.append("")
lines.append(" add-user USER [PASSWORD] Add USER")
+ lines.append(" add-role ROLE Add ROLE")
lines.append(" external-user USER Add USER with external
authentication")
lines.append(" external-sync AUTH [VERBOSE] Batch import users with external
authentication")
lines.append(" AUTH is the name of a mechanism
like 'ldap' or 'script'")
@@ -402,6 +403,22 @@
print("\nNo users removed.")
+def handle_add_role(app, cursor, opts, args):
+ try:
+ name = args[0]
+ except IndexError:
+ error("ROLE is required")
+
+ if app.admin.get_role(cursor, name):
+ error("A role called '%s' already exists" % name)
+
+ try:
+ app.admin.add_role(cursor, name)
+ except IntegrityError:
+ error("A role called '%s' already exists" % name)
+
+ print "Role '%s' is added" % name
+
def handle_add_user(app, cursor, opts, args):
try:
name = args[0]
Modified: branches/roles/cumin/model/access/usergrid.xml
===================================================================
--- branches/roles/cumin/model/access/usergrid.xml 2012-03-23 00:06:59 UTC (rev 5268)
+++ branches/roles/cumin/model/access/usergrid.xml 2012-03-23 17:52:00 UTC (rev 5269)
@@ -16,6 +16,9 @@
<WidgetAccess reg="cumin.widgets.About*" />
<WidgetAccess reg="cumin.widgets.CuminFormPage" />
<WidgetAccess reg="cumin.grid.submission.*" />
+ <WidgetAccess reg="cumin.objectframe.*" />
+ <WidgetAccess reg="cumin.widgets.Notification*" />
+ <WidgetAccess reg="cumin.grid.job.*" />
<FallbackPage name="usergrid.html"/>
</GroupAccess>
<GroupAccess name="admin">
Modified: branches/roles/cumin/python/cumin/account/widgets.py
===================================================================
--- branches/roles/cumin/python/cumin/account/widgets.py 2012-03-23 00:06:59 UTC (rev
5268)
+++ branches/roles/cumin/python/cumin/account/widgets.py 2012-03-23 17:52:00 UTC (rev
5269)
@@ -124,19 +124,27 @@
user = cls.get_object(cursor, name=name)
if not user:
- self.login_invalid.set(session, True)
+ self.login_invalid.set(session, "credentials")
return
authenticated = self.app.authenticator.authenticate(name,password)
if authenticated:
- # You're in!
- login = LoginSession(self.app, user)
+ # You're in! almost...
+ # Check for a valid group if group authorization is on
+ if self.app.authorizator.is_enforcing():
+ roles = self.app.admin.get_roles_for_user(cursor, user)
+ if not self.app.authorizator.contains_valid_group(roles):
+ self.login_invalid.set(session, "roles")
+ return
+ else:
+ roles = []
+ login = LoginSession(self.app, user, roles)
session.client_session.attributes["login_session"] = login
url = self.page.origin.get(session)
self.page.redirect.set(session, url)
else:
- self.login_invalid.set(session, True)
+ self.login_invalid.set(session, "credentials")
def render_operator_link(self, session):
email = self.app.operator_email
@@ -147,7 +155,10 @@
return "site operator"
def render_login_invalid(self, session):
- if self.login_invalid.get(session):
+ reason = self.login_invalid.get(session)
+ if reason == "roles":
+ return self.get_string("roles_invalid")
+ elif reason == "credentials":
return self.get_string("login_invalid")
class Submit(FormButton):
Modified: branches/roles/cumin/python/cumin/account/widgets.strings
===================================================================
--- branches/roles/cumin/python/cumin/account/widgets.strings 2012-03-23 00:06:59 UTC (rev
5268)
+++ branches/roles/cumin/python/cumin/account/widgets.strings 2012-03-23 17:52:00 UTC (rev
5269)
@@ -77,3 +77,7 @@
<p class="login_invalid">The user name and password you entered do not
match any account.</p>
+[LoginForm.roles_invalid]
+<p class="login_invalid">There are no valid roles
+configured for this account.</p>
+
Modified: branches/roles/cumin/python/cumin/authorize.py
===================================================================
--- branches/roles/cumin/python/cumin/authorize.py 2012-03-23 00:06:59 UTC (rev 5268)
+++ branches/roles/cumin/python/cumin/authorize.py 2012-03-23 17:52:00 UTC (rev 5269)
@@ -92,6 +92,9 @@
log.error("Access file '%s' does not parse!" %
accfile)
log.info("MODULES %s", modules)
+ def is_enforcing(self):
+ return self.access_path is not None
+
def map_is_empty(self):
return self.accmap.map_is_empty()
@@ -108,8 +111,14 @@
group = group[0]
return self.accmap.find_fallback(group)
- def authorize(self,web_session, widget_name):
- if self.access_path is None:
+ def contains_valid_group(self, groups):
+ for g in groups:
+ if g in self.accmap.mapping:
+ return True
+ return False
+
+ def authorize(self, web_session, widget):
+ if not self.is_enforcing(): # or not widget.do_authorize:
# The feature is disabled, everything is allowed
return True
try:
@@ -120,17 +129,17 @@
#TODO: bleee ugly ugly ... -> CuminGenericWidget ? .
# skip wooly widgets ....
- if widget_name.startswith("wooly"):
+ if widget.my_name.startswith("wooly"):
return True
if type(group) == type([]):
for g in group:
- if self.accmap.lookup(g,widget_name):
+ if self.accmap.lookup(g, widget.my_name):
log.debug("Allowing %s authorization for %s ",
- widget_name, group)
+ widget.my_name, group)
return True
else:
- return self.accmap.lookup(group,widget_name)
+ return self.accmap.lookup(group,widget.my_name)
- log.debug("Denying %s authorization for %s ", widget_name, group)
+ log.debug("Denying %s authorization for %s ", widget.my_name, group)
return False
Modified: branches/roles/cumin/python/cumin/widgets.py
===================================================================
--- branches/roles/cumin/python/cumin/widgets.py 2012-03-23 00:06:59 UTC (rev 5268)
+++ branches/roles/cumin/python/cumin/widgets.py 2012-03-23 17:52:00 UTC (rev 5269)
@@ -104,7 +104,7 @@
href = Session(page).marshal()
title = page.render_title(session)
#TODO: generalize ??
- if self.app.authorize_cb(session,page.my_name):
+ if self.app.authorize_cb(session, page):
return fmt_link(href, title)
def render_item_class(self, session, page):
@@ -1177,16 +1177,11 @@
# XXX this should move somewhere else
class LoginSession(object):
- def __init__(self, app, user):
+ def __init__(self, app, user, group):
self.app = app
self.user = user
-
- conn = self.app.database.get_connection()
- cursor = conn.cursor()
- self.group = self.app.admin.get_roles_for_user(cursor, user)
-
+ self.group = group
self.created = datetime.now()
-
self.notifications = list()
class NotificationSet(Widget):
@@ -1314,12 +1309,11 @@
return True
login = session.client_session.attributes.get("login_session")
-
if login:
when = datetime.now() - timedelta(hours=24)
-
if login.created > when:
return True
+
elif self.app.auth_proxy or self.app.user:
username = self.app.user
# proxy user overrides app defined user
@@ -1328,35 +1322,57 @@
except KeyError:
log.debug("Proxy auth enabled but no remote user set")
pass
+
if username:
cls = self.app.model.com_redhat_cumin.User
users = cls.get_selection(session.cursor, name=username)
+ if not users:
+ if not self.app.auth_proxy:
+ log.info("User '%s' not found" % username)
+ else:
+ log.info("User %s not found in db, "\
+ "using auth proxy", username )
+ #Hmmm, what is users here? For now just let it return
+ # to the login page
+ return False
- if not users and not self.app.auth_proxy:
- raise Exception("User '%s' not found" %
self.app.user)
- else:
- log.info("User %s not found in db", username )
#TODO prehodit do authenticatora
# ondemand -> authenticator.create_user
# user -> authenticator.force_login
- login = LoginSession(self.app, users[0])
+ # Check for valid group
+ if self.app.authorizator.is_enforcing():
+ cursor = self.app.database.get_read_cursor()
+ roles = self.app.admin.get_roles_for_user(cursor, users[0])
+ if not self.app.authorizator.contains_valid_group(roles):
+ log.info("No valid roles for '%s'" % username)
+ return False # go to login page
+ else:
+ roles = []
+
+ login = LoginSession(self.app, users[0], roles)
session.client_session.attributes["login_session"] = login
-
return True
return False
def redirect_on_exception(self, session):
# If we have an exception from a missing object, redirect to the
# main page with a notice instead of using the not_found_tmpl below.
- # Test for presence on the index.html page already to avoid any possibility
+ # Test for presence on the main page already to avoid any possibility
# of an infinite redirect loop.
cls, value, traceback = sys.exc_info()
+ if self.app.authorizator.is_enforcing():
+ mainpage = self.app.authorizator.find_fallback(session)
+ if not mainpage.startswith("/"):
+ mainpage = "/" + mainpage
+ else:
+ mainpage = "/index.html"
+
if cls is RosemaryNotFound and \
- session.request_environment["REQUEST_URI"] !=
"/index.html":
+ session.request_environment["REQUEST_URI"] != mainpage:
session.add_notice(Notice("An object being displayed became
unavailable"))
- return "/index.html"
+ return mainpage
def render_error(self, session):
cls, value, traceback = sys.exc_info()
Modified: branches/roles/wooly/python/wooly/__init__.py
===================================================================
--- branches/roles/wooly/python/wooly/__init__.py 2012-03-23 00:06:59 UTC (rev 5268)
+++ branches/roles/wooly/python/wooly/__init__.py 2012-03-23 17:52:00 UTC (rev 5269)
@@ -2,7 +2,7 @@
from resources import ResourceFinder
from template import *
from util import *
-
+from traceback import print_exception
log = logging.getLogger("wooly")
strings = StringCatalog(__file__)
@@ -126,6 +126,7 @@
self.nocontent_tmpl = WidgetTemplate(self, "nocontent")
self.my_name = self.__class__.__module__ + '.' + self.__class__.__name__
+ self.do_authorize = False
def init(self):
log.debug("Initializing %s" % self)
@@ -295,7 +296,7 @@
def process(self, session, *args):
#TODO: cleanup
log.debug("WOOLY PROCESS: %s", self.my_name)
- if not self.app.authorize_cb(session, self.my_name):
+ if not self.app.authorize_cb(session, self):
self.redirect_on_not_authorized(session)
else:
if self.update_enabled:
@@ -319,7 +320,7 @@
def render(self, session, *args):
#TODO: cleanup
log.debug("WOOLY RENDER: %s", self.my_name)
- if not self.app.authorize_cb(session, self.my_name):
+ if not self.app.authorize_cb(session, self):
return ""
if self.app.debug:
profile = self.page.profile.get(session)
@@ -503,7 +504,12 @@
return None
def service_error(self, session):
- self.error.set(session, PageError(self, session))
+ # Well, we can have other handled exceptions pop up before
+ # we actually get to the render so we want to record here
+ # what the root cause was.
+ cls, value, traceback = sys.exc_info()
+ self.error.set(session, PageError(self, session,
+ cls, value, traceback))
return self.render(session)
@@ -531,15 +537,18 @@
self.url = url
class PageError(object):
- def __init__(self, page, session):
+ def __init__(self, page, session, cls, value, traceback):
self.page = page
self.session = session
+ self.cls = cls
+ self.value = value
+ self.traceback = traceback
def render(self):
writer = Writer()
writer.write("APPLICATION ERROR\n\n")
- print_exc(None, writer)
+ print_exception(self.cls, self.value, self.traceback, None, writer)
writer.write("\n")
Modified: branches/roles/wooly/python/wooly/pages.py
===================================================================
--- branches/roles/wooly/python/wooly/pages.py 2012-03-23 00:06:59 UTC (rev 5268)
+++ branches/roles/wooly/python/wooly/pages.py 2012-03-23 17:52:00 UTC (rev 5269)
@@ -105,6 +105,7 @@
self.javascript_page = JavascriptPage \
(app, self.base_name + ".js", self)
self.app.add_page(self.javascript_page)
+ self.do_authorize = True
def get_content_type(self, session):
value = session.request_environment.get("HTTP_USER_AGENT")