Added whole app password protection

This commit is contained in:
Rostislav Raykov
2024-10-09 18:05:54 +03:00
parent 534d738646
commit 00aff02dc7
9 changed files with 141 additions and 35 deletions

View File

@@ -75,6 +75,8 @@ file.save.path=files
file.max.age=30 (In days)
logging.file.name=log/quickdrop.log
file.deletion.cron=0 0 2 * * *
app.basic.password=test
app.enable.password=false
```
- Run the application with the external configuration:

2
mvnw vendored
View File

@@ -25,7 +25,7 @@
# -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_USERNAME/MVNW_PASSWORD - user and password.html for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------

View File

@@ -0,0 +1,21 @@
package org.rostislav.quickdrop.config;
import org.rostislav.quickdrop.interceptor.PasswordInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final PasswordInterceptor passwordInterceptor;
public WebConfig(PasswordInterceptor passwordInterceptor) {
this.passwordInterceptor = passwordInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(passwordInterceptor)
.excludePathPatterns("/password/login", "/favicon.ico", "/error");
}
}

View File

@@ -46,7 +46,7 @@ public class FileViewController {
if (fileEntity.passwordHash != null &&
(password == null || !fileService.checkPassword(uuid, password))) {
model.addAttribute("uuid", uuid);
return "password";
return "filePassword";
}
populateModelAttributes(fileEntity, model, request);
@@ -54,11 +54,6 @@ public class FileViewController {
return "fileView";
}
@GetMapping("/password")
public String passwordPage(Model model) {
return "password";
}
@PostMapping("/password")
public String checkPassword(String uuid, String password, HttpServletRequest request, Model model) {
if (fileService.checkPassword(uuid, password)) {
@@ -66,7 +61,7 @@ public class FileViewController {
return "redirect:/file/" + uuid;
} else {
model.addAttribute("uuid", uuid);
return "password";
return "filePassword";
}
}

View File

@@ -0,0 +1,33 @@
package org.rostislav.quickdrop.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/password")
public class PasswordController {
@Value("${app.basic.password}")
private String appPassword;
@GetMapping("/login")
public String passwordPage(Model model) {
return "password";
}
@PostMapping("/login")
public String processPassword(@RequestParam("password") String password, HttpServletRequest request) {
if (appPassword.equals(password)) {
request.getSession().setAttribute("authenticated", true);
return "redirect:/"; // Redirect to home or the intended page
} else {
request.setAttribute("error", "Invalid Password");
return "password"; // Show the password page with an error message
}
}
}

View File

@@ -0,0 +1,29 @@
package org.rostislav.quickdrop.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class PasswordInterceptor implements HandlerInterceptor {
@Value("${app.enable.password}")
private Boolean enablePassword;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!enablePassword) {
return true;
}
Boolean authenticated = (Boolean) request.getSession().getAttribute("authenticated");
if (authenticated != null && authenticated) {
return true;
}
response.sendRedirect("/password/login");
return false;
}
}

View File

@@ -15,5 +15,7 @@ file.save.path=files
file.max.age=30
logging.file.name=log/quickdrop.log
file.deletion.cron=0 0 2 * * *
app.basic.password=test
app.enable.password=false
#logging.level.org.springframework=DEBUG
#logging.level.org.hibernate=DEBUG

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Enter Password</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container mt-5">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
<a class="navbar-brand" href="/">QuickDrop</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/file/list">View Files</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/file/upload">Upload File</a>
</li>
</ul>
</div>
</nav>
<h1 class="text-center mb-4">Enter Password</h1>
<form class="card p-4" id="passwordForm" method="post" th:action="@{/file/password}">
<input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>
<input name="uuid" th:value="${uuid}" type="hidden"/>
<div class="form-group">
<label for="password">Password:</label>
<input class="form-control" id="password" name="password" type="password"/>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
</body>
</html>

View File

@@ -2,34 +2,23 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Enter Password</title>
<title>Password Required</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container mt-5">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
<a class="navbar-brand" href="/">QuickDrop</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/file/list">View Files</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/file/upload">Upload File</a>
</li>
</ul>
<body>
<div class="container mt-5">
<h2>Please enter the password to continue</h2>
<form action="/password/login" method="POST">
<input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>
<div class="form-group">
<label for="password">Password:</label>
<input class="form-control" id="password" name="password" required type="password">
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
<div th:if="${error}">
<p class="text-danger" th:text="${error}"></p>
</div>
</nav>
<h1 class="text-center mb-4">Enter Password</h1>
<form class="card p-4" id="passwordForm" method="post" th:action="@{/file/password}">
<input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>
<input name="uuid" th:value="${uuid}" type="hidden"/>
<div class="form-group">
<label for="password">Password:</label>
<input class="form-control" id="password" name="password" type="password"/>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
</div>
</body>
</html>
</html>