I was using a tutorial on this link:
http://www.mkyong.com/spring-security/display-custom-error-message-in-spring-security/
To show a custom error message on login form and I got it at the beginning. But after declaring a authentication-failure-handler-ref="myAuthErrorHandler" for a custom failure authenticator handler I can't see it the custom message on the login form:
What I am doing wrong? Can anybody explain me what happen and why the 'Invalid username or password' doesn't show?
Here's the code:
AuthentificationListener
public class AuthentificationListener implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException ae)
throws IOException, ServletException {
UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) ae
.getAuthentication();
/* User */
response.sendRedirect(request.getContextPath()
+ "/abc/main/loginfailed");
}
}
applicationContext.xml:
<bean id="myAuthErrorHandler" class="org.abc.handler.AuthentificationListener"/>
Spring Security:
<http auto-config="true">
<intercept-url pattern="/abc/main/welcome*" access="ROLE_USER" />
<intercept-url pattern="/abc/main/record/**" access="ROLE_USER" />
<form-login
login-page="/abc/main/login"
authentication-failure-handler-ref="myAuthErrorHandler"
default-target-url="/abc/main/welcome"
/>
<logout logout-success-url="/abc/main/logout" />
</http>
login.jsp:
<c:if test="${not empty error}">
<div class="errorblock">
Your login attempt was not successful, try again.<br /> Caused :
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
</div>
</c:if>
LoginController.java:
#RequestMapping(value="/loginfailed", method = RequestMethod.GET)
public String loginerror(ModelMap model) {
model.addAttribute("error", "true");
return "login";
}
Update: To answer on Mani answer, I'm using a LoginController, which redirects loginfailed requests to login.jsp and is sending an 'error' attribute with the 'true' value. The problem is I can't see the message on the login.jsp using this expression:
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
Any Idea? Thank You very much!
On Failure of Authendication, you have asked to redirect to different Page.
response.sendRedirect(request.getContextPath()
+ "/abc/main/loginfailed");
your loginfailed jsp not displayed ? it doesn't has div like errorblock in login page ? are you seeing different error in loginfailed.jsp ?
EDIT:
Ok I got it . Before authentication-failure-handler-ref="myAuthErrorHandler" Spring Handles the failure case and placed message in Session with the key SPRING_SECURITY_LAST_EXCEPTION .
After adding the failure handler i.e
authentication-failure-handler-ref="myAuthErrorHandler"
You have to handle the error. You can set the message in session. or simply call the super.onAuthenticationFailure . Your handler is not doing anything !!!
<div style="color: red">
Your login attempt was not successful, try again.<br /> Caused :
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
</div>
use this, remove form login.jsp
create a properties file name as
mymessages.properties
AbstractUserDetailsAuthenticationProvider.badCredentials=Invalid username or password
and save it and place into your project classpath
and add the the bean in your spring-contex.xml
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>mymessages</value>
</list>
</property>
</bean>
Related
I am trying redirect to the previous URL with POST form submission after successful login for that i configured below bean i am able to redirect with POST submission but here i am trying to upload a file but i am unable to get the multipart object after login i.e., i am getting file object as null.Please help me to achieve this thanks in advance. Here is my bean and XML configuration.
spring-security.xml
<http>
<csrf />
<request-cache ref="requestCache" />
</http>
<beans:bean id="requestCache" class="com.web.listeners.Test" />
Test.java
public class Test extends HttpSessionRequestCache {
#Override
public void saveRequest(HttpServletRequest request, HttpServletResponse
response)
{
final String SAVED_REQUEST = "SPRING_SECURITY_SAVED_REQUEST";
DefaultSavedRequest savedRequest = new DefaultSavedRequest(request,
new PortResolverImpl());
request.getSession().setAttribute(SAVED_REQUEST, savedRequest);
}
}
test.jsp
<c:url value="/file/uploadFile?${_csrf.parameterName}=${_csrf.token}" var="uploadFileURL"/>
<form:form action="${uploadFileURL}" method="post" enctype="multipart/form-data" modelAttribute="multiPartVo">
<input id="file" name="file" type="file" />
<button type="submit" value="SAVE" ></button>
</form:form>
I'm trying to make a custom login form and redirect the user to a student page if he has the ROLE_USER.
Controller:
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping("/student")
public String mypage(Model model, Principal principal) {
model.addAttribute("TADADAGHDGHA");
return "student/student";
}
// #RequestMapping(value = "/logout", method = RequestMethod.GET)
// public String logoutPage() {
// return "/logoutPage";
// }
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage() {
return "login/loginPage";
}
}
spring-security.xml
<http auto-config="true" use-expressions="true" disable-url-rewriting="true">
<intercept-url pattern="/login/*" access="ROLE_USER" />
<form-login login-processing-url="/login" login-page="/login/loginPage"
username-parameter="email" password-parameter="password"
default-target-url="/student" authentication-failure-url="/loginPage?auth=fail" />
<logout logout-success-url="/logoutPage" />
</http>
In VIEWS folder I have a page logout,a folder named LOGIN with login.jsp and tiles-definitions.xml and another one named STUDENT with student.jsp file.
Don't restrict the permissions to view your login page. Otherwise people will be continually redirected to a page they don't have access to... This is where your redirect loop is coming from.
Also, there may be an issue with your authentication-failure-url setting. It doesn't seem like a valid link per the given configuration.
According to spring documentation you can check if a user has a role in your spring-security.xml this way:
<intercept-url pattern="/login/*" method="GET" access="hasRole('ROLE_USER')" /> OR
<intercept-url pattern="/login/*" method="POST" access="hasRole('ROLE_USER')" />
If the user has the role, only then he can view the page.
You can also restrict method access of your service layer this way;
#PreAuthorize("hasRole('ROLE_USER')")
public void methodName() {
// Only users with ROLE_USER can access this content.
}
You can use permissions if you want for more information refer to Spring Documentation, Spring in Action or any Spring book.
I'm implementing a login system for a website that I'm building, but I'm very new at spring security. For this reason I have a few questions that I hope someone can help me (for better reference I will enumerate the questions).
1) For example, I have a page howthiswork that is only available if the user is authenticated and have the ROLE_USER and if some one hit this page without been first authenticated the system will redirect to the login page.(that is fantastic and what is to expect). But (always a but) when the user is in the login page and press the banner (the home pag link) and from there try to authenticate, the user will be redirect to the howthiswork. How can I prevent this situation to happen? I still want the redirect to work when the user hit a non authorized page (go to login and then redirect to the hit page) but also if the user leaves the login without any action this redirection will be clean!
2) I had override the loadUserByUsername to check the user information, and I want to throw different exceptions for example, when the user does not exist or when is not confirmed or banned etc. I have there already throw new UsernameNotFoundException("login.error.username.no t.found") and I have a messages.properties files in my resource filepath but in my jsp the SPRING_SECURITY_LAST_EXCEPTION.message has always the bad credential message (I had try to override this in my messages.properties but without success). Can anyone know how I can use my own error messages?
3) In the controller (some controller) we can have the Principal. Is this secure (we can rely that know one will change, let say if I'm ajpcmachado I cant call that controller saying I'm admin)?
My code is:
Login JSP:
<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
<div id="login-message" style="display:none;" title="<fmt:message key="app.error"/>">
<span class="ui-icon ui-icon-circle-close" style="float:left; margin:0 7px 50px 0;"></span>
<p class="error"><c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/></p>
<c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION"/>
</div>
<script type="text/javascript">
$( "#login-message" ).dialog({
resizable: true,
height: "auto",
width: 300,
modal: true,
dialogClass: 'ui-state-error',
buttons : [{
"id" : "closeButton",
text : '<fmt:message key="app.close"/>',
click : function() {
$(this).dialog("close");
}
} ]
});
</script>
</c:if>
<form id="loginuser" name="loginuser" action="<spring:url value="/j_spring_security_check" htmlEscape="true" />" method="POST" class="login">
<div id="user_login">
<fieldset>
<dl>
<input type='text' name='other_email' id='other_email'>
<dt><label for="j_username"><fmt:message key="app.username" />:</label></dt>
<dd><input id="j_username" name="j_username" type="text" tabindex="1" /></dd>
<dt><label for="j_password"><fmt:message key="app.password" />:</label></dt>
<dd><input id="j_password" name="j_password" type="password" tabindex="2" /></dd>
<div style="float:right">
<label for="_spring_security_remember_me"><fmt:message key="app.rememberme" /></label>
<input type='checkbox' id="_spring_security_remember_me" name='_spring_security_remember_me' style="width:30px !important; vertical-align: middle;" tabindex="3"/>
</div>
</dl>
</fieldset>
<p class="btn-paragraph">
<input type="submit" class="submitLoginButton btn-submit-style" value="<fmt:message key="app.login"/>" />
<fmt:message key="login.recovery" />
</p>
</div>
</form>
My Spring-security file
<http pattern="/resources/css" security="none" />
<http pattern="/resources/images" security="none" />
<http pattern="/resources/js" security="none" />
<global-method-security secured-annotations="enabled">
</global-method-security>
<http auto-config="true" use-expressions="true" access-denied-page="/accessDenied/">
<logout logout-success-url="/" invalidate-session="true"/>
<intercept-url pattern="/howthiswork/" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/**" access="permitAll"/>
<!-- Set the login page and what to do if login fails -->
<form-login login-page="/login/" authentication-failure-url="/login/?error=true"/>
<remember-me data-source-ref="dataSource"/>
</http>
<!-- Use a Sha256 encoder since the user's passwords are stored as Sha256 in the database -->
<beans:bean id ="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" >
<beans:constructor-arg value="256"/>
<beans:property name="iterations" value="1024"/>
</beans:bean>
<beans:bean id="loginService" class="com.projectx.standard.services.user.implementation.LoginUserServiceImpl"/>
<authentication-manager>
<authentication-provider user-service-ref="loginService">
<password-encoder ref="passwordEncoder">
<salt-source user-property="username"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
The LoginService.java:
#Override
#SuppressWarnings("static-access")
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = null;
RegisteredUserDTO a = this.registeredUserServiceDAO.getRegisteredUserByUsername(username);
if (a == null) {
throw new UsernameNotFoundException("login.error.username.not.found");
}
int confirmedStatus = Integer.parseInt(Configuration.getInstance().getValue(SystemConfigEnum.STATUS_CONFIRM));
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(3);
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
user = new User(a.getUsername(), a.getPwd().toLowerCase(), a.getFkStatus() == confirmedStatus, true, true, true, authList);
return user;
}
The messages.properties
login.recovery=Forgot your password?
login.error=You have entered an invalid email or password!
AbstractUserDetailsAuthenticationProvider.disabled=Your account is disabled. Please press here to send the confirmation email.
login.error.username.not.found = Username not found in the system!
AbstractUserDetailsAuthenticationProvider.badCredentials=Invalid username or password
BindAuthenticator.badCredentials=Invalid username or password
Sorry about this long post, but I think is better in one post instead of multiple ones!!
Thank you!
Well, this post is a little bit large, but the answers are not to long... so:
1 - Every time someone tries to access to a restricted area, the user is redirected to the login page and this page link is stored into the session SPRING_SECURITY_SAVED_REQUEST (someone correct me if I'm wrong!!). So all you need to do is to clean this attribute when you change page. You can do this in JSLT with
<c:remove scope="session" var="SPRING_SECURITY_SAVED_REQUEST"/>
2 - Not the best option, but you could raise other exception like DisabledException("...") or any other exception that fits.
3 - I don't think you can change the principal, but I'm the best person to help here... Is just my guess!!
I have implemented spring-security in my application, my spring-security.xml has following form-login tag.
<form-login login-page="/login.htm" default-target-url="/dashboard.htm"
authentication-failure-url="/login.htm?error=true"
authentication-success-handler-ref="authenticationSuccessHandler" />
I want to login from /login.htm and after successful authetication I want user to hit dashboard.htm. Everythig is working fine except for the fact that after successfull authetication it doesn't hit /dashboard.htm but hits the context..but if I manually type dashboard.htm in url then everything works fine...Yes..I have the implementation of authticationSuccessHandler.
Try removing the default-target-url attribute and add the following:
<b:bean id="authenticationSuccessHandler" class="com.example.CustomSimpleURLAuthenticationSuccessHandler">
<b:property name="defaultTargetUrl" value="/dashboard.htm"/>
</b:bean>
<beans:bean id="loginSuccessHandler" class="com.example.LoginSuccessHandler">
<beans:property name="defaultTargetUrl" value="/security/success"/>
<beans:property name="alwaysUseDefaultTargetUrl" value="true"/>
</beans:bean>
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
request.getSession().setMaxInactiveInterval(60 * 60); //one hour
System.out.println("Session set up for 60min");
super.onAuthenticationSuccess(request, response, authentication);
}
}
I use this suggestion from the question spring is not redirecting to default target url?. I tried this and it is working.
<form-login login-page="/login.htm"
default-target-url="/dashboard.htm"
always-use-default-target="true"/>
As you can see in the image, there is some kind of bad design (IMO It always redirect to the default-target-url).
When you go to the login form from a forbidden resource, it will redirect you to that URL and not going thru the default-target-url
http://i.stack.imgur.com/fj9ou.png
Im trying to write a controller and a form that can handle a multipart file upload and some other data passing.
First i made the basic form like this:
<form:form method="POST" commandName="myForm">
then everything fine, but no multipart handling of course. Then i add the enctype part like this:
<form:form method="POST" commandName="myForm" enctype="multipart/form-data">
Then my whole form is messed up and all the attribuets gives NullPointers. Not even a simple String name attribute working. Also i added:
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
So i really got no idea whats the problem. Any comment would help a lot. Thnaks in advance.
We are using CommonsMultipartResolver in our project. It goes like this. In your applicationContext.xml:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="1048576000"/>
<property name="defaultEncoding" value="UTF-8" />
</bean>
Then cast yout request to MultipartHttpServletRequest:
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
if (!(req instanceof MultipartHttpServletRequest)) {
error(resp, "Invalid request (multipart request expected)");
return null;
}
Map<String, MultipartFile> files = ((MultipartHttpServletRequest)req).getFileMap();
... do thomething with the files