Differences Between: [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 3 namespace Packback\Lti1p3; 4 5 use Packback\Lti1p3\Interfaces\ICache; 6 use Packback\Lti1p3\Interfaces\ICookie; 7 use Packback\Lti1p3\Interfaces\IDatabase; 8 9 class LtiOidcLogin 10 { 11 public const COOKIE_PREFIX = 'lti1p3_'; 12 public const ERROR_MSG_LAUNCH_URL = 'No launch URL configured'; 13 public const ERROR_MSG_ISSUER = 'Could not find issuer'; 14 public const ERROR_MSG_LOGIN_HINT = 'Could not find login hint'; 15 private $db; 16 private $cache; 17 private $cookie; 18 19 /** 20 * Constructor. 21 * 22 * @param IDatabase $database Instance of the Database interface used for looking up registrations and deployments 23 * @param ICache $cache instance of the Cache interface used to loading and storing launches 24 * @param ICookie $cookie instance of the Cookie interface used to set and read cookies 25 */ 26 public function __construct(IDatabase $database, ICache $cache = null, ICookie $cookie = null) 27 { 28 $this->db = $database; 29 $this->cache = $cache; 30 $this->cookie = $cookie; 31 } 32 33 /** 34 * Static function to allow for method chaining without having to assign to a variable first. 35 */ 36 public static function new(IDatabase $database, ICache $cache = null, ICookie $cookie = null) 37 { 38 return new LtiOidcLogin($database, $cache, $cookie); 39 } 40 41 /** 42 * Calculate the redirect location to return to based on an OIDC third party initiated login request. 43 * 44 * @param string $launch_url URL to redirect back to after the OIDC login. This URL must match exactly a URL white listed in the platform. 45 * @param array|string $request An array of request parameters. If not set will default to $_REQUEST. 46 * @return Redirect returns a redirect object containing the fully formed OIDC login URL 47 */ 48 public function doOidcLoginRedirect($launch_url, array $request = null) 49 { 50 if ($request === null) { 51 $request = $_REQUEST; 52 } 53 54 if (empty($launch_url)) { 55 throw new OidcException(static::ERROR_MSG_LAUNCH_URL, 1); 56 } 57 58 // Validate Request Data. 59 $registration = $this->validateOidcLogin($request); 60 61 /* 62 * Build OIDC Auth Response. 63 */ 64 65 // Generate State. 66 // Set cookie (short lived) 67 $state = static::secureRandomString('state-'); 68 $this->cookie->setCookie(static::COOKIE_PREFIX.$state, $state, 60); 69 70 // Generate Nonce. 71 $nonce = static::secureRandomString('nonce-'); 72 $this->cache->cacheNonce($nonce, $state); 73 74 // Build Response. 75 $auth_params = [ 76 'scope' => 'openid', // OIDC Scope. 77 'response_type' => 'id_token', // OIDC response is always an id token. 78 'response_mode' => 'form_post', // OIDC response is always a form post. 79 'prompt' => 'none', // Don't prompt user on redirect. 80 'client_id' => $registration->getClientId(), // Registered client id. 81 'redirect_uri' => $launch_url, // URL to return to after login. 82 'state' => $state, // State to identify browser session. 83 'nonce' => $nonce, // Prevent replay attacks. 84 'login_hint' => $request['login_hint'], // Login hint to identify platform session. 85 ]; 86 87 // Pass back LTI message hint if we have it. 88 if (isset($request['lti_message_hint'])) { 89 // LTI message hint to identify LTI context within the platform. 90 $auth_params['lti_message_hint'] = $request['lti_message_hint']; 91 } 92 93 $auth_login_return_url = $registration->getAuthLoginUrl().'?'.http_build_query($auth_params, '', '&'); 94 95 // Return auth redirect. 96 return new Redirect($auth_login_return_url, http_build_query($request, '', '&')); 97 } 98 99 public function validateOidcLogin($request) 100 { 101 // Validate Issuer. 102 if (empty($request['iss'])) { 103 throw new OidcException(static::ERROR_MSG_ISSUER, 1); 104 } 105 106 // Validate Login Hint. 107 if (empty($request['login_hint'])) { 108 throw new OidcException(static::ERROR_MSG_LOGIN_HINT, 1); 109 } 110 111 // Fetch Registration Details. 112 $clientId = $request['client_id'] ?? null; 113 $registration = $this->db->findRegistrationByIssuer($request['iss'], $clientId); 114 115 // Check we got something. 116 if (empty($registration)) { 117 $errorMsg = LtiMessageLaunch::getMissingRegistrationErrorMsg($request['iss'], $clientId); 118 119 throw new OidcException($errorMsg, 1); 120 } 121 122 // Return Registration. 123 return $registration; 124 } 125 126 public static function secureRandomString(string $prefix = ''): string 127 { 128 return $prefix.hash('sha256', random_bytes(64)); 129 } 130 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body