JWT refractor

This commit is contained in:
jeffcheasey88 2023-02-24 00:08:17 +01:00
parent c915a96535
commit 64a88f7282
9 changed files with 142 additions and 43 deletions

View file

@ -48,7 +48,7 @@ public class Main {
Class.forName("com.mysql.cj.jdbc.Driver"); Class.forName("com.mysql.cj.jdbc.Driver");
Router router = new Router(); Router router = new Router(new DatabaseRepository(config));
router.setDefault(new Response(){ router.setDefault(new Response(){
@ -66,19 +66,19 @@ public class Main {
} }
}); });
initRoutes(router, new DatabaseRepository(config)); initRoutes(router);
startWebServer(config, router); startWebServer(config, router);
} }
private static void initRoutes(Router router, DatabaseRepository repo) { private static void initRoutes(Router router) {
router.register(new ChapterElement(repo)); router.register(new ChapterElement(router.getDataBase()));
router.register(new ChapterList(repo)); router.register(new ChapterList(router.getDataBase()));
router.register(new PuzzleElement(repo)); router.register(new PuzzleElement(router.getDataBase()));
router.register(new Register(repo)); router.register(new Register(router.getDataBase(), router));
router.register(new Login(repo)); router.register(new Login(router.getDataBase(), router));
router.register(new Result(repo)); router.register(new Result(router.getDataBase()));
router.register(new PuzzleResponse(repo)); router.register(new PuzzleResponse(router.getDataBase()));
} }
private static void startWebServer(Configuration config, Router router) throws IOException { private static void startWebServer(Configuration config, Router router) throws IOException {

View file

@ -0,0 +1,45 @@
package be.jeffcheasey88.peeratcode.model;
public class Player {
private String pseudo;
private String email;
private String firstname;
private String lastname;
private String description;
private String sgroup;
public Player(String pseudo, String email, String firstname, String lastname, String description, String sgroup){
this.pseudo = pseudo;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.description = description;
this.sgroup = sgroup;
}
public String getPseudo(){
return this.pseudo;
}
public String getEmail(){
return this.email;
}
public String getFirstname(){
return this.firstname;
}
public String getLastname(){
return this.lastname;
}
public String getDescription(){
return this.description;
}
public String getGroup(){
return this.sgroup;
}
}

View file

@ -1,19 +1,21 @@
package be.jeffcheasey88.peeratcode.repository; package be.jeffcheasey88.peeratcode.repository;
import be.jeffcheasey88.peeratcode.Configuration;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Puzzle;
import com.password4j.Hash;
import com.password4j.Password;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.password4j.Hash;
import com.password4j.Password;
import be.jeffcheasey88.peeratcode.Configuration;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Puzzle;
public class DatabaseRepository { public class DatabaseRepository {
private static final String SPECIFIC_PUZZLE_QUERY = "SELECT * FROM puzzles WHERE id_puzzle = ?"; private static final String SPECIFIC_PUZZLE_QUERY = "SELECT * FROM puzzles WHERE id_puzzle = ?";
private static final String SPECIFIC_CHAPTER_QUERY = "SELECT * FROM chapters WHERE id_chapter = ?"; private static final String SPECIFIC_CHAPTER_QUERY = "SELECT * FROM chapters WHERE id_chapter = ?";
@ -22,7 +24,7 @@ public class DatabaseRepository {
private static final String CHECK_PSEUDO_AVAILABLE_QUERY = "SELECT * FROM players WHERE pseudo = ?"; private static final String CHECK_PSEUDO_AVAILABLE_QUERY = "SELECT * FROM players WHERE pseudo = ?";
private static final String CHECK_EMAIL_AVAILABLE_QUERY = "SELECT * FROM players WHERE email = ?"; private static final String CHECK_EMAIL_AVAILABLE_QUERY = "SELECT * FROM players WHERE email = ?";
private static final String REGISTER_QUERY = "INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, sgroup, avatar) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; private static final String REGISTER_QUERY = "INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, sgroup, avatar) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
private static final String CHECK_PASSWORD = "SELECT passwd FROM players WHERE pseudo=?"; private static final String CHECK_PASSWORD = "SELECT id_player, passwd FROM players WHERE pseudo=?";
private static final String SCORE = "SELECT score FROM completions WHERE fk_player = ? AND fk_puzzle = ?"; private static final String SCORE = "SELECT score FROM completions WHERE fk_player = ? AND fk_puzzle = ?";
private static final String GET_PUZZLE_SOLUTION = "SELECT soluce FROM puzzles WHERE id_puzzle=?"; private static final String GET_PUZZLE_SOLUTION = "SELECT soluce FROM puzzles WHERE id_puzzle=?";
private static final String GET_PUZZLE_SCORE_MAX = "SELECT score_max FROM puzzles WHERE id_puzzle=?"; private static final String GET_PUZZLE_SCORE_MAX = "SELECT score_max FROM puzzles WHERE id_puzzle=?";
@ -192,11 +194,11 @@ public class DatabaseRepository {
* @param avatar The avatar of the user * @param avatar The avatar of the user
* @return True if the user was registered, false if an error occurred * @return True if the user was registered, false if an error occurred
*/ */
public boolean register(String pseudo, String email, String password, String firstname, String lastname, String description, String sgroup, String avatar) { public int register(String pseudo, String email, String password, String firstname, String lastname, String description, String sgroup, String avatar) {
Hash hash = Password.hash(password).withArgon2(); Hash hash = Password.hash(password).withArgon2();
try { try {
ensureConnection(); ensureConnection();
PreparedStatement statement = con.prepareStatement(REGISTER_QUERY); PreparedStatement statement = con.prepareStatement(REGISTER_QUERY, Statement.RETURN_GENERATED_KEYS);
statement.setString(1, pseudo); statement.setString(1, pseudo);
statement.setString(2, email); statement.setString(2, email);
statement.setString(3, hash.getResult()); statement.setString(3, hash.getResult());
@ -205,11 +207,14 @@ public class DatabaseRepository {
statement.setString(6, description); statement.setString(6, description);
statement.setString(7, sgroup); statement.setString(7, sgroup);
statement.setString(8, avatar); statement.setString(8, avatar);
return statement.executeUpdate() == 1; if(statement.executeUpdate() == 1){
ResultSet inserted = statement.getGeneratedKeys();
if(inserted.next()) return inserted.getInt("id_player");
}
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} }
return false; return -1;
} }
/** /**
@ -217,9 +222,9 @@ public class DatabaseRepository {
* *
* @param username The username of the user * @param username The username of the user
* @param password The password of the user * @param password The password of the user
* @return True if the user's information are correct, false otherwise (or if an error occurred) * @return id the id of the user, -1 if not login successefuly
*/ */
public boolean login(String username, String password) { public int login(String username, String password) {
try { try {
ensureConnection(); ensureConnection();
PreparedStatement statement = con.prepareStatement(CHECK_PASSWORD); PreparedStatement statement = con.prepareStatement(CHECK_PASSWORD);
@ -227,12 +232,11 @@ public class DatabaseRepository {
ResultSet result = statement.executeQuery(); ResultSet result = statement.executeQuery();
if (result.next()) { if (result.next()) {
String hashedPassword = result.getString("passwd"); String hashedPassword = result.getString("passwd");
return Password.check(password, hashedPassword).withArgon2(); if(Password.check(password, hashedPassword).withArgon2()) return result.getInt("id_player");
} }
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace();
} }
return false; return -1;
} }
public byte[] getPuzzleSolution(int puzzleId) { public byte[] getPuzzleSolution(int puzzleId) {

View file

@ -3,6 +3,10 @@ package be.jeffcheasey88.peeratcode.routes;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository; import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
@ -10,14 +14,17 @@ import be.jeffcheasey88.peeratcode.webserver.HttpReader;
import be.jeffcheasey88.peeratcode.webserver.HttpUtil; import be.jeffcheasey88.peeratcode.webserver.HttpUtil;
import be.jeffcheasey88.peeratcode.webserver.HttpWriter; import be.jeffcheasey88.peeratcode.webserver.HttpWriter;
import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Response;
import be.jeffcheasey88.peeratcode.webserver.Router;
import be.jeffcheasey88.peeratcode.webserver.User; import be.jeffcheasey88.peeratcode.webserver.User;
public class Login implements Response { public class Login implements Response {
private final DatabaseRepository databaseRepo; private DatabaseRepository databaseRepo;
private Router router;
public Login(DatabaseRepository databaseRepo) { public Login(DatabaseRepository databaseRepo, Router router){
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
this.router = router;
} }
@Override @Override
@ -27,8 +34,11 @@ public class Login implements Response {
if (informations != null) { if (informations != null) {
String pseudo = (String) informations.get("pseudo"); String pseudo = (String) informations.get("pseudo");
String password = (String) informations.get("passwd"); String password = (String) informations.get("passwd");
if (databaseRepo.login(pseudo, password)) { int id;
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); if ((id = databaseRepo.login(pseudo, password)) >= 0){
HttpUtil.responseHeaders(writer, 200,
"Access-Control-Allow-Origin: *",
"Authorization: Bearer "+this.router.createAuthUser(id));
return; return;
} }
} }

View file

@ -22,8 +22,12 @@ public class PuzzleResponse implements Response {
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.skipHeaders(reader); if(user == null){
HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *");
return;
}
HttpUtil.skipHeaders(reader);
int puzzleId = Integer.parseInt(matcher.group(1)); int puzzleId = Integer.parseInt(matcher.group(1));
byte[] response; byte[] response;
byte[] fileName; byte[] fileName;

View file

@ -10,14 +10,17 @@ import be.jeffcheasey88.peeratcode.webserver.HttpReader;
import be.jeffcheasey88.peeratcode.webserver.HttpUtil; import be.jeffcheasey88.peeratcode.webserver.HttpUtil;
import be.jeffcheasey88.peeratcode.webserver.HttpWriter; import be.jeffcheasey88.peeratcode.webserver.HttpWriter;
import be.jeffcheasey88.peeratcode.webserver.Response; import be.jeffcheasey88.peeratcode.webserver.Response;
import be.jeffcheasey88.peeratcode.webserver.Router;
import be.jeffcheasey88.peeratcode.webserver.User; import be.jeffcheasey88.peeratcode.webserver.User;
public class Register implements Response { public class Register implements Response {
private final DatabaseRepository databaseRepo; private DatabaseRepository databaseRepo;
private Router router;
public Register(DatabaseRepository databaseRepo) { public Register(DatabaseRepository databaseRepo, Router router) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
this.router = router;
} }
@Override @Override
@ -45,8 +48,11 @@ public class Register implements Response {
boolean pseudoAvailable = databaseRepo.checkPseudoAvailability(pseudo); boolean pseudoAvailable = databaseRepo.checkPseudoAvailability(pseudo);
boolean emailAvailable = databaseRepo.checkEmailAvailability(email); boolean emailAvailable = databaseRepo.checkEmailAvailability(email);
if (pseudoAvailable && emailAvailable) { if (pseudoAvailable && emailAvailable) {
if (databaseRepo.register(pseudo, email, password, firstname, lastname, description, group, avatar)){ int id;
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *"); if ((id = databaseRepo.register(pseudo, email, password, firstname, lastname, description, group, avatar)) >= 0){
HttpUtil.responseHeaders(writer, 200,
"Access-Control-Allow-Origin: *",
"Authorization: Bearer "+this.router.createAuthUser(id));
return; return;
} }
} else { } else {

View file

@ -20,9 +20,14 @@ public class Result implements Response{
@Override @Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
if(user == null){
HttpUtil.responseHeaders(writer, 403, "Access-Control-Allow-Origin: *");
return;
}
int puzzle = Integer.parseInt(matcher.group(1)); int puzzle = Integer.parseInt(matcher.group(1));
int score = this.repo.getScore(0, puzzle); int score = this.repo.getScore(user.getId(), puzzle);
if(score < 0) { if(score < 0) {
HttpUtil.responseHeaders(writer, 425, "Access-Control-Allow-Origin: *"); HttpUtil.responseHeaders(writer, 425, "Access-Control-Allow-Origin: *");
}else{ }else{

View file

@ -6,18 +6,30 @@ import java.util.regex.Matcher;
import org.jose4j.jwk.RsaJsonWebKey; import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator; import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.lang.JoseException;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Router{ public class Router{
private List<Response> responses; private List<Response> responses;
private Response noFileFound; private Response noFileFound;
private RsaJsonWebKey rsaJsonWebKey; private RsaJsonWebKey rsaJsonWebKey;
private DatabaseRepository repo;
public Router() throws Exception{ public Router(DatabaseRepository repo) throws Exception{
this.repo = repo;
this.responses = new ArrayList<>(); this.responses = new ArrayList<>();
this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
} }
public DatabaseRepository getDataBase(){
return this.repo;
}
public void register(Response response){ public void register(Response response){
this.responses.add(response); this.responses.add(response);
} }
@ -42,4 +54,23 @@ public class Router{
public RsaJsonWebKey getWebKey(){ public RsaJsonWebKey getWebKey(){
return this.rsaJsonWebKey; return this.rsaJsonWebKey;
} }
public String createAuthUser(int id) throws JoseException{
JwtClaims claims = new JwtClaims();
claims.setIssuer("Issuer"); // who creates the token and signs it
claims.setAudience("Audience"); // to whom the token is intended to be sent
claims.setExpirationTimeMinutesInTheFuture(10); // time when the token will expire (10 minutes from now)
claims.setGeneratedJwtId(); // a unique identifier for the token
claims.setIssuedAtToNow(); // when the token was issued/created (now)
claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
claims.setClaim("id", id);
JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toJson());
jws.setKey(rsaJsonWebKey.getPrivateKey());
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
return jws.getCompactSerialization();
}
} }

View file

@ -4,18 +4,12 @@ import org.jose4j.jwt.JwtClaims;
public class User { public class User {
private String username;
private int id; private int id;
public User(JwtClaims jwtClaims){ public User(JwtClaims jwtClaims){
this.username = (String) jwtClaims.getClaimValue("username");
this.id = (int) jwtClaims.getClaimValue("id"); this.id = (int) jwtClaims.getClaimValue("id");
} }
public String getUsername(){
return username;
}
public int getId(){ public int getId(){
return this.id; return this.id;
} }