QTIWorks LTI request parameter is empty - java

I'm trying to implement LTI in our education platform to connect with QTIWoks in Java.
I have a simple tool consumer that generates the following HTML Form:
<html>
<head> </head>
<body>
<form action="http://192.168.0.114:8080/qtiworks-engine/lti/domainlaunch" name="ltiLaunchForm" id="ltiLaunchForm" method="post" target="basicltiLaunchFrame" enctype="application/x-www-form-urlencoded" style="display: block;">
<input type="hidden" name="context_id" value="cid-00113">
<input type="hidden" name="context_label" value="SI106">
<input type="hidden" name="context_title" value="Design of Personal Environments 1">
<input type="hidden" name="ext_note" value="Instructor from first course">
<input type="hidden" name="launch_presentation_locale" value="en_us">
<input type="hidden" name="lis_person_contact_email_primary" value="sian#imscert.org">
<input type="hidden" name="lis_person_name_family" value="Instructor">
<input type="hidden" name="lis_person_name_given" value="Siân">
<input type="hidden" name="lis_person_sourcedid" value="school.edu:user">
<input type="hidden" name="resource_link_description" value="This learning space is private">
<input type="hidden" name="resource_link_id" value="res-0012612">
<input type="hidden" name="resource_link_title" value="My Weekly Wiki">
<input type="hidden" name="roles" value="Instructor">
<input type="hidden" name="tool_consumer_info_product_family_code" value="sakai-unit">
<input type="hidden" name="tool_consumer_info_version" value="0.9">
<input type="hidden" name="tool_consumer_instance_description" value="University of School (LMSng)">
<input type="hidden" name="tool_consumer_instance_guid" value="lmsng.school.edu">
<input type="hidden" name="user_id" value="user-0016">
<input type="hidden" name="oauth_callback" value="about:blank">
<input type="hidden" name="custom_simple_key" value="custom_simple_value">
<input type="hidden" name="custom_complex____________key" value="Complex!##$^*(){}[]½Value">
<input type="hidden" name="lti_version" value="LTI-1p0">
<input type="hidden" name="lti_message_type" value="basic-lti-launch-request">
<input type="hidden" name="oauth_version" value="1.0">
<input type="hidden" name="oauth_nonce" value="Z2WVNEPUZkzsolOe4hRvKbkXtOSmYiyw">
<input type="hidden" name="oauth_timestamp" value="1429793062">
<input type="hidden" name="oauth_consumer_key" value="feras">
<input type="hidden" name="oauth_signature_method" value="HMAC-SHA1">
<input type="hidden" name="oauth_signature" value="g908qTtVGh8MsOgVUdarVlSBmC0=">
<input type="hidden" name="ext_submit" value="Finish Launch">
</form><iframe name="basicltiLaunchFrame" id="basicltiLaunchFrame" src="" width="100%" height="900" scrolling="auto" frameborder="1" transparency="">
</iframe>
<script type="text/javascript">
document.getElementById("ltiLaunchForm").style.display = "none";
nei = document.createElement('input');
nei.setAttribute('type', 'hidden');
nei.setAttribute('name', 'ext_submit');
nei.setAttribute('value', 'FinishLaunch');
document.getElementById("ltiLaunchForm").appendChild(nei);
document.ltiLaunchForm.submit();
</script>
</body>
</html>
then it calls the dominlaunch from qtiworks
#RequestMapping(value="/domainlaunch", method=RequestMethod.POST)
public String ltiDomainLevelLaunch(final HttpSession httpSession, final HttpServletRequest request,
final HttpServletResponse response)
throws IOException {
/* Decode LTI launch request, and bail out on error */
final DecodedLtiLaunch decodedLtiLaunch = ltiLaunchService.decodeLtiLaunchData(request, LtiLaunchType.DOMAIN);
if (decodedLtiLaunch.isError()) {
response.sendError(decodedLtiLaunch.getErrorCode(), decodedLtiLaunch.getErrorMessage());
return null;
}
final LtiLaunchData ltiLaunchData = decodedLtiLaunch.getLtiLaunchData();
/* Make sure this is a domain launch */
final LtiUser ltiUser = decodedLtiLaunch.getLtiUser();
final LtiDomain ltiDomain = ltiUser.getLtiDomain();
if (ltiDomain==null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "The tool consumer has attempted a domain-level launch using a link-level key");
return null;
}
/* Extract/create the corresponding LtiResource for this launch */
final LtiResource ltiResource = ltiLaunchService.provideLtiResource(decodedLtiLaunch); /* (May be null for candidates) */
final UserRole userRole = ltiUser.getUserRole();
if (userRole==UserRole.INSTRUCTOR) {
/* If user is an instructor, we'll forward to the LTI instructor MVC after
* "authenticating" the user by creating and storing an LtiDomainTicket
* in the session */
final LtiAuthenticationTicket ltiDomainTicket = new LtiAuthenticationTicket(ltiUser.getId(), ltiResource.getId(),ltiLaunchData.getLaunchPresentationReturnUrl());
LtiResourceAuthenticationFilter.authenticateUserForResource(httpSession, ltiDomainTicket);
return "redirect:/lti/resource/" + ltiResource.getId();
}
else if (userRole==UserRole.CANDIDATE) {
/* If user is a candidate, then we'll launch/reuse a candidate session */
if (ltiResource==null) {
return "candidateLaunchError";
}
/* Extract relevant data */
final String returnUrl = ltiLaunchData.getLaunchPresentationReturnUrl();
final String lisOutcomeServiceUrl = ltiLaunchData.getLisOutcomeServiceUrl();
final String lisResultSourcedid = ltiLaunchData.getLisResultSourcedid();
/* Launch and redirect to session */
try {
final CandidateSessionTicket candidateSessionTicket = candidateSessionLaunchService.launchDomainLevelLtiCandidateSession(httpSession,
ltiUser, ltiResource, returnUrl, lisOutcomeServiceUrl, lisResultSourcedid);
return GlobalRouter.buildSessionStartRedirect(candidateSessionTicket);
}
catch (final CandidateException e) {
return "candidateLaunchError";
}
}
else {
throw new QtiWorksLogicException("Unexpected LTI userRole " + userRole);
}
}
the problem is decodedLtiLaunch.isError() returns true and my request is not performed.
I debugged the problem and found that HttpServletRequest request has no item in parameterMap
however, it's working well when the request comes from moodle (request's parameterMap has the passed params)
how can I solve this please?
thanks in advance.

Without knowing what the exact error code you are seeing is, I am going to make a very strong guess that your signature is bad
Since you are using JAVA I would suggest that you utilize the basiclti-util library that IMSGlobal provides to generate a signature
Add the following dependency
<dependency>
<groupId>org.imsglobal</groupId>
<artifactId>basiclti-util</artifactId>
<version>1.1.2</version>
</dependency>
Then use the following code to generate the signature
Map<String, String> signedParameters = new LtiOauthSigner()
.signParameters(parameters, key, secret, url, "POST");
Then take all of the key-value pairs in the signedParameters map, and use that to construct the form input tags you have in your example.

Related

Spring controller get multidimensional array as post parameters

I have a form that can be dynamically edited - the user can add/remove rows and information
The structure is this:
every element in the multidimensional array has the following elements:
id_material
id_detail
and in the rows that can be added/removed within the form:
name
quantity
file
the form:
<input type="hidden" name="myData[id_material][0]" value="123">
<input type="hidden" name="myData[id_detail][0]" value="456">
<input type="text" name="myData[ime_detail][0][1]" value="foo">
<input type="text" name="myData[quantity][0][1]" value="1">
<input type="file" name="myData[file][0][1]" accept=".pdf, .jpg, .dxf">
<input type="hidden" name="myData[id_material][1]" value="123">
<input type="hidden" name="myData[id_detail][1]" value="456">
<input type="text" name="myData[ime_detail][1][1]" value="foo">
<input type="text" name="myData[quantity][1][1]" value="1">
<input type="file" name="myData[file][1][1]" accept=".pdf, .jpg, .dxf">
<input type="text" name="myData[ime_detail][1][2]" value="bar">
<input type="text" name="myData[quantity][1][2]" value="2">
<input type="file" name="myData[file][1][2]" accept=".pdf, .jpg, .dxf">
My Spring controller:
#RequestMapping(value = myURL, method = RequestMethod.POST, consumes = {"multipart/form-data"})
public #ResponseBody error save(ModelMap model, HttpServletRequest req,
HttpSession session, HttpServletResponse resp,
#PathVariable("locale") String loc,
#RequestParam Map<String, Object> params) {
System.out.println("save() method invoked");
return null;
}
However, the controller method is never invoked when the form is submited. I have tried wrapping the parameters in a class like this:
public class CustomWrapper {
private Map<String, Object> customMap= new HashMap<String, Object>();
public Map<String, Object> getCustomMap() {
return customMap;
}
public void setCustomMap(Map<String, Object> customMap) {
this.customMap = customMap;
}
}
still its not invoked. Do you guys have any idea how to properly submit the form?

convert parameter from multiselect checkbox of jsp page

<input type="checkbox" name="premium" value="HBO">HBO <br>
<input type="checkbox" name="premium" value="FOXP">FOX Película <br>
<input type="checkbox" name="premium" value="FOX">FOX + <br><br>
<input type="submit" value="cotizar" name="Cotizar" />
<br><br>
I'm trying to bring from an index.jsp the premium parameter of a checkbox, in a servlet of a client of a web service. I have to save it as a list but what I have tried has not worked
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String plan = request.getParameter("plan");
String PREMIUM = request.getParameter("premium");
How do I convert request.getParameter ("premium") into a list?
Try this:
String[] premiums = request.getParameterValues("premium");
You need to put all the checkbox inside of form then only multiple values will be sent to server.
HTML:
<form method="post">
<input type="checkbox" name="premium" value="HBO">HBO <br>
<input type="checkbox" name="premium" value="FOXP">FOX Película <br>
<input type="checkbox" name="premium" value="FOX">FOX + <br><br>
<input type="submit" value="cotizar" name="Cotizar" />
</form>
Servlet:
To get multiple values we need to use getParameterValues(), if you any value for the given parameter name it will give string array of values. If we have one value it will given string array with length of 1.
String[] premiums = request.getParameterValues("premium");
If no value sent to server then above method will return null value.

How to redirect to servlet when we have multiple buttons

I have 2 textboxes and 3 buttons and each button has specific action i.e. insert, update, delete.
But how to redirect it when specific button click ?
because i have used it in one form tag.
so what will it do when any button click ?
how it will get the action name ?
code :
<form action="Doaction" method="post">
First Name : <input type="text" id="fname" name="fname">
<br>
Last Name : <input type="text" id="lname" name="lname"><br>
<input type="button" value="Insert">
<input type="button" value="Update">
<input type="button" value="Delete">
</form>
any help please ?
in form : give name to buttons
First Name : <input type="text" id="fname" name="fname">
<br>
Last Name : <input type="text" id="lname" name="lname"><br>
<input type="button" value="Insert" name="button">
<input type="button" value="Update" name="button">
<input type="button" value="Delete" name="button">
</form>
String button_param = request.getParameter("button");
RequestDispatcher rd = null;
if(button_param .equals("Insert")
{
rd=request.getRequestDispatcher("InsertServlet");
}
else if(button_param .equals("Update"))
{
rd=request.getRequestDispatcher("UpdateServlet");
}
else if(button_param .equals("Delete"))
{
rd=request.getRequestDispatcher("DeleteServlet");
}
rd.forward(request, response);
you can create a common javascript function like submitForm('pass your action').
Here you can see that function has a parameter. you have to pass action based your requirement
for example :
<input type="button" value="Insert" onclick="submitForm('InsertURL');">
<input type="button" value="Update" onclick="submitForm('UpdateURL');">
Action function body like :
function submitForm(action){
//send Ajax Request to server...using action
}
Yes I have solved it.
I have given a common name to each button and in servlet i have first checked that from which button action call then as per it i have used if condition and inside it's block i have make a related code.
code :
<form action="Doreg" method="post">
First Name : <input type="text" id="fname" name="fname">
<br>
Last Name : <input type="text" id="lname" name="lname"><br>
<input type="submit" value="Insert" name="kb">
<input type="submit" value="Update" name="kb">
<input type="submit" value="Delete" name="kb">
</form>
java code :
String fname =request.getParameter("fname");
String lname =request.getParameter("lname");
String f = request.getParameter("kb");
if (f.equals("Insert"))
{
obj.connect();
String query ="insert into user(firstname,lastname) values('"+fname+"','"+lname+"')";
obj.passquery(query);
}
else if(f.equals("Delete"))
{
obj.connect();
String query ="delete user where firstname='"+fname+"' OR lastname='"+lname+"'";
obj.passquery(query);
}

Reload jsp and lose request.getParameter("...") on servlet

I have 2 jsp-page. In first jsp-page I use combobox who choosing subject, several radio button for action. On servlet this page I get request.getParameter("subjectID").
Better If I show servlets and jsp
<form action="/TutorWebApp/controller" method="POST" name="editTestForm">
<p>
Choose subject
<select name='subject'>
<c:forEach items="${subjects}" var="subject" >
<option value="${subject.key}">
${subject.value.getName()}
</option>
</c:forEach>
</select>
</p>
<input type="radio" name="command" value="add_test">
Add test <br />
<input type="radio" name="command" value="add_subject">
Add subject <br />
<input type="submit" value="OK"/>
</form>
In this page I choose subject from combobox. And choose "Add test". After I go to servlet where
class AddTestCommand implements Command {
private static final String PARAM_TEST_NAME = "testName";
private static final String PARAM_SUBJECT = "subject";
#Override
public String execute(HttpServletRequest request) throws ServletException, IOException {
String page = " ";
String message = " ";
String testName = request.getParameter(PARAM_TEST_NAME);
if (testName != null && (!"".equals(testName))) {
HttpSession session = request.getSession(true);
Integer userID = (Integer) session.getAttribute("userID");
Integer subjectId =
Integer.valueOf(request.getParameter(PARAM_SUBJECT));
if(AddTestLogic.addTest(userID, subjectId, testName)){
message = "Success";
} else{
message = "This test already exist";
}
request.setAttribute("result", message);
}
page = ResourceBuilder.getPropertyManager(PropertyEnum.JSP_PAGE).
getProperty("path.page.addtest");
return page;
}
}
There I can get value of subject as request.getParameter("subject"); near with testName before if(){} And next step - go to next jsp
<form action="/TutorWebApp/controller" method="POST" name="addTestForm">
<input type="hidden" name="command" value="add_test" />
Name of new test:
<input type="text" name="testName" value=""/>
<input type="submit" value="Add test"/>
</form>
An after input data in jsp I go to the same servlet again. But I lose value request.getParameter("subject").
I try to use HttpSession but on first page I send Map. And get with request just choosen subjectID from Map.
I don't know how resolve this problem.
Thanks
You can retain request parameters for the next request with a hidden field. Request parameters are available by the ${param} map in EL. So, this should do:
<input type="hidden" name="subject" value="${fn:escapeXml(param.subject)}" />
Note that I'm using JSTL fn:escapeXml() to escape HTML entities; this will prevent possible XSS attacks.

Liferay doesn't catch form in portlet, and doesn't process

I have .jsp in liferay, and use javascript with applet, but after the form sent to the portlet, on the server side, portlet doesn't catch the form, and do not show in logs additional messages.
jsp page's snippet:
<script type="text/javascript">
function processSigning(){
var applet = document.applets["SignApplet"];
var path_to_certificate = document.getElementById("certificate").value;
var pass = document.getElementById("password").value;
var filePath = document.getElementById("documentSign").value;
applet.filePath = document.getElementById("documentSign").value;
applet.profileTestPKCS12(path_to_certificate, pass);
document.getElementById("file").value = applet.getDocumentString(filePath);
document.getElementById("sign").value = applet.getSignString();
document.getElementById("cert").value = applet.getCertificateString();
document.getElementById("mainForm").submit();
}
</script>
<form id="mainForm" action="<portlet:actionURL>
<portlet:param name="COMMAND" value="LOAD"/>
</portlet:actionURL>">
<hidden id="file" value="asdf"></hidden>
<hidden id="cert" value="asdf"></hidden>
<hidden id="sign" value="asdf"></hidden>
<input type="button" onClick="processSigning();" value="click here!" >
</form>
portlets snippet:
public void processAction(ActionRequest request, ActionResponse response) throws PortletException {
session = request.getPortletSession(true);
String command = request.getParameter("COMMAND");
System.out.println("command=" + command);
log.info("command=" + command);
if ("LOAD".equals(command)) {
{
System.out.println("file");
log.info("file");
String fileBase64 = request.getParameter("file");
System.out.println(request.getParameter("file"));
log.info(request.getParameter("file"));
}
}
}
Check your portlet.xml if the portlet-class is pointing to MVCPortlet or your custom portlet class. It should point to the custom portlet class.
Try this form and see if it works for you:
<portlet:actionURL var="myActionURL"></portlet:actionURL>
<form id="mainForm" action="${myActionURL}" method="post">
<input type="hidden" name="COMMAND" id="COMMAND" value="LOAD" />
<input type="hidden" name="file" id="file" value="asdf" />
<input type="hidden" name="cert" id="cert" value="asdf" />
<input type="hidden" name="sign" id="sign" value="asdf" />
<input type="button" onClick="processSigning();" value="click here!" >
</form>
Hope this helps.
There is method for the form must be specified, because Liferay Portal works with "post" method, also the names of hidden parameters must be used with "name" attribute, because request works with name, not ids

Categories