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]
Leave a Reply