Seam Identity Management

During a recent coding getaway to Maine (see my post on the 2011 HackFestaThon) I decided to write a basic Seam project as a starting point for my future Seam based web applications.  The idea is to provide common features such as Login, Logout, Registration, Forgot Password, User Management, Audit Logging, Image Upload Handling, Video Upload Handling, etc… so next time I have an idea that I want to hack together I won’t have to re-write or copy-paste in basic functionality like that.

I spent about a day working on things before I discovered that I really should be using the Seam framework’s Identity Management feature.  So I threw out everything I’d done, and started by re-reading the docs, and went from there.  Seam’s Identity Management framework is VERY powerful, but is also a little complicated to get going and in many cases it seems like it would easier to just write stuff from scratch.  I’m banking on the powerful stuff being worth the initial learning curve and a little extra pain.

When I get the starter project in a more complete state I will be open sourcing the whole thing to help others along, but I wanted to share a few things I’ve learned so far:

In order to use the Email address as the login instead of a username, you need to remove the username property from your UserAccount entity and annotate the Email address property like so:

[fusion_builder_container hundred_percent=”yes” overflow=”visible”][fusion_builder_row][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][java]
@NotNull
@UserPrincipal
@Email
public String getEmail() {
return email;
}
[/java]

Actions like Registration need a RunAsOperation inner class to handle the fine grained security controls that the Identity Management framework enforces:

[/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][java]
public void register() {
verified = (confirm != null && confirm.equals(password));

if (!verified) {
FacesMessages.instance().addToControl("confirmPassword", "Passwords do not match");
}
new RunAsOperation() {
public void execute() {
try {
// Check if email address has already been used
if (identityManager.userExists(getEmail())) {
FacesMessages.instance().addToControl("email", "Email has already been used.");
return;
}
identityManager.createUser(email, password, mFirstName, mLastName);
} catch (IdentityManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
identityManager.grantRole(email, "member");
}
}.addRole("admin").run();

// Login the user
identity.getCredentials().setUsername(email);
identity.getCredentials().setPassword(password);
identity.login();
}
[/java]

Populating custom properties on the User during things like registration requires observing events:

[/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][java]
@Observer(JpaIdentityStore.EVENT_PRE_PERSIST_USER)
public void prePersistUser(UserAccount pNewUser) {
// Setup additional UserAccount properties before the user is created
pNewUser.setRegistrationDate(new Date());
pNewUser.setOptIn(isOptIn());
}
[/java]

You can log audit events with the user’s IP address by doing things like this:

[/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][java]
@Scope(ScopeType.EVENT)
@Name("userEvents")
public class UserEvents {
@Logger
private Log mLog;

@Observer(JpaIdentityStore.EVENT_USER_AUTHENTICATED)
public void loginSuccessful(UserAccount pUser) {
mLog.info("User logged in with email: #0", pUser.getEmail());
pUser.setLastLoginDate(new Date());
Contexts.getSessionContext().set("currentUser", pUser);
AuditEvent loginEvent = new AuditEvent(((ServletRequest) FacesContext.getCurrentInstance().getExternalContext()
.getRequest()).getRemoteAddr(), pUser.getId(), "Login Success", null);
Events.instance().raiseEvent("auditEvent", loginEvent);
}
}
[/java]

Hopefully I’ll have the starter project ready soon and will share it with you all. In the meantime, happy hacking!
[/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]


Posted

in

,

by

Tags:

Comments

3 responses to “Seam Identity Management”

  1. M M Islam Chisty Avatar
    M M Islam Chisty

    A simple question. Please consider the following scenario:

    – OSR is a government organization where there are 50 roles (e.g. Manager, Operations manager, Director, Secured developer, Chief operator, Systems director, ….. etc etc etc etc etc). A web based application is developed for OSR using Seam2.2, richfaces/JSF, JBoss5.1.

    – In this web application, consider a XHTML page which had 2 buttons (“Save” and “Delete”). The “Save” button will be viewable (rendered=”true”) to 25 roles and the “Delete” button will visible to another 25 roles. In Seam2 (with Richfaces), one way to accomplish it is like this:

    Similarly, for the “Delete” button, we do this conditional check for rendering for another 25 roles and for 25 times. In case of 100s of pages with different role based conditions for different UI components (buttons, hyperlinks, textfields, checkboxes, texareas, radio buttons), this will be a complete mess. Can you see the problem? Is this a good programming practice?

    My question is: is there a better way to do this? JBoss drools/rules does not seem to help much in this case. Does seam3 had some better option to provide in such cases?

    Thanks,
    … Chisty

    1. Devon Avatar

      Chisty,

      you need to use permissions and assign groups of permissions to roles. Then use the s:hasPermission call in the rendered= attribute to manage things like Save and Delete button access.

      Read sections: 15.6.1, 15.6.2, and 15.6.3 from the Seam 2 docs.

      regards,

      Devon

  2. M M Islam Chisty Avatar
    M M Islam Chisty

    Why does it removed all the codes that I included in my comments ???

Leave a Reply

Your email address will not be published. Required fields are marked *

PHP Code Snippets Powered By : XYZScripts.com