Using Spring Security, how to stay on the login page after a successful login? - spring

Using Spring Security, how can I stay on the login page after a successful login?
This part of my Spring config file:
<http auto-config="true" use-expressions="true">
<form-login authentication-failure-url="/index.jsp?failed=true" default-target-url="/index.jsp" />
<logout logout-success-url="/index.jsp" />
</http>
And I have a jsp fragment file /WEB-INF/jsp/subhead.jspf:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<c:url var="postLoginUrl" value="j_spring_security_check" />
<c:url var="logoutUrl" value="j_spring_security_logout"/>
<c:if test="${param.failed == true}">Login Failed...</c:if>
<security:authorize access="isAnonymous()">
<form action="${postLoginUrl}" method="post">
Username: <input type="text" name="j_username"/>
Password: <input type="password" name="j_password" />
<input type="submit" value="Log in"/>
</form>
</security:authorize>
<security:authorize access="isAuthenticated()">
Hi, <security:authentication property="principal.username"/> Log out
</security:authorize>
I have a page say test.jsp:
<html>
<body>
<%# include file="/WEB-INF/jsp/subhead.jspf" %>
</body>
</html>
How can I make
login success
login failed
logout
all redirect back to the login page (test.jsp)?
For now, they will all redirect to /index.jsp.

Related

Spring MVC serve static file when submit a form

I'm running through weird behavior in Spring MVC. I try to make custom login page with spring security.
Here is my simple login page with a link to a style sheet login.jsp:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<link href="/resources/css/style.css" rel="stylesheet"/>
</head>
<body>
<h1>Login Form</h1>
<form:form action="/authuser" method="post">
<c:if test="${param.logout != null}">
<i>You have been logout!</i>
</c:if>
<c:if test="${param.error != null}">
<i>Invalid username or password!</i>
</c:if>
<p>
User name: <input type="text" name="username"/>
</p>
<p>
Password: <input type="password" name="password"/>
</p>
<input type="submit" value="Login"/>
</form:form>
</body>
</html>
when I fill out the form and hit submit it redirect me to http://localhost:8080/resources/css/test.css and serves me with stylesheet file!
when I remove the stylesheet link, it works fine and redirects me to the home page.

Spring MVC: twice auth request - login form and browser window. WHY?

The problem is that after successful authorization on the login form (login.jsp), when trying to access the controllers (path: rest/profile), a browser window appears asking for the username and password (httpbasic).
QUESTION: why Spring Security requires double authentication - entering a password at the login form is not enough?
login.jsp:
<%# page contentType="text/html" pageEncoding="UTF-8" %>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<jsp:include page="fragments/headTag.jsp"/>
<body>
<jsp:include page="fragments/bodyHeader.jsp"/>
<div class="container">
<div class="d-flex justify-content-center h-100">
<div class="card">
<div class="card-header">
<h3><spring:message code="app.signIn"/></h3>
</div>
<div class="card-body">
<form:form id="login_form" action="spring_security_check" method="post">
<div class="input-group form-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-user"></i></span>
</div>
<input type="text" name="username" class="form-control" placeholder="<spring:message code="user.login"/>">
</div>
<div class="input-group form-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-key"></i></span>
</div>
<input type="password" name="password" class="form-control" placeholder="<spring:message code="user.password"/>">
</div>
<div class="row align-items-center remember">
<input type="checkbox"><spring:message code="app.rememberMe"/>
</div>
<div class="form-group">
<button type="submit" class="btn float-right yellow_btn"><spring:message code="app.login"/></button>
</div>
</form:form>
</div>
<br>
<div class="card-footer">
<div class="d-flex justify-content-center links">
<spring:message code="app.notProfileQuestion"/>
</div>
<div class="d-flex form-group justify-content-center">
<a class="btn yellow_btn" href="profile/register"><spring:message code="app.register"/> ยป</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<http pattern="/resources/**" security="none"/>
<http pattern="/webjars/**" security="none"/>
<http pattern="/rest/**" use-expressions="true" name="restSecurityFilterChain" create-session="stateless">
<http-basic/>
<intercept-url pattern="/rest/profile/register" access="isAnonymous()"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
<csrf disabled="true"/>
</http>
<beans:bean class="org.springframework.security.crypto.factory.PasswordEncoderFactories" id="passwordEncoder" factory-method="createDelegatingPasswordEncoder"/>
<http>
<intercept-url pattern="/login" access="permitAll()"/>
<intercept-url pattern="/profile/register" access="isAnonymous()"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
<form-login login-page="/login" default-target-url="/profile"
authentication-failure-url="/login?error=true"
login-processing-url="/spring_security_check"/>
<logout logout-success-url="/login"/>
<!--<csrf disabled="true"/>-->
</http>
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
</beans:beans>
How to fix problem? I want enter password only once - at login page.

spring authentication: can't logout

I'm new to Spring. I can't logout with spring security.
Login works fine, and I'm following this post to implement the logout function.
but I can't make it work.
here's my spring-security.xml:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/index" access="hasRole('ROLE_USER')" />
<security:logout logout-success-url="/index" logout-url="/logout" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="matt3o" password="secret" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
and here's my index.jsp:
<c:if test="${pageContext.request.userPrincipal.name != null}">
<h2>Welcome : ${pageContext.request.userPrincipal.name}
</c:if>
<p>Logout</p>
Please can somebody explain to me how loggin/loggout works and why my logout doesn't ?
In index.jsp I'm trying to logout in different ways, none of them works:
<!--1-->
<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
Logout
</c:if>
<br><br>
<!--2-->
logout1
<br><br>
<!--3-->
<a href='<c:url value="j_spring_security_logout" />'>logout</a>
Spring Security 4 requires a POST request to logout instead of a GET. Next to that by default it is secured using a CSFR token, which you would need to add to the form (see the javadoc).
So instead of a link use a form to invoke the logout.
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
<input type="submit" value="Log out" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
or when using the security tag library
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
<input type="submit" value="Log out" />
<sec:csrfInput />
</form>
See also here and here in the reference guide.
If you want to use a GET either configure the logout functionality as such that it supports GET requests (for this you need to provide an ant matcher) or by disabling CSFR which can be done by adding <sec:csfr disabled="true" /> to your xml configuration.
you can use
href="<c:url value="/logout"/>"

Spring security repeated redirects

I am using spring security in my application. I want the user to be logged in first before accessing any pages on the server, hence i am taking the redirect approach. But the redirect seems to be in an infinite loop cause it redirects me to the login page no matter how many times i submit the page. I tried debugging and the request always hits the GET instead of the POST method as i expected. I am using LDAP authentication using the details entered by the user on the form. Here is the code in the security context xml . Can someone point me in the right direction.
<http pattern="/resources/**" security="none" />
<http auto-config="true">
<intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/login" default-target-url="/dashboard"
authentication-failure-url="/loginfailed" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
When i remove the
<form-login login-page="/login" default-target-url="/dashboard"
authentication-failure-url="/loginfailed" />
it defaults to spring login page and it works but i have to use the user credentials from the configuration xml as opposed to LDAP credentials.
Edit**
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<link rel="stylesheet" href="${contextPath}/resources/css/styles.css" type="text/css">
<h2 style="text-align:center">Login to continue to Application</h2>
<div align="center" class="div">
<form:form method="POST" modelAttribute="login" action="authenticate">
<table>
<tr>
<td><form:label path="username" class="label">Username:</form:label></td>
<td><form:input path="username" class="input"/></td>
<td><form:errors path="username" class="error" /></td>
</tr>
<tr>
<td><form:label path="password" class="label">Password:</form:label></td>
<td><form:password path="password" class="input"/></td>
<td><form:errors path="password" class="error"/></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit"
value="Login" class="button"/></td>
</tr>
</table>
</form:form>
</div>
thanks
Sree
#sri
as mentioned in your code i can see that you have intercepted the URL "/login*"
now any url with login at the end will be intercepted by spring security and after that you have to put the correct credentials....
now After giving credentials your are redirected to page /login
now its clear that again our url is ending with login hence it is intercepted again by spring security ...
thats why the loop continues....
Possible Solution
this may work for you,
just put the following code below <http pattern="/resources/**" security="none" /> tag as shown:
code:
<http pattern="/resources/**" security="none" />
<http pattern="/Login.html" security="none" />
Ok. Finally i got to a working state. Here are the changes i made to the security context xml
<intercept-url pattern="/login/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
the url regex change. And also the action in my login.jsp is now
action="/login/authenticate"
and finally the controller request mapping path is updated.
Hope this helps anyone who has a similar issue. I am yet to discover if this is the right approach to achieve it but works for now.
-Sree

How to display error message in my JSP page using spring security 2.0

Hi I am now using spring security. It works fine. But if login failed, no error message display. I am wondering how can I display error message?
I have configured the ResourceBundleMessageSource in my applicationContext.xml
<!-- Spring security error message config -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages</value>
</list>
</property>
</bean>
And my security-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:David="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<David:http auto-config="true" access-denied-page="/accessDenied.html">
<!-- Don`t set any role restriction on login.jsp -->
<David:intercept-url pattern="/login.jsp"
access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!-- Restrict access to All other pages -->
<David:intercept-url pattern="/admin.jsp"
access="ROLE_ADMIN" />
<!-- Set the login page and what to do if login fails -->
<David:form-login login-page="/login.jsp"
default-target-url="/"/>
<David:logout logout-success-url="/" />
</David:http>
<!-- Specify login examnination strategy -->
<David:authentication-provider>
<David:password-encoder hash="md5" />
<David:jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username, password, status as enabled from user where username=?"
authorities-by-username-query="select u.username,r.name as authority
from user u
join user_role ur
on u.id=ur.user_id
join role r
on r.id=ur.role_id
where u.username=?" />
</David:authentication-provider>
</beans>
My jsp page:
<%# page contentType="text/html;charset=utf-8"%>
<%# taglib prefix="s" uri="/struts-tags"%>
<%# page
import="org.springframework.security.ui.AbstractProcessingFilter"%>
<%# page
import="org.springframework.security.ui.webapp.AuthenticationProcessingFilter"%>
<%# page import="org.springframework.security.AuthenticationException"%>
<form id="myform" class="cmxform" method="post"
action="${pageContext.request.contextPath}/j_spring_security_check">
<fieldset>
<legend>
Please input correct username and password to login
</legend>
<p>
<label for="user">
Username:
</label>
<input id="user" name="j_username" />
</p>
<p>
<label for="pass">
Password:
</label>
<input type="password" name="j_password" id="password" />
</p>
<p>
<input type="submit" class="submit" value="Login" />
</p>
</fieldset>
</form>
Any suggestions? Any help will be appreciated.
<c:if test="${not empty param.login_error}">
<div class="error">
Your login attempt was not successful, try again.<br />
Reason: #{sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
</div>
</c:if>
This works
<c:if test="${param.error != null}">
Error
</c:if>
Where is the jsp to actually display the error? Something like
<c:if test="${not empty param.error}">
<!-- Display error message -->
</c:if>
If you want to customize this message, you should also look at this
Maybe you can try this...put
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
for c tag on jsp page, and then put something like below for error msg display
<c:when test="${param.error == 1}">
<h3 style="font-size:20; color:#FF1C19;">Wrong id or password!</h3>
</c:when>
"param.error == 1" can get return value from Spring Security(security-config.xml) like
<beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="org.springframework.security.core.userdetails.UsernameNotFoundException">/login.action?error=1</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
This worked for me :
<c:if test="${not empty sessionScope.SPRING_SECURITY_LAST_EXCEPTION}">
<div class="error">
Your login attempt was not successful, try again.<br />
Reason: ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}
</div>
</c:if>
I am using spring-security v 4.0.3.RELEASE
Using the not empty did not work for me. However checking for null worked for me.
<c:if test="${ param.error ne null}">
Display error message
</c:if>

Resources