Verifying additional parameter with j-security-check - jsf

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

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

PrimeFaces push to OmniFaces push migration questions

Since PrimeFaces push is going to be discontinued, I started to migrate to OmniFaces push. For notification purposes it's all working as expected, but I have a chat on my application where I'm missing two things in OmniFaces:
1) Change the user of the socket on demand. I require this for private conversations. On PrimeFaces I create a channel for each conversation based on the logged users id, and I pass it to the connect method of their socket component. With OmniFaces I tried to place the socket component inside a PrimeFaces output panel, bind the user property to a view scoped bean, update the panel on a ajax request and on the oncomplete event call OmniFaces.Push.open('channelName'), but I can see on the SocketObserver class(from the showcase) that the user has not been updated. As a workaround I created the channel using the logged user id as user, and if someone different from the person that he is talking at the moment sends a message, I ignore it at the JavaScript callback instead of appending it.
2) When I don't specify the user on PushContext.send, I'd like that the message was sent to everyone connected on the channel, similar to "/channel/*" on PrimeFaces. My requirement with this is to update the list off online/offline users off this chat application. A a workaround I could create a separate channel for these notifications, but as the application don't require this to work, I preferred to check here first.
I'll add code if necessary, but first I'd like to check if these concepts are present in OmniFaces push.
Thanks
It was indeed not possible to change the <o:socket user="#{...}"> value while staying in the same JSF view (ajax updates, etc). As per issue 472, it has been improved in OmniFaces 3.2-SNAPSHOT.
Any dynamic change in value of <o:socket user="#{...}"> during any ajax request in the same JSF view will now be reflected in push behavior.
In other words, below construct will now be possible:
<h:form>
<h:selectOneMenu value="#{bean.chat}">
<f:selectItems value="#{bean.chats}" />
<f:ajax render="#form" />
<h:selectOneMenu>
...
<o:socket channel="chat" user="#{bean.chat.id}" />
</h:form>
If you start by using the user attribute on the o:socket like in the example
<o:socket channel="sess" scope="session" user="#{pushTestUser}" />
1) seems possible by using the 'user id' as can be seen in the showcase push test page
From http://showcase.omnifaces.org/push/socket:
#Inject #Push
private PushContext someChannel;
public void sendMessage(Object message, User recipientUser) {
Long recipientUserId = recipientUser.getId();
someChannel.send(message, recipientUserId);
}
In this example the pass the User which is an 'example' object that could be your own or whatever. In the showcase the user is passed on by binding the id to an input field, but that could be done server-side as well. Up to you
2) seems possible with sending messages to the generic channel or even groups as can be seen in http://showcase.omnifaces.org/push/socket.
#Inject #Push
private PushContext someChannel;
public void sendMessage(Object message, Group recipientGroup) {
Collection<Long> recipientUserIds = recipientGroup.getUserIds();
someChannel.send(message, recipientUserIds);
}
The group here is an example Object that could be your own, it could be passed from the 'frontend' or just read in the backend somewhere. It just needs to contain id's of users (can be mapped guids, does not need to be internal user id's) that are subscribed to the channel. All are just example methods.
So both seem possible in my opinion.

JSF / primefaces Session - Session gets lost

I´m new at JSF programming and got a problem with my login/session which gets lost after the login.
I want to implement an easy login where a user can type in username and password. So I wrote a LoginController:
#ManagedBean
#SessionScoped
public class LoginController extends AbstractController{
#PostConstruct
public void initialiseSession() {
FacesContext.getCurrentInstance().getExternalContext().getSession(true);
}
private String username = "null";
private String password;
private boolean loggedIn = false;
#Inject
private EmployeeService employeeService;
public static final String employeeSessionKey = "user";
public LoginController() {
}
public String login() {
//check username and password and if true redirect to "/"
}
My login.xhtml looks like:
<h:form id="loginForm">
<h:outputLabel style="font-size:24px" value="Bitte melden Sie sich an!"/>
<p:panelGrid columns="2">
<p:outputLabel id="userOutput" for="userInput" value="Benutzername"/>
<p:inputText id="userInput" value="#{loginController.username}"></p:inputText>
<p:outputLabel id="passwordOutput" for="passwordInput" value="Passwort"/>
<p:inputText id="passwordInput" type="password" value="#{loginController.password}"></p:inputText>
<h:outputText value="Logindaten merken?" id="outputRememberLogin">
<p:selectBooleanCheckbox id="loginCheckbox">
</p:selectBooleanCheckbox>
<p:spacer width="10" id="loginFormLittleSpacer"></p:spacer>
</h:outputText>
<p:commandButton id="loginButton" value="Anmelden" action="#{loginController.login()}" ajax="false" >
</p:commandButton>
</p:panelGrid>
</h:form>
So when I login the redirect works. But when I go to another .xhtml page the session gets lost.
To test this, I put
<p:outputLabel value="#{loginController.username}"/>
on my pages. After the login, the username becomes "null".
I´m going crazy on this problem.
Any ideas?
thanks before.
Your LoginController bean looks like its annotations are okay and the code looks like it should work. However, there's a couple other things that you may want to check. Some of this may be obvious but your question is missing a few details so I’m not sure what level of experience you may have and where to start in this answer. Therefore, I’m starting from the beginning (almost)…
1. Domain Name Configuration
To use sessions, you must use a qualified domain name. Sending a request to an IP address will not allow sessions to work since client browsers only send session information to a fully qualified domain name (http://example.com/). If you’re calling your web app with an IP (such as ‘http://127.0.0.1:8080/MyApp’), the session data will never be sent to your web app and you will have a new session created with each request. Make sure you’re using a fully qualified domain name and path with each request to your application, for example ‘http://localhost:8080/MyApp’.
2. Application Configuration
Check that your web application’s <session-config> configuration is setup correctly. The default config should allow your code to work without having to add anything specific, so if you didn’t add anything, don’t worry about this. However, you may want to make sure there’s nothing that may be preventing the sessions from being reused.
Session cookies should be enabled (<tracking-mode>COOKIE</tracking-mode>)
Timeout should be long enough to not expire before the second request (<session-timeout>60</session-timeout>)
The cookie path should be correctly set for your use (<path>/</path>)
The following is a common session config that I use…
<session-config>
<session-timeout>60</session-timeout>
<tracking-mode>COOKIE</tracking-mode>
<cookie-config>
<path>/</path>
<http-only>true</http-only>
<secure>false</secure>
</cookie-config>
</session-config>
3. Session Cookie Tracking on the Client
If the above points don’t resolve the issue, you can really start diving into the session tracking by monitoring the request and response traffic between your app and the client browser. The session info is passed back and forth by a cookie (or query string parameter if cookies are disabled) named ‘JSESSIONID’. Its value will be the ID of the unique session and must be the same for each request to ensure that your web application tracks the same session. The below highlights some of the things to look for…
Make sure the ‘JSESSIONID’ session cookie is sent to the client browser correctly and is being sent back with each subsequent request. You can do this with Chrome or Safari's web developer tools (under the 'Network' tab) or with a separate utility, such as Wireshark.
Make sure the 'JSESSIONID' cookie exists in the response from the first request… this will let you know that your web app is at least creating the session and response cookie.
Make sure the second request from the client browser is passing the 'JSESSIONID' cookie back... this is the only way your web app knows which existing session to use.
Make sure the 'JESSIONID' cookie has a path of '/' (which may display as 'N/A' in the browser) or the path of your web app ('/MyApp', for example)… the client browser will only send cookies to the domain(s) and path associated with each. For example, if your login page is 'http://example.com/MyApp/login', the 'JSESSIONID' cookie may have a path of '/MyApp' (by default), which will not be returned if the following request is made to 'http://example.com/' (without the '/MyApp' path). The default path is the name of your web app (‘/MyApp’) and can be changed using the <path> config item indicated above.
4. Session Management within the Bean (Additional Information)
In your initialiseSession() method, the session object returned by FacesContext.getCurrentInstance().getExternalContext().getSession(true); isn't being saved and this line is essentially doing nothing. The #SessionScoped annotation will have already created a session and added the ‘JSESSIONID’ cookie to the response before initialiseSession() is called. Therefore, the only reason to call getSession(true) is if you want to save the session to a private object within the bean, which would be like this...
#ManagedBean
#SessionScoped
public class LoginController extends AbstractController{
// Create a global, private member for storing the session data...
private HttpSession session;
#PostConstruct
public void initialiseSession() {
// Assign the session to the global member…
session = FacesContext.getCurrentInstance().getExternalContext().getSession(true);
}
…
Again, the call to the getSession(true) isn’t necessary in your example since the SessionScoped bean will have already created the session. The above code is only necessary if you intended to update or use the session object, for example add an attribute or modify a setting.
In summary
Double-check the above points 1 – 3. My assumption would be that the ‘JSESSIONID’ cookie isn’t being sent back in subsequent requests. If you can confirm that the ‘JSESSIONID’ cookie (with the same value) is being included in each request then the problem isn't related to the session and may be related to the code in your login() method.
i used cookies for repair this kind of problems, in my application. inside Faceutils doesn't work before servlet.

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.

Resources