atomic_lti/
dynamic_registration.rs

1use self::{platform_configuration::PlatformConfiguration, tool_configuration::ToolConfiguration};
2use crate::{errors::DynamicRegistrationError, request::send_request, url::parse_host};
3use reqwest::header;
4use serde::Deserialize;
5
6pub mod lti_message;
7pub mod platform_configuration;
8pub mod tool_configuration;
9
10// Define a structure for the dynamic registration request params
11// sent by the platform to the tool to initialize the dynamic registration process
12#[derive(Deserialize, Clone, Debug)]
13pub struct DynamicRegistrationParams {
14  pub openid_configuration: String,
15  pub registration_token: Option<String>,
16}
17
18// Define a structure for the dynamic registration request
19#[derive(Deserialize, Clone, Debug)]
20pub struct DynamicRegistrationFinishParams {
21  pub registration_endpoint: String,
22  pub registration_token: Option<String>,
23  pub product_family_code: Option<String>,
24}
25
26pub fn validate_platform_config(
27  platform_config: &PlatformConfiguration,
28  openid_configuration_url: &str,
29) -> Result<bool, DynamicRegistrationError> {
30  // The issuer domain must match the openid-configuration URL domain
31  let original_host = parse_host(openid_configuration_url)?;
32  let provided_host = parse_host(&platform_config.issuer)?;
33
34  if original_host != provided_host {
35    return Err(DynamicRegistrationError::InvalidConfig(
36      "The issuer domain must match the openid-configuration URL domain".to_string(),
37    ));
38  }
39
40  Ok(true)
41}
42
43pub async fn request_platform_config(
44  openid_configuration_url: &str,
45) -> Result<PlatformConfiguration, DynamicRegistrationError> {
46  let client = reqwest::Client::new();
47  let request = client
48    .get(openid_configuration_url)
49    .header(header::ACCEPT, "application/json");
50  let body = send_request(request).await?;
51  let platform_config: PlatformConfiguration = serde_json::from_str(&body)
52    .map_err(|e| DynamicRegistrationError::RequestFailed(e.to_string()))?;
53
54  Ok(platform_config)
55}
56
57// Send a request to the platform to register the tool
58pub async fn register_tool(
59  registration_endpoint: &str,
60  registration_token: &str,
61  client_registration_request: &ToolConfiguration,
62) -> Result<ToolConfiguration, DynamicRegistrationError> {
63  let json = serde_json::to_string(&client_registration_request)
64    .map_err(|e| DynamicRegistrationError::RequestFailed(e.to_string()))?;
65  let client: reqwest::Client = reqwest::Client::new();
66  let mut request = client
67    .post(registration_endpoint)
68    .header(header::CONTENT_TYPE, "application/json")
69    .header(header::ACCEPT, "application/json")
70    .body(json);
71
72  if !registration_token.is_empty() {
73    request = request.header(
74      header::AUTHORIZATION,
75      format!("Bearer {}", registration_token),
76    );
77  }
78
79  let body = send_request(request).await?;
80  let platform_response: ToolConfiguration = serde_json::from_str(&body)
81    .map_err(|e| DynamicRegistrationError::RequestFailed(e.to_string()))?;
82
83  Ok(platform_response)
84}