README.md in dce_lti-0.4.0 vs README.md in dce_lti-0.5.0

- old
+ new

@@ -8,16 +8,23 @@ * A postgres database * Rails > 4.1.x ## Getting started -Add this engine to your gemfile: +Add these gems to your gemfile: gem 'dce_lti' + gem 'activerecord-session_store', '~> 0.1.1'' -Install it and run migrations: +Update (or create) `config/initializers/session_store.rb` and ensure it contains: + Rails.application.config.session_store :active_record_store, key: '_your_app_session', expire_after: 60.minutes + +Where `_your_app_session` is your application's session key. + +Bundle, install and then run migrations: + bundle rake dce_lti:install rake db:migrate Mount the engine in 'config/routes.rb' @@ -34,10 +41,14 @@ def show @post = current_user.posts.where(id: params[:id]) end end +That's it! You'll need to configure to fit your use case, but you've got the +basics of LTI authentication (including experimental cookieless sessioning, see +below) working already. + ## Configuration The generated config looks something like (commented defaults omitted): DceLti::Engine.setup do |lti| @@ -103,11 +114,11 @@ See [IMS::LTI::Extensions::Canvas::ToolConfig](https://github.com/instructure/ims-lti/blob/master/lib/ims/lti/extensions/canvas.rb) and other classes/modules under the IMS::LTI::Extensions hierarchy for further options. -## Notes +## Other The `DceLti` provided controllers inherit from `ApplicationController` as defined in your application. ### Consumer context info @@ -135,9 +146,98 @@ If an LTI session cannot be validated, `dce_lti/sessions/invalid` will be rendered. You can customize this output by creating a file named `app/views/dce_lti/sessions/invalid.html.erb`, per the default engine view resolution behavior. + +### Cookieless Sessions - Experimental + +If you're running your LTI app on a domain different than your LMS, it will not +work in recent Safari browers. This is because [Safari blocks third party +cookies set in an iframe by +default](https://support.apple.com/kb/PH19214?locale=en_US). Mozilla has hinted +at implementing this default as well, so the days of setting a cookie in an +iframe and expecting it to work are probably numbered. Thanks, pervasive ad +networks! + +There are a few options: + +1. Run your LMS and LTI provider on the same domain. This isn't really doable + if you want to provide a tool useful to multiple consumers on multiple domains, +1. Only provide completely anonymous LTI tools, +1. Build single page javascript-driven apps, +1. Ask your users to enable third-party cookies, +1. Block users when you detect they don't support third-party cookies, +1. Persist the users session by including it in every link and form. + +This engine implements the last option by detecting when a browser doesn't +accept cookies and then rewriting outgoing URLs and forms to include a session. + +This behavior is disabled by default and requires minimal app-level changes: + +1. Edit `config/initializers/dce_lti_config.rb`. Uncomment + `lti.enable_cookieless_sessions = false` and set it to `true`. +1. You must use database sessions as provided by `activerecord-session_store`, + which we install by default and you should've already configured. +1. The `redirect_after_successful_auth` path must include the session key and + id so we can pick it up if cookies aren't available (this is the default as + well). + +Please report bugs to github issues, there are bound to be a few. + +If a user supports cookies, we do basically nothing. We don't rewrite forms or +URLs and we use a cookied (and database-backed) session per the usual. + +#### How cookieless sessions work + +When a request comes in without a cookie but with the session key and ID, then +the `DceLti::Middleware::CookieShim` middleware "shims" it into the Rack +environment and the session information is restored by subsequent middleware. + +When we detect that a user doesn't accept third-party cookies, we use +`Rack::Plastic` to rewrite forms and URLs to include the session key and id +from the `redirect_after_successful_auth` redirect. This happens in the +`DceLti::Middleware::CookielessSessions` middleware. + +#### Known issues with cookieless sessions + +* Even if your app works with cookieless sessions, other cookie sessioned + iframe'd apps won't: for instance the youtube javascript iframe API and many + other third-party javascript apps. +* We only rewrite URLs without a protocol and domain ('/posts/1') to match the + URLs emitted by rails by default. If you're manually inserting links to your + application that include the protocol and domain name + ('http://example.com/posts/1'), the middleware doesn't catch it. This could + be fixed to be a bit smarter in the future. +* You will need to ensure that the session key and id tags along for ajax + requests to your LTI application. + +#### Database session cleanup + +Run the included `dce_lti:clean_sessions` rake task periodically to remove old +sessions - the default is 7 days, you can modify this with the +`OLDER_THAN_X_DAYS` environment variable, thusly: + + OLDER_THAN_X_DAYS=14 rake dce_lti:clean_sessions + +#### Database session hijacking for cookieless sessions + +This is an issue, unfortunately. If a malicious user were able to get ahold of +a link in another user's LTI session (when that other user is under a +cookieless session) it'd contain a working session ID and could be exploited. + +This can be mitigated several ways: + +1. Deliver your LTI application over SSL to protect the transport layer. You + pretty much need to do this anyway, so this shouldn't be a big deal. +1. Expire your sessions by setting the `expire_after` option in + `config/initializers/session_store.rb` to a value short enough to not annoy + your users. + +If you set `expire_after` too short, your users will get annoyed. If you set it +too long, the sessions will linger and increase the time the session is +vulnerable. We're looking into other ways of mitigating this as well - PRs +accepted! ### Nonce cleanup You can clean up lti-related [nonces](http://en.wikipedia.org/wiki/Cryptographic_nonce) via the