diff --git a/bbb-lti/grails-app/conf/Config.groovy b/bbb-lti/grails-app/conf/Config.groovy index 8b1c701b29ddf2ce436120defd464887d7632545..a507556a461188d0d6ac491b75fe76c703ecd3cb 100644 --- a/bbb-lti/grails-app/conf/Config.groovy +++ b/bbb-lti/grails-app/conf/Config.groovy @@ -114,11 +114,12 @@ environments { // log4j configuration log4j = { - // Example of changing the log pattern for the default console appender: - // - //appenders { - // console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n') - //} + appenders { + rollingFile name:"logfile", maxFileSize:20971520, maxBackups:52, file:"/var/log/bigbluebutton/bbb-lti.log", layout:pattern(conversionPattern: '%d{[dd.MM.yy HH:mm:ss.SSS]} %-5p %c %x - %m%n') + console name:'console', layout:pattern(conversionPattern: '%d{[dd.MM.yy HH:mm:ss.SSS]} %-5p %c %x - %m%n') + 'null' name:'stacktrace' + } + debug logfile:"grails.app" error 'org.codehaus.groovy.grails.web.servlet', // controllers 'org.codehaus.groovy.grails.web.pages', // GSP diff --git a/bbb-lti/grails-app/conf/UrlMappings.groovy b/bbb-lti/grails-app/conf/UrlMappings.groovy index beb1333239d1d8dac58ad37aac9abc7b0e78f77f..f28ac34a8cd70af40ebb6487d61d61743366c76a 100644 --- a/bbb-lti/grails-app/conf/UrlMappings.groovy +++ b/bbb-lti/grails-app/conf/UrlMappings.groovy @@ -14,17 +14,16 @@ You should have received a copy of the GNU Lesser General Public License along with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. -*/ +*/ class UrlMappings { - - static mappings = { + static mappings = { "/$controller/$action?/$id?(.$format)?"{ constraints { // apply constraints here } } - "/"(view:"/index") + "/"(controller: "tool") "500"(view:'/error') - } + } } diff --git a/bbb-lti/grails-app/conf/lti.properties b/bbb-lti/grails-app/conf/lti.properties index 830ecfb8a1719e12b47658ed553ad0d0c2c40c00..abe024c7df34daf9853c3880fcd40c1c5dcf6ffe 100644 --- a/bbb-lti/grails-app/conf/lti.properties +++ b/bbb-lti/grails-app/conf/lti.properties @@ -29,8 +29,9 @@ bigbluebuttonSalt=bbb_salt # LTI basic information #---------------------------------------------------- -# This URL is where the LTI plugin is accessible. It can be a different server than the BigBluebutton one -ltiEndPoint=http://localhost/lti/tool +# This URL is where the LTI plugin is accessible. It can be a different server than the BigBluebutton one +# Only the hostname or IP address is required, plus the port number in case it is other than port 80 +ltiEndPoint=localhost:port # The list of consumers allowed to access this lti service. # Format: {consumerId1:sharedSecret1} ##ltiConsumers=bbb:bbb_salt diff --git a/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy b/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy index b4ccbac148099a6ff97d1a38c39b66628a7ecec0..b3e4b2eeb6438be79fef443dcc64f05185dde5fe 100644 --- a/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy +++ b/bbb-lti/grails-app/controllers/org/bigbluebutton/ToolController.groovy @@ -48,6 +48,7 @@ class ToolController { if( ltiService.consumerMap == null) ltiService.initConsumerMap() log.debug CONTROLLER_NAME + "#index" + def endPoint = (request.isSecure()?"https":"http") + "://" + ltiService.endPoint + "/" + grailsApplication.metadata['app.name'] + "/" + params.get("controller") + (params.get("format") != null? "." + params.get("format"): "") setLocalization(params) params.put(REQUEST_METHOD, request.getMethod().toUpperCase()) @@ -63,7 +64,7 @@ class ToolController { def consumer = ltiService.getConsumer(params.get(Parameter.CONSUMER_ID)) if (consumer != null) { log.debug "Found consumer with key " + consumer.get("key") //+ " and sharedSecret " + consumer.get("secret") - if (checkValidSignature(params.get(REQUEST_METHOD), ltiService.endPoint, consumer.get("secret"), sanitizedParams, params.get(Parameter.OAUTH_SIGNATURE))) { + if (checkValidSignature(params.get(REQUEST_METHOD), endPoint, consumer.get("secret"), sanitizedParams, params.get(Parameter.OAUTH_SIGNATURE))) { log.debug "The message has a valid signature." if( !"extended".equals(ltiService.mode) ) { @@ -187,9 +188,7 @@ class ToolController { } render(view: "index", model: ['params': sessionParams, 'recordingList': recordings, 'ismoderator': bigbluebuttonService.isModerator(sessionParams)]) - } - } def delete() { @@ -235,19 +234,15 @@ class ToolController { } private void setLocalization(params){ - String locale = params.get(Parameter.LAUNCH_LOCALE) locale = (locale == null || locale.equals("")?"en":locale) - log.debug "Locale code =" + locale String[] localeCodes = locale.split("_") //Localize the default welcome message - if( localeCodes.length > 1 ) + if( localeCodes.length > 1 ) { session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0], localeCodes[1]) - else + } else { session['org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE'] = new Locale(localeCodes[0]) - - log.debug "Locale has been set to " + locale - + } } private Object doJoinMeeting(params) { @@ -367,6 +362,12 @@ class ToolController { } private String getCartridgeXML(){ + def lti_endpoint = ltiService.retrieveBasicLtiEndpoint() + '/' + grailsApplication.metadata['app.name'] + def launch_url = 'http://' + lti_endpoint + '/tool' + def secure_launch_url = 'https://' + lti_endpoint + '/tool' + def icon = 'http://' + lti_endpoint + '/images/icon.ico' + def secure_icon = 'https://' + lti_endpoint + '/images/icon.ico' + def isSSLEnabled = ltiService.isSSLEnabled('https://' + lti_endpoint + '/tool/test') def cartridge = '' + '<?xml version="1.0" encoding="UTF-8"?>' + '<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0"' + @@ -379,9 +380,11 @@ class ToolController { ' http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd' + ' http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">' + ' <blti:title>BigBlueButton</blti:title>' + - ' <blti:description>Single Sign On into BigBlueButton</blti:description>' + - ' <blti:launch_url>' + ltiService.retrieveBasicLtiEndpoint() + '</blti:launch_url>' + - ' <blti:icon>' + ltiService.retrieveIconEndpoint() + '</blti:icon>' + + ' <blti:description>BigBlueButton is an open source web conferencing system for on-line learning. The LTI integration enables teachers to (a) embed BigBlueButton virtual classes within their course to provide on-line office hours, small group collaboration, and on-line lectures, (b) record sessions, and (c) manage recorded sessions.</blti:description>' + + ' <blti:launch_url>' + launch_url + '</blti:launch_url>' + + (isSSLEnabled? ' <blti:secure_launch_url>' + secure_launch_url + '</blti:secure_launch_url>': '') + + ' <blti:icon>' + icon + '</blti:icon>' + + (isSSLEnabled? ' <blti:secure_icon>' + secure_icon + '</blti:secure_icon>': '') + ' <blti:vendor>' + ' <lticp:code>BBB</lticp:code>' + ' <lticp:name>BigBlueButton</lticp:name>' + diff --git a/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy b/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy index 8254cba65448b7d74545eee2bb1c3ee923005186..8a12432d58fc8a3171ec7c0c7c22af46278cfa74 100644 --- a/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy +++ b/bbb-lti/grails-app/services/org/bigbluebutton/LtiService.groovy @@ -26,16 +26,12 @@ import org.apache.commons.codec.binary.Base64 @Transactional class LtiService { - def endPoint = "http://localhost/lti/tool" + def endPoint = "localhost" def consumers = "demo:welcome" def mode = "simple" Map<String, String> consumerMap - def retrieveIconEndpoint() { - return endPoint.replaceFirst("tool", "images/icon.ico") - } - def retrieveBasicLtiEndpoint() { return endPoint } @@ -91,4 +87,36 @@ class LtiService { for( param in params ) log.debug "${param.getKey()}=${param.getValue()}" log.debug "----------------------------------" } + + def boolean isSSLEnabled(String query) { + def sslEnabled = false + + try { + // open connection + StringBuilder urlStr = new StringBuilder(query) + URL url = new URL(urlStr.toString()) + HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection() + httpConnection.setUseCaches(false) + httpConnection.setDoOutput(true) + httpConnection.setRequestMethod("GET") + httpConnection.connect() + + int responseCode = httpConnection.getResponseCode() + if (responseCode == HttpURLConnection.HTTP_OK) { + sslEnabled = true + } else { + log.debug("HTTPERROR: Message=" + "BBB server responded with HTTP status code " + responseCode) + } + + } catch(IOException e) { + log.debug("IOException: Message=" + e.getMessage()) + } catch(IllegalArgumentException e) { + log.debug("IllegalArgumentException: Message=" + e.getMessage()) + } catch(Exception e) { + log.debug("Exception: Message=" + e.getMessage()) + } + + return sslEnabled + } + }