Index: lams_tool_imscc/.classpath
===================================================================
diff -u
--- lams_tool_imscc/.classpath (revision 0)
+++ lams_tool_imscc/.classpath (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: lams_tool_imscc/.cvsignore
===================================================================
diff -u
--- lams_tool_imscc/.cvsignore (revision 0)
+++ lams_tool_imscc/.cvsignore (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,3 @@
+.myeclipse
+.mymetadata
+build
Index: lams_tool_imscc/conf/hibernate/mappings/.cvsignore
===================================================================
diff -u
--- lams_tool_imscc/conf/hibernate/mappings/.cvsignore (revision 0)
+++ lams_tool_imscc/conf/hibernate/mappings/.cvsignore (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1 @@
+org
Index: lams_tool_imscc/conf/hibernate/mappings/hibernate.cfg.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/hibernate/mappings/hibernate.cfg.xml (revision 0)
+++ lams_tool_imscc/conf/hibernate/mappings/hibernate.cfg.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,13 @@
+
+
+
+
+ lams
+ lamsdemo
+ jdbc:mysql://localhost/lams
+ com.mysql.jdbc.Driver
+ org.hibernate.dialect.MySQLDialect
+
+
+
Index: lams_tool_imscc/conf/jar/META-INF/MANIFEST.MF
===================================================================
diff -u
--- lams_tool_imscc/conf/jar/META-INF/MANIFEST.MF (revision 0)
+++ lams_tool_imscc/conf/jar/META-INF/MANIFEST.MF (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,3 @@
+Implementation-Title: LAMS - CommonCartridge Tool
+Implementation-Version: 2.1
+Implementation-Vendor: LAMS Foundation (http://lamsfoundation.org)
Index: lams_tool_imscc/conf/language/lams/ApplicationResources.properties
===================================================================
diff -u
--- lams_tool_imscc/conf/language/lams/ApplicationResources.properties (revision 0)
+++ lams_tool_imscc/conf/language/lams/ApplicationResources.properties (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,203 @@
+appName = commoncartridge
+#language code: en
+#locale code: AU
+
+ # CVS ID: $Id$ Exported from the LAMS Community by Ernie Ghiglione on Wed Mar 03 00:17:40 CST 2010
+
+#=================== labels for ShareResources =================#
+
+label.authoring.basic.resource.common.cartridge =Common Cartridge
+label.authoring.basic.add.common.cartridge =Add Common Cartridge
+label.authoring.basic.add.basiclti.tool =Add Basic LTI Tool
+
+admin.button.save =Save
+admin.expose.user.name =Expose User Name to Basic LTI Tool
+admin.expose.user.email =Expose User Email to Basic LTI Tool
+admin.page.title =BasicLTI Settings
+admin.return =Return to maintain LAMS
+admin.success =Configuration successfully saved.
+
+label.authoring.basic.bascilti.url =Remote Tool Url
+label.authoring.basic.bascilti.key =Remote Tool Key
+label.authoring.basic.bascilti.secret =Remote Tool Secret
+label.authoring.basic.bascilti.button.text =Button Text
+label.authoring.basic.bascilti.iframe.height =Frame Height
+label.authoring.basic.bascilti.custom.parameters =Custom Parameters (*each starts new line)
+
+export.label.no.basic.lti =No offline basic LTI tools available
+
+activity.description =Sharing resources with others.
+activity.helptext =Uploading your resources to share with others.
+activity.title =Common Cartridge
+appName =Common Cartridge
+authoring.exception =There is a problem in shared resources authoring page, the reason is {0}
+authoring.msg.cancel.save =Do you want to close this window without saving?
+button.add =Add
+button.cancel =Cancel
+button.close =Close
+button.edit =Edit
+button.try.again =Try again
+button.upload =Upload
+define.later.message =Please wait for the teacher to complete the contents of this activity.
+error.attachment.executable =The uploaded file is executable, please zip it before uploading.
+error.inputFileTooLarge =Input File size is too large!
+error.msg.default.content.not.find =Could not retrieve default content record for this tool.
+error.msg.file.not.found =File not found exception occurs when uploading file.
+error.msg.ims.application =ImscpApplicationException occurs when uploading resource item file.
+error.msg.ims.package =Invalid IMS CP format.
+error.msg.invaid.param.upload =InvalidParameterException occured while trying to upload File.
+error.msg.io.exception =IOException occurs when uploading file.
+error.msg.repository =A repository error occurred while trying to upload the file.
+error.msg.upload.file.not.found =Could not find upload file {0}.
+error.msg.website.no.initial.file =Website zip can not find out initial file (index.htm/html or default.htm/html).
+error.msg.zip.file.exception =Could not handle zip file when uploading file.
+errorPage.heading =Some error occurs when handling your request
+errorPage.title =Error page
+error.planner.file.blank =In resource {0} file can not be blank.
+error.planner.no.resource.save =There has to be at least one resource to save.
+error.planner.url.blank =In resource {0} URL can not be blank.
+error.reflection.emtpy =Please input Notebook Entry
+error.resource.item.desc.blank =Comment/Instruction can not be blank
+error.resource.item.file.blank =File can not be blank.
+error.resource.item.invalid.url =Invalid URL format.
+error.resource.item.title.blank =Title can not be blank.
+error.resource.item.url.blank =URL can not be blank.
+errors.footer =
+errors.header =
+errors.maxfilesize =The uploaded file has exceeded the maximum file size limit of {0} bytes
+error.title.empty =Title can not be blank
+error.upload.failed =Upload file failed: {0}
+error.uploading =error uploading
+error.valueReqd =Value Required
+event.assigment.submit.body =The learner {0} submitted an assigment in a Common Cartridge tool.\n\nThis message was sent automatically, following the tool''s advanced settings.
+event.assigment.submit.subject =LAMS: A learner submitted an assigment in a Common Cartridge tool
+export.init.resource =Initial Resources
+export.label.no.learning.object =No offline package available
+export.label.resource =Resource
+export.title =Export portfolio of Common Cartridge
+label.authoring.advance.allow.learner.add.files =Allow learners to add Files
+label.authoring.advance.allow.learner.add.urls =Allow learners to add URLs
+label.authoring.advanced.notify.onassigmentsubmit =Notify monitoring teachers when a learner submits a resource
+label.authoring.advanced.reflectOnActivity =Add Notebook at end of Common Cartridge with the following instructions:
+label.authoring.advance.lock.on.finished =Lock when finished
+label.authoring.advance.mini.number.resources.view =Minimum number of resources to view
+label.authoring.advance.run.content.auto =Run content automatically (only available if there is exactly one resource)
+label.authoring.basic.add.file =Add Common Cartridge
+label.authoring.basic.add.learning.object =Add IMS Content Package
+label.authoring.basic.add.url =Add Basic LTI
+label.authoring.basic.add.website =Add Zipped Website
+label.authoring.basic.instruction =Instruction
+label.authoring.basic.resource.add.instruction =Add Instruction
+label.authoring.basic.resource.delete =Delete
+label.authoring.basic.resource.description.input =Description
+label.authoring.basic.resource.edit =Edit
+label.authoring.basic.resource.file =File
+label.authoring.basic.resource.file.input =File
+label.authoring.basic.resource.instructions =Instructions
+label.authoring.basic.resource.learning.object =IMS CP
+label.authoring.basic.resource.list.title =Resource List
+label.authoring.basic.resource.preview =Preview
+label.authoring.basic.resource.title.input =Title
+label.authoring.basic.resource.url =Basic LTI
+label.authoring.basic.resource.url.input =URL
+label.authoring.basic.resource.verify.url =View
+label.authoring.basic.resource.website =Website
+label.authoring.basic.resource.zip.file.input =Zip file:
+label.authoring.basic.title =Title
+label.authoring.cancel.button =Cancel
+label.authoring.choosefile.button =Choose file
+label.authoring.heading =Common Cartridge
+label.authoring.heading.advance =Advanced
+label.authoring.heading.advance.desc =Please input advance options for common cartridge
+label.authoring.heading.basic =Basic
+label.authoring.heading.basic.desc =Basic input information for common cartridge
+label.authoring.heading.instructions =Instructions
+label.authoring.heading.instructions.desc =Please input online and offline instructions
+label.authoring.offline.delete =Delete
+label.authoring.offline.file =Upload offline file
+label.authoring.offline.filelist =Offline file list
+label.authoring.offline.instruction =Offline Instructions
+label.authoring.online.delete =Delete
+label.authoring.online.file =Upload online file
+label.authoring.online.filelist =Online file list
+label.authoring.online.instruction =Online Instructions
+label.authoring.save.button =Save
+label.authoring.upload.offline.button =Upload Offline
+label.authoring.upload.online.button =Upload Online
+label.author.title =Common Cartridge Authoring
+label.cancel =Cancel
+label.check.for.new =Check for new
+label.completed =Completed
+label.continue =Continue
+label.delete =Delete
+label.description =Description:
+label.down =Move down
+label.download =Download
+label.edit =Edit
+label.export.reflection =Notebook Entries
+label.finish =Finished
+label.finished =Next Activity
+label.hide =Hide
+label.learning.comment.or.instruction =Comment/Instruction
+label.learning.heading =Common Cartridge
+label.learning.minimum.review =You must view at least {0} of the resources.
+label.learning.new.file =New file details:
+label.learning.new.url =New URL details:
+label.learning.title =Common Cartridge Learning
+label.monitoring.edit.activity.cancel =Cancel
+label.monitoring.edit.activity.edit =Edit
+label.monitoring.edit.activity.update =Update
+label.monitoring.heading.access =Learners list
+label.next.instruction =Next Instruction
+label.off =Off
+label.on =On
+label.open =Open
+label.resoruce.to.review =Resources to view
+label.save =Save
+label.show =Show
+label.suggest.new =Suggest a new
+label.up =Move Up
+label.view =View
+lable.learning.minimum.view.number.less =You must view at least another {0} of the resources.
+message.activityLocked =The instructor has set this activity not to allow you to view or share any more resources after you have finished it.
+message.alertContentEdit =Warning: One of more learners have accessed this activity. Changing this content will result in learners getting different information.
+message.monitoring.edit.activity.not.editable =This Activity is no longer editable
+message.monitoring.summary.no.resource.for.group =No resource available for this group.
+message.monitoring.summary.no.session =No Session Available
+message.msg.maxFileSize =Max 250K
+message.no.reflection.available =No notebook available
+message.step.of =Step {0} of {1}
+message.warnLockOnFinish =Note: After you click on "Next Activity\u201d, if you come back to this Common Cartridge, you won\u2019t be able to share new resources.
+monitoring.label.access.time =Access time
+monitoring.label.attachments =Attachments
+monitoring.label.group =Group
+monitoring.label.hidden =Hidden
+monitoring.label.hide =Hide
+monitoring.label.instructions =Instructions
+monitoring.label.number.learners =Number of Learners
+monitoring.label.show =Show
+monitoring.label.suggest =Suggested By
+monitoring.label.title =Title
+monitoring.label.type =Type
+monitoring.label.user.loginname =Login name
+monitoring.label.user.name =Name
+monitoring.summary.note =Note: number of learners is the number of learners who have viewed the resource.
+monitoring.tab.edit.activity =Edit Activity
+monitoring.tab.instructions =Instruction
+monitoring.tab.statistics =Statistic
+monitoring.tab.summary =Summary
+monitoring.user.fullname =Name
+monitoring.user.reflection =Notebook Entry
+monitor.summary.td.addNotebook =Add Notebook at end of Common Cartridge
+monitor.summary.td.notebookInstructions =Notebook instructions
+monitor.summary.th.advancedSettings =Advanced Settings
+msg.no.instruction =No instruction available.
+open.in.new.window =Open URL in pop-up
+page.title.monitoring.view.reflection =View Notebook Entries
+run.offline.message =This activity is not being done on the computer. Please see your instructor for details.
+title.reflection =Notebook Entry
+tool.description =Tool for sharing resources.
+tool.display.name =Common Cartridge Tool
+
+
+#======= End labels: Exported 172 labels for en AU =====
Index: lams_tool_imscc/conf/language/lams/ApplicationResources_en_AU.properties
===================================================================
diff -u
--- lams_tool_imscc/conf/language/lams/ApplicationResources_en_AU.properties (revision 0)
+++ lams_tool_imscc/conf/language/lams/ApplicationResources_en_AU.properties (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,11 @@
+appName = shareresources
+#language code: en
+#locale code: AU
+
+ # CVS ID: $Id$ Exported from the LAMS Community by Ernie Ghiglione on Wed Mar 03 00:17:40 CST 2010
+
+#=================== labels for ShareResources =================#
+
+
+
+#======= End labels: Exported 172 labels for en AU =====
Index: lams_tool_imscc/conf/language/rams/ApplicationResources.properties
===================================================================
diff -u
--- lams_tool_imscc/conf/language/rams/ApplicationResources.properties (revision 0)
+++ lams_tool_imscc/conf/language/rams/ApplicationResources.properties (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,171 @@
+appName = shareresources
+#language code: en
+#locale code: AU
+
+ # CVS ID: $Id$ Exported from the RAMS Community by Ernie Ghiglione on Tue Aug 12 12:00:29 EST 2008
+
+#=================== labels for ShareResources =================#
+
+appName =Share Resources
+activity.title =Common Cartridge
+activity.description =Sharing resource with others.
+activity.helptext =Uploading your resources to share with others.
+tool.display.name =Share Resources Tool
+tool.description =Tool for sharing resources.
+errorPage.title =Error page
+errorPage.heading =Some error occurs when handling your request
+label.authoring.heading =Share Resources
+label.author.title =Share Resources Authoring
+label.authoring.heading.basic =Basic
+label.authoring.heading.advance =Advanced
+label.authoring.heading.instructions =Instructions
+label.authoring.heading.basic.desc =Basic input information for shared resources
+label.authoring.heading.instructions.desc =Please input online and offline instructions
+label.authoring.heading.advance.desc =Please input advance options for shared resources
+label.authoring.basic.title =Title
+label.authoring.basic.instruction =Instruction
+label.authoring.basic.add.url =Add URL
+label.authoring.basic.add.file =Add Single File
+label.authoring.basic.add.website =Add Zipped Website
+label.authoring.basic.add.learning.object =Add IMS Content Package
+label.authoring.basic.resource.list.title =Resource List
+label.authoring.basic.resource.url =URL
+label.authoring.basic.resource.file =File
+label.authoring.basic.resource.website =Website
+label.authoring.basic.resource.learning.object =IMS CP
+label.authoring.basic.resource.verify.url =Verify URL
+label.authoring.basic.resource.preview =Preview
+label.authoring.basic.resource.edit =Edit
+label.authoring.basic.resource.delete =Delete
+label.authoring.basic.resource.add.instruction =Add Instruction
+label.authoring.basic.resource.instructions =Instructions
+label.authoring.basic.resource.title.input =Title
+label.authoring.basic.resource.url.input =URL
+label.authoring.basic.resource.file.input =File
+label.authoring.basic.resource.description.input =Description
+label.authoring.basic.resource.zip.file.input =Zip file:
+label.authoring.online.instruction =Online Instructions
+label.authoring.offline.instruction =Offline Instructions
+label.authoring.online.file =Upload online file
+label.authoring.offline.file =Upload offline file
+label.authoring.choosefile.button =Choose file
+label.authoring.upload.online.button =Upload Online
+label.authoring.upload.offline.button =Upload Offline
+label.authoring.online.filelist =Online file list
+label.authoring.offline.filelist =Offline file list
+label.authoring.online.delete =Delete
+label.authoring.offline.delete =Delete
+label.authoring.advance.lock.on.finished =Lock when finished
+label.authoring.advance.run.content.auto =Run content automatically (only available if there is exactly one resource)
+label.authoring.advance.mini.number.resources.view =Minimum number of resources to view
+label.authoring.advance.allow.learner.add.urls =Allow participants to add URLs
+label.authoring.advance.allow.learner.add.files =Allow participants to add Files
+label.next.instruction =Next Instruction
+label.authoring.save.button =Save
+label.authoring.cancel.button =Cancel
+label.description =Description:
+authoring.exception =There is a problem in shared resources authoring page, the reason is {0}
+error.resource.item.title.blank =Title can not be blank.
+error.resource.item.url.blank =URL can not be blank.
+error.resource.item.file.blank =File can not be blank.
+error.resource.item.desc.blank =Comment/Instruction can not be blank
+error.resource.item.invalid.url =Invalid URL format.
+error.upload.failed =Upload file failed: {0}
+error.msg.upload.file.not.found =Could not find upload file {0}.
+error.msg.zip.file.exception =Could not handle zip file when uploading file.
+error.msg.file.not.found =File not found exception occurs when uploading file.
+error.msg.ims.package =Invalid IMS CP format.
+error.msg.ims.application =ImscpApplicationException occurs when uploading resource item file.
+error.msg.website.no.initial.file =Website zip can not find out initial file (index.htm/html or default.htm/html).
+error.msg.io.exception =IOException occurs when uploading file.
+error.msg.invaid.param.upload =InvalidParameterException occured while trying to upload File.
+error.msg.repository =Repository occurs exception while trying to upload file.
+error.msg.default.content.not.find =Could not retrieve default content record for this tool.
+msg.no.instruction =No instruction available.
+authoring.msg.cancel.save =Do you want to close this window without saving?
+label.learning.title =Share Resource
+label.learning.heading =Share Resources
+label.resoruce.to.review =Resources to view
+label.learning.minimum.review =You must view at least {0} of the resources.
+lable.learning.minimum.view.number.less =You at least view another {0} of the resources.
+label.check.for.new =Check for new
+label.suggest.new =Suggest a new
+label.learning.new.file =New file details:
+label.learning.new.url =New URL details:
+label.learning.comment.or.instruction =Comment/Instruction
+monitoring.tab.summary =Summary
+monitoring.tab.statistics =Statistic
+monitoring.tab.instructions =Instruction
+monitoring.tab.edit.activity =Edit Activity
+monitoring.label.group =Group
+monitoring.summary.note =Note: number of participants is the number of participants who have viewed the resource.
+monitoring.label.type =Type
+monitoring.label.title =Title
+monitoring.label.suggest =Suggested By
+monitoring.label.number.learners =Number of Participants
+monitoring.label.hide =Hide
+monitoring.label.show =Show
+monitoring.label.user.loginname =Login name
+monitoring.label.user.name =Name
+monitoring.label.hidden =Hidden
+label.monitoring.edit.activity.cancel =Cancel
+label.monitoring.edit.activity.update =Update
+label.monitoring.edit.activity.edit =Edit
+message.monitoring.edit.activity.not.editable =This Activity is no longer editable
+export.label.resource =Resource
+export.label.no.learning.object =No offline package available
+export.title =Export portfolio of Share Resource
+export.init.resource =Initial Resources
+errors.header =
+errors.footer =
+error.valueReqd =Value Required
+error.inputFileTooLarge =Input File size is too large!
+error.uploading =error uploading
+error.title.empty =Title can not be blank
+message.msg.maxFileSize =Max 250K
+label.open =Open
+label.delete =Delete
+label.download =Download
+label.view =View
+label.edit =Edit
+label.finished =Finished
+label.completed =Completed
+label.finish =Finish
+button.upload =Upload
+button.add =Add
+button.cancel =Cancel
+message.monitoring.summary.no.session =No Session Available
+label.show =Show
+label.hide =Hide
+label.save =Save
+label.cancel =Cancel
+monitoring.label.access.time =Access time
+define.later.message =Please wait for the researcher to complete the contents of this activity.
+run.offline.message =This activity is not being done on the computer. Please see your instructor for details.
+message.monitoring.summary.no.resource.for.group =No resource available for this group.
+button.try.again =Try again
+open.in.new.window =Open URL in pop-up
+label.up =Move Up
+label.down =Move down
+label.authoring.advanced.reflectOnActivity =Add Notebook at end of Shared Resources with the following instructions:
+error.reflection.emtpy =Please input reflection
+title.reflection =Reflection
+label.continue =Continue
+monitoring.user.fullname =Name
+monitoring.user.reflection =Reflection
+page.title.monitoring.view.reflection =View Reflection
+button.close =Close
+message.step.of =Step {0} of {1}
+message.no.reflection.available =No notebook available
+button.edit =Edit
+errors.maxfilesize =The uploaded file has exceeded the maximum file size limit of {0} bytes
+error.attachment.executable =The uploaded file is executable, please zip it before uploading.
+label.monitoring.heading.access =Participants list
+message.alertContentEdit =Warning: One of more participants have accessed this activity. Changing this content will result in students getting different information.
+label.export.reflection =Notebook Entries
+monitoring.label.attachments =Attachments
+message.activityLocked =Note: After you click on "Next Activity" and you come back to this Share Resources, you won't be able to continue.
+message.warnLockOnFinish =This activitiy has been setup not to allow sharing and viewing of resources after it has been finished.
+
+
+#======= End labels: Exported 160 labels for en AU =====
Index: lams_tool_imscc/conf/language/rams/ApplicationResources_en_AU.properties
===================================================================
diff -u
--- lams_tool_imscc/conf/language/rams/ApplicationResources_en_AU.properties (revision 0)
+++ lams_tool_imscc/conf/language/rams/ApplicationResources_en_AU.properties (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,171 @@
+appName = shareresources
+#language code: en
+#locale code: AU
+
+ # CVS ID: $Id$ Exported from the RAMS Community by Ernie Ghiglione on Tue Aug 12 12:00:29 EST 2008
+
+#=================== labels for ShareResources =================#
+
+appName =Share Resources
+activity.title =Common Cartridge
+activity.description =Sharing resource with others.
+activity.helptext =Uploading your resources to share with others.
+tool.display.name =Share Resources Tool
+tool.description =Tool for sharing resources.
+errorPage.title =Error page
+errorPage.heading =Some error occurs when handling your request
+label.authoring.heading =Share Resources
+label.author.title =Share Resources Authoring
+label.authoring.heading.basic =Basic
+label.authoring.heading.advance =Advanced
+label.authoring.heading.instructions =Instructions
+label.authoring.heading.basic.desc =Basic input information for shared resources
+label.authoring.heading.instructions.desc =Please input online and offline instructions
+label.authoring.heading.advance.desc =Please input advance options for shared resources
+label.authoring.basic.title =Title
+label.authoring.basic.instruction =Instruction
+label.authoring.basic.add.url =Add URL
+label.authoring.basic.add.file =Add Single File
+label.authoring.basic.add.website =Add Zipped Website
+label.authoring.basic.add.learning.object =Add IMS Content Package
+label.authoring.basic.resource.list.title =Resource List
+label.authoring.basic.resource.url =URL
+label.authoring.basic.resource.file =File
+label.authoring.basic.resource.website =Website
+label.authoring.basic.resource.learning.object =IMS CP
+label.authoring.basic.resource.verify.url =Verify URL
+label.authoring.basic.resource.preview =Preview
+label.authoring.basic.resource.edit =Edit
+label.authoring.basic.resource.delete =Delete
+label.authoring.basic.resource.add.instruction =Add Instruction
+label.authoring.basic.resource.instructions =Instructions
+label.authoring.basic.resource.title.input =Title
+label.authoring.basic.resource.url.input =URL
+label.authoring.basic.resource.file.input =File
+label.authoring.basic.resource.description.input =Description
+label.authoring.basic.resource.zip.file.input =Zip file:
+label.authoring.online.instruction =Online Instructions
+label.authoring.offline.instruction =Offline Instructions
+label.authoring.online.file =Upload online file
+label.authoring.offline.file =Upload offline file
+label.authoring.choosefile.button =Choose file
+label.authoring.upload.online.button =Upload Online
+label.authoring.upload.offline.button =Upload Offline
+label.authoring.online.filelist =Online file list
+label.authoring.offline.filelist =Offline file list
+label.authoring.online.delete =Delete
+label.authoring.offline.delete =Delete
+label.authoring.advance.lock.on.finished =Lock when finished
+label.authoring.advance.run.content.auto =Run content automatically (only available if there is exactly one resource)
+label.authoring.advance.mini.number.resources.view =Minimum number of resources to view
+label.authoring.advance.allow.learner.add.urls =Allow participants to add URLs
+label.authoring.advance.allow.learner.add.files =Allow participants to add Files
+label.next.instruction =Next Instruction
+label.authoring.save.button =Save
+label.authoring.cancel.button =Cancel
+label.description =Description:
+authoring.exception =There is a problem in shared resources authoring page, the reason is {0}
+error.resource.item.title.blank =Title can not be blank.
+error.resource.item.url.blank =URL can not be blank.
+error.resource.item.file.blank =File can not be blank.
+error.resource.item.desc.blank =Comment/Instruction can not be blank
+error.resource.item.invalid.url =Invalid URL format.
+error.upload.failed =Upload file failed: {0}
+error.msg.upload.file.not.found =Could not find upload file {0}.
+error.msg.zip.file.exception =Could not handle zip file when uploading file.
+error.msg.file.not.found =File not found exception occurs when uploading file.
+error.msg.ims.package =Invalid IMS CP format.
+error.msg.ims.application =ImscpApplicationException occurs when uploading resource item file.
+error.msg.website.no.initial.file =Website zip can not find out initial file (index.htm/html or default.htm/html).
+error.msg.io.exception =IOException occurs when uploading file.
+error.msg.invaid.param.upload =InvalidParameterException occured while trying to upload File.
+error.msg.repository =Repository occurs exception while trying to upload file.
+error.msg.default.content.not.find =Could not retrieve default content record for this tool.
+msg.no.instruction =No instruction available.
+authoring.msg.cancel.save =Do you want to close this window without saving?
+label.learning.title =Share Resource
+label.learning.heading =Share Resources
+label.resoruce.to.review =Resources to view
+label.learning.minimum.review =You must view at least {0} of the resources.
+lable.learning.minimum.view.number.less =You at least view another {0} of the resources.
+label.check.for.new =Check for new
+label.suggest.new =Suggest a new
+label.learning.new.file =New file details:
+label.learning.new.url =New URL details:
+label.learning.comment.or.instruction =Comment/Instruction
+monitoring.tab.summary =Summary
+monitoring.tab.statistics =Statistic
+monitoring.tab.instructions =Instruction
+monitoring.tab.edit.activity =Edit Activity
+monitoring.label.group =Group
+monitoring.summary.note =Note: number of participants is the number of participants who have viewed the resource.
+monitoring.label.type =Type
+monitoring.label.title =Title
+monitoring.label.suggest =Suggested By
+monitoring.label.number.learners =Number of Participants
+monitoring.label.hide =Hide
+monitoring.label.show =Show
+monitoring.label.user.loginname =Login name
+monitoring.label.user.name =Name
+monitoring.label.hidden =Hidden
+label.monitoring.edit.activity.cancel =Cancel
+label.monitoring.edit.activity.update =Update
+label.monitoring.edit.activity.edit =Edit
+message.monitoring.edit.activity.not.editable =This Activity is no longer editable
+export.label.resource =Resource
+export.label.no.learning.object =No offline package available
+export.title =Export portfolio of Share Resource
+export.init.resource =Initial Resources
+errors.header =
+errors.footer =
+error.valueReqd =Value Required
+error.inputFileTooLarge =Input File size is too large!
+error.uploading =error uploading
+error.title.empty =Title can not be blank
+message.msg.maxFileSize =Max 250K
+label.open =Open
+label.delete =Delete
+label.download =Download
+label.view =View
+label.edit =Edit
+label.finished =Finished
+label.completed =Completed
+label.finish =Finish
+button.upload =Upload
+button.add =Add
+button.cancel =Cancel
+message.monitoring.summary.no.session =No Session Available
+label.show =Show
+label.hide =Hide
+label.save =Save
+label.cancel =Cancel
+monitoring.label.access.time =Access time
+define.later.message =Please wait for the researcher to complete the contents of this activity.
+run.offline.message =This activity is not being done on the computer. Please see your instructor for details.
+message.monitoring.summary.no.resource.for.group =No resource available for this group.
+button.try.again =Try again
+open.in.new.window =Open URL in pop-up
+label.up =Move Up
+label.down =Move down
+label.authoring.advanced.reflectOnActivity =Add Notebook at end of Shared Resources with the following instructions:
+error.reflection.emtpy =Please input reflection
+title.reflection =Reflection
+label.continue =Continue
+monitoring.user.fullname =Name
+monitoring.user.reflection =Reflection
+page.title.monitoring.view.reflection =View Reflection
+button.close =Close
+message.step.of =Step {0} of {1}
+message.no.reflection.available =No notebook available
+button.edit =Edit
+errors.maxfilesize =The uploaded file has exceeded the maximum file size limit of {0} bytes
+error.attachment.executable =The uploaded file is executable, please zip it before uploading.
+label.monitoring.heading.access =Participants list
+message.alertContentEdit =Warning: One of more participants have accessed this activity. Changing this content will result in students getting different information.
+label.export.reflection =Notebook Entries
+monitoring.label.attachments =Attachments
+message.activityLocked =Note: After you click on "Next Activity" and you come back to this Share Resources, you won't be able to continue.
+message.warnLockOnFinish =This activitiy has been setup not to allow sharing and viewing of resources after it has been finished.
+
+
+#======= End labels: Exported 160 labels for en AU =====
Index: lams_tool_imscc/conf/war/META-INF/MANIFEST.MF
===================================================================
diff -u
--- lams_tool_imscc/conf/war/META-INF/MANIFEST.MF (revision 0)
+++ lams_tool_imscc/conf/war/META-INF/MANIFEST.MF (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,4 @@
+Implementation-Title: LAMS - CommonCartridge Tool
+Implementation-Version: 2.1
+Implementation-Vendor: LAMS Foundation (http://lamsfoundation.org)
+Class-Path: ./lams.jar ./lams-tool-laimsc11.jar ./lams-contentrepository.jar
Index: lams_tool_imscc/conf/xdoclet/global-exceptions.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/global-exceptions.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/global-exceptions.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,8 @@
+
+
+
Index: lams_tool_imscc/conf/xdoclet/global-forwards.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/global-forwards.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/global-forwards.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,6 @@
+
+
+
+
+
+
Index: lams_tool_imscc/conf/xdoclet/struts-actions.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/struts-actions.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/struts-actions.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: lams_tool_imscc/conf/xdoclet/struts-forms.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/struts-forms.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/struts-forms.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1 @@
+
Index: lams_tool_imscc/conf/xdoclet/struts-message-resources.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/struts-message-resources.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/struts-message-resources.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1 @@
+
Index: lams_tool_imscc/conf/xdoclet/struts-plugins.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/struts-plugins.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/struts-plugins.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,15 @@
+
+
+
+
+
+
Index: lams_tool_imscc/conf/xdoclet/validation-forms.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/validation-forms.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/validation-forms.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,29 @@
+
Index: lams_tool_imscc/conf/xdoclet/validation-global.xml
===================================================================
diff -u
--- lams_tool_imscc/conf/xdoclet/validation-global.xml (revision 0)
+++ lams_tool_imscc/conf/xdoclet/validation-global.xml (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,6 @@
+
+
+ datePattern
+ yyyy-MM-dd
+
+
Index: lams_tool_imscc/db/model/commonCartridge.clay
===================================================================
diff -u
--- lams_tool_imscc/db/model/commonCartridge.clay (revision 0)
+++ lams_tool_imscc/db/model/commonCartridge.clay (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,873 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: lams_tool_imscc/db/sql/activity_insert.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/activity_insert.sql (revision 0)
+++ lams_tool_imscc/db/sql/activity_insert.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,82 @@
+# Connection: ROOT LOCAL
+# Host: localhost
+# Saved: 2005-04-07 11:08:32
+#
+INSERT INTO lams_learning_activity
+(
+activity_ui_id
+, description
+, title
+, help_text
+, xcoord
+, ycoord
+, parent_activity_id
+, parent_ui_id
+, learning_activity_type_id
+, grouping_support_type_id
+, apply_grouping_flag
+, grouping_id
+, grouping_ui_id
+, order_id
+, define_later_flag
+, learning_design_id
+, learning_library_id
+, create_date_time
+, run_offline_flag
+, max_number_of_options
+, min_number_of_options
+, options_instructions
+, tool_id
+, tool_content_id
+, activity_category_id
+, gate_activity_level_id
+, gate_open_flag
+, gate_start_time_offset
+, gate_end_time_offset
+, gate_start_date_time
+, gate_end_date_time
+, library_activity_ui_image
+, create_grouping_id
+, create_grouping_ui_id
+, library_activity_id
+, language_file
+)
+VALUES
+(
+NULL
+, 'CommonCartridge'
+, 'CommonCartridge'
+, 'Put some help text here.'
+, NULL
+, NULL
+, NULL
+, NULL
+, 1
+, 2
+, 0
+, NULL
+, NULL
+, NULL
+, 0
+, NULL
+, ${learning_library_id}
+, NOW()
+, 0
+, NULL
+, NULL
+, NULL
+, ${tool_id}
+, NULL
+, 4
+, NULL
+, NULL
+, NULL
+, NULL
+, NULL
+, NULL
+, 'tool/laimsc11/images/icon_commonCartridge.swf'
+, NULL
+, NULL
+, NULL
+, 'org.lamsfoundation.lams.tool.commonCartridge.ApplicationResources'
+)
Index: lams_tool_imscc/db/sql/create_lams_tool_commonCartridge.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/create_lams_tool_commonCartridge.sql (revision 0)
+++ lams_tool_imscc/db/sql/create_lams_tool_commonCartridge.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,141 @@
+SET FOREIGN_KEY_CHECKS=0;
+drop table if exists tl_laimsc11_attachment;
+drop table if exists tl_laimsc11_item_instruction;
+drop table if exists tl_laimsc11_commonCartridge;
+drop table if exists tl_laimsc11_commonCartridge_item;
+drop table if exists tl_laimsc11_commonCartridge_item_visit_log;
+drop table if exists tl_laimsc11_session;
+drop table if exists tl_laimsc11_user;
+drop table if exists tl_laimsc11_configuration;
+
+create table tl_laimsc11_attachment (
+ uid bigint not null auto_increment,
+ file_version_id bigint,
+ file_type varchar(255),
+ file_name varchar(255),
+ file_uuid bigint,
+ create_date datetime,
+ commonCartridge_uid bigint,
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_item_instruction (
+ uid bigint not null auto_increment,
+ description varchar(255),
+ sequence_id integer,
+ item_uid bigint,
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_commonCartridge (
+ uid bigint not null auto_increment,
+ create_date datetime,
+ update_date datetime,
+ create_by bigint,
+ title varchar(255),
+ run_offline tinyint,
+ lock_on_finished tinyint,
+ instructions text,
+ online_instructions text,
+ offline_instructions text,
+ content_in_use tinyint,
+ define_later tinyint,
+ content_id bigint unique,
+ mini_view_commonCartridge_number integer,
+ allow_auto_run tinyint,
+ reflect_instructions varchar(255),
+ reflect_on_activity smallint,
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_commonCartridge_item (
+ uid bigint not null auto_increment,
+ file_uuid bigint,
+ file_version_id bigint,
+ description varchar(255),
+ ims_schema varchar(255),
+ init_item varchar(255),
+ organization_xml text,
+ title varchar(255),
+ url text,
+ launch_url varchar(255),
+ secure_launch_url varchar(255),
+ tool_key varchar(255),
+ tool_secret varchar(255),
+ custom_str text,
+ button_text varchar(255),
+ frame_height integer,
+ create_by bigint,
+ create_date datetime,
+ create_by_author tinyint,
+ is_hide tinyint,
+ item_type smallint,
+ file_type varchar(255),
+ file_name varchar(255),
+ open_url_new_window tinyint,
+ commonCartridge_uid bigint,
+ session_uid bigint,
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_item_log (
+ uid bigint not null auto_increment,
+ access_date datetime,
+ commonCartridge_item_uid bigint,
+ user_uid bigint,
+ complete tinyint,
+ session_id bigint,
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_session (
+ uid bigint not null auto_increment,
+ session_end_date datetime,
+ session_start_date datetime,
+ status integer,
+ commonCartridge_uid bigint,
+ session_id bigint,
+ session_name varchar(250),
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_user (
+ uid bigint not null auto_increment,
+ user_id bigint,
+ last_name varchar(255),
+ first_name varchar(255),
+ login_name varchar(255),
+ session_finished smallint,
+ session_uid bigint,
+ commonCartridge_uid bigint,
+ primary key (uid)
+)type=innodb;
+create table tl_laimsc11_configuration (
+ uid bigint not null auto_increment,
+ config_key varchar(30) unique,
+ config_value varchar(255),
+ primary key (uid)
+)TYPE=InnoDB;
+
+alter table tl_laimsc11_attachment add index FK_NEW_1279208528_1E7009430E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_1E7009430E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_item_instruction add index FK_NEW_1279208528_A5665013980570ED (item_uid), add constraint FK_NEW_1279208528_A5665013980570ED foreign key (item_uid) references tl_laimsc11_commonCartridge_item (uid);
+alter table tl_laimsc11_commonCartridge add index FK_NEW_1279208528_89093BF758092FB (create_by), add constraint FK_NEW_1279208528_89093BF758092FB foreign key (create_by) references tl_laimsc11_user (uid);
+alter table tl_laimsc11_commonCartridge_item add index FK_NEW_1279208528_F52D1F93758092FB (create_by), add constraint FK_NEW_1279208528_F52D1F93758092FB foreign key (create_by) references tl_laimsc11_user (uid);
+alter table tl_laimsc11_commonCartridge_item add index FK_NEW_1279208528_F52D1F9330E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_F52D1F9330E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_commonCartridge_item add index FK_NEW_1279208528_F52D1F93EC0D3147 (session_uid), add constraint FK_NEW_1279208528_F52D1F93EC0D3147 foreign key (session_uid) references tl_laimsc11_session (uid);
+alter table tl_laimsc11_item_log add index FK_NEW_1279208528_693580A438BF8DFE (commonCartridge_item_uid), add constraint FK_NEW_1279208528_693580A438BF8DFE foreign key (commonCartridge_item_uid) references tl_laimsc11_commonCartridge_item (uid);
+alter table tl_laimsc11_item_log add index FK_NEW_1279208528_693580A441F9365D (user_uid), add constraint FK_NEW_1279208528_693580A441F9365D foreign key (user_uid) references tl_laimsc11_user (uid);
+alter table tl_laimsc11_session add index FK_NEW_1279208528_24AA78C530E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_24AA78C530E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_user add index FK_NEW_1279208528_30113BFCEC0D3147 (session_uid), add constraint FK_NEW_1279208528_30113BFCEC0D3147 foreign key (session_uid) references tl_laimsc11_session (uid);
+alter table tl_laimsc11_user add index FK_NEW_1279208528_30113BFC309ED320 (commonCartridge_uid), add constraint FK_NEW_1279208528_30113BFC309ED320 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+
+
+
+INSERT INTO `tl_laimsc11_commonCartridge` (`uid`, `create_date`, `update_date`, `create_by`, `title`, `run_offline`, `lock_on_finished`,
+ `instructions`, `online_instructions`, `offline_instructions`, `content_in_use`, `define_later`, `content_id`,
+ `mini_view_commonCartridge_number`, `allow_auto_run`,`reflect_on_activity`) VALUES
+ (1,NULL,NULL,NULL,'CommonCartridge','0','0','Instructions ',null,null,0,0,${default_content_id},0,0,0);
+
+INSERT INTO `tl_laimsc11_commonCartridge_item` (`uid`, `file_uuid`, `file_version_id`, `description`, `ims_schema`, `init_item`, `organization_xml`, `title`, `url`, `create_by`, `create_date`, `create_by_author`, `is_hide`, `item_type`, `file_type`, `file_name`, `open_url_new_window`, `commonCartridge_uid`, `session_uid`, `frame_height`) VALUES
+ (1,NULL,NULL,NULL,NULL,NULL,NULL,'Web Search','http://www.google.com ',null,NOW(),1,0,1,NULL,NULL,0,1,NULL, 100);
+
+INSERT INTO `tl_laimsc11_configuration` (`config_key`, `config_value`) VALUES
+ ('allowExposeUserName', 'true');
+INSERT INTO `tl_laimsc11_configuration` (`config_key`, `config_value`) VALUES
+ ('allowExposeUserEmail', 'true');
+
+SET FOREIGN_KEY_CHECKS=1;
Index: lams_tool_imscc/db/sql/db_version_insert.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/db_version_insert.sql (revision 0)
+++ lams_tool_imscc/db/sql/db_version_insert.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,2 @@
+-- $Id$
+INSERT INTO patches VALUES ('@signature@', '@tool_version@', NOW(), 'F');
Index: lams_tool_imscc/db/sql/drop_lams_tool_commonCartridge.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/drop_lams_tool_commonCartridge.sql (revision 0)
+++ lams_tool_imscc/db/sql/drop_lams_tool_commonCartridge.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,14 @@
+SET FOREIGN_KEY_CHECKS=0;
+drop table if exists tl_laimsc11_attachment;
+drop table if exists tl_laimsc11_item_instruction;
+drop table if exists tl_laimsc11_commonCartridge;
+drop table if exists tl_laimsc11_commonCartridge_item;
+drop table if exists tl_laimsc11_item_log;
+drop table if exists tl_laimsc11_session;
+drop table if exists tl_laimsc11_user;
+SET FOREIGN_KEY_CHECKS=1;
+
+
+
+
+
Index: lams_tool_imscc/db/sql/library_insert.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/library_insert.sql (revision 0)
+++ lams_tool_imscc/db/sql/library_insert.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,18 @@
+# Connection: ROOT LOCAL
+# Host: localhost
+# Saved: 2005-04-07 10:50:55
+#
+INSERT INTO lams_learning_library
+(
+description,
+title,
+valid_flag,
+create_date_time
+)
+VALUES
+(
+'Share commonCartridge',
+'Share commonCartridge',
+0,
+NOW()
+)
Index: lams_tool_imscc/db/sql/table-schema.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/table-schema.sql (revision 0)
+++ lams_tool_imscc/db/sql/table-schema.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,36 @@
+alter table tl_laimsc11_attachment drop foreign key FK_NEW_1279208528_1E7009430E79035;
+alter table tl_laimsc11_item_instruction drop foreign key FK_NEW_1279208528_A5665013980570ED;
+alter table tl_laimsc11_item_log drop foreign key FK_NEW_1279208528_63195BC938BF8DFE;
+alter table tl_laimsc11_item_log drop foreign key FK_NEW_1279208528_63195BC941F9365D;
+alter table tl_laimsc11_commonCartridge drop foreign key FK_NEW_1279208528_89093BF758092FB;
+alter table tl_laimsc11_commonCartridge_item drop foreign key FK_NEW_1279208528_F52D1F9330E79035;
+alter table tl_laimsc11_commonCartridge_item drop foreign key FK_NEW_1279208528_F52D1F93EC0D3147;
+alter table tl_laimsc11_commonCartridge_item drop foreign key FK_NEW_1279208528_F52D1F93758092FB;
+alter table tl_laimsc11_session drop foreign key FK_NEW_1279208528_24AA78C530E79035;
+alter table tl_laimsc11_user drop foreign key FK_NEW_1279208528_30113BFC30E79035;
+alter table tl_laimsc11_user drop foreign key FK_NEW_1279208528_30113BFCEC0D3147;
+drop table if exists tl_laimsc11_attachment;
+drop table if exists tl_laimsc11_item_instruction;
+drop table if exists tl_laimsc11_item_log;
+drop table if exists tl_laimsc11_commonCartridge;
+drop table if exists tl_laimsc11_commonCartridge_item;
+drop table if exists tl_laimsc11_session;
+drop table if exists tl_laimsc11_user;
+create table tl_laimsc11_attachment (uid bigint not null auto_increment, file_version_id bigint, file_type varchar(255), file_name varchar(255), file_uuid bigint, create_date datetime, commonCartridge_uid bigint, primary key (uid));
+create table tl_laimsc11_item_instruction (uid bigint not null auto_increment, description varchar(255), sequence_id integer, item_uid bigint, primary key (uid));
+create table tl_laimsc11_item_log (uid bigint not null auto_increment, access_date datetime, commonCartridge_item_uid bigint, user_uid bigint, complete bit, session_id bigint, primary key (uid));
+create table tl_laimsc11_commonCartridge (uid bigint not null auto_increment, create_date datetime, update_date datetime, create_by bigint, title varchar(255), run_offline bit, lock_on_finished bit, instructions text, online_instructions text, offline_instructions text, content_in_use bit, define_later bit, content_id bigint unique, allow_add_files bit, allow_add_urls bit, mini_view_commonCartridge_number integer, allow_auto_run bit, reflect_instructions varchar(255), reflect_on_activity bit,assigment_submit_notify tinyint DEFAULT 0, primary key (uid));
+create table tl_laimsc11_commonCartridge_item (uid bigint not null auto_increment, file_uuid bigint, file_version_id bigint, description varchar(255), ims_schema varchar(255), init_item varchar(255), organization_xml text, title varchar(255), url text, create_by bigint, create_date datetime, create_by_author bit, is_hide bit, item_type smallint, file_type varchar(255), file_name varchar(255), open_url_new_window bit, commonCartridge_uid bigint, session_uid bigint, primary key (uid));
+create table tl_laimsc11_session (uid bigint not null auto_increment, session_end_date datetime, session_start_date datetime, status integer, commonCartridge_uid bigint, session_id bigint, session_name varchar(250), primary key (uid));
+create table tl_laimsc11_user (uid bigint not null auto_increment, user_id bigint, last_name varchar(255), first_name varchar(255), login_name varchar(255), session_uid bigint, commonCartridge_uid bigint, session_finished bit, primary key (uid));
+alter table tl_laimsc11_attachment add index FK_NEW_1279208528_1E7009430E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_1E7009430E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_item_instruction add index FK_NEW_1279208528_A5665013980570ED (item_uid), add constraint FK_NEW_1279208528_A5665013980570ED foreign key (item_uid) references tl_laimsc11_commonCartridge_item (uid);
+alter table tl_laimsc11_item_log add index FK_NEW_1279208528_63195BC938BF8DFE (commonCartridge_item_uid), add constraint FK_NEW_1279208528_63195BC938BF8DFE foreign key (commonCartridge_item_uid) references tl_laimsc11_commonCartridge_item (uid);
+alter table tl_laimsc11_item_log add index FK_NEW_1279208528_63195BC941F9365D (user_uid), add constraint FK_NEW_1279208528_63195BC941F9365D foreign key (user_uid) references tl_laimsc11_user (uid);
+alter table tl_laimsc11_commonCartridge add index FK_NEW_1279208528_89093BF758092FB (create_by), add constraint FK_NEW_1279208528_89093BF758092FB foreign key (create_by) references tl_laimsc11_user (uid);
+alter table tl_laimsc11_commonCartridge_item add index FK_NEW_1279208528_F52D1F9330E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_F52D1F9330E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_commonCartridge_item add index FK_NEW_1279208528_F52D1F93EC0D3147 (session_uid), add constraint FK_NEW_1279208528_F52D1F93EC0D3147 foreign key (session_uid) references tl_laimsc11_session (uid);
+alter table tl_laimsc11_commonCartridge_item add index FK_NEW_1279208528_F52D1F93758092FB (create_by), add constraint FK_NEW_1279208528_F52D1F93758092FB foreign key (create_by) references tl_laimsc11_user (uid);
+alter table tl_laimsc11_session add index FK_NEW_1279208528_24AA78C530E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_24AA78C530E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_user add index FK_NEW_1279208528_30113BFC30E79035 (commonCartridge_uid), add constraint FK_NEW_1279208528_30113BFC30E79035 foreign key (commonCartridge_uid) references tl_laimsc11_commonCartridge (uid);
+alter table tl_laimsc11_user add index FK_NEW_1279208528_30113BFCEC0D3147 (session_uid), add constraint FK_NEW_1279208528_30113BFCEC0D3147 foreign key (session_uid) references tl_laimsc11_session (uid);
Index: lams_tool_imscc/db/sql/tool_insert.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/tool_insert.sql (revision 0)
+++ lams_tool_imscc/db/sql/tool_insert.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,64 @@
+# Connection: ROOT LOCAL
+# Host: localhost
+# Saved: 2005-04-07 10:42:43
+#
+INSERT INTO lams_tool
+(
+tool_signature,
+service_name,
+tool_display_name,
+description,
+tool_identifier,
+tool_version,
+learning_library_id,
+default_tool_content_id,
+valid_flag,
+grouping_support_type_id,
+supports_run_offline_flag,
+learner_url,
+learner_preview_url,
+learner_progress_url,
+author_url,
+monitor_url,
+define_later_url,
+export_pfolio_learner_url,
+export_pfolio_class_url,
+contribute_url,
+moderation_url,
+pedagogical_planner_url,
+help_url,
+language_file,
+create_date_time,
+modified_date_time,
+admin_url
+)
+VALUES
+(
+'laimsc11',
+'commonCartridgeService',
+'Shared CommonCartridge',
+'Shared CommonCartridge',
+'sharedcommonCartridge',
+'@tool_version@',
+NULL,
+NULL,
+0,
+2,
+1,
+'tool/laimsc11/learning/start.do?mode=learner',
+'tool/laimsc11/learning/start.do?mode=author',
+'tool/laimsc11/learning/start.do?mode=teacher',
+'tool/laimsc11/authoring/start.do',
+'tool/laimsc11/monitoring/summary.do',
+'tool/laimsc11/definelater.do',
+'tool/laimsc11/exportPortfolio?mode=learner',
+'tool/laimsc11/exportPortfolio?mode=teacher',
+'tool/laimsc11/contribute.do',
+'tool/laimsc11/moderate.do',
+'tool/laimsc11/authoring/initPedagogicalPlannerForm.do',
+'http://wiki.lamsfoundation.org/display/lamsdocs/laimsc11',
+'org.lamsfoundation.lams.tool.commonCartridge.ApplicationResources',
+NOW(),
+NOW(),
+'tool/laimsc11/laimsc11admin/start.do'
+)
Index: lams_tool_imscc/db/sql/updatescripts/updateTo20070227.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/updatescripts/updateTo20070227.sql (revision 0)
+++ lams_tool_imscc/db/sql/updatescripts/updateTo20070227.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,4 @@
+-- Update the CommonCartridge tables to 20070227
+-- This is for the LAMS 2.0.1 release.
+
+UPDATE lams_tool set modified_date_time = now(), classpath_addition = 'lams-tool-laimsc11.jar', context_file = '/org/lamsfoundation/lams/tool/commonCartridge/commonCartridgeApplicationContext.xml' where tool_signature = 'laimsc11';
Index: lams_tool_imscc/db/sql/updatescripts/updateTo20080229.sql
===================================================================
diff -u
--- lams_tool_imscc/db/sql/updatescripts/updateTo20080229.sql (revision 0)
+++ lams_tool_imscc/db/sql/updatescripts/updateTo20080229.sql (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,2 @@
+UPDATE lams_tool SET modified_date_time = NOW() WHERE tool_signature = "laimsc11";
+UPDATE lams_tool SET tool_version = "20080229" WHERE tool_signature = "laimsc11";
Index: lams_tool_imscc/lib/jaxen/jaxen-full.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/jaxen/sax.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/jaxen/saxpath.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/castor-0.9.5.3-xml.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/jdom.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/moonunitsrc.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/reload-diva.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/reload-editor.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/reload-jdom.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/reload-moonunit.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/lib/reload_2_0_1/xercesImpl.jar
===================================================================
diff -u
Binary files differ
Index: lams_tool_imscc/licenses/Jaxen LICENSE.txt
===================================================================
diff -u
--- lams_tool_imscc/licenses/Jaxen LICENSE.txt (revision 0)
+++ lams_tool_imscc/licenses/Jaxen LICENSE.txt (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,33 @@
+/*
+ $Id$
+
+ Copyright 2003-2006 The Werken Company. All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the Jaxen Project nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
Index: lams_tool_imscc/licenses/castor license.txt
===================================================================
diff -u
--- lams_tool_imscc/licenses/castor license.txt (revision 0)
+++ lams_tool_imscc/licenses/castor license.txt (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,38 @@
+Copyright 2000-2002 (C) Intalio Inc. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright statements
+ and notices. Redistributions must also contain a copy of this
+ document.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name "ExoLab" must not be used to endorse or promote products
+ derived from this Software without prior written permission of
+ Intalio Inc. For written permission, please contact info@exolab.org.
+
+4. Products derived from this Software may not be called "Castor"
+ nor may "Castor" appear in their names without prior written
+ permission of Intalio Inc. Exolab, Castor and Intalio are
+ trademarks of Intalio Inc.
+
+5. Due credit should be given to the ExoLab Project
+ (http://www.exolab.org/).
+
+THIS SOFTWARE IS PROVIDED BY INTALIO AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO OR ITS
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
Index: lams_tool_imscc/licenses/jdom licence.txt
===================================================================
diff -u
--- lams_tool_imscc/licenses/jdom licence.txt (revision 0)
+++ lams_tool_imscc/licenses/jdom licence.txt (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,54 @@
+/*--
+
+ Copyright (C) 2000-2002 Brett McLaughlin & Jason Hunter.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions, and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions, and the disclaimer that follows
+ these conditions in the documentation and/or other materials
+ provided with the distribution.
+
+ 3. The name "JDOM" must not be used to endorse or promote products
+ derived from this software without prior written permission. For
+ written permission, please contact license@jdom.org.
+
+ 4. Products derived from this software may not be called "JDOM", nor
+ may "JDOM" appear in their name, without prior written permission
+ from the JDOM Project Management (pm@jdom.org).
+
+ In addition, we request (but do not require) that you include in the
+ end-user documentation provided with the redistribution and/or in the
+ software itself an acknowledgement equivalent to the following:
+ "This product includes software developed by the
+ JDOM Project (http://www.jdom.org/)."
+ Alternatively, the acknowledgment may be graphical using the logos
+ available at http://www.jdom.org/images/logos.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many
+ individuals on behalf of the JDOM Project and was originally
+ created by Brett McLaughlin and
+ Jason Hunter . For more information on the
+ JDOM Project, please see .
+
+ */
+
Index: lams_tool_imscc/licenses/library_licenses.txt
===================================================================
diff -u
--- lams_tool_imscc/licenses/library_licenses.txt (revision 0)
+++ lams_tool_imscc/licenses/library_licenses.txt (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,28 @@
+Tigra Tree Javascript license description:
+There is no license fee or royalty fee to be paid at any time for using the Tigra Tree Menu v1.x
+You may include the source code or modified source code within your own projects for either personal or commercial use but excluding the restrictions outlined below. The following restrictions apply to all parts of the component, including all source code, samples and documentation.
+
+ * Header block of script file (tree.js) CAN NOT be modified or removed.
+ * The above items CAN NOT be sold as are, either individually or together.
+ * The above items CAN NOT be modified and then sold as a library component, either individually or together.
+
+
+For more detail, http://www.softcomplex.com/products/tigra_tree_menu/docs/
+
+Library/Package License
+
+Used for the IMSCP functionality (Reload Project)
+castor-0.9.5.3-xml.jar Castor License
+jdom.jar Jdom Jar License
+moonunitsrc.jar Reload License
+reload-diva.jar Reload License
+reload-editor.jar Reload License
+reload-jdom.jar Reload License
+reload-moonunit.jar Reload License
+xercesImpl.jar Apache Software License 1.1
+xml-apis.jar Apache Software License 1.1
+
+Other libraries
+jaxen-full.jar Jaxen Jar License (The Werken Company)
+sax.jar Public Domain
+saxpath.jar Jaxen Jar License (The Werken Company)
Index: lams_tool_imscc/licenses/reload licence.txt
===================================================================
diff -u
--- lams_tool_imscc/licenses/reload licence.txt (revision 0)
+++ lams_tool_imscc/licenses/reload licence.txt (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,45 @@
+RELOAD Tools and Libraries
+
+Copyright (c) 2002-2004 Oleg Liber, Bill Olivier, Phillip Beauvoir
+
+This licence covers:
+
+The Reload "jdom" library
+The Reload "diva" library
+The Reload "dweezil" library
+The Reload "jdom" library
+The Reload "moonunit" library
+The Reload "xindice" library
+The Reload Editor
+The Reload SCORM Player
+The Reload Schema Viewer Eclipse Plugin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Project Management Contact:
+
+Oleg Liber
+Bolton Institute of Higher Education
+Deane Road
+Bolton BL3 5AB
+UK
+
+e-mail: o.liber@bolton.ac.uk
+
+
+Technical Contact:
+
+Phillip Beauvoir
+Bolton Institute of Higher Education
+Deane Road
+Bolton BL3 5AB
+UK
+
+e-mail: p.beauvoir@bolton.ac.uk
+
+
+Web: http://www.reload.ac.uk
Index: lams_tool_imscc/licenses/xerces licence.txt
===================================================================
diff -u
--- lams_tool_imscc/licenses/xerces licence.txt (revision 0)
+++ lams_tool_imscc/licenses/xerces licence.txt (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,56 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xerces" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.ibm.com. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
Index: lams_tool_imscc/src/java/net/oauth/ConsumerProperties.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/ConsumerProperties.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/ConsumerProperties.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A pool of OAuthConsumers that are constructed from Properties. Each consumer
+ * has a name, which is a property of the OAuthConsumer. Other properties come
+ * from Properties whose names are prefixed with the consumer's name. For
+ * example, a consumer's credentials come from properties named
+ * [name].consumerKey and [name].consumerSecret.
+ *
+ * @author John Kristian
+ */
+public class ConsumerProperties {
+
+ public static URL getResource(String name, ClassLoader loader)
+ throws IOException {
+ URL resource = loader.getResource(name);
+ if (resource == null) {
+ throw new IOException("resource not found: " + name);
+ }
+ return resource;
+ }
+
+ public static Properties getProperties(URL source) throws IOException {
+ InputStream input = source.openStream();
+ try {
+ Properties p = new Properties();
+ p.load(input);
+ return p;
+ } finally {
+ input.close();
+ }
+ }
+
+ public ConsumerProperties(String resourceName, ClassLoader loader)
+ throws IOException {
+ this(getProperties(getResource(resourceName, loader)));
+ }
+
+ public ConsumerProperties(Properties consumerProperties) {
+ this.consumerProperties = consumerProperties;
+ }
+
+ private final Properties consumerProperties;
+
+ private final Map pool = new HashMap();
+
+ /** Get the consumer with the given name. */
+ public OAuthConsumer getConsumer(String name) throws MalformedURLException {
+ OAuthConsumer consumer;
+ synchronized (pool) {
+ consumer = pool.get(name);
+ }
+ if (consumer == null) {
+ consumer = newConsumer(name);
+ }
+ synchronized (pool) {
+ OAuthConsumer first = pool.get(name);
+ if (first == null) {
+ pool.put(name, consumer);
+ } else {
+ /*
+ * Another thread just constructed an identical OAuthConsumer.
+ * Use that one (and discard the one we just constructed).
+ */
+ consumer = first;
+ }
+ }
+ return consumer;
+ }
+
+ protected OAuthConsumer newConsumer(String name)
+ throws MalformedURLException {
+ String base = consumerProperties.getProperty(name
+ + ".serviceProvider.baseURL");
+ URL baseURL = (base == null) ? null : new URL(base);
+ OAuthServiceProvider serviceProvider = new OAuthServiceProvider(getURL(
+ baseURL, name + ".serviceProvider.requestTokenURL"), getURL(
+ baseURL, name + ".serviceProvider.userAuthorizationURL"),
+ getURL(baseURL, name + ".serviceProvider.accessTokenURL"));
+ OAuthConsumer consumer = new OAuthConsumer(consumerProperties
+ .getProperty(name + ".callbackURL"), consumerProperties
+ .getProperty(name + ".consumerKey"), consumerProperties
+ .getProperty(name + ".consumerSecret"), serviceProvider);
+ consumer.setProperty("name", name);
+ if (baseURL != null) {
+ consumer.setProperty("serviceProvider.baseURL", baseURL);
+ }
+ for (Map.Entry prop : consumerProperties.entrySet()) {
+ String propName = (String) prop.getKey();
+ if (propName.startsWith(name + ".consumer.")) {
+ String c = propName.substring(name.length() + 10);
+ consumer.setProperty(c, prop.getValue());
+ }
+ }
+ return consumer;
+ }
+
+ private String getURL(URL base, String name) throws MalformedURLException {
+ String url = consumerProperties.getProperty(name);
+ if (base != null) {
+ url = (new URL(base, url)).toExternalForm();
+ }
+ return url;
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuth.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuth.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuth.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author John Kristian
+ */
+public class OAuth {
+
+ public static final String VERSION_1_0 = "1.0";
+
+ /** The encoding used to represent characters as bytes. */
+ public static final String ENCODING = "UTF-8";
+
+ /** The MIME type for a sequence of OAuth parameters. */
+ public static final String FORM_ENCODED = "application/x-www-form-urlencoded";
+
+ public static final String OAUTH_CONSUMER_KEY = "oauth_consumer_key";
+ public static final String OAUTH_TOKEN = "oauth_token";
+ public static final String OAUTH_TOKEN_SECRET = "oauth_token_secret";
+ public static final String OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
+ public static final String OAUTH_SIGNATURE = "oauth_signature";
+ public static final String OAUTH_TIMESTAMP = "oauth_timestamp";
+ public static final String OAUTH_NONCE = "oauth_nonce";
+ public static final String OAUTH_VERSION = "oauth_version";
+ public static final String OAUTH_CALLBACK = "oauth_callback";
+
+ public static final String HMAC_SHA1 = "HMAC-SHA1";
+ public static final String RSA_SHA1 = "RSA-SHA1";
+
+ /**
+ * Strings used for problem
+ * reporting.
+ */
+ public static class Problems {
+ public static final String VERSION_REJECTED = "version_rejected";
+ public static final String PARAMETER_ABSENT = "parameter_absent";
+ public static final String PARAMETER_REJECTED = "parameter_rejected";
+ public static final String TIMESTAMP_REFUSED = "timestamp_refused";
+ public static final String NONCE_USED = "nonce_used";
+ public static final String SIGNATURE_METHOD_REJECTED = "signature_method_rejected";
+ public static final String SIGNATURE_INVALID = "signature_invalid";
+ public static final String CONSUMER_KEY_UNKNOWN = "consumer_key_unknown";
+ public static final String CONSUMER_KEY_REJECTED = "consumer_key_rejected";
+ public static final String CONSUMER_KEY_REFUSED = "consumer_key_refused";
+ public static final String TOKEN_USED = "token_used";
+ public static final String TOKEN_EXPIRED = "token_expired";
+ public static final String TOKEN_REVOKED = "token_revoked";
+ public static final String TOKEN_REJECTED = "token_rejected";
+ public static final String ADDITIONAL_AUTHORIZATION_REQUIRED = "additional_authorization_required";
+ public static final String PERMISSION_UNKNOWN = "permission_unknown";
+ public static final String PERMISSION_DENIED = "permission_denied";
+ public static final String USER_REFUSED = "user_refused";
+
+ public static final String OAUTH_ACCEPTABLE_VERSIONS = "oauth_acceptable_versions";
+ public static final String OAUTH_ACCEPTABLE_TIMESTAMPS = "oauth_acceptable_timestamps";
+ public static final String OAUTH_PARAMETERS_ABSENT = "oauth_parameters_absent";
+ public static final String OAUTH_PARAMETERS_REJECTED = "oauth_parameters_rejected";
+ public static final String OAUTH_PROBLEM_ADVICE = "oauth_problem_advice";
+
+ /**
+ * A map from an oauth_problem value to
+ * the appropriate HTTP response code.
+ */
+ public static final Map TO_HTTP_CODE = mapToHttpCode();
+
+ private static Map mapToHttpCode() {
+ Integer badRequest = new Integer(400);
+ Integer unauthorized = new Integer(401);
+ Integer serviceUnavailable = new Integer(503);
+ Map map = new HashMap();
+
+ map.put(Problems.VERSION_REJECTED, badRequest);
+ map.put(Problems.PARAMETER_ABSENT, badRequest);
+ map.put(Problems.PARAMETER_REJECTED, badRequest);
+ map.put(Problems.TIMESTAMP_REFUSED, badRequest);
+ map.put(Problems.SIGNATURE_METHOD_REJECTED, badRequest);
+
+ map.put(Problems.NONCE_USED, unauthorized);
+ map.put(Problems.TOKEN_USED, unauthorized);
+ map.put(Problems.TOKEN_EXPIRED, unauthorized);
+ map.put(Problems.TOKEN_REVOKED, unauthorized);
+ map.put(Problems.TOKEN_REJECTED, unauthorized);
+ map.put("token_not_authorized", unauthorized);
+ map.put(Problems.SIGNATURE_INVALID, unauthorized);
+ map.put(Problems.CONSUMER_KEY_UNKNOWN, unauthorized);
+ map.put(Problems.CONSUMER_KEY_REJECTED, unauthorized);
+ map.put(Problems.ADDITIONAL_AUTHORIZATION_REQUIRED, unauthorized);
+ map.put(Problems.PERMISSION_UNKNOWN, unauthorized);
+ map.put(Problems.PERMISSION_DENIED, unauthorized);
+
+ map.put(Problems.USER_REFUSED, serviceUnavailable);
+ map.put(Problems.CONSUMER_KEY_REFUSED, serviceUnavailable);
+ return Collections.unmodifiableMap(map);
+ }
+
+ }
+
+ /** Return true if the given Content-Type header means FORM_ENCODED. */
+ public static boolean isFormEncoded(String contentType) {
+ if (contentType == null) {
+ return false;
+ }
+ int semi = contentType.indexOf(";");
+ if (semi >= 0) {
+ contentType = contentType.substring(0, semi);
+ }
+ return FORM_ENCODED.equalsIgnoreCase(contentType.trim());
+ }
+
+ /**
+ * Construct a form-urlencoded document containing the given sequence of
+ * name/value pairs. Use OAuth percent encoding (not exactly the encoding
+ * mandated by HTTP).
+ */
+ public static String formEncode(Iterable extends Map.Entry> parameters)
+ throws IOException {
+ ByteArrayOutputStream b = new ByteArrayOutputStream();
+ formEncode(parameters, b);
+ return new String(b.toByteArray());
+ }
+
+ /**
+ * Write a form-urlencoded document into the given stream, containing the
+ * given sequence of name/value pairs.
+ */
+ public static void formEncode(Iterable extends Map.Entry> parameters,
+ OutputStream into) throws IOException {
+ if (parameters != null) {
+ boolean first = true;
+ for (Map.Entry parameter : parameters) {
+ if (first) {
+ first = false;
+ } else {
+ into.write('&');
+ }
+ into.write(percentEncode(toString(parameter.getKey()))
+ .getBytes());
+ into.write('=');
+ into.write(percentEncode(toString(parameter.getValue()))
+ .getBytes());
+ }
+ }
+ }
+
+ /** Parse a form-urlencoded document. */
+ public static List decodeForm(String form) {
+ List list = new ArrayList();
+ if (!isEmpty(form)) {
+ for (String nvp : form.split("\\&")) {
+ int equals = nvp.indexOf('=');
+ String name;
+ String value;
+ if (equals < 0) {
+ name = decodePercent(nvp);
+ value = null;
+ } else {
+ name = decodePercent(nvp.substring(0, equals));
+ value = decodePercent(nvp.substring(equals + 1));
+ }
+ list.add(new Parameter(name, value));
+ }
+ }
+ return list;
+ }
+
+ /** Construct a &-separated list of the given values, percentEncoded. */
+ public static String percentEncode(Iterable values) {
+ StringBuilder p = new StringBuilder();
+ for (Object v : values) {
+ if (p.length() > 0) {
+ p.append("&");
+ }
+ p.append(OAuth.percentEncode(toString(v)));
+ }
+ return p.toString();
+ }
+
+ public static String percentEncode(String s) {
+ if (s == null) {
+ return "";
+ }
+ try {
+ return URLEncoder.encode(s, ENCODING)
+ // OAuth encodes some characters differently:
+ .replace("+", "%20").replace("*", "%2A")
+ .replace("%7E", "~");
+ // This could be done faster with more hand-crafted code.
+ } catch (UnsupportedEncodingException wow) {
+ throw new RuntimeException(wow.getMessage(), wow);
+ }
+ }
+
+ public static String decodePercent(String s) {
+ try {
+ return URLDecoder.decode(s, ENCODING);
+ // This implements http://oauth.pbwiki.com/FlexibleDecoding
+ } catch (java.io.UnsupportedEncodingException wow) {
+ throw new RuntimeException(wow.getMessage(), wow);
+ }
+ }
+
+ /**
+ * Construct a Map containing a copy of the given parameters. If several
+ * parameters have the same name, the Map will contain the first value,
+ * only.
+ */
+ public static Map newMap(Iterable extends Map.Entry> from) {
+ Map map = new HashMap();
+ if (from != null) {
+ for (Map.Entry f : from) {
+ String key = toString(f.getKey());
+ if (!map.containsKey(key)) {
+ map.put(key, toString(f.getValue()));
+ }
+ }
+ }
+ return map;
+ }
+
+ /** Construct a list of Parameters from name, value, name, value... */
+ public static List newList(String... parameters) {
+ List list = new ArrayList(parameters.length / 2);
+ for (int p = 0; p + 1 < parameters.length; p += 2) {
+ list.add(new Parameter(parameters[p], parameters[p + 1]));
+ }
+ return list;
+ }
+
+ /** A name/value pair. */
+ public static class Parameter implements Map.Entry {
+
+ public Parameter(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ private final String key;
+
+ private String value;
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String setValue(String value) {
+ try {
+ return this.value;
+ } finally {
+ this.value = value;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return percentEncode(getKey()) + '=' + percentEncode(getValue());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Parameter that = (Parameter) obj;
+ if (key == null) {
+ if (that.key != null)
+ return false;
+ } else if (!key.equals(that.key))
+ return false;
+ if (value == null) {
+ if (that.value != null)
+ return false;
+ } else if (!value.equals(that.value))
+ return false;
+ return true;
+ }
+ }
+
+ private static final String toString(Object from) {
+ return (from == null) ? null : from.toString();
+ }
+
+ /**
+ * Construct a URL like the given one, but with the given parameters added
+ * to its query string.
+ */
+ public static String addParameters(String url, String... parameters)
+ throws IOException {
+ return addParameters(url, newList(parameters));
+ }
+
+ public static String addParameters(String url,
+ Iterable extends Map.Entry> parameters)
+ throws IOException {
+ String form = formEncode(parameters);
+ if (form == null || form.length() <= 0) {
+ return url;
+ } else {
+ return url + ((url.indexOf("?") < 0) ? '?' : '&') + form;
+ }
+ }
+
+ public static boolean isEmpty(String str) {
+ return (str == null) || (str.length() == 0);
+ }
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthAccessor.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthAccessor.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthAccessor.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Properties of one User of an OAuthConsumer. Properties may be added freely,
+ * e.g. to support extensions.
+ *
+ * @author John Kristian
+ */
+public class OAuthAccessor implements Cloneable, Serializable {
+
+ private static final long serialVersionUID = 5590788443138352999L;
+
+ public final OAuthConsumer consumer;
+ public String requestToken;
+ public String accessToken;
+ public String tokenSecret;
+
+ public OAuthAccessor(OAuthConsumer consumer) {
+ this.consumer = consumer;
+ this.requestToken = null;
+ this.accessToken = null;
+ this.tokenSecret = null;
+ }
+
+ private final Map properties = new HashMap();
+
+ @Override
+ public OAuthAccessor clone() {
+ try {
+ return (OAuthAccessor) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Object getProperty(String name) {
+ return properties.get(name);
+ }
+
+ public void setProperty(String name, Object value) {
+ properties.put(name, value);
+ }
+
+ /**
+ * Construct a request message containing the given parameters but no body.
+ * Don't send the message, merely construct it. The caller will ordinarily
+ * send it, for example by calling OAuthClient.invoke or access.
+ *
+ * @param method
+ * the HTTP request method. If this is null, use the default
+ * method; that is getProperty("httpMethod") or (if that's null)
+ * consumer.getProperty("httpMethod") or (if that's null)
+ * OAuthMessage.GET.
+ */
+ public OAuthMessage newRequestMessage(String method, String url, Collection extends Map.Entry> parameters,
+ InputStream body) throws OAuthException, IOException, URISyntaxException {
+ if (method == null) {
+ method = (String) this.getProperty("httpMethod");
+ if (method == null) {
+ method = (String) this.consumer.getProperty("httpMethod");
+ if (method == null) {
+ method = OAuthMessage.GET;
+ }
+ }
+ }
+ OAuthMessage message = new OAuthMessage(method, url, parameters, body);
+ message.addRequiredParameters(this);
+ return message;
+ }
+
+ public OAuthMessage newRequestMessage(String method, String url, Collection extends Map.Entry> parameters)
+ throws OAuthException, IOException, URISyntaxException {
+ return newRequestMessage(method, url, parameters, null);
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthConsumer.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthConsumer.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthConsumer.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.oauth.http.HttpMessage;
+
+/**
+ * Properties of an OAuth Consumer. Properties may be added freely, e.g. to
+ * support extensions.
+ *
+ * @author John Kristian
+ */
+public class OAuthConsumer implements Serializable {
+
+ private static final long serialVersionUID = -2258581186977818580L;
+
+ public final String callbackURL;
+ public final String consumerKey;
+ public final String consumerSecret;
+ public final OAuthServiceProvider serviceProvider;
+
+ public OAuthConsumer(String callbackURL, String consumerKey,
+ String consumerSecret, OAuthServiceProvider serviceProvider) {
+ this.callbackURL = callbackURL;
+ this.consumerKey = consumerKey;
+ this.consumerSecret = consumerSecret;
+ this.serviceProvider = serviceProvider;
+ }
+
+ private final Map properties = new HashMap();
+
+ public Object getProperty(String name) {
+ return properties.get(name);
+ }
+
+ public void setProperty(String name, Object value) {
+ properties.put(name, value);
+ }
+
+ /**
+ * The name of the property whose value is the Accept-Encoding header in
+ * HTTP requests.
+ */
+ public static final String ACCEPT_ENCODING = "HTTP.header." + HttpMessage.ACCEPT_ENCODING;
+
+ /**
+ * The name of the property whose value is the Accessor Secret.
+ */
+ public static final String ACCESSOR_SECRET = "oauth_accessor_secret";
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthException.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthException.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthException.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.oauth;
+
+/**
+ * Superclass for extensions thrown by the OAuth library.
+ */
+public class OAuthException extends Exception {
+
+ /**
+ * For subclasses only.
+ */
+ protected OAuthException() {
+ }
+
+ /**
+ * @param message
+ */
+ public OAuthException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param cause
+ */
+ public OAuthException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public OAuthException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthMessage.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthMessage.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthMessage.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2007, 2008 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.oauth.client.OAuthClient;
+import net.oauth.http.HttpMessage;
+import net.oauth.signature.OAuthSignatureMethod;
+
+/**
+ * A request or response message used in the OAuth protocol.
+ *
+ * The parameters in this class are not percent-encoded. Methods like
+ * OAuthClient.invoke and OAuthResponseMessage.completeParameters are
+ * responsible for percent-encoding parameters before transmission and decoding
+ * them after reception.
+ *
+ * @author John Kristian
+ */
+public class OAuthMessage {
+
+ public OAuthMessage(String method, String URL, Collection extends Map.Entry> parameters) {
+ this(method, URL, parameters, null);
+ }
+
+ public OAuthMessage(String method, String URL, Collection extends Map.Entry> parameters,
+ InputStream bodyAsStream) {
+ this.method = method;
+ this.URL = URL;
+ this.bodyAsStream = bodyAsStream;
+ if (parameters == null) {
+ this.parameters = new ArrayList>();
+ } else {
+ this.parameters = new ArrayList>(parameters.size());
+ for (Map.Entry p : parameters) {
+ this.parameters.add(new OAuth.Parameter(
+ toString(p.getKey()), toString(p.getValue())));
+ }
+ }
+ }
+
+ public String method;
+ public String URL;
+
+ private final List> parameters;
+ private Map parameterMap;
+ private boolean parametersAreComplete = false;
+ private final List> headers = new ArrayList>();
+ private final InputStream bodyAsStream;
+
+ public String toString() {
+ return "OAuthMessage(" + method + ", " + URL + ", " + parameters + ")";
+ }
+
+ /** A caller is about to get a parameter. */
+ private void beforeGetParameter() throws IOException {
+ if (!parametersAreComplete) {
+ completeParameters();
+ parametersAreComplete = true;
+ }
+ }
+
+ /**
+ * Finish adding parameters; for example read an HTTP response body and
+ * parse parameters from it.
+ */
+ protected void completeParameters() throws IOException {
+ }
+
+ public List> getParameters() throws IOException {
+ beforeGetParameter();
+ return Collections.unmodifiableList(parameters);
+ }
+
+ public void addParameter(String key, String value) {
+ addParameter(new OAuth.Parameter(key, value));
+ }
+
+ public void addParameter(Map.Entry parameter) {
+ parameters.add(parameter);
+ parameterMap = null;
+ }
+
+ public void addParameters(
+ Collection extends Map.Entry> parameters) {
+ this.parameters.addAll(parameters);
+ parameterMap = null;
+ }
+
+ public String getParameter(String name) throws IOException {
+ return getParameterMap().get(name);
+ }
+
+ public String getConsumerKey() throws IOException {
+ return getParameter(OAuth.OAUTH_CONSUMER_KEY);
+ }
+
+ public String getToken() throws IOException {
+ return getParameter(OAuth.OAUTH_TOKEN);
+ }
+
+ public String getSignatureMethod() throws IOException {
+ return getParameter(OAuth.OAUTH_SIGNATURE_METHOD);
+ }
+
+ public String getSignature() throws IOException {
+ return getParameter(OAuth.OAUTH_SIGNATURE);
+ }
+
+ protected Map getParameterMap() throws IOException {
+ beforeGetParameter();
+ if (parameterMap == null) {
+ parameterMap = OAuth.newMap(parameters);
+ }
+ return parameterMap;
+ }
+
+ /**
+ * The MIME type of the body of this message.
+ *
+ * @return the MIME type, or null to indicate the type is unknown.
+ */
+ public String getBodyType() {
+ return getHeader(HttpMessage.CONTENT_TYPE);
+ }
+
+ /**
+ * The character encoding of the body of this message.
+ *
+ * @return the name of an encoding, or "ISO-8859-1" if no charset has been
+ * specified.
+ */
+ public String getBodyEncoding() {
+ return HttpMessage.DEFAULT_CHARSET;
+ }
+
+ /**
+ * The value of the last HTTP header with the given name. The name is case
+ * insensitive.
+ *
+ * @return the value of the last header, or null to indicate that there is
+ * no such header in this message.
+ */
+ public final String getHeader(String name) {
+ String value = null; // no such header
+ for (Map.Entry header : getHeaders()) {
+ if (name.equalsIgnoreCase(header.getKey())) {
+ value = header.getValue();
+ }
+ }
+ return value;
+ }
+
+ /** All HTTP headers. You can add headers to this list. */
+ public final List> getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Read the body of the HTTP request or response and convert it to a String.
+ * This method isn't repeatable, since it consumes and closes getBodyAsStream.
+ *
+ * @return the body, or null to indicate there is no body.
+ */
+ public final String readBodyAsString() throws IOException
+ {
+ InputStream body = getBodyAsStream();
+ return readAll(body, getBodyEncoding());
+ }
+
+ /**
+ * Get a stream from which to read the body of the HTTP request or response.
+ * This is designed to support efficient streaming of a large message.
+ * The caller must close the returned stream, to release the underlying
+ * resources such as the TCP connection for an HTTP response.
+ *
+ * @return a stream from which to read the body, or null to indicate there
+ * is no body.
+ */
+ public InputStream getBodyAsStream() throws IOException {
+ return bodyAsStream;
+ }
+
+ /** Construct a verbose description of this message and its origins. */
+ public Map getDump() throws IOException {
+ Map into = new HashMap();
+ dump(into);
+ return into;
+ }
+
+ protected void dump(Map into) throws IOException {
+ into.put("URL", URL);
+ if (parametersAreComplete) {
+ try {
+ into.putAll(getParameterMap());
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ /**
+ * Verify that the required parameter names are contained in the actual
+ * collection.
+ *
+ * @throws OAuthProblemException
+ * one or more parameters are absent.
+ * @throws IOException
+ */
+ public void requireParameters(String... names)
+ throws OAuthProblemException, IOException {
+ Set present = getParameterMap().keySet();
+ List absent = new ArrayList();
+ for (String required : names) {
+ if (!present.contains(required)) {
+ absent.add(required);
+ }
+ }
+ if (!absent.isEmpty()) {
+ OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT);
+ problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.percentEncode(absent));
+ throw problem;
+ }
+ }
+
+ /**
+ * Add some of the parameters needed to request access to a protected
+ * resource, if they aren't already in the message.
+ *
+ * @throws IOException
+ * @throws URISyntaxException
+ */
+ public void addRequiredParameters(OAuthAccessor accessor)
+ throws OAuthException, IOException, URISyntaxException {
+ final Map pMap = OAuth.newMap(parameters);
+ if (pMap.get(OAuth.OAUTH_TOKEN) == null && accessor.accessToken != null) {
+ addParameter(OAuth.OAUTH_TOKEN, accessor.accessToken);
+ }
+ final OAuthConsumer consumer = accessor.consumer;
+ if (pMap.get(OAuth.OAUTH_CONSUMER_KEY) == null) {
+ addParameter(OAuth.OAUTH_CONSUMER_KEY, consumer.consumerKey);
+ }
+ String signatureMethod = pMap.get(OAuth.OAUTH_SIGNATURE_METHOD);
+ if (signatureMethod == null) {
+ signatureMethod = (String) consumer.getProperty(OAuth.OAUTH_SIGNATURE_METHOD);
+ if (signatureMethod == null) {
+ signatureMethod = OAuth.HMAC_SHA1;
+ }
+ addParameter(OAuth.OAUTH_SIGNATURE_METHOD, signatureMethod);
+ }
+ if (pMap.get(OAuth.OAUTH_TIMESTAMP) == null) {
+ addParameter(OAuth.OAUTH_TIMESTAMP, (System.currentTimeMillis() / 1000) + "");
+ }
+ if (pMap.get(OAuth.OAUTH_NONCE) == null) {
+ addParameter(OAuth.OAUTH_NONCE, System.nanoTime() + "");
+ }
+ if (pMap.get(OAuth.OAUTH_VERSION) == null) {
+ addParameter(OAuth.OAUTH_VERSION, OAuth.VERSION_1_0);
+ }
+ this.sign(accessor);
+ }
+
+ /**
+ * Add a signature to the message.
+ *
+ * @throws URISyntaxException
+ */
+ public void sign(OAuthAccessor accessor) throws IOException,
+ OAuthException, URISyntaxException {
+ OAuthSignatureMethod.newSigner(this, accessor).sign(this);
+ }
+
+ /**
+ * Construct an HTTP request from this OAuth message.
+ *
+ * @param style
+ * where to put the OAuth parameters, within the HTTP request
+ * @deprecated use HttpMessage.newRequest
+ */
+ public HttpMessage toHttpRequest(OAuthClient.ParameterStyle style) throws IOException {
+ return HttpMessage.newRequest(this, style.getReplacement());
+ }
+
+ /**
+ * Check that the message is valid.
+ *
+ * @throws IOException
+ * @throws URISyntaxException
+ *
+ * @throws OAuthProblemException
+ * the message is invalid
+ */
+ public void validateMessage(OAuthAccessor accessor, OAuthValidator validator)
+ throws OAuthException, IOException, URISyntaxException {
+ validator.validateMessage(this, accessor);
+ }
+
+ /**
+ * Construct a WWW-Authenticate or Authentication header value, containing
+ * the given realm plus all the parameters whose names begin with "oauth_".
+ */
+ public String getAuthorizationHeader(String realm) throws IOException {
+ StringBuilder into = new StringBuilder();
+ if (realm != null) {
+ into.append(" realm=\"").append(OAuth.percentEncode(realm)).append('"');
+ }
+ beforeGetParameter();
+ if (parameters != null) {
+ for (Map.Entry parameter : parameters) {
+ String name = toString(parameter.getKey());
+ if (name.startsWith("oauth_")) {
+ if (into.length() > 0) into.append(",");
+ into.append(" ");
+ into.append(OAuth.percentEncode(name)).append("=\"");
+ into.append(OAuth.percentEncode(toString(parameter.getValue()))).append('"');
+ }
+ }
+ }
+ return AUTH_SCHEME + into.toString();
+ }
+
+ /**
+ * Read all the data from the given stream, and close it.
+ *
+ * @return null if from is null, or the data from the stream converted to a
+ * String
+ */
+ public static String readAll(InputStream from, String encoding) throws IOException
+ {
+ if (from == null) {
+ return null;
+ }
+ try {
+ StringBuilder into = new StringBuilder();
+ Reader r = new InputStreamReader(from, encoding);
+ char[] s = new char[512];
+ for (int n; 0 < (n = r.read(s));) {
+ into.append(s, 0, n);
+ }
+ return into.toString();
+ } finally {
+ from.close();
+ }
+ }
+
+ /**
+ * Parse the parameters from an OAuth Authorization or WWW-Authenticate
+ * header. The realm is included as a parameter. If the given header doesn't
+ * start with "OAuth ", return an empty list.
+ */
+ public static List decodeAuthorization(String authorization) {
+ List into = new ArrayList();
+ if (authorization != null) {
+ Matcher m = AUTHORIZATION.matcher(authorization);
+ if (m.matches()) {
+ if (AUTH_SCHEME.equalsIgnoreCase(m.group(1))) {
+ for (String nvp : m.group(2).split("\\s*,\\s*")) {
+ m = NVP.matcher(nvp);
+ if (m.matches()) {
+ String name = OAuth.decodePercent(m.group(1));
+ String value = OAuth.decodePercent(m.group(2));
+ into.add(new OAuth.Parameter(name, value));
+ }
+ }
+ }
+ }
+ }
+ return into;
+ }
+
+ public static final String AUTH_SCHEME = "OAuth";
+
+ public static final String GET = "GET";
+ public static final String POST = "POST";
+ public static final String PUT = "PUT";
+ public static final String DELETE = "DELETE";
+
+ private static final Pattern AUTHORIZATION = Pattern.compile("\\s*(\\w*)\\s+(.*)");
+ private static final Pattern NVP = Pattern.compile("(\\S*)\\s*\\=\\s*\"([^\"]*)\"");
+
+ private static final String toString(Object from) {
+ return (from == null) ? null : from.toString();
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthProblemException.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthProblemException.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthProblemException.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.oauth.http.HttpMessage;
+
+/**
+ * Describes an OAuth-related problem, using a set of named parameters. One
+ * parameter identifies the basic problem, and the others provide supplementary
+ * diagnostic information. This can be used to capture information from a
+ * response that conforms to the OAuth Problem Reporting
+ * extension.
+ *
+ * @author John Kristian
+ */
+public class OAuthProblemException extends OAuthException {
+
+ public static final String OAUTH_PROBLEM = "oauth_problem";
+
+ public OAuthProblemException() {
+ }
+
+ public OAuthProblemException(String problem) {
+ super(problem);
+ if (problem != null) {
+ parameters.put(OAUTH_PROBLEM, problem);
+ }
+ }
+
+ private final Map parameters = new HashMap();
+
+ @Override
+ public String getMessage() {
+ String msg = super.getMessage();
+ if (msg != null)
+ return msg;
+ msg = getProblem();
+ if (msg != null)
+ return msg;
+ Object response = getParameters().get(HttpMessage.RESPONSE);
+ if (response != null) {
+ msg = response.toString();
+ int eol = msg.indexOf("\n");
+ if (eol < 0) {
+ eol = msg.indexOf("\r");
+ }
+ if (eol >= 0) {
+ msg = msg.substring(0, eol);
+ }
+ msg = msg.trim();
+ if (msg.length() > 0) {
+ return msg;
+ }
+ }
+ response = getHttpStatusCode();
+ if (response != null) {
+ return HttpMessage.STATUS_CODE + " " + response;
+ }
+ return null;
+ }
+
+ public void setParameter(String name, Object value) {
+ getParameters().put(name, value);
+ }
+
+ public Map getParameters() {
+ return parameters;
+ }
+
+ public String getProblem() {
+ return (String) getParameters().get(OAUTH_PROBLEM);
+ }
+
+ public int getHttpStatusCode() {
+ Object code = getParameters().get(HttpMessage.STATUS_CODE);
+ if (code == null) {
+ return 200;
+ } else if (code instanceof Number) { // the usual case
+ return ((Number) code).intValue();
+ } else {
+ return Integer.parseInt(code.toString());
+ }
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthServiceProvider.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthServiceProvider.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthServiceProvider.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.Serializable;
+
+/**
+ * Properties of an OAuth Service Provider.
+ *
+ * @author John Kristian
+ */
+public class OAuthServiceProvider implements Serializable {
+
+ private static final long serialVersionUID = 3306534392621038574L;
+
+ public final String requestTokenURL;
+ public final String userAuthorizationURL;
+ public final String accessTokenURL;
+
+ public OAuthServiceProvider(String requestTokenURL,
+ String userAuthorizationURL, String accessTokenURL) {
+ this.requestTokenURL = requestTokenURL;
+ this.userAuthorizationURL = userAuthorizationURL;
+ this.accessTokenURL = accessTokenURL;
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/OAuthValidator.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/OAuthValidator.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/OAuthValidator.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.oauth;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+/**
+ * An algorithm to determine whether a message has a valid signature, a correct
+ * version number, a fresh timestamp, etc.
+ *
+ * @author Dirk Balfanz
+ * @author John Kristian
+ */
+public interface OAuthValidator {
+
+ /**
+ * Check that the given message from the given accessor is valid.
+ * @throws OAuthException TODO
+ * @throws IOException TODO
+ * @throws URISyntaxException
+ * @throws OAuthProblemException the message is invalid.
+ * The implementation should throw exceptions that conform to the OAuth
+ * Problem Reporting extension.
+ */
+ public void validateMessage(OAuthMessage message, OAuthAccessor accessor)
+ throws OAuthException, IOException, URISyntaxException;
+
+}
Index: lams_tool_imscc/src/java/net/oauth/ParameterStyle.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/ParameterStyle.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/ParameterStyle.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,24 @@
+package net.oauth;
+
+/**
+ * Where to place OAuth parameters in an HTTP message. The alternatives are
+ * summarized in OAuth Core section 5.2.
+ */
+public enum ParameterStyle {
+ /**
+ * Send parameters whose names begin with "oauth_" in an HTTP header, and
+ * other parameters (whose names don't begin with "oauth_") in either the
+ * message body or URL query string. The header formats are specified by
+ * OAuth Core section 5.4.
+ */
+ AUTHORIZATION_HEADER,
+
+ /**
+ * Send all parameters in the message body, with a Content-Type of
+ * application/x-www-form-urlencoded.
+ */
+ BODY,
+
+ /** Send all parameters in the query string part of the URL. */
+ QUERY_STRING;
+}
Index: lams_tool_imscc/src/java/net/oauth/SimpleOAuthValidator.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/SimpleOAuthValidator.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/SimpleOAuthValidator.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2008 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.oauth;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import net.oauth.signature.OAuthSignatureMethod;
+
+/**
+ * A simple OAuthValidator, which checks the version, whether the timestamp
+ * is close to now and the signature is valid. Each check may be overridden.
+ *
+ * @author Dirk Balfanz
+ * @author John Kristian
+ */
+public class SimpleOAuthValidator implements OAuthValidator {
+
+ /** The default window for timestamps is 5 minutes. */
+ public static final long DEFAULT_TIMESTAMP_WINDOW = 5 * 60 * 1000L;
+
+ /**
+ * Names of parameters that may not appear twice in a valid message.
+ * This limitation is specified by OAuth Core section 5.
+ */
+ public static final Set SINGLE_PARAMETERS = constructSingleParameters();
+
+ private static Set constructSingleParameters() {
+ Set s = new HashSet();
+ for (String p : new String[] { OAuth.OAUTH_CONSUMER_KEY, OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET,
+ OAuth.OAUTH_CALLBACK, OAuth.OAUTH_SIGNATURE_METHOD, OAuth.OAUTH_SIGNATURE, OAuth.OAUTH_TIMESTAMP,
+ OAuth.OAUTH_NONCE, OAuth.OAUTH_VERSION }) {
+ s.add(p);
+ }
+ return Collections.unmodifiableSet(s);
+ }
+
+ /**
+ * Construct a validator that rejects messages more than five minutes out
+ * of date, or with a OAuth version other than 1.0, or with an invalid
+ * signature.
+ */
+ public SimpleOAuthValidator() {
+ this(DEFAULT_TIMESTAMP_WINDOW, Double.parseDouble(OAuth.VERSION_1_0));
+ }
+
+ /**
+ * Public constructor.
+ *
+ * @param timestampWindowSec
+ * specifies, in seconds, the windows (into the past and
+ * into the future) in which we'll accept timestamps.
+ * @param maxVersion
+ * the maximum acceptable oauth_version
+ */
+ public SimpleOAuthValidator(long timestampWindowMsec, double maxVersion) {
+ this.timestampWindow = timestampWindowMsec;
+ this.maxVersion = maxVersion;
+ }
+
+ protected final double minVersion = 1.0;
+ protected final double maxVersion;
+ protected final long timestampWindow;
+
+ /** {@inherit}
+ * @throws URISyntaxException */
+ public void validateMessage(OAuthMessage message, OAuthAccessor accessor)
+ throws OAuthException, IOException, URISyntaxException {
+ checkSingleParameters(message);
+ validateVersion(message);
+ validateTimestampAndNonce(message);
+ validateSignature(message, accessor);
+ }
+
+ /** Throw an exception if any SINGLE_PARAMETERS occur repeatedly. */
+ protected void checkSingleParameters(OAuthMessage message) throws IOException, OAuthException {
+ // Check for repeated oauth_ parameters:
+ boolean repeated = false;
+ Map> nameToValues = new HashMap>();
+ for (Map.Entry parameter : message.getParameters()) {
+ String name = parameter.getKey();
+ if (SINGLE_PARAMETERS.contains(name)) {
+ Collection values = nameToValues.get(name);
+ if (values == null) {
+ values = new ArrayList();
+ nameToValues.put(name, values);
+ } else {
+ repeated = true;
+ }
+ values.add(parameter.getValue());
+ }
+ }
+ if (repeated) {
+ Collection rejected = new ArrayList();
+ for (Map.Entry> p : nameToValues.entrySet()) {
+ String name = p.getKey();
+ Collection values = p.getValue();
+ if (values.size() > 1) {
+ for (String value : values) {
+ rejected.add(new OAuth.Parameter(name, value));
+ }
+ }
+ }
+ OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_REJECTED);
+ problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_REJECTED, OAuth.formEncode(rejected));
+ throw problem;
+ }
+ }
+
+ protected void validateVersion(OAuthMessage message)
+ throws OAuthException, IOException {
+ String versionString = message.getParameter(OAuth.OAUTH_VERSION);
+ if (versionString != null) {
+ double version = Double.parseDouble(versionString);
+ if (version < minVersion || maxVersion < version) {
+ OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.VERSION_REJECTED);
+ problem.setParameter(OAuth.Problems.OAUTH_ACCEPTABLE_VERSIONS, minVersion + "-" + maxVersion);
+ throw problem;
+ }
+ }
+ }
+
+ /** This implementation doesn't check the nonce value. */
+ protected void validateTimestampAndNonce(OAuthMessage message)
+ throws IOException, OAuthProblemException {
+ message.requireParameters(OAuth.OAUTH_TIMESTAMP, OAuth.OAUTH_NONCE);
+ long timestamp = Long.parseLong(message.getParameter(OAuth.OAUTH_TIMESTAMP)) * 1000L;
+ long now = currentTimeMsec();
+ long min = now - timestampWindow;
+ long max = now + timestampWindow;
+ if (timestamp < min || max < timestamp) {
+ OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.TIMESTAMP_REFUSED);
+ problem.setParameter(OAuth.Problems.OAUTH_ACCEPTABLE_TIMESTAMPS, min + "-" + max);
+ throw problem;
+ }
+ }
+
+ protected void validateSignature(OAuthMessage message, OAuthAccessor accessor)
+ throws OAuthException, IOException, URISyntaxException {
+ message.requireParameters(OAuth.OAUTH_CONSUMER_KEY,
+ OAuth.OAUTH_SIGNATURE_METHOD, OAuth.OAUTH_SIGNATURE);
+ OAuthSignatureMethod.newSigner(message, accessor).validate(message);
+ }
+
+ protected long currentTimeMsec() {
+ return System.currentTimeMillis();
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/client/ExcerptInputStream.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/client/ExcerptInputStream.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/client/ExcerptInputStream.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,42 @@
+package net.oauth.client;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/** A decorator that retains a copy of the first few bytes of data. */
+public class ExcerptInputStream extends BufferedInputStream
+{
+ /**
+ * A marker that's appended to the excerpt if it's less than the complete
+ * stream.
+ */
+ public static final byte[] ELLIPSIS = " ...".getBytes();
+
+ public ExcerptInputStream(InputStream in) throws IOException {
+ super(in);
+ mark(LIMIT);
+ int total = 0;
+ int read;
+ while ((read = read(excerpt, total, LIMIT - total)) != -1 && ((total += read) < LIMIT));
+ if (total == LIMIT) {
+ // Only add the ellipsis if there are at least LIMIT bytes
+ System.arraycopy(ELLIPSIS, 0, excerpt, total, ELLIPSIS.length);
+ } else {
+ byte[] tmp = new byte[total];
+ System.arraycopy(excerpt, 0, tmp, 0, total);
+ excerpt = tmp;
+ }
+ reset();
+ }
+
+ private static final int LIMIT = 1024;
+ private byte[] excerpt = new byte[LIMIT + ELLIPSIS.length];
+
+ /** The first few bytes of data, plus ELLIPSIS if there are more bytes. */
+ public byte[] getExcerpt()
+ {
+ return excerpt;
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/client/OAuthClient.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/client/OAuthClient.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/client/OAuthClient.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2007, 2008 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth.client;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
+import net.oauth.OAuthException;
+import net.oauth.OAuthMessage;
+import net.oauth.OAuthProblemException;
+import net.oauth.http.HttpClient;
+import net.oauth.http.HttpMessage;
+import net.oauth.http.HttpMessageDecoder;
+import net.oauth.http.HttpResponseMessage;
+
+/**
+ * Methods for an OAuth consumer to request tokens from a service provider.
+ *
+ * This class can also be used to request access to protected resources, in some
+ * cases. But not in all cases. For example, this class can't handle arbitrary
+ * HTTP headers.
+ *
+ * Methods of this class return a response as an OAuthMessage, from which you
+ * can get a body or parameters but not both. Calling a getParameter method will
+ * read and close the body (like readBodyAsString), so you can't read it later.
+ * If you read or close the body first, then getParameter can't read it. The
+ * response headers should tell you whether the response contains encoded
+ * parameters, that is whether you should call getParameter or not.
+ *
+ * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose
+ * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein.
+ *
+ *
+ * @see RFC 2045
+ * @author Apache Software Foundation
+ * @author John Kristian
+ */
+class Base64 {
+ /**
+ * Chunk size per RFC 2045 section 6.8.
+ *
+ *
+ * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
+ * equal signs.
+ *
+ *
+ * @see RFC 2045 section 6.8
+ */
+ static final int CHUNK_SIZE = 76;
+
+ /**
+ * Chunk separator per RFC 2045 section 2.1.
+ *
+ * @see RFC 2045 section 2.1
+ */
+ static final byte[] CHUNK_SEPARATOR = {'\r','\n'};
+
+ /**
+ * This array is a lookup table that translates 6-bit positive integer
+ * index values into their "Base64 Alphabet" equivalents as specified
+ * in Table 1 of RFC 2045.
+ *
+ * Thanks to "commons" project in ws.apache.org for this code.
+ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+ */
+ private static final byte[] intToBase64 = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+
+ /**
+ * Byte used to pad output.
+ */
+ private static final byte PAD = '=';
+
+ /**
+ * This array is a lookup table that translates unicode characters
+ * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
+ * into their 6-bit positive integer equivalents. Characters that
+ * are not in the Base64 alphabet but fall within the bounds of the
+ * array are translated to -1.
+ *
+ * Thanks to "commons" project in ws.apache.org for this code.
+ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+ */
+ private static final byte[] base64ToInt = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+ };
+
+ /** Mask used to extract 6 bits, used when encoding */
+ private static final int MASK_6BITS = 0x3f;
+
+ /** Mask used to extract 8 bits, used in decoding base64 bytes */
+ private static final int MASK_8BITS = 0xff;
+
+ // The static final fields above are used for the original static byte[] methods on Base64.
+ // The private member fields below are used with the new streaming approach, which requires
+ // some state be preserved between calls of encode() and decode().
+
+
+ /**
+ * Line length for encoding. Not used when decoding. A value of zero or less implies
+ * no chunking of the base64 encoded data.
+ */
+ private final int lineLength;
+
+ /**
+ * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
+ */
+ private final byte[] lineSeparator;
+
+ /**
+ * Convenience variable to help us determine when our buffer is going to run out of
+ * room and needs resizing. decodeSize = 3 + lineSeparator.length;
+ */
+ private final int decodeSize;
+
+ /**
+ * Convenience variable to help us determine when our buffer is going to run out of
+ * room and needs resizing. encodeSize = 4 + lineSeparator.length;
+ */
+ private final int encodeSize;
+
+ /**
+ * Buffer for streaming.
+ */
+ private byte[] buf;
+
+ /**
+ * Position where next character should be written in the buffer.
+ */
+ private int pos;
+
+ /**
+ * Position where next character should be read from the buffer.
+ */
+ private int readPos;
+
+ /**
+ * Variable tracks how many characters have been written to the current line.
+ * Only used when encoding. We use it to make sure each encoded line never
+ * goes beyond lineLength (if lineLength > 0).
+ */
+ private int currentLinePos;
+
+ /**
+ * Writes to the buffer only occur after every 3 reads when encoding, an
+ * every 4 reads when decoding. This variable helps track that.
+ */
+ private int modulus;
+
+ /**
+ * Boolean flag to indicate the EOF has been reached. Once EOF has been
+ * reached, this Base64 object becomes useless, and must be thrown away.
+ */
+ private boolean eof;
+
+ /**
+ * Place holder for the 3 bytes we're dealing with for our base64 logic.
+ * Bitwise operations store and extract the base64 encoding or decoding from
+ * this variable.
+ */
+ private int x;
+
+ /**
+ * Default constructor: lineLength is 76, and the lineSeparator is CRLF
+ * when encoding, and all forms can be decoded.
+ */
+ public Base64() {
+ this(CHUNK_SIZE, CHUNK_SEPARATOR);
+ }
+
+ /**
+ *
+ * Consumer can use this constructor to choose a different lineLength
+ * when encoding (lineSeparator is still CRLF). All forms of data can
+ * be decoded.
+ *
+ * Note: lineLengths that aren't multiples of 4 will still essentially
+ * end up being multiples of 4 in the encoded data.
+ *
+ *
+ * @param lineLength each line of encoded data will be at most this long
+ * (rounded up to nearest multiple of 4).
+ * If lineLength <= 0, then the output will not be divided into lines (chunks).
+ * Ignored when decoding.
+ */
+ public Base64(int lineLength) {
+ this(lineLength, CHUNK_SEPARATOR);
+ }
+
+ /**
+ *
+ * Consumer can use this constructor to choose a different lineLength
+ * and lineSeparator when encoding. All forms of data can
+ * be decoded.
+ *
+ * Note: lineLengths that aren't multiples of 4 will still essentially
+ * end up being multiples of 4 in the encoded data.
+ *
+ * @param lineLength Each line of encoded data will be at most this long
+ * (rounded up to nearest multiple of 4). Ignored when decoding.
+ * If <= 0, then output will not be divided into lines (chunks).
+ * @param lineSeparator Each line of encoded data will end with this
+ * sequence of bytes.
+ * If lineLength <= 0, then the lineSeparator is not used.
+ * @throws IllegalArgumentException The provided lineSeparator included
+ * some base64 characters. That's not going to work!
+ */
+ public Base64(int lineLength, byte[] lineSeparator) {
+ this.lineLength = lineLength;
+ this.lineSeparator = new byte[lineSeparator.length];
+ System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
+ if (lineLength > 0) {
+ this.encodeSize = 4 + lineSeparator.length;
+ } else {
+ this.encodeSize = 4;
+ }
+ this.decodeSize = encodeSize - 1;
+ if (containsBase64Byte(lineSeparator)) {
+ String sep;
+ try {
+ sep = new String(lineSeparator, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ sep = new String(lineSeparator);
+ }
+ throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]");
+ }
+ }
+
+ /**
+ * Returns true if this Base64 object has buffered data for reading.
+ *
+ * @return true if there is Base64 object still available for reading.
+ */
+ boolean hasData() { return buf != null; }
+
+ /**
+ * Returns the amount of buffered data available for reading.
+ *
+ * @return The amount of buffered data available for reading.
+ */
+ int avail() { return buf != null ? pos - readPos : 0; }
+
+ /** Doubles our buffer. */
+ private void resizeBuf() {
+ if (buf == null) {
+ buf = new byte[8192];
+ pos = 0;
+ readPos = 0;
+ } else {
+ byte[] b = new byte[buf.length * 2];
+ System.arraycopy(buf, 0, b, 0, buf.length);
+ buf = b;
+ }
+ }
+
+ /**
+ * Extracts buffered data into the provided byte[] array, starting
+ * at position bPos, up to a maximum of bAvail bytes. Returns how
+ * many bytes were actually extracted.
+ *
+ * @param b byte[] array to extract the buffered data into.
+ * @param bPos position in byte[] array to start extraction at.
+ * @param bAvail amount of bytes we're allowed to extract. We may extract
+ * fewer (if fewer are available).
+ * @return The number of bytes successfully extracted into the provided
+ * byte[] array.
+ */
+ int readResults(byte[] b, int bPos, int bAvail) {
+ if (buf != null) {
+ int len = Math.min(avail(), bAvail);
+ if (buf != b) {
+ System.arraycopy(buf, readPos, b, bPos, len);
+ readPos += len;
+ if (readPos >= pos) {
+ buf = null;
+ }
+ } else {
+ // Re-using the original consumer's output array is only
+ // allowed for one round.
+ buf = null;
+ }
+ return len;
+ } else {
+ return eof ? -1 : 0;
+ }
+ }
+
+ /**
+ * Small optimization where we try to buffer directly to the consumer's
+ * output array for one round (if consumer calls this method first!) instead
+ * of starting our own buffer.
+ *
+ * @param out byte[] array to buffer directly to.
+ * @param outPos Position to start buffering into.
+ * @param outAvail Amount of bytes available for direct buffering.
+ */
+ void setInitialBuffer(byte[] out, int outPos, int outAvail) {
+ // We can re-use consumer's original output array under
+ // special circumstances, saving on some System.arraycopy().
+ if (out != null && out.length == outAvail) {
+ buf = out;
+ pos = outPos;
+ readPos = outPos;
+ }
+ }
+
+ /**
+ *
+ * Encodes all of the provided data, starting at inPos, for inAvail bytes.
+ * Must be called at least twice: once with the data to encode, and once
+ * with inAvail set to "-1" to alert encoder that EOF has been reached,
+ * so flush last remaining bytes (if not multiple of 3).
+ *
+ * Thanks to "commons" project in ws.apache.org for the bitwise operations,
+ * and general approach.
+ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+ *
+ *
+ * @param in byte[] array of binary data to base64 encode.
+ * @param inPos Position to start reading data from.
+ * @param inAvail Amount of bytes available from input for encoding.
+ */
+ void encode(byte[] in, int inPos, int inAvail) {
+ if (eof) {
+ return;
+ }
+
+ // inAvail < 0 is how we're informed of EOF in the underlying data we're
+ // encoding.
+ if (inAvail < 0) {
+ eof = true;
+ if (buf == null || buf.length - pos < encodeSize) {
+ resizeBuf();
+ }
+ switch (modulus) {
+ case 1:
+ buf[pos++] = intToBase64[(x >> 2) & MASK_6BITS];
+ buf[pos++] = intToBase64[(x << 4) & MASK_6BITS];
+ buf[pos++] = PAD;
+ buf[pos++] = PAD;
+ break;
+
+ case 2:
+ buf[pos++] = intToBase64[(x >> 10) & MASK_6BITS];
+ buf[pos++] = intToBase64[(x >> 4) & MASK_6BITS];
+ buf[pos++] = intToBase64[(x << 2) & MASK_6BITS];
+ buf[pos++] = PAD;
+ break;
+ }
+ if (lineLength > 0) {
+ System.arraycopy(lineSeparator, 0, buf, pos, lineSeparator.length);
+ pos += lineSeparator.length;
+ }
+ } else {
+ for (int i = 0; i < inAvail; i++) {
+ if (buf == null || buf.length - pos < encodeSize) {
+ resizeBuf();
+ }
+ modulus = (++modulus) % 3;
+ int b = in[inPos++];
+ if (b < 0) { b += 256; }
+ x = (x << 8) + b;
+ if (0 == modulus) {
+ buf[pos++] = intToBase64[(x >> 18) & MASK_6BITS];
+ buf[pos++] = intToBase64[(x >> 12) & MASK_6BITS];
+ buf[pos++] = intToBase64[(x >> 6) & MASK_6BITS];
+ buf[pos++] = intToBase64[x & MASK_6BITS];
+ currentLinePos += 4;
+ if (lineLength > 0 && lineLength <= currentLinePos) {
+ System.arraycopy(lineSeparator, 0, buf, pos, lineSeparator.length);
+ pos += lineSeparator.length;
+ currentLinePos = 0;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * Decodes all of the provided data, starting at inPos, for inAvail bytes.
+ * Should be called at least twice: once with the data to decode, and once
+ * with inAvail set to "-1" to alert decoder that EOF has been reached.
+ * The "-1" call is not necessary when decoding, but it doesn't hurt, either.
+ *
+ * Ignores all non-base64 characters. This is how chunked (e.g. 76 character)
+ * data is handled, since CR and LF are silently ignored, but has implications
+ * for other bytes, too. This method subscribes to the garbage-in, garbage-out
+ * philosophy: it will not check the provided data for validity.
+ *
+ * Thanks to "commons" project in ws.apache.org for the bitwise operations,
+ * and general approach.
+ * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
+ *
+
+ * @param in byte[] array of ascii data to base64 decode.
+ * @param inPos Position to start reading data from.
+ * @param inAvail Amount of bytes available from input for encoding.
+ */
+ void decode(byte[] in, int inPos, int inAvail) {
+ if (eof) {
+ return;
+ }
+ if (inAvail < 0) {
+ eof = true;
+ }
+ for (int i = 0; i < inAvail; i++) {
+ if (buf == null || buf.length - pos < decodeSize) {
+ resizeBuf();
+ }
+ byte b = in[inPos++];
+ if (b == PAD) {
+ x = x << 6;
+ switch (modulus) {
+ case 2:
+ x = x << 6;
+ buf[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ break;
+ case 3:
+ buf[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ buf[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ break;
+ }
+ // WE'RE DONE!!!!
+ eof = true;
+ return;
+ } else {
+ if (b >= 0 && b < base64ToInt.length) {
+ int result = base64ToInt[b];
+ if (result >= 0) {
+ modulus = (++modulus) % 4;
+ x = (x << 6) + result;
+ if (modulus == 0) {
+ buf[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ buf[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ buf[pos++] = (byte) (x & MASK_8BITS);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether or not the octet is in the base 64 alphabet.
+ *
+ * @param octet
+ * The value to test
+ * @return true if the value is defined in the the base 64 alphabet, false otherwise.
+ */
+ public static boolean isBase64(byte octet) {
+ return octet == PAD || (octet >= 0 && octet < base64ToInt.length && base64ToInt[octet] != -1);
+ }
+
+ /**
+ * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet.
+ * Currently the method treats whitespace as valid.
+ *
+ * @param arrayOctet
+ * byte array to test
+ * @return true if all bytes are valid characters in the Base64 alphabet or if the byte array is
+ * empty; false, otherwise
+ */
+ public static boolean isArrayByteBase64(byte[] arrayOctet) {
+ for (int i = 0; i < arrayOctet.length; i++) {
+ if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet.
+ *
+ * @param arrayOctet
+ * byte array to test
+ * @return true if any byte is a valid character in the Base64 alphabet; false herwise
+ */
+ private static boolean containsBase64Byte(byte[] arrayOctet) {
+ for (int i = 0; i < arrayOctet.length; i++) {
+ if (isBase64(arrayOctet[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm but does not chunk the output.
+ *
+ * @param binaryData
+ * binary data to encode
+ * @return Base64 characters
+ */
+ public static byte[] encodeBase64(byte[] binaryData) {
+ return encodeBase64(binaryData, false);
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
+ *
+ * @param binaryData
+ * binary data to encode
+ * @return Base64 characters chunked in 76 character blocks
+ */
+ public static byte[] encodeBase64Chunked(byte[] binaryData) {
+ return encodeBase64(binaryData, true);
+ }
+
+ /**
+ * Decodes a byte[] containing containing characters in the Base64 alphabet.
+ *
+ * @param pArray
+ * A byte array containing Base64 character data
+ * @return a byte array containing binary data
+ */
+ public byte[] decode(byte[] pArray) {
+ return decodeBase64(pArray);
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
+ *
+ * @param binaryData
+ * Array containing binary data to encode.
+ * @param isChunked
+ * if true this encoder will chunk the base64 output into 76 character blocks
+ * @return Base64-encoded data.
+ * @throws IllegalArgumentException
+ * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
+ */
+ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
+ if (binaryData == null || binaryData.length == 0) {
+ return binaryData;
+ }
+ Base64 b64 = isChunked ? new Base64() : new Base64(0);
+
+ long len = (binaryData.length * 4) / 3;
+ long mod = len % 4;
+ if (mod != 0) {
+ len += 4 - mod;
+ }
+ if (isChunked) {
+ len += (1 + (len / CHUNK_SIZE)) * CHUNK_SEPARATOR.length;
+ }
+
+ if (len > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "Input array too big, output array would be bigger than Integer.MAX_VALUE=" + Integer.MAX_VALUE);
+ }
+ byte[] buf = new byte[(int) len];
+ b64.setInitialBuffer(buf, 0, buf.length);
+ b64.encode(binaryData, 0, binaryData.length);
+ b64.encode(binaryData, 0, -1); // Notify encoder of EOF.
+
+ // Encoder might have resized, even though it was unnecessary.
+ if (b64.buf != buf) {
+ b64.readResults(buf, 0, buf.length);
+ }
+ return buf;
+ }
+
+ /**
+ * Decodes Base64 data into octets
+ *
+ * @param base64Data Byte array containing Base64 data
+ * @return Array containing decoded data.
+ */
+ public static byte[] decodeBase64(byte[] base64Data) {
+ if (base64Data == null || base64Data.length == 0) {
+ return base64Data;
+ }
+ Base64 b64 = new Base64();
+
+ long len = (base64Data.length * 3) / 4;
+ byte[] buf = new byte[(int) len];
+ b64.setInitialBuffer(buf, 0, buf.length);
+ b64.decode(base64Data, 0, base64Data.length);
+ b64.decode(base64Data, 0, -1); // Notify decoder of EOF.
+
+ // We have no idea what the line-length was, so we
+ // cannot know how much of our array wasn't used.
+ byte[] result = new byte[b64.pos];
+ b64.readResults(result, 0, result.length);
+ return result;
+ }
+
+ /**
+ * Check if a byte value is whitespace or not.
+ *
+ * @param byteToCheck the byte to check
+ * @return true if byte is whitespace, false otherwise
+ */
+ private static boolean isWhiteSpace(byte byteToCheck){
+ switch (byteToCheck) {
+ case ' ' :
+ case '\n' :
+ case '\r' :
+ case '\t' :
+ return true;
+ default :
+ return false;
+ }
+ }
+
+ /**
+ * Discards any characters outside of the base64 alphabet, per the requirements on page 25 of RFC 2045 - "Any
+ * characters outside of the base64 alphabet are to be ignored in base64 encoded data."
+ *
+ * @param data
+ * The base-64 encoded data to groom
+ * @return The data, less non-base64 characters (see RFC 2045).
+ */
+ static byte[] discardNonBase64(byte[] data) {
+ byte groomedData[] = new byte[data.length];
+ int bytesCopied = 0;
+
+ for (int i = 0; i < data.length; i++) {
+ if (isBase64(data[i])) {
+ groomedData[bytesCopied++] = data[i];
+ }
+ }
+
+ byte packedData[] = new byte[bytesCopied];
+
+ System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+ return packedData;
+ }
+
+ // Implementation of the Encoder Interface
+
+ /**
+ * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet.
+ *
+ * @param pArray
+ * a byte array containing binary data
+ * @return A byte array containing only Base64 character data
+ */
+ public byte[] encode(byte[] pArray) {
+ return encodeBase64(pArray, false);
+ }
+
+ // Implementation of integer encoding used for crypto
+ /**
+ * Decode a byte64-encoded integer according to crypto
+ * standards such as W3C's XML-Signature
+ *
+ * @param pArray a byte array containing base64 character data
+ * @return A BigInteger
+ */
+ public static BigInteger decodeInteger(byte[] pArray) {
+ return new BigInteger(1, decodeBase64(pArray));
+ }
+
+ /**
+ * Encode to a byte64-encoded integer according to crypto
+ * standards such as W3C's XML-Signature
+ *
+ * @param bigInt a BigInteger
+ * @return A byte array containing base64 character data
+ * @throws NullPointerException if null is passed in
+ */
+ public static byte[] encodeInteger(BigInteger bigInt) {
+ if(bigInt == null) {
+ throw new NullPointerException("encodeInteger called with null parameter");
+ }
+
+ return encodeBase64(toIntegerBytes(bigInt), false);
+ }
+
+ /**
+ * Returns a byte-array representation of a BigInteger
+ * without sign bit.
+ *
+ * @param bigInt BigInteger to be converted
+ * @return a byte array representation of the BigInteger parameter
+ */
+ static byte[] toIntegerBytes(BigInteger bigInt) {
+ int bitlen = bigInt.bitLength();
+ // round bitlen
+ bitlen = ((bitlen + 7) >> 3) << 3;
+ byte[] bigBytes = bigInt.toByteArray();
+
+ if(((bigInt.bitLength() % 8) != 0) &&
+ (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
+ return bigBytes;
+ }
+
+ // set up params for copying everything but sign bit
+ int startSrc = 0;
+ int len = bigBytes.length;
+
+ // if bigInt is exactly byte-aligned, just skip signbit in copy
+ if((bigInt.bitLength() % 8) == 0) {
+ startSrc = 1;
+ len--;
+ }
+
+ int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
+ byte[] resizedBytes = new byte[bitlen / 8];
+
+ System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
+
+ return resizedBytes;
+ }
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/HMAC_SHA1.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/HMAC_SHA1.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/HMAC_SHA1.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth.signature;
+
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthException;
+
+/**
+ * @author John Kristian
+ */
+class HMAC_SHA1 extends OAuthSignatureMethod {
+
+ @Override
+ protected String getSignature(String baseString) throws OAuthException {
+ try {
+ String signature = base64Encode(computeSignature(baseString));
+ return signature;
+ } catch (GeneralSecurityException e) {
+ throw new OAuthException(e);
+ } catch (UnsupportedEncodingException e) {
+ throw new OAuthException(e);
+ }
+ }
+
+ @Override
+ protected boolean isValid(String signature, String baseString)
+ throws OAuthException {
+ try {
+ byte[] expected = computeSignature(baseString);
+ byte[] actual = decodeBase64(signature);
+ return Arrays.equals(expected, actual);
+ } catch (GeneralSecurityException e) {
+ throw new OAuthException(e);
+ } catch (UnsupportedEncodingException e) {
+ throw new OAuthException(e);
+ }
+ }
+
+ private byte[] computeSignature(String baseString)
+ throws GeneralSecurityException, UnsupportedEncodingException {
+ SecretKey key = null;
+ synchronized (this) {
+ if (this.key == null) {
+ String keyString = OAuth.percentEncode(getConsumerSecret())
+ + '&' + OAuth.percentEncode(getTokenSecret());
+ byte[] keyBytes = keyString.getBytes(ENCODING);
+ this.key = new SecretKeySpec(keyBytes, MAC_NAME);
+ }
+ key = this.key;
+ }
+ Mac mac = Mac.getInstance(MAC_NAME);
+ mac.init(key);
+ byte[] text = baseString.getBytes(ENCODING);
+ return mac.doFinal(text);
+ }
+
+ /** ISO-8859-1 or US-ASCII would work, too. */
+ private static final String ENCODING = OAuth.ENCODING;
+
+ private static final String MAC_NAME = "HmacSHA1";
+
+ private SecretKey key = null;
+
+ @Override
+ public void setConsumerSecret(String consumerSecret) {
+ synchronized (this) {
+ key = null;
+ }
+ super.setConsumerSecret(consumerSecret);
+ }
+
+ @Override
+ public void setTokenSecret(String tokenSecret) {
+ synchronized (this) {
+ key = null;
+ }
+ super.setTokenSecret(tokenSecret);
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/OAuthSignatureMethod.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/OAuthSignatureMethod.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/OAuthSignatureMethod.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth.signature;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
+import net.oauth.OAuthException;
+import net.oauth.OAuthMessage;
+import net.oauth.OAuthProblemException;
+
+/**
+ * A pair of algorithms for computing and verifying an OAuth digital signature.
+ *
+ * @author John Kristian
+ */
+public abstract class OAuthSignatureMethod {
+
+ /** Add a signature to the message.
+ * @throws URISyntaxException
+ * @throws IOException */
+ public void sign(OAuthMessage message)
+ throws OAuthException, IOException, URISyntaxException {
+ message.addParameter(new OAuth.Parameter("oauth_signature",
+ getSignature(message)));
+ }
+
+ /**
+ * Check whether the message has a valid signature.
+ * @throws URISyntaxException
+ *
+ * @throws OAuthProblemException
+ * the signature is invalid
+ */
+ public void validate(OAuthMessage message)
+ throws IOException, OAuthException, URISyntaxException {
+ message.requireParameters("oauth_signature");
+ String signature = message.getSignature();
+ String baseString = getBaseString(message);
+ if (!isValid(signature, baseString)) {
+ OAuthProblemException problem = new OAuthProblemException(
+ "signature_invalid");
+ problem.setParameter("oauth_signature", signature);
+ problem.setParameter("oauth_signature_base_string", baseString);
+ problem.setParameter("oauth_signature_method", message
+ .getSignatureMethod());
+ throw problem;
+ }
+ }
+
+ protected String getSignature(OAuthMessage message)
+ throws OAuthException, IOException, URISyntaxException {
+ String baseString = getBaseString(message);
+ String signature = getSignature(baseString);
+ // Logger log = Logger.getLogger(getClass().getName());
+ // if (log.isLoggable(Level.FINE)) {
+ // log.fine(signature + "=getSignature(" + baseString + ")");
+ // }
+ return signature;
+ }
+
+ protected void initialize(String name, OAuthAccessor accessor)
+ throws OAuthException {
+ String secret = accessor.consumer.consumerSecret;
+ if (name.endsWith(_ACCESSOR)) {
+ // This code supports the 'Accessor Secret' extensions
+ // described in http://oauth.pbwiki.com/AccessorSecret
+ final String key = OAuthConsumer.ACCESSOR_SECRET;
+ Object accessorSecret = accessor.getProperty(key);
+ if (accessorSecret == null) {
+ accessorSecret = accessor.consumer.getProperty(key);
+ }
+ if (accessorSecret != null) {
+ secret = accessorSecret.toString();
+ }
+ }
+ if (secret == null) {
+ secret = "";
+ }
+ setConsumerSecret(secret);
+ }
+
+ public static final String _ACCESSOR = "-Accessor";
+
+ /** Compute the signature for the given base string. */
+ protected abstract String getSignature(String baseString) throws OAuthException;
+
+ /** Decide whether the signature is valid. */
+ protected abstract boolean isValid(String signature, String baseString)
+ throws OAuthException;
+
+ private String consumerSecret;
+
+ private String tokenSecret;
+
+ protected String getConsumerSecret() {
+ return consumerSecret;
+ }
+
+ protected void setConsumerSecret(String consumerSecret) {
+ this.consumerSecret = consumerSecret;
+ }
+
+ public String getTokenSecret() {
+ return tokenSecret;
+ }
+
+ public void setTokenSecret(String tokenSecret) {
+ this.tokenSecret = tokenSecret;
+ }
+
+ public static String getBaseString(OAuthMessage message)
+ throws IOException, URISyntaxException {
+ List> parameters;
+ String url = message.URL;
+ int q = url.indexOf('?');
+ if (q < 0) {
+ parameters = message.getParameters();
+ } else {
+ // Combine the URL query string with the other parameters:
+ parameters = new ArrayList>();
+ parameters.addAll(OAuth.decodeForm(message.URL.substring(q + 1)));
+ parameters.addAll(message.getParameters());
+ url = url.substring(0, q);
+ }
+ return OAuth.percentEncode(message.method.toUpperCase()) + '&'
+ + OAuth.percentEncode(normalizeUrl(url)) + '&'
+ + OAuth.percentEncode(normalizeParameters(parameters));
+ }
+
+ protected static String normalizeUrl(String url) throws URISyntaxException {
+ URI uri = new URI(url);
+ String scheme = uri.getScheme().toLowerCase();
+ String authority = uri.getAuthority().toLowerCase();
+ boolean dropPort = (scheme.equals("http") && uri.getPort() == 80)
+ || (scheme.equals("https") && uri.getPort() == 443);
+ if (dropPort) {
+ // find the last : in the authority
+ int index = authority.lastIndexOf(":");
+ if (index >= 0) {
+ authority = authority.substring(0, index);
+ }
+ }
+ String path = uri.getRawPath();
+ if (path == null || path.length() <= 0) {
+ path = "/"; // conforms to RFC 2616 section 3.2.2
+ }
+ // we know that there is no query and no fragment here.
+ return scheme + "://" + authority + path;
+ }
+
+ protected static String normalizeParameters(
+ Collection extends Map.Entry> parameters) throws IOException {
+ if (parameters == null) {
+ return "";
+ }
+ List p = new ArrayList(
+ parameters.size());
+ for (Map.Entry parameter : parameters) {
+ if (!"oauth_signature".equals(parameter.getKey())) {
+ p.add(new ComparableParameter(parameter));
+ }
+ }
+ Collections.sort(p);
+ return OAuth.formEncode(getParameters(p));
+ }
+
+ public static byte[] decodeBase64(String s) {
+ return BASE64.decode(s.getBytes());
+ }
+
+ public static String base64Encode(byte[] b) {
+ return new String(BASE64.encode(b));
+ }
+
+ private static final Base64 BASE64 = new Base64();
+
+ public static OAuthSignatureMethod newSigner(OAuthMessage message,
+ OAuthAccessor accessor) throws IOException, OAuthException {
+ message.requireParameters(OAuth.OAUTH_SIGNATURE_METHOD);
+ OAuthSignatureMethod signer = newMethod(message.getSignatureMethod(),
+ accessor);
+ signer.setTokenSecret(accessor.tokenSecret);
+ return signer;
+ }
+
+ /** The factory for signature methods. */
+ public static OAuthSignatureMethod newMethod(String name,
+ OAuthAccessor accessor) throws OAuthException {
+ try {
+ Class methodClass = NAME_TO_CLASS.get(name);
+ if (methodClass != null) {
+ OAuthSignatureMethod method = (OAuthSignatureMethod) methodClass
+ .newInstance();
+ method.initialize(name, accessor);
+ return method;
+ }
+ OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.SIGNATURE_METHOD_REJECTED);
+ String acceptable = OAuth.percentEncode(NAME_TO_CLASS.keySet());
+ if (acceptable.length() > 0) {
+ problem.setParameter("oauth_acceptable_signature_methods",
+ acceptable.toString());
+ }
+ throw problem;
+ } catch (InstantiationException e) {
+ throw new OAuthException(e);
+ } catch (IllegalAccessException e) {
+ throw new OAuthException(e);
+ }
+ }
+
+ /**
+ * Subsequently, newMethod(name) will attempt to instantiate the given
+ * class, with no constructor parameters.
+ */
+ public static void registerMethodClass(String name, Class clazz) {
+ NAME_TO_CLASS.put(name, clazz);
+ }
+
+ private static final Map NAME_TO_CLASS = new ConcurrentHashMap();
+ static {
+ registerMethodClass("HMAC-SHA1", HMAC_SHA1.class);
+ registerMethodClass("PLAINTEXT", PLAINTEXT.class);
+ registerMethodClass("RSA-SHA1", RSA_SHA1.class);
+ registerMethodClass("HMAC-SHA1" + _ACCESSOR, HMAC_SHA1.class);
+ registerMethodClass("PLAINTEXT" + _ACCESSOR, PLAINTEXT.class);
+ }
+
+ /** An efficiently sortable wrapper around a parameter. */
+ private static class ComparableParameter implements
+ Comparable {
+
+ ComparableParameter(Map.Entry value) {
+ this.value = value;
+ String n = toString(value.getKey());
+ String v = toString(value.getValue());
+ this.key = OAuth.percentEncode(n) + ' ' + OAuth.percentEncode(v);
+ // ' ' is used because it comes before any character
+ // that can appear in a percentEncoded string.
+ }
+
+ final Map.Entry value;
+
+ private final String key;
+
+ private static String toString(Object from) {
+ return (from == null) ? null : from.toString();
+ }
+
+ public int compareTo(ComparableParameter that) {
+ return this.key.compareTo(that.key);
+ }
+
+ @Override
+ public String toString() {
+ return key;
+ }
+
+ }
+
+ /** Retrieve the original parameters from a sorted collection. */
+ private static List getParameters(
+ Collection parameters) {
+ if (parameters == null) {
+ return null;
+ }
+ List list = new ArrayList(parameters.size());
+ for (ComparableParameter parameter : parameters) {
+ list.add(parameter.value);
+ }
+ return list;
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/PLAINTEXT.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/PLAINTEXT.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/PLAINTEXT.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2007 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth.signature;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthException;
+
+/**
+ * @author John Kristian
+ */
+class PLAINTEXT extends OAuthSignatureMethod {
+
+ @Override
+ public String getSignature(String baseString) {
+ return getSignature();
+ }
+
+ @Override
+ protected boolean isValid(String signature, String baseString)
+ throws OAuthException {
+ return signature.equals(getSignature());
+ }
+
+ private synchronized String getSignature() {
+ if (signature == null) {
+ signature = OAuth.percentEncode(getConsumerSecret()) + '&'
+ + OAuth.percentEncode(getTokenSecret());
+ }
+ return signature;
+ }
+
+ private String signature = null;
+
+ @Override
+ public void setConsumerSecret(String consumerSecret) {
+ synchronized (this) {
+ signature = null;
+ }
+ super.setConsumerSecret(consumerSecret);
+ }
+
+ @Override
+ public void setTokenSecret(String tokenSecret) {
+ synchronized (this) {
+ signature = null;
+ }
+ super.setTokenSecret(tokenSecret);
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/RSA_SHA1.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/RSA_SHA1.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/RSA_SHA1.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2007 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth.signature;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import net.oauth.OAuth;
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthException;
+import net.oauth.signature.pem.PEMReader;
+import net.oauth.signature.pem.PKCS1EncodedKeySpec;
+
+/**
+ * Class to handle RSA-SHA1 signatures on OAuth requests. A consumer
+ * that wishes to use public-key signatures on messages does not need
+ * a shared secret with the service provider, but it needs a private
+ * RSA signing key. You create it like this:
+ *
+ * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key,
+ * null, provider);
+ * c.setProperty(RSA_SHA1.PRIVATE_KEY, consumer_privateRSAKey);
+ *
+ * consumer_privateRSAKey must be an RSA signing key and
+ * of type java.security.PrivateKey, String, byte[] or InputStream.
+ * The key must either PKCS#1 or PKCS#8 encoded.
+ *
+ * A service provider that wishes to verify signatures made by such a
+ * consumer does not need a shared secret with the consumer, but it needs
+ * to know the consumer's public key. You create the necessary
+ * OAuthConsumer object (on the service provider's side) like this:
+ *
+ * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key,
+ * null, provider);
+ * c.setProperty(RSA_SHA1.PUBLIC_KEY, consumer_publicRSAKey);
+ *
+ * consumer_publicRSAKey must be the consumer's public RSAkey and
+ * of type java.security.PublicKey, String, or byte[]. In the latter two
+ * cases, the key must be X509-encoded (byte[]) or X509-encoded and
+ * then Base64-encoded (String).
+ *
+ * Alternatively, a service provider that wishes to verify signatures made
+ * by such a consumer can use a X509 certificate containing the consumer's
+ * public key. You create the necessary OAuthConsumer object (on the service
+ * provider's side) like this:
+ *
+ * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key,
+ * null, provider);
+ * c.setProperty(RSA_SHA1.X509_CERTIFICATE, consumer_cert);
+ *
+ * consumer_cert must be a X509 Certificate containing the consumer's public
+ * key and be of type java.security.cert.X509Certificate, String,
+ * or byte[]. In the latter two cases, the certificate must be DER-encoded
+ * (byte[]) or PEM-encoded (String).
+ *
+ * @author Dirk Balfanz
+ *
+ */
+public class RSA_SHA1 extends OAuthSignatureMethod {
+
+ final static public String PRIVATE_KEY = "RSA-SHA1.PrivateKey";
+ final static public String PUBLIC_KEY = "RSA-SHA1.PublicKey";
+ final static public String X509_CERTIFICATE = "RSA-SHA1.X509Certificate";
+
+ private PrivateKey privateKey = null;
+ private PublicKey publicKey = null;
+
+ @Override
+ protected void initialize(String name, OAuthAccessor accessor)
+ throws OAuthException {
+ super.initialize(name, accessor);
+
+ // Due to the support of PEM input stream, the keys must be cached.
+ // The stream may not be markable so it can't be read again.
+ try {
+ Object privateKeyObject = accessor.consumer.getProperty(PRIVATE_KEY);
+ if (privateKeyObject != null) {
+ privateKey = loadPrivateKey(privateKeyObject);
+ }
+
+ Object publicKeyObject = accessor.consumer.getProperty(PUBLIC_KEY);
+ if (publicKeyObject != null) {
+ publicKey = loadPublicKey(publicKeyObject, false);
+ } else { // public key was null. perhaps they gave us a X509 cert.
+ Object certObject = accessor.consumer.getProperty(X509_CERTIFICATE);
+ if (certObject != null) {
+ publicKey = loadPublicKey(certObject, true);
+ }
+ }
+ } catch (GeneralSecurityException e) {
+ throw new OAuthException(e);
+ } catch (IOException e) {
+ throw new OAuthException(e);
+ }
+ }
+
+ private PublicKey getPublicKeyFromDerCert(byte[] certObject)
+ throws GeneralSecurityException {
+ CertificateFactory fac = CertificateFactory.getInstance("X509");
+ ByteArrayInputStream in = new ByteArrayInputStream(certObject);
+ X509Certificate cert = (X509Certificate)fac.generateCertificate(in);
+ return cert.getPublicKey();
+ }
+
+ private PublicKey getPublicKeyFromDer(byte[] publicKeyObject)
+ throws GeneralSecurityException {
+ KeyFactory fac = KeyFactory.getInstance("RSA");
+ EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKeyObject);
+ return fac.generatePublic(pubKeySpec);
+ }
+
+ private PublicKey getPublicKeyFromPem(String pem)
+ throws GeneralSecurityException, IOException {
+
+ InputStream stream = new ByteArrayInputStream(
+ pem.getBytes("UTF-8"));
+
+ PEMReader reader = new PEMReader(stream);
+ byte[] bytes = reader.getDerBytes();
+ PublicKey pubKey;
+
+ if (PEMReader.PUBLIC_X509_MARKER.equals(reader.getBeginMarker())) {
+ KeySpec keySpec = new X509EncodedKeySpec(bytes);
+ KeyFactory fac = KeyFactory.getInstance("RSA");
+ pubKey = fac.generatePublic(keySpec);
+ } else if (PEMReader.CERTIFICATE_X509_MARKER.equals(reader.getBeginMarker())) {
+ pubKey = getPublicKeyFromDerCert(bytes);
+ } else {
+ throw new IOException("Invalid PEM fileL: Unknown marker for " +
+ " public key or cert " + reader.getBeginMarker());
+ }
+
+ return pubKey;
+ }
+
+ private PrivateKey getPrivateKeyFromDer(byte[] privateKeyObject)
+ throws GeneralSecurityException {
+ KeyFactory fac = KeyFactory.getInstance("RSA");
+ EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privateKeyObject);
+ return fac.generatePrivate(privKeySpec);
+ }
+
+ private PrivateKey getPrivateKeyFromPem(String pem)
+ throws GeneralSecurityException, IOException {
+
+ InputStream stream = new ByteArrayInputStream(
+ pem.getBytes("UTF-8"));
+
+ PEMReader reader = new PEMReader(stream);
+ byte[] bytes = reader.getDerBytes();
+ KeySpec keySpec;
+
+ if (PEMReader.PRIVATE_PKCS1_MARKER.equals(reader.getBeginMarker())) {
+ keySpec = (new PKCS1EncodedKeySpec(bytes)).getKeySpec();
+ } else if (PEMReader.PRIVATE_PKCS8_MARKER.equals(reader.getBeginMarker())) {
+ keySpec = new PKCS8EncodedKeySpec(bytes);
+ } else {
+ throw new IOException("Invalid PEM file: Unknown marker " +
+ "for private key " + reader.getBeginMarker());
+ }
+
+ KeyFactory fac = KeyFactory.getInstance("RSA");
+ return fac.generatePrivate(keySpec);
+ }
+
+ @Override
+ protected String getSignature(String baseString) throws OAuthException {
+ try {
+ byte[] signature = sign(baseString.getBytes(OAuth.ENCODING));
+ return base64Encode(signature);
+ } catch (UnsupportedEncodingException e) {
+ throw new OAuthException(e);
+ } catch (GeneralSecurityException e) {
+ throw new OAuthException(e);
+ }
+ }
+
+ @Override
+ protected boolean isValid(String signature, String baseString)
+ throws OAuthException {
+ try {
+ return verify(decodeBase64(signature),
+ baseString.getBytes(OAuth.ENCODING));
+ } catch (UnsupportedEncodingException e) {
+ throw new OAuthException(e);
+ } catch (GeneralSecurityException e) {
+ throw new OAuthException(e);
+ }
+ }
+
+ private byte[] sign(byte[] message) throws GeneralSecurityException {
+ if (privateKey == null) {
+ throw new IllegalStateException("need to set private key with " +
+ "OAuthConsumer.setProperty when " +
+ "generating RSA-SHA1 signatures.");
+ }
+ Signature signer = Signature.getInstance("SHA1withRSA");
+ signer.initSign(privateKey);
+ signer.update(message);
+ return signer.sign();
+ }
+
+ private boolean verify(byte[] signature, byte[] message)
+ throws GeneralSecurityException {
+ if (publicKey == null) {
+ throw new IllegalStateException("need to set public key with " +
+ " OAuthConsumer.setProperty when " +
+ "verifying RSA-SHA1 signatures.");
+ }
+ Signature verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(publicKey);
+ verifier.update(message);
+ return verifier.verify(signature);
+ }
+
+ /**
+ * Load private key from various sources, including
+ *
+ *
A PrivateKey object
+ *
A string buffer for PEM
+ *
A byte array with PKCS#8 encoded key
+ *
+ * @param privateKeyObject
+ * @return The private key
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ private PrivateKey loadPrivateKey(Object privateKeyObject)
+ throws IOException, GeneralSecurityException {
+
+ PrivateKey privateKey;
+
+ if (privateKeyObject instanceof PrivateKey) {
+ privateKey = (PrivateKey)privateKeyObject;
+ } else if (privateKeyObject instanceof String) {
+ try {
+ // PEM Reader's native string constructor is for filename.
+ privateKey = getPrivateKeyFromPem((String)privateKeyObject);
+ } catch (IOException e) {
+ // Check if it's PEM with markers stripped
+ privateKey = getPrivateKeyFromDer(
+ decodeBase64((String)privateKeyObject));
+ }
+ } else if (privateKeyObject instanceof byte[]) {
+ privateKey = getPrivateKeyFromDer((byte[])privateKeyObject);
+ } else {
+ throw new IllegalArgumentException(
+ "Private key set through RSA_SHA1.PRIVATE_KEY must be of " +
+ "type PrivateKey, String or byte[] and not " +
+ privateKeyObject.getClass().getName());
+ }
+
+ return privateKey;
+ }
+
+ /**
+ * Load a public key from key file or certificate. It can load from
+ * different sources depending on the type of the input,
+ *
+ *
A PublicKey object
+ *
A X509Certificate object
+ *
A string buffer for PEM
+ *
A byte array with X509 encoded key or certificate
+ *
+ *
+ * @param publicKeyObject The object for public key or certificate
+ * @param isCert True if this object is provided as Certificate
+ * @return The public key
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ private PublicKey loadPublicKey(Object publicKeyObject, boolean isCert)
+ throws IOException, GeneralSecurityException {
+
+ PublicKey publicKey;
+
+ if (publicKeyObject instanceof PublicKey) {
+ publicKey = (PublicKey)publicKeyObject;
+ } else if (publicKeyObject instanceof X509Certificate) {
+ publicKey = ((X509Certificate) publicKeyObject).getPublicKey();
+ } else if (publicKeyObject instanceof String) {
+ try {
+ publicKey = getPublicKeyFromPem((String)publicKeyObject);
+ } catch (IOException e) {
+ // Check if it's marker-stripped PEM for public key
+ if (isCert)
+ throw e;
+ publicKey = getPublicKeyFromDer(
+ decodeBase64((String)publicKeyObject));
+ }
+ } else if (publicKeyObject instanceof byte[]) {
+ if (isCert)
+ publicKey = getPublicKeyFromDerCert((byte[])publicKeyObject);
+ else
+ publicKey = getPublicKeyFromDer((byte[])publicKeyObject);
+ } else {
+ String source;
+ if (isCert)
+ source = "RSA_SHA1.X509_CERTIFICATE";
+ else
+ source = "RSA_SHA1.PUBLIC_KEY";
+ throw new IllegalArgumentException(
+ "Public key or certificate set through " + source + " must be of " +
+ "type PublicKey, String or byte[], and not " +
+ publicKeyObject.getClass().getName());
+ }
+
+ return publicKey;
+ }
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/pem/Asn1Object.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/pem/Asn1Object.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/pem/Asn1Object.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,150 @@
+/****************************************************************************
+ * Copyright (c) 1998-2009 AOL LLC.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+package net.oauth.signature.pem;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * An ASN.1 TLV. The object is not parsed. It can
+ * only handle integers and strings.
+ *
+ * @author zhang
+ *
+ */
+class Asn1Object {
+
+ protected final int type;
+ protected final int length;
+ protected final byte[] value;
+ protected final int tag;
+
+ /**
+ * Construct a ASN.1 TLV. The TLV could be either a
+ * constructed or primitive entity.
+ *
+ * The first byte in DER encoding is made of following fields,
+ *
Class: Universal, Application, Context or Private
+ *
CF: Constructed flag. If 1, the field is constructed.
+ *
Type: This is actually called tag in ASN.1. It
+ * indicates data type (Integer, String) or a construct
+ * (sequence, choice, set).
+ *
+ *
+ * @param tag Tag or Identifier
+ * @param length Length of the field
+ * @param value Encoded octet string for the field.
+ */
+ public Asn1Object(int tag, int length, byte[] value) {
+ this.tag = tag;
+ this.type = tag & 0x1F;
+ this.length = length;
+ this.value = value;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public byte[] getValue() {
+ return value;
+ }
+
+ public boolean isConstructed() {
+ return (tag & DerParser.CONSTRUCTED) == DerParser.CONSTRUCTED;
+ }
+
+ /**
+ * For constructed field, return a parser for its content.
+ *
+ * @return A parser for the construct.
+ * @throws IOException
+ */
+ public DerParser getParser() throws IOException {
+ if (!isConstructed())
+ throw new IOException("Invalid DER: can't parse primitive entity"); //$NON-NLS-1$
+
+ return new DerParser(value);
+ }
+
+ /**
+ * Get the value as integer
+ *
+ * @return BigInteger
+ * @throws IOException
+ */
+ public BigInteger getInteger() throws IOException {
+ if (type != DerParser.INTEGER)
+ throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$
+
+ return new BigInteger(value);
+ }
+
+ /**
+ * Get value as string. Most strings are treated
+ * as Latin-1.
+ *
+ * @return Java string
+ * @throws IOException
+ */
+ public String getString() throws IOException {
+
+ String encoding;
+
+ switch (type) {
+
+ // Not all are Latin-1 but it's the closest thing
+ case DerParser.NUMERIC_STRING:
+ case DerParser.PRINTABLE_STRING:
+ case DerParser.VIDEOTEX_STRING:
+ case DerParser.IA5_STRING:
+ case DerParser.GRAPHIC_STRING:
+ case DerParser.ISO646_STRING:
+ case DerParser.GENERAL_STRING:
+ encoding = "ISO-8859-1"; //$NON-NLS-1$
+ break;
+
+ case DerParser.BMP_STRING:
+ encoding = "UTF-16BE"; //$NON-NLS-1$
+ break;
+
+ case DerParser.UTF8_STRING:
+ encoding = "UTF-8"; //$NON-NLS-1$
+ break;
+
+ case DerParser.UNIVERSAL_STRING:
+ throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$
+
+ default:
+ throw new IOException("Invalid DER: object is not a string"); //$NON-NLS-1$
+ }
+
+ return new String(value, encoding);
+ }
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/pem/DerParser.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/pem/DerParser.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/pem/DerParser.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,170 @@
+/****************************************************************************
+ * Copyright (c) 1998-2009 AOL LLC.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+package net.oauth.signature.pem;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+/**
+ * A bare-minimum ASN.1 DER decoder, just having enough functions to
+ * decode PKCS#1 private keys. Especially, it doesn't handle explicitly
+ * tagged types with an outer tag.
+ *
+ * This parser can only handle one layer. To parse nested constructs,
+ * get a new parser for each layer using Asn1Object.getParser().
+ *
+ * There are many DER decoders in JRE but using them will tie this
+ * program to a specific JCE/JVM.
+ *
+ * @author zhang
+ *
+ */
+class DerParser {
+
+ // Classes
+ public final static int UNIVERSAL = 0x00;
+ public final static int APPLICATION = 0x40;
+ public final static int CONTEXT = 0x80;
+ public final static int PRIVATE = 0xC0;
+
+ // Constructed Flag
+ public final static int CONSTRUCTED = 0x20;
+
+ // Tag and data types
+ public final static int ANY = 0x00;
+ public final static int BOOLEAN = 0x01;
+ public final static int INTEGER = 0x02;
+ public final static int BIT_STRING = 0x03;
+ public final static int OCTET_STRING = 0x04;
+ public final static int NULL = 0x05;
+ public final static int OBJECT_IDENTIFIER = 0x06;
+ public final static int REAL = 0x09;
+ public final static int ENUMERATED = 0x0a;
+ public final static int RELATIVE_OID = 0x0d;
+
+ public final static int SEQUENCE = 0x10;
+ public final static int SET = 0x11;
+
+ public final static int NUMERIC_STRING = 0x12;
+ public final static int PRINTABLE_STRING = 0x13;
+ public final static int T61_STRING = 0x14;
+ public final static int VIDEOTEX_STRING = 0x15;
+ public final static int IA5_STRING = 0x16;
+ public final static int GRAPHIC_STRING = 0x19;
+ public final static int ISO646_STRING = 0x1A;
+ public final static int GENERAL_STRING = 0x1B;
+
+ public final static int UTF8_STRING = 0x0C;
+ public final static int UNIVERSAL_STRING = 0x1C;
+ public final static int BMP_STRING = 0x1E;
+
+ public final static int UTC_TIME = 0x17;
+ public final static int GENERALIZED_TIME = 0x18;
+
+ protected InputStream in;
+
+ /**
+ * Create a new DER decoder from an input stream.
+ *
+ * @param in
+ * The DER encoded stream
+ */
+ public DerParser(InputStream in) throws IOException {
+ this.in = in;
+ }
+
+ /**
+ * Create a new DER decoder from a byte array.
+ *
+ * @param The
+ * encoded bytes
+ * @throws IOException
+ */
+ public DerParser(byte[] bytes) throws IOException {
+ this(new ByteArrayInputStream(bytes));
+ }
+
+ /**
+ * Read next object. If it's constructed, the value holds
+ * encoded content and it should be parsed by a new
+ * parser from Asn1Object.getParser.
+ *
+ * @return A object
+ * @throws IOException
+ */
+ public Asn1Object read() throws IOException {
+ int tag = in.read();
+
+ if (tag == -1)
+ throw new IOException("Invalid DER: stream too short, missing tag"); //$NON-NLS-1$
+
+ int length = getLength();
+
+ byte[] value = new byte[length];
+ int n = in.read(value);
+ if (n < length)
+ throw new IOException("Invalid DER: stream too short, missing value"); //$NON-NLS-1$
+
+ Asn1Object o = new Asn1Object(tag, length, value);
+
+ return o;
+ }
+
+ /**
+ * Decode the length of the field. Can only support length
+ * encoding up to 4 octets.
+ *
+ * In BER/DER encoding, length can be encoded in 2 forms,
+ *
+ *
Short form. One octet. Bit 8 has value "0" and bits 7-1
+ * give the length.
+ *
Long form. Two to 127 octets (only 4 is supported here).
+ * Bit 8 of first octet has value "1" and bits 7-1 give the
+ * number of additional length octets. Second and following
+ * octets give the length, base 256, most significant digit first.
+ *
+ * @return The length as integer
+ * @throws IOException
+ */
+ private int getLength() throws IOException {
+
+ int i = in.read();
+ if (i == -1)
+ throw new IOException("Invalid DER: length missing"); //$NON-NLS-1$
+
+ // A single byte short length
+ if ((i & ~0x7F) == 0)
+ return i;
+
+ int num = i & 0x7F;
+
+ // We can't handle length longer than 4 bytes
+ if ( i >= 0xFF || num > 4)
+ throw new IOException("Invalid DER: length field too big (" //$NON-NLS-1$
+ + i + ")"); //$NON-NLS-1$
+
+ byte[] bytes = new byte[num];
+ int n = in.read(bytes);
+ if (n < num)
+ throw new IOException("Invalid DER: length too short"); //$NON-NLS-1$
+
+ return new BigInteger(1, bytes).intValue();
+ }
+
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/pem/PEMReader.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/pem/PEMReader.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/pem/PEMReader.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,135 @@
+/****************************************************************************
+ * Copyright (c) 1998-2009 AOL LLC.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************
+ *
+ * @author: zhang
+ * @version: $Revision$
+ * @created: Apr 24, 2009
+ *
+ * Description: A class to decode PEM files
+ *
+ ****************************************************************************/
+package net.oauth.signature.pem;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import net.oauth.signature.OAuthSignatureMethod;
+
+/**
+ * This class convert PEM into byte array. The begin marker
+ * is saved and it can be used to determine the type of the
+ * PEM file.
+ *
+ * @author zhang
+ */
+public class PEMReader {
+
+ // Begin markers for all supported PEM files
+ public static final String PRIVATE_PKCS1_MARKER =
+ "-----BEGIN RSA PRIVATE KEY-----";
+ public static final String PRIVATE_PKCS8_MARKER =
+ "-----BEGIN PRIVATE KEY-----";
+ public static final String CERTIFICATE_X509_MARKER =
+ "-----BEGIN CERTIFICATE-----";
+ public static final String PUBLIC_X509_MARKER =
+ "-----BEGIN PUBLIC KEY-----";
+
+ private static final String BEGIN_MARKER = "-----BEGIN ";
+
+ private InputStream stream;
+ private byte[] derBytes;
+ private String beginMarker;
+
+ public PEMReader(InputStream inStream) throws IOException {
+ stream = inStream;
+ readFile();
+ }
+
+ public PEMReader(byte[] buffer) throws IOException {
+ this(new ByteArrayInputStream(buffer));
+ }
+
+ public PEMReader(String fileName) throws IOException {
+ this(new FileInputStream(fileName));
+ }
+
+ public byte[] getDerBytes() {
+ return derBytes;
+ }
+
+ public String getBeginMarker() {
+ return beginMarker;
+ }
+
+ /**
+ * Read the PEM file and save the DER encoded octet
+ * stream and begin marker.
+ *
+ * @throws IOException
+ */
+ protected void readFile() throws IOException {
+
+ String line;
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(stream));
+ try {
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.indexOf(BEGIN_MARKER) != -1)
+ {
+ beginMarker = line.trim();
+ String endMarker = beginMarker.replace("BEGIN", "END");
+ derBytes = readBytes(reader, endMarker);
+ return;
+ }
+ }
+ throw new IOException("Invalid PEM file: no begin marker");
+ } finally {
+ reader.close();
+ }
+ }
+
+
+ /**
+ * Read the lines between BEGIN and END marker and convert
+ * the Base64 encoded content into binary byte array.
+ *
+ * @return DER encoded octet stream
+ * @throws IOException
+ */
+ private byte[] readBytes(BufferedReader reader, String endMarker) throws IOException
+ {
+ String line = null;
+ StringBuffer buf = new StringBuffer();
+
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.indexOf(endMarker) != -1) {
+
+ return OAuthSignatureMethod.decodeBase64(buf.toString());
+ }
+
+ buf.append(line.trim());
+ }
+
+ throw new IOException("Invalid PEM file: No end marker");
+ }
+}
Index: lams_tool_imscc/src/java/net/oauth/signature/pem/PKCS1EncodedKeySpec.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/net/oauth/signature/pem/PKCS1EncodedKeySpec.java (revision 0)
+++ lams_tool_imscc/src/java/net/oauth/signature/pem/PKCS1EncodedKeySpec.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,116 @@
+/****************************************************************************
+ * Copyright (c) 1998-2009 AOL LLC.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************
+ *
+ * @author: zhang
+ * @version: $Revision$
+ * @created: Apr 24, 2009
+ *
+ * Description: A KeySpec for PKCS#1 encoded RSA private key
+ *
+ ****************************************************************************/
+package net.oauth.signature.pem;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+/**
+ * PKCS#1 encoded private key is commonly used with OpenSSL. It provides CRT parameters
+ * so the private key operation can be much faster than using exponent/modulus alone,
+ * which is the case for PKCS#8 encoded key.
+ *
+ * Unfortunately, JCE doesn't have an API to decode the DER. This class takes DER
+ * buffer and decoded into CRT key.
+ *
+ * @author zhang
+ */
+public class PKCS1EncodedKeySpec {
+
+ private RSAPrivateCrtKeySpec keySpec;
+
+ /**
+ * Create a PKCS#1 keyspec from DER encoded buffer
+ *
+ * @param keyBytes DER encoded octet stream
+ * @throws IOException
+ */
+ public PKCS1EncodedKeySpec(byte[] keyBytes) throws IOException {
+ decode(keyBytes);
+ }
+
+ /**
+ * Get the key spec that JCE understands.
+ *
+ * @return CRT keyspec defined by JCE
+ */
+ public RSAPrivateCrtKeySpec getKeySpec() {
+ return keySpec;
+ }
+
+ /**
+ * Decode PKCS#1 encoded private key into RSAPrivateCrtKeySpec.
+ *
+ * The ASN.1 syntax for the private key with CRT is
+ *
+ *
+ * --
+ * -- Representation of RSA private key with information for the CRT algorithm.
+ * --
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ *
+ *
+ * @param keyBytes PKCS#1 encoded key
+ * @throws IOException
+ */
+
+ private void decode(byte[] keyBytes) throws IOException {
+
+ DerParser parser = new DerParser(keyBytes);
+
+ Asn1Object sequence = parser.read();
+ if (sequence.getType() != DerParser.SEQUENCE)
+ throw new IOException("Invalid DER: not a sequence"); //$NON-NLS-1$
+
+ // Parse inside the sequence
+ parser = sequence.getParser();
+
+ parser.read(); // Skip version
+ BigInteger modulus = parser.read().getInteger();
+ BigInteger publicExp = parser.read().getInteger();
+ BigInteger privateExp = parser.read().getInteger();
+ BigInteger prime1 = parser.read().getInteger();
+ BigInteger prime2 = parser.read().getInteger();
+ BigInteger exp1 = parser.read().getInteger();
+ BigInteger exp2 = parser.read().getInteger();
+ BigInteger crtCoef = parser.read().getInteger();
+
+ keySpec = new RSAPrivateCrtKeySpec(
+ modulus, publicExp, privateExp, prime1, prime2,
+ exp1, exp2, crtCoef);
+ }
+}
Index: lams_tool_imscc/src/java/org/imsglobal/basiclti/Base64.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/org/imsglobal/basiclti/Base64.java (revision 0)
+++ lams_tool_imscc/src/java/org/imsglobal/basiclti/Base64.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,267 @@
+/*
+ * $Header$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.imsglobal.basiclti;
+// package org.apache.commons.httpclient.util;
+
+// import org.apache.commons.httpclient.HttpConstants;
+
+/**
+ * Base64 encoder and decoder.
+ *
+
+ * This class provides encoding/decoding methods for the Base64 encoding as
+ * defined by RFC 2045, N. Freed and N. Borenstein. RFC 2045: Multipurpose
+ * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies.
+ * Reference 1996. Available at:
+ * http://www.ietf.org/rfc/rfc2045.txt
+ *
+
+
+ *
+ * @author Jeffrey Rodriguez
+ * @author Mike Bowler
+ * @version $Revision$ $Date$
+ *
+ */
+public final class Base64 {
+
+ /** */
+ private static final int BASELENGTH = 255;
+
+ /** */
+ private static final int LOOKUPLENGTH = 64;
+
+ /** */
+ private static final int TWENTYFOURBITGROUP = 24;
+
+ /** */
+ private static final int EIGHTBIT = 8;
+
+ /** */
+ private static final int SIXTEENBIT = 16;
+
+ /** */
+ private static final int SIXBIT = 6;
+
+ /** */
+ private static final int FOURBYTE = 4;
+
+ /** The sign bit as an int */
+ private static final int SIGN = -128;
+
+ /** The padding character */
+ private static final byte PAD = (byte) '=';
+
+ /** The alphabet */
+ private static final byte [] BASE64_ALPHABET = new byte[BASELENGTH];
+
+ /** The lookup alphabet */
+ private static final byte [] LOOKUP_BASE64_ALPHABET = new byte[LOOKUPLENGTH];
+
+ static {
+
+ for (int i = 0; i < BASELENGTH; i++) {
+ BASE64_ALPHABET[i] = -1;
+ }
+ for (int i = 'Z'; i >= 'A'; i--) {
+ BASE64_ALPHABET[i] = (byte) (i - 'A');
+ }
+ for (int i = 'z'; i >= 'a'; i--) {
+ BASE64_ALPHABET[i] = (byte) (i - 'a' + 26);
+ }
+
+ for (int i = '9'; i >= '0'; i--) {
+ BASE64_ALPHABET[i] = (byte) (i - '0' + 52);
+ }
+
+ BASE64_ALPHABET['+'] = 62;
+ BASE64_ALPHABET['/'] = 63;
+
+ for (int i = 0; i <= 25; i++) {
+ LOOKUP_BASE64_ALPHABET[i] = (byte) ('A' + i);
+ }
+
+ for (int i = 26, j = 0; i <= 51; i++, j++) {
+ LOOKUP_BASE64_ALPHABET[i] = (byte) ('a' + j);
+ }
+
+ for (int i = 52, j = 0; i <= 61; i++, j++) {
+ LOOKUP_BASE64_ALPHABET[i] = (byte) ('0' + j);
+ }
+ LOOKUP_BASE64_ALPHABET[62] = (byte) '+';
+ LOOKUP_BASE64_ALPHABET[63] = (byte) '/';
+
+ }
+
+ /**
+ * Create an instance.
+ */
+ private Base64() {
+ // the constructor is intentionally private
+ }
+
+ /**
+ * Encodes hex octects into Base64
+ *
+ * @param binaryData Array containing binaryData
+ * @return Base64-encoded array
+ */
+ public static byte[] encode(byte[] binaryData) {
+
+ int lengthDataBits = binaryData.length * EIGHTBIT;
+ int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+ int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+ byte encodedData[] = null;
+
+
+ if (fewerThan24bits != 0) { //data not divisible by 24 bit
+ encodedData = new byte[(numberTriplets + 1) * 4];
+ } else { // 16 or 8 bit
+ encodedData = new byte[numberTriplets * 4];
+ }
+
+ byte k = 0;
+ byte l = 0;
+ byte b1 = 0;
+ byte b2 = 0;
+ byte b3 = 0;
+ int encodedIndex = 0;
+ int dataIndex = 0;
+ int i = 0;
+ for (i = 0; i < numberTriplets; i++) {
+
+ dataIndex = i * 3;
+ b1 = binaryData[dataIndex];
+ b2 = binaryData[dataIndex + 1];
+ b3 = binaryData[dataIndex + 2];
+
+ l = (byte) (b2 & 0x0f);
+ k = (byte) (b1 & 0x03);
+
+ encodedIndex = i * 4;
+ byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
+ : (byte) ((b1) >> 2 ^ 0xc0);
+
+ byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
+ : (byte) ((b2) >> 4 ^ 0xf0);
+ byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
+ : (byte) ((b3) >> 6 ^ 0xfc);
+
+ encodedData[encodedIndex] = LOOKUP_BASE64_ALPHABET[val1];
+ encodedData[encodedIndex + 1] = LOOKUP_BASE64_ALPHABET[val2
+ | (k << 4)];
+ encodedData[encodedIndex + 2] = LOOKUP_BASE64_ALPHABET[(l << 2)
+ | val3];
+ encodedData[encodedIndex + 3] = LOOKUP_BASE64_ALPHABET[b3 & 0x3f];
+ }
+
+ // form integral number of 6-bit groups
+ dataIndex = i * 3;
+ encodedIndex = i * 4;
+ if (fewerThan24bits == EIGHTBIT) {
+ b1 = binaryData[dataIndex];
+ k = (byte) (b1 & 0x03);
+ byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
+ : (byte) ((b1) >> 2 ^ 0xc0);
+ encodedData[encodedIndex] = LOOKUP_BASE64_ALPHABET[val1];
+ encodedData[encodedIndex + 1] = LOOKUP_BASE64_ALPHABET[k << 4];
+ encodedData[encodedIndex + 2] = PAD;
+ encodedData[encodedIndex + 3] = PAD;
+ } else if (fewerThan24bits == SIXTEENBIT) {
+ b1 = binaryData[dataIndex];
+ b2 = binaryData[dataIndex + 1];
+ l = (byte) (b2 & 0x0f);
+ k = (byte) (b1 & 0x03);
+
+ byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
+ : (byte) ((b1) >> 2 ^ 0xc0);
+ byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
+ : (byte) ((b2) >> 4 ^ 0xf0);
+
+ encodedData[encodedIndex] = LOOKUP_BASE64_ALPHABET[val1];
+ encodedData[encodedIndex + 1] = LOOKUP_BASE64_ALPHABET[val2
+ | (k << 4)];
+ encodedData[encodedIndex + 2] = LOOKUP_BASE64_ALPHABET[l << 2];
+ encodedData[encodedIndex + 3] = PAD;
+ }
+ return encodedData;
+ }
+
+
+ /**
+ * Decodes Base64 data into octects
+ *
+ * @param base64Data byte array containing Base64 data
+ * @return Array containing decoded data.
+ */
+ public static byte[] decode(byte[] base64Data) {
+ // Should we throw away anything not in base64Data ?
+
+ // handle the edge case, so we don't have to worry about it later
+ if (base64Data.length == 0) {
+ return new byte[0];
+ }
+
+ int numberQuadruple = base64Data.length / FOURBYTE;
+ byte decodedData[] = null;
+ byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
+
+ int encodedIndex = 0;
+ int dataIndex = 0;
+ {
+ // this block sizes the output array properly - rlw
+ int lastData = base64Data.length;
+ // ignore the '=' padding
+ while (base64Data[lastData - 1] == PAD) {
+ if (--lastData == 0) { return new byte[0]; }
+ }
+ decodedData = new byte[lastData - numberQuadruple];
+ }
+
+ for (int i = 0; i < numberQuadruple; i++) {
+ dataIndex = i * 4;
+ marker0 = base64Data[dataIndex + 2];
+ marker1 = base64Data[dataIndex + 3];
+
+ b1 = BASE64_ALPHABET[base64Data[dataIndex]];
+ b2 = BASE64_ALPHABET[base64Data[dataIndex + 1]];
+
+ if (marker0 != PAD && marker1 != PAD) { //No PAD e.g 3cQl
+ b3 = BASE64_ALPHABET[marker0];
+ b4 = BASE64_ALPHABET[marker1];
+
+ decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+ decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4)
+ | ((b3 >> 2) & 0xf));
+ decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
+ } else if (marker0 == PAD) { //Two PAD e.g. 3c[Pad][Pad]
+ decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4) ;
+ } else if (marker1 == PAD) { //One PAD e.g. 3cQ[Pad]
+ b3 = BASE64_ALPHABET[marker0];
+ decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+ decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4)
+ | ((b3 >> 2) & 0xf));
+ }
+ encodedIndex += 3;
+ }
+ return decodedData;
+ }
+}
\ No newline at end of file
Index: lams_tool_imscc/src/java/org/imsglobal/basiclti/BasicLTIConstants.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/org/imsglobal/basiclti/BasicLTIConstants.java (revision 0)
+++ lams_tool_imscc/src/java/org/imsglobal/basiclti/BasicLTIConstants.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2008 IMS GLobal Learning Consortium
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.imsglobal.basiclti;
+
+public class BasicLTIConstants {
+ /**
+ * context_id=8213060-006f-27b2066ac545
+ *
+ * This is an opaque identifier that uniquely identifies the context that
+ * contains the link being launched.
+ */
+ public static final String CONTEXT_ID = "context_id";
+ /**
+ * context_label=SI182
+ *
+ * A label for the context - intended to fit in a column.
+ */
+ public static final String CONTEXT_LABEL = "context_label";
+ /**
+ * context_title=Design of Personal Environments
+ *
+ * A title of the context - it should be about the length of a line.
+ */
+ public static final String CONTEXT_TITLE = "context_title";
+
+ /**
+ * context_type=CourseSection
+ *
+ * This string is a comma-separated list of URN values that identify the type
+ * of context. At a minimum, the list MUST include a URN value drawn from the
+ * LIS vocabulary (see Appendix A). The assumed namespace of these URNs is the
+ * LIS vocabulary so TCs can use the handles when the intent is to refer to an
+ * LIS context type. If the TC wants to include a context type from another
+ * namespace, a fully-qualified URN should be used.
+ */
+ public static final String CONTEXT_TYPE = "context_type";
+ public static final String CONTEXT_TYPE_COURSE_OFFERING = "CourseOffering";
+ public static final String CONTEXT_TYPE_COURSE_SECTION = "CourseSection";
+ public static final String CONTEXT_TYPE_COURSE_TEMPLATE = "CourseTemplate";
+ public static final String CONTEXT_TYPE_GROUP = "GROUP";
+
+ /**
+ * ext_param=value
+ *
+ * Systems can add their own values to the launch but should prefix
+ * any extensions with "ext_".
+ */
+ public static final String EXTENSION_PREFIX = "ext_";
+ /**
+ * custom_keyname=value
+ *
+ * The creator of a Basic LTI link can add custom key/value parameters to a
+ * launch which are to be included with the launch of the Basic LTI link. The
+ * Common Cartridge section below describes how these parameters are
+ * represented when storing custom parameters in a Common Cartridge.
+ *
+ * When there are custom name / value parameters in the launch, a POST
+ * parameter is included for each custom parameter. The parameter names are
+ * mapped to lower case and any character that is neither a number nor letter
+ * in a parameter name is replaced with an "underscore". So if a custom entry
+ * was as follows:
+ *
+ * Review:Chapter=1.2.56
+ *
+ * Would map to: custom_review_chapter=1.2.56
+ *
+ * Creators of Basic LTI links would be well served to limit their parameter
+ * names to lower case and to use no punctuation other than underscores. If
+ * these custom parameters are included in the Basic LTI link, the TC must
+ * include them in the launch data or the TP may fail to function.
+ */
+ public static final String CUSTOM_PREFIX = "custom_";
+ /**
+ * Parameters with the OAuth prefix are also acceptible.
+ */
+ public static final String OAUTH_PREFIX = "oauth_";
+ /**
+ * launch_presentation_document_target=iframe
+ *
+ * The value should be either 'frame', 'iframe' or 'window'. This field
+ * communicates the kind of browser window/frame where the TC has launched the
+ * tool.
+ */
+ public static final String LAUNCH_PRESENTATION_DOCUMENT_TARGET = "launch_presentation_document_target";
+ /**
+ * launch_presentation_height=240
+ *
+ * The height of the window or frame where the content from the tool will be
+ * displayed.
+ */
+ public static final String LAUNCH_PRESENTATION_HEIGHT = "launch_presentation_height";
+ /**
+ * launch_presentation_locale=en_US_variant
+ *
+ * Language, country and variant separated by underscores. Language is the
+ * lower-case, two-letter code as defined by ISO-639 (list of codes available
+ * at http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt). Country is the
+ * upper-case, two-letter code as defined by ISO-3166 (list of codes available
+ * at http://www.chemie.fu- berlin.de/diverse/doc/ISO_3166.html). Country and
+ * variant codes are optional.
+ */
+ public static final String LAUNCH_PRESENTATION_LOCALE = "launch_presentation_locale";
+ /**
+ * launch_presentation_return_url=http://lmsng.school.edu/portal/123/page/988/
+ *
+ * Fully qualified URL where the TP can redirect the user back to the TC interface. This
+ * URL can be used once the TP is finished or if the TP cannot start or has some
+ * technical difficulty. In the case of an error, the TP may add a parameter called
+ * lti_errormsg that includes some detail as to the nature of the error. The
+ * lti_errormsg value should make sense if displayed to the user. If the tool has
+ * displayed a message to the end user and only wants to give the TC a message to log,
+ * use the parameter lti_errorlog instead of lti_errormsg. If the tool is terminating
+ * normally, and wants a message displayed to the user it can include a text message as
+ * the lti_msg parameter to the return URL. If the tool is terminating normally and
+ * wants to give the TC a message to log, use the parameter lti_log. This data should be
+ * sent on the URL as a GET - so the TP should take care to keep the overall length of
+ * the parameters small enough to fit within the limitations of a GET request.
+ */
+ public static final String LAUNCH_PRESENTATION_RETURN_URL = "launch_presentation_return_url";
+ /**
+ * launch_presentation_width=320
+ *
+ * The width of the window or frame where the content from the tool will be
+ * displayed.
+ */
+ public static final String LAUNCH_PRESENTATION_WIDTH = "launch_presentation_width";
+ /**
+ * launch_presentation_css_url=http://www.toolconsumer.url/path/to/lti.css
+ *
+ * This points to a fully qualified URL for a CSS which can be used to style the tool.
+ * There are no officially defined CSS classes for this file, but the Consumer can
+ * apply styles to paragraphs, body, and the various HTML elements. It is up to the
+ * tool as to whether this CSS is used or not, and in what order this is included relative
+ * to the tool-specific CSS.
+ */
+ public static final String LAUNCH_PRESENTATION_CSS_URL = "launch_presentation_css_url";
+ /**
+ * lis_person_contact_email_primary=user@school.edu
+ *
+ * These fields contain information about the user account that is performing
+ * this launch. The names of these data items are taken from LIS. The precise
+ * meaning of the content in these fields is defined by LIS.
+ */
+ public static final String LIS_PERSON_CONTACT_EMAIL_PRIMARY = "lis_person_contact_email_primary";
+ /**
+ * lis_person_name_family=Public
+ *
+ * These fields contain information about the user account that is performing
+ * this launch. The names of these data items are taken from LIS. The precise
+ * meaning of the content in these fields is defined by LIS.
+ */
+ public static final String LIS_PERSON_NAME_FAMILY = "lis_person_name_family";
+ /**
+ * lis_person_name_full=Jane Q. Public
+ *
+ * These fields contain information about the user account that is performing
+ * this launch. The names of these data items are taken from LIS. The precise
+ * meaning of the content in these fields is defined by LIS.
+ */
+ public static final String LIS_PERSON_NAME_FULL = "lis_person_name_full";
+ /**
+ * lis_person_name_given=Jane
+ *
+ * These fields contain information about the user account that is performing
+ * this launch. The names of these data items are taken from LIS. The precise
+ * meaning of the content in these fields is defined by LIS.
+ */
+ public static final String LIS_PERSON_NAME_GIVEN = "lis_person_name_given";
+
+ /**
+ * lis_person_sourcedid=school.edu:user
+ *
+ * This field contains the LIS identifier for the user account that is
+ * performing this launch. The example syntax of "school:user"
+ * is not the required format � lis_person_sourcedid is simply a
+ * globally unique identifier (i.e., a normalized string). This field
+ * is optional and its content and meaning are defined by LIS.
+ */
+ public static final String LIS_PERSON_SOURCEDID = "lis_person_sourcedid";
+
+ /**
+ * lis_course_offering_sourcedid=school.edu:SI182-F08
+ * lis_course_section_sourcedid=school.edu:SI182-001-F08
+ *
+ * These fields contain LIS course identifiers associated with the
+ * context of this launch. These fields are optional and their
+ * content and meaning are defined by LIS.
+ */
+ public static final String LIS_COURSE_OFFERING_SOURCEDID = "lis_course_offering_sourcedid";
+ public static final String LIS_COURSE_SECTION_SOURCEDID = "lis_course_section_sourcedid";
+
+ /**
+ * lis_result_sourcedid=83873872987329873264783687634
+ *
+ * This field contains an identifier that indicates the LIS Result
+ * Identifier (if any) associated with this launch. This field is
+ * optional and its content and meaning is defined by LIS.
+ */
+ public static final String LIS_RESULT_SOURCEDID = "lis_result_sourcedid";
+
+ /**
+ * lti_message_type=basic-lti-launch-request
+ *
+ * This indicates that this is a Basic LTI Launch Message. This allows a TP to
+ * accept a number of different LTI message types at the same launch URL. This
+ * parameter is required.
+ */
+ public static final String LTI_MESSAGE_TYPE = "lti_message_type";
+ /**
+ * lti_version=LTI-1p0
+ *
+ * This indicates which version of the specification is being used for this
+ * particular message. This parameter is required.
+ */
+ public static final String LTI_VERSION = "lti_version";
+ // launch settings per spec - computed not stored
+ /**
+ * resource_link_id=88391-e1919-bb3456
+ *
+ * This is an opaque unique identifier that the TC guarantees will be unique
+ * within the TC for every placement of the link. If the tool / activity is
+ * placed multiple times in the same context, each of those placements will be
+ * distinct. This value will also change if the item is exported from one
+ * system or context and imported into another system or context. This
+ * parameter is required.
+ */
+ public static final String RESOURCE_LINK_ID = "resource_link_id";
+
+ /**
+ * resource_link_title=My Weekly Wiki
+ *
+ * A title for the resource. This is the clickable text that appears
+ * in the link. This parameter is recommended.
+ */
+ public static final String RESOURCE_LINK_TITLE = "resource_link_title";
+
+ /**
+ * resource_link_description=�
+ *
+ * A plain text description of the link�s destination, suitable for
+ * display alongside the link. Typically no more than several lines
+ * long. This parameter is optional.
+ */
+ public static final String RESOURCE_LINK_DESCRIPTION = "resource_link_description";
+
+ /**
+ * roles=Instructor,Student
+ *
+ * A comma-separated list of URN values for roles. If this list is non-empty,
+ * it should contain at least one role from the LIS System Role, LIS
+ * Institution Role, or LIS Context Role vocabularies (See Appendix A). The
+ * assumed namespace of these URNs is the LIS vocabulary of LIS Context Roles
+ * so TCs can use the handles when the intent is to refer to an LIS context
+ * role. If the TC wants to include a role from another namespace, a
+ * fully-qualified URN should be used. Usage of roles from non-LIS
+ * vocabularies is discouraged as it may limit interoperability. This
+ * parameter is recommended.
+ */
+ public static final String ROLES = "roles";
+ /**
+ * tool_consumer_instance_contact_email=System.Admin@school.edu
+ *
+ * An email contact for the TC instance.
+ */
+ public static final String TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL = "tool_consumer_instance_contact_email";
+ /**
+ * tool_consumer_instance_description=University of School (LMSng)
+ *
+ * This is a user visible field - it should be about the length of a line.
+ */
+ public static final String TOOL_CONSUMER_INSTANCE_DESCRIPTION = "tool_consumer_instance_description";
+ // global settings
+ /**
+ * tool_consumer_instance_guid=lmsng.school.edu
+ *
+ * This is a key to be used when setting a TC-wide password. The TP uses this
+ * as a key to look up the TC-wide secret when validating a message. A common
+ * practice is to use the DNS of the organization or the DNS of the TC
+ * instance. If the organization has multiple TC instances, then the best
+ * practice is to prefix the domain name with a locally unique identifier for
+ * the TC instance. This parameter is recommended.
+ */
+ public static final String TOOL_CONSUMER_INSTANCE_GUID = "tool_consumer_instance_guid";
+ /**
+ * tool_consumer_instance_name=SchoolU
+ *
+ * This is a user visible field - it should be about the length of a column.
+ */
+ public static final String TOOL_CONSUMER_INSTANCE_NAME = "tool_consumer_instance_name";
+ /**
+ * Missing from implementation guide. Needs documentation. Not required, but
+ * "tasty".
+ */
+ public static final String TOOL_CONSUMER_INSTANCE_URL = "tool_consumer_instance_url";
+ /**
+ * user_id=0ae836b9-7fc9-4060-006f-27b2066ac545
+ *
+ * Uniquely identifies the user. This should not contain any identifying
+ * information for the user. Best practice is that this field should be a
+ * TC-generated long-term "primary key" to the user record - not the logical
+ * key. This parameter is recommended.
+ */
+ public static final String USER_ID = "user_id";
+
+ /**
+ * ext_sakai_provider_eid=jsmith26
+ *
+ * If set, this will signal that the external application has provided an eid which
+ * should be used preferentially. Many external applications will not have access to a user's uuid
+ * in Sakai, so this allows integrations with those systems.
+ * This parameter is optional and is unique to the Sakai Basic LTI provider.
+ */
+ public static final String EXT_SAKAI_PROVIDER_EID = "ext_sakai_provider_eid";
+
+ /**
+ * Utility array useful for validating property names when building launch
+ * data.
+ */
+ public static final String[] validPropertyNames = { CONTEXT_ID,
+ CONTEXT_LABEL, CONTEXT_TITLE, CONTEXT_TYPE,
+ LAUNCH_PRESENTATION_DOCUMENT_TARGET, LAUNCH_PRESENTATION_HEIGHT,
+ LAUNCH_PRESENTATION_LOCALE, LAUNCH_PRESENTATION_RETURN_URL,
+ LAUNCH_PRESENTATION_WIDTH, LIS_PERSON_CONTACT_EMAIL_PRIMARY,
+ LAUNCH_PRESENTATION_CSS_URL,
+ LIS_PERSON_NAME_FAMILY, LIS_PERSON_NAME_FULL, LIS_PERSON_NAME_GIVEN,
+ LIS_PERSON_SOURCEDID, LIS_COURSE_OFFERING_SOURCEDID,
+ LIS_COURSE_SECTION_SOURCEDID, LIS_RESULT_SOURCEDID,
+ LTI_MESSAGE_TYPE, LTI_VERSION, RESOURCE_LINK_ID,
+ RESOURCE_LINK_TITLE, RESOURCE_LINK_DESCRIPTION, ROLES,
+ TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL, TOOL_CONSUMER_INSTANCE_DESCRIPTION,
+ TOOL_CONSUMER_INSTANCE_GUID, TOOL_CONSUMER_INSTANCE_NAME,
+ TOOL_CONSUMER_INSTANCE_URL, USER_ID };
+}
\ No newline at end of file
Index: lams_tool_imscc/src/java/org/imsglobal/basiclti/BasicLTIUtil.java
===================================================================
diff -u
--- lams_tool_imscc/src/java/org/imsglobal/basiclti/BasicLTIUtil.java (revision 0)
+++ lams_tool_imscc/src/java/org/imsglobal/basiclti/BasicLTIUtil.java (revision 7f68f72a3d80b8e24ba596d34ccea104ca285d05)
@@ -0,0 +1,849 @@
+/*
+ * $URL$
+ * $Id$
+ *
+ * Copyright (c) 2008 IMS GLobal Learning Consortium
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package org.imsglobal.basiclti;
+
+import static org.imsglobal.basiclti.BasicLTIConstants.CUSTOM_PREFIX;
+import static org.imsglobal.basiclti.BasicLTIConstants.LTI_MESSAGE_TYPE;
+import static org.imsglobal.basiclti.BasicLTIConstants.LTI_VERSION;
+import static org.imsglobal.basiclti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL;
+import static org.imsglobal.basiclti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_DESCRIPTION;
+import static org.imsglobal.basiclti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_GUID;
+import static org.imsglobal.basiclti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_NAME;
+import static org.imsglobal.basiclti.BasicLTIConstants.TOOL_CONSUMER_INSTANCE_URL;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import net.oauth.OAuthAccessor;
+import net.oauth.OAuthConsumer;
+import net.oauth.OAuthMessage;
+
+/* Leave out until we have JTidy 0.8 in the repository
+ import org.w3c.tidy.Tidy;
+ import java.io.ByteArrayOutputStream;
+ */
+
+/**
+ * Some Utility code for IMS Basic LTI
+ * http://www.anyexample.com/programming/java
+ * /java_simple_class_to_compute_sha_1_hash.xml
+ *
+ * Sample Descriptor
+ *
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <basic_lti_link xmlns="http://www.imsglobal.org/xsd/imsbasiclti_v1p0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ * <title>generated by tp+user</title>
+ * <description>generated by tp+user</description>
+ * <custom>
+ * <parameter key="keyname">value</parameter>
+ * </custom>
+ * <extensions platform="www.lms.com">
+ * <parameter key="keyname">value</parameter>
+ * </extensions>
+ * <launch_url>url to the basiclti launch URL</launch_url>
+ * <secure_launch_url>url to the basiclti launch URL</secure_launch_url>
+ * <icon>url to an icon for this tool (optional)</icon>
+ * <secure_icon>url to an icon for this tool (optional)</secure_icon>
+ * <cartridge_icon identifierref="BLTI001_Icon"/>
+ * <vendor>
+ * <code>vendor.com</code>
+ * <name>Vendor Name</name>
+ * <description>
+ * This is a Grade Book that supports many column types.
+ * </description>
+ * <contact>
+ * <email>support@vendor.com</email>
+ * </contact>
+ * <url>http://www.vendor.com/product</url>
+ * </vendor>
+ * </basic_lti_link>
+ *
+ */
+public class BasicLTIUtil {
+
+ // We use the built-in Java logger because this code needs to be very generic
+ private static Logger M_log = Logger.getLogger(BasicLTIUtil.class.toString());
+
+ /** To turn on really verbose debugging */
+ private static boolean verbosePrint = false;
+
+ public static final String BASICLTI_SUBMIT = "ext_basiclti_submit";
+
+ private static final Pattern CUSTOM_REGEX = Pattern.compile("[^A-Za-z0-9]");
+ private static final String UNDERSCORE = "_";
+
+ // Simple Debug Print Mechanism
+ public static void dPrint(String str) {
+ if (verbosePrint)
+ System.out.println(str);
+ M_log.fine(str);
+ }
+
+ public static String validateDescriptor(String descriptor) {
+ if (descriptor == null)
+ return null;
+ if (descriptor.indexOf(" tm = XMLMap.getFullMap(descriptor.trim());
+ if (tm == null)
+ return null;
+
+ // We demand at least an endpoint
+ String ltiSecureLaunch = XMLMap.getString(tm,
+ "/basic_lti_link/secure_launch_url");
+ // We demand at least an endpoint
+ if (ltiSecureLaunch != null && ltiSecureLaunch.trim().length() > 0)
+ return ltiSecureLaunch;
+ String ltiLaunch = XMLMap.getString(tm, "/basic_lti_link/launch_url");
+ if (ltiLaunch != null && ltiLaunch.trim().length() > 0)
+ return ltiLaunch;
+ return null;
+ }
+
+ /**
+ * Any properties which are not well known (i.e. in
+ * {@link BasicLTIConstants#validPropertyNames}) will be mapped to custom
+ * properties per the specified semantics. NOTE: no blacklisting of keys is
+ * performed.
+ *
+ * @param rawProperties
+ * A set of properties that will be cleaned.
+ * @return A cleansed version of rawProperties.
+ */
+ public static Map cleanupProperties(
+ final Map rawProperties) {
+ return cleanupProperties(rawProperties, null);
+ }
+
+ /**
+ * Any properties which are not well known (i.e. in
+ * {@link BasicLTIConstants#validPropertyNames}) will be mapped to custom
+ * properties per the specified semantics.
+ *
+ * @param rawProperties
+ * A set of properties that will be cleaned.
+ * @param blackList
+ * An array of {@link String}s which are considered unsafe to be
+ * included in launch data. Any matches will be removed from the
+ * return.
+ * @return A cleansed version of rawProperties.
+ */
+ public static Map cleanupProperties(
+ final Map rawProperties, final String[] blackList) {
+ final Map newProp = new HashMap(
+ rawProperties.size()); // roughly the same size
+ for (String okey : rawProperties.keySet()) {
+ final String key = okey.trim();
+ if (blackList != null) {
+ boolean blackListed = false;
+ for (String blackKey : blackList) {
+ if (blackKey.equals(key)) {
+ blackListed = true;
+ break;
+ }
+ }
+ if (blackListed) {
+ continue;
+ }
+ }
+ final String value = rawProperties.get(key);
+ if (value == null || "".equals(value)) {
+ // remove null or empty values
+ continue;
+ }
+ if (isSpecifiedPropertyName(key)) {
+ // a well known property name
+ newProp.put(key, value);
+ } else {
+ // convert to a custom property name
+ newProp.put(adaptToCustomPropertyName(key), value);
+ }
+ }
+ return newProp;
+ }
+
+ /**
+ * Any properties which are not well known (i.e. in
+ * {@link BasicLTIConstants#validPropertyNames}) will be mapped to custom
+ * properties per the specified semantics.
+ *
+ * @deprecated See {@link #cleanupProperties(Map)}
+ * @param rawProperties
+ * A set of {@link Properties} that will be cleaned. Keys must be of
+ * type {@link String}.
+ * @return A cleansed version of {@link Properties}.
+ */
+ public static Properties cleanupProperties(final Properties rawProperties) {
+ final Map map = cleanupProperties(
+ convertToMap(rawProperties), null);
+ return convertToProperties(map);
+ }
+
+ /**
+ * Checks to see if the passed propertyName is equal to one of the Strings
+ * contained in {@link BasicLTIConstants#validPropertyNames}. String matching
+ * is case sensitive.
+ *
+ * @param propertyName
+ * @return true if propertyName is equal to one of the Strings contained in
+ * {@link BasicLTIConstants#validPropertyNames}
+ * or is a custom parameter oe extension parameter ;
+ * else return false.
+ */
+ public static boolean isSpecifiedPropertyName(final String propertyName) {
+ boolean found = false;
+ if ( propertyName.startsWith(BasicLTIConstants.CUSTOM_PREFIX) ) return true;
+ if ( propertyName.startsWith(BasicLTIConstants.EXTENSION_PREFIX) ) return true;
+ if ( propertyName.startsWith(BasicLTIConstants.OAUTH_PREFIX) ) return true;
+ for (String key : BasicLTIConstants.validPropertyNames) {
+ if (key.equals(propertyName)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ }
+
+ /**
+ * A simple utility method which implements the specified semantics of custom
+ * properties.
+ *
+ * i.e. The parameter names are mapped to lower case and any character that is
+ * neither a number nor letter in a parameter name is replaced with an
+ * "underscore".
+ *
+ * e.g. Review:Chapter=1.2.56 would map to custom_review_chapter=1.2.56.
+ *
+ * @param propertyName
+ * @return
+ */
+ public static String adaptToCustomPropertyName(final String propertyName) {
+ if (propertyName == null || "".equals(propertyName)) {
+ throw new IllegalArgumentException("propertyName cannot be null");
+ }
+ String customName = propertyName.toLowerCase();
+ customName = CUSTOM_REGEX.matcher(customName).replaceAll(UNDERSCORE);
+ if (!customName.startsWith(CUSTOM_PREFIX)) {
+ customName = CUSTOM_PREFIX + customName;
+ }
+ return customName;
+ }
+
+ /**
+ * Add the necessary fields and sign.
+ *
+ * @deprecated See:
+ * {@link BasicLTIUtil#signProperties(Map, String, String, String, String, String, String, String, String, String)}
+ *
+ * @param postProp
+ * @param url
+ * @param method
+ * @param oauth_consumer_key
+ * @param oauth_consumer_secret
+ * @param org_id
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_GUID}
+ * @param org_desc
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_DESCRIPTION}
+ * @param org_url
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_URL}
+ * @return
+ */
+ public static Properties signProperties(Properties postProp, String url,
+ String method, String oauth_consumer_key, String oauth_consumer_secret,
+ String org_id, String org_desc, String org_url) {
+ final Map signedMap = signProperties(
+ convertToMap(postProp), url, method, oauth_consumer_key,
+ oauth_consumer_secret, org_id, org_desc, org_url, null, null);
+ return convertToProperties(signedMap);
+ }
+
+ /**
+ * Add the necessary fields and sign.
+ *
+ * @param postProp
+ * @param url
+ * @param method
+ * @param oauth_consumer_key
+ * @param oauth_consumer_secret
+ * @param tool_consumer_instance_guid
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_GUID}
+ * @param tool_consumer_instance_description
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_DESCRIPTION}
+ * @param tool_consumer_instance_url
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_URL}
+ * @param tool_consumer_instance_name
+ * See: {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_NAME}
+ * @param tool_consumer_instance_contact_email
+ * See:
+ * {@link BasicLTIConstants#TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL}
+ * @return
+ */
+ public static Map signProperties(
+ Map postProp, String url, String method,
+ String oauth_consumer_key, String oauth_consumer_secret,
+ String tool_consumer_instance_guid,
+ String tool_consumer_instance_description,
+ String tool_consumer_instance_url, String tool_consumer_instance_name,
+ String tool_consumer_instance_contact_email) {
+ postProp = BasicLTIUtil.cleanupProperties(postProp);
+ postProp.put(LTI_VERSION, "LTI-1p0");
+ postProp.put(LTI_MESSAGE_TYPE, "basic-lti-launch-request");
+ // Allow caller to internationalize this for us...
+ if (postProp.get(BASICLTI_SUBMIT) == null) {
+ postProp.put(BASICLTI_SUBMIT, "Launch Endpoint with BasicLTI Data");
+ }
+ if (tool_consumer_instance_guid != null)
+ postProp.put(TOOL_CONSUMER_INSTANCE_GUID, tool_consumer_instance_guid);
+ if (tool_consumer_instance_description != null)
+ postProp.put(TOOL_CONSUMER_INSTANCE_DESCRIPTION,
+ tool_consumer_instance_description);
+ if (tool_consumer_instance_url != null)
+ postProp.put(TOOL_CONSUMER_INSTANCE_URL, tool_consumer_instance_url);
+ if (tool_consumer_instance_name != null)
+ postProp.put(TOOL_CONSUMER_INSTANCE_NAME, tool_consumer_instance_name);
+ if (tool_consumer_instance_contact_email != null)
+ postProp.put(TOOL_CONSUMER_INSTANCE_CONTACT_EMAIL,
+ tool_consumer_instance_contact_email);
+
+ if (postProp.get("oauth_callback") == null)
+ postProp.put("oauth_callback", "about:blank");
+
+ if (oauth_consumer_key == null || oauth_consumer_secret == null) {
+ dPrint("No signature generated in signProperties");
+ return postProp;
+ }
+
+ OAuthMessage oam = new OAuthMessage(method, url, postProp.entrySet());
+ OAuthConsumer cons = new OAuthConsumer("about:blank", oauth_consumer_key,
+ oauth_consumer_secret, null);
+ OAuthAccessor acc = new OAuthAccessor(cons);
+ try {
+ oam.addRequiredParameters(acc);
+ // System.out.println("Base Message String\n"+OAuthSignatureMethod.getBaseString(oam)+"\n");
+
+ List> params = oam.getParameters();
+
+ Map nextProp = new HashMap();
+ // Convert to Map
+ for (final Map.Entry entry : params) {
+ nextProp.put(entry.getKey(), entry.getValue());
+ }
+ return nextProp;
+ } catch (net.oauth.OAuthException e) {
+ M_log.warning("BasicLTIUtil.signProperties OAuth Exception "
+ + e.getMessage());
+ throw new Error(e);
+ } catch (java.io.IOException e) {
+ M_log.warning("BasicLTIUtil.signProperties IO Exception "
+ + e.getMessage());
+ throw new Error(e);
+ } catch (java.net.URISyntaxException e) {
+ M_log.warning("BasicLTIUtil.signProperties URI Syntax Exception "
+ + e.getMessage());
+ throw new Error(e);
+ }
+
+ }
+
+ /**
+ * Create the HTML to render a POST form and then automatically submit it.
+ * Make sure to call {@link #cleanupProperties(Properties)} before signing.
+ *
+ * @deprecated Moved to {@link #postLaunchHTML(Map, String, boolean)}
+ * @param cleanProperties
+ * Assumes you have called {@link #cleanupProperties(Properties)}
+ * beforehand.
+ * @param endpoint
+ * The LTI launch url.
+ * @param debug
+ * Useful for viewing the HTML before posting to end point.
+ * @return the HTML ready for IFRAME src = inclusion.
+ */
+ public static String postLaunchHTML(final Properties cleanProperties,
+ String endpoint, boolean debug) {
+ Map map = convertToMap(cleanProperties);
+ return postLaunchHTML(map, endpoint, debug);
+ }
+
+ /**
+ * Create the HTML to render a POST form and then automatically submit it.
+ * Make sure to call {@link #cleanupProperties(Properties)} before signing.
+ *
+ * @param cleanProperties
+ * Assumes you have called {@link #cleanupProperties(Properties)}
+ * beforehand.
+ * @param endpoint
+ * The LTI launch url.
+ * @param debug
+ * Useful for viewing the HTML before posting to end point.
+ * @return the HTML ready for IFRAME src = inclusion.
+ */
+ public static String postLaunchHTML(
+ final Map cleanProperties, String endpoint, boolean debug) {
+ if (cleanProperties == null || cleanProperties.isEmpty()) {
+ throw new IllegalArgumentException(
+ "cleanProperties == null || cleanProperties.isEmpty()");
+ }
+ if (endpoint == null) {
+ throw new IllegalArgumentException("endpoint == null");
+ }
+ Map newMap = null;
+ if (debug) {
+ // sort the properties for readability
+ newMap = new TreeMap(cleanProperties);
+ } else {
+ newMap = cleanProperties;
+ }
+ StringBuilder text = new StringBuilder();
+ // paint form
+ text.append("