JSF 2 + Primefaces 5 + Spring Security How to do an AJAX login - ajax

I have the following configuration in Spring Security:
http.requestMatchers().antMatchers("/admin/**", "/login", "/logout").and()
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.and().formLogin().loginPage("/main.xhtml")
.loginProcessingUrl("/login").defaultSuccessUrl("/admin.xhtml").and()
.exceptionHandling().accessDeniedPage("/denied.xhtml");
In a login controller (JSF backing bean) I have:
public void doLogin() throws ServletException, IOException {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest)context.getRequest()).getRequestDispatcher("/login");
dispatcher.forward((ServletRequest)context.getRequest(), (ServletResponse)context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
}
I am using Primefaces for frontend components.
This is the login form:
<h:form id="form" prependId="false">
<p:messages id="errorMessages" showDetail="false" autoUpdate="true" />
<p:outputLabel for="username" value="Username" />
<p:inputText id="username" required="true" label="username" />
<p:outputLabel for="password" value="Password" />
<p:inputText id="password" required="true" label="password" />
<p:commandButton id="login" value="Login" update="errorMessages"
action="#{loginController.doLogin}" />
</h:form>
The problem is that the previous configuration forwards completely the response from Spring Security when trying to log in, so the login doesn't work. For it to work I would need to add ajax="false" in the p:commandButton but this would cause the whole page to reload in case of a login failure. Reloading the whole page breaks the user experience, for example, in my case users would need to scroll down to the login form if there's a login error.
How can I configure in either JSF or Spring Security so that I can do an AJAX login? Also, in this process, how could I show authentication failure messages from Spring Security?

Related

Safari Autopassword is Blank String

I have a site with a login form that looks like this.
<h:panelGrid columns="3">
<p:outputLabel value="Username:" for="username"/>
<p:inputText id="username" autocomplete="off" />
<p:message for="username"/>
<p:outputLabel value="Password:" for="password"/>
<p:password id="password" />
<p:message for="password"/>
</h:panelGrid>
We are using Spring security to validate passwords, and when I throw a break point in Spring's UsernamePasswordAuthenticationFilter, the password is always blank when using Safari's autofill password feature. This causes the login to fail.
For reference, here is the portion of Spring's code that my break point is located in
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
//My breakpoint is here, but password = "" even though we have a user name
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
I'm at a total loss as to what I can check to solve this. This password issue only affects Safari. Other browsers such as IE, Chrome, FF work just fine.
Ok. I found the problem!
<p:defaultCommand target="ndaLoginButton" />
<h:panelGroup styleClass="errorText centered" rendered="#{authenticationBean.failedLogin}">
<h:outputText rendered="#{authenticationBean.isFailedLogin() and not authenticationBean.lockedAccount}"
value="Invalid username or password. Please try again." />
<h:outputText rendered="#{authenticationBean.lockedAccount}"
value="Account locked. You can reset account password below." />
</h:panelGroup>
#{authenticationBean.setFailedLogin(false)}
<h:form id="loginDialogForm" prependId="false">
<h:panelGrid columns="2" styleClass="ndaLoginDialogTable" columnClasses="ndaLoginDialogTop, ndaLoginDialogTop">
<h:panelGroup>
<h:panelGrid columns="3">
<p:outputLabel value="Username:" for="username"/>
<p:inputText id="username" autocomplete="off" />
<p:message for="username"/>
<p:outputLabel value="Password:" for="password"/>
<p:password id="password" autocomplete="off" />
<p:message for="password"/>
</h:panelGrid>
<input type="submit" style="visibility: hidden;" onclick="$j('#ndaLoginButton').click();"/>
<input type="hidden" id="loginDialogSubmit" name="loginDialogSubmit" value="loginDialogSubmit" />
<input type="hidden" id="loginDialogRedirect" name="loginDialogRedirect" />
</h:panelGroup>
<h:panelGroup>
<p:commandButton id="ndaLoginButton" value="NDA Login" type="submit" action="#{loginDialogPageBean.login}"
ajax="false" onclick="ndar.showPreloader()"/>
</h:panelGroup>
</h:panelGrid>
</h:form>
The problem is the <p:defaultCommand> tag. This tag is used to specify which control gets pressed when the user hits the enter key on the keyboard. What was happing was that Safari was sending a virtual enter key press prior to populating the password field on the form. I solved the problem by simply removing this <p:defaultCommand> tag since it wasn't necessary anyway.

How to get the response from a bean in jsf ajax call using f:ajax

Hi i am working on jsf f:ajax i it worked for me when i have done the validations with in the page using ajax. but now i wanted to get the response from a Managed bean method that is called on as a ajax listener.
I m not able to get the response back in any of the format.any body please help me.
Here is the code
register.xhtml
<h:outputText value="Full Name:" escape="false" />
<h:inputText value="#{display.user}" required="true" label="User ID"
id="username">
<f:validateRegex pattern="[A-Za-z]*[\.][A-Za-z]*"></f:validateRegex>
<!-- <f:validator validatorId="com.jason.jsf.custom.Myvalidator"></f:validator> -->
<f:ajax render="usernameMessage outputMessage" event="blur" />
</h:inputText>
<h:message id="usernameMessage" for="username" style="color:red;" />
<h:outputText value="Email:" escape="false" />
<h:inputText value="#{display.email}" required="true" id="EmailID"
label="Email ID"
validatorMessage="#{display.email} is not valid email">
<f:validateRegex
pattern="[\w\.-]*[a-zA-Z0-9_]#[\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]" />
<f:ajax render="EmailIDmsg" event="blur"
listener="#{display.getMessage}" onevent="fun" />
</h:inputText>
<h:message id="EmailIDmsg" for="EmailID" />
script.js
function fun(e){
var xmlDoc,x,txt,i;
alert("text"+e.responseText);
alert("XML"+e.responseXML);
}
Method in Display.java a managed bean with name display contians a field email with all the setters and getters
public String getMessage(AjaxBehaviorEvent e) throws InterruptedException {
System.out.println("hai this is listener method");
System.out.println(e.getComponent().getId());
System.out.println(email);
return email;
}
I using JSF 2.0 Mojarra 2.0.3

is Spring Security custom login method cancels redirec?

So basiclly redirect to /index.xhtml doesn't work after login. I can't figure out how to fix it but I think what is the problem with my code, if someone could help I'd be glad.
I have login() method, which in my opinion lacks something:
public String login() {
try {
Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (BadCredentialsException badCredentialsException) {
//handle exception
} catch (DisabledException disabledException) {
//handle exception
}
return "loggedin";
}
Also in my securityContext:
<sec:http auto-config="true" use-expressions="true" request-matcher="regex" create-session="always">
<access-denied-handler error-page="/?accessDenied=true"/>
<form-login login-page="/login.xhtml" default-target-url="/index.xhtml" always-use-default-target="true"/>
<logout invalidate-session="true" delete-cookies="true" logout-success-url="/"/>
</sec:http>
Am I right that redirect doesn't work is because I have custom login method that doesn't use the .xml settings?
How can I fix that?
EDIT:
<h:form prependId="false">
<h:panelGroup id="loginRender" layout="block">
<h:panelGroup layout="block">
<h:inputText id="j_username" required="true" value="#{loginBean.username}"></h:inputText>
<h:outputText value="LOGIN"></h:outputText>
<h:inputSecret id="j_password" required="true" value="#{loginBean.password}"></h:inputSecret>
<h:outputText value="PASSWORD"></h:outputText>
<h:commandButton id="login_button" value="LOG IN" action="#{loginBean.login}"> <!-- Login button, with login() action -->
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
When using spring security's form login you're not supposed to handle the login yourself.
Spring's form login handler will handle the login operation for you. The login handler is pretty configurable and will most likely serve your needs.
<security:http>
<security:form-login login-page="/login.xhtml" login-processing-url="/login"
password-parameter="username" username-parameter="password"
default-target-url="/index.xhtml" authentication-failure-url="/login.xhtml?error"/>
</security:http>
The login-page attribute tells spring what the login page of your application is. It will redirect unauthenticated users to this page when they access a secured page. The login-processing-url attribute specifies the url to which the login form will POST the login credentials. The username-parameterand password-parameter attributes tell spring which parameters the contain the username and password. After a successful login spring will redirect the user to the default-target-url page. After a failed login attempt the user will be redirected to the authentication-failure-url.
It's not necessary configure all this if you're happy with the default values of these attributes. All this and more is pretty well explained in the documentation so you really should take at look at it.
UPDATE
The login form on your index.xhtml page should look like this given the example form-login configuration above. The action of your form must match the value of the login-processing-url. Spring security will handle login request when the form is submitted.
<form name='loginForm' action="/login" method='POST'>
<input type='text' name='username' placeholder="username">
<input type='text' name='password' placeholder="password">
</form>

Passing <p:inputText> values to Bean using ajax

I am having the h:inputText which having a text and by ajax request how can i send it's values to bean class and the values will be validated in further action begin at bean class ..
view page code is
<h:form>
<p:panel id="panel" header="Login Panel" style="margin:0 auto;width:350px;margin-top:15%;">
<p:panelGrid columns="3" id="pgrid1" styleClass="theme" >
<p:outputLabel value="User Name:" />
<p:inputText id="name" value="#{loginBean.name}" required="true" requiredMessage="Name is required">
<f:ajax event="blur" render="label" listener="loginBean.validateName" ></f:ajax>
<!--Here the ajax event working properly but how can i get the inputText value when ajax event is invoked-->
</p:inputText>
<p:message for="name" style="color: red;" />
</p:panelGrid>
<p:commandButton type="Submit" value="Submit" action="#{loginBean.validate}" update="pgrid1" />
</p:panel>
My Bean class Code is :
public void validateName(AjaxBehaviorEvent e)
{
//Here i need inputText value..how can i handle this task..!!
}
JSF has already set the #{loginBean.name} value at that moment. Just access it directly.
public void validateName(AjaxBehaviorEvent e)
{
System.out.println(name); // Look, JSF has already set it.
// ...
}
You've by the way an EL syntax error in <f:ajax listener> which causes the listener method never to be invoked, but I'll bet it to be just carelessness during preparing the question as you mentioned that it is "working properly". In the future questions, please edit code in the real development environment and copypaste real working code instead of blindly editing the code in the question editor.

How to use Spring security with Primefaces

I have found so many examples but the problem is all of them are using JSP/JSF as view. The problem is they always use j_username as username input id and j_password as password id. What I found is these names are standard names. Primefaces doesn't allow me to give name to p:inputtext component. Do you have any solution?
Here is an example : http://krams915.blogspot.com/2012/01/spring-security-31-implement_13.html
j_username and j_password are only default values in Spring Security. You can customize these names as you expected. To do this, you set values for password-parameter and username-parameter as below:
<security:form-login login-page="/login.html"
default-target-url="/welcome.html"
always-use-default-target="true"
authentication-failure-url="/login.html?error"
password-parameter="your_value"
username-parameter="your_value"/>
I'm using Spring Security 3.1. With another version, the configuration is possibly something like above.
Try to use a normal HTML form pointing to the URL of login controller instead of a Primefaces tags:
<form name='f' action="/j_spring_security_check" method='POST'>
<input type='text' name='j_username' value=''>
<input type='password' name='j_password' />
<input name="submit" type="submit" value="submit" />
</form>
You can post directly to j_spring_security_check, but sometimes it might come handy to do it programmatically to combine both worlds.
<p:commandButton value="Login" action="#{loginController.login}" ajax="false">
<h:inputText id="j_username" required="true" />
<h:inputSecret id="j_password" required="true" />
with h xmlns:h="http://java.sun.com/jsf/html"
in your loginController:
ExternalContext context = FacesContext.getCurrentInstance()
.getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher("/j_spring_security_check");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());

Resources