org.imsglobal.json.IMSJSONRequest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of basiclti-util Show documentation
Show all versions of basiclti-util Show documentation
BasicLTI Utilities are a set of utility classes to aid in the development of BasicLTI consumers and
providers. They deal with much of the heavy lifting and make the process more opaque to the developer.
The newest version!
package org.imsglobal.json;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Logger;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import net.oauth.OAuthValidator;
import net.oauth.SimpleOAuthValidator;
import net.oauth.server.OAuthServlet;
import net.oauth.signature.OAuthSignatureMethod;
import org.apache.commons.codec.binary.Base64;
import org.json.simple.JSONValue;
public class IMSJSONRequest {
private final static Logger Log = Logger.getLogger(IMSJSONRequest.class .getName());
public final static String STATUS = "status";
public final static String STATUS_CODE = "code";
public final static String STATUS_DESCRIPTION = "description";
public final static String CODE_MAJOR_SUCCESS = "success";
public final static String CODE_MAJOR_FAILURE = "failure";
public final static String CODE_MAJOR_UNSUPPORTED = "unsupported";
public String postBody = null;
private String header = null;
private String oauth_body_hash = null;
private String oauth_consumer_key = null;
public boolean valid = false;
public String errorMessage = null;
public String base_string = null;
private static final String APPLICATION_JSON = "application/json";
public String getOAuthConsumerKey()
{
return oauth_consumer_key;
}
public String getPostBody()
{
return postBody;
}
// Normal Constructor
public IMSJSONRequest(String oauth_consumer_key, String oauth_secret, HttpServletRequest request)
{
loadFromRequest(request);
if ( ! valid ) return;
validateRequest(oauth_consumer_key, oauth_secret, request);
}
// Constructor for delayed validation
public IMSJSONRequest(HttpServletRequest request)
{
loadFromRequest(request);
}
// Constructor for testing...
public IMSJSONRequest(String bodyString)
{
postBody = bodyString;
}
// Load but do not check the authentication
@SuppressWarnings("deprecation")
public void loadFromRequest(HttpServletRequest request)
{
header = request.getHeader("Authorization");
System.out.println("Header: "+header);
oauth_body_hash = null;
if ( header != null ) {
if (header.startsWith("OAuth ")) header = header.substring(5);
String [] parms = header.split(",");
for ( String parm : parms ) {
parm = parm.trim();
if ( parm.startsWith("oauth_body_hash=") ) {
String [] pieces = parm.split("\"");
if ( pieces.length == 2 ) oauth_body_hash = URLDecoder.decode(pieces[1]);
}
if ( parm.startsWith("oauth_consumer_key=") ) {
String [] pieces = parm.split("\"");
if ( pieces.length == 2 ) oauth_consumer_key = URLDecoder.decode(pieces[1]);
}
}
}
if ( oauth_body_hash == null ) {
errorMessage = "Did not find oauth_body_hash";
Log.info(errorMessage+"\n"+header);
return;
}
System.out.println("OBH="+oauth_body_hash);
byte[] buf = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int chars = 0;
try {
ServletInputStream is = request.getInputStream();
int readNum;
do {
readNum = is.read(buf);
if (readNum>0) {
bos.write(buf, 0, readNum);
chars = chars + readNum;
// We dont' want a DOS
if ( chars > 10000000 ) {
errorMessage = "Message body size exceeded";
return;
}
}
} while (readNum>=0);
} catch(Exception e) {
errorMessage = "Could not read message body:"+e.getMessage();
return;
}
byte[] bytes = bos.toByteArray();
try {
postBody = new String(bytes, "UTF-8");
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(bytes);
byte[] output = Base64.encodeBase64(md.digest());
String hash = new String(output);
System.out.println("HASH="+hash+" bytes="+bytes.length);
if ( ! hash.equals(oauth_body_hash) ) {
errorMessage = "Body hash does not match. bytes="+bytes.length;
System.out.println(postBody);
return;
}
} catch (Exception e) {
errorMessage = "Could not compute body hash. bytes="+bytes.length;
return;
}
valid = true; // So far we are valid
}
// Assumes data is all loaded
public void validateRequest(String oauth_consumer_key, String oauth_secret, HttpServletRequest request)
{
validateRequest(oauth_consumer_key, oauth_secret, request, null) ;
}
public void validateRequest(String oauth_consumer_key, String oauth_secret, HttpServletRequest request, String URL)
{
valid = false;
OAuthMessage oam = OAuthServlet.getMessage(request, URL);
OAuthValidator oav = new SimpleOAuthValidator();
OAuthConsumer cons = new OAuthConsumer("about:blank#OAuth+CallBack+NotUsed",
oauth_consumer_key, oauth_secret, null);
OAuthAccessor acc = new OAuthAccessor(cons);
try {
base_string = OAuthSignatureMethod.getBaseString(oam);
} catch (Exception e) {
base_string = null;
}
try {
oav.validateMessage(oam,acc);
} catch(Exception e) {
errorMessage = "Launch fails OAuth validation: "+e.getMessage();
return;
}
valid = true;
}
public boolean inArray(final String [] theArray, final String theString)
{
if ( theString == null ) return false;
for ( String str : theArray ) {
if ( theString.equals(str) ) return true;
}
return false;
}
public static Map getStatusUnsupported(String desc)
{
return getStatus(desc, CODE_MAJOR_UNSUPPORTED);
}
public static Map getStatusFailure(String desc)
{
return getStatus(desc, CODE_MAJOR_FAILURE);
}
public static Map getStatusSuccess(String desc)
{
return getStatus(desc, CODE_MAJOR_SUCCESS);
}
public static Map getStatus(String description, String major)
{
Map retval = new LinkedHashMap();
retval.put(STATUS_CODE,major);
retval.put(STATUS_DESCRIPTION,description);
return retval;
}
/* IMS JSON version of Errors - does the complet request - returns the JSON in case
the code above us wants to log it. */
@SuppressWarnings("static-access")
public static String doErrorJSON(HttpServletRequest request,HttpServletResponse response,
IMSJSONRequest json, String message, Exception e)
throws java.io.IOException
{
response.setContentType(APPLICATION_JSON);
Map jsonResponse = new TreeMap();
Map status = null;
if ( json == null ) {
status = IMSJSONRequest.getStatusFailure(message);
} else {
status = json.getStatusFailure(message);
if ( json.base_string != null ) {
jsonResponse.put("base_string", json.base_string);
}
}
jsonResponse.put(IMSJSONRequest.STATUS, status);
if ( e != null ) {
jsonResponse.put("exception", e.getLocalizedMessage());
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
e.printStackTrace(pw);
pw.flush();
sw.flush();
jsonResponse.put("traceback", sw.toString() );
} catch ( Exception f ) {
jsonResponse.put("traceback", f.getLocalizedMessage());
}
}
String jsonText = JSONValue.toJSONString(jsonResponse);
PrintWriter out = response.getWriter();
out.println(jsonText);
return jsonText;
}
/** Unit Tests */
static final String inputTestData = "\n" +
"\n" +
"\n" +
"\n" +
"V1.0 \n" +
"999999123 \n" +
" \n" +
" \n" +
"\n" +
"\n" +
"\n" +
"\n" +
"3124567 \n" +
" \n" +
"\n" +
"\n" +
"en-us \n" +
"A \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" ";
public static void runTest() {
/*
System.out.println("Runnig test.");
IMSJSONRequest pox = new IMSJSONRequest(inputTestData);
System.out.println("Version = "+pox.getHeaderVersion());
System.out.println("Operation = "+pox.getOperation());
Map bodyMap = pox.getBodyMap();
String guid = bodyMap.get("/resultRecord/sourcedGUID/sourcedId");
System.out.println("guid="+guid);
String grade = bodyMap.get("/resultRecord/result/resultScore/textString");
System.out.println("grade="+grade);
String desc = "Message received and validated operation="+pox.getOperation()+
" guid="+guid+" grade="+grade;
String output = pox.getResponseUnsupported(desc);
System.out.println("---- Unsupported ----");
System.out.println(output);
Properties props = new Properties();
props.setProperty("fred","zap");
props.setProperty("sam",IMSPOXRequest.MINOR_IDALLOC);
System.out.println("---- Generate Log Error ----");
output = pox.getResponseFailure(desc,props);
System.out.println("---- Failure ----");
System.out.println(output);
Map theMap = new TreeMap ();
theMap.put("/readMembershipResponse/membershipRecord/sourcedId", "123course456");
List