Remove debug headers and return 403 on access denied
All checks were successful
build-and-deploy / build-deploy (push) Successful in 26s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 26s
This commit is contained in:
@@ -1,23 +0,0 @@
|
|||||||
package com.android.trisolarisserver.config
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
|
||||||
import jakarta.servlet.http.HttpServletResponse
|
|
||||||
import org.springframework.stereotype.Component
|
|
||||||
import org.springframework.web.servlet.HandlerExceptionResolver
|
|
||||||
import org.springframework.web.servlet.ModelAndView
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class DebugExceptionResolver : HandlerExceptionResolver {
|
|
||||||
override fun resolveException(
|
|
||||||
request: HttpServletRequest,
|
|
||||||
response: HttpServletResponse,
|
|
||||||
handler: Any?,
|
|
||||||
ex: Exception
|
|
||||||
): ModelAndView? {
|
|
||||||
if (request.getHeader("X-Debug-Auth") == "1" && !response.isCommitted) {
|
|
||||||
val msg = ex.message?.take(200) ?: ""
|
|
||||||
response.setHeader("X-Exception", "${ex::class.java.simpleName}:$msg")
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.ResponseStatus
|
|||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
import org.springframework.web.server.ResponseStatusException
|
import org.springframework.web.server.ResponseStatusException
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
|
||||||
import jakarta.servlet.http.HttpServletResponse
|
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -165,76 +164,34 @@ class Rooms(
|
|||||||
fun createRoom(
|
fun createRoom(
|
||||||
@PathVariable propertyId: UUID,
|
@PathVariable propertyId: UUID,
|
||||||
@AuthenticationPrincipal principal: MyPrincipal?,
|
@AuthenticationPrincipal principal: MyPrincipal?,
|
||||||
response: HttpServletResponse,
|
|
||||||
@org.springframework.web.bind.annotation.RequestHeader(value = "X-Debug-Auth", required = false)
|
|
||||||
debugAuth: String?,
|
|
||||||
@RequestBody request: RoomUpsertRequest
|
@RequestBody request: RoomUpsertRequest
|
||||||
): RoomResponse {
|
): RoomResponse {
|
||||||
if (debugAuth == "1") {
|
|
||||||
response.setHeader("X-Principal-Present", (principal != null).toString())
|
|
||||||
response.setHeader("X-Principal-Id", principal?.userId?.toString() ?: "none")
|
|
||||||
response.setHeader("X-Room-Create-Step", "start")
|
|
||||||
}
|
|
||||||
requirePrincipal(principal)
|
requirePrincipal(principal)
|
||||||
try {
|
propertyAccess.requireMember(propertyId, principal!!.userId)
|
||||||
propertyAccess.requireMember(propertyId, principal!!.userId)
|
|
||||||
} catch (ex: Exception) {
|
if (roomRepo.existsByPropertyIdAndRoomNumber(propertyId, request.roomNumber)) {
|
||||||
if (debugAuth == "1") {
|
throw ResponseStatusException(HttpStatus.CONFLICT, "Room number already exists for property")
|
||||||
val msg = ex.message?.take(200) ?: ""
|
|
||||||
response.setHeader("X-Member-Check", "${ex::class.java.simpleName}:$msg")
|
|
||||||
}
|
|
||||||
throw ex
|
|
||||||
}
|
|
||||||
if (debugAuth == "1") {
|
|
||||||
response.setHeader("X-Room-Create-Step", "member_ok")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
val property = propertyRepo.findById(propertyId).orElseThrow {
|
||||||
if (debugAuth == "1") {
|
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
|
||||||
response.setHeader("X-Room-Create-Step", "check_duplicate")
|
|
||||||
}
|
|
||||||
if (roomRepo.existsByPropertyIdAndRoomNumber(propertyId, request.roomNumber)) {
|
|
||||||
throw ResponseStatusException(HttpStatus.CONFLICT, "Room number already exists for property")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugAuth == "1") {
|
|
||||||
response.setHeader("X-Room-Create-Step", "load_property")
|
|
||||||
}
|
|
||||||
val property = propertyRepo.findById(propertyId).orElseThrow {
|
|
||||||
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
|
|
||||||
}
|
|
||||||
if (debugAuth == "1") {
|
|
||||||
response.setHeader("X-Room-Create-Step", "resolve_room_type")
|
|
||||||
}
|
|
||||||
val roomType = resolveRoomType(propertyId, request)
|
|
||||||
|
|
||||||
val room = Room(
|
|
||||||
property = property,
|
|
||||||
roomType = roomType,
|
|
||||||
roomNumber = request.roomNumber,
|
|
||||||
floor = request.floor,
|
|
||||||
hasNfc = request.hasNfc,
|
|
||||||
active = request.active,
|
|
||||||
maintenance = request.maintenance,
|
|
||||||
notes = request.notes
|
|
||||||
)
|
|
||||||
|
|
||||||
if (debugAuth == "1") {
|
|
||||||
response.setHeader("X-Room-Create-Step", "save_room")
|
|
||||||
}
|
|
||||||
val saved = roomRepo.save(room).toRoomResponse()
|
|
||||||
if (debugAuth == "1") {
|
|
||||||
response.setHeader("X-Room-Create-Step", "saved")
|
|
||||||
}
|
|
||||||
roomBoardEvents.emit(propertyId)
|
|
||||||
return saved
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
if (debugAuth == "1") {
|
|
||||||
val msg = ex.message?.take(200) ?: ""
|
|
||||||
response.setHeader("X-Room-Create-Exception", "${ex::class.java.simpleName}:$msg")
|
|
||||||
}
|
|
||||||
throw ex
|
|
||||||
}
|
}
|
||||||
|
val roomType = resolveRoomType(propertyId, request)
|
||||||
|
|
||||||
|
val room = Room(
|
||||||
|
property = property,
|
||||||
|
roomType = roomType,
|
||||||
|
roomNumber = request.roomNumber,
|
||||||
|
floor = request.floor,
|
||||||
|
hasNfc = request.hasNfc,
|
||||||
|
active = request.active,
|
||||||
|
maintenance = request.maintenance,
|
||||||
|
notes = request.notes
|
||||||
|
)
|
||||||
|
|
||||||
|
val saved = roomRepo.save(room).toRoomResponse()
|
||||||
|
roomBoardEvents.emit(propertyId)
|
||||||
|
return saved
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{roomId}")
|
@PutMapping("/{roomId}")
|
||||||
|
|||||||
@@ -30,17 +30,9 @@ class FirebaseAuthFilter(
|
|||||||
response: HttpServletResponse,
|
response: HttpServletResponse,
|
||||||
filterChain: FilterChain
|
filterChain: FilterChain
|
||||||
) {
|
) {
|
||||||
val debug = request.getHeader("X-Debug-Auth") == "1"
|
|
||||||
fun setDebug(value: String) {
|
|
||||||
if (debug) {
|
|
||||||
response.setHeader("X-Auth-Debug", value)
|
|
||||||
logger.info("Auth debug: {} {} -> {}", request.method, request.requestURI, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val header = request.getHeader(HttpHeaders.AUTHORIZATION)
|
val header = request.getHeader(HttpHeaders.AUTHORIZATION)
|
||||||
if (header.isNullOrBlank() || !header.startsWith("Bearer ")) {
|
if (header.isNullOrBlank() || !header.startsWith("Bearer ")) {
|
||||||
logger.debug("Auth missing/invalid header for {}", request.requestURI)
|
logger.debug("Auth missing/invalid header for {}", request.requestURI)
|
||||||
setDebug(if (header.isNullOrBlank()) "missing_authorization" else "invalid_authorization")
|
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Missing Authorization token")
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Missing Authorization token")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -49,10 +41,7 @@ class FirebaseAuthFilter(
|
|||||||
val decoded = FirebaseAuth.getInstance().verifyIdToken(token)
|
val decoded = FirebaseAuth.getInstance().verifyIdToken(token)
|
||||||
val firebaseUid = decoded.uid
|
val firebaseUid = decoded.uid
|
||||||
val user = appUserRepo.findByFirebaseUid(firebaseUid)
|
val user = appUserRepo.findByFirebaseUid(firebaseUid)
|
||||||
?: run {
|
?: throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found")
|
||||||
setDebug("user_not_found")
|
|
||||||
throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found")
|
|
||||||
}
|
|
||||||
logger.debug("Auth verified uid={}, userId={}", firebaseUid, user.id)
|
logger.debug("Auth verified uid={}, userId={}", firebaseUid, user.id)
|
||||||
|
|
||||||
val principal = MyPrincipal(
|
val principal = MyPrincipal(
|
||||||
@@ -61,19 +50,9 @@ class FirebaseAuthFilter(
|
|||||||
)
|
)
|
||||||
val auth = UsernamePasswordAuthenticationToken(principal, token, emptyList())
|
val auth = UsernamePasswordAuthenticationToken(principal, token, emptyList())
|
||||||
SecurityContextHolder.getContext().authentication = auth
|
SecurityContextHolder.getContext().authentication = auth
|
||||||
setDebug("ok:userId=${principal.userId},superAdmin=${user.superAdmin}")
|
filterChain.doFilter(request, response)
|
||||||
try {
|
|
||||||
filterChain.doFilter(request, response)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
if (debug) {
|
|
||||||
val msg = ex.message?.take(200) ?: ""
|
|
||||||
response.setHeader("X-Downstream-Exception", "${ex::class.java.simpleName}:$msg")
|
|
||||||
}
|
|
||||||
throw ex
|
|
||||||
}
|
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
logger.debug("Auth failed for {}: {}", request.requestURI, ex.message)
|
logger.debug("Auth failed for {}: {}", request.requestURI, ex.message)
|
||||||
setDebug("verify_failed")
|
|
||||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token")
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,8 @@ class SecurityConfig(
|
|||||||
}
|
}
|
||||||
.exceptionHandling {
|
.exceptionHandling {
|
||||||
it.authenticationEntryPoint(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
|
it.authenticationEntryPoint(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
|
||||||
it.accessDeniedHandler { request, response, ex ->
|
it.accessDeniedHandler { _, response, _ ->
|
||||||
if (request.getHeader("X-Debug-Auth") == "1") {
|
response.sendError(HttpStatus.FORBIDDEN.value(), "Forbidden")
|
||||||
val msg = ex.message?.take(200) ?: "access_denied"
|
|
||||||
response.setHeader("X-Access-Debug", msg)
|
|
||||||
}
|
|
||||||
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Unauthorized")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.httpBasic { it.disable() }
|
.httpBasic { it.disable() }
|
||||||
|
|||||||
Reference in New Issue
Block a user