I have a login.jsp page in my application. I am using Struts 2 and a simple validate() method to validate my form. I have two questions:
validate() method in my form bean class validates the form. I.e checks for empty fields etc. If I need to check my username and password combination should I do this inside validate() or in my action class?
If I am doing the same in my Action class, correct combination leads to success page. I want the incorrect combination to lead to my JSP page along with the error message: "Incorrect combination". How can I check in my JSP page that the request has come from action class so that it can print the error message "Incorrect combination"?
Authentication belongs in the action, not in validation, IMO.
I might consider using XML or annotation validations for the fields themselves and put the login attempt in validate(), but the code is small, and I'd be pretty comfortable with it either way.
public String execute() {
if (userService.loginValid(username, password) {
return SUCCESS;
}
addActionError(getText("login.failure"));
return FAILURE;
}
I would use the framework's support for action-level error messages rather than using a flag (and I wouldn't duplicate that flag with a local if I did), and I strongly recommend using something you can inject to do the actual logging in to make testing easier.
Using the validate() approach makes things pretty tight:
public void validate() {
if (!userService.loginValid(username, password)) {
addActionError(getText("login.failure"));
}
}
Assuming you define reasonable "input" and "success" results that might be all you need. If developers looking at the code are familiar with the framework the validate() version is relatively clear.
If you're not interested in using XML or annotation validations, you can do that manually as well. That definitely belongs in validate(), and for common utility methods like this, static imports make the code still relatively concise:
public void validate() {
boolean tryLogin = true;
if (isBlank(username)) {
addFieldError("username", getText("login.username.required"));
tryLogin = false;
}
if (isBlank(password)) {
addFieldError("password", getText("login.password.required"));
tryLogin = false;
}
if (tryLogin && !userService.loginValid(username, password)) {
addActionError(getText("login.failure"));
}
}
(I added the tryLogin flag to avoid seeing the error message for a login that will obviously fail, although this could be handled in other ways as well. Post-login processing elided.)
I would say you definitely don't want the login logic in the validate method; that's for validating data.
I would suggest that if your login fails, just expose a data property on the action like:
execute () {
boolean authenticated = login( getUsername(), getPassword() );
setLoginValid( authenticated );
if ( authenticated )
result = SUCCESS;
else
result = FAILURE;
return result;
}
And then in your login.jsp, simply wrap a message about bad credentials in the struts if tag, with a test on the loginValid property.
The purpose of the validation framework is to check field values to be valid to prevent unexpected errors while executing the action.
It is a good practice to separate the validation logic from the business logic. Authentication has nothing to do with validation logic. It is a separate process provided by security mechanisms. Of course you can create the action or interceptor that performs authentication, and as with any action you can configure it for validation.
In Struts2 it's even more simplified by applying a validation interceptor is a part of the job for processing request. In more sophisticated scenarios authentication becomes a part of the business logic, but the method to validate the input fields renames the same. If your action is only do is authenticating then you may not require the validation to process authentication.
To your second question: all you need is to addActionError(getText("error.key")) to invalidate the action. Then return to the result where <s:actionerror> to display the message.
What is more important the validation logic remains the same if you decide to move it to the action. In this case the only thing you have to do is to remove the validation stack. The only reason of such validation is to return the result that is different than "input".
Related
I have my regex patterns stored like:
private final Pattern regex1...
private final Pattern regex2...
As fields in my view. I have a validation check method in the view class which throws an exception to the controller when validation fails. Is this valid in MVC or not?
public void validation() throws Exception{
if(regex failed){
throw new exception("...");
}
...
}
It is always somehow up to you how you splitt the code, if there is a good reason behind your decision.
However, I would prefer to put the validation methode at least into the controller, because it looks like it will be triggered by an actionevent from a button. (Events should be handled in the controller)
What you can do, is to create a methode in your view, which shows an error message in the gui, if your validation has failed.
All this implice that also the regex is saved in the controller.
It is not good practice. Logic has to be moved into dedicated layed.
Best way is creating dedicated validator class OR create validation method of a service (if some operations like search in DB have to be done during the validation). In that way validator class can be well covered by unit tests.
#Autowire
UserInputValidator userInputValidator;
public void validation() throws Exception{
if(userInputValidator.validate(param1, param2)){
throw new exception("...");
}
...
}
While we're talking about MVC, it's always best to consider that as the app evolves, "input" may come from more than one place eventually.
User
service call
file
other
In this case we wouldn't want to build the validation mechanisms into the View or the Controller, but into another component that the Controller would just use/integrate with.
Validation can be a cross cutting concern (but not always)
Ideally we would want to avoid duplicating the validation of incoming data especially if the data is always valid in the same way. Duplicating the validation can cause inconsistencies. Imagine data being invalid from the UI, but the same data being considered "ok" from a service call.
There are a number of ways that you can separate the validation logic from your view:
Annotate beans for JSR-303
Create custom validation annotations (abstracting your defined regex's) and/or use libraries that provide some basic ones
Dedicated service
Resolving validation failures
I can see that you're throwing an exception when you have a validation failure. Consider the awesome article by Martin Fowler. The suggestion is that a validation failure can be expected and is not an Exception case. He also suggests a notification approach.
Another advantage of a notification approach is that your dedicated validation service/tier can support multiple validation failures. This would allow your view to highlight multiple fields or your API to return a list of failures.
I have some interceptors that need to check the headers and the authorization in some requests done to my API. For example, some requests should require user authentication (for example, to alter user details from the database) and some don't require authentication (for example, to create a user). Unfortunately, the methods for excluding paths from the interceptors don't depend on the request method.
Right now I have created an Util class that receives an array of strings of paths and methods that should be excluded from the verifications. For example: "POST /api/users" should not be intercepted by my authentication interceptor because it is for creating a user, but "PUT /api/users" should be intercepted because it is for altering an existing user (who should be logged in).
public static Boolean skipVerification(HttpServletRequest request, String... skipRequests) {
for (String string : skipRequests) {
String[] split = string.split(" ");
if(split[0].equals(request.getMethod()) && split[1].equals(request.getRequestURI()))
return true;
}
return false;
}
In the constructor of my interceptor, I add the requests that should be skipped and in the PreHandle method I return true if the request matches any one of them as they didn't need to me intercepted in the first place.
public AuthenticationHeaderInterceptor(String...skipWhen) {
this.skipWhen = skipWhen;
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if(InterceptorUtils.skipVerification(request, skipWhen))
return true;
///Do Authentication Logic
}
I know that changing the URI for creating and editing users would solve this, but I prefer not to clutter my API with too many URIs and was wondering if there was a cleaner way to solve this.
Looking at the code, I was checking if you would be able to extend InterceptorRegistry, InterceptorRegistration, and MappedInterceptor. You would also have to extend PathMatcher and incorporate code to check methods as well as paths, which PathMatcher isn't meant for. So overall, the way you are doing it currently is probably best. I would also point out the code in Spring's AntPathMatcher has always been very messy and buggy so you probably wouldn't want to take on any task that involved dealing with it.
I'm using Spring-MVC with Spring Security for my web application. It includes user registration pages and private user panel. I have it set up currently with the following URL patterns:
whatever/myapp/login user log in
whatever/myapp/register?step=1 start registration
whatever/myapp/account/** private area views (pages)
whatever/myapp/pending view shown while post-registration processes complete
whatever/myapp/blocked account blocked view
whatever/myapp/register/retry if registration failed, allow retry
Essentially, these URLs below should require user authentication, i.e. require log-in:
whatever/myapp/account/** (private area pages)
whatever/myapp/pending (this page has a timer set to redirect to /account/home)
whatever/myapp/register/retry
This is quite straightforward to achieve using Spring security. However, regardless of user authentication through Spring security, private area pages should be accessible or not, depending on user's current account status (stored in my DB).
More specifically: if a user tries to access anything in the private area (/account/**), he should be shown the appropriate view (redirected to appropriate page), according to the status. I have these statuses defined:
suspended - relates to pending view
enabled - allow full access
disabled - not relevant here
retry_allowed- relates to retry view
blocked - relates to account-blocked view
Currently, I have a MVC interceptor setup to /account/**, that checks user status, and redirects to appropriate pages, but somehow I get the sense that this is not really the ideal or appropriate solution here, since I'm facing strange behavior, like multiple controller invocation... and also I'm not quite certain when to return true / false within preHandle() method. Here's the code snippet from the interceptor:
#Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object arg2)
throws Exception {
IPanelUser pUser = (IPanelUser) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
// check principal first and then load from DB
// "suspended" is initial status upon registration
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {
// if suspended, load from DB and update status
Customer customer = this.customerService.getUserByUsername(pUser.getUsername());
if(customer != null)
pUser.getCustomer().setStatus(customer.getStatus());
// still suspended? redirect to pending
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {
response.sendRedirect("../pending");
return false;
}
}
if(pUser.getCustomer().getStatus() == CustomerStatus.Blocked.getCode()) {
// redirect to blocked page
response.sendRedirect("../blocked");
SecurityContextHolder.clearContext();
return false;
}
if(pUser.getCustomer().getStatus() == CustomerStatus.AllowRetry.getCode()) {
// redirect to CC submission page
response.sendRedirect("../register/retry");
return false;
}
if(pUser.getCustomer().getStatus() == CustomerStatus.Enabled.getCode() ||
pUser.getCustomer().getStatus() == CustomerStatus.Disabled.getCode()) {
// do nothing
}
return true;
}
.
Is this a valid approach ? Any alternative suggestions ?
All options are valid, it depends on the level of abstraction you want.
In a Filter, you only have access to HttpServletRequest and HttpServletResponse objects, so you are very much coupled with the Servlet API. You also don't (directly) have access to all the great Spring functionality like returning a view to be rendered or a ResponseEntity.
In a HandlerInterceptor, it's again more of the same. You can do your redirection or request handling directly in the preHandle() where you don't have access to the ModelAndView or set a flag which you check in postHandle(). You would have access to the ModelAndView but not to some other Spring MVC functionality.
Spring Security is a good alternative, but I find it has a lot of configuration that I don't like too much.
One final alternative, that I like the most, is to use AOP (you can do this with Spring Security or Shiro as well). You create an annotation like #Private and you annotate your #Controller handler methods. You use AOP to advise these methods. The advice basically checks some session or request attribute for a flag (authorized or not). If you are allowed, you continue executing the handler method, if not, you throw an UnauthorizedException (or similar). You then also declare an #ExceptionHandler for that exception where you have pretty much complete control over how the response is generated: a ModelAndView (and related), a ResponseEntity, annotate the handler with #ResponseBody, write the response directly, etc. I feel like you have much more control, if you want it.
Is it possible to perform some actions (some cleanup) if jsf validation errors occur?
Fields are validated with tags in xhtml, for example 'required="true"', 'f:validateRegex pattern="\d*"', 'f:validator validatorId="someValidator"'.
I need to set some property field of managed bean to null (when there are any failures on the page).
But if validation fails, then JSF goes to Render Response Phase and managed bean method is not invoked.
Listener (using f:actionListener tag) also is not invoked in that case.
Now I'm thinking about to replace xhtml validation by validation using bean annotations like #AssertTrue, #Size, etc.
Then in some of this validating methods it would be possible to make a cleanup:
#ManagedBean
class SomeBean {
...
#AssertTrue
public void isClenup() {
cleanup();
}
...
}
But it seems not a good solution to me. Also I noticed that several methods annotated with #AssertTrue are called in undefined order. Therefore switching from xhtml validation to bean annotations validation is getting not so easy.
Is it possible to define some order of calling methods annotated with #AssertTrue?
In fact I have quite ordinary task: there is a page with search functionality.
On search success with no errors the result should be shown, but if validation errors occur (during next search), then previous result should not be shown (but it was visible and that was a problem).
My plan was as follows: to check for validation failures in initialize() method using facesContext.isValidationFailed() and if it is true, then to hide (delete) previous search results:
public void initialize() {
FacesContext context = FacesContext.getCurrentInstance();
boolean validationFailed = context.isValidationFailed();
if(validationFailed) {
clearPreviousSearchResult();
}
}
But then I found out that validation using bean annotations (like #AssertTrue) does not set facesContext.validationFailed();!
I.e. after this
#AssertTrue(message = "Some error message")
public boolean isValidateSomeField() {
return validate(getSomeFieldValue());
}
you get context.isValidationFailed() == false when fails occur (though I expected true)
(xhtml validation or validator or f:validator do set facesContext.validationFailed() as expected)
Therefore it is necessary to set context failed manually:
#AssertTrue(message = "Some error message")
public boolean isValidateSomeField() {
if(!validate(getSomeFieldValue())) {
FacesContext.getCurrentInstance().validationFailed();
return false;
}
return true;
}
But due to How to check in after phase of Validations phase if validation has failed? I realized that the problem can be resolved much more easier! Just to wrap with couple of lines:
<h:panelGroup rendered="#{!facesContext.validationFailed}">
...block not to show if validation errors occur...
</h:panelGroup>
And no need to use annotations bean validation and some initialize() method!
If a validation exception is thrown during the JSF validation phase then none of the submitted form values will be applied to the model. Also none of the invoked events that would otherwise execute during the Invoke Application JSF phase will be called. You do notice however that Render will still occur, and any components that need to be rendered or updated will still do so.
In theory this should be sufficient for rolling back most any user submissions if any of those submissions were invalid, however there are a few edge cases where additional cleanup will need to occur. I urge you however to closely evaluate the design decisions that led you to this need in the first place, as it is possible that perhaps there is a better way to meet your business requirements without having to resort to this.
With that being said, I would perform a Pre Render event that will execute on every postback and check for certain validations and perform necessary business and presentation logic.
<f:event listener="#{managedBean.initialize()}" type="preRenderView" />
Edit: I have looked into Spring 3's #ExceptionHandler annotation and combining this with Option 1 below looks to be a pretty clean solution.
See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-exceptionhandlers
I also found this to be a good read: http://blog.decaresystems.ie/index.php/2006/04/07/difficult-choices-in-handling-exceptions-in-enterprise-java-applications/
I have been developing using the Spring MVC framework for some time now however I am struggling to come up with a 'nice' way to pass errors that are raised in the service layer back to the JSP.
Basically, I don't believe that business logic (beyond "this field is mandatory") should be in the Validators, especially any logic that requires access to the DB. So, what I have been doing is placing further, more complicated validation and business logic in the service layer.
For example, lets say I have a page that allows a user to buy a Book. They click "Purchase" on the JSP and the controller calls the service to make it all happen... Now, what happens if the service sees that they have insufficient funds - how do I get this message back to the JSP so a nice little "Insufficient funds" message can be displayed to the user? I have considered two ways and I'm not sure which is correct...
Option 1: Exceptions
The first way I thought was to raise an exception in the service layer, trap it in the controller and add a message to the BindingResult.
Service:
public void pay(Book book) throws InsufficientFundsException {
// Some logic goes here, which ends up throwing the above exception
}
Controller:
public ModelAndView(#ModelAttribute("book") Book book, BindingResult errors) {
try {
pay(book);
} catch (InsufficientFundsException ex) {
errors.reject("insufficient.funds");
}
return new ModelAndView(blahblahblah);
}
Option 2: Pass BindingResult to Service layer
The second way was to pass the BindingResult object to the service layer and raise further errors against it.
Service:
public void pay(Book book, BindingResult errors) {
// User has insufficient funds, so...
errors.reject("insufficient.funds);
}
I can see problems with both of these ways. Option 1 feels awkward because not only do I have to catch the exception, I then have to add the error to the binding result so it feels like I'm doing the same thing twice. And Option 2 seems to bind the service layer too tightly to the controller.
Finally, I realise there is the SimpleMappingExceptionResolver that could be used in conjunction with Option 1, but I'm not sure how appropriate it is (perhaps I have not seen a proper example?). In the above example, lets just say for argument's sake that I'd like the user returned to the original form with a red error above the form, not redirected to an entirely different page. The SimpleMappingExceptionResolver seems to me to be useful when you want to redirect a user to a standard error page when a certain exception is raised (which is not quite what I want to know how to do).
Java uses exceptions to naturally handle this kind of thing. In the end it generally simplifies your logic and reduces the chance of making a mistake by forgetting to check that something had an error. You are also able to move error logic out of the main flow of the code.
I don't see why the case you present is different from any other case where I would use exception handling to deal with errors.