server-side auth handling and managing endpoints

This commit is contained in:
Zhongheng Liu 2024-04-01 23:46:05 +03:00
commit b128628f49
No known key found for this signature in database
3 changed files with 76 additions and 13 deletions

View file

@ -2,61 +2,113 @@ package me.imsonmia.epqapi.controller;
import java.util.Date; import java.util.Date;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import org.aspectj.internal.lang.annotation.ajcDeclareAnnotation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import io.micrometer.common.lang.Nullable; import io.micrometer.common.lang.Nullable;
import lombok.Data;
import lombok.Setter;
import me.imsonmia.epqapi.model.User;
import me.imsonmia.epqapi.repository.UserRepository; import me.imsonmia.epqapi.repository.UserRepository;
@Controller
@RequestMapping("/api/v1") @RequestMapping("/api/v1")
public class AuthController { public class AuthController {
@Autowired
private UserRepository userRepository; private UserRepository userRepository;
private Logger logger = LoggerFactory.getLogger(getClass()); private Logger logger = LoggerFactory.getLogger(getClass());
/** /**
* AuthData * AuthData
*/ */
@Data
public class AuthData { public class AuthData {
private boolean success; private boolean success;
private boolean hasProfile; private boolean hasProfile;
private boolean exists; private boolean exists;
private String authMessage; private String authMessage;
private long authResponseTimestampMillis; private long authResponseTimestampMillis;
public AuthData(boolean success, boolean hasProfile, @Nullable String authMessage) { public AuthData(boolean success, boolean hasProfile, boolean exists, @Nullable String authMessage) {
this.success = success; this.success = success;
this.hasProfile = hasProfile; this.hasProfile = hasProfile;
this.exists = exists;
this.authMessage = authMessage == null ? "" : authMessage; this.authMessage = authMessage == null ? "" : authMessage;
this.authResponseTimestampMillis = new Date().getTime(); this.authResponseTimestampMillis = new Date().getTime();
} }
} }
public abstract class AuthRequestData { public static class AuthRequestData {
private String userName; private String userName;
private String userPasswordHash; private String userPasswordHash;
public String getUserName() {
return userName;
}
public String getUserPasswordHash() {
return userPasswordHash;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setUserPasswordHash(String userPasswordHash) {
this.userPasswordHash = userPasswordHash;
}
public AuthRequestData() {
}
public AuthRequestData(String userName, String userPasswordHash) { public AuthRequestData(String userName, String userPasswordHash) {
this.userName = userName; this.userName = userName;
this.userPasswordHash = userPasswordHash; this.userPasswordHash = userPasswordHash;
} }
} }
@Data
public static class RegisterRequestData {
@Setter
private String userName;
@Setter
private String newUserPassword;
public RegisterRequestData() {}
public RegisterRequestData(String userName, String newUserPassword) {
this.userName = userName;
this.newUserPassword = newUserPassword;
}
}
@PostMapping("/register")
public ResponseEntity<AuthData> authRegister(@RequestBody RegisterRequestData registerRequestData) {
if (userRepository.existsByUserName(registerRequestData.userName)) {
return new ResponseEntity<>(new AuthData(false, true, true, "Login failed. Username already exists."), null,
200);
}
User newUser = new User(UUID.randomUUID().toString(), registerRequestData.userName, new Date(), new Date(),
registerRequestData.newUserPassword);
userRepository.save(newUser);
return new ResponseEntity<AuthData>(new AuthData(true, true, true, "Login successful. Used registration endpoint."),
null, 200);
}
/** /**
* Authentication HTTPS endpoint used instead of client-side verification which * Authentication HTTPS endpoint used instead of client-side verification which
* is unsafe * is unsafe
*/ */
@PostMapping("/auth") @PostMapping(value = "/auth",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AuthData> authLogin(@RequestBody AuthRequestData authRequestData) { public ResponseEntity<AuthData> authLogin(@RequestBody AuthRequestData authRequestData) {
if (!userRepository.existsByUserName(authRequestData.userName)) { if (!userRepository.existsByUserName(authRequestData.userName)) {
logger.info("Invalid login since user doesn't exist"); logger.info("Invalid login since user doesn't exist");
return new ResponseEntity<AuthData>(new AuthData( return new ResponseEntity<AuthData>(new AuthData(
false,
false, false,
false, false,
"Login invalid: User doesn't exist in database."), "Login invalid: User doesn't exist in database."),
@ -64,10 +116,16 @@ public class AuthController {
200); 200);
} }
String pwdHash = userRepository.findByUserName(authRequestData.userName).get().getPasswordHash(); String pwdHash = userRepository.findByUserName(authRequestData.userName).get().getPasswordHash();
if (pwdHash != authRequestData.userPasswordHash) { // NOTE Cannot use straight == comparison. Must use equals function @ 22:17 2024-04-01
return new ResponseEntity<>(new AuthData(false, true, "Login invalid: Password incorrect."), null, 200); if (!pwdHash.equals(authRequestData.getUserPasswordHash())) {
return new ResponseEntity<>(new AuthData(
false,
true,
true,
"Login invalid: Password incorrect."
), null, 200);
} else { } else {
return new ResponseEntity<>(new AuthData(true, true, "Authentication success"), null, 200); return new ResponseEntity<>(new AuthData(true, true, true, "Authentication success"), null, 200);
} }
} }
} }

View file

@ -1,5 +1,6 @@
package me.imsonmia.epqapi.controller; package me.imsonmia.epqapi.controller;
import org.antlr.v4.runtime.misc.NotNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.handler.annotation.SendTo;
@ -13,6 +14,7 @@ import me.imsonmia.epqapi.repository.MessageRepository;
public class MessageController { public class MessageController {
@Autowired @Autowired
private MessageRepository repository; private MessageRepository repository;
@MessageMapping("/chat") @MessageMapping("/chat")
@SendTo("/sub/chat") @SendTo("/sub/chat")
public Message messageHandler(Message message) throws Exception { public Message messageHandler(Message message) throws Exception {
@ -21,9 +23,9 @@ public class MessageController {
// Forward message to subscribers of Stomp endpoint // Forward message to subscribers of Stomp endpoint
return message; return message;
} }
// @GetMapping("/msg/{id}") // @GetMapping("/msg/{id}")
// public ChatMessage getMessageById(@PathVariable(value = "id") Long id) { // public ChatMessage getMessageById(@PathVariable(value = "id") Long id) {
// return chatMessageRepository.findById(id).get(); // return chatMessageRepository.findById(id).get();
// } // }
} }

View file

@ -19,6 +19,9 @@ public class User {
Long id; Long id;
@Getter @Getter
@Setter @Setter
String userId;
@Getter
@Setter
String userName; String userName;
@Getter @Getter
@Setter @Setter
@ -34,8 +37,8 @@ public class User {
} }
public User(Long id, String userName, Date dateJoined, Date lastSeen, String passwordHash) { public User(String userId, String userName, Date dateJoined, Date lastSeen, String passwordHash) {
this.id = id; this.userId = userId;
this.userName = userName; this.userName = userName;
this.dateJoined = dateJoined; this.dateJoined = dateJoined;
this.lastSeen = lastSeen; this.lastSeen = lastSeen;