You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Status

Proposal under development

Target Release

Roller Weblogger 4.1

Original Authors

Dave Johnson

Abstract

This is a proposal to make it possible to externalize user management so that Roller can pull user profile and role information from a separate user management system.

Background

Here's an explanation of Roller's current user/role management, the perceived problems and proposed solutions.

Roller manages it's own users and roles

So that it can stand-alone without an external user repository, Roller stores
users and role information in it's own database tables.

    create table rolleruser (
        id              varchar(48) not null primary key,
        username        varchar(255) not null,
        passphrase      varchar(255) not null,
        screenname      varchar(255) not null,
        fullname        varchar(255) not null,
        emailaddress    varchar(255) not null,
        activationcode	varchar(48),
        datecreated     timestamp not null,
        locale          varchar(20),  
        timezone        varchar(50),    
        isenabled       boolean not null
    )
    create table userrole (
        id               varchar(48) not null primary key,
        rolename         varchar(255) not null,
        username         varchar(255) not null,
        userid           varchar(48) not null
    )

There are two distinct roles:

  • editor: user able to login and see main menu
  • admin: user is able edit site-wide settings and any blog in system

Those tables are represented in Roller by the User and UserRole objects, simple
POJO objects stored by Roller's ORM based UserManager.

The problem

For sites that have an external user repository or user permissions system,
this is a problem. Some would like user information like email address, locale,
timezone, fullname and etc. pulled from an external system. Some would like
user's roles to be pulled from an external system. Some would like both.

The solution

Reduce the User class down to just two fields, id and username. Everything
else goes into a new UserProfile class. UserProfiles can be stored externally
so Roller should obtain them through a new User Respotory API

   User Respository API, part 1/2

   UserRespository interface methods
      public UserProfile getUserProfile(String userid)
      public void saveUserProfile(UserProfile userProfile)

   UserProfile bean properties
      username
      password
      screenName
      emailAddress
      locale
      timezone
      biography
      etc.

Roller authentication is manages 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 the RollerUserDetailsService, which in turn fetches that
information from the User and UserRole objects 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.

The problem

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

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.

Acegi manages URI authorization

These rules in Acegi's configuration (security.xml) file govern URI based
authorization used in Roller.

    /roller-ui/login-redirect**=admin,editor
    /roller-ui/profile**=admin,editor
    /roller-ui/createWeblog**=admin,editor
    /roller-ui/menu**=admin,editor
    /roller-ui/authoring/**=admin,editor
    /roller-ui/admin/**=admin
    /rewrite-status*=admin

The Problem? There's no problem here. When operating without Acegi, Roller will
have to be configured with a web.xml file that specifies those contraints.

Roller manages all other authorization involving user roles

Roller also does it's own authorization checks on user Roles.

For each new user session, Roller creates a RollerSession object. RollerSession
calls request.getUserPrincipal().getName() to get the user name, fetches
corresponing User object from UserManager and holds on to that User object.

The RollerSession provides access to the session's authenticated user:

    public User getAuthenticatedUser()

The User object provides read/write access to user's roles:

    public boolean hasRole(String roleName)
    public void grantRole(String roleName)
    public Set getRoles()

As of Roller 4.0, Roller calls hasRole() for one reason, to ensure that only
those with the admin role can:

  • View set the Admin options in the tabbed menu
  • Modify another user's profile
  • Edit any weblog
  • Set pinned field of a weblog entry
  • Use RAP web services

The Problem

Because Roller uses the ORM system to load a User's Roles, the roles must come
from the database. And because Roles are part of the User, some sort of join
must happen to load each User object with Roles.

The Solution

Instead of relying on ORM supported role methods in the user object, Roller
front-end code should call the user manager:

UserManager interface methods

      public boolean isUserInRole(String username)
      public Set<String> getUserRoles(String username)
      public void revokeRole(String userid, String rolename)
      public void grantRole(String userid, String rolename)

And instead of calling role-related methods on the user object, Roller code
should use either request.isUserInRole() or the isUserInRole() method provided
by the UserManager.

Our UserManager implemenation will in turn call the User Repository API.

User Respository API, part 2/3

UserRespository interface methods

      public boolean isUserInRole(String username)
      public Set<String> getUserRoles(String username)
      public void revokeRole(String userid, String rolename)
      public void grantRole(String userid, String rolename)

Roller will include a User Repository API that stores data in the Roller
database. Other implementations can be plugged in via DI.

Requirements

Requirements satisfied by this proposal

Issues

Issues to be considered

Design

List and describe new manager methods, Struts actions, JSP pages, macros, etc.

Comments

Other can leave commments here.

  • No labels