Question

I am learning Struts 2 now and trying to make a login attempt counter to block any further login attempts after x failed attempts.

Here is the body of my login.jsp

<body>

<h1><s:property value="loginAttempts"/></h1>

<s:form action="login">
    <s:textfield name="username" label="Username" />
    <s:password name="password" label="Password"/>
<%-- <s:hidden name="loginAttempts"  value="<s:property value="loginAttempts"/>" /> --%>
    <s:set var="loginAttempts"><s:property value="loginAttempts"/></s:set>
    <s:submit value="login"/>
</s:form>

</body>

And my Action class (I am not including the private var w/their getters and setters but they are all there)

public String execute() throws Exception{

    if (username.equals("admin")&& password.equals("admin"))
    {   return SUCCESS;}
    else if (Integer.parseInt(getLoginAttempts())>2)
    {
        return "lockout";
    }
    else
    {   setLoginAttempts(String.valueOf(Integer.parseInt(getLoginAttempts())+1));
        return "fail";}
}

In the action that initially calls the login.jsp I pass in an intitial value

loginAttempts="0";

and that works fine. The problem comes when i hit submit on the login.jsp page.

I get the following stack trace

java.lang.NumberFormatException: null 
java.lang.Integer.parseInt(Integer.java:417)
java.lang.Integer.parseInt(Integer.java:499)
com.struts.users.LoginAction.execute(LoginAction.java:17)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Line 17 is

else if (Integer.parseInt(getLoginAttempts())>2)

And every time i hit the submit button the loginAttempt variable it resets itself to NULL.

Thanks

Edit: I understand that this probably isn't the right way to be doing this and i should probably be doing this with sessions. However I am trying to understand why it isn't working.

Was it helpful?

Solution

A struts2 action is not persistent! It is recreated each and every time the request happens.
What you need to do is implement the ServletRequestAware interface for the action which will give you access to the HttpServletRequest, you can then obtian the http session object stored by your webserver and increment the value on that. Be careful as this will need to be threadsafe - you may need to lock the http session while updaing the value.
Another approach would be to have an object in the ServletContext that stored a Map of username to login attempts. This may be more reliable.

A bit of clarification from comments:

Your form sends (known as POSTing) the values on it to your webserver, struts2 then takes this 'POST data' and interprets it for you - using the relevant setters on your action to make this data available to you.
So, in order to send the login attempts value your form needs to have it as a variable, hence the need for an <s:hidden>. Your action should then have a setter for loginattempts; i.e. a method with the signature setLoginAttempts(int loginAttempts).
Now, when your action is done and finds that the request is invalid you want to increment that variable and provide a getter for it in the action.
Now your JSP, which is rendered by the action on a failed attempt, can read that value off the action and add it to the HTML form that the user will send. Hence my reference to a circle.
This method will not do anything to add to the security of your website as the variable loginAttempts is read from the user POST data - the user can send anything it wants and your action will read that as the number of login attempts.
I hope that helps...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top