Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

4.1.2 Proposed solution

Ensure that User objects are user, role and permission information is always retrieved via UserManager methods and never by ORM relationship management (e.g. never by weblog.getUser()).

Now, let's move from user profiles to user authentication.

4.2 Roller authentication is managed via Acegi

Roller uses a framework called Acegi to handle authentication and authorization. Instead of relying on the authentication and authorization features built into the container on which Roller runs, Roller relies on Acegi.

When Acegi is authenticating a user it pulls username, password and role information from the RollerUserDetailsService, which in turn fetches that information from Roller's User and UserRole POJOs via UserManager.

Acegi is implemented as a Servlet Filter, which intercepts each request and decides if the user is authenticated, needs to login first, etc. Acegi takes care of routing the user to the login page and back to the original page that the user requested. Acegi wraps the ServletRequest so that it can return the
right value when request.getUserPrincipal() is called by the application.

4.2.1 The problem with relying solely on Acegi

Using Acegi makes Roller installation painless in standalone situations, but some Acegi skills are required to reconfigure Roller to authenticate against an LDAP system. Unfortunately, the only SSO system that Acegi supports out of the box is Yale CAS. Plus, some folks would like to disable Acegi to take advantage of the powerful auth & auth services that are built into containers now, e.g. SSO support that's built into Glassfish, Websphere, JBoss, etc.

4.2.2 The Solution

Make it possible to turn off Acegi by modifying web.xml and to extend the Roller application class RollerContext to init without Acegi. Moving forward, we should not introduce further dependencies on Acegi in Roller.

4.3 Roller manages user-weblog permissions

In addition to roles, which are global across a Roller site, Roller also manages each user's permissions to access weblogs. There is a many-to-many relationship between users and weblogs and it's stored in a database table:

Code Block

-- User permissions within a website
-- permission_mask: bitmask 000 limited, 001 author, 011 admin
-- pending: pending user acceptance of invitation to join website
create table roller_user_permissions (
   id              varchar(48) not null primary key,
   website_id      varchar(48) not null,
   user_id         varchar(48) not null,
   permission_mask integer not null, 
   pending         $db.BOOLEAN_SQL_TYPE_TRUE not null
);

There are three permission levels:

  • limited: can edit draft weblog entries only, can submit for review
  • author: can edit draft and publish weblog entries
  • admin: can author and can manage users, weblog settings, theme and etc.

Each User object provides access to the User's weblog permissions. When a user logs in, we use this to display the user's list of weblogs.

User

Code Block

public List getPermissions()
public void setPermissions(List perms)

Each Weblog object provides access to the Weblog's permissions. When a weblog admin uses the manage members page, we use this information to display the list of weblog members and the permissions levels of each.

Weblog

Code Block

public List getPermissions() 
public void setPermissions(List perms) 
public void removePermission(WeblogPermission perms)
public int getUserCount()
public int getAdminUserCount()

WeblogEntry

Code Block

public boolean hasWritePermissions(User user)

4.3.1 Problem

Permissions cannot be managed by external system because the User to Permissions to Weblog relationship is managed by the ORM, the information must be stored in Roller database tables and cannot be externalized and managed by another system.

4.3.2 Solution

That approach will make user/permissions management truly pluggable. Also, refactor the UserManager interface so that it is responsible only for user/perms management. The result of this refactoring will be this arrangement:

  • UserManager - for user and role/permissions management
  • WeblogManager - for Weblog and Page management
  • WeblogEntryManager - for WeblogEntry and Comment management

Now, let's move from user/role management to permissions.

4.2 Roller manages user-weblog permissions

In addition to roles, which are global across a Roller site, Roller also manages each user's permissions to access weblogs. There is a many-to-many relationship between users and weblogs and it's stored in a database table:

Code Block

-- User permissions within a website
-- permission_mask: bitmask 000 limited, 001 author, 011 admin
-- pending: pending user acceptance of invitation to join website
create table roller_user_permissions (
   id              varchar(48) not null primary key,
   website_id      varchar(48) not null,
   user_id         varchar(48) not null,
   permission_mask integer not null, 
   pending         $db.BOOLEAN_SQL_TYPE_TRUE not null
);

There are three permission levels:

  • limited: can edit draft weblog entries only, can submit for review
  • author: can edit draft and publish weblog entries
  • admin: can author and can manage users, weblog settings, theme and etc.

Each User object provides access to the User's weblog permissions. When a user logs in, we use this to display the user's list of weblogs.

User

Code Block

public List getPermissions()
public void setPermissions(List perms)

Each Weblog object provides access to the Weblog's permissions. When a weblog admin uses the manage members page, we use this information to display the list of weblog members and the permissions levels of each.

Weblog

Code Block

public List getPermissions() 
public void setPermissions(List perms) 
public void removePermission(WeblogPermission perms)
public int getUserCount()
public int getAdminUserCount()

WeblogEntry

Code Block

public boolean hasWritePermissions(User user)

4.2.1 Problem

Permissions cannot be managed by external system because the User to Permissions to Weblog relationship is managed by the ORM, the information must be stored in Roller database tables and cannot be externalized and managed by another system.

4.2.2 Solution

Remove the Roller front-end's dependence on UserRole and WeblogPermissions completely and put in place a single consistent permissions system via the UserManager interface.

Now let's discussion authentication.

4.3 Roller authentication is managed via Acegi

Roller uses a framework called Acegi to handle authentication and authorization. Instead of relying on the authentication and authorization features built into the container on which Roller runs, Roller relies on Acegi.

When Acegi is authenticating a user it pulls username, password and role information from the RollerUserDetailsService, which in turn fetches that information from Roller's User and UserRole POJOs via UserManager.

Acegi is implemented as a Servlet Filter, which intercepts each request and decides if the user is authenticated, needs to login first, etc. Acegi takes care of routing the user to the login page and back to the original page that the user requested. Acegi wraps the ServletRequest so that it can return the
right value when request.getUserPrincipal() is called by the application.

4.3.1 The problem with relying solely on Acegi

Using Acegi makes Roller installation painless in standalone situations, but some Acegi skills are required to reconfigure Roller to authenticate against an LDAP system. Unfortunately, the only SSO system that Acegi supports out of the box is Yale CAS. Plus, some folks would like to disable Acegi to take advantage of the powerful auth & auth services that are built into containers now, e.g. SSO support that's built into Glassfish, Websphere, JBoss, etc.

4.3.2 The Solution

Make it possible to turn off Acegi by modifying web.xml and to extend the Roller application class RollerContext to init without Acegi. Moving forward, we should not introduce further dependencies on Acegi in RollerRemove Roller's dependence on UserRole and WeblogPermissions completely and put in place a single consistent permissions system.

5.0 Specific changes to Managers, POJOS, Actions and JSPsActions and JSPs

Specific changes that will be made to implement the solutions described above.

5.1 Define new permissions classes

Define new permissions classes using java.security.Permission as the base class. A Permssion object defines a list of "actions" that are permitted.

Class RollerPermission extends java.security.Permission

...

. This is simply a common base class for all Roller permissions, it provides no additional functionality over what is provided by Permssion.

Class GlobalPermission extends RollerPermission defines the global actions:actions below. Each GlobalPermission object will have a list of those actions.

  • login: allowed to login and edit user profile
  • comment: allowed to comment on weblog entries
  • createWeblog: allowed to create weblogs
  • admin: allowed to administer the Roller installation

Class WeblogPermission extends RollerPermission defines the weblog specific actions :below. Each WeblogPermission object will have a list of those actions.

  • editDraft: allowed to edit draft posts only
  • post: allowed to edit and post weblog entries
  • admin: allowed to administer the weblog

...

Code Block
WeblogPermssion desiredPerm = new WeblogPermission(weblog, "post");
boolean allowed = userManager.checkPermssion(desiredPerm, user);
 userManager.checkPermssion(desiredPerm, user);

Roller will look up the WeblogPermission object for the specified user and weblog and will return true if the "post" action is in the permission's action list.

Next, we need to provide a way for the Roller front-end to grant and revoke roles because roles imply global permissions.

...

Code Block
public List<String> getRoles(User user);
public List<WeblogPermission> getWeblogPermssions(User user);
public List<WeblogPermission> getWeblogPermssions(Weblog weblog);

5.4

...

Implementation of new UserManagement permissions methods

Global permissions are implied by role, so we'll keep the userrole table and UserRole POJO.

...

5.5 Removing dependence on ORM for user/role/perms management

Here are the specific changes to Roller POJOs and front-end code to remove dependence on ORM for user, role and permissions management.

User POJO: remove the set/getRoles() and set/getPermissions() methods

...

5.6 Make Acegi and CMA optional

Here's some notes on what would have to happen to To make CMA optional.:

  • Make RollerContext into an abstract base class so that we can have a Acegi
    version and a non-Acegi version that share the same base logic.

...