spring data neo4j 4 - SDN4 - Error mapping GraphModel to instance -
in web app storing , authenticating users against neo4j server.
in flow if register app (thus saving user instance) , proceed login page can log in fine. if stop server , start again cannot log in. error is:
org.springframework.security.authentication.internalauthenticationserviceexception: error mapping graphmodel instance of co.foo.data.models.user
the user in database. if delete user, register again , log in works fine until restart server, repeatable.
using sdn 4.0.0.rc1
code
public interface myuserdetailsservice extends userdetailsservice { @override userdetails loaduserbyusername(string username) throws usernamenotfoundexception, dataaccessexception; user getuserfromsession(); @transactional user register(string username, string firstname, string lastname, string password); } public interface userrepository extends graphrepository<user>, myuserdetailsservice { user findbyusername(string username); } @primary @service public class userrepositoryimpl implements myuserdetailsservice { @autowired private userrepository userrepository; @autowired private passwordencoder passwordencoder; private user findbyusername(string username) { return userrepository.findbyusername(username); } @override public userdetails loaduserbyusername(string username) throws usernamenotfoundexception, dataaccessexception { final user user = findbyusername(username); if (user==null) throw new usernamenotfoundexception("username not found: " + username); return new myuserdetails(user); } @override public user getuserfromsession() { securitycontext context = securitycontextholder.getcontext(); authentication authentication = context.getauthentication(); object principal = authentication.getprincipal(); if (principal instanceof myuserdetails) { myuserdetails userdetails = (myuserdetails) principal; return userdetails.getuser(); } return null; } @override @transactional public user register(string username, string firstname, string lastname, string password) { user found = findbyusername(username); if (found!=null) throw new runtimeexception("login taken: " + username); if (firstname==null || firstname.isempty()) throw new runtimeexception("no first name provided."); if (lastname==null || lastname.isempty()) throw new runtimeexception("no last name provided."); if (password==null || password.isempty()) throw new runtimeexception("no password provided."); user user = new user(username, firstname, lastname, password, null, passwordencoder, user.roles.role_user); userrepository.save(user); setuserinsession(user); return user; } void setuserinsession(user user) { securitycontext context = securitycontextholder.getcontext(); myuserdetails userdetails = new myuserdetails(user); usernamepasswordauthenticationtoken authentication = new usernamepasswordauthenticationtoken(userdetails, user.getpassword(),userdetails.getauthorities()); context.setauthentication(authentication); } @target(elementtype.parameter) @retention(retentionpolicy.runtime) @documented @authenticationprincipal public @interface currentuser { } } @configuration @enablewebsecurity @order(2) public class securityconfiguration extends websecurityconfigureradapter { @override protected void configure(httpsecurity http) throws exception { http.authorizerequests() .antmatchers("/login/**", "/resources/**", "/web/register").permitall() .antmatchers("/web/**").authenticated() .and() .formlogin().loginprocessingurl("/login").failureurl("/login?authorization_error=true").defaultsuccessurl("/web/home").loginpage("/login").permitall() .and() .logout().logouturl("/logout").logoutsuccessurl("/login") .permitall(); } @autowired private myuserdetailsservice userdetailsservice; @autowired private passwordencoder passwordencoder; @autowired public void globaluserdetails(authenticationmanagerbuilder auth) throws exception { auth.userdetailsservice(userdetailsservice).passwordencoder(passwordencoder); } @override @bean public authenticationmanager authenticationmanagerbean() throws exception { return super.authenticationmanagerbean(); } }
user entity
@nodeentity public class user extends baseentity { public static final string has_account = "has_account"; @index(unique = true) private string username; public string firstname; public string lastname; private string password; private roles[] roles; private yodleesession yodleesession; @transient private passwordencoder passwordencoder; public user() {} public user(string username, string firstname, string lastname, string password, yodleesession yodleesession, passwordencoder passwordencoder, roles... roles) { this.username = username; this.firstname = firstname; this.lastname = lastname; this.yodleesession = yodleesession; this.passwordencoder = passwordencoder; this.roles = roles; this.password = encodepassword(password); } // getters public string getfirstname() { return firstname; } public string getlastname() { return lastname; } public string getusername() { return this.username; } public string getpassword() { return password; } public yodleesession getyodleesession() { return yodleesession; } public roles[] getroles() { return roles; } // setters public void setusername(string username) { this.username = username; } public void setfirstname(string firstname) { this.firstname = firstname; } public void setlastname(string lastname) { this.lastname = lastname; } public void setyodleesession(yodleesession yodleesession) { this.yodleesession = yodleesession; } public void setpassword(string password) { encodepassword(password); } public void setpasswordencoder(passwordencoder passwordencoder) { this.passwordencoder = passwordencoder; } // roles public enum roles implements grantedauthority { role_user, role_admin; @override public string getauthority() { return name(); } } public void setroles(roles[] roles) { this.roles = roles; } // bank accounts @relationship(type=has_account, direction = relationship.outgoing) private set<account> accounts; public set<account> getaccounts() { return this.accounts; } public void addaccount(account account) { if (accounts == null) { accounts = new hashset<account>(); } accounts.add(account); } // password private string encodepassword(string password) { return passwordencoder.encode(password); } public void updatepassword(string old, string newpass1, string newpass2) { if (!password.equals(encodepassword(old))) throw new illegalargumentexception("existing password invalid"); if (!newpass1.equals(newpass2)) throw new illegalargumentexception("new passwords don't match"); this.password = encodepassword(newpass1); } @override public boolean equals(object o) { if (this == o) return true; if (o == null || getclass() != o.getclass()) return false; user user = (user) o; if (nodeid == null) return super.equals(o); return nodeid.equals(user.nodeid); } }
this not directly caused spring caused npe when sdn tries create object, calling setpassword() in turn tries use passwordencoder field null.
i tried autowire field this question shows entities don't autowire.
furthermore couldn't autowiring work anyway made workaround in setpassword method.
Comments
Post a Comment