Class: AtomicLti::Lti
- Inherits:
-
Object
- Object
- AtomicLti::Lti
- Defined in:
- app/lib/atomic_lti/lti.rb
Class Method Summary collapse
- .client_id(decoded_token) ⇒ Object
- .matching_uri?(target, actual, ignore_host:) ⇒ Boolean
- .valid_version?(decoded_token) ⇒ Boolean
- .validate!(decoded_token, requested_target_link_uri = nil, validate_target_link_url = false) ⇒ Object
- .validate_resource_link_request(decoded_token, requested_target_link_uri = nil, validate_target_link_url = false) ⇒ Object
Class Method Details
.client_id(decoded_token) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 |
# File 'app/lib/atomic_lti/lti.rb', line 117 def self.client_id(decoded_token) if decoded_token["aud"]&.is_a?(Array) if decoded_token["aud"].length > 1 decoded_token["azp"] else decoded_token["aud"][0] end else decoded_token["aud"] end end |
.matching_uri?(target, actual, ignore_host:) ⇒ Boolean
129 130 131 132 133 134 135 136 137 138 |
# File 'app/lib/atomic_lti/lti.rb', line 129 def self.matching_uri?(target, actual, ignore_host:) t = URI.parse(target) a = URI.parse(actual) t.scheme == a.scheme && t.path == a.path && t.query == a.query && t.fragment == a.fragment && (ignore_host || t.host == a.host) end |
.valid_version?(decoded_token) ⇒ Boolean
109 110 111 112 113 114 115 |
# File 'app/lib/atomic_lti/lti.rb', line 109 def self.valid_version?(decoded_token) if decoded_token[AtomicLti::Definitions::LTI_VERSION] decoded_token[AtomicLti::Definitions::LTI_VERSION].starts_with?("1.3") else false end end |
.validate!(decoded_token, requested_target_link_uri = nil, validate_target_link_url = false) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'app/lib/atomic_lti/lti.rb', line 4 def self.validate!(decoded_token, requested_target_link_uri = nil, validate_target_link_url = false) if decoded_token.blank? raise AtomicLti::Exceptions::InvalidLTIToken end errors = [] if decoded_token["iss"].blank? errors.push("LTI token is missing required field iss") end if decoded_token["sub"].blank? && !AtomicLti.allow_anonymous_user errors.push("LTI token is missing required field sub") end if decoded_token["aud"].blank? errors.push("LTI token is missing required field aud") end if decoded_token["aud"].is_a?(Array) && decoded_token["aud"].length > 1 # OpenID Connect spec specifies the AZP should exist and be an AUD if decoded_token["azp"].blank? errors.push("LTI token has multiple aud and is missing required field azp") elsif decoded_token["aud"].exclude?(decoded_token["azp"]) errors.push("LTI token azp is not one of the aud's") end end if decoded_token[AtomicLti::Definitions::DEPLOYMENT_ID].blank? errors.push( "LTI token is missing required field #{AtomicLti::Definitions::DEPLOYMENT_ID}" ) end if decoded_token[AtomicLti::Definitions::MESSAGE_TYPE].blank? errors.push( "LTI token is missing required claim #{AtomicLti::Definitions::MESSAGE_TYPE}" ) end if decoded_token[AtomicLti::Definitions::MESSAGE_TYPE] === "LtiResourceLinkRequest" errors.concat(validate_resource_link_request(decoded_token, requested_target_link_uri, validate_target_link_url)) end if decoded_token[AtomicLti::Definitions::ROLES_CLAIM].blank? errors.push( "LTI token is missing required claim #{AtomicLti::Definitions::ROLES_CLAIM}" ) end roles = decoded_token[AtomicLti::Definitions::ROLES_CLAIM] if AtomicLti.role_enforcement_mode == AtomicLti::RoleEnforcementMode::STRICT && roles.is_a?(Array) && !roles.empty? invalid_roles = roles - AtomicLti::Definitions::ROLES if invalid_roles.length == roles.length errors.push("LTI token has invalid roles: #{invalid_roles.join(", ")}") end end if errors.length > 0 raise AtomicLti::Exceptions::InvalidLTIToken.new(errors.join(" ")) end if decoded_token[AtomicLti::Definitions::LTI_VERSION].blank? raise AtomicLti::Exceptions::NoLTIVersion end raise AtomicLti::Exceptions::InvalidLTIVersion unless valid_version?(decoded_token) true end |
.validate_resource_link_request(decoded_token, requested_target_link_uri = nil, validate_target_link_url = false) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/lib/atomic_lti/lti.rb', line 75 def self.validate_resource_link_request(decoded_token, requested_target_link_uri = nil, validate_target_link_url = false) errors = [] if decoded_token[AtomicLti::Definitions::TARGET_LINK_URI_CLAIM].blank? errors.push( "LTI token is missing required claim #{AtomicLti::Definitions::TARGET_LINK_URI_CLAIM}", ) end # Validate that we are at the target_link_uri target_link_uri = decoded_token[AtomicLti::Definitions::TARGET_LINK_URI_CLAIM] if validate_target_link_url && !matching_uri?(target_link_uri, requested_target_link_uri, ignore_host: AtomicLti.update_target_link_host) errors.push( "LTI token target link uri '#{target_link_uri}' doesn't match url '#{requested_target_link_uri}'", ) end if decoded_token[AtomicLti::Definitions::RESOURCE_LINK_CLAIM].blank? errors.push( "LTI token is missing required claim #{AtomicLti::Definitions::RESOURCE_LINK_CLAIM}", ) end if decoded_token.dig(AtomicLti::Definitions::RESOURCE_LINK_CLAIM, "id").blank? errors.push( "LTI token is missing required field id from the claim #{AtomicLti::Definitions::RESOURCE_LINK_CLAIM}", ) end errors end |