I have a web application which uses JSF and Spring security is used for login and authorization.
When a user types in a specific page and he is not logged in, e.g. localhost:8080/APP/page.xhtml, the application redirects to the login page which is OK. After that, the user is logged in but the page he is redirected to is index.xhtml which is the default welcome page, and not to page.xhtml.
I want the following behaviour: user goes to localhost:8080/APP/page.xhtml, he is redirected to be logged in and after that he should be redirected to his desired page - page.xhtml.
Edited - Snippet of spring-security.xml:
<security:http auto-config="true">
<security:intercept-url pattern="/javax.faces.resource/*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/login.xhtml" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/**" access="ROLE_UNALLOCATED, ROLE_MANAGER"/>
<security:intercept-url pattern="/pages/management/" access="ROLE_MANAGER"/>
<security:intercept-url pattern="/pages/requests/" access="ROLE_UNALLOCATED, ROLE_EMPLOYEE, ROLE_TEAM_LEADER, ROLE_MANAGER"/>
<security:form-login login-page="/login.xhtml"
/>
<security:logout logout-url="/j_spring_security_logout"
logout-success-url="/login.xhtml"
invalidate-session="true"/>
</security:http>
Any ideas? Thanks
Edit:
I thought it was because:
<!-- Welcome page -->
<welcome-file-list>
<welcome-file>/index.xhtml</welcome-file>
</welcome-file-list>
from web.xml. I removed this but with the same result.
Later edit:
I just noticed a line in my custom loginController after if (authenticationResponseToken.isAuthenticated()) which is almost surely the source of the problem:
The loginController:
@ManagedBean(name = "loginController")
@SessionScoped
@Controller
public class LoginController implements Serializable {
private static final long serialVersionUID = 1L;
@Autowired
IUserService userService;
@Autowired
@Qualifier("authenticationManager")
protected AuthenticationManager authenticationManager;
// save the current user after login to be able to inject it in other places
// as needed
private User currentUser;
/**
* This action logs the user in and returns to the secure area.
*
* @return String path to secure area
*/
public String loginUsingSpringAuthenticationManager() {
// get backing bean for simple redirect form
LoginFormBackingBean loginFormBean = (LoginFormBackingBean) FacesUtils
.getBackingBean("loginFormBean");
// simple token holder
Authentication authenticationRequestToken = createAuthenticationToken(loginFormBean);
// authentication action
try {
Authentication authenticationResponseToken = authenticationManager
.authenticate(authenticationRequestToken);
Authentication authCopy = null;
final Object principal = authenticationResponseToken.getPrincipal();
if (principal instanceof LdapUserDetailsImpl) {
LdapUserDetailsImpl userImpl = (LdapUserDetailsImpl) principal;
userImpl.getUsername();
// here check if we already have a User with his DN in the DB
// get the User by DN
User u = userService.getUserByDn(userImpl.getDn());
// if a user with this DN does not exist in the DB, create a new
// one with the DN from LDAP and the default settings for a new
// user
if (null == u) {
u = userService.createNewUserFromDn(userImpl.getDn(),
userImpl.getUsername());
}
// set the obtained user as the current user
setCurrentUser(u);
List<GrantedAuthority> grAuth = new ArrayList<GrantedAuthority>();
// after this, do the role authority stuff
// here loop through user roles if he has more and
if (null != u.getUserTeamRoles()) {
for (UserTeamRole urt : u.getUserTeamRoles()) {
// here get role for every UserTeamRole
grAuth.add(new SimpleGrantedAuthority(urt.getRole()
.getName()));
}
}
// add the above found roles to the granted authorities of the
// current authentication
authCopy = new UsernamePasswordAuthenticationToken(
authenticationResponseToken.getPrincipal(),
authenticationResponseToken.getCredentials(), grAuth);
}
SecurityContextHolder.getContext().setAuthentication(authCopy);
// ok, test if authenticated, if yes reroute
if (authenticationResponseToken.isAuthenticated()) {
// lookup authentication success url, or find redirect parameter
// from login bean
return "index.xhtml?faces-redirect=true";
}
} catch (BadCredentialsException badCredentialsException) {
// FacesMessage facesMessage = new FacesMessage(
// "Login Failed: please check your username/password and try again.");
// FacesContext.getCurrentInstance().addMessage(null, facesMessage);
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Sample error message",
"Login Failed! Please check your credentials"));
} catch (LockedException lockedException) {
FacesMessage facesMessage = new FacesMessage(
"Account Locked: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} catch (DisabledException disabledException) {
FacesMessage facesMessage = new FacesMessage(
"Account Disabled: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
}
return null;
}
private Authentication createAuthenticationToken(
LoginFormBackingBean loginFormBean) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
loginFormBean.getUserName(), loginFormBean.getPassword());
return usernamePasswordAuthenticationToken;
}
How can I redirect to the page I need? I have a loginBean which contains the user and password and I could add a redirectUrl but how do I find the previous url path?
Spring Security implements this logic for you in the AbstractAuthenticationProcessingFilter (typically using the concrete implementation of UsernamePasswordAuthenticationFilter) by using the SavedRequestAwareAuthenticationSuccessHandler (which uses the HttpSessionRequestCache under the covers). Since you have written a controller to authenticate (rather than using the built in support) you will need to implement this logic yourself. Rather than implementing all of the logic yourself, you can reuse the same classes Spring Security does.
For example, your LoginController might be updated as follows:
public class LoginController implements Serializable {
// ... same as before ...
private RequestCache requestCache = new HttpSessionRequestCache();
public String loginUsingSpringAuthenticationManager() {
// ... just as you had been doing ...
if (authenticationResponseToken.isAuthenticated()) {
HttpServletRequest request = (HttpServletRequest)
FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpServletResponse response = (HttpServletResponse)
FacesContext.getCurrentInstance().getExternalContext().getResponse();
SavedRequest savedRequest = requestCache.getRequest(request, response);
return savedRequest.getRedirectUrl();
}
// ... same as you had ...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With