diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 8e7f21e..afb0c1e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,7 +1,4 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Java CI with Maven +name: Build with Maven on: push: @@ -11,16 +8,13 @@ on: jobs: build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 with: - java-version: '11' + java-version-file: .java-version distribution: 'temurin' cache: maven - name: Build with Maven - run: mvn -B package --file pom.xml + run: mvn -B package diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..8e2afd3 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +17 \ No newline at end of file diff --git a/README.md b/README.md index 2a77408..8dc13dd 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Go to you account and add a LTI Developer Key, fill in the following: ## Local Canvas Setup -Open the file `config/application.properties` and add these properties: +Open the file `config/application.properties` and add these properties or copy `config/application-example.properties`: spring.security.oauth2.client.registration.canvas.client-id=1234 spring.security.oauth2.client.registration.canvas.client-secret=secret @@ -55,7 +55,6 @@ Open the file `config/application.properties` and add these properties: spring.security.oauth2.client.provider.canvas.user-name-attribute=sub * replace the client-id value (1234) with the ID of the LTI Developer Key you have created. - * replace the client-secret value (secret) with the LTI Developer Key secret. * you can update the URIs to point to the canvas instance you are using, but it works fine using the canvas.instructure.com ## LTI Reference Implementation Setup diff --git a/config/application-example.properties b/config/application-example.properties new file mode 100644 index 0000000..6c8f07b --- /dev/null +++ b/config/application-example.properties @@ -0,0 +1,18 @@ +# Copy this file to `application.properties` and customise + +# Set this to the client ID of the key +spring.security.oauth2.client.registration.canvas.client-id= +# This isn't used for the implicit OAuth grant so it's value doesn't matter +spring.security.oauth2.client.registration.canvas.client-secret=secret +# This must be implicit +spring.security.oauth2.client.registration.canvas.authorization-grant-type=implicit +# This must be openid +spring.security.oauth2.client.registration.canvas.scope=openid +# Unless you remap the login path this should be the same +spring.security.oauth2.client.registration.canvas.redirect-uri={baseUrl}/lti/login + +# These are example values for a production Canvas instance. +spring.security.oauth2.client.provider.canvas.authorization-uri=https://canvas.instructure.com/api/lti/authorize_redirect +spring.security.oauth2.client.provider.canvas.token-uri=https://canvas.instructure.com/login/oauth2/token +spring.security.oauth2.client.provider.canvas.jwk-set-uri=https://canvas.instructure.com/api/lti/security/jwks +spring.security.oauth2.client.provider.canvas.user-name-attribute=sub \ No newline at end of file diff --git a/pom.xml b/pom.xml index c4b9e48..27e1596 100644 --- a/pom.xml +++ b/pom.xml @@ -6,24 +6,24 @@ uk.ac.ox.ctl spring-security-lti13-demo - 1.0-SNAPSHOT + 2.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent - 2.5.4 + 3.2.5 - 1.8 + 17 uk.ac.ox.ctl spring-security-lti13 - 0.0.4 + 0.2.0 org.springframework.boot @@ -41,6 +41,10 @@ org.springframework.boot spring-boot-starter-validation + + org.springframework.boot + spring-boot-starter-mustache + diff --git a/src/main/java/uk/ac/ox/ctl/lti13/demo/WebSecurityConfig.java b/src/main/java/uk/ac/ox/ctl/lti13/demo/WebSecurityConfig.java index 2075142..b0e4800 100644 --- a/src/main/java/uk/ac/ox/ctl/lti13/demo/WebSecurityConfig.java +++ b/src/main/java/uk/ac/ox/ctl/lti13/demo/WebSecurityConfig.java @@ -1,23 +1,29 @@ package uk.ac.ox.ctl.lti13.demo; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import uk.ac.ox.ctl.lti13.Lti13Configurer; @Configuration @EnableWebSecurity -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { +public class WebSecurityConfig { - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests() - .antMatchers("/", "/resources/**", "/favicon.ico", "/config.json", "/.well-known/jwks.json") - .permitAll() - ; + @Bean + protected SecurityFilterChain configure(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(authorizeHttpRequestsCustomizer -> { + authorizeHttpRequestsCustomizer.requestMatchers( + "/", "/index.html", "/resources/**", "/favicon.ico", + "/config.json", "/.well-known/jwks.json", "/error").permitAll(); + authorizeHttpRequestsCustomizer.anyRequest().authenticated(); + }); Lti13Configurer lti13Configurer = new Lti13Configurer(); + lti13Configurer.setSecurityContextRepository(new HttpSessionSecurityContextRepository()); http.apply(lti13Configurer); + return http.build(); } } diff --git a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/Config13Controller.java b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/Config13Controller.java index d726e25..8be4254 100644 --- a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/Config13Controller.java +++ b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/Config13Controller.java @@ -1,13 +1,13 @@ package uk.ac.ox.ctl.lti13.demo.controller; import com.nimbusds.jose.jwk.JWKSet; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import uk.ac.ox.ctl.lti13.demo.controller.lti13.*; -import javax.servlet.http.HttpServletRequest; import java.util.*; import static uk.ac.ox.ctl.lti13.demo.controller.lti13.Canvas13Extension.INSTRUCTURE; diff --git a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/DemoController.java b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/DemoController.java new file mode 100644 index 0000000..51672d9 --- /dev/null +++ b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/DemoController.java @@ -0,0 +1,27 @@ +package uk.ac.ox.ctl.lti13.demo.controller; + +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.servlet.ModelAndView; + +import java.util.HashMap; +import java.util.Map; + +/** + * This is a simple controller to demonstrate how you can use data from the LTI launch. + */ +@Controller +public class DemoController { + + @GetMapping("/demo") + public ModelAndView index( + @AuthenticationPrincipal(expression = "claims['sub']") String sub, + @AuthenticationPrincipal(expression = "claims['name']") String name + ) { + Map model = new HashMap<>(); + model.put("sub", sub); + model.put("name", name); + return new ModelAndView("demo", model); + } +} diff --git a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13Config.java b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13Config.java index 2836a21..cfe053b 100644 --- a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13Config.java +++ b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13Config.java @@ -2,9 +2,9 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.Collection; import java.util.Map; diff --git a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13ConfigBuilder.java b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13ConfigBuilder.java index 04d5bb6..90438b8 100644 --- a/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13ConfigBuilder.java +++ b/src/main/java/uk/ac/ox/ctl/lti13/demo/controller/lti13/Lti13ConfigBuilder.java @@ -1,7 +1,8 @@ package uk.ac.ox.ctl.lti13.demo.controller.lti13; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + import java.util.Collection; import java.util.Map; diff --git a/src/main/java/uk/ac/ox/ctl/lti13/demo/utils/SameSiteCookeValve.java b/src/main/java/uk/ac/ox/ctl/lti13/demo/utils/SameSiteCookeValve.java index 9947929..edd58ed 100644 --- a/src/main/java/uk/ac/ox/ctl/lti13/demo/utils/SameSiteCookeValve.java +++ b/src/main/java/uk/ac/ox/ctl/lti13/demo/utils/SameSiteCookeValve.java @@ -1,12 +1,12 @@ package uk.ac.ox.ctl.lti13.demo.utils; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.util.SessionConfig; import org.apache.catalina.valves.ValveBase; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; import java.io.IOException; import java.util.Collection; diff --git a/src/main/resources/templates/demo.mustache b/src/main/resources/templates/demo.mustache new file mode 100644 index 0000000..e390b10 --- /dev/null +++ b/src/main/resources/templates/demo.mustache @@ -0,0 +1,19 @@ + + + + Demo Application + + +

Demo

+

+ Hello {{name}} (sub:{{sub}}) +

+

+ This reloads the current document to check that HTTP sessions are correctly setup and the user remains + authenticated.
+ +

+ + \ No newline at end of file