Skip to content

Commit

Permalink
SAK-50378 LTI - Remove Tool Features / Rationalize DB Fields (sakaip…
Browse files Browse the repository at this point in the history
…roject#12857)

Co-authored-by: Earle Nietzel <[email protected]>
  • Loading branch information
csev and ern authored Sep 10, 2024
1 parent 94ee9d9 commit 0237b47
Show file tree
Hide file tree
Showing 50 changed files with 757 additions and 1,204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,17 @@ public interface LTIService extends LTISubstitutionsFilter {
"id:key",
"tool_id:integer:hidden=true",
"SITE_ID:text:label=bl_content_site_id:required=true:maxlength=99:role=admin",
"title:text:label=bl_title:required=true:allowed=true:maxlength=1024",
"title:text:label=bl_title:required=true:maxlength=1024",
"description:textarea:label=bl_description:maxlength=4096",
"pagetitle:text:label=bl_pagetitle:allowed=true:maxlength=1024",
"fa_icon:text:label=bl_fa_icon:allowed=true:maxlength=1024",
"frameheight:integer:label=bl_frameheight:allowed=true",
"toolorder:integer:label=bl_toolorder:hidden=true:maxlength=2:role=admin",
"frameheight:integer:label=bl_frameheight",
"newpage:checkbox:label=bl_newpage",
"protect:checkbox:label=bl_protect:role=admin",
"debug:checkbox:label=bl_debug",
"custom:textarea:label=bl_custom:rows=5:cols=25:allowed=true:maxlength=16384",
"launch:url:label=bl_launch:maxlength=1024:allowed=true",
"consumerkey:text:label=bl_consumerkey:allowed=true:maxlength=1024",
"secret:text:label=bl_secret:allowed=true:maxlength=1024",
"custom:textarea:label=bl_custom:rows=5:cols=25:maxlength=16384",
"launch:url:label=bl_launch:hidden=true:maxlength=1024",
"xmlimport:text:hidden=true:maxlength=1M",
// LTI 2.x settings
"settings:text:hidden=true:maxlength=1M",
// Sakai LTI 1.x extension settings (see SAK-25621)
"settings_ext:text:hidden=true:maxlength=1M",
// This actually ends up storing the lineitem within the contentitem (not the whole contentitem)
"contentitem:text:label=bl_contentitem:rows=5:cols=25:maxlength=1M:hidden=true",
"placement:text:hidden=true:maxlength=256",
Expand All @@ -105,24 +98,14 @@ public interface LTIService extends LTISubstitutionsFilter {
"id:key",
"SITE_ID:text:maxlength=99:role=admin",
"title:text:label=bl_title:required=true:maxlength=1024",
"allowtitle:radio:label=bl_allowtitle:choices=disallow,allow",
"pagetitle:text:label=bl_pagetitle:required=true:maxlength=1024",
"allowpagetitle:radio:label=bl_allowpagetitle:choices=disallow,allow",
"description:textarea:label=bl_description:maxlength=4096",
"status:radio:label=bl_status:choices=enable,disable",
"visible:radio:label=bl_visible:choices=visible,stealth:role=admin",
"deployment_id:integer:hidden=true",
"launch:url:label=bl_launch:maxlength=1024:required=true",
"allowlaunch:radio:label=bl_allowlaunch:choices=disallow,allow",
"consumerkey:text:label=bl_consumerkey:maxlength=1024",
"allowconsumerkey:radio:label=bl_allowconsumerkey:hidden=true:choices=disallow,allow",
"secret:text:label=bl_secret:maxlength=1024",
"allowsecret:radio:label=bl_allowsecret:hidden=true:choices=disallow,allow",
"newpage:radio:label=bl_newpage:choices=off,on,content",
"frameheight:integer:label=bl_frameheight",
"allowframeheight:radio:label=bl_allowframeheight:choices=disallow,allow",
"fa_icon:text:label=bl_fa_icon:allowed=true:maxlength=1024",
"allowfa_icon:radio:label=bl_allowfa_icon:choices=disallow,allow",
"fa_icon:text:label=bl_fa_icon:maxlength=1024",
// SAK-49540 - Message Types (keep columns named pl_ for upwards compatibility)
"pl_header:header:fields=pl_launch,pl_linkselection",
"pl_launch:checkbox:label=bl_pl_launch",
Expand All @@ -136,7 +119,6 @@ public interface LTIService extends LTISubstitutionsFilter {
"pl_coursenav:checkbox:label=bl_pl_coursenav",
"pl_importitem:checkbox:label=bl_pl_importitem:role=admin",
"pl_fileitem:checkbox:label=bl_pl_fileitem:role=admin:hidden=true",
"toolorder:integer:label=bl_toolorder:hidden=true:advanced:maxlength=2",
"privacy:header:fields=sendname,sendemailaddr,pl_privacy",
"sendname:checkbox:label=bl_sendname",
"sendemailaddr:checkbox:label=bl_sendemailaddr",
Expand All @@ -145,26 +127,39 @@ public interface LTIService extends LTISubstitutionsFilter {
"allowoutcomes:checkbox:label=bl_allowoutcomes",
"allowlineitems:checkbox:label=bl_allowlineitems",
"allowroster:checkbox:label=bl_allowroster",
"allowsettings_ext:checkbox:label=bl_allowsettings_ext:hidden=true",

"debug:radio:label=bl_debug:choices=off,on,content",
"siteinfoconfig:radio:label=bl_siteinfoconfig:advanced:choices=bypass,config",
"splash:textarea:label=bl_splash:rows=5:cols=25:maxlength=16384",

// LTI 1.x user-entered custom
"custom:textarea:label=bl_custom:rows=5:cols=25:maxlength=16384",
"rolemap:textarea:label=bl_rolemap:rows=5:cols=25:maxlength=16384:role=admin",
// LTI 1.3 expansion space (See SAK-33772)
"lti13:radio:label=bl_lti13:choices=off,on:role=admin",
"lti13:radio:label=bl_lti13:choices=off,on,both:role=admin",

// LTI 1.3 security values from the tool
"lti13_tool_security:header:fields=lti13_tool_keyset,lti13_oidc_endpoint,lti13_oidc_redirect",
"lti13_tool_keyset:text:label=bl_lti13_tool_keyset:maxlength=1024:role=admin", // From the tool - keep legacy field name
"lti13_oidc_endpoint:text:label=bl_lti13_oidc_endpoint:maxlength=1024:role=admin", // From the tool - keep legacy field name
"lti13_oidc_redirect:text:label=bl_lti13_oidc_redirect:maxlength=1024:role=admin", // From the tool - keep legacy field name

// LTI 1.3 security values from the LMS
"lti13_lms_security:header:fields=lti13_lms_issuer,lti13_client_id,lti13_lms_keyset,lti13_lms_endpoint,lti13_lms_token",
"lti13_lms_issuer:text:label=bl_lti13_lms_issuer:readonly=true:persist=false:maxlength=1024:role=admin",
"lti13_client_id:text:label=bl_lti13_client_id:readonly=true:maxlength=1024:role=admin",
"lti13_lms_deployment_id:text:label=bl_lti13_lms_deployment_id:readonly=true:maxlength=1024:role=admin",
"lti13_lms_keyset:text:label=bl_lti13_lms_keyset:readonly=true:persist=false:maxlength=1024:role=admin",
"lti13_lms_endpoint:text:label=bl_lti13_lms_endpoint:readonly=true:persist=false:maxlength=1024:role=admin",
"lti13_lms_token:text:label=bl_lti13_lms_token:readonly=true:persist=false:maxlength=1024:role=admin",

// LTI 1.1 security arrangement
"lti11_security:header:fields=consumerkey,allowconsumerkey,secret,allowsecret",
"consumerkey:text:label=bl_consumerkey:maxlength=1024",

// The core values from LTI 1.3 tools (we prefer keyset over explicit key)
"lti13_client_id:text:hide=insert:label=bl_lti13_client_id:maxlength=1024:role=admin",
"lti13_tool_keyset:text:label=bl_lti13_tool_keyset:maxlength=1024:role=admin",
"lti13_oidc_endpoint:text:label=bl_lti13_oidc_endpoint:maxlength=1024:role=admin",
"lti13_oidc_redirect:text:label=bl_lti13_oidc_redirect:maxlength=1024:role=admin",
"secret:text:label=bl_secret:maxlength=1024",

"lti13_settings:textarea:hidden=true:maxlength=1M:role=admin",

"debug:radio:label=bl_debug:choices=off,on,content",

"lti11_launch_type:radio:label=bl_lti11_launch_type:role=admin:choices=inherit,legacy,lti112:hidden=true",
"xmlimport:textarea:hidden=true:maxlength=1M",
"lti13_auto_token:text:hidden=true:maxlength=1024",
"lti13_auto_state:integer:hidden=true",
Expand All @@ -185,7 +180,7 @@ public interface LTIService extends LTISubstitutionsFilter {
"SITE_ID:text:maxlength=99:required=true",
"memberships_id:text:maxlength=256:required=true",
"memberships_url:text:maxlength=4000:required=true",
"consumerkey:text:label=bl_consumerkey:allowed=true:maxlength=1024",
"consumerkey:text:label=bl_consumerkey:maxlength=1024",
"lti_version:text:maxlength=32:required=true"};
/**
* Static constants for data fields
Expand All @@ -195,34 +190,24 @@ public interface LTIService extends LTISubstitutionsFilter {
String LTI_SITE_ID = "SITE_ID";
String LTI_TOOL_ID = "tool_id";
String LTI_TITLE = "title";
String LTI_ALLOWTITLE = "allowtitle";
String LTI_PAGETITLE = "pagetitle";
String LTI_ALLOWPAGETITLE = "allowpagetitle";
String LTI_FA_ICON = "fa_icon";
String LTI_PLACEMENT = "placement";
String LTI_DESCRIPTION = "description";
String LTI_ID_HISTORY = "id_history";
String LTI_STATUS = "status";
String LTI_VISIBLE = "visible";
String LTI_LAUNCH = "launch";
String LTI_ALLOWLAUNCH = "allowlaunch";
String LTI_CONSUMERKEY = "consumerkey";
String LTI_ALLOWCONSUMERKEY = "allowconsumerkey";
String LTI_SECRET = "secret";
String LTI_NEW_SECRET = "new_secret";
String LTI_ALLOWSECRET = "allowsecret";
String LTI_SECRET_INCOMPLETE = "-----";
String LTI_FRAMEHEIGHT = "frameheight";
String LTI_ALLOWFRAMEHEIGHT = "allowframeheight";
String LTI_TOOLORDER = "toolorder";
String LTI_SENDNAME = "sendname";
String LTI_SENDEMAILADDR = "sendemailaddr";
String LTI_ALLOWOUTCOMES = "allowoutcomes";
String LTI_ALLOWLINEITEMS = "allowlineitems";
String LTI_ALLOWROSTER = "allowroster";
String LTI_ALLOWSETTINGS_EXT = "allowsettings_ext";
String LTI_SETTINGS = "settings";
String LTI_SETTINGS_EXT = "settings_ext";
// This field is mis-named - so we make an alias :(
String LTI_CONTENTITEM = "contentitem";
String LTI_LINEITEM = "contentitem";
Expand All @@ -247,23 +232,6 @@ public interface LTIService extends LTISubstitutionsFilter {
String LTI_PLACEMENTSECRET = "placementsecret";
String LTI_OLDPLACEMENTSECRET = "oldplacementsecret";

// Removed LTI 2.0 - SAK-40065
// SAK-40065 String LTI_RESOURCE_HANDLER = "resource_handler";
// SAK-40065 String LTI_VERSION = "version";
// SAK-40065 Long LTI_VERSION_1 = 0L;
// SAK-40065 String LTI_DEPLOYMENT_ID = "deployment_id";
// SAK-40065 Long LTI_VERSION_2 = new Long(1);
// SAK-40065 String LTI_REG_STATE = "reg_state";
// SAK-40065 String LTI_REG_STATE_REGISTERED = "1";
// SAK-40065 String LTI_REG_LAUNCH = "reg_launch";
// SAK-40065 String LTI_REG_KEY = "reg_key";
// SAK-40065 String LTI_REG_ACK = "reg_ack";
// SAK-40065 String LTI_REG_PASSWORD = "reg_password";
// SAK-40065 String LTI_PARAMETER = "parameter";
// SAK-40065 String LTI_REG_PROFILE = "reg_profile"; // A.k.a tool_proxy
// A subset of a tool_proxy with only a single resource_handler
// SAK-40065 String LTI_TOOL_PROXY_BINDING = "tool_proxy_binding";

// SAK-49540 - Message Types (keep columns named pl_ for upwards compatibility)
String LTI_MT_LAUNCH = "pl_launch";
String LTI_MT_LINKSELECTION = "pl_linkselection";
Expand Down Expand Up @@ -292,18 +260,23 @@ public interface LTIService extends LTISubstitutionsFilter {
String LTI_SITE_ATTRIBUTION_PROPERTY_NAME = "basiclti.tool.site.attribution.name";
String LTI_SITE_ATTRIBUTION_PROPERTY_NAME_DEFAULT = "content.attribution";

String LTI11_LAUNCH_TYPE = "lti11_launch_type";
Long LTI11_LAUNCH_TYPE_INHERIT = 0L;
Long LTI11_LAUNCH_TYPE_LEGACY = 1L;
Long LTI11_LAUNCH_TYPE_LTI112 = 2L;

// LTI 1.3
String LTI13 = "lti13";
Long LTI13_LTI11 = 0L;
Long LTI13_LTI13 = 1L;
Long LTI13_BOTH = 2L;
String LTI13_CLIENT_ID = "lti13_client_id";
String LTI13_TOOL_KEYSET = "lti13_tool_keyset";

String LTI13_OIDC_ENDPOINT = "lti13_oidc_endpoint";
String LTI13_OIDC_REDIRECT = "lti13_oidc_redirect";
String LTI13_TOOL_KEYSET = "lti13_tool_keyset";
String LTI13_TOOL_ENDPOINT = "lti13_oidc_endpoint";
String LTI13_TOOL_REDIRECT = "lti13_oidc_redirect";

// Not persisted - generated dynamically
String LTI13_LMS_ISSUER = "lti13_lms_issuer";
String LTI13_LMS_DEPLOYMENT_ID = "lti13_lms_deployment_id";
String LTI13_LMS_KEYSET = "lti13_lms_keyset";
String LTI13_LMS_TOKEN = "lti13_lms_token";
String LTI13_LMS_ENDPOINT = "lti13_lms_endpoint";

// For Instructors, this model is filtered down dynamically based on
// Tool settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
import org.sakaiproject.util.api.FormattedText;

import static org.sakaiproject.basiclti.util.SakaiBLTIUtil.BASICLTI_PORTLET_ALLOWROSTER;
import static org.sakaiproject.basiclti.util.SakaiBLTIUtil.BASICLTI_PORTLET_ALLOWSETTINGS;
import static org.sakaiproject.basiclti.util.SakaiBLTIUtil.BASICLTI_PORTLET_ON;
import static org.sakaiproject.basiclti.util.SakaiBLTIUtil.BASICLTI_PORTLET_OFF;
import static org.sakaiproject.basiclti.util.SakaiBLTIUtil.BASICLTI_PORTLET_TOOLSETTING;
Expand Down Expand Up @@ -159,15 +158,11 @@ protected void doPostForm(HttpServletRequest request, HttpServletResponse respon
SakaiBLTIUtil.BASICLTI_OUTCOMES_ENABLED, SakaiBLTIUtil.BASICLTI_OUTCOMES_ENABLED_DEFAULT);
if ( ! "true".equals(allowOutcomes) ) allowOutcomes = null;

String allowSettings = ServerConfigurationService.getString(
SakaiBLTIUtil.BASICLTI_SETTINGS_ENABLED, SakaiBLTIUtil.BASICLTI_SETTINGS_ENABLED_DEFAULT);
if ( ! "true".equals(allowSettings) ) allowSettings = null;

String allowRoster = ServerConfigurationService.getString(
SakaiBLTIUtil.BASICLTI_ROSTER_ENABLED, SakaiBLTIUtil.BASICLTI_ROSTER_ENABLED_DEFAULT);
if ( ! "true".equals(allowRoster) ) allowRoster = null;

if (allowOutcomes == null && allowSettings == null && allowRoster == null ) {
if (allowOutcomes == null && allowRoster == null ) {
log.warn("LTI Services are disabled IP={}", ipAddress);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
Expand All @@ -193,11 +188,6 @@ protected void doPostForm(HttpServletRequest request, HttpServletResponse respon
BasicLTIUtil.equals(lti_message_type, "basic-lis-readresult") ) {
sourcedid = request.getParameter("sourcedid");
if ( allowOutcomes != null ) message_type = "basicoutcome";
} else if( BasicLTIUtil.equals(lti_message_type, "basic-lti-loadsetting") ||
BasicLTIUtil.equals(lti_message_type, "basic-lti-savesetting") ||
BasicLTIUtil.equals(lti_message_type, "basic-lti-deletesetting") ) {
sourcedid = request.getParameter("id");
if ( allowSettings != null ) message_type = "toolsetting";
} else if( BasicLTIUtil.equals(lti_message_type, "basic-lis-readmembershipsforcontext") ) {
sourcedid = request.getParameter("id");
if ( allowRoster != null ) message_type = "roster";
Expand All @@ -219,7 +209,6 @@ protected void doPostForm(HttpServletRequest request, HttpServletResponse respon
return;
}


// No point continuing without a sourcedid
if(BasicLTIUtil.isBlank(sourcedid)) {
doError(request, response, theMap, "outcomes.missing", "sourcedid", null);
Expand Down Expand Up @@ -366,116 +355,9 @@ protected void doPostForm(HttpServletRequest request, HttpServletResponse respon
return;
}

// These are the Sakai-post form extensions
if ( "toolsetting".equals(message_type) ) processSetting(request, response, lti_message_type, site, siteId, placement_id, normalProps, user_id, theMap);

if ( "roster".equals(message_type) ) processRoster(request, response, lti_message_type, site, siteId, placement_id, normalProps, user_id, theMap);
}

protected void processSetting(HttpServletRequest request, HttpServletResponse response,
String lti_message_type,
Site site, String siteId, String placement_id, Properties normalProps,
String user_id, Map<String, Object> theMap)
throws java.io.IOException
{
String setting = null;

log.debug("normalProps={}", normalProps);

// Check for permission in placement
String allowSetting = normalProps.getProperty(BASICLTI_PORTLET_ALLOWSETTINGS);
if ( ! BASICLTI_PORTLET_ON.equals(allowSetting) ) {
doError(request, response, theMap, "service.notallowed", "lti_message_type="+lti_message_type, null);
return;
}

SakaiBLTIUtil.pushAdvisor();
boolean success = false;
boolean changed = false;
try {
if ( SakaiBLTIUtil.isPlacement(placement_id) ) {
ToolConfiguration placement = SiteService.findTool(placement_id);
if ( "basic-lti-loadsetting".equals(lti_message_type) ) {
setting = placement.getPlacementConfig().getProperty("imsti."+BASICLTI_PORTLET_TOOLSETTING, null);
if ( setting != null ) {
theMap.put("/message_response/setting/value", setting);
}
success = true;
} else if ( "basic-lti-savesetting".equals(lti_message_type) ) {
setting = request.getParameter("setting");
if ( setting == null ) {
log.warn("No setting parameter");
doError(request, response, theMap, "setting.empty", "", null);
} else {
if ( setting.length() > 8096) setting = setting.substring(0,8096);
placement.getPlacementConfig().setProperty("imsti."+BASICLTI_PORTLET_TOOLSETTING, setting);
changed = true;
}
} else if ( "basic-lti-deletesetting".equals(lti_message_type) ) {
placement.getPlacementConfig().remove("imsti."+BASICLTI_PORTLET_TOOLSETTING);
changed = true;
}
if ( changed ) {
try {
placement.save();
success = true;
} catch(Exception e) {
doError(request, response, theMap, "setting.save.fail", "", e);
success = false;
}
}
} else {
Map<String,Object> content = null;
String contentStr = normalProps.getProperty("contentKey");
Long contentKey = SakaiBLTIUtil.getLongKey(contentStr);
if ( contentKey >= 0 ) content = ltiService.getContentDao(contentKey, siteId);
if ( content != null ) {
success = true;
if ( "basic-lti-loadsetting".equals(lti_message_type) ) {
setting = (String) content.get(LTIService.LTI_SETTINGS_EXT);
if ( setting != null ) {
theMap.put("/message_response/setting/value", setting);
}
} else if ( "basic-lti-savesetting".equals(lti_message_type) ) {
setting = request.getParameter("setting");
if ( setting == null ) {
log.warn("No setting parameter");
doError(request, response, theMap, "setting.empty", "", null);
} else {
if ( setting.length() > 8096) setting = setting.substring(0,8096);
content.put(LTIService.LTI_SETTINGS_EXT,setting);
changed = true;
}
} else if ( "basic-lti-deletesetting".equals(lti_message_type) ) {
content.put(LTIService.LTI_SETTINGS_EXT,null);
changed = true;
}
if ( changed ) {
Object result = ltiService.updateContentDao(contentKey,content, siteId);
if ( result instanceof String ) {
log.warn("Setting update failed: {}", result);
doError(request, response, theMap, "setting.fail", "", null);
success = false;
}
}
}
}
} catch (Exception e) {
doError(request, response, theMap, "setting.fail", "", e);
} finally {
SakaiBLTIUtil.popAdvisor();
}

if ( ! success ) return;

theMap.put("/message_response/statusinfo/codemajor", "Success");
theMap.put("/message_response/statusinfo/severity", "Status");
theMap.put("/message_response/statusinfo/codeminor", "fullsuccess");
String theXml = XMLMap.getXML(theMap, true);
PrintWriter out = response.getWriter();
out.println(theXml);
}

protected void processOutcome(HttpServletRequest request, HttpServletResponse response,
String lti_message_type, String sourcedid, Map<String, Object> theMap)
throws java.io.IOException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,4 @@ public void testAdjustMapAddId() {
assertThat(map, hasEntry("@id", "/lti/kind/siteId/1"));
}

@Test
public void testAdjustMapAllow() {
map.put(LTIService.LTI_ALLOWSECRET, "1");
provider.adjustMap(map, false, "siteId", "kind");
assertThat(map, hasEntry(LTI_ALLOWSECRET, "1"));
}
}
Loading

0 comments on commit 0237b47

Please sign in to comment.