Dear Team,
Using seam examples I tried to persist user using UserHome. However it throws entity detached exception. Please guide as how to store the user with hashed password and generated salt.
Even guide how to deal with creating and persisting Roles and RoleGroups.
Thank you in advance.
@Name("userHome")
public class UserHome extends EntityHome<User> {
.
.
@PrePersist
@Transactional
public void handlePrePersist() {
createUser();
}
@Transactional
private void createUser() {
instance.setPassword(generateHashedPassword());
identityManager.createUser(instance.getUserName(),instance.getPassword());
identityManager.grantRole(instance.getUserName(), "user");
}
@Transactional
private String generateHashedPassword() {
byte[] salt;
String passwordSalt = instance.getPasswordSalt();
if (passwordSalt == null || "".equals(passwordSalt.trim())) {
salt = PasswordHash.instance().generateRandomSalt();
passwordSalt = BinTools.bin2hex(salt);
instance.setPasswordSalt(passwordSalt);
} else {
salt = BinTools.hex2bin(passwordSalt);
}
return identityStore.generatePasswordHash(instance.getPassword(), salt);
}
}
@Entity
@Table(name = "USER", schema = "security", catalog = "philately")
public class User implements Serializable {
private static final long serialVersionUID = -520371581731672359L;
private Long id;
private String userName;
private String password;
private String passwordSalt;
private boolean enabled;
private Set<Role> roles;
public User(){}
public User(Long id, String userName, String password, boolean enabled) {
this.id = id;
this.userName = userName;
this.password = password;
this.enabled = enabled;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
@NotNull
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "USER_NAME", unique = true, nullable = false, length = 15)
@NotNull
@UserPrincipal
@Length(max = 15)
public String getUserName() {
return this.userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Column(name = "PASSWORD", nullable = false, length = 50)
@NotNull
@UserPassword(hash = "MD5")
@Length(max = 50)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
System.out.println("password" + password);
}
@Column(name = "PASSWORD_SALT", nullable = true, length = 50)
@PasswordSalt
public String getPasswordSalt() {
return passwordSalt;
}
public void setPasswordSalt(String passwordSalt) {
this.passwordSalt = passwordSalt;
}
@Column(name = "ENABLED", nullable = true)
@UserEnabled
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@UserRoles
@ManyToMany(targetEntity = Role.class)
@JoinTable(name = "security.USER_ROLE",
joinColumns = @JoinColumn(name = "USER_ID"),
inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
In order to solve detached entity problem, you need to attach stack trace.
I had a brief look at your code snippet, and I think that it wont work even in theory.
For start @PrePersist annotation applies only to Entity and Entity Listeners, your UserHome is neither of them, unless you configured it in orm.xml.
Not to mention that identityManager.createUser method takes plain password as a argument, so whole generateHashedPassword method is pointless really.
Bye
PS: I am a Seam newbie, so do not take my advice too seriously. :)
@Override
public String persist(){
try {
createUser();
} catch (Exception e) {
e.printStackTrace();
return "failure";
}
return "success";
}
The problem is createUser() from IdentityManager checks permission for isLoggedIn(). And therefore create user option fails.
Errors: Login Failed !
How should I create the default user account with passwordSalt? Please suggest a way for initial loading database tables.
Regards,
Well, in order to use IdentityManager.createUser you have to be logged in and you have to posses Permission with target and action . ...CATCH XXII :)...
So if you need to populate your database with first user, you can use ordinary SQL INSERT statement in import-dev.sql (which is located in resources directory), provided you have generated your application with seam-gen and you are using dev profile. If not you can run INSERT statement against your database manually.
However in order to do this you have to find out how to calculate passwordHash. I suggest you create small TestNG test to help you, something like this...
public class PasswordHashTest extends SeamTest { @Test public void testPasswordHash() throws Exception { new ComponentTest() { @Override protected void testComponents() throws Exception { PasswordHash passwordHash = PasswordHash.instance(); final byte[] salt = passwordHash.generateRandomSalt(); final int iterations = 1000; final String password = "password"; final String hash = passwordHash.createPasswordKey(password.toCharArray(), salt, iterations); assert hash != null : "Hash not calculated!"; System.out.println("Password: " + password); System.out.println("Salt: " + BinTools.bin2hex(salt)); System.out.println("Iterations: " + iterations); System.out.println("Hash: " + hash); } }.run(); } }This should print out password, salt, iterations and calculated hash, this works with default hashing algorithm and seam version 2.2.GA, it might not work with different version and you might need to modify it to work with different hashing algorithm...
But If you use seam 2.2.GA and you change
@Column(name = "PASSWORD", nullable = false, length = 50) @NotNull @UserPassword(hash = "MD5") @Length(max = 50) public String getPassword() { return this.password; }to
@Column(name = "PASSWORD", nullable = false, length = 50) @NotNull @UserPassword() @Length(max = 50) public String getPassword() { return this.password; }it might just work...because now you have all fields you needed for your SQL statement.
PS: Still I am seam newbie so there might be much easier way how to accomplish this.
PS2: There is no guarantee what so ever, that any code I wrote is useful for any particular purpose. :)
Martin Vician, your reply is useful for me. Thank you. I'll workout.
However, unable to create the user. The permission check in identityManager.createUser(...) failed.
12:24:41,171 ERROR [STDERR] org.jboss.seam.security.AuthorizationException: Authorization check failed for permission[seam.user,create]
I have created the default entries in tables: USER 'admin', ROLE 'admin', PERMISSION ['seam.user', 'create','admin'] and mapping in USER_ROLE.
Do I need to modify security.drl file? Or anything else m'I missing?
You can use security.drl if you like, for example this is how you grant all permissions to user. (not role, but particular user)
But if you have set up JpaPermissionStore correctly in components.xml, you should not need to modify security.drl at all.
Permissions can be granted directly to User or to Role. You can have 2 Permission tables, one for User and one for Role, or one Permission table for both with discriminator column.
In your case you need to post source code for your Permission table and your components.xml, and probably db scripts, otherwise it is hard to tell.
To be frank I'm newbie excluding core java. I'm working with seam as trial-error method. Seam is the first technology I'm working after core java.
Ok, to the track. I have uploaded the source code of component.xml, Permission.java and create scripts of tables along with contents at:
http://www.sendspace.com/file/s8d0ua
Queries:
1. Purpose of discriminator column in PERMISSION table? Please elaborate your reply
2. Permissions granularity records/object/entity based instead of page/view based. Does Seam/Drools support it? I mean instead of restricting a view/operation can we impose restriction record based. Example: Login user will be able to view only the records he has created or last modified, etc.
3. Difference between permission with and without drools?
[If feasible please reply with the email-ID and preferred time.]
Contacts: seamuser@gmail.com
_Praty G wrote on Sep 21, 2009 09:00:_<br/>
However, unable to create the user. The permission check in identityManager.createUser(...) failed.
12:24:41,171 ERROR [STDERR] org.jboss.seam.security.AuthorizationException: Authorization check failed for permission[seam.user,create]
</blockquote>
Actually I missed to add <security:jpa-permission-store user-permission-class="org.domain.philately.entity.Permission"/>
. Now the related exception is resolved.
However, it is throwing validation exception. Unable to predict which one doing it. If user.java and UserEdit.xhtml is needed please feel free.
Please clarify for the prior/preceding queries.
It must be pretty difficult to start with seam if you do not have any EJB/Hibernate skills...I suggest you read Seam in Action or Seam reference first...trial and error will not work in this case...
RE: source code
I see several problems:
1. you have to define permission class in your components.xml:
add something like this:
details here:
15.6.10.3. JpaPermissionStore
2. I don't think that your role should be conditional true, change it to false
RE: questions
1. as I said you are storing permissions for two different entities, user and role in one table, in your case all permissions apply to role, if you changed discriminator to user, your permissions would apply directly to user, if you stored permissions in two different tables let's say UserPermissions and RolePermissions, then there would be no discriminator column...
2. yes it can be done, permission target will simply contain entity name and id separated by colon, for example provided you have an entity called , your permission target will contain .
details here:
15.6.10.3.5. Identifier Policy
3. Simply said:
When you set up your JpaPermissionResolver correctly you will have 2 resolvers in chain, if drools is first and jpa second, then if you grand permission in drools resolver, jpa resolver will be skipped...
If drools resolver does not grand permission, then jpa resolver will be queried and might grand permission...
If neither of them grands permission, then you will receive AuthorizationException.
So these resolvers are complementary...you might even write your own resolver if needed.
Have a look here:
15.6.8. The Permission Authorization Model
Hi I am workng on the same issue of Password Hashing.Can you please share some code with me.
Thanks!!