How does PasswordEncoder get called in Spring Security? -
i'm experimenting spring boot (1.0.0, using boot web , security), , have working web application secured endpoints authenticated user so. code works (configure httpsecurity omitted brevity) requiring username / password http requests endpoints:
@enableglobalmethodsecurity(prepostenabled = true) @configuration public class securityconfiguration extends websecurityconfigureradapter { @inject public void configureglobal(authenticationmanagerbuilder auth) throws exception { auth.inmemoryauthentication().withuser("user").password("password").roles("user"); }
in preparation using spring security users database, put security pieces in way think should work, notably without database @ all. purely experiment security related classes.
so above code used configure authenticationmanagerbuilder changed this:
// private test implementations can explore security without database // here usernames , passwords valid // org.springframework.security.crypto.password.passwordencoder @bean public passwordencoder passwordencoder() { return new passwordencoder() { @override public string encode(charsequence cs) { return cs.tostring(); } @override public boolean matches(charsequence cs, string string) { return true; } }; } @bean public userdetailsservice createuserdetailsservice() { return new userdetailsservice() { @override public userdetails loaduserbyusername(string string) throws usernamenotfoundexception { return new user(); // trivial implementation of userdetails } }; } @bean @inject public daoauthenticationprovider createdaoauthenticationprovider(userdetailsservice service, passwordencoder encoder) { daoauthenticationprovider provider = new daoauthenticationprovider(); provider.setuserdetailsservice(service); provider.setpasswordencoder(encoder); return provider; } @bean @inject public authenticationmanager authenticationmanager(authenticationprovider provider) throws exception { // includes trivial implementation of objectpostprocessor return new authenticationmanagerbuilder(new noppostprocessor()) .authenticationprovider(provider) .build(); }
my custom user details service called custom password encoder never called, verified setting breakpoints @ appropriate lines. , authentication fails.
how password encoder called? shouldn't called authentication of every http request? should expect called above configuration?
the authenticate
method of abstractuserdetailsauthenticationprovider ( extended daoauthenticationprovider) this
public authentication authenticate(authentication authentication) throws authenticationexception { assert.isinstanceof(usernamepasswordauthenticationtoken.class, authentication, messages.getmessage("abstractuserdetailsauthenticationprovider.onlysupports", "only usernamepasswordauthenticationtoken supported")); // determine username string username = (authentication.getprincipal() == null) ? "none_provided" : authentication.getname(); boolean cachewasused = true; userdetails user = this.usercache.getuserfromcache(username); if (user == null) { cachewasused = false; try { user = retrieveuser(username, (usernamepasswordauthenticationtoken) authentication); } catch (usernamenotfoundexception notfound) { logger.debug("user '" + username + "' not found"); if (hideusernotfoundexceptions) { throw new badcredentialsexception(messages.getmessage( "abstractuserdetailsauthenticationprovider.badcredentials", "bad credentials")); } else { throw notfound; } } assert.notnull(user, "retrieveuser returned null - violation of interface contract"); } try { preauthenticationchecks.check(user); additionalauthenticationchecks(user, (usernamepasswordauthenticationtoken) authentication); } catch (authenticationexception exception) { if (cachewasused) { // there problem, try again after checking // we're using latest data (i.e. not cache) cachewasused = false; user = retrieveuser(username, (usernamepasswordauthenticationtoken) authentication); preauthenticationchecks.check(user); additionalauthenticationchecks(user, (usernamepasswordauthenticationtoken) authentication); } else { throw exception; } } postauthenticationchecks.check(user); if (!cachewasused) { this.usercache.putuserincache(user); } object principaltoreturn = user; if (forceprincipalasstring) { principaltoreturn = user.getusername(); } return createsuccessauthentication(principaltoreturn, authentication, user); }
as can see after user loaded , confirmed present in repository, there call additionalauthenticationchecks.if user not found additional check not done. in additionalcheck method password encoder used. here implementation in daauthenticationprovider
@suppresswarnings("deprecation") protected void additionalauthenticationchecks(userdetails userdetails, usernamepasswordauthenticationtoken authentication) throws authenticationexception { object salt = null; if (this.saltsource != null) { salt = this.saltsource.getsalt(userdetails); } if (authentication.getcredentials() == null) { logger.debug("authentication failed: no credentials provided"); throw new badcredentialsexception(messages.getmessage( "abstractuserdetailsauthenticationprovider.badcredentials", "bad credentials"), userdetails); } string presentedpassword = authentication.getcredentials().tostring(); if (!passwordencoder.ispasswordvalid(userdetails.getpassword(), presentedpassword, salt)) { logger.debug("authentication failed: password not match stored value"); throw new badcredentialsexception(messages.getmessage( "abstractuserdetailsauthenticationprovider.badcredentials", "bad credentials"), userdetails); } }
as can see password encoder used match password presented stored in repository. if password encoder not being called, 1 probable reason user not found.
Comments
Post a Comment