Pages

Wednesday, April 29, 2009

seamy photo gallery, securing it (part 2)

The new requirement that I wanted was "photos should be approved before being shown in the main page". For that I needed users with approving privledge or role, therefore it was time to dive in to the seam security part. I used simplest User and Role classes that I could think them and configured them :
<security:jpa-identity-store
user-class="domain.User"
role-class="domain.Role" />
Seam requires that you annotate your user domain and specify your username, password and other fields with annotations. Simplest model mostly from the reference :
public class User {
@Id
@UserPrincipal
private String login;

@UserPassword
private String password;

@ManyToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "USER_ROLE")
@UserRoles
private Set<Role> roles = new HashSet<Role>();
...
@Entity
public class Role {
@Id
@RoleName
private String name;
...
@Password annotation has the option to hash the data behind the scenes if you wish so. 
The next thing to the is authenticator method.
<security:identity
authenticate-method="#{authenticator.authenticate}" />
@Scope(ScopeType.APPLICATION)
@Name("authenticator")
public class Authenticator {

@In
EntityManager entityManager;

@In
Identity identity;

public boolean authenticate() {
try {
User u = (User) entityManager.createQuery(
"select u from User u where "
+ "u.login = #{credentials.username} and u.password = #{credentials.password}")
.getSingleResult();

CollectionUtils.forAllDo(u.getRoles(), new Closure() {
public void execute(Object objrole) {
Role role = (Role) objrole;
identity.addRole(role.getName());
}
});

return true;
}
catch (NoResultException ex) {
return false;
}
}

@Create
public void initTestUsers() {
entityManager.persist(new User("mca", "mca").addRole(new Role("user")));
entityManager.persist(new User("op", "op").addRole(new Role("admin")));
}

}
Authenticate method returns if the authentication is successfull or not. Credentials component is used to hold username and password of the user trying to login. If the authentication is successfull we also need to add the user roles to identity component. I have also used the @Create annotation so that I could create some test users when the component is created. The login page needs to get the values to credentials compenent and simply call the Identity.login method :
<h:inputText id="txt_username"
value="#{credentials.username}" ...
<h:inputSecret id="password"
value="#{credentials.password}" ...
<h:commandButton value="Login" action="#{identity.login}"/>
Up to this value we have done what is needed to authenticate a user. To secure our main page we need to mark it a page which needs login on pages.xml :
<pages login-view-id="/login.xhtml" ...

<page view-id="/photo/index.xhtml" login-required="true">
<rewrite pattern="/photo/index" />
</page>
Now when a user logs in he will be redirected to the login page specified in the pages tag. When the login is successfull to redirect the user to their original target page you can use the redirect component with the events:
<event type="org.jboss.seam.security.notLoggedIn">
<action execute="#{redirect.captureCurrentView}" />
</event>

<event type="org.jboss.seam.security.postAuthenticate">
<action execute="#{redirect.returnToCapturedView}" />
</event>
Will be continued...

No comments:

Post a Comment