diff --git a/BlogPost/.classpath b/BlogPost/.classpath new file mode 100644 index 0000000..906bfce --- /dev/null +++ b/BlogPost/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BlogPost/.project b/BlogPost/.project new file mode 100644 index 0000000..6b49b98 --- /dev/null +++ b/BlogPost/.project @@ -0,0 +1,28 @@ + + + BlogPost + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + org.springframework.ide.eclipse.boot.validation.springbootbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/BlogPost/.settings/org.eclipse.core.resources.prefs b/BlogPost/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..365bbd6 --- /dev/null +++ b/BlogPost/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding/=UTF-8 diff --git a/BlogPost/.settings/org.eclipse.jdt.core.prefs b/BlogPost/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..0ada971 --- /dev/null +++ b/BlogPost/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.methodParameters=generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/BlogPost/.settings/org.springframework.ide.eclipse.prefs b/BlogPost/.settings/org.springframework.ide.eclipse.prefs new file mode 100644 index 0000000..e587c65 --- /dev/null +++ b/BlogPost/.settings/org.springframework.ide.eclipse.prefs @@ -0,0 +1,2 @@ +boot.validation.initialized=true +eclipse.preferences.version=1 diff --git a/BlogPost/pom.xml b/BlogPost/pom.xml new file mode 100644 index 0000000..42de451 --- /dev/null +++ b/BlogPost/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + com.example + blogpost + 0.0.1-SNAPSHOT + jar + + BlogPost + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-web + + + org.webjars + js-cookie + 2.1.0 + + + org.webjars + jquery + 2.1.1 + + + org.webjars + bootstrap + 3.2.0 + + + org.webjars + webjars-locator-core + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/BlogPost/src/main/java/com/example/BlogPost.java b/BlogPost/src/main/java/com/example/BlogPost.java new file mode 100644 index 0000000..be01123 --- /dev/null +++ b/BlogPost/src/main/java/com/example/BlogPost.java @@ -0,0 +1,46 @@ +package com.example; + +public class BlogPost { + private int userId; + private String title; + private String body; + + public BlogPost() { + } + + public BlogPost(int userId, String title, String body) { + this.userId = userId; + this.title = title; + this.body = body; + } + + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return "Blog Post [userId=" +userId + ", title=" +title +", body=" +body +"]"; + } +} diff --git a/BlogPost/src/main/java/com/example/BlogPostApp.java b/BlogPost/src/main/java/com/example/BlogPostApp.java new file mode 100644 index 0000000..1950367 --- /dev/null +++ b/BlogPost/src/main/java/com/example/BlogPostApp.java @@ -0,0 +1,153 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +@RestController +public class BlogPostApp extends WebSecurityConfigurerAdapter { + @Autowired + private BlogPostService blogService; + + @RequestMapping("/user") + public Map user(@AuthenticationPrincipal OAuth2User principal) { + return Collections.singletonMap("name", principal.getAttribute("name")); + } + + @RequestMapping(value= {"/posts", "/posts/{numberOfPosts}"}) + public String getBlogPosts(@PathVariable(required = false) Optional numberOfPosts, + @RequestParam(required = false) Integer userId) { + if (numberOfPosts.isPresent()) { + //System.out.println("numberOfPosts="+numberOfPosts); + return blogService.getUserBlogPosts(numberOfPosts); + } + else if (userId == null){ + //System.out.println("about to getAllBlogPosts..."); + return blogService.getAllBlogPosts(); + } + else { + //System.out.println("userId="+userId); + return blogService.getUserIdPosts(userId); + } + } + + @RequestMapping("/posts/1/comments") + public String getAllComments() { + return blogService.getAllComments(); + } + + @RequestMapping("/comments") + public String getPostIdComments(@RequestParam int postId) { + return blogService.getPostIdComments(postId); + } + /* + @RequestMapping(value="/posts") + public String getUserIdPosts(@PathVariable int userId) { + return blogService.getUserIdPosts(userId); + } + */ + @PostMapping("/posts") + public String createPost(@RequestParam("userId") int userId, //assumes auto-increment is on so no id needed + @RequestParam("title") String title, + @RequestParam("body") String body, + ModelMap newBlogPost) { + System.out.println("userId="+userId+", title="+title +", body="+body); + newBlogPost.putIfAbsent("userId",userId); + newBlogPost.putIfAbsent("title",title); + newBlogPost.putIfAbsent("body",body); + return blogService.addPost(newBlogPost); + } + + @PutMapping("/posts/{postId}") + public String putPost(@RequestParam("postId") Integer postId, + @RequestParam("userId") Integer userId, + @RequestParam("title") String title, + @RequestParam("body") String body, + ModelMap oldBlogPost) { + oldBlogPost.put("userId",userId); + oldBlogPost.put("title",title); + oldBlogPost.put("body",body); + return blogService.updatePost(oldBlogPost); + } + + @PatchMapping("/posts/{postId}") + public String patchPost(@RequestParam("postId") Integer postId, + @RequestParam("userId") Integer userId, + @RequestParam("title") String title, + @RequestParam("body") String body, + ModelMap oldBlogPost) { + oldBlogPost.put("userId",userId); + oldBlogPost.put("title",title); + oldBlogPost.put("body",body); + return blogService.updatePost(oldBlogPost); + } + + @DeleteMapping("/posts/{postId}") + public String deletePost(@RequestParam("postId") Integer postId) { + return blogService.deletePost(postId); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests(a -> a + .antMatchers("/", "/error", "/webjars/**").permitAll() + .anyRequest().authenticated() + ) + .exceptionHandling(e -> e + .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) + ) + .csrf(c -> c + .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) + ) + .logout(l -> l + .logoutSuccessUrl("/").permitAll() + ) + .oauth2Login(); + // @formatter:on + } + + public static void main(String[] args) { + SpringApplication.run(BlogPostApp.class, args); + } + +} diff --git a/BlogPost/src/main/java/com/example/BlogPostService.java b/BlogPost/src/main/java/com/example/BlogPostService.java new file mode 100644 index 0000000..61f3202 --- /dev/null +++ b/BlogPost/src/main/java/com/example/BlogPostService.java @@ -0,0 +1,66 @@ +package com.example; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.ui.ModelMap; +import org.springframework.web.client.RestTemplate; + +@Service +public class BlogPostService { + @Autowired + private RestTemplate restTemplate; + + public String getAllBlogPosts() { + ResponseEntity resp = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/posts", String.class); + return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null; + } + + public String getUserBlogPosts(Optional numberOfPosts) { + Integer numPosts = numberOfPosts.get(); + //System.out.println("numPosts="+numPosts); + ResponseEntity resp = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/posts/" +numPosts, String.class); + return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null; + } + + public String getAllComments() { + ResponseEntity resp = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/posts/1/comments", String.class); + return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null; + } + + public String getPostIdComments(int postId) { + ResponseEntity resp = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/comments?postId=" +postId, String.class); + return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null; + } + + public String getUserIdPosts(Integer userId) { + ResponseEntity resp = restTemplate.getForEntity("https://jsonplaceholder.typicode.com/posts?userId=" +userId, String.class); + return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null; + } + + public String addPost(ModelMap newBlogPost) { + return "If this were a real post, it would have added the form fields to a repository"; + } + + public String updatePost(ModelMap oldBlogPost) { + return "If this were a real post, it would have updated the form fields associated with the postId in the repository"; + } + + public String patchPost(ModelMap oldBlogPost) { + return "If this were a real post, it would have patched the form fields associated with the postId in the repository"; + } + + public String deletePost(int postId) { + return "If this were a real post, it would have deleted the post associated with the postId from the repository"; + } + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder){ + return builder.build(); + } +} diff --git a/BlogPost/src/main/resources/application.yml b/BlogPost/src/main/resources/application.yml new file mode 100644 index 0000000..af0d3de --- /dev/null +++ b/BlogPost/src/main/resources/application.yml @@ -0,0 +1,12 @@ +spring: + security: + oauth2: + client: + registration: + github: + client-id: 29633ee192bc653fe467 + client-secret: 4dd48ffb4cf0a468660adb4e8d2fcc6e7efb475d + +#logging: +# level: +# org.springframework.security: DEBUG diff --git a/BlogPost/src/main/resources/static/BlogPosts.doc b/BlogPost/src/main/resources/static/BlogPosts.doc new file mode 100644 index 0000000..3c2d231 Binary files /dev/null and b/BlogPost/src/main/resources/static/BlogPosts.doc differ diff --git a/README.md b/BlogPost/src/main/resources/static/README.md similarity index 98% rename from README.md rename to BlogPost/src/main/resources/static/README.md index 03e902d..43a98fd 100644 --- a/README.md +++ b/BlogPost/src/main/resources/static/README.md @@ -1,65 +1,63 @@ -# BlogPost - -If you would like to see a version of these instructions that contains screenshots, please see BlogPosts.doc instead. - -In order to use GitHub as your “single sign-on”, you need to create an account, if you don’t already have one. -Navigate to the Profile page and enter your Name in the Name field, as shown below: - -Open the application code in your favorite IDE. I used Eclipse. I run the application by selecting the top most root, -right click, select Run As > Spring Boot App. This will build the application and run it. You should see something -like this in your IDE’s console: - -"Started BlogPostApp in 2.327 seconds (JVM running for 3.272)" - -Open a browser page and enter "localhost:8080", you should see a web page like this: - -Click the “click here” link. You should see: - -When you run the Simple app for the first time, you should see something like this: - -or this: - -Once you click the “Authorize tekknow” button, it will never ask for it again. From now on the application will let you right in -without having to login, hence the term “single sign-on”. - -Once you are authorized on GitHub you should see the full application web page that looks like this: - -Notice the “Logged in as TekKnow”. It extracted your name from GitHub. -When you click the “GET /posts” button, you should see something like this: - -And all available posts will be in the table. - -When you click the “GET /posts/1” button, you should see something like this: - -When you click the “GET /posts/1/comments” button, you should see something like this: - -When you click the “GET /comments?postId=1” button, you should see something like this: - -When you click the “GET/posts?userId=1” button, you should see something like this: - -When you enter data into the “POST /posts” form and click its button, you should see something like this: -"If this were a real post, it would have added the form fields to a repository" -Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" - -When you enter data into the “PUT /posts/1” form and click its button, you should see something like this: -"If this were a real post, it would have updated the form fields associated with the postId in the repository" -Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" - -When you enter data into the “PATCH /posts/1” form and click its button, you should see something like this: -"If this were a real post, it would have patched the form fields associated with the postId in the repository" -Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" - -When you enter data into the “DELETE /posts/1” form and click its button, you should see something like this: -"If this were a real post, it would have deleted the post associated with the postId from the repository" -Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" - -I suspect these errors are related to Cross-Site Request Forgery (CSRF) or permission issues. -However, they are occuring even before the form data is sent to the server, which is puzzling to me at the moment. - -As you study the code, you will notice that there are only two files, BlogPost.java and BlogPostService.java. -These are both in the "com.example" package. Normally I would have multiple packages like "controller", "model" -"service", "repository", "exception", etc., where there are many java files in each package. But since this -was a relatively small project, I just left them in the main com.example package. - - - +If you would like to see a version of these instructions that contains screenshots, please see BlogPosts.doc instead. + +In order to use GitHub as your “single sign-on”, you need to create an account, if you don’t already have one. +Navigate to the Profile page and enter your Name in the Name field, as shown below: + +Open the application code in your favorite IDE. I used Eclipse. I run the application by selecting the top most root, +right click, select Run As > Spring Boot App. This will build the application and run it. You should see something +like this in your IDE’s console: + +"Started BlogPostApp in 2.327 seconds (JVM running for 3.272)" + +Open a browser page and enter "localhost:8080", you should see a web page like this: + +Click the “click here” link. You should see: + +When you run the Simple app for the first time, you should see something like this: + +or this: + +Once you click the “Authorize tekknow” button, it will never ask for it again. From now on the application will let you right in +without having to login, hence the term “single sign-on”. + +Once you are authorized on GitHub you should see the full application web page that looks like this: + +Notice the “Logged in as TekKnow”. It extracted your name from GitHub. +When you click the “GET /posts” button, you should see something like this: + +And all available posts will be in the table. + +When you click the “GET /posts/1” button, you should see something like this: + +When you click the “GET /posts/1/comments” button, you should see something like this: + +When you click the “GET /comments?postId=1” button, you should see something like this: + +When you click the “GET/posts?userId=1” button, you should see something like this: + +When you enter data into the “POST /posts” form and click its button, you should see something like this: +"If this were a real post, it would have added the form fields to a repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +When you enter data into the “PUT /posts/1” form and click its button, you should see something like this: +"If this were a real post, it would have updated the form fields associated with the postId in the repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +When you enter data into the “PATCH /posts/1” form and click its button, you should see something like this: +"If this were a real post, it would have patched the form fields associated with the postId in the repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +When you enter data into the “DELETE /posts/1” form and click its button, you should see something like this: +"If this were a real post, it would have deleted the post associated with the postId from the repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +I suspect these errors are related to Cross-Site Request Forgery (CSRF) or permission issues. +However, they are occuring even before the form data is sent to the server, which is puzzling to me at the moment. + +As you study the code, you will notice that there are only two files, BlogPost.java and BlogPostService.java. +These are both in the "com.example" package. Normally I would have multiple packages like "controller", "model" +"service", "repository", "exception", etc., where there are many java files in each package. But since this +was a relatively small project, I just left them in the main com.example package. + + + diff --git a/BlogPost/src/main/resources/static/index.html b/BlogPost/src/main/resources/static/index.html new file mode 100644 index 0000000..7352701 --- /dev/null +++ b/BlogPost/src/main/resources/static/index.html @@ -0,0 +1,222 @@ + + + + + +Demo + + + + + + + + +

Charter Code Challenge

+
+ With GitHub: click here +
+ + + + + \ No newline at end of file diff --git a/BlogPost/src/main/resources/static/~$ogPosts.doc b/BlogPost/src/main/resources/static/~$ogPosts.doc new file mode 100644 index 0000000..6fe460f Binary files /dev/null and b/BlogPost/src/main/resources/static/~$ogPosts.doc differ diff --git a/BlogPost/src/test/java/com/example/BlogPostTests.java b/BlogPost/src/test/java/com/example/BlogPostTests.java new file mode 100644 index 0000000..cebf478 --- /dev/null +++ b/BlogPost/src/test/java/com/example/BlogPostTests.java @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.example; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +public class BlogPostTests { + + @Test + public void contextLoads() { + } + +} diff --git a/BlogPost/target/classes/META-INF/MANIFEST.MF b/BlogPost/target/classes/META-INF/MANIFEST.MF new file mode 100644 index 0000000..d6001fd --- /dev/null +++ b/BlogPost/target/classes/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Implementation-Title: BlogPost +Implementation-Version: 0.0.1-SNAPSHOT +Build-Jdk-Spec: 1.8 +Created-By: Maven Integration for Eclipse + diff --git a/BlogPost/target/classes/META-INF/maven/com.example/blogpost/pom.properties b/BlogPost/target/classes/META-INF/maven/com.example/blogpost/pom.properties new file mode 100644 index 0000000..f6ecdb1 --- /dev/null +++ b/BlogPost/target/classes/META-INF/maven/com.example/blogpost/pom.properties @@ -0,0 +1,7 @@ +#Generated by Maven Integration for Eclipse +#Thu Oct 01 20:16:56 MDT 2020 +version=0.0.1-SNAPSHOT +groupId=com.example +m2e.projectName=BlogPost +m2e.projectLocation=C\:\\Users\\Greg\\Projects\\BlogPost +artifactId=blogpost diff --git a/BlogPost/target/classes/META-INF/maven/com.example/blogpost/pom.xml b/BlogPost/target/classes/META-INF/maven/com.example/blogpost/pom.xml new file mode 100644 index 0000000..42de451 --- /dev/null +++ b/BlogPost/target/classes/META-INF/maven/com.example/blogpost/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + com.example + blogpost + 0.0.1-SNAPSHOT + jar + + BlogPost + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-web + + + org.webjars + js-cookie + 2.1.0 + + + org.webjars + jquery + 2.1.1 + + + org.webjars + bootstrap + 3.2.0 + + + org.webjars + webjars-locator-core + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/BlogPost/target/classes/META-INF/maven/com.example/social-logout/pom.properties b/BlogPost/target/classes/META-INF/maven/com.example/social-logout/pom.properties new file mode 100644 index 0000000..2fb8d33 --- /dev/null +++ b/BlogPost/target/classes/META-INF/maven/com.example/social-logout/pom.properties @@ -0,0 +1,7 @@ +#Generated by Maven Integration for Eclipse +#Thu Oct 01 20:06:28 MDT 2020 +version=0.0.1-SNAPSHOT +groupId=com.example +m2e.projectName=BlogPost +m2e.projectLocation=C\:\\Users\\Greg\\Projects\\BlogPost +artifactId=social-logout diff --git a/BlogPost/target/classes/META-INF/maven/com.example/social-logout/pom.xml b/BlogPost/target/classes/META-INF/maven/com.example/social-logout/pom.xml new file mode 100644 index 0000000..f314726 --- /dev/null +++ b/BlogPost/target/classes/META-INF/maven/com.example/social-logout/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + com.example + social-logout + 0.0.1-SNAPSHOT + jar + + social-logout + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-web + + + org.webjars + js-cookie + 2.1.0 + + + org.webjars + jquery + 2.1.1 + + + org.webjars + bootstrap + 3.2.0 + + + org.webjars + webjars-locator-core + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/BlogPost/target/classes/application.yml b/BlogPost/target/classes/application.yml new file mode 100644 index 0000000..af0d3de --- /dev/null +++ b/BlogPost/target/classes/application.yml @@ -0,0 +1,12 @@ +spring: + security: + oauth2: + client: + registration: + github: + client-id: 29633ee192bc653fe467 + client-secret: 4dd48ffb4cf0a468660adb4e8d2fcc6e7efb475d + +#logging: +# level: +# org.springframework.security: DEBUG diff --git a/BlogPost/target/classes/com/example/BlogPost.class b/BlogPost/target/classes/com/example/BlogPost.class new file mode 100644 index 0000000..46e1770 Binary files /dev/null and b/BlogPost/target/classes/com/example/BlogPost.class differ diff --git a/BlogPost/target/classes/com/example/BlogPostApp.class b/BlogPost/target/classes/com/example/BlogPostApp.class new file mode 100644 index 0000000..0c53fb5 Binary files /dev/null and b/BlogPost/target/classes/com/example/BlogPostApp.class differ diff --git a/BlogPost/target/classes/com/example/BlogPostService.class b/BlogPost/target/classes/com/example/BlogPostService.class new file mode 100644 index 0000000..7d93fe7 Binary files /dev/null and b/BlogPost/target/classes/com/example/BlogPostService.class differ diff --git a/BlogPost/target/classes/static/README.md b/BlogPost/target/classes/static/README.md new file mode 100644 index 0000000..67a6315 --- /dev/null +++ b/BlogPost/target/classes/static/README.md @@ -0,0 +1,63 @@ +If you would like to see a version of these instructions that contains screenshots, please see BlogPosts.doc instead. + +In order to use GitHub as your “single sign-on”, you need to create an account, if you don’t already have one. +Navigate to the Profile page and enter your Name in the Name field, as shown below: + +Open the application code in your favorite IDE. I used Eclipse. I run the application by selecting the top most root, +right click, select Run As > Spring Boot App. This will build the application and run it. You should see something +like this in your IDE’s console: + +"Started BlogPost in 2.327 seconds (JVM running for 3.272)" + +Open a browser page and enter "localhost:8080", you should see a web page like this: + +Click the “click here” link. You should see: + +When you run the Simple app for the first time, you should see something like this: + +or this: + +Once you click the “Authorize tekknow” button, it will never ask for it again. From now on the application will let you right in +without having to login, hence the term “single sign-on”. + +Once you are authorized on GitHub you should see the full application web page that looks like this: + +Notice the “Logged in as TekKnow”. It extracted your name from GitHub. +When you click the “GET /posts” button, you should see something like this: + +And all available posts will be in the table. + +When you click the “GET /posts/1” button, you should see something like this: + +When you click the “GET /posts/1/comments” button, you should see something like this: + +When you click the “GET /comments?postId=1” button, you should see something like this: + +When you click the “GET/posts?userId=1” button, you should see something like this: + +When you enter data into the “POST /posts” form and click its button, you should see something like this: +"If this were a real post, it would have added the form fields to a repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +When you enter data into the “PUT /posts/1” form and click its button, you should see something like this: +"If this were a real post, it would have updated the form fields associated with the postId in the repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +When you enter data into the “PATCH /posts/1” form and click its button, you should see something like this: +"If this were a real post, it would have patched the form fields associated with the postId in the repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +When you enter data into the “DELETE /posts/1” form and click its button, you should see something like this: +"If this were a real post, it would have deleted the post associated with the postId from the repository" +Unfortunately, ran out of time. Unable to fix "There was an unexpected error (type=Forbidden, status=403)" + +I suspect these errors are related to Cross-Site Request Forgery (CSRF) or permission issues. +However, they are occuring even before the form data is sent to the server, which is puzzling to me at the moment. + +As you study the code, you will notice that there are only two files, BlogPost.java and BlogPostService.java. +These are both in the "com.example" package. Normally I would have multiple packages like "controller", "model" +"service", "repository", "exception", etc., where there are many java files in each package. But since this +was a relatively small project, I just left them in the main com.example package. + + + diff --git a/BlogPost/target/classes/static/index.html b/BlogPost/target/classes/static/index.html new file mode 100644 index 0000000..7352701 --- /dev/null +++ b/BlogPost/target/classes/static/index.html @@ -0,0 +1,222 @@ + + + + + +Demo + + + + + + + + +

Charter Code Challenge

+
+ With GitHub: click here +
+ + + + + \ No newline at end of file diff --git a/BlogPost/target/test-classes/com/example/BlogPostTests.class b/BlogPost/target/test-classes/com/example/BlogPostTests.class new file mode 100644 index 0000000..da68a0c Binary files /dev/null and b/BlogPost/target/test-classes/com/example/BlogPostTests.class differ