├── .gitignore
├── src
├── main
│ ├── java
│ │ └── ltistarter
│ │ │ ├── model
│ │ │ ├── README.md
│ │ │ ├── BaseEntity.java
│ │ │ ├── ConfigEntity.java
│ │ │ ├── LmsPluginsEntity.java
│ │ │ ├── LtiMembershipEntity.java
│ │ │ ├── KeyRequestEntity.java
│ │ │ ├── SSOKeyEntity.java
│ │ │ ├── LtiServiceEntity.java
│ │ │ ├── LtiLinkEntity.java
│ │ │ ├── LtiContextEntity.java
│ │ │ ├── LtiKeyEntity.java
│ │ │ ├── ProfileEntity.java
│ │ │ ├── LtiUserEntity.java
│ │ │ └── LtiResultEntity.java
│ │ │ ├── oauth
│ │ │ ├── MyOAuthNonceServices.java
│ │ │ ├── ZeroLeggedOAuthProviderProcessingFilter.java
│ │ │ ├── MyOAuthProcessingFilterEntryPointImpl.java
│ │ │ ├── MyConsumerDetailsService.java
│ │ │ ├── OAuthUtils.java
│ │ │ └── MyOAuthAuthenticationHandler.java
│ │ │ ├── ServletInitializer.java
│ │ │ ├── controllers
│ │ │ ├── OpenController.java
│ │ │ ├── OAuthController.java
│ │ │ ├── BasicController.java
│ │ │ ├── HomeController.java
│ │ │ ├── LTI2Controller.java
│ │ │ ├── BaseController.java
│ │ │ ├── FormController.java
│ │ │ └── LTIController.java
│ │ │ ├── repository
│ │ │ ├── LtiLinkRepository.java
│ │ │ ├── LtiUserRepository.java
│ │ │ ├── LtiMembershipRepository.java
│ │ │ ├── ProfileRepository.java
│ │ │ ├── KeyRequestRepository.java
│ │ │ ├── LtiServiceRepository.java
│ │ │ ├── LtiResultRepository.java
│ │ │ ├── SSOKeyRepository.java
│ │ │ ├── LtiKeyRepository.java
│ │ │ ├── LtiContextRepository.java
│ │ │ ├── ConfigRepository.java
│ │ │ └── AllRepositories.java
│ │ │ ├── database
│ │ │ └── DatabasePreload.java
│ │ │ ├── lti
│ │ │ ├── LTIOAuthProviderProcessingFilter.java
│ │ │ ├── LTIConsumerDetailsService.java
│ │ │ └── LTIOAuthAuthenticationHandler.java
│ │ │ ├── config
│ │ │ └── ApplicationConfig.java
│ │ │ └── Application.java
│ └── resources
│ │ ├── logback-sample.xml
│ │ ├── templates
│ │ ├── login.html
│ │ ├── register.html
│ │ └── home.html
│ │ └── application.properties
└── test
│ └── java
│ └── ltistarter
│ ├── ApplicationTests.java
│ ├── BaseApplicationTest.java
│ ├── oauth
│ └── OAuth1LibraryTests.java
│ ├── controllers
│ └── AppControllersTest.java
│ └── lti
│ └── LTITests.java
├── LICENSE_HEADER
├── README.md
├── pom.xml
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | # editor (intellij)
3 | .idea/
4 | *.iml
5 | # Mobile Tools for Java (J2ME)
6 | .mtj.tmp/
7 | # Package Files #
8 | *.jar
9 | *.war
10 | *.ear
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/model/README.md:
--------------------------------------------------------------------------------
1 | WARNING
2 | =======
3 | These entities are from the tsugi project and should be kept in alignment with that project. Do not change these unless you really know what you are doing!
4 |
5 | tsugi (https://github.com/csev/tsugi) is a Multi-tenant learning tool hosting platform (http://www.tsugi.org)
6 |
7 | Aaron Zeckoski (azeckoski @ vt.edu)
8 |
--------------------------------------------------------------------------------
/LICENSE_HEADER:
--------------------------------------------------------------------------------
1 | Copyright ${year} ${holder}
2 | Licensed under the Apache License, Version 2.0 (the "License");
3 | you may not use this file except in compliance with the License.
4 | You may obtain a copy of the License at
5 |
6 | http://www.apache.org/licenses/LICENSE-2.0
7 |
8 | Unless required by applicable law or agreed to in writing, software
9 | distributed under the License is distributed on an "AS IS" BASIS,
10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | See the License for the specific language governing permissions and
12 | limitations under the License.
--------------------------------------------------------------------------------
/src/main/resources/logback-sample.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/oauth/MyOAuthNonceServices.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.oauth;
16 |
17 | import org.springframework.security.oauth.provider.nonce.InMemoryNonceServices;
18 | import org.springframework.stereotype.Component;
19 |
20 | @Component
21 | public class MyOAuthNonceServices extends InMemoryNonceServices {
22 |
23 | @Override
24 | public long getValidityWindowSeconds() {
25 | return 1200;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/ServletInitializer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter;
16 |
17 | import org.springframework.boot.builder.SpringApplicationBuilder;
18 | import org.springframework.boot.context.web.SpringBootServletInitializer;
19 |
20 | public class ServletInitializer extends SpringBootServletInitializer {
21 |
22 | @Override
23 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
24 | return application.sources(Application.class);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 | LTI Starter LOGIN
22 |
23 |
24 |
25 |
Simple login page
26 |
27 |
Wrong user or password
28 |
29 |
36 |
37 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/OpenController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import org.springframework.stereotype.Controller;
18 | import org.springframework.ui.Model;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 |
21 | import javax.servlet.http.HttpServletRequest;
22 | import java.security.Principal;
23 |
24 | /**
25 | * This controller should be protected by no auth (it is public access)
26 | */
27 | @Controller
28 | @RequestMapping("/open")
29 | public class OpenController extends BaseController {
30 |
31 | @RequestMapping({"", "/"})
32 | public String home(HttpServletRequest req, Principal principal, Model model) {
33 | commonModelPopulate(req, principal, model);
34 | model.addAttribute("name", "open (no auth)");
35 | return "home"; // name of the template
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/src/main/resources/templates/register.html:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
21 |
22 | LTI 2.0 Tool Registration
23 |
24 |
36 |
37 |
38 |
39 |
LTI 2.0 Registration
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiLinkRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiLinkEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | @Transactional
22 | public interface LtiLinkRepository extends PagingAndSortingRepository {
23 | /* Add custom crud methods here
24 | * If you need a custom implementation of the methods then see docs for steps to add it
25 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
26 | * Can also write a custom query like so:
27 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
28 | * List findAliased();
29 | * OR:
30 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
31 | * List findWithAlias(String alias);
32 | */
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiUserRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiUserEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | @Transactional
22 | public interface LtiUserRepository extends PagingAndSortingRepository {
23 | /* Add custom crud methods here
24 | * If you need a custom implementation of the methods then see docs for steps to add it
25 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
26 | * Can also write a custom query like so:
27 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
28 | * List findAliased();
29 | * OR:
30 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
31 | * List findWithAlias(String alias);
32 | */
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/OAuthController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import org.springframework.stereotype.Controller;
18 | import org.springframework.ui.Model;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 |
21 | import javax.servlet.http.HttpServletRequest;
22 | import java.security.Principal;
23 |
24 | /**
25 | * This controller should be protected by OAuth 1.0a (on the /oauth path)
26 | * Key "key" and secret "secret"
27 | */
28 | @Controller
29 | @RequestMapping("/oauth")
30 | public class OAuthController extends BaseController {
31 |
32 | @RequestMapping({"", "/"})
33 | public String home(HttpServletRequest req, Principal principal, Model model) {
34 | commonModelPopulate(req, principal, model);
35 | model.addAttribute("name", "oauth");
36 | req.getSession().setAttribute("login", "basic");
37 | return "home"; // name of the template
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiMembershipRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiMembershipEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | @Transactional
22 | public interface LtiMembershipRepository extends PagingAndSortingRepository {
23 | /* Add custom crud methods here
24 | * If you need a custom implementation of the methods then see docs for steps to add it
25 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
26 | * Can also write a custom query like so:
27 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
28 | * List findAliased();
29 | * OR:
30 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
31 | * List findWithAlias(String alias);
32 | */
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/BasicController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import org.springframework.stereotype.Controller;
18 | import org.springframework.ui.Model;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 |
21 | import javax.servlet.http.HttpServletRequest;
22 | import java.security.Principal;
23 |
24 | /**
25 | * This controller should be protected by basic auth authentication (on the /basic path)
26 | * Username and password controlled in application.properties
27 | */
28 | @Controller
29 | @RequestMapping("/basic")
30 | public class BasicController extends BaseController {
31 |
32 | @RequestMapping({"", "/"})
33 | public String home(HttpServletRequest req, Principal principal, Model model) {
34 | commonModelPopulate(req, principal, model);
35 | model.addAttribute("name", "basic");
36 | req.getSession().setAttribute("login", "basic");
37 | return "home"; // name of the template
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/ProfileRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.ProfileEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | @Transactional
22 | public interface ProfileRepository extends PagingAndSortingRepository {
23 | /* Add custom crud methods here
24 | * If you need a custom implementation of the methods then see docs for steps to add it
25 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
26 | * Can also write a custom query like so:
27 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
28 | * List findAliased();
29 | * OR:
30 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
31 | * List findWithAlias(String alias);
32 | */
33 |
34 | ProfileEntity findByProfileKey(String profileKey);
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/HomeController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import org.springframework.stereotype.Controller;
18 | import org.springframework.ui.Model;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 | import org.springframework.web.bind.annotation.RequestMethod;
21 |
22 | import javax.servlet.http.HttpServletRequest;
23 | import java.security.Principal;
24 |
25 | /**
26 | * This is the default home (i.e. root or "/") controller which should be wide open
27 | * (no security)
28 | */
29 | @Controller
30 | public class HomeController extends BaseController {
31 |
32 | @RequestMapping(method = RequestMethod.GET)
33 | public String index(HttpServletRequest req, Principal principal, Model model) {
34 | log.info("HOME: " + req);
35 | commonModelPopulate(req, principal, model);
36 | model.addAttribute("name", "HOME");
37 | counterService.increment("home");
38 | return "home"; // name of the template
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/KeyRequestRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.KeyRequestEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | @Transactional
22 | public interface KeyRequestRepository extends PagingAndSortingRepository {
23 | /* Add custom crud methods here
24 | * If you need a custom implementation of the methods then see docs for steps to add it
25 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
26 | * Can also write a custom query like so:
27 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
28 | * List findAliased();
29 | * OR:
30 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
31 | * List findWithAlias(String alias);
32 | */
33 |
34 | public KeyRequestEntity findByUser_UserId(long userId);
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/ltistarter/ApplicationTests.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter;
16 |
17 | import ltistarter.model.ConfigEntity;
18 | import ltistarter.repository.ConfigRepository;
19 | import org.junit.Test;
20 | import org.junit.runner.RunWith;
21 | import org.springframework.beans.factory.annotation.Autowired;
22 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
23 | import org.springframework.transaction.annotation.Transactional;
24 |
25 | import static org.junit.Assert.assertNotNull;
26 |
27 | @RunWith(SpringJUnit4ClassRunner.class)
28 | public class ApplicationTests extends BaseApplicationTest {
29 |
30 | @Autowired
31 | @SuppressWarnings({"SpringJavaAutowiredMembersInspection", "SpringJavaAutowiringInspection"})
32 | ConfigRepository configRepository;
33 |
34 | @Test
35 | @Transactional
36 | public void testConfig() {
37 | assertNotNull(applicationConfig);
38 | assertNotNull(configRepository);
39 | configRepository.save(new ConfigEntity("test.thing", "Value"));
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LTI 1 and 2 java starter app
2 | ============================
3 |
4 | IMS LTI 1 and 2 based starter (sample) application written using Java and Spring Boot
5 |
6 | The goal is to have a Java based web app which can serve as the basis (or starting point) for building a fully compliant LTI 1 or 2 based tool without having to manage the complexities of LTI 2 or come up with a strategy for handling the various types of data storage.
7 |
8 | Parts based on the data structures and code in tsugi (https://github.com/csev/tsugi) which is a Multi-tenant learning tool hosting platform (http://www.tsugi.org)
9 |
10 | Build
11 | -----
12 | This will produce a starter.war file in the *target* directory which can be placed into any standard servlet container.
13 |
14 | mvn install
15 |
16 | Quick Run
17 | ---------
18 | You can run the app in place to try it out without having to install and deploy a servlet container.
19 |
20 | mvn clean install spring-boot:run
21 |
22 | Then go to the following default URL:
23 |
24 | http://localhost:8080/
25 |
26 | You can access the H2 console for default in-memory DB (JDBC URL: **jdbc:h2:mem:AZ**, username: **sa**, password: *(blank)*) at:
27 |
28 | http://localhost:8080/console
29 |
30 | Customizing
31 | -----------
32 | Use the application.properties to control various aspects of the Spring Boot application (like setup your own database connection).
33 | Use the logback.xml to adjust and control logging.
34 |
35 | Debugging
36 | ---------
37 | To enable the debugging port (localhost:8000) when using spring-boot:run, use the maven profile: **-Pdebug**. Then you can attach any remote debugger (eclipse, intellij, etc.) to localhost:8000. NOTE that the application will pause until you connect the debugger to it.
38 |
39 | mvn clean install spring-boot:run -Pdebug
40 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiServiceRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiServiceEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | /**
22 | * NOTE: use of this interface magic makes all subclass-based (CGLIB) proxies fail
23 | */
24 | @Transactional
25 | public interface LtiServiceRepository extends PagingAndSortingRepository {
26 | /* Add custom crud methods here
27 | * If you need a custom implementation of the methods then see docs for steps to add it
28 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
29 | * Can also write a custom query like so:
30 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
31 | * List findAliased();
32 | * OR:
33 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
34 | * List findWithAlias(String alias);
35 | */
36 |
37 | /**
38 | * @param key the unique key
39 | * @return the LtiServiceEntity OR null if there is no entity matching this key
40 | */
41 | LtiServiceEntity findByServiceKey(String key);
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiResultRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiResultEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | /**
22 | * NOTE: use of this interface magic makes all subclass-based (CGLIB) proxies fail
23 | */
24 | @Transactional
25 | public interface LtiResultRepository extends PagingAndSortingRepository {
26 | /* Add custom crud methods here
27 | * If you need a custom implementation of the methods then see docs for steps to add it
28 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
29 | * Can also write a custom query like so:
30 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
31 | * List findAliased();
32 | * OR:
33 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
34 | * List findWithAlias(String alias);
35 | */
36 |
37 | /**
38 | * @param sourcedid the unique sourcedid key
39 | * @return the LtiResultEntity OR null if there is no entity matching this key
40 | */
41 | LtiResultEntity findBySourcedid(String sourcedid);
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/SSOKeyRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.SSOKeyEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | @Transactional
22 | public interface SSOKeyRepository extends PagingAndSortingRepository {
23 | /* Add custom crud methods here
24 | * If you need a custom implementation of the methods then see docs for steps to add it
25 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
26 | * Can also write a custom query like so:
27 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
28 | * List findAliased();
29 | * OR:
30 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
31 | * List findWithAlias(String alias);
32 | */
33 |
34 | /**
35 | * @param key the unique key
36 | * @return the SSOKeyEntity OR null if there is no entity matching this key
37 | */
38 | SSOKeyEntity findByKeyKey(String key);
39 |
40 | /**
41 | * @param key the unique key
42 | * @return the number of keys removed (0 or 1)
43 | */
44 | int deleteByKeyKey(String key);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # ----------------------------------------
2 | # CORE PROPERTIES
3 | # ----------------------------------------
4 |
5 | # SPRING CONFIG (ConfigFileApplicationListener)
6 | # config file name (default to 'application')
7 | #spring.config.name=
8 | # location of config file
9 | #spring.config.location=
10 |
11 | #spring.application.name=ltistarter
12 | #server.port=8080
13 |
14 | ## thymeleaf base settings
15 | spring.thymeleaf.mode=HTML5
16 | #spring.thymeleaf.encoding=UTF-8
17 |
18 | # INTERNATIONALIZATION (MessageSourceAutoConfiguration)
19 | #spring.messages.basename=messages
20 | #spring.messages.cacheSeconds=-1
21 | #spring.messages.encoding=UTF-8
22 |
23 | ## Logging settings
24 | #logging.path=/var/logs
25 | #logging.file=myapp.log
26 | #logging.level.ltistarter=DEBUG
27 | #logging.level.org.springframework.web=DEBUG
28 | #logging.level.org.hibernate=ERROR
29 |
30 | ## Database connection (MySQL)
31 | #spring.jpa.generate-ddl=true
32 | # ddl-auto: none, validate, update, create-drop
33 | #spring.jpa.show-sql=true
34 | spring.jpa.hibernate.ddl-auto=update
35 | spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
36 | spring.datasource.driverClassName=org.h2.Driver
37 | spring.datasource.username=sa
38 | spring.datasource.password=
39 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
40 | #spring.datasource.url=jdbc:mysql://localhost/test
41 | #spring.datasource.username=dbuser
42 | #spring.datasource.password=dbpass
43 | #spring.datasource.driverClassName=com.mysql.jdbc.Driver
44 | # populate using data.sql
45 | #spring.datasource.initialize=true
46 | # a schema (DDL) script resource reference
47 | #spring.datasource.schema=
48 | #spring.datasource.separator=;
49 | #spring.datasource.continueOnError=false
50 |
51 | ### Settings for development ONLY
52 | http.mappers.json-pretty-print=true
53 | http.mappers.json-sort-keys=true
54 | spring.thymeleaf.cache=false
55 | #logging.level.org.springframework.security=DEBUG
56 | #spring.jpa.show-sql=true
57 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiKeyRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiKeyEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | /**
22 | * NOTE: use of this interface magic makes all subclass-based (CGLIB) proxies fail
23 | */
24 | @Transactional
25 | public interface LtiKeyRepository extends PagingAndSortingRepository {
26 | /* Add custom crud methods here
27 | * If you need a custom implementation of the methods then see docs for steps to add it
28 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
29 | * Can also write a custom query like so:
30 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
31 | * List findAliased();
32 | * OR:
33 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
34 | * List findWithAlias(String alias);
35 | */
36 |
37 | /**
38 | * @param key the unique key
39 | * @return the LtiKeyEntity OR null if there is no entity matching this key
40 | */
41 | LtiKeyEntity findByKeyKey(String key);
42 |
43 | /**
44 | * @param key the unique key
45 | * @return the number of keys removed (0 or 1)
46 | */
47 | int deleteByKeyKey(String key);
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/LtiContextRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.LtiContextEntity;
18 | import org.springframework.data.repository.PagingAndSortingRepository;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 | /**
22 | * NOTE: use of this interface magic makes all subclass-based (CGLIB) proxies fail
23 | */
24 | @Transactional
25 | public interface LtiContextRepository extends PagingAndSortingRepository {
26 | /* Add custom crud methods here
27 | * If you need a custom implementation of the methods then see docs for steps to add it
28 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
29 | * Can also write a custom query like so:
30 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
31 | * List findAliased();
32 | * OR:
33 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
34 | * List findWithAlias(String alias);
35 | */
36 |
37 | /**
38 | * @param key the unique key
39 | * @return the LtiContextEntity OR null if there is no entity matching this key
40 | */
41 | LtiContextEntity findByContextKey(String key);
42 |
43 | /**
44 | * @param key the unique key
45 | * @return the number of keys removed (0 or 1)
46 | */
47 | int deleteByContextKey(String key);
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/oauth/ZeroLeggedOAuthProviderProcessingFilter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.oauth;
16 |
17 | import org.springframework.security.oauth.provider.OAuthAuthenticationHandler;
18 | import org.springframework.security.oauth.provider.OAuthProcessingFilterEntryPoint;
19 | import org.springframework.security.oauth.provider.filter.ProtectedResourceProcessingFilter;
20 | import org.springframework.security.oauth.provider.token.OAuthProviderTokenServices;
21 |
22 | /**
23 | * Zero Legged OAuth processing servlet filter
24 | */
25 | public class ZeroLeggedOAuthProviderProcessingFilter extends ProtectedResourceProcessingFilter {
26 |
27 | public ZeroLeggedOAuthProviderProcessingFilter(MyConsumerDetailsService oAuthConsumerDetailsService, MyOAuthNonceServices oAuthNonceServices, OAuthProcessingFilterEntryPoint oAuthProcessingFilterEntryPoint, OAuthAuthenticationHandler oAuthAuthenticationHandler, OAuthProviderTokenServices oAuthProviderTokenServices, boolean testing) {
28 | super();
29 | setAuthenticationEntryPoint(oAuthProcessingFilterEntryPoint);
30 | setAuthHandler(oAuthAuthenticationHandler);
31 | setConsumerDetailsService(oAuthConsumerDetailsService);
32 | setNonceServices(oAuthNonceServices);
33 | setTokenServices(oAuthProviderTokenServices);
34 | if (testing) {
35 | setIgnoreMissingCredentials(true); // die if OAuth params are not included
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/ConfigRepository.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import ltistarter.model.ConfigEntity;
18 | import org.springframework.cache.annotation.Cacheable;
19 | import org.springframework.data.repository.PagingAndSortingRepository;
20 | import org.springframework.transaction.annotation.Transactional;
21 |
22 | /**
23 | * NOTE: use of this interface magic makes all subclass-based (CGLIB) proxies fail
24 | */
25 | @Transactional
26 | public interface ConfigRepository extends PagingAndSortingRepository {
27 | /* Add custom crud methods here
28 | * If you need a custom implementation of the methods then see docs for steps to add it
29 | * http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/repositories.html
30 | * Can also write a custom query like so:
31 | * @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
32 | * List findAliased();
33 | * OR:
34 | * @Query("SELECT u FROM User u WHERE u.alias = ?1")
35 | * List findWithAlias(String alias);
36 | */
37 |
38 | /**
39 | * @param name the config name (e.g. app.config)
40 | * @return the count of config items with this exact name
41 | */
42 | public int countByName(String name);
43 |
44 | /**
45 | * @param name the config name (e.g. app.config)
46 | * @return the config item (or null if none found)
47 | */
48 | @Cacheable(value = "configs", key = "#name")
49 | public ConfigEntity findByName(String name);
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/LTI2Controller.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import ltistarter.lti.LTIRequest;
18 | import org.springframework.stereotype.Controller;
19 | import org.springframework.ui.Model;
20 | import org.springframework.web.bind.annotation.RequestMapping;
21 |
22 | import javax.servlet.http.HttpServletRequest;
23 | import java.security.Principal;
24 |
25 | /**
26 | * This LTI controller should be protected by OAuth 1.0a and is here for cases
27 | * where we need lti2 specific processing that can't be done under the lti path
28 | */
29 | @Controller
30 | @RequestMapping("/lti2")
31 | public class LTI2Controller extends BaseController {
32 |
33 | @RequestMapping({"", "/"})
34 | public String home(HttpServletRequest req, Principal principal, Model model) {
35 | commonModelPopulate(req, principal, model);
36 | model.addAttribute("name", "lti2");
37 | req.getSession().setAttribute("login", "oauth");
38 | LTIRequest ltiRequest = LTIRequest.getInstance();
39 | if (ltiRequest != null) {
40 | model.addAttribute("lti", true);
41 | model.addAttribute("ltiVersion", ltiRequest.getLtiVersion());
42 | model.addAttribute("ltiContext", ltiRequest.getLtiContextId());
43 | model.addAttribute("ltiUser", ltiRequest.getLtiUserDisplayName());
44 | model.addAttribute("ltiLink", ltiRequest.getLtiLinkId());
45 | }
46 | //noinspection SpringMVCViewInspection
47 | return "home"; // name of the template
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/oauth/MyOAuthProcessingFilterEntryPointImpl.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.oauth;
16 |
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 | import org.springframework.security.core.AuthenticationException;
20 | import org.springframework.security.oauth.provider.OAuthProcessingFilterEntryPoint;
21 | import org.springframework.stereotype.Component;
22 |
23 | import javax.servlet.ServletException;
24 | import javax.servlet.http.HttpServletRequest;
25 | import javax.servlet.http.HttpServletResponse;
26 | import java.io.IOException;
27 |
28 | /**
29 | * Shows how to handle OAuth failures in a special way if desired (just logs it for now)
30 | */
31 | @Component
32 | public class MyOAuthProcessingFilterEntryPointImpl extends OAuthProcessingFilterEntryPoint {
33 |
34 | final static Logger log = LoggerFactory.getLogger(MyOAuthProcessingFilterEntryPointImpl.class);
35 |
36 | @Override
37 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
38 | log.info("OAuth FILTER Failure (commence), req=" + request + ", ex=" + authException);
39 | // Called when there is an OAuth Auth failure, authException may be InsufficientAuthenticationException
40 | super.commence(request, response, authException);
41 | /*
42 | response.setCharacterEncoding("UTF-8");
43 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
44 | response.setContentType(MediaType.APPLICATION_JSON.getType());
45 | response.getWriter().println("{\"Unauthorized\":\"" + authException + "\"}");
46 | */
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/BaseController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 | import org.springframework.beans.factory.annotation.Autowired;
20 | import org.springframework.boot.actuate.metrics.CounterService;
21 | import org.springframework.ui.Model;
22 |
23 | import javax.servlet.http.HttpServletRequest;
24 | import java.security.Principal;
25 | import java.util.Date;
26 |
27 | /**
28 | * Common controller methods
29 | */
30 | public class BaseController {
31 |
32 | final static Logger log = LoggerFactory.getLogger(BaseController.class);
33 |
34 | @Autowired
35 | @SuppressWarnings("SpringJavaAutowiringInspection")
36 | CounterService counterService;
37 |
38 | /**
39 | * Just populate some common model stuff for less repeating
40 | *
41 | * @param req the request
42 | * @param principal the current security principal (if there is one)
43 | * @param model the model
44 | */
45 | void commonModelPopulate(HttpServletRequest req, Principal principal, Model model) {
46 | model.addAttribute("today", new Date());
47 | // TODO real user and pass
48 | model.addAttribute("basicUser", "admin");
49 | model.addAttribute("basicPass", "admin");
50 | // TODO real key and secret?
51 | model.addAttribute("oauthKey", "key");
52 | model.addAttribute("oauthSecret", "secret");
53 | // a little extra request handling stuff
54 | model.addAttribute("req", req);
55 | model.addAttribute("reqURI", req.getMethod() + " " + req.getRequestURI());
56 | // current user
57 | model.addAttribute("username", principal != null ? principal.getName() : "ANONYMOUS");
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/FormController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import org.springframework.stereotype.Controller;
18 | import org.springframework.ui.Model;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 | import org.springframework.web.bind.annotation.RequestMethod;
21 |
22 | import javax.servlet.http.HttpServletRequest;
23 | import java.security.Principal;
24 |
25 | /**
26 | * This controller should be protected by basic auth authentication (on the /basic path)
27 | * Username and password controlled in application.properties
28 | */
29 | @Controller
30 | @RequestMapping("/form")
31 | public class FormController extends BaseController {
32 |
33 | @RequestMapping({"", "/"})
34 | public String home(HttpServletRequest req, Principal principal, Model model) {
35 | commonModelPopulate(req, principal, model);
36 | model.addAttribute("name", "form");
37 | model.addAttribute("canLogout", true);
38 | req.getSession().setAttribute("login", "form");
39 | return "home"; // name of the template
40 | }
41 |
42 | @RequestMapping(value = "/login", method = RequestMethod.GET)
43 | public String login(HttpServletRequest req) {
44 | log.info("login: " + req);
45 | return "login";
46 | }
47 |
48 | // Login form with error
49 | @RequestMapping(value = "/login", params = "error=true")
50 | public String loginError(HttpServletRequest req, Model model) {
51 | log.info("login-error: " + req);
52 | model.addAttribute("loginError", true);
53 | return "login";
54 | }
55 |
56 | /*
57 | @RequestMapping("/logout")
58 | public void logout(HttpServletRequest req) {
59 | log.info("logout: " + req);
60 | }*/
61 |
62 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/model/BaseEntity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.model;
16 |
17 | import org.apache.commons.lang3.StringUtils;
18 |
19 | import javax.persistence.*;
20 | import java.sql.Timestamp;
21 |
22 | /**
23 | * Specialty class which handles the created_at and updated_at fields automatically
24 | */
25 | @MappedSuperclass
26 | public class BaseEntity {
27 |
28 | @Column(name = "created_at", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
29 | Timestamp createdAt;
30 |
31 | @Column(name = "updated_at")
32 | Timestamp updatedAt;
33 |
34 | @Version
35 | @Column(name = "entity_version")
36 | int version;
37 |
38 | @PrePersist
39 | void preCreate() {
40 | this.createdAt = this.updatedAt = new Timestamp(System.currentTimeMillis());
41 | }
42 |
43 | @PreUpdate
44 | void preUpdate() {
45 | this.updatedAt = new Timestamp(System.currentTimeMillis());
46 | }
47 |
48 | public Timestamp getCreatedAt() {
49 | return createdAt;
50 | }
51 |
52 | public void setCreatedAt(Timestamp createdAt) {
53 | this.createdAt = createdAt;
54 | }
55 |
56 | public Timestamp getUpdatedAt() {
57 | return updatedAt;
58 | }
59 |
60 | public void setUpdatedAt(Timestamp updatedAt) {
61 | this.updatedAt = updatedAt;
62 | }
63 |
64 | public int getVersion() {
65 | return version;
66 | }
67 |
68 | public void setVersion(int version) {
69 | this.version = version;
70 | }
71 |
72 | public static String makeSHA256(String text) {
73 | String encode = null;
74 | if (StringUtils.isNotBlank(text)) {
75 | encode = org.apache.commons.codec.digest.DigestUtils.sha256Hex(text);
76 | }
77 | return encode;
78 | }
79 |
80 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/model/ConfigEntity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.model;
16 |
17 | import javax.persistence.*;
18 |
19 | @Entity
20 | @Table(name = "config")
21 | public class ConfigEntity extends BaseEntity {
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.AUTO)
24 | @Column(name = "config_id", nullable = false, insertable = true, updatable = true)
25 | private long id;
26 | @Basic
27 | @Column(name = "config_name", nullable = false, insertable = true, updatable = true, length = 255)
28 | private String name;
29 | @Basic
30 | @Column(name = "config_value", nullable = true, insertable = true, updatable = true, length = 4096)
31 | private String value;
32 |
33 | public ConfigEntity() {
34 | }
35 |
36 | public ConfigEntity(String name, String value) {
37 | assert name != null;
38 | this.name = name;
39 | this.value = value;
40 | }
41 |
42 | public long getId() {
43 | return id;
44 | }
45 |
46 | public void setId(long id) {
47 | this.id = id;
48 | }
49 |
50 | public String getName() {
51 | return name;
52 | }
53 |
54 | public void setName(String name) {
55 | this.name = name;
56 | }
57 |
58 | public String getValue() {
59 | return value;
60 | }
61 |
62 | public void setValue(String value) {
63 | this.value = value;
64 | }
65 |
66 | @Override
67 | public boolean equals(Object o) {
68 | if (this == o) return true;
69 | if (o == null || getClass() != o.getClass()) return false;
70 |
71 | ConfigEntity that = (ConfigEntity) o;
72 |
73 | if (id != that.id) return false;
74 | if (!name.equals(that.name)) return false;
75 |
76 | return true;
77 | }
78 |
79 | @Override
80 | public int hashCode() {
81 | int result = (int) (id ^ (id >>> 32));
82 | result = 31 * result + name.hashCode();
83 | return result;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/oauth/MyConsumerDetailsService.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.oauth;
16 |
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
20 | import org.springframework.security.oauth.common.OAuthException;
21 | import org.springframework.security.oauth.common.signature.SharedConsumerSecretImpl;
22 | import org.springframework.security.oauth.provider.BaseConsumerDetails;
23 | import org.springframework.security.oauth.provider.ConsumerDetails;
24 | import org.springframework.security.oauth.provider.ConsumerDetailsService;
25 | import org.springframework.stereotype.Component;
26 |
27 | /**
28 | * Sample consumer details service which verifies the key and secret,
29 | * In our case the key is "key" and secret is "secret"
30 | */
31 | @Component
32 | public class MyConsumerDetailsService implements ConsumerDetailsService {
33 |
34 | final static Logger log = LoggerFactory.getLogger(MyConsumerDetailsService.class);
35 |
36 | @Override
37 | public ConsumerDetails loadConsumerByConsumerKey(String consumerKey) throws OAuthException {
38 | BaseConsumerDetails cd;
39 | // NOTE: really lookup the key and secret, for the sample here we just hardcoded
40 | if ("key".equals(consumerKey)) {
41 | // allow this oauth request
42 | cd = new BaseConsumerDetails();
43 | cd.setConsumerKey(consumerKey);
44 | cd.setSignatureSecret(new SharedConsumerSecretImpl("secret"));
45 | cd.setConsumerName("Sample");
46 | cd.setRequiredToObtainAuthenticatedToken(false); // no token required (0-legged)
47 | cd.getAuthorities().add(new SimpleGrantedAuthority("ROLE_OAUTH")); // add the ROLE_OAUTH (can add others as well)
48 | log.info("OAuth check SUCCESS, consumer key: " + consumerKey);
49 | } else {
50 | // deny - failed to match
51 | throw new OAuthException("For this example, key must be 'key'");
52 | }
53 | return cd;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/controllers/LTIController.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.controllers;
16 |
17 | import ltistarter.lti.LTIRequest;
18 | import org.springframework.stereotype.Controller;
19 | import org.springframework.ui.Model;
20 | import org.springframework.web.bind.annotation.RequestMapping;
21 |
22 | import javax.servlet.http.HttpServletRequest;
23 | import java.security.Principal;
24 |
25 | /**
26 | * This LTI controller should be protected by OAuth 1.0a (on the /oauth path)
27 | * This will handle LTI 1 and 2 (many of the paths ONLY make sense for LTI2 though)
28 | * Sample Key "key" and secret "secret"
29 | */
30 | @Controller
31 | @RequestMapping("/lti")
32 | public class LTIController extends BaseController {
33 |
34 | @RequestMapping({"", "/"})
35 | public String home(HttpServletRequest req, Principal principal, Model model) {
36 | commonModelPopulate(req, principal, model);
37 | model.addAttribute("name", "lti");
38 | req.getSession().setAttribute("login", "oauth");
39 | LTIRequest ltiRequest = LTIRequest.getInstance();
40 | if (ltiRequest != null) {
41 | model.addAttribute("lti", true);
42 | model.addAttribute("ltiVersion", ltiRequest.getLtiVersion());
43 | model.addAttribute("ltiContext", ltiRequest.getLtiContextId());
44 | model.addAttribute("ltiUser", ltiRequest.getLtiUserDisplayName());
45 | model.addAttribute("ltiLink", ltiRequest.getLtiLinkId());
46 | }
47 | //noinspection SpringMVCViewInspection
48 | return "home"; // name of the template
49 | }
50 |
51 | @RequestMapping({"/register"})
52 | public String register(HttpServletRequest req, Model model) {
53 | LTIRequest ltiRequest = LTIRequest.getInstanceOrDie();
54 | if (ltiRequest.checkValidToolRegistration()) { // throws exception on failure
55 | model.addAttribute("validToolRegistration", true);
56 | // TODO process it!
57 | }
58 | //noinspection SpringMVCViewInspection
59 | return "register"; // name of the template
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/src/main/java/ltistarter/repository/AllRepositories.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.repository;
16 |
17 | import org.springframework.beans.factory.annotation.Autowired;
18 | import org.springframework.stereotype.Component;
19 |
20 | import javax.persistence.EntityManager;
21 | import javax.persistence.PersistenceContext;
22 |
23 | /**
24 | * Special service to give access to all the repositories in one place
25 | *
26 | * This is just here to make it a little easier to get access to the full set of repositories instead of always injecting
27 | * the lot of them (reduces code duplication)
28 | */
29 | @SuppressWarnings("SpringJavaAutowiringInspection")
30 | @Component
31 | public class AllRepositories {
32 |
33 | @Autowired
34 | public ConfigRepository configs;
35 |
36 | @Autowired
37 | public KeyRequestRepository keyRequests;
38 |
39 | @Autowired
40 | public LtiContextRepository contexts;
41 |
42 | @Autowired
43 | public LtiKeyRepository keys;
44 |
45 | @Autowired
46 | public LtiLinkRepository links;
47 |
48 | @Autowired
49 | public LtiMembershipRepository members;
50 |
51 | @Autowired
52 | public LtiResultRepository results;
53 |
54 | @Autowired
55 | public LtiServiceRepository services;
56 |
57 | @Autowired
58 | public LtiUserRepository users;
59 |
60 | @Autowired
61 | public ProfileRepository profiles;
62 |
63 | @Autowired
64 | public SSOKeyRepository ssoKeys;
65 |
66 | @PersistenceContext
67 | public EntityManager entityManager;
68 |
69 | /**
70 | * @return a version of the entity manager which is transactional for cases where we cannot use the @Transactional annotation
71 | * or we are not operating in a service method
72 | */
73 | public EntityManager getTransactionalEntityManager() {
74 | /* Need a transactional entity manager and for some reason the normal one is NOT, without this we get:
75 | * java.lang.IllegalStateException: No transactional EntityManager available
76 | * http://forum.spring.io/forum/spring-projects/roo/88329-entitymanager-problem
77 | * http://stackoverflow.com/questions/14522691/java-lang-illegalstateexception-no-transactional-entitymanager-available
78 | */
79 | return entityManager.getEntityManagerFactory().createEntityManager();
80 | }
81 |
82 | /**
83 | * Do NOT construct this class manually
84 | */
85 | protected AllRepositories() {
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/database/DatabasePreload.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.database;
16 |
17 | import ltistarter.config.ApplicationConfig;
18 | import ltistarter.model.LtiKeyEntity;
19 | import ltistarter.model.LtiUserEntity;
20 | import ltistarter.model.ProfileEntity;
21 | import ltistarter.repository.LtiKeyRepository;
22 | import ltistarter.repository.LtiUserRepository;
23 | import ltistarter.repository.ProfileRepository;
24 | import org.slf4j.Logger;
25 | import org.slf4j.LoggerFactory;
26 | import org.springframework.beans.factory.annotation.Autowired;
27 | import org.springframework.context.annotation.Profile;
28 | import org.springframework.stereotype.Component;
29 |
30 | import javax.annotation.PostConstruct;
31 |
32 | /**
33 | * Check if the database has initial data in it,
34 | * if it is empty on startup then we populate it with some initial data
35 | */
36 | @Component
37 | @Profile("!testing")
38 | // only load this when running the application (not for unit tests which have the 'testing' profile active)
39 | public class DatabasePreload {
40 |
41 | final static Logger log = LoggerFactory.getLogger(DatabasePreload.class);
42 |
43 | @Autowired
44 | ApplicationConfig applicationConfig;
45 |
46 | @Autowired
47 | @SuppressWarnings({"SpringJavaAutowiredMembersInspection", "SpringJavaAutowiringInspection"})
48 | LtiKeyRepository ltiKeyRepository;
49 | @Autowired
50 | @SuppressWarnings({"SpringJavaAutowiredMembersInspection", "SpringJavaAutowiringInspection"})
51 | LtiUserRepository ltiUserRepository;
52 | @Autowired
53 | @SuppressWarnings({"SpringJavaAutowiredMembersInspection", "SpringJavaAutowiringInspection"})
54 | ProfileRepository profileRepository;
55 |
56 | @PostConstruct
57 | public void init() {
58 | if (ltiKeyRepository.count() > 0) {
59 | // done, no preloading
60 | log.info("INIT - no preload");
61 | } else {
62 | // preload the sample data
63 | log.info("INIT - preloaded keys and user");
64 | // create our sample key
65 | ltiKeyRepository.save(new LtiKeyEntity("key", "secret"));
66 | // create our sample user
67 | LtiUserEntity user = ltiUserRepository.save(new LtiUserEntity("azeckoski", null));
68 | ProfileEntity profile = profileRepository.save(new ProfileEntity("AaronZeckoski", null, "azeckoski@test.com"));
69 | // now add profile to the user
70 | user.setProfile(profile);
71 | profile.getUsers().add(user);
72 | ltiUserRepository.save(user);
73 | }
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/model/LmsPluginsEntity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.model;
16 |
17 | import javax.persistence.*;
18 |
19 | @Entity
20 | @Table(name = "lms_plugins")
21 | public class LmsPluginsEntity extends BaseEntity {
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.AUTO)
24 | @Column(name = "plugin_id", nullable = false, insertable = true, updatable = true)
25 | private long pluginId;
26 | @Basic
27 | @Column(name = "plugin_path", nullable = false, insertable = true, updatable = true, length = 255)
28 | private String pluginPath;
29 | @Basic
30 | @Column(name = "plugin_version", nullable = false, insertable = true, updatable = true)
31 | private long pluginVersion;
32 | @Basic
33 | @Column(name = "title", nullable = true, insertable = true, updatable = true, length = 4096)
34 | private String title;
35 | @Basic
36 | @Column(name = "json", nullable = true, insertable = true, updatable = true, length = 65535)
37 | private String json;
38 |
39 | public long getPluginId() {
40 | return pluginId;
41 | }
42 |
43 | public void setPluginId(long pluginId) {
44 | this.pluginId = pluginId;
45 | }
46 |
47 | public String getPluginPath() {
48 | return pluginPath;
49 | }
50 |
51 | public void setPluginPath(String pluginPath) {
52 | this.pluginPath = pluginPath;
53 | }
54 |
55 | public long getPluginVersion() {
56 | return pluginVersion;
57 | }
58 |
59 | public void setPluginVersion(long version) {
60 | this.pluginVersion = version;
61 | }
62 |
63 | public String getTitle() {
64 | return title;
65 | }
66 |
67 | public void setTitle(String title) {
68 | this.title = title;
69 | }
70 |
71 | public String getJson() {
72 | return json;
73 | }
74 |
75 | public void setJson(String json) {
76 | this.json = json;
77 | }
78 |
79 | @Override
80 | public boolean equals(Object o) {
81 | if (this == o) return true;
82 | if (o == null || getClass() != o.getClass()) return false;
83 |
84 | LmsPluginsEntity that = (LmsPluginsEntity) o;
85 |
86 | if (pluginId != that.pluginId) return false;
87 | if (pluginVersion != that.pluginVersion) return false;
88 | if (pluginPath != null ? !pluginPath.equals(that.pluginPath) : that.pluginPath != null) return false;
89 |
90 | return true;
91 | }
92 |
93 | @Override
94 | public int hashCode() {
95 | int result = (int) pluginId;
96 | result = 31 * result + (pluginPath != null ? pluginPath.hashCode() : 0);
97 | result = 31 * result + (int) (pluginVersion ^ (pluginVersion >>> 32));
98 | return result;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/lti/LTIOAuthProviderProcessingFilter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.lti;
16 |
17 | import ltistarter.oauth.MyOAuthNonceServices;
18 | import org.springframework.security.oauth.provider.OAuthProcessingFilterEntryPoint;
19 | import org.springframework.security.oauth.provider.filter.ProtectedResourceProcessingFilter;
20 | import org.springframework.security.oauth.provider.token.OAuthProviderTokenServices;
21 |
22 | import javax.servlet.FilterChain;
23 | import javax.servlet.ServletException;
24 | import javax.servlet.ServletRequest;
25 | import javax.servlet.ServletResponse;
26 | import javax.servlet.http.HttpServletRequest;
27 | import java.io.IOException;
28 |
29 | /**
30 | * LTI compatible Zero Legged OAuth processing servlet filter
31 | */
32 | public class LTIOAuthProviderProcessingFilter extends ProtectedResourceProcessingFilter {
33 |
34 | LTIDataService ltiDataService;
35 |
36 | public LTIOAuthProviderProcessingFilter(LTIDataService ltiDataService, LTIConsumerDetailsService oAuthConsumerDetailsService, MyOAuthNonceServices oAuthNonceServices, OAuthProcessingFilterEntryPoint oAuthProcessingFilterEntryPoint, LTIOAuthAuthenticationHandler oAuthAuthenticationHandler, OAuthProviderTokenServices oAuthProviderTokenServices) {
37 | super();
38 | assert ltiDataService != null;
39 | this.ltiDataService = ltiDataService;
40 | setAuthenticationEntryPoint(oAuthProcessingFilterEntryPoint);
41 | setAuthHandler(oAuthAuthenticationHandler);
42 | setConsumerDetailsService(oAuthConsumerDetailsService);
43 | setNonceServices(oAuthNonceServices);
44 | setTokenServices(oAuthProviderTokenServices);
45 | //setIgnoreMissingCredentials(false); // die if OAuth params are not included
46 | }
47 |
48 | @Override
49 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
50 | // NOTE: tsugi handles failures by just allowing the request to continue - since we have a dedicated endpoint for launches the LTIRequest object will throw an IllegalStateException is the LTI request is invalid somehow
51 | if (!(servletRequest instanceof HttpServletRequest)) {
52 | throw new IllegalStateException("LTI request MUST be an HttpServletRequest (cannot only be a ServletRequest)");
53 | }
54 | HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
55 | // load and initialize the LTI request object (loads and validates the data)
56 | LTIRequest ltiRequest = new LTIRequest(httpServletRequest, ltiDataService, true); // IllegalStateException if invalid
57 | httpServletRequest.setAttribute("LTI", true); // indicate this request is an LTI one
58 | httpServletRequest.setAttribute("lti_valid", ltiRequest.isLoaded() && ltiRequest.isComplete()); // is LTI request totally valid and complete
59 | httpServletRequest.setAttribute(LTIRequest.class.getName(), ltiRequest); // make the LTI data accessible later in the request if needed
60 | super.doFilter(servletRequest, servletResponse, chain);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/oauth/OAuthUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.oauth;
16 |
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 | import org.springframework.http.ResponseEntity;
20 | import org.springframework.security.oauth.common.signature.SharedConsumerSecretImpl;
21 | import org.springframework.security.oauth.consumer.BaseProtectedResourceDetails;
22 | import org.springframework.security.oauth.consumer.client.OAuthRestTemplate;
23 | import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
24 | import org.springframework.security.oauth2.client.OAuth2RestTemplate;
25 | import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
26 | import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
27 | import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
28 | import org.springframework.security.oauth2.common.AuthenticationScheme;
29 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
30 |
31 | import java.util.Map;
32 |
33 | /**
34 | * OAuth handling utils
35 | */
36 | public class OAuthUtils {
37 |
38 | final static Logger log = LoggerFactory.getLogger(OAuthUtils.class);
39 |
40 | public static ResponseEntity sendOAuth1Request(String url, String consumerKey, String sharedSecret, Map params, Map headers) {
41 | assert url != null;
42 | assert consumerKey != null;
43 | assert sharedSecret != null;
44 | BaseProtectedResourceDetails prd = new BaseProtectedResourceDetails();
45 | prd.setId("oauth");
46 | prd.setConsumerKey(consumerKey);
47 | prd.setSharedSecret(new SharedConsumerSecretImpl(sharedSecret));
48 | prd.setAdditionalParameters(params);
49 | prd.setAdditionalRequestHeaders(headers);
50 | OAuthRestTemplate restTemplate = new OAuthRestTemplate(prd);
51 | ResponseEntity response = restTemplate.postForEntity(url, params, String.class, (Map) null);
52 | return response;
53 | }
54 |
55 | public static ResponseEntity sendOAuth2Request(String url, String clientId, String clientSecret, String accessTokenURI, Map params) {
56 | assert url != null;
57 | assert clientId != null;
58 | assert clientSecret != null;
59 | AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider();
60 | BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
61 | resource.setClientAuthenticationScheme(AuthenticationScheme.form);
62 | resource.setClientId(clientId);
63 | resource.setClientSecret(clientSecret);
64 | resource.setAccessTokenUri(accessTokenURI);
65 | resource.setGrantType("access");
66 | OAuth2AccessToken accessToken = provider.obtainAccessToken(resource, new DefaultAccessTokenRequest());
67 | OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(accessToken));
68 | ResponseEntity response = restTemplate.postForEntity(url, params, String.class, (Map) null);
69 | return response;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/lti/LTIConsumerDetailsService.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.lti;
16 |
17 | import ltistarter.model.LtiKeyEntity;
18 | import ltistarter.repository.LtiKeyRepository;
19 | import org.apache.commons.lang3.StringUtils;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 | import org.springframework.beans.factory.annotation.Autowired;
23 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
24 | import org.springframework.security.oauth.common.OAuthException;
25 | import org.springframework.security.oauth.common.signature.SharedConsumerSecretImpl;
26 | import org.springframework.security.oauth.provider.BaseConsumerDetails;
27 | import org.springframework.security.oauth.provider.ConsumerDetails;
28 | import org.springframework.security.oauth.provider.ConsumerDetailsService;
29 | import org.springframework.stereotype.Component;
30 |
31 | /**
32 | * Sample consumer details service which verifies the key and secret using the LTI key DB.
33 | * Populates the ConsumerDetails.consumerName with the ID of the LtiKeyEntity if a match is found
34 | * and grants the OAUTH and LTI Authority Roles
35 | */
36 | @Component
37 | public class LTIConsumerDetailsService implements ConsumerDetailsService {
38 |
39 | final static Logger log = LoggerFactory.getLogger(LTIConsumerDetailsService.class);
40 |
41 | @Autowired
42 | @SuppressWarnings("SpringJavaAutowiringInspection")
43 | LtiKeyRepository ltiKeyRepository;
44 |
45 | @Override
46 | public ConsumerDetails loadConsumerByConsumerKey(String consumerKey) throws OAuthException {
47 | consumerKey = StringUtils.trimToNull(consumerKey);
48 | assert StringUtils.isNotEmpty(consumerKey) : "consumerKey must be set and not null";
49 | //HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
50 | //assert request != null : "request must be available for this to make sense";
51 | BaseConsumerDetails cd;
52 | LtiKeyEntity ltiKey = ltiKeyRepository.findByKeyKey(consumerKey);
53 | if (ltiKey == null) {
54 | // no matching key found
55 | throw new OAuthException("No matching lti key record was found for " + consumerKey);
56 | } else {
57 | cd = new BaseConsumerDetails();
58 | cd.setConsumerKey(consumerKey);
59 | // If there is a new_secret it means an LTI2 re-registration is in progress
60 | if (StringUtils.isNotBlank(ltiKey.getNewSecret()) && !StringUtils.equals(ltiKey.getSecret(), ltiKey.getNewSecret())) {
61 | log.info("LTI 2 re-registration in progress - new_secret is not blank");
62 | // TODO do we need to do anything here?
63 | }
64 | cd.setSignatureSecret(new SharedConsumerSecretImpl(ltiKey.getSecret()));
65 | cd.setConsumerName(String.valueOf(ltiKey.getKeyId()));
66 | cd.setRequiredToObtainAuthenticatedToken(false); // no token required (0-legged)
67 | cd.getAuthorities().add(new SimpleGrantedAuthority("ROLE_OAUTH")); // add the ROLE_OAUTH (can add others as well)
68 | cd.getAuthorities().add(new SimpleGrantedAuthority("ROLE_LTI"));
69 | log.info("LTI check SUCCESS, consumer key: " + consumerKey);
70 | }
71 | return cd;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/model/LtiMembershipEntity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.model;
16 |
17 | import javax.persistence.*;
18 |
19 | @Entity
20 | @Table(name = "lti_membership")
21 | public class LtiMembershipEntity extends BaseEntity {
22 |
23 | public final static int ROLE_STUDENT = 0;
24 | public final static int ROLE_INTRUCTOR = 1;
25 |
26 | @Id
27 | @GeneratedValue(strategy = GenerationType.AUTO)
28 | @Column(name = "membership_id", nullable = false, insertable = true, updatable = true)
29 | private long membershipId;
30 | @Basic
31 | @Column(name = "role", nullable = true, insertable = true, updatable = true)
32 | private Integer role;
33 | @Basic
34 | @Column(name = "role_override", nullable = true, insertable = true, updatable = true)
35 | private Integer roleOverride;
36 |
37 | @ManyToOne(fetch = FetchType.LAZY, optional = false)
38 | @JoinColumn(name = "context_id")
39 | private LtiContextEntity context;
40 | @ManyToOne(fetch = FetchType.LAZY, optional = false)
41 | @JoinColumn(name = "user_id")
42 | private LtiUserEntity user;
43 |
44 | protected LtiMembershipEntity() {
45 | }
46 |
47 | public LtiMembershipEntity(LtiContextEntity context, LtiUserEntity user, Integer role) {
48 | assert user != null;
49 | assert context != null;
50 | this.user = user;
51 | this.context = context;
52 | this.role = role;
53 | }
54 |
55 | public long getMembershipId() {
56 | return membershipId;
57 | }
58 |
59 | public void setMembershipId(long membershipId) {
60 | this.membershipId = membershipId;
61 | }
62 |
63 | public Integer getRole() {
64 | return role;
65 | }
66 |
67 | public void setRole(Integer role) {
68 | this.role = role;
69 | }
70 |
71 | public Integer getRoleOverride() {
72 | return roleOverride;
73 | }
74 |
75 | public void setRoleOverride(Integer roleOverride) {
76 | this.roleOverride = roleOverride;
77 | }
78 |
79 | public LtiContextEntity getContext() {
80 | return context;
81 | }
82 |
83 | public void setContext(LtiContextEntity context) {
84 | this.context = context;
85 | }
86 |
87 | public LtiUserEntity getUser() {
88 | return user;
89 | }
90 |
91 | public void setUser(LtiUserEntity user) {
92 | this.user = user;
93 | }
94 |
95 | @Override
96 | public boolean equals(Object o) {
97 | if (this == o) return true;
98 | if (o == null || getClass() != o.getClass()) return false;
99 |
100 | LtiMembershipEntity that = (LtiMembershipEntity) o;
101 |
102 | if (context.getContextId() != that.context.getContextId()) return false;
103 | if (membershipId != that.membershipId) return false;
104 | if (user.getUserId() != that.user.getUserId()) return false;
105 | if (role != null ? !role.equals(that.role) : that.role != null) return false;
106 |
107 | return true;
108 | }
109 |
110 | @Override
111 | public int hashCode() {
112 | int result = (int) membershipId;
113 | result = 31 * result + (int) context.getContextId();
114 | result = 31 * result + (int) user.getUserId();
115 | result = 31 * result + (role != null ? role.hashCode() : 0);
116 | return result;
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/ltistarter/model/KeyRequestEntity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Unicon (R)
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package ltistarter.model;
16 |
17 | import javax.persistence.*;
18 |
19 | @Entity
20 | @Table(name = "key_request")
21 | public class KeyRequestEntity extends BaseEntity {
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.AUTO)
24 | @Column(name = "request_id", nullable = false, insertable = true, updatable = true)
25 | private long requestId;
26 | @Basic
27 | @Column(name = "title", nullable = false, insertable = true, updatable = true, length = 4096)
28 | private String title;
29 | @Basic
30 | @Column(name = "notes", nullable = true, insertable = true, updatable = true, length = 65535)
31 | private String notes;
32 | @Basic
33 | @Column(name = "admin", nullable = true, insertable = true, updatable = true, length = 65535)
34 | private String admin;
35 | @Basic
36 | @Column(name = "state", nullable = true, insertable = true, updatable = true)
37 | private Short state;
38 | @Basic
39 | @Column(name = "lti", nullable = true, insertable = true, updatable = true)
40 | private Byte lti;
41 | @Basic
42 | @Column(name = "json", nullable = true, insertable = true, updatable = true, length = 65535)
43 | private String json;
44 |
45 | @ManyToOne
46 | @JoinColumn(name = "user_id", referencedColumnName = "user_id", nullable = false, insertable = false, updatable = false)
47 | private LtiUserEntity user;
48 |
49 | public long getRequestId() {
50 | return requestId;
51 | }
52 |
53 | public void setRequestId(long requestId) {
54 | this.requestId = requestId;
55 | }
56 |
57 | public String getTitle() {
58 | return title;
59 | }
60 |
61 | public void setTitle(String title) {
62 | this.title = title;
63 | }
64 |
65 | public String getNotes() {
66 | return notes;
67 | }
68 |
69 | public void setNotes(String notes) {
70 | this.notes = notes;
71 | }
72 |
73 | public String getAdmin() {
74 | return admin;
75 | }
76 |
77 | public void setAdmin(String admin) {
78 | this.admin = admin;
79 | }
80 |
81 | public Short getState() {
82 | return state;
83 | }
84 |
85 | public void setState(Short state) {
86 | this.state = state;
87 | }
88 |
89 | public Byte getLti() {
90 | return lti;
91 | }
92 |
93 | public void setLti(Byte lti) {
94 | this.lti = lti;
95 | }
96 |
97 | public String getJson() {
98 | return json;
99 | }
100 |
101 | public void setJson(String json) {
102 | this.json = json;
103 | }
104 |
105 | public LtiUserEntity getUser() {
106 | return user;
107 | }
108 |
109 | public void setUser(LtiUserEntity user) {
110 | this.user = user;
111 | }
112 |
113 | @Override
114 | public boolean equals(Object o) {
115 | if (this == o) return true;
116 | if (o == null || getClass() != o.getClass()) return false;
117 |
118 | KeyRequestEntity that = (KeyRequestEntity) o;
119 |
120 | if (requestId != that.requestId) return false;
121 | if (title != null ? !title.equals(that.title) : that.title != null) return false;
122 |
123 | return true;
124 | }
125 |
126 | @Override
127 | public int hashCode() {
128 | int result = (int) requestId;
129 | result = 31 * result + (title != null ? title.hashCode() : 0);
130 | return result;
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/resources/templates/home.html:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
21 |
22 | LTI Starter
23 |
24 |
25 |
26 |