mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-09 11:53:30 +00:00
Return Invalid Credentials message on login error
Closes gh-16484 Signed-off-by: tejas-teju <tejas8196@gmail.com>
This commit is contained in:
parent
e42865b926
commit
c4b223266c
@ -22,14 +22,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.support.MessageSourceAccessor;
|
|
||||||
import org.springframework.mock.web.MockHttpSession;
|
import org.springframework.mock.web.MockHttpSession;
|
||||||
import org.springframework.security.config.ObjectPostProcessor;
|
import org.springframework.security.config.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
|
||||||
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
@ -77,8 +75,6 @@ public class DefaultLoginPageConfigurerTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
MockMvc mvc;
|
MockMvc mvc;
|
||||||
|
|
||||||
MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getWhenFormLoginEnabledThenRedirectsToLoginPage() throws Exception {
|
public void getWhenFormLoginEnabledThenRedirectsToLoginPage() throws Exception {
|
||||||
this.spring.register(DefaultLoginPageConfig.class).autowire();
|
this.spring.register(DefaultLoginPageConfig.class).autowire();
|
||||||
@ -148,8 +144,7 @@ public class DefaultLoginPageConfigurerTests {
|
|||||||
this.mvc.perform(get("/login?error").session((MockHttpSession) mvcResult.getRequest().getSession())
|
this.mvc.perform(get("/login?error").session((MockHttpSession) mvcResult.getRequest().getSession())
|
||||||
.sessionAttr(csrfAttributeName, csrfToken))
|
.sessionAttr(csrfAttributeName, csrfToken))
|
||||||
.andExpect((result) -> {
|
.andExpect((result) -> {
|
||||||
String badCredentialsLocalizedMessage = this.messages
|
String defaultErrorMessage = "Invalid credentials";
|
||||||
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials");
|
|
||||||
CsrfToken token = (CsrfToken) result.getRequest().getAttribute(CsrfToken.class.getName());
|
CsrfToken token = (CsrfToken) result.getRequest().getAttribute(CsrfToken.class.getName());
|
||||||
assertThat(result.getResponse().getContentAsString()).isEqualTo("""
|
assertThat(result.getResponse().getContentAsString()).isEqualTo("""
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -184,7 +179,7 @@ public class DefaultLoginPageConfigurerTests {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>""".formatted(badCredentialsLocalizedMessage, token.getToken()));
|
</html>""".formatted(defaultErrorMessage, token.getToken()));
|
||||||
});
|
});
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,10 @@ import jakarta.servlet.ServletRequest;
|
|||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.servlet.http.HttpSession;
|
|
||||||
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.web.WebAttributes;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
|
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.filter.GenericFilterBean;
|
import org.springframework.web.filter.GenericFilterBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,7 +217,7 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess) {
|
private String generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess) {
|
||||||
String errorMsg = loginError ? getLoginErrorMessage(request) : "Invalid credentials";
|
String errorMsg = "Invalid credentials";
|
||||||
String contextPath = request.getContextPath();
|
String contextPath = request.getContextPath();
|
||||||
|
|
||||||
return HtmlTemplates.fromTemplate(LOGIN_PAGE_TEMPLATE)
|
return HtmlTemplates.fromTemplate(LOGIN_PAGE_TEMPLATE)
|
||||||
@ -358,21 +354,6 @@ public class DefaultLoginPageGeneratingFilter extends GenericFilterBean {
|
|||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLoginErrorMessage(HttpServletRequest request) {
|
|
||||||
HttpSession session = request.getSession(false);
|
|
||||||
if (session == null) {
|
|
||||||
return "Invalid credentials";
|
|
||||||
}
|
|
||||||
if (!(session
|
|
||||||
.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) instanceof AuthenticationException exception)) {
|
|
||||||
return "Invalid credentials";
|
|
||||||
}
|
|
||||||
if (!StringUtils.hasText(exception.getMessage())) {
|
|
||||||
return "Invalid credentials";
|
|
||||||
}
|
|
||||||
return exception.getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String renderHiddenInput(String name, String value) {
|
private String renderHiddenInput(String name, String value) {
|
||||||
return HtmlTemplates.fromTemplate(HIDDEN_HTML_INPUT_TEMPLATE)
|
return HtmlTemplates.fromTemplate(HIDDEN_HTML_INPUT_TEMPLATE)
|
||||||
.withValue("name", name)
|
.withValue("name", name)
|
||||||
|
@ -18,17 +18,14 @@ package org.springframework.security.web.authentication;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.context.support.MessageSourceAccessor;
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
|
||||||
import org.springframework.security.web.WebAttributes;
|
import org.springframework.security.web.WebAttributes;
|
||||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||||
|
|
||||||
@ -128,22 +125,6 @@ public class DefaultLoginPageGeneratingFilterTests {
|
|||||||
assertThat(response.getContentAsString()).isEmpty();
|
assertThat(response.getContentAsString()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SEC-1111 */
|
|
||||||
@Test
|
|
||||||
public void handlesNonIso8859CharsInErrorMessage() throws Exception {
|
|
||||||
DefaultLoginPageGeneratingFilter filter = new DefaultLoginPageGeneratingFilter(
|
|
||||||
new UsernamePasswordAuthenticationFilter());
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/login");
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
request.setQueryString("error");
|
|
||||||
MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
|
||||||
String message = messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials",
|
|
||||||
"Bad credentials", Locale.KOREA);
|
|
||||||
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, new BadCredentialsException(message));
|
|
||||||
filter.doFilter(request, response, this.chain);
|
|
||||||
assertThat(response.getContentAsString()).contains(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// gh-5394
|
// gh-5394
|
||||||
@Test
|
@Test
|
||||||
public void generatesForOAuth2LoginAndEscapesClientName() throws Exception {
|
public void generatesForOAuth2LoginAndEscapesClientName() throws Exception {
|
||||||
@ -244,7 +225,7 @@ public class DefaultLoginPageGeneratingFilterTests {
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<form class="login-form" method="post" action="null">
|
<form class="login-form" method="post" action="null">
|
||||||
<h2>Please sign in</h2>
|
<h2>Please sign in</h2>
|
||||||
<div class="alert alert-danger" role="alert">Bad credentials</div>
|
<div class="alert alert-danger" role="alert">Invalid credentials</div>
|
||||||
<p>
|
<p>
|
||||||
<label for="username" class="screenreader">Username</label>
|
<label for="username" class="screenreader">Username</label>
|
||||||
<input type="text" id="username" name="username" placeholder="Username" required autofocus>
|
<input type="text" id="username" name="username" placeholder="Username" required autofocus>
|
||||||
@ -259,12 +240,12 @@ public class DefaultLoginPageGeneratingFilterTests {
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h2>Login with OAuth 2.0</h2>
|
<h2>Login with OAuth 2.0</h2>
|
||||||
<div class="alert alert-danger" role="alert">Bad credentials</div>
|
<div class="alert alert-danger" role="alert">Invalid credentials</div>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<tr><td><a href="/oauth2/authorization/google">Google < > " ' &</a></td></tr>
|
<tr><td><a href="/oauth2/authorization/google">Google < > " ' &</a></td></tr>
|
||||||
</table>
|
</table>
|
||||||
<h2>Login with SAML 2.0</h2>
|
<h2>Login with SAML 2.0</h2>
|
||||||
<div class="alert alert-danger" role="alert">Bad credentials</div>
|
<div class="alert alert-danger" role="alert">Invalid credentials</div>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<tr><td><a href="/saml/sso/google">Google < > " ' &</a></td></tr>
|
<tr><td><a href="/saml/sso/google">Google < > " ' &</a></td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user