Skip to content

Commit

Permalink
change authorization grant type to implicit and refactor classes to r…
Browse files Browse the repository at this point in the history
…ecords
  • Loading branch information
krusche committed Jan 2, 2025
1 parent b26821c commit e67389c
Show file tree
Hide file tree
Showing 16 changed files with 109 additions and 279 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import de.tum.cit.aet.artemis.core.exception.LtiEmailAlreadyInUseException;
import de.tum.cit.aet.artemis.core.security.SecurityUtils;
import de.tum.cit.aet.artemis.lti.dto.Claims;
import de.tum.cit.aet.artemis.lti.dto.LtiAuthenticationResponse;
import de.tum.cit.aet.artemis.lti.dto.Lti13AuthenticationResponse;
import de.tum.cit.aet.artemis.lti.service.Lti13Service;
import uk.ac.ox.ctl.lti13.security.oauth2.client.lti.authentication.OidcAuthenticationToken;
import uk.ac.ox.ctl.lti13.security.oauth2.client.lti.web.OAuth2LoginAuthenticationFilter;
Expand Down Expand Up @@ -125,7 +125,7 @@ private void writeResponse(String targetLinkUri, OidcIdToken ltiIdToken, String
log.info("User is authenticated, building LTI response");
lti13Service.buildLtiResponse(uriBuilder, response);
}
LtiAuthenticationResponse jsonResponse = new LtiAuthenticationResponse(uriBuilder.build().toUriString(), ltiIdToken.getTokenValue(), clientRegistrationId);
Lti13AuthenticationResponse jsonResponse = new Lti13AuthenticationResponse(uriBuilder.build().toUriString(), ltiIdToken.getTokenValue(), clientRegistrationId);

response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/tum/cit/aet/artemis/lti/dto/Claims.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.tum.cit.aet.artemis.lti.dto;

public class Claims extends uk.ac.ox.ctl.lti13.lti.Claims {
public final class Claims extends uk.ac.ox.ctl.lti13.lti.Claims {

/**
* Constant for LTI Assignment and Grade Services (AGS) claim endpoint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@

import org.springframework.security.oauth2.core.oidc.OidcIdToken;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
* A wrapper record for an LTI 1.3 Assignment and Grading Services Claim. We support the Score Publishing Service in order to transmit scores.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record Lti13AgsClaim(List<String> scope, String lineItem) {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package de.tum.cit.aet.artemis.lti.dto;

import com.fasterxml.jackson.annotation.JsonInclude;

/**
* Holds LTI authentication response details.
*
* @param targetLinkUri URI targeted in the LTI process.
* @param ltiIdToken LTI service provided ID token.
* @param clientRegistrationId Client's registration ID with LTI service.
*/
public record LtiAuthenticationResponse(String targetLinkUri, String ltiIdToken, String clientRegistrationId) {
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record Lti13AuthenticationResponse(String targetLinkUri, String ltiIdToken, String clientRegistrationId) {
}
Original file line number Diff line number Diff line change
@@ -1,276 +1,20 @@
package de.tum.cit.aet.artemis.lti.dto;

import java.util.Arrays;
import java.util.List;

import org.springframework.security.oauth2.core.AuthorizationGrantType;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import de.tum.cit.aet.artemis.lti.config.CustomLti13Configurer;

/**
* Represents the client registration details for an LTI 1.3 integration.
* This class encapsulates information required for LTI 1.3 client registration,
* including response types, grant types, redirect URIs, and tool configuration.
*/
public class Lti13ClientRegistration {

@JsonProperty("client_id")
private String clientId;

@JsonProperty("response_types")
private List<String> responseTypes;

@JsonProperty("grant_types")
private List<String> grantTypes;

@JsonProperty("initiate_login_uri")
private String initiateLoginUri;

@JsonProperty("redirect_uris")
private List<String> redirectUris;

@JsonProperty("client_name")
private String clientName;

@JsonProperty("jwks_uri")
private String jwksUri;

@JsonProperty("logo_uri")
private String logoUri;

@JsonProperty("token_endpoint_auth_method")
private String tokenEndpointAuthMethod;

private String scope;

@JsonProperty("https://purl.imsglobal.org/spec/lti-tool-configuration")
private Lti13ToolConfiguration lti13ToolConfiguration;

/**
* Default constructor necessary for conversion.
*/
public Lti13ClientRegistration() { // Necessary for conversion
}

/**
* Constructs a new Lti13ClientRegistration with specified server URL and client registration ID.
* Initializes various properties such as grant types, response types, and tool configurations.
*
* @param serverUrl The server URL for LTI configuration.
* @param clientRegistrationId The client registration ID for LTI configuration.
*/
public Lti13ClientRegistration(String serverUrl, String clientRegistrationId) {
this.setGrantTypes(Arrays.asList(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue(), AuthorizationGrantType.AUTHORIZATION_CODE.getValue()));
this.setResponseTypes(List.of("id_token"));
this.setClientName("Artemis - " + serverUrl);
this.setTokenEndpointAuthMethod("private_key_jwt");
this.setScope(String.join(" ", List.of(Scopes.AGS_SCORE, Scopes.AGS_RESULT)));
this.setRedirectUris(List.of(serverUrl + "/" + CustomLti13Configurer.LTI13_LOGIN_REDIRECT_PROXY_PATH));
this.setInitiateLoginUri(serverUrl + "/" + CustomLti13Configurer.LTI13_LOGIN_INITIATION_PATH + "/" + clientRegistrationId);
this.setJwksUri(serverUrl + "/.well-known/jwks.json");
this.setLogoUri(serverUrl + "/public/images/logo.png");

Lti13ToolConfiguration toolConfiguration = getLti13ToolConfiguration(serverUrl);
this.setLti13ToolConfiguration(toolConfiguration);
}

private static Lti13ToolConfiguration getLti13ToolConfiguration(String serverUrl) {
Lti13ToolConfiguration toolConfiguration = new Lti13ToolConfiguration();

// Extracting the domain from the server URL
String[] urlParts = serverUrl.split("://");
String domain = "";
if (urlParts.length >= 1) {
domain = urlParts[1]; // Domain cannot include protocol
}
toolConfiguration.setDomain(domain);
toolConfiguration.setTargetLinkUri(serverUrl + "/courses");
toolConfiguration.setDescription("Artemis: Interactive Learning with Individual Feedback");
toolConfiguration.setClaims(Arrays.asList("iss", "email", "sub", "name", "given_name", "family_name"));
Message deepLinkingMessage = new Message(CustomLti13Configurer.LTI13_DEEPLINK_MESSAGE_REQUEST, serverUrl + "/" + CustomLti13Configurer.LTI13_DEEPLINK_REDIRECT_PATH);
toolConfiguration.setMessages(List.of(deepLinkingMessage));
return toolConfiguration;
}

public String getClientId() {
return clientId;
}

public void setClientId(String clientId) {
this.clientId = clientId;
}

public List<String> getResponseTypes() {
return responseTypes;
}

public void setResponseTypes(List<String> responseTypes) {
this.responseTypes = responseTypes;
}

public List<String> getGrantTypes() {
return grantTypes;
}

public void setGrantTypes(List<String> grantTypes) {
this.grantTypes = grantTypes;
}

public String getInitiateLoginUri() {
return initiateLoginUri;
}

public void setInitiateLoginUri(String initiateLoginUri) {
this.initiateLoginUri = initiateLoginUri;
}

public List<String> getRedirectUris() {
return redirectUris;
}

public void setRedirectUris(List<String> redirectUris) {
this.redirectUris = redirectUris;
}

public String getClientName() {
return clientName;
}

public void setClientName(String clientName) {
this.clientName = clientName;
}

public String getJwksUri() {
return jwksUri;
}

public void setJwksUri(String jwksUri) {
this.jwksUri = jwksUri;
}

public String getLogoUri() {
return logoUri;
}

public void setLogoUri(String logoUri) {
this.logoUri = logoUri;
}

public String getTokenEndpointAuthMethod() {
return tokenEndpointAuthMethod;
}

public void setTokenEndpointAuthMethod(String tokenEndpointAuthMethod) {
this.tokenEndpointAuthMethod = tokenEndpointAuthMethod;
}

public String getScope() {
return scope;
}

public void setScope(String scope) {
this.scope = scope;
}

public Lti13ToolConfiguration getLti13ToolConfiguration() {
return lti13ToolConfiguration;
}

public void setLti13ToolConfiguration(Lti13ToolConfiguration lti13ToolConfiguration) {
this.lti13ToolConfiguration = lti13ToolConfiguration;
}

/**
* Inner class representing the LTI 1.3 tool configuration.
*/
public static class Lti13ToolConfiguration {

private String domain;

@JsonProperty("target_link_uri")
private String targetLinkUri;

private String description;

private List<Message> messages;

private List<String> claims;

public String getDomain() {
return domain;
}

public void setDomain(String domain) {
this.domain = domain;
}

public String getTargetLinkUri() {
return targetLinkUri;
}

public void setTargetLinkUri(String targetLinkUri) {
this.targetLinkUri = targetLinkUri;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public List<Message> getMessages() {
return messages;
}

public void setMessages(List<Message> messages) {
this.messages = messages;
}

public List<String> getClaims() {
return claims;
}

public void setClaims(List<String> claims) {
this.claims = claims;
}
}

/**
* Inner class representing a message in LTI 1.3 tool configuration.
*/
public static class Message {

private String type;

@JsonProperty("target_link_uri")
private String targetLinkUri;

public Message() {// Necessary for conversion
}

public Message(String type, String targetLinkUri) {
this.type = type;
this.targetLinkUri = targetLinkUri;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getTargetLinkUri() {
return targetLinkUri;
}
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record Lti13ClientRegistration(@JsonProperty("client_id") String clientId, @JsonProperty("response_types") List<String> responseTypes,
@JsonProperty("grant_types") List<String> grantTypes, @JsonProperty("initiate_login_uri") String initiateLoginUri, @JsonProperty("redirect_uris") List<String> redirectUris,
@JsonProperty("client_name") String clientName, @JsonProperty("jwks_uri") String jwksUri, @JsonProperty("logo_uri") String logoUri,
@JsonProperty("token_endpoint_auth_method") String tokenEndpointAuthMethod, String scope,
@JsonProperty("https://purl.imsglobal.org/spec/lti-tool-configuration") Lti13ToolConfiguration lti13ToolConfiguration) {

public void setTargetLinkUri(String targetLinkUri) {
this.targetLinkUri = targetLinkUri;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package de.tum.cit.aet.artemis.lti.dto;

import java.util.Arrays;
import java.util.List;

import org.springframework.security.oauth2.core.AuthorizationGrantType;

import de.tum.cit.aet.artemis.lti.config.CustomLti13Configurer;
import uk.ac.ox.ctl.lti13.security.oauth2.client.lti.web.LTIAuthorizationGrantType;

public class Lti13ClientRegistrationFactory {

/**
* Constructs a new Lti13ClientRegistration with specified server URL and client registration ID.
* Initializes various properties such as grant types, response types, and tool configurations.
*
* @param serverUrl The server URL for LTI configuration.
* @param clientRegistrationId The client registration ID for LTI configuration.
*/
public static Lti13ClientRegistration createRegistration(String serverUrl, String clientRegistrationId) {
var grantTypes = Arrays.asList(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue(), LTIAuthorizationGrantType.IMPLICIT.getValue());
var responseTypes = List.of("id_token");
var clientName = "Artemis - " + serverUrl;
var tokenEndpointAuthMethod = "private_key_jwt";
var scope = String.join(" ", List.of(Scopes.AGS_SCORE, Scopes.AGS_RESULT));
var redirectUris = List.of(serverUrl + "/" + CustomLti13Configurer.LTI13_LOGIN_REDIRECT_PROXY_PATH);
var initiateLoginUri = serverUrl + "/" + CustomLti13Configurer.LTI13_LOGIN_INITIATION_PATH + "/" + clientRegistrationId;
var jwksUri = serverUrl + "/.well-known/jwks.json";
var logoUri = serverUrl + "/public/images/logo.png";

return new Lti13ClientRegistration(clientRegistrationId, responseTypes, grantTypes, initiateLoginUri, redirectUris, clientName, jwksUri, logoUri, tokenEndpointAuthMethod,
scope, createLti13ToolConfiguration(serverUrl));
}

private static Lti13ToolConfiguration createLti13ToolConfiguration(String serverUrl) {

// Extracting the domain from the server URL
String[] urlParts = serverUrl.split("://");
String domain = "";
if (urlParts.length >= 1) {
domain = urlParts[1]; // Domain cannot include protocol
}
var claims = Arrays.asList("iss", "email", "sub", "name", "given_name", "family_name");
var deepLinkingMessage = new Lti13Message(CustomLti13Configurer.LTI13_DEEPLINK_MESSAGE_REQUEST, serverUrl + "/" + CustomLti13Configurer.LTI13_DEEPLINK_REDIRECT_PATH);
return new Lti13ToolConfiguration(domain, serverUrl + "/courses", "Artemis: Interactive Learning with Individual Feedback", List.of(deepLinkingMessage), claims);
}
}
Loading

0 comments on commit e67389c

Please sign in to comment.