Uploaded image for project: 'Sakai'
  1. Sakai
  2. SAK-45491

Support LTI 1.3 Key Rotation

    XMLWordPrintable

Details

    • Yes
    • Yes
    • Hide

      To do a full test, it is good to to have access to logs and to the database and you need a test version of the server with a property to tell Sakai to rotate keys every two minutes (default is 30 days).

      lti.advantage.key.rotation.days=-2

      All LTI 1.3 test scripts should work unchanged (i.e. this should not introduce a regression).

      To watch the actual rotation you need to look at a keyset url and watch the logs.

      Manually verify rotation using keyset URL

      Install a LTI 1.3 tool.  Do not launch the tool - do not "install learning app" - but first note the keyset url (i.e. like http://localhost:8080/imsblis/lti13/keyset/8 ) in the Sakai UI.  Watch the Sakai logs.  Navigate to the URL.  You should see one key in the JSON - not the "kid" value.  The log should say:

      org.sakaiproject.basiclti.util.SakaiBLTIUtil.rotateToolKeys Created future keys for tool=8

      Then refresh the keyset URL - you should see two keys - one key with the original kid and a new key with a second kid.   Press refresh again and you should see two keys.

      At this point you need to wait 30 days or two minutes with this setting:

      lti.advantage.key.rotation.days=-2

      If you wait 30 days (or 2 minutes) and press refresh on the keyset URL you would see a log entry that looks like:

      org.sakaiproject.basiclti.util.SakaiBLTIUtil.rotateToolKeys Rotated keys for tool=8 days=30 delta=34

      And you would see three keys with both of the first two kids and a new kid.  Then if you waited another 30 days (or 2 minutes) and press refresh you would see the "rotate" log message. And the first kid would be gone and there would be three kids.  The kids are rotating while keeping a history of the most recent two kids.

      If you have access to the database you can force a rotation by going into the `lti_tools` table, find your tool, edit it and change the `lti13_platform_public_next_at` value to more than 30 days in the past and press refresh to trigger a rotation.

      In general, if there is one key in the keyset, the next has not yet been populated.  If there are two keys in the keyset, next has been populated but rotation has not yet happened.  Once there are three keys in the keyset, at least one rotation has happened.

      Testing Launches While Rotation Is Happening

      Now install a tool using Deep Linking / Install Learning App - watch the logs - you might see the "future key" or "rotate key" messages depending on your settings and elapsed time.

      After the tool is installed launch the tool - it should work.   Then force key rotation by waiting 30 days, 2 minutes or editing the `lti13_platform_public_next_at` and making it 2 months in the past.

      Do three successive launches - you should see a rotate message for one of the launches (likely the first launch).

      Wait or change `lti13_platform_public_next_at` again and do three more launches - they all should succeed.

      If you want to reset the tool to the "just installed state" set `lti13_platform_public_next_at`, `lti13_platform_public_next`, `lti13_platform_private_next`, `lti13_platform_public_old`, and `lti13_platform_public_old_at` to NULL.  Then do a launch and you will see the "future key" message and the launch will work.  Do a second launch, it should work.  Force a rotation by editing `lti13_platform_public_next_at` and do a launch - you will see the "rotate" message - and then do another launch.

      No matter what you do, rotate or not - all launches should work.  The rotation is supposed to be seamless to Sakai and to the Tool - the tool detects the new kid and gets the new public key from the keyset url.  Just don't set the current public/private key to null - that will break everything quickly

       

       

      Show
      To do a full test, it is good to to have access to logs and to the database and you need a test version of the server with a property to tell Sakai to rotate keys every two minutes (default is 30 days). lti.advantage.key.rotation.days=-2 All LTI 1.3 test scripts should work unchanged (i.e. this should not introduce a regression). To watch the actual rotation you need to look at a keyset url and watch the logs. Manually verify rotation using keyset URL Install a LTI 1.3 tool.  Do not launch the tool - do not "install learning app" - but first note the keyset url (i.e. like http://localhost:8080/imsblis/lti13/keyset/8 ) in the Sakai UI.  Watch the Sakai logs.  Navigate to the URL.  You should see one key in the JSON - not the "kid" value.  The log should say: org.sakaiproject.basiclti.util.SakaiBLTIUtil.rotateToolKeys Created future keys for tool=8 Then refresh the keyset URL - you should see two keys - one key with the original kid and a new key with a second kid.   Press refresh again and you should see two keys. At this point you need to wait 30 days or two minutes with this setting: lti.advantage.key.rotation.days=-2 If you wait 30 days (or 2 minutes) and press refresh on the keyset URL you would see a log entry that looks like: org.sakaiproject.basiclti.util.SakaiBLTIUtil.rotateToolKeys Rotated keys for tool=8 days=30 delta=34 And you would see three keys with both of the first two kids and a new kid.  Then if you waited another 30 days (or 2 minutes) and press refresh you would see the "rotate" log message. And the first kid would be gone and there would be three kids.  The kids are rotating while keeping a history of the most recent two kids. If you have access to the database you can force a rotation by going into the `lti_tools` table, find your tool, edit it and change the `lti13_platform_public_next_at` value to more than 30 days in the past and press refresh to trigger a rotation. In general, if there is one key in the keyset, the next has not yet been populated.  If there are two keys in the keyset, next has been populated but rotation has not yet happened.  Once there are three keys in the keyset, at least one rotation has happened. Testing Launches While Rotation Is Happening Now install a tool using Deep Linking / Install Learning App - watch the logs - you might see the "future key" or "rotate key" messages depending on your settings and elapsed time. After the tool is installed launch the tool - it should work.   Then force key rotation by waiting 30 days, 2 minutes or editing the `lti13_platform_public_next_at` and making it 2 months in the past. Do three successive launches - you should see a rotate message for one of the launches (likely the first launch). Wait or change `lti13_platform_public_next_at` again and do three more launches - they all should succeed. If you want to reset the tool to the "just installed state" set `lti13_platform_public_next_at`, `lti13_platform_public_next`, `lti13_platform_private_next`, `lti13_platform_public_old`, and `lti13_platform_public_old_at` to NULL.  Then do a launch and you will see the "future key" message and the launch will work.  Do a second launch, it should work.  Force a rotation by editing `lti13_platform_public_next_at` and do a launch - you will see the "rotate" message - and then do another launch. No matter what you do, rotate or not - all launches should work.  The rotation is supposed to be seamless to Sakai and to the Tool - the tool detects the new kid and gets the new public key from the keyset url.  Just don't set the current public/private key to null - that will break everything quickly    

    Description

      This will add a feature to rotate the platform public / private key pairs in LTI tool registrations.   There are three public/private keys that Sakai uses:

      • The current public/private pair that is being used to sign outgoing launches
      • The next public/private pair that will be used after the rotation period has expired.   We create the "next" key well before we start using it so that it can already be in the tool keyset caches when we start signing with the "next" key.
      • The previous public key that we were using to sign before the rotation period.  We don't need the previous private key because all we need to do is allow signatures "in flight" to be verified for a short period after key rotation happens.

      Rotation happens as a side effect of the tool retrieving the keyset URL.  We check if the "next key" is empty - if so we generate a new key and set the "next date".  If the "next key" exists and has been around for at least the rotation period, we push the current public key to the old position, push the "next" key pair to the current position, and generate a new "next" pair and set the "next date".

      Once things are cruising along, the tools will always see the next, current, and previous public keys in the keyset url.  Because each LTI 1.3 launch has a "kid" value in the launch, Sakai tells the tool which public key to use from the keyset.  It means that Sakai can sign launches with a current key and an instant later Sakai can use another current key and for a time period tools can validate using either key because both keys remain in the keyset for a while.

      The nominal rotation period is between days and a month or so.  Some LMSs do it as seldom as once per year.  Any period from a week to a year is seen as reasonable.  Sakai will have a property to control how often the keys are rotated.

      lti.advantage.key.rotation.days=30

      • For positive numbers this is the number of days before rotation happens
      • For negative numbers it is the number of minutes before rotation happens (for testing)
      • If it is zero, no rotation happens
      • The default is 30 days

      The rotation happens as a side effect of retrieving the keyset url - so inactive tools are not rotated.  We may later add a timed task to trigger rotations even when keyset urls are not accessed - but for now we will keep this new feature simple.

       

      Gliffy Diagrams

        Zeplin

          Attachments

            Issue Links

              Activity

                People

                  csev Charles Severance
                  csev Charles Severance
                  Votes:
                  0 Vote for this issue
                  Watchers:
                  1 Start watching this issue

                  Dates

                    Created:
                    Updated:
                    Resolved:

                    Git Integration