BAEL-1489: Refactoring and successful login event handling
This commit is contained in:
parent
99ef66b2cb
commit
20ef3b0299
|
@ -1,33 +1,41 @@
|
|||
package com.baeldung.passwordstorage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class BaeldungPasswordEncoderSetup {
|
||||
|
||||
private final static Logger LOG = LoggerFactory.getLogger(BaeldungPasswordEncoderSetup.class);
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
// set up the list of supported encoders and their prefixes
|
||||
String encodingId = "rot13";
|
||||
Map<String, PasswordEncoder> encoders = new HashMap<>();
|
||||
encoders.put(encodingId, new Rot13PasswordEncoder());
|
||||
encoders.put("scrypt", new SCryptPasswordEncoder());
|
||||
encoders.put("bcrypt", new BCryptPasswordEncoder());
|
||||
public AuthenticationEventPublisher authenticationEventPublisher(final ApplicationEventPublisher publisher) {
|
||||
return new DefaultAuthenticationEventPublisher(publisher);
|
||||
}
|
||||
|
||||
// get an instance of the DelegatingPasswordEncoder, set up to use our instance as default encoder
|
||||
DelegatingPasswordEncoder delegatingPasswordEncoder = new DelegatingPasswordEncoder(encodingId, encoders);
|
||||
@Bean
|
||||
public ApplicationListener<AuthenticationSuccessEvent> authenticationSuccessListener(final PasswordEncoder encoder) {
|
||||
return (AuthenticationSuccessEvent event) -> {
|
||||
final Authentication authentication = event.getAuthentication();
|
||||
|
||||
// configure our instance as default encoder for actual matching
|
||||
delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(encoders.get(encodingId));
|
||||
if (authentication instanceof UsernamePasswordAuthenticationToken && authentication.getCredentials() != null) {
|
||||
final CharSequence clearTextPassword = (CharSequence) authentication.getCredentials(); // 1
|
||||
final String newPasswordHash = encoder.encode(clearTextPassword); // 2
|
||||
|
||||
return delegatingPasswordEncoder;
|
||||
LOG.info("New password hash {} for user {}", newPasswordHash, authentication.getName());
|
||||
|
||||
((UsernamePasswordAuthenticationToken) authentication).eraseCredentials(); // 3
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.passwordstorage;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class PasswordStorageApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PasswordStorageApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.passwordstorage;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class PasswordStorageWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final AuthenticationEventPublisher eventPublisher;
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
public PasswordStorageWebSecurityConfigurer(AuthenticationEventPublisher eventPublisher, UserDetailsService userDetailsService) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.eraseCredentials(false) // 4
|
||||
.authenticationEventPublisher(eventPublisher)
|
||||
.userDetailsService(userDetailsService)
|
||||
.passwordEncoder(passwordEncoder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
// set up the list of supported encoders and their prefixes
|
||||
String encodingId = "bcrypt";
|
||||
Map<String, PasswordEncoder> encoders = new HashMap<>();
|
||||
encoders.put(encodingId, new BCryptPasswordEncoder());
|
||||
encoders.put("scrypt", new SCryptPasswordEncoder());
|
||||
encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
|
||||
|
||||
// get an instance of the DelegatingPasswordEncoder, set up to use our instance as default encoder
|
||||
DelegatingPasswordEncoder delegatingPasswordEncoder = new DelegatingPasswordEncoder(encodingId, encoders);
|
||||
|
||||
// configure our instance as default encoder for actual matching
|
||||
delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(encoders.get(encodingId));
|
||||
|
||||
return delegatingPasswordEncoder;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.baeldung.passwordstorage;
|
||||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* DISCLAIMER: Never ever use this in any production environment!
|
||||
* <p>
|
||||
* Does only work for characters.
|
||||
*/
|
||||
public class Rot13PasswordEncoder implements PasswordEncoder {
|
||||
|
||||
@Override
|
||||
public String encode(CharSequence rawPassword) {
|
||||
StringBuffer result = new StringBuffer(rawPassword.length());
|
||||
rawPassword
|
||||
.chars()
|
||||
.forEach(charCode -> {
|
||||
if (charCode >= 65 && charCode <= 77 || charCode >= 97 && charCode <= 109) {
|
||||
result.append(Character.toChars(charCode + 13));
|
||||
} else if (charCode >= 78 && charCode <= 90 || charCode >= 110 && charCode <= 133) {
|
||||
result.append(Character.toChars(charCode - 13));
|
||||
}
|
||||
});
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||
return encode(rawPassword).equals(encodedPassword);
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package com.baeldung.passwordstorage;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class Rot13PasswordEncoderTest {
|
||||
|
||||
private final Rot13PasswordEncoder encoder = new Rot13PasswordEncoder();
|
||||
|
||||
@Test
|
||||
public void givenEncodedPassword_whenEncodeIsCalledWithTheEncodedPassword_thenTheClearTextPassword() {
|
||||
String password = "baeldung";
|
||||
String encoded = encoder.encode(password);
|
||||
String actualResult = encoder.encode(encoded);
|
||||
|
||||
assertThat(actualResult, is(password));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCorrectPassword_whenMatchesIsCalled_thenReturnTrue() {
|
||||
String password = "baeldung";
|
||||
String encoded = encoder.encode(password);
|
||||
boolean actualResult = encoder.matches(password, encoded);
|
||||
|
||||
assertThat(actualResult, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIncorrectPassword_whenMatchesIsCalled_thenReturnFalse() {
|
||||
boolean actualResult = encoder.matches("baeldung", "spring");
|
||||
|
||||
assertThat(actualResult, is(false));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue