diff --git a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc index a023a53caf..e72d3536f0 100644 --- a/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/about/authentication/password-storage.adoc @@ -366,6 +366,15 @@ public static NoOpPasswordEncoder passwordEncoder() { ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun passwordEncoder(): PasswordEncoder { + return NoOpPasswordEncoder.getInstance(); +} +---- ==== [NOTE] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/basic.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/basic.adoc index aff665573f..383059d4a1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/basic.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/basic.adoc @@ -29,4 +29,15 @@ protected void configure(HttpSecurity http) { ---- + +[source,kotlin,role="secondary"] +.Kotlin +---- +fun configure(http: HttpSecurity) { + http { + // ... + httpBasic { } + } +} +---- ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/form.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/form.adoc index 64d3f3a0a6..b99537ab43 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/form.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/input/form.adoc @@ -32,6 +32,17 @@ protected void configure(HttpSecurity http) { ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +fun configure(http: HttpSecurity) { + http { + // ... + formLogin { } + } +} +---- ==== In this configuration Spring Security will render a default log in page. @@ -66,6 +77,20 @@ protected void configure(HttpSecurity http) throws Exception { ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +fun configure(http: HttpSecurity) { + http { + // ... + formLogin { + loginPage = "/login" + permitAll() + } + } +} +---- ==== [[servlet-authentication-form-custom-html]] diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/in-memory.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/in-memory.adoc index f48c52e839..40adbd4cf7 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/in-memory.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/in-memory.adoc @@ -40,6 +40,25 @@ public UserDetailsService users() { authorities="ROLE_USER,ROLE_ADMIN" /> ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun users(): UserDetailsService { + val user = User.builder() + .username("user") + .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW") + .roles("USER") + .build() + val admin = User.builder() + .username("admin") + .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW") + .roles("USER", "ADMIN") + .build() + return InMemoryUserDetailsManager(user, admin) +} +---- ==== The samples above store the passwords in a secure format, but leave a lot to be desired in terms of getting started experience. @@ -51,7 +70,8 @@ For this reason, `User.withDefaultPasswordEncoder` should only be used for "gett .InMemoryUserDetailsManager with User.withDefaultPasswordEncoder ==== -[source,java] +.Java +[source,java,role="primary"] ---- @Bean public UserDetailsService users() { @@ -70,6 +90,27 @@ public UserDetailsService users() { return new InMemoryUserDetailsManager(user, admin); } ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun users(): UserDetailsService { + // The builder will ensure the passwords are encoded before saving in memory + val users = User.withDefaultPasswordEncoder() + val user = users + .username("user") + .password("password") + .roles("USER") + .build() + val admin = users + .username("admin") + .password("password") + .roles("USER", "ADMIN") + .build() + return InMemoryUserDetailsManager(user, admin) +} +---- ==== There is no simple way to use `User.withDefaultPasswordEncoder` with XML based configuration. diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/jdbc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/jdbc.adoc index b5b2f5abba..54853c93a1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/jdbc.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/jdbc.adoc @@ -128,6 +128,18 @@ DataSource dataSource() { ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun dataSource(): DataSource { + return EmbeddedDatabaseBuilder() + .setType(H2) + .addScript("classpath:org/springframework/security/core/userdetails/jdbc/users.ddl") + .build() +} +---- ==== In a production environment, you will want to ensure you setup a connection to an external database. @@ -173,4 +185,26 @@ UserDetailsManager users(DataSource dataSource) { authorities="ROLE_USER,ROLE_ADMIN" /> ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun users(dataSource: DataSource): UserDetailsManager { + val user = User.builder() + .username("user") + .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW") + .roles("USER") + .build(); + val admin = User.builder() + .username("admin") + .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW") + .roles("USER", "ADMIN") + .build(); + val users = JdbcUserDetailsManager(dataSource) + users.createUser(user) + users.createUser(admin) + return users +} +---- ==== diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/ldap.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/ldap.adoc index 6102a786dd..d63b6267e1 100644 --- a/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/ldap.adoc +++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authentication/unpwd/storage/ldap.adoc @@ -133,12 +133,21 @@ UnboundIdContainer ldapContainer() { ---- .XML -[source,xml] +[source,xml,role="secondary"] ---- ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun ldapContainer(): UnboundIdContainer { + return UnboundIdContainer("dc=springframework,dc=org","classpath:users.ldif") +} +---- ==== [[servlet-authentication-ldap-apacheds]] @@ -203,6 +212,15 @@ ApacheDSContainer ldapContainer() { c:defaultPartitionSuffix="dc=springframework,dc=org" c:ldif="classpath:users.ldif"/> ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun ldapContainer(): ApacheDSContainer { + return ApacheDSContainer("dc=springframework,dc=org", "classpath:users.ldif") +} +---- ==== [[servlet-authentication-ldap-contextsource]] @@ -227,6 +245,14 @@ ContextSource contextSource(UnboundIdContainer container) { ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +fun contextSource(container: UnboundIdContainer): ContextSource { + return DefaultSpringSecurityContextSource("ldap://localhost:53389/dc=springframework,dc=org") +} +---- ==== [[servlet-authentication-ldap-authentication]] @@ -279,6 +305,22 @@ LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticato ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticator(contextSource: BaseLdapPathContextSource): BindAuthenticator { + val authenticator = BindAuthenticator(contextSource) + authenticator.setUserDnPatterns(arrayOf("uid={0},ou=people")) + return authenticator +} + +@Bean +fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthenticationProvider { + return LdapAuthenticationProvider(authenticator) +} +---- ==== This simple example would obtain the DN for the user by substituting the user login name in the supplied pattern and attempting to bind as that user with the login password. @@ -314,6 +356,25 @@ LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticato user-search-filter="(uid={0})" user-search-base="ou=people"/> ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticator(contextSource: BaseLdapPathContextSource): BindAuthenticator { + val searchBase = "ou=people" + val filter = "(uid={0})" + val search = FilterBasedLdapUserSearch(searchBase, filter, contextSource) + val authenticator = BindAuthenticator(contextSource) + authenticator.setUserSearch(search) + return authenticator +} + +@Bean +fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthenticationProvider { + return LdapAuthenticationProvider(authenticator) +} +---- ==== If used with the `ContextSource` <>, this would perform a search under the DN `ou=people,dc=springframework,dc=org` using `(uid={0})` as a filter. @@ -351,6 +412,20 @@ LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticato ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticator(contextSource: BaseLdapPathContextSource): PasswordComparisonAuthenticator { + return PasswordComparisonAuthenticator(contextSource) +} + +@Bean +fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthenticationProvider { + return LdapAuthenticationProvider(authenticator) +} +---- ==== A more advanced configuration with some customizations can be found below. @@ -387,6 +462,23 @@ LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticato ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticator(contextSource: BaseLdapPathContextSource): PasswordComparisonAuthenticator { + val authenticator = PasswordComparisonAuthenticator(contextSource) + authenticator.setPasswordAttributeName("pwd") // <1> + authenticator.setPasswordEncoder(BCryptPasswordEncoder()) // <2> + return authenticator +} + +@Bean +fun authenticationProvider(authenticator: LdapAuthenticator): LdapAuthenticationProvider { + return LdapAuthenticationProvider(authenticator) +} +---- ==== <1> Specify the password attribute as `pwd` @@ -424,6 +516,23 @@ LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticato user-dn-pattern="uid={0},ou=people" group-search-filter="member={0}"/> ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun authorities(contextSource: BaseLdapPathContextSource): LdapAuthoritiesPopulator { + val groupSearchBase = "" + val authorities = DefaultLdapAuthoritiesPopulator(contextSource, groupSearchBase) + authorities.setGroupSearchFilter("member={0}") + return authorities +} + +@Bean +fun authenticationProvider(authenticator: LdapAuthenticator, authorities: LdapAuthoritiesPopulator): LdapAuthenticationProvider { + return LdapAuthenticationProvider(authenticator, authorities) +} +---- ==== == Active Directory @@ -457,4 +566,13 @@ ActiveDirectoryLdapAuthenticationProvider authenticationProvider() { ---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +@Bean +fun authenticationProvider(): ActiveDirectoryLdapAuthenticationProvider { + return ActiveDirectoryLdapAuthenticationProvider("example.com", "ldap://company.example.com/") +} +---- ====