diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/LdapAuthentication.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/LdapAuthentication.java
new file mode 100644
index 00000000..f75587ca
--- /dev/null
+++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/LdapAuthentication.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.util.Assert;
+import org.springframework.vault.VaultException;
+import org.springframework.vault.client.VaultResponses;
+import org.springframework.vault.support.VaultResponse;
+import org.springframework.vault.support.VaultToken;
+import org.springframework.web.client.HttpStatusCodeException;
+import org.springframework.web.client.RestOperations;
+
+import static java.util.Collections.singletonMap;
+import static org.springframework.vault.authentication.AuthenticationUtil.getLoginPath;
+
+/**
+ * LDAP implementation of {@link ClientAuthentication}.
+ *
+ * @author Mikhael Sokolov
+ * @see LdapAuthenticationOptions
+ * @see RestOperations
+ * @see LDAP
+ * @since 2.4
+ */
+public class LdapAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
+
+ private static final Log logger = LogFactory.getLog(LdapAuthentication.class);
+
+ private final LdapAuthenticationOptions options;
+
+ private final RestOperations restOperations;
+
+ public LdapAuthentication(LdapAuthenticationOptions options, RestOperations restOperations) {
+ Assert.notNull(options, "LdapAuthenticationOptions must not be null");
+ Assert.notNull(restOperations, "RestOperations must not be null");
+
+ this.options = options;
+ this.restOperations = restOperations;
+ }
+
+ @Override
+ public VaultToken login() throws VaultException {
+ return createTokenUsingLdapAuthentication();
+ }
+
+ @Override
+ public AuthenticationSteps getAuthenticationSteps() {
+ return AuthenticationSteps
+ .fromSupplier(() -> singletonMap("password", options.getPassword()))
+ .login(String.format("%s/%s", getLoginPath(options.getPath()), options.getUsername()));
+ }
+
+ private VaultToken createTokenUsingLdapAuthentication() {
+ try {
+ VaultResponse response = restOperations.postForObject(String.format("%s/%s", getLoginPath(options.getPath()), options.getUsername()), singletonMap("password", options.getPassword()), VaultResponse.class);
+
+ logger.debug("Login successful using LDAP credentials");
+
+ return LoginTokenUtil.from(response.getAuth());
+ } catch (HttpStatusCodeException e) {
+ throw new VaultException(String.format("Cannot login using LDAP: %s", VaultResponses.getError(e.getResponseBodyAsString())), e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/LdapAuthenticationOptions.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/LdapAuthenticationOptions.java
new file mode 100644
index 00000000..d54ba0d4
--- /dev/null
+++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/LdapAuthenticationOptions.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.springframework.util.Assert;
+
+import javax.annotation.Nullable;
+
+/**
+ * @author Mikhael Sokolov
+ */
+public class LdapAuthenticationOptions {
+
+ public static final String DEFAULT_LDAP_AUTHENTICATION_PATH = "ldap";
+
+ /**
+ * Path of the ldap authentication backend mount.
+ */
+ private final String path;
+
+ /**
+ * Username of the ldap authentication backend mount.
+ */
+ private final String username;
+
+ /**
+ * Password of the ldap authentication backend mount.
+ */
+ private final CharSequence password;
+
+ private LdapAuthenticationOptions(String username, CharSequence password, String path) {
+ this.username = username;
+ this.password = password;
+ this.path = path;
+ }
+
+ public static LdapAuthenticationOptionsBuilder builder() {
+ return new LdapAuthenticationOptionsBuilder();
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public CharSequence getPassword() {
+ return password;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public static class LdapAuthenticationOptionsBuilder {
+
+ @Nullable
+ private String username;
+
+ @Nullable
+ private CharSequence password;
+
+ private String path = DEFAULT_LDAP_AUTHENTICATION_PATH;
+
+ LdapAuthenticationOptionsBuilder() {
+ }
+
+ public LdapAuthenticationOptionsBuilder username(String username) {
+ this.username = username;
+ return this;
+ }
+
+ public LdapAuthenticationOptionsBuilder password(CharSequence password) {
+ this.password = password;
+ return this;
+ }
+
+ public LdapAuthenticationOptionsBuilder path(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public LdapAuthenticationOptions build() {
+ Assert.notNull(this.username, "Username must not be null");
+ Assert.notNull(this.password, "Password must not be null");
+
+ return new LdapAuthenticationOptions(username, password, path);
+ }
+ }
+}
diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/UsernamePasswordAuthentication.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/UsernamePasswordAuthentication.java
new file mode 100644
index 00000000..121478b8
--- /dev/null
+++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/UsernamePasswordAuthentication.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.util.Assert;
+import org.springframework.vault.VaultException;
+import org.springframework.vault.client.VaultResponses;
+import org.springframework.vault.support.VaultResponse;
+import org.springframework.vault.support.VaultToken;
+import org.springframework.web.client.HttpStatusCodeException;
+import org.springframework.web.client.RestOperations;
+
+import static java.util.Collections.singletonMap;
+import static org.springframework.vault.authentication.AuthenticationUtil.getLoginPath;
+
+/**
+ * Username and password implementation of {@link ClientAuthentication}.
+ *
+ * @author Mikhael Sokolov
+ * @see UsernamePasswordAuthenticationOptions
+ * @see RestOperations
+ * @see Username & password
+ * @since 2.4
+ */
+public class UsernamePasswordAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
+
+ private static final Log logger = LogFactory.getLog(UsernamePasswordAuthentication.class);
+
+ private final UsernamePasswordAuthenticationOptions options;
+
+ private final RestOperations restOperations;
+
+ public UsernamePasswordAuthentication(UsernamePasswordAuthenticationOptions options, RestOperations restOperations) {
+ Assert.notNull(options, "UsernamePasswordAuthenticationOptions must not be null");
+ Assert.notNull(restOperations, "RestOperations must not be null");
+
+ this.options = options;
+ this.restOperations = restOperations;
+ }
+
+ @Override
+ public VaultToken login() throws VaultException {
+ return createTokenUsingUsernamePasswordAuthentication();
+ }
+
+ @Override
+ public AuthenticationSteps getAuthenticationSteps() {
+ return AuthenticationSteps
+ .fromSupplier(() -> singletonMap("password", options.getPassword()))
+ .login(String.format("%s/%s", getLoginPath(options.getPath()), options.getUsername()));
+ }
+
+ private VaultToken createTokenUsingUsernamePasswordAuthentication() {
+ try {
+ VaultResponse response = restOperations.postForObject(String.format("%s/%s", getLoginPath(options.getPath()), options.getUsername()), singletonMap("password", options.getPassword()), VaultResponse.class);
+
+ logger.debug("Login successful using username and password credentials");
+
+ return LoginTokenUtil.from(response.getAuth());
+ } catch (HttpStatusCodeException e) {
+ throw new VaultException(String.format("Cannot login using username and password: %s", VaultResponses.getError(e.getResponseBodyAsString())), e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationOptions.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationOptions.java
new file mode 100644
index 00000000..519ab5d9
--- /dev/null
+++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationOptions.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.springframework.util.Assert;
+
+import javax.annotation.Nullable;
+
+/**
+ * @author Mikhael Sokolov
+ */
+public class UsernamePasswordAuthenticationOptions {
+
+ public static final String DEFAULT_USERPASS_AUTHENTICATION_PATH = "userpass";
+
+ /**
+ * Path of the userpass authentication backend mount.
+ */
+ private final String path;
+
+ /**
+ * Username of the userpass authentication backend mount.
+ */
+ private final String username;
+
+ /**
+ * Password of the userpass authentication backend mount.
+ */
+ private final CharSequence password;
+
+ private UsernamePasswordAuthenticationOptions(String username, CharSequence password, String path) {
+ this.username = username;
+ this.password = password;
+ this.path = path;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public CharSequence getPassword() {
+ return password;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public static UsernamePasswordAuthenticationBuilder builder() {
+ return new UsernamePasswordAuthenticationBuilder();
+ }
+
+ public static class UsernamePasswordAuthenticationBuilder {
+
+ @Nullable
+ private String username;
+
+ @Nullable
+ private CharSequence password;
+
+ private String path = DEFAULT_USERPASS_AUTHENTICATION_PATH;
+
+ UsernamePasswordAuthenticationBuilder() {
+ }
+
+ public UsernamePasswordAuthenticationBuilder username(String username) {
+ this.username = username;
+ return this;
+ }
+
+ public UsernamePasswordAuthenticationBuilder password(CharSequence password) {
+ this.password = password;
+ return this;
+ }
+
+ public UsernamePasswordAuthenticationBuilder path(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public UsernamePasswordAuthenticationOptions build() {
+ Assert.notNull(this.username, "Username must not be null");
+ Assert.notNull(this.password, "Password must not be null");
+
+ return new UsernamePasswordAuthenticationOptions(username, password, path);
+ }
+ }
+}
diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/LdapAuthenticationIntegrationTestBase.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/LdapAuthenticationIntegrationTestBase.java
new file mode 100644
index 00000000..e751cdcd
--- /dev/null
+++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/LdapAuthenticationIntegrationTestBase.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.springframework.vault.support.Policy;
+import org.springframework.vault.util.IntegrationTestSupport;
+
+import java.util.Map;
+
+import static java.util.Collections.singletonMap;
+import static org.springframework.vault.authentication.LdapAuthenticationOptions.DEFAULT_LDAP_AUTHENTICATION_PATH;
+import static org.springframework.vault.support.Policy.BuiltinCapabilities.*;
+
+/**
+ * Integration test base class for {@link LdapAuthentication} tests.
+ *
+ * @author Mikhael Sokolov
+ */
+public abstract class LdapAuthenticationIntegrationTestBase extends IntegrationTestSupport {
+
+ static final Policy POLICY = Policy.of(Policy.Rule.builder().path("/*").capabilities(READ, CREATE, UPDATE).build());
+
+ protected final String username = "admin";
+ protected final String password = "qwerty";
+
+ @BeforeEach
+ public void before() {
+
+ if (!prepare().hasAuth(DEFAULT_LDAP_AUTHENTICATION_PATH)) {
+ prepare().mountAuth(DEFAULT_LDAP_AUTHENTICATION_PATH);
+ }
+
+ prepare().getVaultOperations().opsForSys().createOrUpdatePolicy(DEFAULT_LDAP_AUTHENTICATION_PATH, POLICY);
+ prepare().getVaultOperations().doWithSession(restOperations -> restOperations.postForEntity(String.format("auth/%s/users/%s", DEFAULT_LDAP_AUTHENTICATION_PATH, username), singletonMap("password", password), Map.class));
+ }
+}
\ No newline at end of file
diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/LdapAuthenticationIntegrationTests.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/LdapAuthenticationIntegrationTests.java
new file mode 100644
index 00000000..d4c4417a
--- /dev/null
+++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/LdapAuthenticationIntegrationTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.vault.client.VaultClients;
+import org.springframework.vault.support.VaultToken;
+import org.springframework.web.client.RestTemplate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link LdapAuthentication}.
+ *
+ * @author Mikhael Sokolov
+ */
+class LdapAuthenticationIntegrationTests extends LdapAuthenticationIntegrationTestBase {
+
+ @Test
+ void shouldLoginSuccessfully() {
+
+ RestTemplate restTemplate = VaultClients.createRestTemplate();
+ LdapAuthenticationOptions options = LdapAuthenticationOptions.builder()
+ .username(username)
+ .password(password)
+ .build();
+
+ LdapAuthentication authentication = new LdapAuthentication(options, restTemplate);
+ VaultToken login = authentication.login();
+
+ assertThat(login.getToken()).isNotEmpty();
+ }
+}
\ No newline at end of file
diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationIntegrationTestBase.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationIntegrationTestBase.java
new file mode 100644
index 00000000..50780ab1
--- /dev/null
+++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationIntegrationTestBase.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.springframework.vault.support.Policy;
+import org.springframework.vault.util.IntegrationTestSupport;
+
+import java.util.Map;
+
+import static java.util.Collections.singletonMap;
+import static org.springframework.vault.authentication.UsernamePasswordAuthenticationOptions.DEFAULT_USERPASS_AUTHENTICATION_PATH;
+import static org.springframework.vault.support.Policy.BuiltinCapabilities.*;
+
+/**
+ * Integration test base class for {@link UsernamePasswordAuthentication} tests.
+ *
+ * @author Mikhael Sokolov
+ */
+public abstract class UsernamePasswordAuthenticationIntegrationTestBase extends IntegrationTestSupport {
+
+ static final Policy POLICY = Policy.of(Policy.Rule.builder().path("/*").capabilities(READ, CREATE, UPDATE).build());
+
+ protected final String username = "admin";
+ protected final String password = "qwerty";
+
+ @BeforeEach
+ public void before() {
+
+ if (!prepare().hasAuth(DEFAULT_USERPASS_AUTHENTICATION_PATH)) {
+ prepare().mountAuth(DEFAULT_USERPASS_AUTHENTICATION_PATH);
+ }
+
+ prepare().getVaultOperations().opsForSys().createOrUpdatePolicy(DEFAULT_USERPASS_AUTHENTICATION_PATH, POLICY);
+ prepare().getVaultOperations().doWithSession(restOperations -> restOperations.postForEntity(String.format("auth/%s/users/%s", DEFAULT_USERPASS_AUTHENTICATION_PATH, username), singletonMap("password", password), Map.class));
+ }
+}
\ No newline at end of file
diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationIntegrationTests.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationIntegrationTests.java
new file mode 100644
index 00000000..4c12a4c0
--- /dev/null
+++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/UsernamePasswordAuthenticationIntegrationTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.vault.authentication;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.vault.client.VaultClients;
+import org.springframework.vault.support.VaultToken;
+import org.springframework.web.client.RestTemplate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration tests for {@link UsernamePasswordAuthentication}.
+ *
+ * @author Mikhael Sokolov
+ */
+class UsernamePasswordAuthenticationIntegrationTests extends UsernamePasswordAuthenticationIntegrationTestBase {
+
+ @Test
+ void shouldLoginSuccessfully() {
+
+ RestTemplate restTemplate = VaultClients.createRestTemplate();
+ UsernamePasswordAuthenticationOptions options = UsernamePasswordAuthenticationOptions.builder()
+ .username(username)
+ .password(password)
+ .build();
+
+ UsernamePasswordAuthentication authentication = new UsernamePasswordAuthentication(options, restTemplate);
+ VaultToken login = authentication.login();
+
+ assertThat(login.getToken()).isNotEmpty();
+ }
+}
\ No newline at end of file