Skip to content

Commit d0372ef

Browse files
committed
Use include-code for password4j docs
This follows the new convention of using include-code going forward to ensure that the documentation compiles and is tested. This also corrected a few errors in custom params for Ballooning and PBKDF2 examples. Issue gh-17706
1 parent 9f83938 commit d0372ef

File tree

13 files changed

+487
-141
lines changed

13 files changed

+487
-141
lines changed

crypto/spring-security-crypto.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ dependencies {
88
management platform(project(":spring-security-dependencies"))
99
optional 'org.springframework:spring-core'
1010
optional 'org.bouncycastle:bcpkix-jdk18on'
11-
optional 'com.password4j:password4j'
11+
optional libs.com.password4j.password4j
1212

1313
testImplementation "org.assertj:assertj-core"
1414
testImplementation "org.junit.jupiter:junit-jupiter-api"

docs/modules/ROOT/pages/features/authentication/password-storage.adoc

Lines changed: 32 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -483,37 +483,15 @@ This provides an alternative to Spring Security's built-in `Argon2PasswordEncode
483483
Argon2 is the winner of the https://en.wikipedia.org/wiki/Password_Hashing_Competition[Password Hashing Competition] and is recommended for new applications.
484484
This implementation leverages Password4j's Argon2 support which properly includes the salt in the output hash.
485485

486+
Create an encoder with default settings:
487+
486488
.Argon2Password4jPasswordEncoder
487-
[tabs]
488-
======
489-
Java::
490-
+
491-
[source,java,role="primary"]
492-
----
493-
// Create an encoder with default settings
494-
Argon2Password4jPasswordEncoder encoder = new Argon2Password4jPasswordEncoder();
495-
String result = encoder.encode("myPassword");
496-
assertTrue(encoder.matches("myPassword", result));
489+
include-code::./Argon2UsageTests[tag=default-params,indent=0]
497490

498-
// Create an encoder with custom Argon2 function
499-
Argon2Function customArgon2 = Argon2Function.getInstance(65536, 3, 4, 32, Argon2.ID);
500-
Argon2Password4jPasswordEncoder customEncoder = new Argon2Password4jPasswordEncoder(customArgon2);
501-
----
491+
Create an encoder with custom Argon2 parameters:
502492

503-
Kotlin::
504-
+
505-
[source,kotlin,role="secondary"]
506-
----
507-
// Create an encoder with default settings
508-
val encoder = Argon2Password4jPasswordEncoder()
509-
val result: String = encoder.encode("myPassword")
510-
assertTrue(encoder.matches("myPassword", result))
511-
512-
// Create an encoder with custom Argon2 function
513-
val customArgon2 = Argon2Function.getInstance(65536, 3, 4, 32, Argon2.ID)
514-
val customEncoder = Argon2Password4jPasswordEncoder(customArgon2)
515-
----
516-
======
493+
.Argon2Password4jPasswordEncoder Custom
494+
include-code::./Argon2UsageTests[tag=custom-params,indent=0]
517495

518496
[[password4j-bcrypt]]
519497
=== BcryptPassword4jPasswordEncoder
@@ -524,37 +502,15 @@ This provides an alternative to Spring Security's built-in `BCryptPasswordEncode
524502
BCrypt is a well-established password hashing algorithm that includes built-in salt generation and is resistant to rainbow table attacks.
525503
This implementation leverages Password4j's BCrypt support which properly includes the salt in the output hash.
526504

527-
.BcryptPassword4jPasswordEncoder
528-
[tabs]
529-
======
530-
Java::
531-
+
532-
[source,java,role="primary"]
533-
----
534-
// Create an encoder with default settings
535-
BcryptPassword4jPasswordEncoder encoder = new BcryptPassword4jPasswordEncoder();
536-
String result = encoder.encode("myPassword");
537-
assertTrue(encoder.matches("myPassword", result));
505+
Create an encoder with default settings:
538506

539-
// Create an encoder with custom round count
540-
BcryptFunction customBcrypt = BcryptFunction.getInstance(12);
541-
BcryptPassword4jPasswordEncoder customEncoder = new BcryptPassword4jPasswordEncoder(customBcrypt);
542-
----
507+
.BcryptPassword4jPasswordEncoder
508+
include-code::./BcryptUsageTests[tag=default-params,indent=0]
543509

544-
Kotlin::
545-
+
546-
[source,kotlin,role="secondary"]
547-
----
548-
// Create an encoder with default settings
549-
val encoder = BcryptPassword4jPasswordEncoder()
550-
val result: String = encoder.encode("myPassword")
551-
assertTrue(encoder.matches("myPassword", result))
510+
Create an encoder with custom bcrypt parameters:
552511

553-
// Create an encoder with custom round count
554-
val customBcrypt = BcryptFunction.getInstance(12)
555-
val customEncoder = BcryptPassword4jPasswordEncoder(customBcrypt)
556-
----
557-
======
512+
.BcryptPassword4jPasswordEncoder Custom
513+
include-code::./BcryptUsageTests[tag=custom-params,indent=0]
558514

559515
[[password4j-scrypt]]
560516
=== ScryptPassword4jPasswordEncoder
@@ -565,37 +521,16 @@ This provides an alternative to Spring Security's built-in `SCryptPasswordEncode
565521
SCrypt is a memory-hard password hashing algorithm designed to be resistant to hardware brute-force attacks.
566522
This implementation leverages Password4j's SCrypt support which properly includes the salt in the output hash.
567523

568-
.ScryptPassword4jPasswordEncoder
569-
[tabs]
570-
======
571-
Java::
572-
+
573-
[source,java,role="primary"]
574-
----
575-
// Create an encoder with default settings
576-
ScryptPassword4jPasswordEncoder encoder = new ScryptPassword4jPasswordEncoder();
577-
String result = encoder.encode("myPassword");
578-
assertTrue(encoder.matches("myPassword", result));
579524

580-
// Create an encoder with custom SCrypt parameters
581-
ScryptFunction customScrypt = ScryptFunction.getInstance(32768, 8, 1, 32);
582-
ScryptPassword4jPasswordEncoder customEncoder = new ScryptPassword4jPasswordEncoder(customScrypt);
583-
----
525+
Create an encoder with default settings:
584526

585-
Kotlin::
586-
+
587-
[source,kotlin,role="secondary"]
588-
----
589-
// Create an encoder with default settings
590-
val encoder = ScryptPassword4jPasswordEncoder()
591-
val result: String = encoder.encode("myPassword")
592-
assertTrue(encoder.matches("myPassword", result))
527+
.ScryptPassword4jPasswordEncoder
528+
include-code::./ScryptUsageTests[tag=default-params,indent=0]
593529

594-
// Create an encoder with custom SCrypt parameters
595-
val customScrypt = ScryptFunction.getInstance(32768, 8, 1, 32)
596-
val customEncoder = ScryptPassword4jPasswordEncoder(customScrypt)
597-
----
598-
======
530+
Create an encoder with custom scrypt parameters:
531+
532+
.ScryptPassword4jPasswordEncoder Custom
533+
include-code::./ScryptUsageTests[tag=custom-params,indent=0]
599534

600535
[[password4j-pbkdf2]]
601536
=== Pbkdf2Password4jPasswordEncoder
@@ -607,37 +542,15 @@ PBKDF2 is a key derivation function designed to be computationally expensive to
607542
This implementation handles salt management explicitly since Password4j's PBKDF2 implementation does not include the salt in the output hash.
608543
The encoded password format is: `+{salt}:{hash}+` where both salt and hash are Base64 encoded.
609544

610-
.Pbkdf2Password4jPasswordEncoder
611-
[tabs]
612-
======
613-
Java::
614-
+
615-
[source,java,role="primary"]
616-
----
617-
// Create an encoder with default settings
618-
Pbkdf2Password4jPasswordEncoder encoder = new Pbkdf2Password4jPasswordEncoder();
619-
String result = encoder.encode("myPassword");
620-
assertTrue(encoder.matches("myPassword", result));
545+
Create an encoder with default settings:
621546

622-
// Create an encoder with custom PBKDF2 function and salt length
623-
PBKDF2Function customPbkdf2 = PBKDF2Function.getInstance(Algorithm.HMAC_SHA256, 100000, 256);
624-
Pbkdf2Password4jPasswordEncoder customEncoder = new Pbkdf2Password4jPasswordEncoder(customPbkdf2, 32);
625-
----
547+
.Pbkdf2Password4jPasswordEncoder
548+
include-code::./Pbkdf2UsageTests[tag=default-params,indent=0]
626549

627-
Kotlin::
628-
+
629-
[source,kotlin,role="secondary"]
630-
----
631-
// Create an encoder with default settings
632-
val encoder = Pbkdf2Password4jPasswordEncoder()
633-
val result: String = encoder.encode("myPassword")
634-
assertTrue(encoder.matches("myPassword", result))
550+
Create an encoder with custom PBKDF2 parameters:
635551

636-
// Create an encoder with custom PBKDF2 function and salt length
637-
val customPbkdf2 = PBKDF2Function.getInstance(Algorithm.HMAC_SHA256, 100000, 256)
638-
val customEncoder = Pbkdf2Password4jPasswordEncoder(customPbkdf2, 32)
639-
----
640-
======
552+
.Pbkdf2Password4jPasswordEncoder Custom
553+
include-code::./Pbkdf2UsageTests[tag=custom-params,indent=0]
641554

642555
[[password4j-ballooning]]
643556
=== BalloonHashingPassword4jPasswordEncoder
@@ -648,37 +561,16 @@ Balloon hashing is a memory-hard password hashing algorithm designed to be resis
648561
This implementation handles salt management explicitly since Password4j's Balloon hashing implementation does not include the salt in the output hash.
649562
The encoded password format is: `+{salt}:{hash}+` where both salt and hash are Base64 encoded.
650563

651-
.BalloonHashingPassword4jPasswordEncoder
652-
[tabs]
653-
======
654-
Java::
655-
+
656-
[source,java,role="primary"]
657-
----
658-
// Create an encoder with default settings
659-
BalloonHashingPassword4jPasswordEncoder encoder = new BalloonHashingPassword4jPasswordEncoder();
660-
String result = encoder.encode("myPassword");
661-
assertTrue(encoder.matches("myPassword", result));
662564

663-
// Create an encoder with custom Balloon hashing function and salt length
664-
BalloonHashingFunction customBalloon = BalloonHashingFunction.getInstance(1024, 3, 4, "SHA-256");
665-
BalloonHashingPassword4jPasswordEncoder customEncoder = new BalloonHashingPassword4jPasswordEncoder(customBalloon, 32);
666-
----
565+
Create an encoder with default settings:
667566

668-
Kotlin::
669-
+
670-
[source,kotlin,role="secondary"]
671-
----
672-
// Create an encoder with default settings
673-
val encoder = BalloonHashingPassword4jPasswordEncoder()
674-
val result: String = encoder.encode("myPassword")
675-
assertTrue(encoder.matches("myPassword", result))
567+
.BalloonHashingPassword4jPasswordEncoder
568+
include-code::./BallooningHashingUsageTests[tag=default-params,indent=0]
676569

677-
// Create an encoder with custom Balloon hashing function and salt length
678-
val customBalloon = BalloonHashingFunction.getInstance(1024, 3, 4, "SHA-256")
679-
val customEncoder = BalloonHashingPassword4jPasswordEncoder(customBalloon, 32)
680-
----
681-
======
570+
Create an encoder with custom parameters:
571+
572+
.BalloonHashingPassword4jPasswordEncoder Custom
573+
include-code::./BallooningHashingUsageTests[tag=custom-params,indent=0]
682574

683575
[[authentication-password-storage-configuration]]
684576
== Password Storage Configuration

docs/spring-security-docs.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ dependencies {
3939
testImplementation project(':spring-security-test')
4040
testImplementation project(':spring-security-oauth2-client')
4141
testImplementation 'com.squareup.okhttp3:mockwebserver'
42+
testImplementation libs.com.password4j.password4j
4243
testImplementation 'com.unboundid:unboundid-ldapsdk'
4344
testImplementation libs.webauthn4j.core
4445
testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.docs.features.authentication.password4jargon2;
18+
19+
import com.password4j.Argon2Function;
20+
import com.password4j.types.Argon2;
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.security.crypto.password.PasswordEncoder;
24+
import org.springframework.security.crypto.password4j.Argon2Password4jPasswordEncoder;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* @author Rob Winch
30+
*/
31+
public class Argon2UsageTests {
32+
33+
@Test
34+
void defaultParams() {
35+
// tag::default-params[]
36+
PasswordEncoder encoder = new Argon2Password4jPasswordEncoder();
37+
String result = encoder.encode("myPassword");
38+
assertThat(encoder.matches("myPassword", result)).isTrue();
39+
// end::default-params[]
40+
}
41+
42+
@Test
43+
void customParameters() {
44+
// tag::custom-params[]
45+
Argon2Function argon2Fn = Argon2Function.getInstance(65536, 3, 4, 32,
46+
Argon2.ID);
47+
PasswordEncoder encoder = new Argon2Password4jPasswordEncoder(argon2Fn);
48+
String result = encoder.encode("myPassword");
49+
assertThat(encoder.matches("myPassword", result)).isTrue();
50+
// end::custom-params[]
51+
}
52+
53+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.docs.features.authentication.password4jballooning;
18+
19+
import com.password4j.BalloonHashingFunction;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.security.crypto.password.PasswordEncoder;
23+
import org.springframework.security.crypto.password4j.BalloonHashingPassword4jPasswordEncoder;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* @author Rob Winch
29+
*/
30+
public class BallooningHashingUsageTests {
31+
32+
@Test
33+
void defaultParams() {
34+
// tag::default-params[]
35+
PasswordEncoder encoder = new BalloonHashingPassword4jPasswordEncoder();
36+
String result = encoder.encode("myPassword");
37+
assertThat(encoder.matches("myPassword", result)).isTrue();
38+
// end::default-params[]
39+
}
40+
41+
@Test
42+
void customParameters() {
43+
// tag::custom-params[]
44+
BalloonHashingFunction ballooningHashingFn =
45+
BalloonHashingFunction.getInstance("SHA-256", 1024, 3, 4, 3);
46+
PasswordEncoder encoder = new BalloonHashingPassword4jPasswordEncoder(ballooningHashingFn);
47+
String result = encoder.encode("myPassword");
48+
assertThat(encoder.matches("myPassword", result)).isTrue();
49+
// end::custom-params[]
50+
}
51+
52+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.docs.features.authentication.password4jbcrypt;
18+
19+
import com.password4j.BcryptFunction;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
23+
import org.springframework.security.crypto.password.PasswordEncoder;
24+
import org.springframework.security.crypto.password4j.BcryptPassword4jPasswordEncoder;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* @author Rob Winch
30+
*/
31+
public class BcryptUsageTests {
32+
33+
@Test
34+
void defaultParams() {
35+
// tag::default-params[]
36+
PasswordEncoder encoder = new BCryptPasswordEncoder();
37+
String result = encoder.encode("myPassword");
38+
assertThat(encoder.matches("myPassword", result)).isTrue();
39+
// end::default-params[]
40+
}
41+
42+
@Test
43+
void customParameters() {
44+
// tag::custom-params[]
45+
BcryptFunction bcryptFn = BcryptFunction.getInstance(12);
46+
PasswordEncoder encoder = new BcryptPassword4jPasswordEncoder(bcryptFn);
47+
String result = encoder.encode("myPassword");
48+
assertThat(encoder.matches("myPassword", result)).isTrue();
49+
// end::custom-params[]
50+
}
51+
52+
}

0 commit comments

Comments
 (0)