Spring Security and JSF redirect after login not working - jsf

I am trying to integrate Spring Security with my JSF application.
I am able to get to make the login page show up, but after a successful login, the protected URL does not show up, it stays on the login page.
My applicationContext.xml:
<security:http auto-config="true" access-denied-page="/login/loginerror.jspx">
<security:intercept-url pattern="/restricted/**" access="ROLE_SU"/>
<security:form-login login-page="/login/login.jspx"
default-target-url="/restricted/equipment.jspx"/>
<security:logout logout-success-url="/logoutSuccess.jspx"/>
</security:http>
<security:authentication-provider user-service-ref="userDetailsService"/>
<bean id="userDetailsService" class="com.teach.security.UserDetailsServiceImpl">
<property name="rolesDao" ref="RolesDAO"/>
</bean>
My JSF managed bean, the method that get called when the user hits submit on the login page:
public void login()
{
FacesContext.getCurrentInstance().getExternalContext().redirect("/spring-authentication/j_spring_security_check?j_username=" + userId + "&j_password=" + password);
}
My Java console confirms a successful login, it says "login successful"

Just to be sure, you are not using an AJAX submit but a standard HTML form submit, is that right?

Are you sure the login is sucessful?
The line should be:
FacesContext.getCurrentInstance().getExternalContext().redirect("/j_spring_security_check?j_username=" + userId + "&j_password=" + password);

Related

simple jsf commandbutton work on every single page except home page

A Java EE 8/SE 8 web application in deployement runnnig on Glassfish 5 build 25 both production and development, uses jsf 2.3. users create accounts and login. there is a 'logout' button for loging out.
Problem: 'logout' button works as expected everywhere on the website. EXCEPT home page (example.com) & (example.com/home.xhtml). the problem does not exists on my local computer. only in production (example.com).
So I have a template called : index.xhtml . all pages use it, including home.xhtml:
<ui:composition template="index.xhtml">
<ui:define name="top-bar">
<c:if test="#{request.remoteUser ne null}">
<h:form ><h:commandButton value="Log out" action="#{registerAdvanced.logout}"/></h:form>
</c:if>
</ui:define>
and
#Named
#RequestScoped
public class RegisterAdvanced extends BaseBacking implements Serializable {
public String logout() {
try {
getRequest().logout();
getContext().getExternalContext().getSessionMap().remove("user");
return REDIRECT_PAGE;
} catch (ServletException ex) {
return REDIRECT_PAGE;
}
}
}
Users login & logout fairly easily until I noticied that clicking on logout on the home page (home.xhtml) prints a null pointer exception AND redirect to 404 error page.
[[/home.xhtml #450,77 value="#{passesTestBean.displayPassSummaryList}": java.lang.NullPointerException
javax.el.ELException: /home.xhtml #450,77 value="#{passesTestBean.displayPassSummaryList}": java.lang.NullPointerException
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:119)
at com.sun.faces.facelets.component.UIRepeat.getValue(UIRepeat.java:314)
at com.sun.faces.facelets.component.UIRepeat.getDataModel(UIRepeat.java:256)
at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:507)
at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:557)
at com.sun.faces.facelets.component.UIRepeat.processDecodes(UIRepeat.java:861)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1258)....
part of jsf where there is a call to value="#{passesTestBean.displayPassSummaryList}" is 100% seperate to logout and PassesTestBean CDI is request scope.
so the problem is SOMEHOW when I click on logout button. PassesTestBean is called for no reason and not since jsf must Initialize (since Request Scoped). it ends up returning null.
Now remember this only happens in: production at example.com AND only home page of all pages.
I'm thinking of writing a page only for loging out: has a log out button only.
Check for null pointer exception
getRequest().logout(); //here
getContext().getExternalContext().getSessionMap().remove("user");//here

Verifying additional parameter with j-security-check

I have implemented web application login using j-security-check which accepts parameters j_username and j_password for authentication with background registry. Now, I need to add date of birth as one more parameter and need to authenticate the user with this parameter too.
Is there a way to extend j-security-check to accept additional parameters?
I would like to avoid performing the check in a servlet filter, if possible.
Using WebSphere V8, MyFaces JSF 2.0, Servlet 3.0, Custom database based authentication
The easiest way would be to append the date of birth to the actual j_username (ie. with JavaScript and then manually split it in the login module.
Replace j_security_check by programmatic login via HttpServletRequest#login().
E.g.
<h:form>
<h:inputText value="#{bean.username}" />
<h:inputSecret value="#{bean.password}" />
<h:inputText value="#{bean.birthdate}" />
<h:commandButton value="Login" action="#{bean.login}" />
</h:form>
with
public void login() {
// Do your thing with birthdate here.
// ...
// Then perform programmatic login.
try {
request.login(username, password);
// Login success. Redirect to landing page.
} catch (ServletException e) {
// Login fail. Return to login page.
}
}
This is in detail outlined in 2nd part of this answer: Performing user authentication in Java EE / JSF using j_security_check

JSF / Java EE form vs programmatic authentication

I have been experimenting with the substance of this question (JSF / Java EE login without requiring a protected resource).
If I set up a sample application using BASIC authentication, with one public page (/public.xhtml), and one protected page (/protected/private.xhtml), and I have a link from the first page to the second (as shown below), everything works perfectly.
<h:commandButton value="Go Private" action="/protected/private?faces-redirect=true" />
However, if I remove the login-config and replace the above button with:
<h:commandButton value="Go Private" action="#{mybean.login}" />
...and #{mybean.login} looks something like this...
public String login() {
HttpServletRequest request = ...
try {
request.login("known username", "known password");
} catch (Exception e) {
// handle unknown credentials
}
return "/protected/private?faces-redirect=true";
}
In this case, the login succeeds (no exception from request.login()), but the browser shows a "forbidden resource" page.
Can anyone shed any light on the difference between the two scenarios?
The HttpServletRequest#login() programmatic login works only with FORM based authentication configuration. Removing the <login-config> would make it to default to BASIC and thus the login() will never work. The login() basically sets the user in the session, however the BASIC authentication basically checks the Authenticate HTTP request header, not the session.
Put that <login-config> back and set it to FORM if you want to utilize login().
Where it is:
<h:commandButton value="Go Private" action="#{mybean.login}" />
it should be:
<h:commandButton value="Go Private" action="#{mybean.login()}" />
if you want to use the login methode.
But maybe your mybean also has
String private login;
public String getLogin(){ return this.login ;}
and you've loaded the var with the desired response.

jsf spring security user info

I'm new at Spring Security. I'm using jsf2 with spring security 3. Three questions:
How can I access, from a session managed bean, the user info (name,password,roles) of the user currently logged in?
In order to use it in a view, for example for rendering elements depending on the roles of the user.
How can I know if a user is logged in? In order to show in a view a "login link" if the user is not logged in, or a "logout link" if the user is logged in. Which property of Spring Security do I have to use in my managed bean to store this info and use it in the view?
The "login link" is just a GET request to the URL of the login page. But how can I show "logout link"? Do it have to be a POST request and use "h:commandLink" like this?:
<h:commandLink value="Logout" action="#{request.contextPath}/j_spring_security_logout" />
Or can it be a GET request?:
<h:link value="Logout" outcome="#{request.contextPath}/j_spring_security_logout" />
Thank you very much in advanced.
The object authentication is who save this properties, you can obtain with next line in your managedBean:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
A user is logged if his Authentication is not a instace of AnonymousAuthenticationToken, in your spring-security-context.xml you must define the urls intercepted by Spring.
The first interceptor is not analyzed by Spring. In this case the Authentication object is an instance of AnonymousAuthenticationToken.
The second interceptor is analyzed by Spring and the user is redirected to login page declared in spring-security-context.xml
/* This is a example for to obtain the rol name for example for generate automatic menu */
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String namePrincipalRol = null;
if (auth instanceof AnonymousAuthenticationToken) {
namePrincipalRol = "ROLE_ANONYMOUS";
} else {
namePrincipalRol = auth.getAuthorities().iterator().next().getAuthority();
}
Good question, I am not sure but I think I remember having read that it must be POST, would be interesting to try. I use h:outputLink
Kind regards.

jsf navigation question

I have a JSF2 project with a "view user" page that reads the currently selected user from a session bean; userHandler.selectedUser.
The page is intended to be visited by navigating with links in the app.
However, if the user attempts to hit the "view user" page directly by this URL ...
http://localhost:8080/webapp/userView.jsf
... they see the page with no data on it (because there's no selected user in the userHandler).
I think what I'd like to do is redirect the user to the main page of the app if they try to hit it directly like that. What is a simple and elegant way of handling this problem?
Thanks,
Rob
You'd like to hook on the preRenderView event and then send a redirect when this is the case.
<f:metadata>
<f:event type="preRenderView" listener="#{bean.preRenderView}" />
</f:metadata>
with
public void preRenderView() throws IOException {
if (userHandler.getSelectedUser() == null) {
FacesContext.getCurrentInstance().getExternalContext().redirect("home.jsf");
}
}
A way to avoid this problem from the start is to have pages that you don't want to be accessed directly via URL into the WEB-INF folder of your project.
This way, your pages aren't accessible directly via URL.

Resources