mirror of
https://github.com/dalbodeule/sh0rt.kr-pdns.git
synced 2026-11-05 22:29:34 +09:00
feat: Add script to refresh README from OpenAPI document
refactor: Improve error handling in PowerDNSAPIClient and streamline response processing fix: Update RecordController to directly return records without unnecessary mapping refactor: Update DomainRepository and RecordRepository to remove nullable types for IDs fix: Change User domains fetch strategy to lazy loading for performance improvement fix: Enhance user authentication handling in UserFilter to ensure authenticated user presence refactor: Improve DomainService to enforce ownership checks before domain deletion refactor: Update RecordService to streamline record retrieval and ensure proper domain association test: Add OpenAPI generation test to validate API documentation endpoint test: Implement PowerDNSAPIClient tests to verify HTTP method usage and error handling test: Create DomainService tests to validate domain ownership and deletion logic test: Add application-test.properties for in-memory database configuration during tests
This commit is contained in:
24 files changed
+920
-1329
No files matched your search
@@ -6,10 +6,10 @@ import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Service
|
||||
import java.lang.reflect.Type
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
@Service
|
||||
@@ -21,40 +21,46 @@ class PowerDNSAPIClient() {
|
||||
private lateinit var apiKey: String
|
||||
|
||||
private val gson = Gson()
|
||||
private val client = OkHttpClient()
|
||||
private val client = OkHttpClient.Builder()
|
||||
.callTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
@Throws(PowerDNSAPIException::class)
|
||||
fun createZone(zoneName: String): Response {
|
||||
try {
|
||||
val body = gson.toJson(
|
||||
mapOf(
|
||||
"name" to "$zoneName.",
|
||||
"kind" to "Primary"
|
||||
)
|
||||
).toRequestBody()
|
||||
val request = Request.Builder()
|
||||
.url("$apiUrl/api/v1/servers/localhost/zones")
|
||||
.addHeader("X-API-Key", apiKey)
|
||||
.addHeader("Accept", "application/json")
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.post(body)
|
||||
.build()
|
||||
private fun execute(request: Request) {
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (response.isSuccessful) return
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
if (!response.isSuccessful) {
|
||||
val str = response.body?.string()
|
||||
val error = gson.fromJson(str, PowerDNSAPIError::class.java)
|
||||
throw PowerDNSAPIException(error)
|
||||
}
|
||||
return response
|
||||
} catch(ex: Exception) {
|
||||
println(ex)
|
||||
throw ex
|
||||
val error = runCatching {
|
||||
gson.fromJson(response.peekBody(64 * 1024L).string(), PowerDNSAPIError::class.java)
|
||||
}.getOrNull()
|
||||
throw PowerDNSAPIException(
|
||||
if (error?.error.isNullOrBlank())
|
||||
PowerDNSAPIError("PowerDNS API returned HTTP ${response.code}", null)
|
||||
else error
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(PowerDNSAPIException::class)
|
||||
fun deleteZone(zoneName: String): Response {
|
||||
fun createZone(zoneName: String) {
|
||||
val body = gson.toJson(
|
||||
mapOf(
|
||||
"name" to "$zoneName.",
|
||||
"kind" to "Primary"
|
||||
)
|
||||
).toRequestBody()
|
||||
val request = Request.Builder()
|
||||
.url("$apiUrl/api/v1/servers/localhost/zones")
|
||||
.addHeader("X-API-Key", apiKey)
|
||||
.addHeader("Accept", "application/json")
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.post(body)
|
||||
.build()
|
||||
|
||||
execute(request)
|
||||
}
|
||||
|
||||
@Throws(PowerDNSAPIException::class)
|
||||
fun deleteZone(zoneName: String) {
|
||||
val request = Request.Builder()
|
||||
.url("$apiUrl/api/v1/servers/localhost/zones/$zoneName.")
|
||||
.addHeader("X-API-Key", apiKey)
|
||||
@@ -63,17 +69,11 @@ class PowerDNSAPIClient() {
|
||||
.delete()
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
if(!response.isSuccessful) {
|
||||
val str = response.body?.string()
|
||||
val error = gson.fromJson(str, PowerDNSAPIError::class.java)
|
||||
throw PowerDNSAPIException(error)
|
||||
}
|
||||
return response
|
||||
execute(request)
|
||||
}
|
||||
|
||||
@Throws(PowerDNSAPIException::class)
|
||||
fun createRecord(zoneName: String, recordName: String, recordType: String, recordContent: String, ttl: Int = 300, priority: Int = 0): Response {
|
||||
fun createRecord(zoneName: String, recordName: String, recordType: String, recordContent: String, ttl: Int = 300, priority: Int = 0) {
|
||||
val rrset = mapOf(
|
||||
"name" to recordName,
|
||||
"type" to recordType,
|
||||
@@ -95,17 +95,11 @@ class PowerDNSAPIClient() {
|
||||
.patch(body)
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
if(!response.isSuccessful) {
|
||||
val str = response.body?.string()
|
||||
val error = gson.fromJson(str, PowerDNSAPIError::class.java)
|
||||
throw PowerDNSAPIException(error)
|
||||
}
|
||||
return response
|
||||
execute(request)
|
||||
}
|
||||
|
||||
@Throws(PowerDNSAPIException::class)
|
||||
fun updateRecord(zoneName: String, recordName: String, recordType: String, recordContent: String, ttl: Int = 300, priority: Int = 0): Response {
|
||||
fun updateRecord(zoneName: String, recordName: String, recordType: String, recordContent: String, ttl: Int = 300, priority: Int = 0) {
|
||||
val rrset = mapOf(
|
||||
"name" to recordName,
|
||||
"type" to recordType,
|
||||
@@ -127,17 +121,11 @@ class PowerDNSAPIClient() {
|
||||
.patch(body)
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
if(!response.isSuccessful) {
|
||||
val str = response.body?.string()
|
||||
val error = gson.fromJson(str, PowerDNSAPIError::class.java)
|
||||
throw PowerDNSAPIException(error)
|
||||
}
|
||||
return response
|
||||
execute(request)
|
||||
}
|
||||
|
||||
@Throws(PowerDNSAPIException::class)
|
||||
fun deleteRecord(zoneName: String, recordName: String, recordType: String): Response {
|
||||
fun deleteRecord(zoneName: String, recordName: String, recordType: String) {
|
||||
val rrset = mapOf(
|
||||
"name" to recordName,
|
||||
"type" to recordType,
|
||||
@@ -153,13 +141,7 @@ class PowerDNSAPIClient() {
|
||||
.patch(body)
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
if(!response.isSuccessful) {
|
||||
val str = response.body?.string()
|
||||
val error = gson.fromJson(str, PowerDNSAPIError::class.java)
|
||||
throw PowerDNSAPIException(error)
|
||||
}
|
||||
return response
|
||||
execute(request)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,4 +174,4 @@ class PowerDNSAPIException(private val error: PowerDNSAPIError): RuntimeExceptio
|
||||
get() = error.errors
|
||||
|
||||
override fun toString(): String = "PowerDNSAPIException(${error.error} ${errors?.joinToString(", ") ?: ""})"
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class RecordController(
|
||||
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))]),
|
||||
])
|
||||
fun allRecords(@PathVariable zone_id: String): ApiResponseDTO<List<RecordResponseDTO>> {
|
||||
return ApiResponseDTO(result = recordService.getRecordsByDomain(zone_id)?.map{ it } ?: listOf())
|
||||
return ApiResponseDTO(result = recordService.getRecordsByDomain(zone_id))
|
||||
}
|
||||
|
||||
@GetMapping("{zone_id}/dns_records/{dns_record_id}")
|
||||
@@ -71,4 +71,4 @@ class RecordController(
|
||||
fun updateRecord(@PathVariable zone_id: String, @PathVariable dns_record_id: String, @RequestBody record: RecordRequestDTO): ApiResponseDTO<RecordResponseDTO> {
|
||||
return ApiResponseDTO(result = recordService.updateRecord(zone_id, dns_record_id, record))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository
|
||||
import java.util.*
|
||||
|
||||
|
||||
interface DomainRepository : JpaRepository<Domain?, Long?> {
|
||||
interface DomainRepository : JpaRepository<Domain, Long> {
|
||||
@Transactional
|
||||
fun findByCfid(cfid: String): Optional<Domain>
|
||||
|
||||
@@ -14,4 +14,4 @@ interface DomainRepository : JpaRepository<Domain?, Long?> {
|
||||
|
||||
@Transactional
|
||||
fun deleteByCfid(cfid: String): Int
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,18 @@ import org.springframework.data.jpa.repository.JpaRepository
|
||||
import java.util.*
|
||||
|
||||
|
||||
interface RecordRepository : JpaRepository<Record?, Long?> {
|
||||
interface RecordRepository : JpaRepository<Record, Long> {
|
||||
@Transactional
|
||||
fun findByCfid(cfid: String): Optional<Record>
|
||||
|
||||
@Transactional
|
||||
fun findByDomainIdAndCfid(domainId: Long, cfid: String): Optional<Record>
|
||||
|
||||
fun findAllByDomainId(domainId: Long): List<Record>
|
||||
|
||||
@Transactional
|
||||
fun deleteByCfid(cfid: String): Int
|
||||
|
||||
@Transactional
|
||||
fun deleteByDomainIdAndCfid(domain_id: Long, cfid: String): Int
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ data class User(
|
||||
@Column(nullable = false, unique = false, length = 20)
|
||||
val name: String,
|
||||
|
||||
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
val domains: List<Domain> = mutableListOf(),
|
||||
) {
|
||||
override fun toString(): String = "User(id=$id, name='$name')"
|
||||
}
|
||||
}
|
||||
@@ -35,4 +35,5 @@ class UserFilter(
|
||||
}
|
||||
|
||||
fun getCurrentUser(): User =
|
||||
SecurityContextHolder.getContext().authentication.principal as User
|
||||
SecurityContextHolder.getContext().authentication?.principal as? User
|
||||
?: throw IllegalStateException("Authenticated user is required")
|
||||
@@ -20,7 +20,6 @@ class DomainService(
|
||||
try {
|
||||
val user = getCurrentUser()
|
||||
val domain = domainRepository.findAllByUser(user)
|
||||
if (domain.isEmpty()) throw RuntimeException("Unauthorized")
|
||||
|
||||
return domain
|
||||
} catch(ex: Error) {
|
||||
@@ -62,14 +61,17 @@ class DomainService(
|
||||
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
|
||||
throw RuntimeException("Domain with CFID $domain_id not found")
|
||||
}
|
||||
val user = getCurrentUser()
|
||||
if (domain.user.id != user.id)
|
||||
throw RuntimeException("Unauthorized to delete domain in API: $domain_id")
|
||||
|
||||
powerDNSApiClient.deleteZone(domain.name)
|
||||
val count = domainRepository.deleteByCfid(domain_id)
|
||||
|
||||
if (count > 0) throw RuntimeException("Domain with CFID $domain_id not found")
|
||||
if (count == 0) throw RuntimeException("Domain with CFID $domain_id not found")
|
||||
return domain_id
|
||||
} catch(ex: Error) {
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class RecordService(
|
||||
proxied = false,
|
||||
ttl = record.ttl,
|
||||
locked = false,
|
||||
zoneId = record.domain.cfid,
|
||||
zoneId = domain.cfid,
|
||||
zoneName = domain.name,
|
||||
createdOn = record.createdOn.getISOFormat(),
|
||||
modifiedOn = record.modifiedOn.getISOFormat(),
|
||||
@@ -82,8 +82,9 @@ class RecordService(
|
||||
if(domain.user.id != user.id)
|
||||
throw RuntimeException("Unauthorized to get record in API: $domain_id")
|
||||
|
||||
val record = domain.records.find { it.cfid == record_id }
|
||||
if(record == null) throw RuntimeException("Failed to find record in API: $record_id")
|
||||
val record = recordRepository.findByDomainIdAndCfid(domain.id!!, record_id).orElseThrow {
|
||||
RuntimeException("Failed to find record in API: $record_id")
|
||||
}
|
||||
|
||||
return RecordResponseDTO(
|
||||
id = record.cfid,
|
||||
@@ -91,15 +92,15 @@ class RecordService(
|
||||
name = record.name,
|
||||
content = record.content,
|
||||
ttl = record.ttl,
|
||||
zoneId = record.domain.cfid,
|
||||
zoneName = record.domain.name,
|
||||
zoneId = domain.cfid,
|
||||
zoneName = domain.name,
|
||||
createdOn = record.createdOn.getISOFormat(),
|
||||
modifiedOn = record.modifiedOn.getISOFormat(),
|
||||
comment = record.comment,
|
||||
)
|
||||
}
|
||||
|
||||
fun getRecordsByDomain(domain_id: String): List<RecordResponseDTO>? {
|
||||
fun getRecordsByDomain(domain_id: String): List<RecordResponseDTO> {
|
||||
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
|
||||
RuntimeException("Failed to find domain in API: $domain_id")
|
||||
}
|
||||
@@ -108,13 +109,13 @@ class RecordService(
|
||||
if(domain.user.id != user.id)
|
||||
throw RuntimeException("Unauthorized to create record in API: $domain_id")
|
||||
|
||||
return domain?.records?.map { RecordResponseDTO(
|
||||
return recordRepository.findAllByDomainId(domain.id!!).map { RecordResponseDTO(
|
||||
id = it.cfid,
|
||||
type = it.type,
|
||||
name = it.name,
|
||||
content = it.content,
|
||||
zoneId = it.domain.cfid,
|
||||
zoneName = it.domain.name,
|
||||
zoneId = domain.cfid,
|
||||
zoneName = domain.name,
|
||||
priority = it.prio,
|
||||
ttl = it.ttl,
|
||||
createdOn = it.createdOn.getISOFormat(),
|
||||
@@ -153,7 +154,7 @@ class RecordService(
|
||||
else -> record.ttl
|
||||
}
|
||||
|
||||
powerDNSApiClient.updateRecord(domain!!.name, updatedRecord.name, updatedRecord.type, updatedRecord.value)
|
||||
powerDNSApiClient.updateRecord(domain.name, updatedRecord.name, updatedRecord.type, updatedRecord.value, record.ttl, record.prio)
|
||||
|
||||
// 저장
|
||||
val savedRecord = recordRepository.save(record)
|
||||
@@ -192,4 +193,4 @@ class RecordService(
|
||||
|
||||
return record_id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package space.mori.dnsapi
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("test")
|
||||
class DnsapiApplicationTests {
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package space.mori.dnsapi
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonParser
|
||||
import org.junit.jupiter.api.Tag
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||
import org.springframework.web.context.WebApplicationContext
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
@Tag("openapi-generation")
|
||||
@SpringBootTest(properties = ["springdoc.api-docs.enabled=true"])
|
||||
@ActiveProfiles("test")
|
||||
class OpenApiGenerationTest(@Autowired private val context: WebApplicationContext) {
|
||||
@Test
|
||||
fun generateOpenApi() {
|
||||
val response = MockMvcBuilders.webAppContextSetup(context).build()
|
||||
.perform(get("/api-docs").with { request ->
|
||||
request.serverName = "localhost"
|
||||
request.serverPort = 8080
|
||||
request
|
||||
})
|
||||
.andReturn().response
|
||||
check(response.status == 200) { "OpenAPI endpoint returned HTTP ${response.status}: ${response.contentAsString}" }
|
||||
|
||||
val output = Path.of(System.getProperty("openapi.output"))
|
||||
val json = GsonBuilder().setPrettyPrinting().create()
|
||||
.toJson(JsonParser.parseString(response.contentAsString))
|
||||
Files.writeString(output, json + "\n")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package space.mori.dnsapi
|
||||
|
||||
import mockwebserver3.MockResponse
|
||||
import mockwebserver3.MockWebServer
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.test.util.ReflectionTestUtils
|
||||
|
||||
class PowerDNSAPIClientTest {
|
||||
@Test
|
||||
fun successfulCallsUseTheExpectedHttpMethods() {
|
||||
MockWebServer().use { server ->
|
||||
server.start()
|
||||
repeat(5) { server.enqueue(MockResponse.Builder().body("ok").build()) }
|
||||
val client = clientFor(server)
|
||||
|
||||
client.createZone("example.com")
|
||||
client.deleteZone("example.com")
|
||||
client.createRecord("example.com", "www.example.com.", "A", "192.0.2.1")
|
||||
client.updateRecord("example.com", "www.example.com.", "A", "192.0.2.2")
|
||||
client.deleteRecord("example.com", "www.example.com.", "A")
|
||||
|
||||
assertEquals("POST", server.takeRequest().method)
|
||||
assertEquals("DELETE", server.takeRequest().method)
|
||||
repeat(3) { assertEquals("PATCH", server.takeRequest().method) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun errorResponsesKeepThePowerDnsMessageAndHandleInvalidJson() {
|
||||
MockWebServer().use { server ->
|
||||
server.start()
|
||||
server.enqueue(MockResponse.Builder().code(400)
|
||||
.body("{\"error\":\"invalid zone\",\"errors\":[\"bad name\"]}").build())
|
||||
server.enqueue(MockResponse.Builder().code(500).body("not json").build())
|
||||
val client = clientFor(server)
|
||||
|
||||
val error = assertThrows(PowerDNSAPIException::class.java) { client.deleteZone("example.com") }
|
||||
assertEquals("invalid zone", error.message)
|
||||
assertEquals(listOf("bad name"), error.errors)
|
||||
|
||||
val fallback = assertThrows(PowerDNSAPIException::class.java) { client.deleteZone("example.com") }
|
||||
assertEquals("PowerDNS API returned HTTP 500", fallback.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun clientFor(server: MockWebServer): PowerDNSAPIClient = PowerDNSAPIClient().also {
|
||||
ReflectionTestUtils.setField(it, "apiUrl", server.url("/").toString().removeSuffix("/"))
|
||||
ReflectionTestUtils.setField(it, "apiKey", "test-key")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package space.mori.dnsapi.service
|
||||
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import space.mori.dnsapi.PowerDNSAPIClient
|
||||
import space.mori.dnsapi.db.Domain
|
||||
import space.mori.dnsapi.db.DomainRepository
|
||||
import space.mori.dnsapi.db.User
|
||||
import java.util.Optional
|
||||
|
||||
class DomainServiceTest {
|
||||
private val repository = Mockito.mock(DomainRepository::class.java)
|
||||
private val powerDns = Mockito.mock(PowerDNSAPIClient::class.java)
|
||||
private val service = DomainService(repository, powerDns)
|
||||
|
||||
@AfterEach
|
||||
fun clearSecurityContext() {
|
||||
SecurityContextHolder.clearContext()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rejectsDeletingAnotherUsersDomainBeforeCallingPowerDns() {
|
||||
val owner = User(id = 1, apiKey = "owner", name = "owner")
|
||||
val otherUser = User(id = 2, apiKey = "other", name = "other")
|
||||
val domain = Domain(name = "example.com", user = owner)
|
||||
Mockito.`when`(repository.findByCfid(domain.cfid)).thenReturn(Optional.of(domain))
|
||||
authenticate(otherUser)
|
||||
|
||||
assertThrows(RuntimeException::class.java) { service.deleteDomain(domain.cfid) }
|
||||
Mockito.verifyNoInteractions(powerDns)
|
||||
Mockito.verify(repository, Mockito.never()).deleteByCfid(domain.cfid)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deletingAnOwnedDomainSucceedsWhenOneRowWasRemoved() {
|
||||
val owner = User(id = 1, apiKey = "owner", name = "owner")
|
||||
val domain = Domain(name = "example.com", user = owner)
|
||||
Mockito.`when`(repository.findByCfid(domain.cfid)).thenReturn(Optional.of(domain))
|
||||
Mockito.`when`(repository.deleteByCfid(domain.cfid)).thenReturn(1)
|
||||
authenticate(owner)
|
||||
|
||||
assertEquals(domain.cfid, service.deleteDomain(domain.cfid))
|
||||
Mockito.verify(powerDns).deleteZone(domain.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aUserWithoutDomainsGetsAnEmptyList() {
|
||||
val user = User(id = 1, apiKey = "owner", name = "owner")
|
||||
Mockito.`when`(repository.findAllByUser(user)).thenReturn(emptyList())
|
||||
authenticate(user)
|
||||
|
||||
assertEquals(emptyList<Domain>(), service.getAllDomains())
|
||||
}
|
||||
|
||||
private fun authenticate(user: User) {
|
||||
SecurityContextHolder.getContext().authentication =
|
||||
UsernamePasswordAuthenticationToken(user, null, emptyList())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
spring.datasource.url=jdbc:h2:mem:dnsapi;DB_CLOSE_DELAY=-1
|
||||
spring.datasource.driver-class-name=org.h2.Driver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=
|
||||
spring.jpa.hibernate.ddl-auto=create-drop
|
||||
pdns.api.key=test
|
||||
pdns.api.url=http://localhost
|
||||
pdns.ns=ns.example
|
||||
Reference in new issue
Block a user