Skip to content

Commit

Permalink
#2270 config for DB variants
Browse files Browse the repository at this point in the history
  • Loading branch information
DarioGii committed Dec 10, 2024
1 parent d0e3846 commit 69db8b0
Show file tree
Hide file tree
Showing 21 changed files with 198 additions and 74 deletions.
16 changes: 1 addition & 15 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ dependencies {
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
dependsOn "spotlessApply"
dependsOn "initDB"
// dependsOn "initDB"
}

compileJava {
Expand All @@ -253,20 +253,6 @@ bootRun {
}
}


tasks.register("initDB", Exec) {
description = "Creates a database of the specified type (postgresql, mysql, oracle)."
def scriptPath = "$projectDir/scripts/init_db.sh"
// Set the database type argument
def dbType = project.hasProperty('dbType') ? project.property('dbType') : "postgresql"

if (!["postgresql", "mysql", "oracle"].contains(dbType)) {
throw new GradleException("Invalid database type: $dbType. Valid types are: postgresql, mysql, oracle.")
} else {
commandLine "bash", scriptPath, dbType
}
}

task writeVersion {
def propsFile = file("src/main/resources/version.properties")
def props = new Properties()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public LicenseKeyChecker(
this.checkLicense();
}

@Scheduled(initialDelay = 604800000,fixedRate = 604800000) // 7 days in milliseconds
@Scheduled(initialDelay = 604800000, fixedRate = 604800000) // 7 days in milliseconds
public void checkLicensePeriodically() {
checkLicense();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import stirling.software.SPDF.utils.FileInfo;

public interface DatabaseBackupInterface {
void setAdminUser();

void exportDatabase() throws IOException;

void importDatabase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,26 @@
@Slf4j
public class InitialSecuritySetup {

public static final String POSTGRES = "postgres";

@Autowired private UserService userService;

@Autowired private ApplicationProperties applicationProperties;

@Autowired private DatabaseBackupInterface databaseBackupHelper;
@Autowired private DatabaseBackupInterface databaseBackupService;

@PostConstruct
public void init() throws IllegalArgumentException, IOException {
if (databaseBackupHelper.hasBackup() && userService.hasUsers()) {
databaseBackupHelper.importDatabase();
} else if (!userService.hasUsers()) {
if (applicationProperties.getSystem().getEnvironmentName().equals(POSTGRES)) {
log.debug("PostgreSQL configuration settings detected. Creating admin user");
databaseBackupService.setAdminUser();
}

if (!userService.hasUsers()) {
initializeAdminUser();
} else {
databaseBackupHelper.exportDatabase();
userService.migrateOauth2ToSSO();
}

userService.migrateOauth2ToSSO();
initializeInternalApiUser();
}

Expand Down Expand Up @@ -73,7 +77,7 @@ private void initializeInternalApiUser() throws IllegalArgumentException, IOExce
UUID.randomUUID().toString(),
Role.INTERNAL_API_USER.getRoleId());
userService.addApiKeyToUser(Role.INTERNAL_API_USER.getRoleId());
log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId());
log.info("Internal API user created: {}", Role.INTERNAL_API_USER.getRoleId());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package stirling.software.SPDF.config.security.database;

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Configuration;

import lombok.Data;

@Data
@Configuration
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceConfig {

private String driverClassName;
private String url;
private String username;
private String password;

public DataSource dataSource() {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName(driverClassName);
dataSourceBuilder.url(url);
dataSourceBuilder.username(username);
dataSourceBuilder.password(password);
return dataSourceBuilder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
Expand All @@ -20,38 +19,62 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.jdbc.datasource.init.ScriptException;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface;
import stirling.software.SPDF.model.exception.BackupNotFoundException;
import stirling.software.SPDF.utils.FileInfo;

@Slf4j
@Configuration
public class DatabaseBackupHelper implements DatabaseBackupInterface {
@Service
public class DatabaseBackupService implements DatabaseBackupInterface {

public static final String BACKUP_PREFIX = "backup_";
public static final String SQL_SUFFIX = ".sql";
private static final Path BACKUP_PATH = Paths.get("configs/db/backup/");

@Value("${dbType:postgresql}")
private String dbType;
@Autowired private DatabaseConfig databaseConfig;

@Value("${spring.datasource.url}")
private String url;

@Value("${spring.datasource.username}")
private String username;

@Value("${spring.datasource.password}")
private String password;
@Override
public void setAdminUser() {
String adminScript =
"""
DO
$do$
BEGIN
IF EXISTS (
SELECT FROM pg_catalog.pg_roles
WHERE rolname = 'admin') THEN
RAISE NOTICE 'Role "admin" already exists. Skipping.';
ELSE
CREATE USER admin WITH ENCRYPTED PASSWORD 'stirling';
END IF;
END
$do$;
CREATE SCHEMA IF NOT EXISTS stirling_pdf AUTHORIZATION admin;
GRANT ALL PRIVILEGES ON DATABASE postgres TO admin;
ALTER DATABASE postgres SET search_path TO stirling_pdf;
ALTER USER admin SET search_path TO stirling_pdf;
"""
.trim();

try (Connection connection = databaseConfig.connection();
Statement statement = connection.createStatement()) {
statement.execute(adminScript);
} catch (SQLException e) {
log.error("Error: Failed to create admin user for database", e);
}

private final Path BACKUP_PATH = Paths.get("configs/db/backup/");
log.info("Created admin user for database");
}

@Override
public boolean hasBackup() {
Expand Down Expand Up @@ -154,7 +177,7 @@ public void exportDatabase() {
Path insertOutputFilePath =
this.getBackupFilePath(BACKUP_PREFIX + dateNow.format(myFormatObj) + SQL_SUFFIX);

try (Connection conn = DriverManager.getConnection(url, username, password)) {
try (Connection conn = databaseConfig.connection()) {
ScriptUtils.executeSqlScript(
conn, new EncodedResource(new PathResource(insertOutputFilePath)));

Expand Down Expand Up @@ -183,7 +206,7 @@ private static void deleteOldestBackup(List<FileInfo> filteredBackupList) {
// Retrieves the H2 database version.
public String getH2Version() {
String version = "Unknown";
try (Connection conn = DriverManager.getConnection(url, username, password)) {
try (Connection conn = databaseConfig.connection()) {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT H2VERSION() AS version")) {
if (rs.next()) {
Expand Down Expand Up @@ -223,7 +246,7 @@ public Path getBackupFilePath(String fileName) {
}

private void executeDatabaseScript(Path scriptPath) {
try (Connection conn = DriverManager.getConnection(url, username, password)) {
try (Connection conn = databaseConfig.connection()) {
ScriptUtils.executeSqlScript(conn, new EncodedResource(new PathResource(scriptPath)));

log.info("Database import completed: {}", scriptPath);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package stirling.software.SPDF.config.security.database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import lombok.Getter;

@Getter
@Configuration
public class DatabaseConfig {

@Autowired private DataSourceConfig dataSourceConfig;

@Autowired private JpaConfig jpaConfig;

@Bean
public DataSource dataSource() {
return dataSourceConfig.dataSource();
}

@Bean
public Connection connection() throws SQLException {
return DriverManager.getConnection(
dataSourceConfig.getUrl(),
dataSourceConfig.getUsername(),
dataSourceConfig.getPassword());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package stirling.software.SPDF.config.security.database;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import lombok.Data;

@Data
@Configuration
@ConfigurationProperties(prefix = "spring.jpa")
public class JpaConfig {

@Value("${environment.name}")
private String environmentName;

private String databasePlatform;
private String openInView;
private String generateDDL;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@Component
public class ScheduledTasks {

@Autowired private DatabaseBackupHelper databaseBackupService;
@Autowired private DatabaseBackupService databaseBackupService;

@Scheduled(cron = "0 0 0 * * ?")
public void performBackup() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;

import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.security.database.DatabaseBackupHelper;
import stirling.software.SPDF.config.security.database.DatabaseBackupService;

@Slf4j
@Controller
Expand All @@ -37,7 +37,7 @@
@Tag(name = "Database", description = "Database APIs")
public class DatabaseController {

@Autowired DatabaseBackupHelper databaseBackupHelper;
@Autowired DatabaseBackupService databaseBackupService;

@Hidden
@PostMapping(consumes = "multipart/form-data", value = "import-database")
Expand All @@ -56,7 +56,7 @@ public String importDatabase(
try (InputStream in = file.getInputStream()) {
Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING);
boolean importSuccess =
databaseBackupHelper.importDatabaseFromUI(tempTemplatePath.toString());
databaseBackupService.importDatabaseFromUI(tempTemplatePath.toString());
if (importSuccess) {
redirectAttributes.addAttribute("infoMessage", "importIntoDatabaseSuccessed");
} else {
Expand All @@ -79,14 +79,14 @@ public String importDatabaseFromBackupUI(@PathVariable String fileName)

// Check if the file exists in the backup list
boolean fileExists =
databaseBackupHelper.getBackupList().stream()
databaseBackupService.getBackupList().stream()
.anyMatch(backup -> backup.getFileName().equals(fileName));
if (!fileExists) {
log.error("File {} not found in backup list", fileName);
return "redirect:/database?error=fileNotFound";
}
log.info("Received file: {}", fileName);
if (databaseBackupHelper.importDatabaseFromUI(fileName)) {
if (databaseBackupService.importDatabaseFromUI(fileName)) {
log.info("File {} imported to database", fileName);
return "redirect:/database?infoMessage=importIntoDatabaseSuccessed";
}
Expand All @@ -104,7 +104,7 @@ public String deleteFile(@PathVariable String fileName) {
throw new IllegalArgumentException("File must not be null or empty");
}
try {
if (databaseBackupHelper.deleteBackupFile(fileName)) {
if (databaseBackupService.deleteBackupFile(fileName)) {
log.info("Deleted file: {}", fileName);
} else {
log.error("Failed to delete file: {}", fileName);
Expand All @@ -128,7 +128,7 @@ public ResponseEntity<?> downloadFile(@PathVariable String fileName) {
throw new IllegalArgumentException("File must not be null or empty");
}
try {
Path filePath = databaseBackupHelper.getBackupFilePath(fileName);
Path filePath = databaseBackupService.getBackupFilePath(fileName);
InputStreamResource resource = new InputStreamResource(Files.newInputStream(filePath));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
import io.swagger.v3.oas.annotations.tags.Tag;

import jakarta.servlet.http.HttpServletRequest;
import stirling.software.SPDF.config.security.database.DatabaseBackupHelper;
import stirling.software.SPDF.config.security.database.DatabaseBackupService;
import stirling.software.SPDF.utils.FileInfo;

@Controller
@Tag(name = "Database Management", description = "Database management and security APIs")
public class DatabaseWebController {

@Autowired private DatabaseBackupHelper databaseBackupHelper;
@Autowired private DatabaseBackupService databaseBackupService;

@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/database")
Expand All @@ -33,10 +33,10 @@ public String database(HttpServletRequest request, Model model, Authentication a
model.addAttribute("infoMessage", confirmed);
}

List<FileInfo> backupList = databaseBackupHelper.getBackupList();
List<FileInfo> backupList = databaseBackupService.getBackupList();
model.addAttribute("backupFiles", backupList);

model.addAttribute("databaseVersion", databaseBackupHelper.getH2Version());
model.addAttribute("databaseVersion", databaseBackupService.getH2Version());

return "database";
}
Expand Down
Loading

0 comments on commit 69db8b0

Please sign in to comment.