package com.claresco.tinman.servlet; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import org.apache.abdera.i18n.iri.IRISyntaxException; import org.apache.abdera.i18n.text.InvalidCharacterException; import org.apache.commons.codec.binary.Base64; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import com.claresco.tinman.json.XapiJsonControl; import com.claresco.tinman.json.XapiParseException; import com.claresco.tinman.lrs.XapiActivity; import com.claresco.tinman.lrs.XapiActor; import com.claresco.tinman.lrs.XapiClarescoException; import com.claresco.tinman.lrs.XapiContext; import com.claresco.tinman.lrs.XapiContextActivities; import com.claresco.tinman.lrs.XapiIRI; import com.claresco.tinman.lrs.XapiState; import com.claresco.tinman.lrs.XapiStatement; import com.claresco.tinman.lrs.XapiStatementBatch; import com.claresco.tinman.lrs.XapiStatementResult; import com.claresco.tinman.sql.XapiDataIntegrityException; import com.claresco.tinman.sql.XapiDataNotFoundException; import com.claresco.tinman.sql.XapiSQLControl; import com.google.gson.JsonSyntaxException; /** * @author Rheza * * Description: * Just a trial * * Status: * RED * */ public class XapiServlet extends HttpServlet{ static final long serialVersionUID = 1L; private static final String POST = "POST"; private static final String PUT = "PUT"; private static final String GET = "GET"; private static final String OPTIONS = "OPTIONS"; private static final String CONTENTTYPE = "Content-Type"; private static final String PLAINTEXT = "text/plain"; private static final String HTMLTEXT = "text/html"; private static final String JSON = "application/json"; private static final String UTF8 = "UTF-8"; private ServletContext myServletContext; // The serializer and deserializer private XapiJsonControl myJson; // My connection pool private ConnectionPooling myConnectionPooling; // Generate login and password combination for user private XapiServletSecretKeyGenerator mySecretKeyGenerator; // Logger private XapiServletSimpleErrorLogger myLogger; // Another logger private XapiLogger myOtherLogger; // List of permissions private XapiAccessManager myAccessManager; // List of accepted params for different kind of requests private ArrayList<String> myCredentialsRequestParams; private ArrayList<String> myStatementGetParams; private ArrayList<String> myStateSingleParams; private ArrayList<String> myStateSingleGetParams; private ArrayList<String> myStateMultipleGetParams; private ArrayList<String> myStateMultipleDeleteParams; private ArrayList<String> myActivityProfileSingleParams; private ArrayList<String> myActivityProfileSingleGetParams; private ArrayList<String> myActivityProfileMultipleGetPrams; private ArrayList<String> myAgentProfileSingleParams; private ArrayList<String> myAgentProfileMultipleParams; private ArrayList<String> myAllowedDomainList; private ArrayList<String> myAllowedHeaderList; // Debug mode value is defined in the web.xml private boolean isDebugMode = false; @Override public void init() throws ServletException { super.init(); myJson = new XapiJsonControl(); // Get Servlet Context myServletContext = getServletContext(); // Retrieving information for database connection and initializing connection String myDriverName = myServletContext.getInitParameter("DriverName"); String myURL = myServletContext.getInitParameter("DatabaseServer"); String myUser = myServletContext.getInitParameter("DatabaseLogin"); String myPassword = myServletContext.getInitParameter("DatabasePassword"); String myAcceptedDomain = myServletContext.getInitParameter("AcceptedDomains"); String[] myAcceptedDomainList = myAcceptedDomain.split(","); populateDomainList(myAcceptedDomainList); String theCredentialsListFileName = myServletContext.getInitParameter("CredentialsListFileName"); String theCredentialsListPath = myServletContext.getInitParameter("CredentialsListPath"); XapiCredentialsList theCredentialsList = null; try{ BufferedReader theReader = new BufferedReader(new FileReader(new File(theCredentialsListPath + theCredentialsListFileName))); theCredentialsList = myJson.deserialiCredentialsList(theReader); }catch(FileNotFoundException e){ e.printStackTrace(); } if(theCredentialsList == null){ myAccessManager = new XapiAccessManager(theCredentialsListPath + theCredentialsListFileName); }else{ myAccessManager = new XapiAccessManager(theCredentialsList, theCredentialsListPath + theCredentialsListFileName); } myServletContext.setAttribute("Access Manager", myAccessManager); // check if it is the debug mode from web.xml; if(myServletContext.getInitParameter("debug").equals("yes")){ isDebugMode = true; myAccessManager.setDebugMode(isDebugMode); } myOtherLogger = new XapiLogger(); // Getting the LMS key secret from web.xml getServerKeySecret(); // This will populate the list of accepted params for every request populateCredentialRequestParams(); populateStatementGetParams(); populateStateSingleParams(); populateStateSingleGetParams(); populateStateMultipleDeleteParams(); populateStateMultipleGetParams(); populateActivityProfileSingleParams(); populateActivityProfileSingleGetParams(); populateActivityProfileMultipleGetParams(); populateAgentProfileSingleParams(); populateAgentProfileMultipleParams(); populateHeaderList(); // This is a timer which will maintain the credentials/permissions list from getting // too big maintainCredentialsList(); try{ myConnectionPooling = new ConnectionPooling(myURL, myUser, myPassword, myDriverName); mySecretKeyGenerator = new XapiServletSecretKeyGenerator(); String theLogPath = myServletContext.getInitParameter("LogPath"); String theFileName = myServletContext.getInitParameter("LogFileName"); myLogger = new XapiServletSimpleErrorLogger(theLogPath, theFileName); }catch(SQLException e){ e.printStackTrace(); }catch (ClassNotFoundException e) { e.printStackTrace(); }catch (NoSuchAlgorithmException e) { e.printStackTrace(); }catch (Exception e) { e.printStackTrace(); } myOtherLogger.keepTrack("Servlet initialized"); } @Override public void destroy() { String theList = myJson.serializeCredentialsList(myAccessManager.getCredentialsList()); myAccessManager.saveCredentialsList(theList); myOtherLogger.keepTrack("Servlet destroyed"); super.destroy(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException{ // Can't have super here String methodName = POST; boolean alternateSyntax = false; // For IE8 and IE9 if(req.getParameter("method") != null){ methodName = req.getParameter("method"); alternateSyntax = true; } handleRequest(req, resp, methodName, alternateSyntax); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException{ // Can't have super here String methodName = GET; /** boolean alternateSyntax = false; // For IE8 and IE9 if(req.getParameter("method") != null){ methodName = req.getParameter("method"); alternateSyntax = true; } **/ handleRequest(req, resp, methodName, false); } /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException{ String methodName = PUT; handleRequest(req, resp, methodName, false); } /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doOptions(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { handleCORS(req, resp); } /** private void debugFreakingIE8(HttpServletRequest req){ // For IE8 debugging purposes StringBuffer theStringBuffer = new StringBuffer(); theStringBuffer.append("Request URI : " + req.getRequestURI() +"\n"); theStringBuffer.append("Query String : " + req.getQueryString() +"\n"); Enumeration<String> e = req.getParameterNames(); theStringBuffer.append("the param names :\n"); while(e.hasMoreElements()){ String paramName = e.nextElement(); theStringBuffer.append(paramName + " : " + req.getParameter(paramName) + "\n"); } theStringBuffer.append("\nthe header names :\n"); e = req.getHeaderNames(); while(e.hasMoreElements()){ String headerName = e.nextElement(); theStringBuffer.append(headerName + " : " + req.getHeader(headerName) + "\n"); } try{ theStringBuffer.append("\nThe reader:\n"); theStringBuffer.append(XapiServletUtility.getStringFromReader(req.getReader()) + "\n\n\n"); }catch(IOException e1){ theStringBuffer.append("Having trouble reading from the reader \n"); }catch(XapiServletOperationProblemException e2) { theStringBuffer.append("Having trouble reading from the reader \n"); } myOtherLogger.keepTrack(theStringBuffer.toString()); } **/ /** * * Definition: * Handling request, decide which handler functions are called * * Params: * * */ private void handleRequest(HttpServletRequest req, HttpServletResponse resp, String methodName, boolean alternateSyntax){ Connection conn = null; XapiSQLControl mySQLControl = null; long theLogID = -1; /** // Logging purposes StringBuffer theStringBuffer = new StringBuffer(); theStringBuffer.append("request.getRequstURI() gives :"); theStringBuffer.append(req.getRequestURI() + "\n"); theStringBuffer.append("request.getQueryString() gives :"); theStringBuffer.append(req.getQueryString() + "\n"); theStringBuffer.append("method is :"); theStringBuffer.append(req.getMethod() + "\n"); theStringBuffer.append("Path info : " + req.getPathInfo() + "\n"); myOtherLogger.keepTrack(theStringBuffer.toString()); **/ try { // Getting connection and calling SQL control conn = myConnectionPooling.getConnection(); //conn.setAutoCommit(false); //myOtherLogger.keepTrack("connection gotten succesfully"); // Initialize SQL Control mySQLControl = new XapiSQLControl(conn); // Checking validity of URL checkURL(req, resp); // Getting bit and pieces from the URL String theAPI = getAPI(req); String theAction = getAction(req); // Add some headers to allow cross site requests respondToCORS(req, resp); // create header and parameter map HashMap<String, String> theHeaderAndParameterMap = getHeaderAndParameterMap(req, alternateSyntax); // Set response encoding universally to UTF-8 resp.setCharacterEncoding(UTF8); // Calling appropriate handler function // Basic API if(theAPI.equalsIgnoreCase("basic")){ handleBasicAPI(req, resp, methodName, mySQLControl, theHeaderAndParameterMap); // STATE and ACTIVITIES API }else if(theAPI.equalsIgnoreCase("activities")){ if(XapiServletUtility.checkAction(theAction, "state")){ handleStateAPI(req, resp, methodName, mySQLControl, theHeaderAndParameterMap); }else if(theAction == null){ // Asking to read the activity handleActivityProfileAPI(req, resp, methodName, mySQLControl, theHeaderAndParameterMap); }else if(theAction.equalsIgnoreCase("profile")){ handleActivityProfileAPI(req, resp, methodName, mySQLControl, theHeaderAndParameterMap); } else{ throw new XapiBadURLException("Can't find what you are looking for."); } // STATEMENT API }else if(theAPI.equalsIgnoreCase("statements")){ handleStatementAPI(req, resp, methodName, mySQLControl, theHeaderAndParameterMap); // AGENT PROFILE API }else if(theAPI.equalsIgnoreCase("agents")){ handleAgentProfileAPI(req, resp, methodName, mySQLControl, theHeaderAndParameterMap); }else{ throw new XapiBadURLException("Can't find what you are looking for"); } } catch(IRISyntaxException e){ rollback(conn, resp); theLogID = myLogger.log(e, 400, "IRI Not Valid", req); handleError(resp, 400, "IRI Not Valid", e, theLogID); } catch(InvalidCharacterException e){ rollback(conn, resp); theLogID = myLogger.log(e, 400, "IRI Not Valid", req); handleError(resp, 400, "IRI Not Valid", e, theLogID); } catch(XapiParseException e){ //e.printStackTrace(); rollback(conn, resp); theLogID = myLogger.log(e, e.getErrorCode(), e.getMessage(), req); handleError(resp, e.getErrorCode(), e.getMessage(), e, theLogID); } catch (XapiServletException e){ //e.printStackTrace(); rollback(conn, resp); theLogID = myLogger.log(e, req); handleError(resp, e.getErrorNumber(), e.getMessage(), e, theLogID); } catch (JsonSyntaxException e){ //e.printStackTrace(); rollback(conn, resp); theLogID = myLogger.log(e, 400, "Having trouble parsing", req); handleError(resp, 400, e.getMessage(), e, theLogID); } catch (XapiDataIntegrityException e) { //e.printStackTrace(); rollback(conn, resp); theLogID = myLogger.log(e, req); handleError(resp, e.getErrorCode(), e.getMessage(), e, theLogID); } catch (XapiDataNotFoundException e) { //e.printStackTrace(); rollback(conn, resp); theLogID = myLogger.log(e, req); handleError(resp, e.getErrorCode(), e.getMessage(), e, theLogID); } catch(XapiClarescoException e){ //e.printStackTrace(); rollback(conn, resp); theLogID = myLogger.log(e, req); handleError(resp, e.getErrorCode(), e.getMessage(), e, theLogID); } catch (SQLException e) { //e.printStackTrace(); rollback(conn, resp); theLogID = defaultLog(e, req); handleError(resp, 500, e.getMessage(), e, theLogID); myOtherLogger.logBug("SQL went wrong", e); } catch (Exception e) { //e.printStackTrace(); rollback(conn, resp); theLogID = defaultLog(e, req); handleError(resp, 500, e.getMessage(), e, theLogID); //Log as much as possible StringBuffer theBuffer = new StringBuffer(); theBuffer.append("Something went wrong\n"); theBuffer.append("request.getRequstURI() gives :"); if(req.getRequestURI() != null){ theBuffer.append(req.getRequestURI() + "\n"); } theBuffer.append("request.getQueryString() gives :"); if(req.getQueryString() != null){ theBuffer.append(req.getQueryString() + "\n"); } theBuffer.append("method is :"); if(req.getMethod() != null){ theBuffer.append(req.getMethod() + "\n"); } theBuffer.append("Path info : " + req.getPathInfo() + "\n"); theBuffer.append("Reading from the request's reader gives :\n"); try{ theBuffer.append(XapiServletUtility.getStringFromReader( XapiServletUtility.getReader(req))); }catch(XapiServletOperationProblemException excpt){ theBuffer.append("UNABLE to read from the reader"); } theBuffer.append("iterating through parameter names gives :\n"); Enumeration<String> paramNames = req.getParameterNames(); while(paramNames.hasMoreElements()){ String paramName = paramNames.nextElement(); theBuffer.append(paramName + " : " + req.getParameter(paramName) + "\n"); } theBuffer.append("\nthe header names :\n"); Enumeration<String> headerNames = req.getHeaderNames(); while(headerNames.hasMoreElements()){ String headerName = headerNames.nextElement(); theBuffer.append(headerName + " : " + req.getHeader(headerName) + "\n"); } myOtherLogger.logBug(theBuffer.toString(), e); } finally{ // Always close/release the connection //try{ // conn.commit(); //}catch(SQLException excpt){ //} XapiServletUtility.closeConnection(conn); XapiServletUtility.closeSQLControl(mySQLControl); } } /** * * Definition: * * * Params: * * */ private HashMap<String, String> getHeaderAndParameterMap(HttpServletRequest req, boolean alternateSyntax) throws XapiServletOperationProblemException, XapiBadParamException{ HashMap<String, String> theHeaderAndParameterMap = new HashMap<String, String>(); if(!alternateSyntax){ StringBuffer theBuffer = new StringBuffer(); Enumeration<String> e = req.getHeaderNames(); while(e.hasMoreElements()){ String headerName = e.nextElement(); theBuffer.append(headerName + " : "); theHeaderAndParameterMap.put(headerName, req.getHeader(headerName)); theBuffer.append(req.getHeader(headerName) + "\n"); } BufferedReader theReader = XapiServletUtility.getReader(req); String theContent = XapiServletUtility.getStringFromReader(theReader); theHeaderAndParameterMap.put("content", theContent); theBuffer.append("content : " + theContent + "\n"); e = req.getParameterNames(); while(e.hasMoreElements()){ String paramName = e.nextElement(); theBuffer.append(paramName + " : "); theHeaderAndParameterMap.put(paramName, req.getParameter(paramName)); theBuffer.append(req.getParameter(paramName) + "\n"); } //myOtherLogger.keepTrack(theBuffer.toString()); }else{ // Uses alternate syntax, this is to support IE8 and IE9 String theRequestBody = XapiServletUtility.getStringFromReader(XapiServletUtility.getReader(req)); if(theRequestBody != null){ //myOtherLogger.keepTrack("IE8 body : " + theRequestBody); if(!theRequestBody.isEmpty()){ String[] theHeadersAndParams = theRequestBody.split("&"); for(String theEntry : theHeadersAndParams){ String[] theKeyAndValue = theEntry.split("="); if(theKeyAndValue.length == 2){ try{ String theKey = URLDecoder.decode(theKeyAndValue[0], "UTF-8"); String theValue = URLDecoder.decode(theKeyAndValue[1], "UTF-8"); theHeaderAndParameterMap.put(theKey, theValue); }catch(UnsupportedEncodingException e){ throw new XapiServletOperationProblemException("Having trouble reading the request"); } }else{ throw new XapiBadParamException("Something wrong with the body of the message"); } } } }else{ //The request body is null throw new XapiBadParamException("Request body not supposed to be null"); } } return theHeaderAndParameterMap; } /** * * Definition: * Handler for Statement API * * Params: * * */ private void handleStatementAPI(HttpServletRequest req, HttpServletResponse resp, String theMethod, XapiSQLControl theSQLControl, HashMap<String, String> theHeaderAndParameterMap) throws XapiServletException, SQLException, XapiClarescoException{ // Verify that client has basic key secret verifyClientCredentials(theHeaderAndParameterMap); PrintWriter out = null; String theAction = getAction(req); // URL is bad if(theAction != null){ throw new XapiBadURLException("Cannot find what you are looking for"); } // Get client credentials/permissions XapiCredentials theClientCredentials = getClientCredentials(theHeaderAndParameterMap); XapiActor theActor = null; // timestamp's default is now DateTime theTimestamp = DateTime.now(); ArrayList<XapiIRI> theActivityID = new ArrayList<XapiIRI>(); UUID theRegistration = null; boolean isDefiningAllowed = false; // POST method if(theMethod.equals(POST)){ // If it is a batch of statement, if it is not, it will return an array // that contains one statement only XapiStatementBatch theStatementBatch = myJson.deserializeStatementBatch( theHeaderAndParameterMap.get("content")); ArrayList<String> theIDArray = new ArrayList<String>(); for(XapiStatement s : theStatementBatch){ // This part needs to be changed if the scope of the project is expanded theActor = s.getActor(); theActivityID = fillUpActivityIDs(s, theActivityID); // This is to help check permission XapiServletActionRequested theActionRequested = new XapiServletActionRequested( XapiServletActionType.STATEMENTWRITE, theActor, theTimestamp, theActivityID, theRegistration); // Check if this is permissible verifyPermission(theClientCredentials, theActionRequested); if(!myAccessManager.isDebugMode()){ isDefiningAllowed = theClientCredentials.isDefiningAllowed(); }else{ isDefiningAllowed = true; } theSQLControl.insertNewStatement(s, isDefiningAllowed, true); theIDArray.add(s.getId()); } sendOK(resp); resp.setHeader(CONTENTTYPE, JSON); out = XapiServletUtility.getWriter(resp); out.print(XapiServletUtility.createJsonArray(theIDArray)); }else if(theMethod.equals(GET)){ // GET Method verifyParams(theHeaderAndParameterMap, myStatementGetParams, "retrieving statements"); // Get the actor String theAgent = theHeaderAndParameterMap.get("agent"); if(theAgent != null){ theActor = myJson.deserializeActor(theHeaderAndParameterMap.get("agent")); } // Get the activityId String theActvString = theHeaderAndParameterMap.get("activity"); if(theActvString != null){ theActivityID.add(new XapiIRI(theActvString)); } // Get registration String theRegistrationString = theHeaderAndParameterMap.get("registration"); if(theRegistrationString != null){ theRegistration = XapiServletUtility.validateUUID(theRegistrationString); } // How do I know when they want to read any or just mine? XapiServletActionRequested theActionRequested = new XapiServletActionRequested( XapiServletActionType.STATEMENTREADMINE, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); // This is the map of all the parameters HashMap<String, String> myParamMap = new HashMap<String, String>(); // List of all the accepted param names String[] paramNames = new String[]{"statementId", "voidedStatementId", "agent", "verb", "activity", "since", "until"}; for(String s : paramNames){ if (theHeaderAndParameterMap.get(s) != null) { if(s.equals("agent")){ int theActorID = theSQLControl.retrieveActorID(theActor); myParamMap.put(s, String.valueOf(theActorID)); }else{ myParamMap.put(s, theHeaderAndParameterMap.get(s)); } } } // The function will take care of retrieving the statements from the database HashMap<Integer, XapiStatement> theResultMap = theSQLControl.retrieveStatements(myParamMap); if(theResultMap != null && !theResultMap.isEmpty()){ XapiStatementBatch theStatementBatch = createStatementBatch(theResultMap); XapiStatementResult theStatementResult = new XapiStatementResult(theStatementBatch); sendOK(resp); resp.setHeader(CONTENTTYPE, JSON); out = XapiServletUtility.getWriter(resp); out.print(myJson.serializeStatementResult(theStatementResult)); }else{ handleError(resp, 404, "Statements not found"); } // PUT Method }else if(theMethod.equals(PUT)){ XapiStatement theStatement = myJson.deserializeStatement(theHeaderAndParameterMap.get("content")); // This verifies all the parameters /** for(Enumeration<String> paramNames = req.getParameterNames(); paramNames.hasMoreElements();){ String paramName = paramNames.nextElement(); if(!paramName.equals("statementId")){ throw new XapiBadParamException(paramName + " not accepted"); } } **/ // If the statementId is specified, set the statement to that id String theStatementID = theHeaderAndParameterMap.get("statementId"); if(theStatementID != null){ theStatement.setID(theStatementID); }else{ throw new XapiRequiredParameterNotFoundException("need statementId parameter"); } theActor = theStatement.getActor(); theActivityID = fillUpActivityIDs(theStatement, theActivityID); XapiServletActionRequested theActionRequested = new XapiServletActionRequested( XapiServletActionType.STATEMENTWRITE, theActor, theTimestamp, theActivityID, theRegistration); // Check if this is permissible verifyPermission(theClientCredentials, theActionRequested); if(!myAccessManager.isDebugMode()){ isDefiningAllowed = theClientCredentials.isDefiningAllowed(); }else{ isDefiningAllowed = true; } theSQLControl.insertNewStatement(theStatement, isDefiningAllowed, false); sendNoContent(resp); }else{ throw new XapiAPIMethodNotSupportedException("Basic API does not support this method : " + theMethod); } } /** * * Definition: * Handler for Basic API which is mainly for requesting client's permission * * Params: * * */ private void handleBasicAPI(HttpServletRequest req, HttpServletResponse resp, String theMethod, XapiSQLControl theSQLControl, HashMap<String, String> theHeaderAndParameterMap) throws XapiServletException{ PrintWriter out = null; String theAction = getAction(req); if(XapiServletUtility.checkAction(theAction, "request")){ // If LMS is authorized verifyLMSCredentials(theHeaderAndParameterMap); if(theMethod.equals(PUT) || theMethod.equals(POST)){ // Check for invalid params verifyParams(theHeaderAndParameterMap, myCredentialsRequestParams); XapiKeySecret theKeySecret = generateClientCredentials(theHeaderAndParameterMap.get("content")); out = XapiServletUtility.getWriter(resp); out.print(myJson.createKeySecretJson(theKeySecret)); resp.setContentType(JSON); sendOK(resp); //myOtherLogger.keepTrack("Credentials sent"); }else{ throw new XapiAPIMethodNotSupportedException("Basic API does not support this method"); } /** }else if(XapiServletUtility.checkAction(theAction, "debug")){ if(theMethod.equals(POST)){ verifyLMSCredentials(theHeaderAndParameterMap); String theValue = theHeaderAndParameterMap.get("debugMode"); if(theValue.equalsIgnoreCase("on")){ isDebugMode = true; isEpicDebugMode = true; } else if(theValue.equalsIgnoreCase("off")){ isDebugMode = false; isEpicDebugMode = false; }else{ throw new XapiBadParamException("value of param debugMode is not accepted"); } sendNoContent(resp); }else{ throw new XapiAPIMethodNotSupportedException("Basic API does not support this method"); } **/ }else{ throw new XapiBadURLException("Cannot find what you are looking for"); } } /** * * Definition: * Handler for the state API * * Params: * * */ private void handleStateAPI(HttpServletRequest req, HttpServletResponse resp, String theMethod, XapiSQLControl theSQLControl, HashMap<String, String> theHeaderAndParameterMap) throws XapiServletException, SQLException, XapiClarescoException{ PrintWriter out = null; String theAction = getAction(req); verifyClientCredentials(theHeaderAndParameterMap); // Retrieve client credentials XapiCredentials theClientCredentials = getClientCredentials(theHeaderAndParameterMap); // Default values XapiActor theActor = null; DateTime theTimestamp = DateTime.now(); XapiIRI theActivityID = null; UUID theRegistration = null; XapiServletActionRequested theActionRequested = null; // PUT and POST method if(theMethod.equals(PUT) || theMethod.equals(POST)){ if(XapiServletUtility.checkAction(theAction, "state")){ // If this is not called before verifyParams, its gonna get messy String theResult = theHeaderAndParameterMap.get("content"); // Check for invalid params verifyParams(theHeaderAndParameterMap, myStateSingleParams); // Getting all the parameters String theStateID = theHeaderAndParameterMap.get("stateId"); String theActvID = theHeaderAndParameterMap.get("activityId"); String theActorString = theHeaderAndParameterMap.get("agent"); if(theActorString != null){ theActor = myJson.deserializeActor(theActorString); } String theStateRegistration = theHeaderAndParameterMap.get("registration"); // Check if any of the required parameters is missing if(theStateID == null || theActvID == null || theActor == null){ throw new XapiRequiredParameterNotFoundException("Missing the required params"); } theActivityID = new XapiIRI(theActvID); if(theStateRegistration != null){ theRegistration = XapiServletUtility.validateUUID(theStateRegistration); } XapiState theState = new XapiState(theStateID, theActvID, theActor, theStateRegistration, theResult); // To help with checking permission theActionRequested = new XapiServletActionRequested(XapiServletActionType.STATEWRITE, theActor, theTimestamp, theActivityID, theRegistration); // Check if this is permissible verifyPermission(theClientCredentials, theActionRequested); theSQLControl.insertState(theState); sendNoContent(resp); }else{ throw new XapiBadURLException("Cannot find what you are looking for"); } }else if(theMethod.equals(GET)){ try{ verifyParams(theHeaderAndParameterMap, myStateSingleGetParams, "single GET request"); // Getting all the params String theStateID = theHeaderAndParameterMap.get("stateId"); String theActvID = theHeaderAndParameterMap.get("activityId"); String theAgentParameter = theHeaderAndParameterMap.get("agent"); // Check if required parameter exists if(theStateID == null || theActvID == null || theAgentParameter == null){ throw new XapiRequiredParameterNotFoundException("One of the required params not found"); } theActor = myJson.deserializeActor(theAgentParameter); theActivityID = new XapiIRI(theActvID); String theStateRegistration = theHeaderAndParameterMap.get("registration"); if(theStateRegistration != null){ theRegistration = XapiServletUtility.validateUUID(theStateRegistration); } theActionRequested = new XapiServletActionRequested(XapiServletActionType.STATEREAD, theActor, theTimestamp, theActivityID, theRegistration); // Check permission verifyPermission(theClientCredentials, theActionRequested); String theDocument; if(theRegistration != null){ theDocument = theSQLControl.retrieveState(theActvID, theActor, theStateID, theStateRegistration); }else{ theDocument = theSQLControl.retrieveState(theActvID, theActor, theStateID); } // Check if there is such document if(theDocument != null){ out = XapiServletUtility.getWriter(resp); out.print(theDocument); resp.setContentType(JSON); sendOK(resp); }else{ // or should we throw an exception instead? handleError(resp, 404, "Document not found"); //sendNoContent(resp); } }catch(XapiBadParamException e){ out = XapiServletUtility.getWriter(resp); handleMultipleGetState(req, resp, theClientCredentials, theSQLControl, out, theHeaderAndParameterMap); } }else{ throw new XapiAPIMethodNotSupportedException("State API does not have this method"); } } /** * * Definition: * Helper method to handle Multiple GET request for State API * * Params: * * */ private void handleMultipleGetState(HttpServletRequest req, HttpServletResponse resp, XapiCredentials theClientCredentials, XapiSQLControl theSQLControl, PrintWriter out, HashMap<String, String> theHeaderAndParameterMap) throws XapiServletException, SQLException, XapiClarescoException{ verifyParams(theHeaderAndParameterMap, myStateMultipleGetParams, "multiple get request"); // Get the params String theActvID = theHeaderAndParameterMap.get("activityId"); String theAgentParam = theHeaderAndParameterMap.get("agent"); XapiActor theActor = null; if(theAgentParam != null){ theActor = myJson.deserializeActor(theAgentParam); } String theStateRegistration = theHeaderAndParameterMap.get("registration"); String theStringTS = theHeaderAndParameterMap.get("since"); // Check if any of the required params is missing if(theActvID == null || theActor == null){ throw new XapiRequiredParameterNotFoundException("either the activityId or the agent is missing"); } XapiIRI theActivityID = new XapiIRI(theActvID); UUID theRegistration = null; if(theStateRegistration != null){ theRegistration = XapiServletUtility.validateUUID(theStateRegistration); } DateTime theSince = null; if(theStringTS != null){ DateTimeFormatter theFormatter = ISODateTimeFormat.dateTimeParser(); try{ theSince = theFormatter.parseDateTime(theStringTS); }catch(IllegalArgumentException exc){ throw new XapiServletOperationProblemException("Having trouble parsing the timestamp"); } } HashMap<String, String> result; DateTime theTimestamp = DateTime.now(); XapiServletActionRequested theActionRequested = new XapiServletActionRequested(XapiServletActionType.STATEREAD, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); // Case 1 : requests include registration and since if(theStateRegistration != null && theStringTS != null){ result = theSQLControl.retrieveMultipleState(theActvID, theActor, theStateRegistration, theSince); }else if(theStateRegistration == null && theStringTS == null){ // Case 2 : requests do not include registration and since result = theSQLControl.retrieveMultipleState(theActvID, theActor); }else if(theStringTS == null){ // Case 3 : requests only include registration result = theSQLControl.retrieveMultipleState(theActvID, theActor, theStateRegistration); }else{ // Case 4 : requests only include since result = theSQLControl.retrieveMultipleState(theActvID, theActor, theSince); } // Throw an exception instead if(result == null){ handleError(resp, 404, "Document not found"); }else{ resp.setContentType(JSON); out.print(XapiServletUtility.createJsonArray(result.keySet())); } } /** * * Definition: * Handling request as defined under Activity Profile API * * Params: * * */ private void handleActivityProfileAPI(HttpServletRequest req, HttpServletResponse resp, String theMethod, XapiSQLControl theSQLControl, HashMap<String, String> theHeaderAndParameterMap) throws XapiServletException, SQLException, XapiClarescoException{ PrintWriter out = null; String theAction = getAction(req); // Verify Client Login and Password verifyClientCredentials(theHeaderAndParameterMap); XapiCredentials theClientCredentials = getClientCredentials(theHeaderAndParameterMap); XapiActor theActor = null; DateTime theTimestamp = DateTime.now(); XapiIRI theActivityID = null; UUID theRegistration = null; XapiServletActionRequested theActionRequested= null; if(theAction == null){ // GET if(theMethod.equals(GET)){ ArrayList<String> acceptableParams = new ArrayList<String>(); acceptableParams.add("activityId"); // Check if all params are accepted verifyParams(theHeaderAndParameterMap, acceptableParams); String theActvID = theHeaderAndParameterMap.get("activityId"); if(!myAccessManager.isDebugMode()){ theActor = theClientCredentials.getActor(); } // To help checking permission theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEREAD, theActor, theTimestamp, new XapiIRI(theActvID), theRegistration); // Check permission verifyPermission(theClientCredentials, theActionRequested); // Retrieve activity XapiActivity theActv = theSQLControl.retrieveActivity(theActvID); // Throw an error instead??? if(theActv == null){ handleError(resp, 404, "Activity not found"); }else{ // Serialize the activity String myActivityJson = myJson.serializeActivity(theActv); sendOK(resp); resp.setHeader(CONTENTTYPE, JSON); out = XapiServletUtility.getWriter(resp); out.println(myActivityJson); } }else{ throw new XapiBadURLException("Can't find what you are looking for"); } }else if(theAction.equals("profile")){ // PUT and POST if(theMethod.equals(PUT) || theMethod.equals(POST)){ // If this is not called before verifyParams, it will not behave as we want it. String theDocument = theHeaderAndParameterMap.get("content"); verifyParams(theHeaderAndParameterMap, myActivityProfileSingleParams); String theActvID = theHeaderAndParameterMap.get("activityId"); if(!myAccessManager.isDebugMode()){ theActor = theClientCredentials.getActor(); } if(theActvID != null){ theActivityID = new XapiIRI(theActvID); } theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEWRITE, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); String theProfileID = theHeaderAndParameterMap.get("profileId"); if(theActvID == null || theProfileID == null){ throw new XapiRequiredParameterNotFoundException("Missing required params"); } theSQLControl.insertActivityProfile(theActvID, theProfileID, theDocument); sendNoContent(resp); } else if(theMethod.equals(GET)){ // GET try{ verifyParams(theHeaderAndParameterMap, myActivityProfileSingleGetParams); String theActvID = theHeaderAndParameterMap.get("activityId"); String theProfileID = theHeaderAndParameterMap.get("profileId"); // If any of the required params is missing, the request could be a multiple get request if(theActvID == null || theProfileID == null){ throw new XapiRequiredParameterNotFoundException("Missing required params"); } if(!myAccessManager.isDebugMode()){ theActor = theClientCredentials.getActor(); } theActivityID = new XapiIRI(theActvID); theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEREAD, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); String theDocument = theSQLControl.retrieveActivityProfile(theActvID, theProfileID); out = XapiServletUtility.getWriter(resp); if(theDocument != null){ sendOK(resp); resp.setContentType(JSON); out.println(theDocument); }else{ handleError(resp, 404, "Document not found"); } }catch(XapiBadParamException e){ // If exception is thrown, this request could be a multiple get request verifyParams(theHeaderAndParameterMap, myActivityProfileMultipleGetPrams, "multiple get request"); // Get all params String theActvID = theHeaderAndParameterMap.get("activityId"); String theStringTS = theHeaderAndParameterMap.get("since"); // Make sure activity ID not null if(theActvID == null){ throw new XapiRequiredParameterNotFoundException("Activity ID can't be null"); } if(!myAccessManager.isDebugMode()){ theActor = theClientCredentials.getActor(); } theActivityID = new XapiIRI(theActvID); theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEREAD, theActor, theTimestamp, theActivityID, theRegistration); // Verifying that the request is permissible verifyPermission(theClientCredentials, theActionRequested); HashMap<String, String> result; // If there is no since param if(theStringTS == null){ result = theSQLControl.retrieveMultipleActivityProfile(theActvID); // If there is }else{ DateTimeFormatter theFormatter = ISODateTimeFormat.dateTimeParser(); try{ DateTime myTimeStamp = theFormatter.parseDateTime(theStringTS); result = theSQLControl.retrieveMultipleActivityProfile(theActvID, myTimeStamp); }catch(IllegalArgumentException exception){ //exception.printStackTrace(); defaultLog(exception, req); throw new XapiServletOperationProblemException("Having trouble parsing the timestamp." + "Perhaps you should check it again"); } } if(result != null){ out = XapiServletUtility.getWriter(resp); out.print(XapiServletUtility.createJsonArray(result.keySet())); resp.setContentType(JSON); }else{ handleError(resp, 404, "Documents not found"); } } }else{ throw new XapiBadURLException("I do not know what you want"); } } } /** * * Definition: * Method to handle Agent Profile API * * Params: * * */ private void handleAgentProfileAPI(HttpServletRequest req, HttpServletResponse resp, String theMethod, XapiSQLControl theSQLControl, HashMap<String, String> theHeaderAndParameterMap) throws XapiServletException, XapiClarescoException, SQLException{ PrintWriter out = null; out = XapiServletUtility.getWriter(resp); String theAction = getAction(req); // Verify Client Login and Password verifyClientCredentials(theHeaderAndParameterMap); XapiCredentials theClientCredentials = getClientCredentials(theHeaderAndParameterMap); XapiActor theActor = null; DateTime theTimestamp = DateTime.now(); XapiIRI theActivityID = null; UUID theRegistration = null; XapiServletActionRequested theActionRequested= null; if(theAction == null){ }else if(theAction.equals("profile")){ // PUT and POST if(theMethod.equals(POST) || theMethod.equals(PUT)){ String theDocument = theHeaderAndParameterMap.get("content"); verifyParams(theHeaderAndParameterMap, myAgentProfileSingleParams); String theAgentParam = theHeaderAndParameterMap.get("agent"); if(theAgentParam != null){ theActor = myJson.deserializeActor(theAgentParam); } String theProfileID = theHeaderAndParameterMap.get("profileId"); if(theAgentParam == null || theProfileID == null){ throw new XapiRequiredParameterNotFoundException("agent and profileid can't be null"); } theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEWRITE, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); theSQLControl.insertNewAgentProfile(theActor, theProfileID, theDocument); sendNoContent(resp); // GET Method }else if(theMethod.equals(GET)){ try{ verifyParams(theHeaderAndParameterMap, myAgentProfileSingleParams); String theActorString = theHeaderAndParameterMap.get("agent"); if(theActorString != null){ theActor = myJson.deserializeActor(theActorString); } String theProfileID = theHeaderAndParameterMap.get("profileId"); if(theActor == null || theProfileID == null){ throw new XapiRequiredParameterNotFoundException("either agent or profileId is missing"); } theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEREAD, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); String theResult = theSQLControl.retrieveSingleAgentProfile(theActor, theProfileID); if(theResult == null){ handleError(resp, 404, "Document not found"); }else { out = XapiServletUtility.getWriter(resp); out.println(theResult); resp.setContentType(JSON); } }catch(XapiBadParamException e){ verifyParams(theHeaderAndParameterMap, myAgentProfileMultipleParams); String theAgentString = theHeaderAndParameterMap.get("agent"); String theStringTS = theHeaderAndParameterMap.get("since"); if(theAgentString == null){ throw new XapiRequiredParameterNotFoundException("can't find the required parameter : agent"); } theActor = myJson.deserializeActor(theAgentString); theActionRequested = new XapiServletActionRequested(XapiServletActionType.PROFILEREAD, theActor, theTimestamp, theActivityID, theRegistration); verifyPermission(theClientCredentials, theActionRequested); HashMap<String, String> theResult; // If there is no since param if(theStringTS == null){ theResult = theSQLControl.retrieveMultipleAgentProfile(theActor); // If there is }else{ DateTimeFormatter theFormatter = ISODateTimeFormat.dateTimeParser(); try{ DateTime myTimeStamp = theFormatter.parseDateTime(theStringTS); theResult = theSQLControl.retrieveMultipleAgentProfile(theActor, myTimeStamp); }catch(IllegalArgumentException exc){ //exc.printStackTrace(); defaultLog(exc, req); throw new XapiServletOperationProblemException("Having trouble parsing your timestamp"); } } if(theResult != null){ out = XapiServletUtility.getWriter(resp); out.print(XapiServletUtility.createJsonArray(theResult.keySet())); resp.setContentType(JSON); }else{ handleError(resp, 404, "Documents not found"); } } } } } /** * * Definition: * This is to verify if the client has permission to proceed with request * * Params: * * */ private void verifyPermission(XapiCredentials theCredentials , XapiServletActionRequested theAction) throws XapiForbiddenException{ // If it is not any debug mode if(!myAccessManager.isDebugMode()){ if(!(theCredentials instanceof XapiLMSCredentials) && !theCredentials.isActionRequestedAllow(theAction)){ myOtherLogger.logThreats("User try something fancy"); throw new XapiForbiddenException("Nice try, punk! You are not allowed to do so"); } } } /** * * Definition: * Handle cross domain request * * Params: * * */ private void handleCORS(HttpServletRequest req, HttpServletResponse resp){ String theOriginURL = XapiServletUtility.getOriginURL(req); String theMethodName = req.getHeader("Access-Control-Request-Method"); String theHeaderRequested = req.getHeader("Access-Control-Request-Headers"); String headersToBeAllowed = XapiServletUtility.createHeaderString(myAllowedHeaderList); if(!myAllowedHeaderList.contains(theHeaderRequested)){ headersToBeAllowed += "," + theHeaderRequested; } String methodToBeAllowed = POST + "," + PUT + "," + GET; if(myAllowedDomainList.contains(theOriginURL)){ resp.setHeader("Access-Control-Allow-Origin", theOriginURL); resp.setHeader("Access-Control-Allow-Methods", theMethodName); resp.setHeader("Access-Control-Allow-Headers", headersToBeAllowed); } resp.setHeader("Vary", "Origin"); resp.setIntHeader("Access-Control-Max-Age", 17280); } /** * * Definition: * Helper method to respond to CORS * * Params: * * */ private boolean checkCORSPermission(HttpServletRequest req, HttpServletResponse resp){ String theOriginURL = XapiServletUtility.getOriginURL(req); return myAllowedDomainList.contains(theOriginURL); } /** * * Definition: * Helper method to respond to CORS * * Params: * * */ private void addCORSResponse(HttpServletRequest req, HttpServletResponse resp){ String theOriginURL = XapiServletUtility.getOriginURL(req); resp.setHeader("Access-Control-Allow-Origin", theOriginURL); } /** * * Definition: * Helper method to respond to CORS * * Params: * * */ private void respondToCORS(HttpServletRequest req, HttpServletResponse resp){ if(checkCORSPermission(req, resp)){ addCORSResponse(req, resp); } } private void handleError(HttpServletResponse resp, int errorNumber, String theMessage, Exception exc, long longID){ try{ if(myAccessManager.isDebugMode()){ //resp.sendError(errorNumber, theMessage); resp.setContentType("text/plain"); resp.setStatus(errorNumber); PrintWriter out = resp.getWriter(); out.print("Log ID : " + longID + "\n"); exc.printStackTrace(out); }else{ handleError(resp, errorNumber, theMessage); } }catch(Exception e){ } } /** * * Definition: * Handling error, if an exception is thrown * * Params: * * */ private void handleError(HttpServletResponse resp, int errorNumber, String theMessage){ try { resp.setContentType(PLAINTEXT); resp.setStatus(errorNumber); PrintWriter out = XapiServletUtility.getWriter(resp); out.print(theMessage); } catch (Exception e) { } } private void handleError(HttpServletResponse resp, int errorNumber){ try { resp.setContentType(PLAINTEXT); resp.setStatus(errorNumber); PrintWriter out = XapiServletUtility.getWriter(resp); out.print(errorNumber); } catch (Exception e) { } } /** * * Definition: * Sending an OK (200 status) * * Params: * * */ private void sendOK(HttpServletResponse resp){ resp.setStatus(200); } /** * * Definition: * Sending a 204 * * Params: * * */ private void sendNoContent(HttpServletResponse resp){ resp.setStatus(204); } /** * * Definition: * This function will check if the LMS is authorized to do so * If not throw and exception * * Params: * * */ private void verifyLMSCredentials(HashMap<String, String> theHeaderAndParameterMap) throws XapiNotAuthorizedException, XapiServletOperationProblemException{ if(!doesLMSCredentialsExists(theHeaderAndParameterMap)){ throw new XapiNotAuthorizedException("LMS is not authorized to do so"); } } /** * * Definition: * This function will check if the client is authorized * If not throw and exception * * Params: * * */ private void verifyClientCredentials(HashMap<String, String> theHeaderAndParameterMap) throws XapiNotAuthorizedException, XapiServletOperationProblemException{ if(!myAccessManager.isDebugMode()){ if(!doesClientCredentialExists(theHeaderAndParameterMap) && !doesLMSCredentialsExists(theHeaderAndParameterMap)){ myOtherLogger.logThreats("User try something fancy"); throw new XapiNotAuthorizedException("Client not authorized to do so"); } } } /** * * Definition: * Check if the LMS is using the correct key-secret combination * * Params: * * */ private boolean doesLMSCredentialsExists(HashMap<String, String> theHeaderAndParameterMap) throws XapiServletOperationProblemException{ // In the header, the format has to be 'login:password' String[] theLoginInfo = handleAuthorizationHeader(theHeaderAndParameterMap); return doesLMSCredentialsExists(theLoginInfo); } private boolean doesLMSCredentialsExists(String[] theLoginInfo){ if(!myAccessManager.isDebugMode()){ if(theLoginInfo == null){ return false; } // Length has to be 2 if(theLoginInfo.length != 2){ return false; } return myAccessManager.containServerKeySecret(new XapiKeySecret(theLoginInfo[0], theLoginInfo[1])); }else{ return true; } } /** * * Definition: * Check if the client is using an existing key-secret combination * * Params: * * */ private boolean doesClientCredentialExists(HashMap<String, String> theHeaderAndParameterMap) throws XapiServletOperationProblemException{ if(!myAccessManager.isDebugMode()){ String[] theLoginInfo = handleAuthorizationHeader(theHeaderAndParameterMap); // There has to be authorization header if(theLoginInfo == null){ return false; } // Length has to be 2 if(theLoginInfo.length != 2){ return false; } XapiKeySecret theKeySecret = new XapiKeySecret(theLoginInfo[0], theLoginInfo[1]); if(myAccessManager.containsClientCredentials(theKeySecret)){ myAccessManager.addLastAccessedTime(theKeySecret, DateTime.now()); return true; } return false; }else{ return true; } } /** * * Definition: * Getting client credentials from the HTTPServletRequest * * Params: * * */ private XapiCredentials getClientCredentials(HashMap<String, String> theHeaderAndParameterMap) throws XapiServletSecurityRiskException, XapiServletOperationProblemException{ if(myAccessManager.isDebugMode()){ return new XapiCredentials(myAccessManager.isDebugMode()); } String[] theLoginInfo = handleAuthorizationHeader(theHeaderAndParameterMap); if(theLoginInfo == null){ throw new XapiServletSecurityRiskException("No authorization header"); } if(doesLMSCredentialsExists(theLoginInfo)){ return new XapiLMSCredentials(); } return myAccessManager.getCredential(new XapiKeySecret(theLoginInfo[0], theLoginInfo[1])); } /** * * Definition: * Helper method to get key secret passed on as Authorization header * * Params: * * */ private String[] handleAuthorizationHeader(HashMap<String, String> theHeaderAndParameterMap) throws XapiServletOperationProblemException{ String theAuthorizationHeader = theHeaderAndParameterMap.get("authorization"); if(theAuthorizationHeader == null){ theAuthorizationHeader = theHeaderAndParameterMap.get("Authorization"); } if(theAuthorizationHeader == null){ return null; } theAuthorizationHeader = theAuthorizationHeader.trim(); if(!theAuthorizationHeader.startsWith("Basic")){ return null; } String temp = theAuthorizationHeader.substring(5); temp = temp.trim(); try{ temp = XapiServletUtility.decodeBase64(temp); }catch(UnsupportedEncodingException e){ throw new XapiServletOperationProblemException("Can't decode the message"); } String[] theLoginInfo = temp.split(":"); return theLoginInfo; } /** * * Definition: * Assuming that the second string in the array is "xapi" * * Params: * * */ private boolean isURLSupported(String[] urlArray){ // Too short if(urlArray.length < 2){ return false; } // Too long if(urlArray.length > 3){ return false; } // does not have keyword 'xapi' if(!urlArray[0].equalsIgnoreCase("xapi")){ return false; } return true; } /** * * Definition: * Checking if URL is valid * * Params: * * */ private void checkURL(HttpServletRequest req, HttpServletResponse resp) throws XapiBadURLException{ String[] urlArray = XapiServletUtility.getRequestURLArray(req); if (!isURLSupported(urlArray)){ throw new XapiBadURLException("We do not support that URL"); } } /** * * Definition: * Get the API from the URL * * Params: * * */ private String getAPI(HttpServletRequest req){ return XapiServletUtility.getRequestURLArray(req)[1]; } /** * * Definition: * Get the string after the API, we call it action here * * Params: * * */ private String getAction(HttpServletRequest req){ String[] urlArray = XapiServletUtility.getRequestURLArray(req); if(urlArray.length == 2){ return null; } return urlArray[2]; } /** * * Definition: * Getting Accepted KeySecret for LMS * * Params: * * */ private void getServerKeySecret(){ String theKey = myServletContext.getInitParameter("LMSLogin"); String theSecret = myServletContext.getInitParameter("LMSPassword"); myAccessManager.addServerKeySecret(new XapiKeySecret(theKey, theSecret)); } /** * * Definition: * Generate client key secret * * Params: * * */ private XapiKeySecret generateClientCredentials(BufferedReader theReader) throws XapiParseException, XapiServletOperationProblemException{ StringBuilder theBuilder = new StringBuilder(); String line; try{ // Need this to turn the request into json while ((line = theReader.readLine()) != null) { theBuilder.append(line).append('\n'); } return generateClientCredentials(theBuilder.toString()); }catch(IOException e){ myOtherLogger.logBug("Credentials problem", e); throw new XapiServletOperationProblemException("Having problem reading the request"); } } /** * * Definition: * Generate client key secret * * Params: * * */ private XapiKeySecret generateClientCredentials(String theContent) throws XapiParseException, XapiServletOperationProblemException{ try{ // What are they sending myOtherLogger.keepTrack(theContent); XapiCredentials theCredentials = myJson.deserializeCredentials(theContent); XapiKeySecret theKeySecret = mySecretKeyGenerator.getLoginInformation(theContent); myAccessManager.addCrendential(theKeySecret, theCredentials); myOtherLogger.keepTrack(theKeySecret.getKey() + ":" + theKeySecret.getSecret()); return theKeySecret; }catch(IOException e){ myOtherLogger.logBug("Credentials problem", e); throw new XapiServletOperationProblemException("Having problem reading the request"); } } /** * * Definition: * Checking if the params of the request are all part of the allowed params * Does not have to be on * * Params: * * */ private void verifyParams(HashMap<String, String> theHeaderAndParameterMap, ArrayList<String> acceptedParamList) throws XapiBadParamException{ /** for(Enumeration<String> paramNames = req.getParameterNames(); paramNames.hasMoreElements();){ String paramName = paramNames.nextElement(); if(!acceptedParamList.contains(paramName)){ throw new XapiBadParamException("Param name : " + paramName + " not accepted"); } } **/ } /** * * Definition: * Checking if the params of the request are all part of the allowed params * Does not have to be on * * Params: * * */ private void verifyParams(HashMap<String, String> theHeaderAndParameterMap, ArrayList<String> acceptedParamList, String typeOfRequest) throws XapiBadParamException{ /** for(Enumeration<String> paramNames = req.getParameterNames(); paramNames.hasMoreElements();){ String paramName = paramNames.nextElement(); if(!acceptedParamList.contains(paramName)){ throw new XapiBadParamException("Param name : " + paramName + " not accepted for " + typeOfRequest); } } **/ } /** * * Definition: * Helper function -- create StatementBatch * * Params: * * */ private XapiStatementBatch createStatementBatch(HashMap<Integer, XapiStatement> theStatements){ XapiStatementBatch theStatementBatch = new XapiStatementBatch(); for(Integer i : theStatements.keySet()){ theStatementBatch.addStatementToBatch(theStatements.get(i)); } return theStatementBatch; } private ArrayList<XapiIRI> fillUpActivityIDs(XapiStatement theStatement, ArrayList<XapiIRI> theList){ if(theStatement.getObject() instanceof XapiActivity){ theList.add(((XapiActivity) theStatement.getObject()).getId()); } // Add other possible activity IDs if(theStatement.hasContext()){ XapiContext theContext = theStatement.getContext(); if(theContext.hasContextActivities()){ XapiContextActivities theContextActivities = theContext.getContextActivities(); if(theContextActivities.hasParent()){ theList = addActivityIDs(theList, theContextActivities.getParent()); } if(theContextActivities.hasGrouping()){ theList = addActivityIDs(theList, theContextActivities.getGrouping()); } if(theContextActivities.hasCategory()){ theList = addActivityIDs(theList, theContextActivities.getCategory()); } if(theContextActivities.hasOther()){ theList = addActivityIDs(theList, theContextActivities.getOther()); } } } return theList; } private ArrayList<XapiIRI> addActivityIDs(ArrayList<XapiIRI> theList, ArrayList<XapiActivity> theActivities){ for(XapiActivity theActivity : theActivities){ theList.add(theActivity.getId()); } return theList; } /** * * Definition: * All the next methods down below are to populate the list of allowed params * * Params: * * */ private void populateCredentialRequestParams(){ myCredentialsRequestParams = new ArrayList<String>(); myCredentialsRequestParams.add("scope"); myCredentialsRequestParams.add("expiry"); myCredentialsRequestParams.add("historical"); myCredentialsRequestParams.add("actors"); myCredentialsRequestParams.add("activity"); myCredentialsRequestParams.add("registration"); } private void populateStatementGetParams(){ myStatementGetParams = new ArrayList<String>(); myStatementGetParams.add("statementId"); myStatementGetParams.add("agent"); myStatementGetParams.add("verb"); myStatementGetParams.add("activity"); myStatementGetParams.add("registration"); myStatementGetParams.add("since"); myStatementGetParams.add("until"); myStatementGetParams.add("limit"); myStatementGetParams.add("related_activities"); myStatementGetParams.add("related_agents"); } private void populateStateSingleParams(){ myStateSingleParams = new ArrayList<String>(); myStateSingleParams.add("activityId"); myStateSingleParams.add("agent"); myStateSingleParams.add("registration"); myStateSingleParams.add("stateId"); } private void populateStateSingleGetParams(){ myStateSingleGetParams = new ArrayList<String>(); myStateSingleGetParams.add("activityId"); myStateSingleGetParams.add("agent"); myStateSingleGetParams.add("registration"); myStateSingleGetParams.add("stateId"); } private void populateStateMultipleGetParams(){ myStateMultipleGetParams = new ArrayList<String>(); myStateMultipleGetParams.add("activityId"); myStateMultipleGetParams.add("agent"); myStateMultipleGetParams.add("registration"); myStateMultipleGetParams.add("since"); } private void populateStateMultipleDeleteParams(){ myStateMultipleDeleteParams = new ArrayList<String>(); myStateMultipleDeleteParams.add("activityId"); myStateMultipleDeleteParams.add("agent"); myStateMultipleDeleteParams.add("registration"); } private void populateActivityProfileSingleParams(){ myActivityProfileSingleParams = new ArrayList<String>(); myActivityProfileSingleParams.add("activityId"); myActivityProfileSingleParams.add("profileId"); } private void populateActivityProfileSingleGetParams(){ myActivityProfileSingleGetParams = new ArrayList<String>(); myActivityProfileSingleGetParams.add("activityId"); myActivityProfileSingleGetParams.add("profileId"); } private void populateActivityProfileMultipleGetParams(){ myActivityProfileMultipleGetPrams = new ArrayList<String>(); myActivityProfileMultipleGetPrams.add("activityId"); myActivityProfileMultipleGetPrams.add("since"); } private void populateAgentProfileSingleParams(){ myAgentProfileSingleParams = new ArrayList<String>(); myAgentProfileSingleParams.add("agent"); myAgentProfileSingleParams.add("profileId"); } private void populateAgentProfileMultipleParams(){ myAgentProfileMultipleParams = new ArrayList<String>(); myAgentProfileMultipleParams.add("agent"); myAgentProfileMultipleParams.add("since"); } /** * * Definition: * Populate the list of the accepted domains * for CORS * * Params: * * */ private void populateDomainList(String[] theList){ myAllowedDomainList = new ArrayList<String>(); for(String s : theList){ myAllowedDomainList.add(s.trim()); } } /** * * Definition: * Fill the list of the header allowed * * Params: * * */ private void populateHeaderList(){ myAllowedHeaderList = new ArrayList<String>(); myAllowedHeaderList.add("Authorization"); myAllowedHeaderList.add("content"); myAllowedHeaderList.add("X-Experience-API-Version"); } /** * * Definition: * Function to maintaing the permission list from getting too big * * Params: * * */ private void maintainCredentialsList(){ // Interval equals to ten minutes int theInterval = 3 * 60 * 1000; Timer theTimer = new Timer(); theTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { DateTime theNow = DateTime.now(); // Iterating through credentials maps Iterator<XapiKeySecret> theIterator = myAccessManager.getCredentialsKeySet().iterator(); /** for(XapiKeySecret ks : myAccessManager.getCredentialsKeySet()){ XapiCredentials cred = myAccessManager.getCredential(ks); if(cred.getExpiry().isBefore(theNow)){ myAccessManager.removePermission(ks); } } **/ while(theIterator.hasNext()){ XapiKeySecret ks = theIterator.next(); XapiCredentials cred = myAccessManager.getCredential(ks); if(cred.getExpiry().isBefore(theNow)){ theIterator.remove(); myAccessManager.removePermission(ks); } } } }, theInterval, theInterval); } private long defaultLog(Exception theException, HttpServletRequest req){ return myLogger.log(theException, 500, theException.getMessage(), req); } /** * * Definition: * Rollback the transaction * * Params: * * */ private void rollback(Connection conn, HttpServletResponse resp){ //try{ // conn.rollback(); //}catch(SQLException e){ // defaultLog(e); // handleError(resp, 500, "Having trouble writing to the database"); //} } }