In order to take control of the parameters which an action accept you must:
Make your action implement ParameterNameAware like:
public class sample implements ParameterNameAware(){
public boolean acceptableParameterName(String parameterName) {
if (("amount".equals(parameterName) ||
"sourceAccount".equals(parameterName) ||
"destinationAccount".equals(parameterName))
return true;
else
return false;
}
}
This method is called for the excluded properties of param properties.
So, you need to configure params interceptor to exclude all parameters, so the acceptableParameters get the chance to be called by params interceptor.
<interceptor-ref name="params">
<param name="excludeParams">\w+((\.\w+)|(\[\d+\])|(\(\d+\))|(\['\w+'\])|(\('\w+'\)))*</param>
</interceptor-ref>
Am I correct?! This seems some how strange for me (Excluding all parameters and then adding them in each action).
The Struts2 params interceptor behavior against accepting or declining parameters could be extended via the ParameterNameAware action. All parameters are handled by this interceptor if they are accepted or ignored if they are excluded. The extension point checks for accepted parameters. If they are accepted by the interceptor then they are passed, nevertheless additional checks is performed by calling acceptableParameterName but it useless if parameter is accepted by the interceptor. On the other hand if parameter is excluded by the interceptor then calling this method makes a power. Coexisting both methods looks strange because they are designed to be mutually exclusive.
Related
I have a method annotated with #PreAuthorize(...) with some logic that goes away and queries an API for some information about what the user can view. However, I have this endpoint that I need to add this #PreAuthorize annotation into which receives in a more "complex" object which I want to transform slightly (the object contains an array that is some cases I want to add/remove data from).
#PostMapping("/search")
#PreAuthorize("#Service.isAuth(#searchParam)")
public ResponseEntity<Response> search(SearchParams searchParam) {
return service.getSearchResult(searchParam);
}
Is there a way I can modify searchParam inside the #PreAuthorize annotation then have it passed into the method body, I know that this is probably is not the correct way to do this and maybe isn't something that #PreAuthorize wasn't designed for but is there any way of doing this even with a different type of annotation. Obviously worst case I can move the logic into the method body but I would prefer to use an annotation-based solution like #PreAuthorize offers if possible. Thanks for any help even links to other relevant things would be useful I've not found much on google related to this.
I think the best solution is to make a handler/interceptor and then annotate it with #PreAuthorize. So I think you are in the right track but you need to make sure that you modify your code to implement the HandlerMapping interface to create the interceptor and then override the prehandle method. After you need to annotate it with #PreAuthorize programatically. The last thing will be to use a wrapper to modify the HttpWrapper, it cannot be done manually. Here links to the relevant resources in order:
Creating a Handler/Interceptor: https://www.baeldung.com/spring-mvc-handlerinterceptor
Using PreAuthorise in the interceptor: How can I require that all request handlers in my Spring application have #PreAuthorize
To modify the HttpServlet request you will need a wrapper: How to modify HttpServletRequest body in java?
Have a try, hopefully that works.
Snippet of code taken from second link uses a programatic PreAuthorize rather than annotation:
public class PreAuthorizeChecker implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
PreAuthorize annotation = AnnotationUtils.findAnnotation(hm.getMethod(), PreAuthorize.class);
//TODO use the technique shown on the third link to wrap and modify the HttpServletRequest
if (annotation == null) {
// prevent access to method wihout security restrictions
throw new RuntimeException("Rights are not defined for this handler");
}
}
return true;
}
.....
I would like to create an action class with no setter and getter on properties for the data coming from the user interface. Instead, I would like to use ServletActionContext.getRequest().getParameterMap() in my own builder class to construct the object.
I had created my Action class with no properties. When I am submitting my form I am running into ognl.OgnlException: target is null for setProperty(null, "field-name", [Ljava.lang.String;#5513fab7)
Is there any additional conventions or configurations required to convey Struts2 framework to not set properties and stop avoid the exception I am receiving above?
You can exclude some properties from the accepted parameters for params interceptor by setting parameter excludeParams to the interceptor. By default this parameter is initialized with
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
</interceptor-ref>
You should add you properties here, it accepts the regex pattern to match the property names. The strategy applied with accepted parameter names could be compromised via the ParameterNameAware implemented actions where you could remove the restriction given above.
To be more specific about "data coming from the user interface" I'd adhere that parameters to the interceptor-ref element is applied to the interceptor on start up and is not stored elsewhere in the configuration manager. This means you can't get this parameters at runtime and only could change via updating and reloading the configuration file struts.xml. If you keep your configuration in the safe place and it's protected from modification then you could make more claims toward your running application safety.
Yes, you need to remove the Struts params interceptor mapping for this specific action. I believe you can take an approach similar to the one in this related question. Otherwise you will have to create another interceptor stack with the interceptors you desire, minus the parameter interceptor and map the action to that stack in struts.xml or use the #InterceptorRef annotation on your action class, assuming you're using the convention plugin.
I'm new to Struts2, coming from a PHP background, where I'd often have the same file handling GET and POST requests, and processing a form if the request is a POST request.
I currently have the following in struts.xml:
<action name="ProcessData" class="ProcessDataAction">
<result name="*">processdata.jsp</result>
</action>
<action name="ProcessDataUpload" class="ProcessDataAction" method="upload">
<result name="*">processsdata.jsp</result>
</action>
Which works fine, but it bothers me that the URL that handles POST is different, since now if the user reloads the page, they get an error rather than simply seeing the contents of the GET page.
So my question is, is there any way to tell struts2 to call one method if it's a GET request, and another method if it's a POST request?
Struts2 doesn't offer what you described out of the box. If you want to enforce that a particular action method is invokable only by certain HTTP methods, then you'd need to create a custom interceptor and probably a few custom annotations.
If you just want the same action to handle displaying the form and processing it, then you can do the following:
public class MyAction {
public String execute() {
return INPUT;
}
public void validate() {
// perform any form validation needed
}
public String submit() {
// process the form and then redirect
}
}
In your form, you would submit to ProcessData!submit. The ! separates the action from the action method name. It provides what you have already, but you don't need to explicitly map each method in the struts.xml.
But it bothers me that the URL that handles POST is different, since now if the user reloads the page, they get an error rather than simply seeing the contents of the GET page.
Redirecting the user after a successful post completely nullifies this point. Look at the "Redirect After Post" or "Post/Redirect/Get" pattern).
Not by default, no. IMO the cleanest solution is to tweak the method name via an interceptor that looks at the request type. For example, I had a simple one that looked for executeGet and executePost methods.
Whether or not it's a great idea... different issue.
I'm building a Struts2 application, where data is sent to my application in a request header. I have a custom interceptor that grabs this data and uses it to retrieve some data from the database and store it in the session. I then use this session data in the resultant JSP. One problem: the session variable is null until I refresh the page.
Here is my stack:
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
Here is my intercept method in myInterceptor:
ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);
HttpSession session = request.getSession(true);
MyObject obj = new MyObject();
String header = request.getHeader("HEADER_VALUE");
if(header != null) {
obj.loadByHeader(header);
session.setAttribute("value", obj);
}
return invocation.invoke();
And here is the JSP code:
<s:if test="#session.value == null">
...
</s:if>
Like I said, this works when I either refresh or go to another page using this value. Am I doing something wrong? Or can I not get the value until the next time around? If it's the latter, is there an alternative way to get that data on first pass?
You should be able to do set it and use it in one shot! I don't see any issue in what you've provided, my guess would be that you are rendering your view the first time without going though your interceptor.
Two ways this could happen: 1, you have more than one package. One of the packages has your custom interceptor stack defined and the other does not. The one that does not renders the view the first time and then subsequent renderings do pass through your interceptor, 2) it is also possible if you have more than one action which will render the view and you have interceptors being applied at the action level.
Throw print/logging message into the interceptor and make sure it is being executed when you think it is.
Edit: reverse order of defaultStack and myInterceptor since the params interceptor will not have run before myInterceptor.
I always wondered why there exists no removeParameters() method in Servlet API.
What could be the motive behind this design?
Here is a scenario: I am posed with a challenge in a proprietary MVC framework that I am compelled to use. This framework uses a Controller Servlet that hosts an algorithm in it's post method:
doPost() {
//create instance of action - just like struts action
action.init
action.preexecution
if(redirection state is not set)
action.process
action.postprocess
action.finish
}
The only way I can skip process of any particular action would be by setting a redirection url. The Controller Servlet is FINAL. Now, when I do a requestdispatcher.forward from say the preexecution method of an action, the controller will go ahead and execute the rest of the methods and not skip the rest. I cannot change this behavior, neither can I set the redirect, coz I need to do a forward. It works fine as long as I am not forwarding request to the same action. When a request is forwarded to the same action, the http parameters are all the same. This would take it into a never ending loop. Hence, I am compelled to add extra parameters indicating that it is a repeat request and should be treated differently.
Not sure if my problem made sense, but thought this is a good forum to post the same.
Umm... because it would serve no purpose? Request parameters are sent by the client to the server. The server is free to ignore them, but what practical effect would you expect such a removeParameter() method to have?
Edit: Request parameters are meant for the communication between server and client. For server-internal communication, you can use request attributes, which can be set and removed.
EDIT: McDowell reminded me of HttpServletRequestWrapper, so I'm changing the below to make it a little less work... Thanks McD!
You can decorate the request to "hide" parameters you don't want and/or add extra parameters.
Something like (off the top of me head -- no compiling so the API might be a tweak off...)
public class MyParameterHider extends HttpServletRequestWrapper {
public MyParameterHider(HttpServletRequest request) {
super(request);
}
public String getParameter(String name) {
if ("parameterToHide".equals(name))
return null;
return realRequest.getParameter(name);
}
// similar for getParameterNames and getParameterMap - don't include the hidden parm
// all other methods are strictly pass-through and are automatically
// handled by HttpServletRequestWrapper
}
In your forward, just wrap the request in a ParameterHider when calling doFilter:
dispatcher.forward(new MyParameterHider(request), response);
Patterns FTW!
Hope this helps!