Skip to content
This repository has been archived by the owner on Apr 1, 2024. It is now read-only.

Commit

Permalink
added token checks
Browse files Browse the repository at this point in the history
  • Loading branch information
officialPlocki committed Sep 25, 2023
1 parent 18f391d commit 51ee69f
Showing 1 changed file with 185 additions and 5 deletions.
190 changes: 185 additions & 5 deletions src/main/java/com/zyneonstudios/accounts/AccountSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,42 @@
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

public class AccountSystem {

private static final ConcurrentHashMap<String, AtomicLong> accessCounts = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Integer> accesses = new ConcurrentHashMap<>();
private static final int MAX_ACCESS_PER_MINUTE = 100;
private static final int MAX_JSON_SIZE_BYTES = 1024;

private void setTimeStamp(String username) {
if(!accessCounts.containsKey(username)) {
accessCounts.put(username, new AtomicLong(System.currentTimeMillis()));
}
}

private boolean validateAccessRate(String username) {
setTimeStamp(username);

if(accesses.get(username) >= MAX_ACCESS_PER_MINUTE) {
return false;
}

accesses.put(username, accesses.get(username)+1);

return true;
}

private boolean validateJsonSize(String jsonString) {
int jsonSizeBytes = jsonString.getBytes(StandardCharsets.UTF_8).length;

return jsonSizeBytes <= MAX_JSON_SIZE_BYTES;
}

private static final Logger logger = LogManager.getLogger(AccountSystem.class);

public static void main(String[] args) throws IOException, NoSuchAlgorithmException, KeyManagementException {
Expand All @@ -45,6 +77,14 @@ public void start() throws IOException, NoSuchAlgorithmException, KeyManagementE
if (undertow == null) {
undertow = Undertow.builder()
.addHttpListener(908, "0.0.0.0", new RoutingHandler()
.post("/login", this::loginHandler)
.post("/logout", this::logoutHandler)
.post("/refresh", this::refreshTokenHandler)
.get("/api/application", this::applicationApiHandler)
.get("/account", this::accountHandler)
.get("/information", this::getAllInformationHandler))

.addHttpListener(908, "::", new RoutingHandler()
.post("/login", this::loginHandler)
.post("/logout", this::logoutHandler)
.post("/refresh", this::refreshTokenHandler)
Expand All @@ -53,6 +93,23 @@ public void start() throws IOException, NoSuchAlgorithmException, KeyManagementE
.get("/information", this::getAllInformationHandler)).build();
}

Thread thread = new Thread(() -> {
while (true) {
accessCounts.forEach((s, atomicLong) -> {
if((System.currentTimeMillis() - atomicLong.get()) > 3600000) {
accesses.remove(s);
accessCounts.put(s, new AtomicLong(System.currentTimeMillis()));
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {}
}
});
thread.start();

Runtime.getRuntime().addShutdownHook(new Thread(thread::interrupt));

undertow.start();
}

Expand All @@ -76,7 +133,14 @@ private void loginHandler(HttpServerExchange exchange) {
exchange.getRequestReceiver().receiveFullString((httpServerExchange, requestBody) -> {
try {
JSONObject requestJson = new JSONObject(requestBody);

String username = requestJson.getString("username");

if(!validateAccessRate(username)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

String password = requestJson.getString("password");
boolean requestNonExpiringToken = requestJson.optBoolean("nonExpiringToken", false);

Expand All @@ -91,6 +155,7 @@ private void loginHandler(HttpServerExchange exchange) {
// Respond with the authentication token
JSONObject responseJson = new JSONObject();
responseJson.put("authToken", authToken.getTokenValue());
responseJson.put("uuid", account.getUuid());
respondWithJson(exchange, responseJson);
} else {
respondWithError(exchange, "Invalid credentials", 401);
Expand All @@ -103,6 +168,15 @@ private void loginHandler(HttpServerExchange exchange) {
});
}

private boolean checkExpirationAuthToken(String token) throws Exception {
if(Objects.requireNonNull(AuthenticationToken.getAuthenticationToken(token)).isTemporary()) {
if((System.currentTimeMillis() - Objects.requireNonNull(AuthenticationToken.getAuthenticationToken(token)).getCreationTimestamp()) > 300000) {
Objects.requireNonNull(AuthenticationToken.getAuthenticationToken(token)).deleteToken();
return false;
}
}
return true;
}

private void logoutHandler(HttpServerExchange exchange) {
// Extract the authentication token from the request body
Expand All @@ -112,13 +186,21 @@ private void logoutHandler(HttpServerExchange exchange) {
JSONObject requestJson = new JSONObject(requestBody);
if (requestJson.has("authToken")) {
authTokenRef.set(requestJson.getString("authToken"));

if(!checkExpirationAuthToken(authTokenRef.get())) {
respondWithError(exchange, "Token invalid", 401);
return;
}

// Continue with token validation and deletion
handleLogout(exchange, authTokenRef.get());
} else {
respondWithError(exchange, "Invalid request format: authToken missing", 401);
}
} catch (JSONException e) {
respondWithError(exchange, "Invalid request format: JSON parsing error", 401);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
Expand Down Expand Up @@ -158,13 +240,23 @@ private void refreshTokenHandler(HttpServerExchange exchange) {
AuthenticationToken token = AuthenticationToken.getAuthenticationToken(authToken);

if (token != null) {
if(token.isTemporary()) {
if((System.currentTimeMillis() - token.getCreationTimestamp()) > 86400000) {
token.deleteToken();
respondWithError(exchange, "Token exceeded refresh time", 401);;
return;
}
}
// Generate a new token with the same username and a new token value
AuthenticationToken newToken = new AuthenticationToken(token.getUsername(), generateNewToken(), token.isTemporary());
newToken.saveToken();
token.deleteToken();

// Respond with the new authentication token
JSONObject responseJson = new JSONObject();
responseJson.put("authToken", newToken.getTokenValue());
responseJson.put("uuid", accountManager.getAccount(token.getUsername()));
responseJson.put("username", token.getUsername());
respondWithJson(exchange, responseJson);
return;
}
Expand Down Expand Up @@ -212,7 +304,13 @@ private static JSONObject getAdminViewUserData(String username) {
}
}

private static JSONObject getUserData(String username, Token token) {
private static JSONObject getUserData(String username, Token token) throws Exception {

if(accountManager.getAccount(token.getUsername()) == null) {
token.deleteToken();
return new JSONObject();
}

try {
// Check if the token is authorized to access the data for the given username
if (token.isAdminToken() || token.getUsername().equals(username)) {
Expand All @@ -227,14 +325,19 @@ private static JSONObject getUserData(String username, Token token) {
}
}

private void applicationApiHandler(HttpServerExchange exchange) {
private void applicationApiHandler(HttpServerExchange exchange) throws Exception {
String applicationToken = extractApplicationTokenFromRequest(exchange);

if (applicationToken != null) {
Token token = Token.getApplicationToken(applicationToken);

assert token != null;
if(accountManager.getAccount(token.getUsername()) == null) {
token.deleteToken();
respondWithError(exchange, "Token expired", 401);
}

try {
assert token != null;
boolean isAdminToken = token.isAdminToken();

String requestBody = extractRequestBody(exchange);
Expand Down Expand Up @@ -322,7 +425,7 @@ private boolean deleteAccount(String username) {
}
}

private static boolean modifyUserData(String username, String key, JSONObject modifiedData) {
private static boolean modifyUserData(String username, String key, JSONObject modifiedData) {
try {
// Modify user data
return accountManager.updateUserData(username, key, modifiedData);
Expand Down Expand Up @@ -377,6 +480,17 @@ private void accountHandler(HttpServerExchange exchange) {
if (requestData.has("username") && requestData.has("password")) {
try {
String username = requestData.getString("username");

if(accountManager.getAccount(username) != null) {
respondWithError(exchange, "Username already in use", 401);
return;
}

if(!validateAccessRate(username)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

String password = requestData.getString("password");

// Call the AccountManager's createAccount method
Expand All @@ -399,6 +513,10 @@ private void accountHandler(HttpServerExchange exchange) {
String authToken = extractAuthTokenFromRequest(exchange);
AuthenticationToken token = AuthenticationToken.getAuthenticationToken(authToken);
assert token != null;
if(!checkExpirationAuthToken(token.getTokenValue())) {
respondWithError(exchange, "Token invalid", 401);
return;
}
if (token.getUsername().equalsIgnoreCase(actionData.optString("username", ""))) {
String usernameToDelete = actionData.optString("username", "");
boolean deletionResult = deleteAccount(usernameToDelete);
Expand All @@ -413,10 +531,24 @@ private void accountHandler(HttpServerExchange exchange) {
String authToken2 = extractAuthTokenFromRequest(exchange);
AuthenticationToken token2 = AuthenticationToken.getAuthenticationToken(authToken2);
assert token2 != null;
if(!checkExpirationAuthToken(token2.getTokenValue())) {
respondWithError(exchange, "Token invalid", 401);
return;
}
if (token2.getUsername().equalsIgnoreCase(actionData.optString("username", ""))) {
String usernameToUpdate = actionData.optString("username", "");

if(!validateAccessRate(usernameToUpdate)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

String dataKey = actionData.optString("dataKey", "");
JSONObject modifiedData = actionData.optJSONObject("modifiedData");
if(!validateJsonSize(modifiedData.toString())) {
respondWithError(exchange, "JSON data too large", 401);
return;
}
boolean modificationResult = modifyUserData(usernameToUpdate, dataKey, modifiedData);
responseJson.put("success", modificationResult);
} else {
Expand All @@ -428,11 +560,22 @@ private void accountHandler(HttpServerExchange exchange) {
String authToken3 = extractAuthTokenFromRequest(exchange);
AuthenticationToken token3 = AuthenticationToken.getAuthenticationToken(authToken3);
assert token3 != null;
if(!checkExpirationAuthToken(token3.getTokenValue())) {
respondWithError(exchange, "Token invalid", 401);
return;
}
if (token3.getUsername().equalsIgnoreCase(actionData.optString("username", ""))) {
String usernameToRetrieve = actionData.optString("username", "");

if(!validateAccessRate(usernameToRetrieve)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

String dataKey = actionData.optString("dataKey", "*");
JSONObject userData = accountManager.getUserData(usernameToRetrieve, dataKey);
responseJson.put("userData", userData);
responseJson.put("uuid", accountManager.getAccount(usernameToRetrieve).getUuid());
} else {
respondWithError(exchange, "Unauthorized action", 401);
return;
Expand All @@ -442,8 +585,18 @@ private void accountHandler(HttpServerExchange exchange) {
String authToken5 = extractAuthTokenFromRequest(exchange);
AuthenticationToken token5 = AuthenticationToken.getAuthenticationToken(authToken5);
assert token5 != null;
if(!checkExpirationAuthToken(token5.getTokenValue())) {
respondWithError(exchange, "Token invalid", 401);
return;
}
if (token5.getUsername().equalsIgnoreCase(actionData.optString("username", ""))) {
String usernameToUpdate = actionData.optString("username", "");

if(!validateAccessRate(usernameToUpdate)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

String newPassword = actionData.optString("newPassword", "");
boolean passwordChangeResult = accountManager.updatePassword(usernameToUpdate, newPassword);
responseJson.put("success", passwordChangeResult);
Expand All @@ -457,9 +610,30 @@ private void accountHandler(HttpServerExchange exchange) {
String authToken4 = extractAuthTokenFromRequest(exchange);
AuthenticationToken token4 = AuthenticationToken.getAuthenticationToken(authToken4);
assert token4 != null;
if(!checkExpirationAuthToken(token4.getTokenValue())) {
respondWithError(exchange, "Token invalid", 401);
return;
}
if (token4.getUsername().equalsIgnoreCase(actionData.optString("username", ""))) {
String usernameToUpdate = actionData.optString("username", "");

if(!validateAccessRate(usernameToUpdate)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

String newUsername = actionData.optString("newUsername", "");

if(accountManager.getAccount(newUsername) != null) {
respondWithError(exchange, "Username already in use", 401);
return;
}

if(!validateAccessRate(newUsername)) {
respondWithError(exchange, "Exceed of rate limit", 401);
return;
}

boolean usernameChangeResult = accountManager.changeUsername(usernameToUpdate, newUsername);
responseJson.put("success", usernameChangeResult);
} else {
Expand Down Expand Up @@ -489,7 +663,13 @@ private void getAllInformationHandler(HttpServerExchange exchange) {
try {
// Check if the application token is an admin token
Token token = Token.getApplicationToken(applicationToken);
if (token != null && token.isAdminToken()) {

if(accountManager.getAccount(token.getUsername()) == null) {
token.deleteToken();
respondWithError(exchange, "Token invalid", 401);
}

if (token.isAdminToken()) {
// Token is an admin token, proceed to fetch user information

// Extract the username of the user whose information is requested
Expand Down

0 comments on commit 51ee69f

Please sign in to comment.