-
Notifications
You must be signed in to change notification settings - Fork 2
LTI Integration #351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bhunt02
wants to merge
57
commits into
main
Choose a base branch
from
bridgette/canvas-lti-integration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
LTI Integration #351
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This reverts commit 17d140e.
…i and overall begun work
…ork ultimately, but leaving it in for usage later when i figure out how the cookie... will crumble
…o bridgette/canvas-lti-integration
…o bridgette/canvas-lti-integration
…ll works. ltijs isn't perfect but at least i don't have to code all the access handshakes myself
# Conflicts: # packages/common/index.ts # packages/server/ormconfig.ts # yarn.lock
# Conflicts: # packages/frontend/app/(dashboard)/components/CourseCloneForm.tsx # packages/frontend/app/(dashboard)/components/coursesSection.tsx
# Conflicts: # packages/server/ormconfig.ts # packages/server/postgres.env.example
…made tweaks. and then coded a lot. and a lot more. and then added the oauth pipeline and started work on refactoring how LMS integrations will work in the first place
…on and refactored lms integrations (course + org) for changes, added new attributes to forms and redesigned input interfaces, controller methods, service methods, etc.
…ch data. also added a QOL LMS integration within the LTI interface (and solved problems surrounding that)
* moved key middleware definitions back into addGlobals (was affecting tests lol) * small tweaks here and there * added lti_test to docker-compose config * added factories for new LMS models * wrote tests for LTI (excl. middleware as its 90% tested by native library tests) + new tests for LMS (oauth pipeline + expansion)
…integration # Conflicts: # packages/frontend/app/(dashboard)/components/FooterBar.tsx
…d for the LTI auth interactions on frontend as well. tested, everything is working great! separating the tokens was a good plan for this. also, updated the SSO auth (w/ google, at least) to use authstate and state query param to verify the request is authorized + carry the organization id information, rather than old impl w/ the cookie
…integration # Conflicts: # packages/frontend/app/(auth)/login/page.tsx
… canvas environment and staged helpme), also made it so SSO login options can access legacy accounts (doesn't convert them either, we just assume it's their account as we should)
…integration # Conflicts: # packages/frontend/app/(dashboard)/components/FooterBar.tsx
…' into bridgette/canvas-lti-integration
holy smokes, i just finished mostly reading the PR description. I don't have any comments yet and I haven't started reviewing the code itself, but I just wanna say I appreciate you putting in so much effort and detail into it EDIT: the description (everything above the "Type of Change" header) is almost 3500 words haha |
…integration merge with main
…i interface, also ensuring that if user is unverified they're shown the verify email interface (dashboard in both main/lti interface layout will show it even if middleware fails to redirect if profile returned is unverified!)
…an access token, we let the other prof (non-owner) know there's already one and warn them to be careful or overwriting)
…eds to be accessed off-site)
…as-helpme account emails, added model for tracking a cookie which will store a code that syncs up to one of these models upon login/registration (account will be created through lti and have a link from the get-go ensuring auto-login on later launches), updated tests for new behaviour
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
This will get a better description laterOh god... do I really have to???
Fine...
Major Changes/Additions
Learning-Teaching Interoperability
userRole = admin
.https://<domain>/api/v1/lti/register
for dynamic registration)lti-typescript
(more on that later) to perform the LTI launch authorization/pipelineAuthentication Pipeline Expansion/Refactor
/lti/(auth)/...
SameSite=None
;auth.service.ts
now contains methods which process the response, but take in several optional parameters.login.service.ts
was created to facilitate the login methods for both (at least, the two current versions, default and lti) with variable behavioursentry
is a function which maps to the old login entry behaviour that was repeated in several instances of the code (e.g., SSO auth & legacy auth had shared behaviours)handleCookies
performs the management of redirects with email-verification specific behaviours added, and LTI-specific ones tooauth.controller.ts
heavily modified with a lot of behaviour extracted toauth.service.ts
lti-auth.controller.ts
created to callauth.service.ts
methods with LTI-specific parameters (e.g., cookie options, redirects)lti_auth_token
specificallyauth_token
so we can differentiate (at least slightly)state
query parameter to pass a unique, 32-bit identifier that is later used to authenticate the SSO login request (at the callback) and retrieve the stored organization ID.AuthStateModel
is used for this. It stores thestate
sequence as a primary key, expires in 60 seconds, and identifies the organization being logged in with.LMS Integrations
LMSAccessTokenModel
entitiesLMSAuthStateModel
entity is created (it has some useful properties such as storing a redirect right back to the page with certain query params)What's an LTI-Typescript???
A library called
ltijs
was offered to me as an option for configuring our integration.I started trying to use the library and then I realized it was pure Javascript.
This deeply upset me. I then embarked on a 2-week-long endeavor to fork and rebuild this library using TypeScript.
It uses TypeORM, like we do, for compatibility. Also because the original implementation used MongoDB and I wasn't about to add another DBMS and database server/container we have to use and secure.
Learned a lot about the LTI protocol and how it works. We now have a library that is strongly typed and I'll try to maintain.
You can find it here.
What else has been added?
server/.env
LTI_SECRET_KEY
- the secret key used by LTI-Typescript for en/decrypting data in encrypted tablesserver/postgres.env
POSTGRES_LTI_DB
- the name of the database used for lti (it'slti
)lti
,lti_test
(purposes are exactly what you think)test_createdb.sql
file that is used for creating the test DBs in CIapi/server.ts
file added, provides server-side version (NOT FOR MIDDLEWARE) of theapi/index.ts
file/lti
path/admin
path/admin/lti
- LTI platform managementconstants.tsx
- File for defining constants. Currently exports and holds the HELPME_VERSION variableadmin.controller.ts
(empty, for now) andadmin.service.ts
(same)lti.middleware.ts
, a middleware that is registered and used to configure the LTI-Typescript instancedataEndec.ts
, which will decrypt and encrypt values for storage in an entity that has an encrypted columnLMSAccessTokenModel
as it encrypts the token details with the client secret.AdminRoleGuard
is used to guard routes only for users withuserRole = admin
LTIGuard
checks that theresponse.locals['token']
object is defined.LMSAuthStateModel
,AuthStateModel
.AbstractLMSAdapter
/ LMS Adapters in generalcreateState
- creates an LMSAuthStateModel instance with a unique state sequencelogoutAuth
- initializes a logout (invalidation) operation of a user's access tokenredirectAuth
- initializes an authorization redirect operation for access token generation.postAuth
- accepts an authorization response for access token generation.logoutAuth
- implemented in subclasses. Used for invalidating access tokens.checkAccessToken
- implemented method for checking whether an access token is valid. Refreshes the access token if not.getAuthorization
- implemented method for getting the authorization header.Bearer <token>
header.<token-type> <token>
header.getUserCourses
- implemented in subclasses, gets the courses to which a user belongs, pending they have an access token.lmsIntegration.controller.ts
GET org/:oid/token
-> (ORG ADMIN) retrieves the tokens for the organization and (optional) platformDELETE org/:oid/token/:tokenId
-> (ORG ADMIN) invalidates user access token if foundGET oauth2/token
-> retrieves the user's options for tokens (used in course integration upsert)DELETE oauth2/token/:tokenId
-> invalidates user access token if found and belonging to userGET oauth2/authorize
-> starts the pipeline for generating an access tokenGET oauth2/response
-> performs the response actions for generating an access token after redirected backGET course/list/:tokenId
-> gets the platform course list for the user given their tokenlmsIntegration.service.ts
createAccessToken
,destroyAccessToken
methodscreateAccessToken
- takes the data from the oauth2 response, encrypts it into anLMSAccessTokenModel
deleteAccessToken
- performs the logout auth and deletes the token if successfullogin.service.ts
initLoginEnter
- used in login controller and lti auth controller to try to call LoginService.enter, fails if token is invalidenter
- performs the old entry method with modificationshandleCookies
- performs the redirect/cookie handling that the old entry method (and duplicates of it) would dohandleLTICourseInviteCookie
- used in specific circumstances to check the LTI course invite without calling for a redirectgenerateAuthToken
- generates an authentication token for HelpMe with given parameterslti-auth.controller.ts
- implements several methods fromauth.controller.ts
, customized for LTI (nothing unique besides parameter differences)lti.controller.ts
- entrypoint for LTI functionality.ALL /
- entrypoint for LTI. returns a redirect to the/lti
frontend route, or/lti/<courseId>
frontend route if course matching API course is found.LoginService.enter
method if the user is found./lti/login
frontend if user is not found.LTICourseInviteModel
s and cookies to add the user to a course after they've registered, if not foundAdminGuard
'd endpoints for platform management.lti.middleware.ts
- defines the configuration for the LTI-Typescript provider-as-middlewarelti.service.ts
createCourseInvite
- creates an LTI course invitecheckCourseInvite
- checks an LTI course invite for validity, if valid, adds user to coursefindMatchingUserAndCourse
- uses the LTI launch parameters to find a) a matching user, and b) a matching course, if possible.extractCourseId
- uses the LTI launch parameters and finds the course ID from the platformWhat else has changed?
User
class incommon/index.ts
now maps to the enum.UBCOloginParam
to genericLoginParam
(just for convenience, it's not even UBCO-specific - in fact, it's less UBCO-specific than the shibboleth login!!!)common/index.ts
in general for placements, added class-transformer decorators to the LMS types/classestypings/*.ts
tocommon/index.ts
so the backend and frontend declarations are fully alignedregistration/page.tsx
extrapolated to optionally take in anoid
URL parameter, rather than relying on the value in localStoragecoursesSection.tsx
modified to support the needed behaviour within the LTI pagesapi/cookieApi.ts
renamed toapi/cookie-utils.ts
and modified for LTI-specific behavioursapi/index.ts
auth
routes here as a result of removingapi/authApi.ts
profile.index
->profile.getUser
, with original implementation that was inuserApi.ts
profile.index
->profile.fullResponse
,profile.getUser
but returns full response objectmail
added,mail.resendVerificationCode
added (result of removingapi/mailAPI.ts
)fetchUserDetails
(reused to supply profile to UserInfoContext) extracted/addedmiddleware.ts
auth.controller.ts
methods extracted toauth.service.ts
for use with other authentication controllers, likelti-auth.controller.ts
auth.service.ts
now contains additional general-purpose authentication methodsbootstrap.ts
modified for LTI usage{ frameguard: false, contentSecurityPolicy: false }
- prevents issues with displaying app in iframeLTI_SECRET_KEY
as the key used to decrypt the cookies (cookies written along the LTI routes will also be signed with this key)addGlobalsToApp
function take test as an argument as the Regex used for the custom middlewares would be far too complicated (and unrealistic to use) for tests/api/v1/
prefix, complicates things, can't make that optionalJWTAuthGuard
updated with customhandleRequest
lmsIntegration.controller.ts
POST org/:oid/upsert
->upsertOrganizationLMSIntegration
POST course/:courseId/upsert
POST :courseId/test
lmsIntegration.service.ts
upsertOrganizationLMSIntegration
updateCourseLMSIntegration
testConnection
getAPICourses
Adapter.getUserCourses
JwtStrategy
auth_token
(default) or if it is null, thelti_auth_token
, rather than justauth_token
or nulllogin.controller.ts
login.service.ts
I_AM_A_TEAPOT
logout
- now tries to clear bothauth_token
andlti_auth_token
mail.controller.ts
resendRegistrationToken
adjusted.profile.controller.ts
get
profile returns restrictPaths as well.user-token.entity.ts
created_at
-> createdAt, CreateDateColumn withtimestamp with timezone type
, Date type in TSexpires_at
-> expiresIn,bigint
column that aligned with epoch millis tobigint
column that represents the number of seconds until the token expires.What's been removed?
GOOGLE_REDIRECT_URI
- we just compute this now since we have multiple redirect URIs (default, LTI) and other SSO providers will follow similar URIsapi/authApi.ts
file was removed, methods extracted to centralindex.ts
fileapi/mailAPI.ts
file removed, ...api/userAPI.ts
file removed, ...api/organizationAPI.ts
almost entirely scrapped with methods extractedgetOrganization
remains... might remove this in this PR as welladmin.command.ts
command fileadmin-user.entity.ts
fileCloses #308, #389
Type of change
yarn install
server/.env
server/postgres.env
server/.env
server/postgres.env
Production Environment Changes
How Has This Been Tested?
I wrote a lot of tests. A LOT.
Checklist: