Wicket link replay attack - java

I have a ListView composed by different fragment which contains text and a link (inside another fragment). The link is visible depending on the state of the listview model.
For simplicity let's say the link is visible depending on a boolean field of the listview model, if it's true is visible, invisible otherwise.
At first the link is visible, I copy the link location (encrypted), I wait for my model to change (i.e. boolean to false) and after I refresh the page the link is gone. (correct!)
If I try to give the URL (copied before) back in the browser I receive a WicketRuntimeException telling me that the listener for this link was not found.
To be more complete the link is inside a fragment:
<wicket:fragment wicket:id="reservationRatingFragment">
<li>
<div>
<img src="/img/good.png" />
</div>
<p>
<a wicket:id="ratingGoodLink" href="#"> <wicket:message
key="messaging.reservation.rating.good" />
</a>
</p>
</li>
</wicket:fragment>
And when I say invisible I mean that I set the markup container of the fragment as .setVisible(false);
Why is this happening? I'm supposing that if I recall a link which is not visible anymore the framework should just skip it and refresh the page I'm currently on (or redirect me to the base page).
If for example I copy the link and I change BasePage (go to the homepage for example), the exception still occurs when I'm recalling the copied URL.
EDITED:
In the first fragment:
WebMarkupContainer msgRatingContainer = new WebMarkupContainer("messageRatingContainer") {
private static final long serialVersionUID = 1L;
#Override
public void onConfigure() {
setVisible(message.getType() == MessageType.RATING);
}
};
if (msgRatingContainer.isVisible()) {
if (message.getType() == MessageType.RATING) {
msgRatingContainer.add(new ReservationRatingFragment("messageRatingSection",
"reservationRatingFragment", this, item, message));
}
The nested fragment (ReservationRatingFragment):
public ReservationRatingFragment(String id, String markupId,MarkupContainer markupContainer, Item item, Message msg) {
super(id, markupId, markupContainer, new Model<Message>(msg));
/* Avoid render container */
setRenderBodyOnly(true);
/* Load button components */
Link<Void> ratingGoodLink = new Link<Void>("ratingGoodLink"){
private static final long serialVersionUID = 1L;
#Override
public void onClick() {
processRating(ReservationEvaluationResult.GOOD);
}
};
add(ratingGoodLink);
Link<Void> ratingBadLink = new Link<Void>("ratingBadLink"){
private static final long serialVersionUID = 1L;
#Override
public void onClick() {
processRating(ReservationEvaluationResult.BAD);
}
};
add(ratingBadLink);
}
Markup for both fragments:
<wicket:fragment wicket:id="messageFragment">
Some content...
<!-- Here goes my fragment with link -->
<ul wicket:id="messageRatingContainer">
<div wicket:id="messageRatingSection"></div>
</ul>
<wicket:fragment wicket:id="reservationRatingFragment">
<li><div>
<img src="/img/messaging/good.png" />
</div>
<p>
<a wicket:id="ratingGoodLink" href="#"> <wicket:message
key="messaging.reservation.rating.good" />
</a>
</p></li>
<li><div>
<img src="/img/messaging/bad.png" />
</div>
<p>
<a wicket:id="ratingBadLink" href="#"> <wicket:message
key="messaging.reservation.rating.bad" />
</a>
</p></li>
</wicket:fragment>
</wicket:fragment>
EDITED:
The processRating just perform a call to a controller (which handle the change in the backend). In the controller I check for the replay attack (if this action is already performed) and if so I throw a runtime exception that lead the user to a warning page (You already rated this message). The fact is, in this case it don't get to this point, since the link is not available it doesn't call the controller and it just throw the InvalidUrlException since the link is not visible.
Wicket version: 1.4.19
Thanks

Your assumption that an invalid link will be ignored or redirect you to the base page is wrong.
Why is that?
If we take a step back, what happens when you click a link? The state of your application changes. However this is only safe to do so if the application is in the state it was when the link was created. If this rule wasn't enforced, you would need to make sure that every single potential state transition is either acceptable or explicitly marked as invalid. This would be highly impractical, if not impossible in most systems. But neglecting this would not only be a security risk but it could result in corrupt data.
It's best to think of it as a case of optimistic locking. (Mostly because it is :)) When the link is created, it is given the version number of the internal state at the time of creation. When the link is clicked, that version number is compared to the current version of the internal state. If the two match, the link is accepted as valid, the internal state is updated and its version number is incremented. If the two numbers don't match, the link is rejected and an exception is thrown because an invalid state transition attempt can't be ignored.
I won't explain how to get around this limitation as it's already been told in another answer, I just wanted to answer the "why" question.

I am not sure I understand the exact reason for your implementation. That said, I would recommend using the BookmarkablePageLink() with PageParameters set to perform your processRating() method upon loading the destination page.
Add your link components:
PageParameters ppGood = new PageParameters("0="+ReservationEvaluationResult.GOOD);
PageParameters ppBad = new PageParameters("0="+ReservationEvaluationResult.BAD);
add(new BookmarkablePageLink("ratingGoodLink", DestinationPage.class, ppGood));
add(new BookmarkablePageLink("ratingBadLink", DestinationPage.class, ppBad));
Then create a new constructor in your DestinationPage:
public class DestinationPage extends WebPage {
public DestinationPage(PageParameters param) {
if(param.getString("0")!=null){
String rating = param.getString("0");
processRating(rating);
}
...
This will give you a link that will be persistent and should allow you to copy and paste the URL.

The only viable solution I found was to extend the RequestCycle and override the onRuntimeException method this way:
#Override
public Page onRuntimeException(Page page, RuntimeException e) {
if(e instanceof InvalidUrlException) {
return new HomePage();
} else {
return super.onRuntimeException(page, e);
}
}

Related

Java Spring MVC PRG Pattern preserve Data on reload

i'm currently woking on a spring mvc project. I have a page with a form, which represents a configurator.
The user can choose some data in a bunch of select fields and proceeds to the next step, where he gets the same jsp-page but with some more fields, depending on his inputs he made. This will be repeated a few times until he gets his result on another page. Each time a POST will be performed.
Now if the user uses the back function of the Browser he doesn't get to the previous page, but to a browser default "broken page", where Chrome for example says something like "Please confirm resubmission of the form data...". To actually resubmit the data he has to press reload and confirm a popup.
The resubmission itself isn't really a problem, because the data does not get inconsistent, it just performs another call to the backend and receives the data it provides.
The real no-go is the fact that the user has to manually refresh the page and by chance gets confused by the default browser page.
I did some research and found out, that the PRG (Post-Redirect-Get) Pattern might solve this problem.
In fact i can now navigate through the browser or reload the page and does not get the popup or broken page - because it's now a GET request of course.
The problem now is, that if i navigate back, the last page does not contain the data it contained before, but is now empty because no data at all is existing.
I understand that it is now a GET request and no data gets posted, but i thought the previous page would be "reused", like shown here.
Now with the PRG-Pattern the handling of the application is even worse, because if the user reloads or navigates back, he basically has to start from scratch.
Did i misunderstood the meaning of this Pattern?
A quick look into some code, how i implemented this:
#PostMapping("/config")
public String handlePostRequestConfig(RedirectAttributes redirectAttributes, ProductForm productForm){
//Handle productForm and add additional content to it
if(noMoreStepsLeft){
return "redirect:/result";
}
redirectAttributes.addFlashAttribute("form", productForm);
return "redirect:/config";
}
#GetMapping("/config")
public String handleGetRequestConfig(Model model, #ModelAttribute("form") ProductForm productForm{
model.addAttribute("form", productForm);
return getJsp("product");
}
Inside JSP:
<form method="post" action="/config">
<c:foreach items="${form.selectFields}" var="selectField">
<input...>
</c:foreach>
<button type="submit">Submit</button>
</form>
In PRG, P is not the first step of user action flow. PRG is a part of the full flow.
The following shows a flow and how PRG fits in it:
User will hit a URL. For example: http://localhost:8080/myContextPath/config.
This will be handled using a GET handler:
#GetMapping("/config")
public String show(ModelMap model) {
// code
model.put("form", productForm);
return "product"; // returning view name which will be resolved by a view resolver
}
product.jsp:
<form commandName="form" method="post">
<c:foreach items="${form.selectFields}" var="selectField">
<input...>
</c:foreach>
<input type="submit" value="Submit"/>
</form>
This submit action will be handled by a POST handler:
#PostMapping("/config")
public String submit(#ModelAttribute("form") ProductForm productForm,
RedirectAttributes redirectAttributes){
// code, may be service calls, db actions etc
return "redirect:/config";
}
This redirect to /config will be handled again by /config GET handler. (Or you can redirect to any GET handler of course)

Spring form:radiobutton(s) having one selected on page load

<form:form method="post" action="/changeEnabledResource" modelAttribute="user">
<c:forEach items="${user.resources}" var="resource">
<form:radiobutton path="resources"
value="${resource}"
label="${resource.name}"
checked="${resource.enabled ? 'checked' : ''}/>
</c:forEach>
<input type="submit" value="Submit"/>
</form>
Resource class:
public class Resource {
private Long id;
private String name;
private boolean enabled;
//getters setters
}
User class:
public class User {
private List<Resource> resources;
....
//rest of code
}
With the above code all form:radiobuttons have checked="checked", so the last one is always checked when the form loads. Submitting works correctly and it changes the correct one to enabled and the rest to not enabled (service class handles this). But when the page loads all radio buttons have checked="checked".
Why is this happening, or what would be the correct way to do this so that the resource that IS enabled has the radio button checked?
The answer to this is to NOT use the form:radiobutton(s) tags since they apparently don't work very well. I have yet to find any good examples anywhere using this tag. My solution was just to use plain HTML input tags and use the #RequestParam in the controller method which will pass only the value of the radio button that is checked. And I can easily use ${resource.enabled ? 'checked' : ''} to ensure that the correct one is selected.
Set the selected value in a separate property:
public class User {
private int selectedResourceId;
private List<Resource> resources;
....
//rest of code
}
...
<form:radiobutton path="selectedResourceId"
value="${resource.id}"
label="${resource.name}"/>
...
On page load, initalize the selectedResourceId (based on the resource where enabled flag is true), so that the form:radiobutton tag knows which one is selected when the page is rendered.
Upon form submission, go in the other direction and set the appropriate resource.enabled flag based on the selectedResourceId.

Wicket - Form not submitting

I just upgraded a Wicket application from 6.0.0 to 7.6.0 and now I am having problems with one of my forms not submitting.
I went through the versions and my form was working in version 6.12.0 and not working in 6.14.0 there were other problems with 6.13.0
I am using a Button and overriding the onSubmit() method. I have some logging as the first line in the method. I also have overridden the onError() method with logging as the first line in that also.
I also removed the Button and put my code in the Form onSubmit() and onError() with logging and it still is not called in that code.
I have a FeedbackPanel on the page and no errors show up there.
I have checked the javascript console and there are no errors showing.
I also tried to change the Button into a SubmitLink and that produced the same results.
I checked over my HTML and all tags are present, again it was working in the previous version.
When these options are clicked it just refreshes the same page and resets all the values in the form to the values on the original load of the page.
Any help would be appreciated.
Java
Form form = new Form("vvoForm"){
#Override
protected void onSubmit(){
System.out.println("comment here");//This is never called
{
#Override
public void onError(){
System.out.println("Another commment here");//This is never called
{
}
HTML
<form wicket:id="vvoForm">
//There is a table here with input tags all with wicket:id's and
//included and added to the Java code
<input type="submit" value="Save" />//I had a wicket:id here but removed it for simplicity. The wicket:id refferenced the Button
</form>

Chaining multiple select components in Tapestry 5.3 (Ajax update)

I’m using tapestry 5.3.7, and I want to use Ajax chaining select form elements : If I choose one option in a select element, another select appear to choose another element based on your first choice. I try a sample in the tapestry doc, and adapted for my project. Despite the fact that my custom code is very close to the sample, I always have the following error :
Render queue error in SetupRender[SelectZoneDemo:version]: Component SelectZoneDemo:version must be enclosed by a Form component.
Working sample from the doc (Chaining of select components CarMaker) http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/corelib/components/Select.html)
Here is my code :
Template file (.tml)
<t:form>
<p>
<t:errors />
</p>
<p>
<t:select t:id="selectApplicatifs" t:model="selectApplicatifs"
t:value="selectedApplicatif" validate="required" zone= "VersionZone"
t:zone="versionZone" t:encoder="ApplicatifDtoEncoder" />
</p>
<t:zone t:id="versionZone" id="versionZone">
<t:if test="selectedApplicatif">
<p>
<t:select t:id="version" model="selectVersions" t:encoder="VersionDtoEncoder" />
</p>
</t:if>
<p>
<t:submit value="literal:Submit" />
</p>
</t:zone>
</t:form>
Java file
#Inject
private AjaxResponseRenderer ajaxResponseRenderer;
#Inject
private IServiceApplicatif serviceApplicatif;
#Inject
private SelectModelFactory selectModelFactory;
#Property
#Persist
private SelectModel selectApplicatifs;
#Property
#Persist
private String version;
#Property
#Persist
private SelectModel selectVersions;
#Inject
#Property
private ApplicatifDtoEncoder applicatifDtoEncoder;
#Inject
#Property
private VersionDtoEncoder versionDtoEncoder;
#Property
#Persist
private ApplicatifDto selectedApplicatif;
#InjectComponent
private Zone versionZone;
public void onActivate() {
List<ApplicatifDto> listApplicatifs = serviceApplicatif.findAllApplicatifDto();
List<VersionDto> listVersionApplicatifs = new ArrayList<VersionDto>();
selectApplicatifs = selectModelFactory.create(listApplicatifs, "nom");
if (selectVersions == null) {
selectVersions = selectModelFactory.create(listVersionApplicatifs,"version");
}
}
public void onValueChangedFromSelectApplicatifs(ApplicatifDto applicatifDto) {
List<VersionDto> versionList = applicatifDto.getVersionList();
selectVersions = selectModelFactory.create(versionList,"version");
ajaxResponseRenderer.addRender(versionZone);
}
Rendering zones within a form via ajax can get tricky as you have discovered. Fields require a FormSupport instance to be on the Environment stack. This is normally added to the environment as the parent form renders but as you have discovered, when rendering a zone within a form the FormSupport is not available.
Here's a few options:
Have a zone that wraps the entire form and update the whole form via ajax
Instead of refreshing a zone, use some javascript (via JavaScriptSupport) to update the options in an existing select menu
Use the Observe mixin to update zones in the form. Instead of using the core tapestry select component, you could render your own select. This might require you to use #RequestParameter to get the values serverside when the form is finally submitted.
Use the FormInjector. I've never used it myself but I think it somehow spoofs the environmental. I'm not sure how you'd pass the user's selection in the event. I think this component may have also been scrapped in tapestry 5.4.

Ajax style loading with IceFaces

I have a page on which I show a list of objects which are loaded from a webservice. This may take a while.
Now I'd like to do it the Ajax way and first show the page and then load the list. While the list is loading a animated should be shown.
Can anybody give me an example how to do that with JSF/ICEFaces? Thanks.
It would be better to use the SessionRenderer. Have a look at my ICEfaces book examples (http://icecube-on-icefusion.googlecode.com/) and search for the progressDialog tag for an example. Or page 244ff in the book.
Ok, solved it myself.
Here's how I'm doing it:
in the Managed Bean's constructor I'm calling a method which creates and starts a new thread. This thread loads the objects. As soon as the objects are there the 'loading' flag of my bean is set to false and
PersistentFacesState.getInstance().renderLater();
is called. 'loading' is initially set to false.
That's the method for loading the objects in async mode:
private void asyncLoading() {
final MyBackingBean bean = this;
final String userName = CallerContextUtil.getCurrentUserCompany();
new Thread() {
#Override
public void run() {
bean.setLoading(true);
PersistentFacesState.getInstance().renderLater();
load(userName );
bean.setLoading(false);
PersistentFacesState.getInstance().renderLater();
}
}.start();
}
On the view I'm showing or hiding an animated loading images on the state of the loading flag.
I don't know if that is the best or even a good solution. Comments are welcome.
It is strongly discouraged to create new threads in a J2EE server. It's server's job to manage threads.
You can ask for the submission of an icefaces form using ajax when your page is loaded, that should do the trick.
i think i have answer for this question, because i have the same trouble about ajax style loading..
after lurking in many sites and icefaces forum, i have this code, without using thread:
first you have to download jquery, and then the code is like this:
<script type="text/javascript" src="js/jquery-1.6.min.js"/>
<script type="text/javascript">
var j = jQuery.noConflict();
j(document).ready(function(){
j(".wrapper-popup-loading").hide();
});
function icesubmitlocal() {
var windowWidth = document.documentElement.clientWidth;
var windowHeight = document.documentElement.clientHeight;
var popupHeight = j(".wrapper-popup-loading").height();
var popupWidth = j(".wrapper-popup-loading").width();
j(".wrapper-popup-loading").css({
"position": "absolute",
"top": windowHeight/2-popupHeight/2,
"left": windowWidth/2-popupWidth/2
}).show();
j(".wrapper-popup-white").show();
}
function icereceivelocal() {
j(".wrapper-popup-loading").hide();
j(".wrapper-popup-white").hide();
}
function init() {
Ice.onSendReceive('document:body',icesubmitlocal,icereceivelocal);
}
</script>
<body onload="init()" id="outputBody1" style="-rave-layout: grid">
the basic idea is simple, every ajax call you just have to show the popup div, and every you receive confirmation from icefaces js, you just have to hide the popup,
the popup panel is like this:
<div class="wrapper-popup-loading"><!-- start wrapper -->
<div class="wrapper-popup-white"><!-- start wrapper -->
<center>
<img src="images/aed-popup.png" alt="" style="margin-top: 5px;"/>
<br />
<img src="images/aed-garuda.gif" alt="" style="margin-top: 5px;"/>
</center>
</div>
</div><!-- end footer -->
then, everytime ajax request on, your popup is show, and if ajax stop, your popup is hide..
hope this help..thanks

Categories

Resources