Skip to content

Commit

Permalink
Merge pull request #2 from kiyotakeshi/explore-BCryptPasswordEncoder
Browse files Browse the repository at this point in the history
Explore b crypt password encoder
  • Loading branch information
kiyotakeshi committed Jan 19, 2023
2 parents 690805b + ab630d0 commit 04bbec1
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
@@ -1,5 +1,7 @@
# Sample Application for article

- [article1](https://zenn.dev/kiyotatakeshi/articles/fc593c768ad7e0)

## requirement

- kotlin(1.6),java(17)
Expand Down
32 changes: 32 additions & 0 deletions src/main/kotlin/com/example/zenn/CustomEncoder.kt
@@ -0,0 +1,32 @@
package com.example.zenn

import org.springframework.security.crypto.bcrypt.BCrypt
import org.springframework.security.crypto.password.PasswordEncoder
import java.util.regex.Pattern

/**
* salt の値を固定にするとハッシュが同じになることを確認するために追加
*/
class CustomEncoder: PasswordEncoder {

private val bcryptPattern = Pattern.compile("\\A\\$2(a|y|b)?\\$(\\d\\d)\\$[./0-9A-Za-z]{53}")

override fun encode(rawPassword: CharSequence?): String {
requireNotNull(rawPassword) { "rawPassword cannot be null" }
val notRandomSalt: String = "\$2a\$10\$AzYnC1K8/95SCW8Wktu1e."
return BCrypt.hashpw(rawPassword.toString(), notRandomSalt)
}


// BCryptPasswordEncoder と同じ実装
override fun matches(rawPassword: CharSequence?, encodedPassword: String?): Boolean {
requireNotNull(rawPassword) { "rawPassword cannot be null" }
if (encodedPassword == null || encodedPassword.isEmpty()) {
return false
}
if (!this.bcryptPattern.matcher(encodedPassword).matches()) {
return false
}
return BCrypt.checkpw(rawPassword.toString(), encodedPassword)
}
}
16 changes: 15 additions & 1 deletion src/main/kotlin/com/example/zenn/SampleApplication.kt
Expand Up @@ -2,12 +2,26 @@ package com.example.zenn

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import kotlin.reflect.typeOf

@SpringBootApplication
@EnableWebSecurity(debug = true)
class SampleApplication

fun main(args: Array<String>) {
runApplication<SampleApplication>(*args)
val runApplication: ConfigurableApplicationContext = runApplication<SampleApplication>(*args)

/*
runApplication.beanDefinitionNames
// .filter { it.contains("security") }
// .filter { it.contains("defaultSecurityFilterChain") }
.forEach(::println)
*/

/*
val bean = runApplication.getBean("defaultSecurityFilterChain")
println(bean.javaClass.name) // org.springframework.security.web.DefaultSecurityFilterChain
*/
}
34 changes: 34 additions & 0 deletions src/main/kotlin/com/example/zenn/SecurityConfig.kt
@@ -0,0 +1,34 @@
package com.example.zenn

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.provisioning.InMemoryUserDetailsManager
import org.springframework.security.provisioning.UserDetailsManager

/**
* @author kiyota
*/
@Configuration
class SecurityConfig {

@Bean
fun userDetailsManager(): UserDetailsManager {
val admin: UserDetails = User.builder()
.username("admin")
// encode with Spring Boot CLI
// https://docs.spring.io/spring-security/reference/features/authentication/password-storage.html#authentication-password-storage-boot-cli
// $ spring encodepassword 1qazxsw2
.password("{bcrypt}\$2a\$10\$1gHHMqYmv7spE.896lYtKuenhXSRGyZ0FK.JTzAOSD6qgRKtPl5wy")
.authorities("USER", "ADMIN")
.build()
val user: UserDetails = User.builder()
.username("user")
// $ spring encodepassword 2wsxzaq1
.password("{bcrypt}\$2a\$10\$saAFPwyIghNePc0C4sKuUOBUIQBs6xnC8sUh2OvLW6fuU57oJ1tp6")
.authorities("USER")
.build()
return InMemoryUserDetailsManager(admin, user)
}
}
45 changes: 45 additions & 0 deletions src/test/kotlin/com/example/zenn/PasswordEncodingTest.kt
@@ -0,0 +1,45 @@
package com.example.zenn

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder

class PasswordEncodingTest {
private val password = "1qazxsw2"

@Test
@DisplayName("BCryptPasswordEncoder は実行するたびに別のHash値を生成する")
fun `"generated different hash using different salt"`() {
// 以下のように説明があったので試してみた
// @ref https://www.baeldung.com/spring-security-registration-password-encoding-bcrypt#:~:text=The%C2%A0%E2%80%9C2a,the%20plain%20text.
// > BCrypt, however, will internally generate a random salt instead. This is important to understand because it means that each call will have a different result
// > The “2a” represents the BCrypt algorithm version
// > The “10” represents the strength of the algorithm
// > The “Vt2ycIsscotk3diW/6RsHO” part is actually the randomly generated salt.
// Basically, the first 22 characters are salt. The remaining part of the last field is the actual hashed version of the plain text
// ex.) $2a$10$Vt2ycIsscotk3diW/6RsHO/xtwLJbbg9pLD59qckrCEv7xqf4A296

val bcrypt: PasswordEncoder = BCryptPasswordEncoder()
val bcryptEncodedPass1 = bcrypt.encode(password)
val bcryptEncodedPass2 = bcrypt.encode(password)
println("bcrypt encoded password1: $bcryptEncodedPass1")
println("bcrypt encoded password2: $bcryptEncodedPass2")

assertNotEquals(bcryptEncodedPass1, bcryptEncodedPass2)
}

@Test
@DisplayName("同じ salt を使用して encode したら同じHash値になる")
fun `"generated same hash using same salt"`() {
val customEncoder: PasswordEncoder = CustomEncoder()
val customEncodedPass1 = customEncoder.encode(password)
val customEncodedPass2 = customEncoder.encode(password)
println("custom encoded password1: $customEncodedPass1")
println("custom encoded password2: $customEncodedPass2")

assertEquals(customEncodedPass1, customEncodedPass2)
}
}

0 comments on commit 04bbec1

Please sign in to comment.