From 855bf817e137df5f57245dcd3abc75258ff511e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lorenzo=20Dellac=C3=A0?= Date: Tue, 3 Aug 2021 17:55:45 +0200 Subject: [PATCH] Implement JWT, registration, login and comment posting This is still a demo, to learn the framework. Most of this will probably we rewritten more elengantly. --- pom.xml | 5 ++ .../comments/CommentingServer.java | 1 + .../net/mindoverflow/comments/WebServer.java | 63 ---------------- .../comments/utils/SecurityUtil.java | 30 ++++++++ .../comments/webapp/WebServer.java | 28 +++++++ .../webapp/controllers/CommentController.java | 59 +++++++++++++++ .../controllers/CommentsController.java | 31 ++++++++ .../webapp/controllers/LoginController.java | 75 +++++++++++++++++++ .../controllers/RegisterController.java | 61 +++++++++++++++ src/main/resources/templates/comment.ftl | 12 +++ src/main/resources/templates/login.ftl | 4 +- src/main/resources/templates/register.ftl | 14 ++++ 12 files changed, 318 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/net/mindoverflow/comments/WebServer.java create mode 100644 src/main/java/net/mindoverflow/comments/utils/SecurityUtil.java create mode 100644 src/main/java/net/mindoverflow/comments/webapp/WebServer.java create mode 100644 src/main/java/net/mindoverflow/comments/webapp/controllers/CommentController.java create mode 100644 src/main/java/net/mindoverflow/comments/webapp/controllers/CommentsController.java create mode 100644 src/main/java/net/mindoverflow/comments/webapp/controllers/LoginController.java create mode 100644 src/main/java/net/mindoverflow/comments/webapp/controllers/RegisterController.java create mode 100644 src/main/resources/templates/comment.ftl create mode 100644 src/main/resources/templates/register.ftl diff --git a/pom.xml b/pom.xml index c196b10..1f0b1b1 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,11 @@ pippo-jetty 1.13.1 + + com.auth0 + java-jwt + 3.10.3 + diff --git a/src/main/java/net/mindoverflow/comments/CommentingServer.java b/src/main/java/net/mindoverflow/comments/CommentingServer.java index a1ad328..0409114 100644 --- a/src/main/java/net/mindoverflow/comments/CommentingServer.java +++ b/src/main/java/net/mindoverflow/comments/CommentingServer.java @@ -1,5 +1,6 @@ package net.mindoverflow.comments; +import net.mindoverflow.comments.webapp.WebServer; import ro.pippo.core.Pippo; public class CommentingServer diff --git a/src/main/java/net/mindoverflow/comments/WebServer.java b/src/main/java/net/mindoverflow/comments/WebServer.java deleted file mode 100644 index ee51914..0000000 --- a/src/main/java/net/mindoverflow/comments/WebServer.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.mindoverflow.comments; - -import ro.pippo.core.Application; -import ro.pippo.core.route.TrailingSlashHandler; - -import java.awt.*; -import java.util.*; - -public class WebServer extends Application -{ - - String username = "lollo"; - String userpass = "password"; - - @Override - public void onInit() - { - - POST("/login", routeContext -> { - System.out.println("POST"); - - String name = routeContext.getParameter("username").toString(); - System.out.println(name); - - String password = routeContext.getParameter("password").toString(); - System.out.println(password); - - - Map model = new HashMap<>(); - - if(name.isEmpty()) - { - model.put("errorMessage", "Empty username!"); - } - else if (password.isEmpty()) - { - model.put("errorMessage", "Empty password!"); - } - else if(!name.equals(username) || !password.equals(userpass)) - { - model.put("errorMessage", "Wrong username or password!"); - - } - else - { - model.put("errorMessage", "Logged in!"); - } - - - routeContext.render("login", model); - - }); - - GET("/login", routeContext -> - { - System.out.println("GET"); - - routeContext.render("login"); - }); - - ANY("/.*", new TrailingSlashHandler(false)); // remove trailing slash - } -} diff --git a/src/main/java/net/mindoverflow/comments/utils/SecurityUtil.java b/src/main/java/net/mindoverflow/comments/utils/SecurityUtil.java new file mode 100644 index 0000000..257594f --- /dev/null +++ b/src/main/java/net/mindoverflow/comments/utils/SecurityUtil.java @@ -0,0 +1,30 @@ +package net.mindoverflow.comments.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; + +import java.nio.charset.StandardCharsets; +import java.time.ZonedDateTime; +import java.util.Date; + +public class SecurityUtil +{ + public static final int JWT_EXPIRY_MINUTES = 60; + + public static String generateJWT(String claimName, String claimValue, Date expiry) + { + + Algorithm algorithm = Algorithm.HMAC256("minafewnf0928f392".getBytes(StandardCharsets.UTF_8)); + return JWT.create() + .withIssuer("CommentingServer") + .withClaim(claimName, claimValue) + .withExpiresAt(expiry) + .sign(algorithm); + } + + public static String generateJWT(String claimName, String claimValue) + { + Date expiry = Date.from(ZonedDateTime.now().plusMinutes(JWT_EXPIRY_MINUTES).toInstant()); + return generateJWT(claimName, claimValue, expiry); + } +} diff --git a/src/main/java/net/mindoverflow/comments/webapp/WebServer.java b/src/main/java/net/mindoverflow/comments/webapp/WebServer.java new file mode 100644 index 0000000..95c75d3 --- /dev/null +++ b/src/main/java/net/mindoverflow/comments/webapp/WebServer.java @@ -0,0 +1,28 @@ +package net.mindoverflow.comments.webapp; + +import net.mindoverflow.comments.webapp.controllers.CommentController; +import net.mindoverflow.comments.webapp.controllers.CommentsController; +import net.mindoverflow.comments.webapp.controllers.LoginController; +import net.mindoverflow.comments.webapp.controllers.RegisterController; +import ro.pippo.controller.ControllerApplication; +import ro.pippo.core.route.TrailingSlashHandler; + +import java.util.HashMap; + +public class WebServer extends ControllerApplication +{ + + public static final HashMap userAndPassword = new HashMap<>(); + public static final HashMap jwtAndUser = new HashMap<>(); + public static final HashMap userAndComment = new HashMap<>(); + + @Override + public void onInit() + { + + addControllers(new LoginController(), new RegisterController(), new CommentsController(), new CommentController()); + + ANY("/.*", new TrailingSlashHandler(false)); // remove trailing slash + + } +} diff --git a/src/main/java/net/mindoverflow/comments/webapp/controllers/CommentController.java b/src/main/java/net/mindoverflow/comments/webapp/controllers/CommentController.java new file mode 100644 index 0000000..1ac4264 --- /dev/null +++ b/src/main/java/net/mindoverflow/comments/webapp/controllers/CommentController.java @@ -0,0 +1,59 @@ +package net.mindoverflow.comments.webapp.controllers; + +import com.auth0.jwt.JWT; +import net.mindoverflow.comments.webapp.WebServer; +import ro.pippo.controller.Controller; +import ro.pippo.controller.GET; +import ro.pippo.controller.POST; +import ro.pippo.controller.Path; +import ro.pippo.controller.extractor.Param; + +import javax.servlet.http.Cookie; +import java.util.HashMap; +import java.util.Map; + +@Path("/comment") +public class CommentController extends Controller +{ + + @GET + public void getCommentPage() + { + Map model = new HashMap<>(); + getRouteContext().render("comment", model); + } + + @POST + public void addComment(@Param("comment") String comment, @Param("commentbtn") String commentbtn) + { + Cookie session = getRequest().getCookie("session"); + if(session == null) + { + System.out.println("null cookie"); + return; + } + + String jwtFromCookie = session.getValue(); + if(jwtFromCookie == null) + { + System.out.println("null jwt"); + return; + } + + String username = WebServer.jwtAndUser.get(jwtFromCookie); + if(username == null) + { + System.out.println("null user"); + return; + } + + // check if jwt is null, if saved in hashmap, and finally verify it with JWT.verify() + + if(commentbtn != null) + { + WebServer.userAndComment.put(username, comment); + } + + } + +} diff --git a/src/main/java/net/mindoverflow/comments/webapp/controllers/CommentsController.java b/src/main/java/net/mindoverflow/comments/webapp/controllers/CommentsController.java new file mode 100644 index 0000000..1151eaf --- /dev/null +++ b/src/main/java/net/mindoverflow/comments/webapp/controllers/CommentsController.java @@ -0,0 +1,31 @@ +package net.mindoverflow.comments.webapp.controllers; + +import net.mindoverflow.comments.webapp.WebServer; +import ro.pippo.controller.Controller; +import ro.pippo.controller.GET; +import ro.pippo.controller.Path; + +import java.util.ArrayList; +import java.util.List; + +@Path("/comments") +public class CommentsController extends Controller +{ + + @GET + public void getComments() + { + List lines = new ArrayList<>(); + lines.add("Comments:"); + + for(String user : WebServer.userAndComment.keySet()) + { + String comment = WebServer.userAndComment.get(user); + if(comment != null) lines.add(user + ": " + comment); + } + + getRouteContext().text().send(lines); + } + + +} diff --git a/src/main/java/net/mindoverflow/comments/webapp/controllers/LoginController.java b/src/main/java/net/mindoverflow/comments/webapp/controllers/LoginController.java new file mode 100644 index 0000000..597af86 --- /dev/null +++ b/src/main/java/net/mindoverflow/comments/webapp/controllers/LoginController.java @@ -0,0 +1,75 @@ +package net.mindoverflow.comments.webapp.controllers; + +import net.mindoverflow.comments.utils.SecurityUtil; +import net.mindoverflow.comments.webapp.WebServer; +import ro.pippo.controller.Controller; +import ro.pippo.controller.GET; +import ro.pippo.controller.POST; +import ro.pippo.controller.Path; +import ro.pippo.controller.extractor.Param; + +import java.util.HashMap; +import java.util.Map; + +@Path("/login") +public class LoginController extends Controller +{ + + @GET + public void getLogin() + { + getRouteContext().render("login"); + } + + @POST + public void handleLogin( + @Param("loginbtn") String loginbtn, + @Param("username") String username, + @Param("password") String password) + { + Map model = new HashMap<>(); + + if(username == null || username.isEmpty()) + { + model.put("message", "Empty username!"); + } + else if (password == null || password.isEmpty()) + { + model.put("message", "Empty password!"); + } else if(loginbtn != null) + { + System.out.println(loginbtn); + + if(!WebServer.userAndPassword.containsKey(username)) + { + model.put("message", "Unknown user!"); + } + else + { + String gottenPass = WebServer.userAndPassword.get(username); + if(!gottenPass.equals(password)) + { + model.put("message", "Wrong password!"); + } + else + { + model.put("message", "Valid data!"); + + // generate JWT + String jwt = SecurityUtil.generateJWT("username", username); + + // set JWT as cookie + getResponse().cookie("session", jwt, SecurityUtil.JWT_EXPIRY_MINUTES * 60 /* in seconds */); + + // store JWT in RAM + WebServer.jwtAndUser.put(jwt, username); + } + } + } + + System.out.println("User: " + username); + System.out.println("Pass: " + password); + + getRouteContext().render("login", model); + } +} diff --git a/src/main/java/net/mindoverflow/comments/webapp/controllers/RegisterController.java b/src/main/java/net/mindoverflow/comments/webapp/controllers/RegisterController.java new file mode 100644 index 0000000..e182a94 --- /dev/null +++ b/src/main/java/net/mindoverflow/comments/webapp/controllers/RegisterController.java @@ -0,0 +1,61 @@ +package net.mindoverflow.comments.webapp.controllers; + +import net.mindoverflow.comments.webapp.WebServer; +import ro.pippo.controller.Controller; +import ro.pippo.controller.GET; +import ro.pippo.controller.POST; +import ro.pippo.controller.Path; +import ro.pippo.controller.extractor.Param; + +import java.util.HashMap; +import java.util.Map; + +@Path("/register") +public class RegisterController extends Controller +{ + + @GET + public void getLogin() + { + getRouteContext().render("register"); + } + + @POST + public void handleLogin( + @Param("registerbtn") String registerbtn, + @Param("username") String username, + @Param("password") String password) + { + Map model = new HashMap<>(); + + if(username == null || username.isEmpty()) + { + model.put("message", "Empty username!"); + } + else if (password == null || password.isEmpty()) + { + model.put("message", "Empty password!"); + } + else if(registerbtn != null) + { + System.out.println(registerbtn); + + if(WebServer.userAndPassword.containsKey(username)) + { + model.put("message", "User already exists!"); + } + else + { + WebServer.userAndPassword.put(username, password); + model.put("message", "User created!"); + } + } + + System.out.println("User: " + username); + System.out.println("Pass: " + password); + + + getRouteContext().render("register", model); + } + +} diff --git a/src/main/resources/templates/comment.ftl b/src/main/resources/templates/comment.ftl new file mode 100644 index 0000000..aca66f5 --- /dev/null +++ b/src/main/resources/templates/comment.ftl @@ -0,0 +1,12 @@ + + + Send Comment + + +

Send Comment

+
+ + +
+ +
\ No newline at end of file diff --git a/src/main/resources/templates/login.ftl b/src/main/resources/templates/login.ftl index c40c368..a67c66e 100644 --- a/src/main/resources/templates/login.ftl +++ b/src/main/resources/templates/login.ftl @@ -4,11 +4,11 @@

Login Form

-
<#if errorMessage??>${errorMessage}
+
<#if message??>${message}
- +
\ No newline at end of file diff --git a/src/main/resources/templates/register.ftl b/src/main/resources/templates/register.ftl new file mode 100644 index 0000000..ef3b15c --- /dev/null +++ b/src/main/resources/templates/register.ftl @@ -0,0 +1,14 @@ + + + Register + + +

Registration Form

+
<#if message??>${message}
+
+ + + +
+ + \ No newline at end of file