Reputation: 716
I use overridden values for spring security username and password. Following properties are in my application.properties
.
spring.security.user.name=myUser
spring.security.user.password=myPassword
spring.security.user.roles=admin
I would like to encrypt the password value as follows:
spring.security.user.name=myUser
spring.security.user.password={bcrypt}hashedpassword valuevalue
spring.security.user.roles=admin
I added PasswordEncoder
in my SpringConfig
:
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
In some example I noticed that there is for AuthenitcationManagerBuilder
but I do not know what datasource should be used. What else do I need to use encrypted password for default user?
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
Adding my Spring Security config as a reference:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/v1/custom").hasRole("admin")
.anyRequest().authenticated()
.and()
.httpBasic();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
Upvotes: 2
Views: 1056
Reputation: 13291
Grabbing:
$2a$12$7Bg57uTtN7GWIdiqRW4h5e/aOUFagHwkEGv9byUr0bb/QbUU8S4rS
for input:
hello
... from (e.g. thx): https://bcrypt-generator.com/
With:
application.properties
:
spring.security.user.password={bcrypt}$2a$12$7Bg57uTtN7GWIdiqRW4h5e/aOUFagHwkEGv9byUr0bb/QbUU8S4rS
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
// @Bean
// public PasswordEncoder encoder() {
// return new BCryptPasswordEncoder();
// }
@GetMapping("secured")
public String secured() {
return "Hello Admin";
}
}
user=user
and password=hello
.Adding:
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
breaks this behavior!! To "fix it", we can (application.properties
):
spring.security.user.password=$2a$12$7Bg57uTtN7GWIdiqRW4h5e/aOUFagHwkEGv9byUr0bb/QbUU8S4rS
.. omit the "tag" {bcrypt}
! ...
Responsible for "tags"/capable of several algorithms is the DelegatingPasswordEncoder
, which is auto configured (via [AuthenticationConfiguration|HttpSecurityConfiguration].LazyPasswordEncoder
..if no other PasswordEncoder bean found) and uses
PasswordEncoderFactories
behind the scenes, like (currently) this:
@SuppressWarnings("deprecation") public static PasswordEncoder createDelegatingPasswordEncoder() { String encodingId = "bcrypt"; Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put(encodingId, new BCryptPasswordEncoder()); encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder()); encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder()); encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5")); encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance()); encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5()); encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()); encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1()); encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8()); encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1")); encoders.put("SHA-256", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256")); encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder()); encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2()); encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()); return new DelegatingPasswordEncoder(encodingId, encoders); }
No, also introducing:
@Configuration
class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeHttpRequests().requestMatchers("/secured").hasRole("admin")
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
}
Plus:
spring.security.user.roles=admin
Doesn't change my observations:
$2a$12$7Bg57uTtN7GWIdiqRW4h5e/aOUFagHwkEGv9byUr0bb/QbUU8S4rS
user:hello
(and view /secured
response){bcrypt}$2a$12$7Bg57uTtN7GWIdiqRW4h5e/aOUFagHwkEGv9byUr0bb/QbUU8S4rS
user:hello
(and view /secured
response)(it only switches from form to basic login:)
Test (good/app config):
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest
class WithAppConfigTest {
@Autowired
MockMvc mockMvc;
@Test
void expectAccess() throws Exception {
mockMvc.perform(
get("/secured")
.with(httpBasic("user", "hello"))
).andExpectAll(
authenticated(),
status().isOk(),
content().string("Hello Admin"));
}
@Test
void expectUnauthorized() throws Exception {
mockMvc.perform(
get("/secured")
.with(httpBasic("user", "wrong"))
).andExpectAll(
unauthenticated(),
status().isUnauthorized(),
content().bytes(new byte[0]));
}
}
Test forbidden:
@WebMvcTest(properties = "spring.security.user.roles=foo,bar,baz")
class WithFakeConfigTest {
@Autowired
MockMvc mockMvc;
@Test
void expectForbidden() throws Exception {
mockMvc.perform(
get("/secured")
.with(httpBasic("user", "hello"))
).andExpectAll(
authenticated(), // !, but:
status().isForbidden(),
content().bytes(new byte[0]));
}
}
Upvotes: 1