Skip to content

Commit

Permalink
Write the DENY AuthorizeResult to the response. (#8)
Browse files Browse the repository at this point in the history
* Write the DENY `AuthorizeResult` to the response.
  • Loading branch information
Ahoo-Wang authored Nov 24, 2022
1 parent 48e97f4 commit a8f2aae
Show file tree
Hide file tree
Showing 8 changed files with 28 additions and 13 deletions.
4 changes: 2 additions & 2 deletions cosec-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ dependencies {
compileOnly("org.springframework:spring-expression")
api("io.projectreactor:reactor-core")
api("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
api("com.fasterxml.jackson.core:jackson-databind")
api("com.fasterxml.jackson.module:jackson-module-kotlin")
testImplementation("ognl:ognl")
testImplementation("org.springframework:spring-web")
testImplementation("org.springframework:spring-expression")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ interface AuthorizeResult {
val reason: String

companion object {
val ALLOW: AuthorizeResult = AuthorizeResultData(true, "Allowed")
val EXPLICIT_DENY: AuthorizeResult = AuthorizeResultData(false, "Explicit Denied")
val IMPLICIT_DENY: AuthorizeResult = AuthorizeResultData(false, "Implicit Denied")
val ALLOW: AuthorizeResult = allow("Allow")
val EXPLICIT_DENY: AuthorizeResult = deny("Explicit Deny")
val IMPLICIT_DENY: AuthorizeResult = deny("Implicit Deny")
fun allow(reason: String): AuthorizeResult = AuthorizeResultData(true, reason)
fun deny(reason: String): AuthorizeResult = AuthorizeResultData(false, reason)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import me.ahoo.cosec.authorization.Authorization
import me.ahoo.cosec.context.SecurityContext
import me.ahoo.cosec.context.SecurityContextParser
import me.ahoo.cosec.context.request.RequestParser
import me.ahoo.cosec.policy.serialization.CoSecJsonSerializer
import me.ahoo.cosec.webflux.ServerWebExchanges.setSecurityContext
import org.springframework.http.HttpStatus
import org.springframework.web.server.ServerWebExchange
Expand Down Expand Up @@ -50,7 +51,10 @@ abstract class ReactiveSecurityFilter(
} else {
exchange.response.statusCode = HttpStatus.FORBIDDEN
}
exchange.response.setComplete()
val builder =
exchange.response.bufferFactory().wrap(CoSecJsonSerializer.writeValueAsBytes(authorizeResult))
.toMono()
exchange.response.writeWith(builder)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import me.ahoo.cosec.authorization.Authorization
import me.ahoo.cosec.authorization.AuthorizeResult
import me.ahoo.cosec.context.request.RequestTenantIdParser
import me.ahoo.cosec.jwt.Jwts
import me.ahoo.cosec.policy.serialization.CoSecJsonSerializer
import me.ahoo.cosec.webflux.ServerWebExchanges.setSecurityContext
import org.junit.jupiter.api.Test
import org.springframework.http.HttpStatus
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilterChain
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toMono
import java.nio.ByteBuffer

internal class ReactiveAuthorizationFilterTest {

Expand Down Expand Up @@ -80,8 +82,9 @@ internal class ReactiveAuthorizationFilterTest {
every { request.headers.getFirst(RequestTenantIdParser.TENANT_ID_KEY) } returns "tenantId"
every { request.path.value() } returns "/path"
every { request.methodValue } returns "GET"
every { response.setComplete() } returns Mono.empty()
every { response.setStatusCode(HttpStatus.UNAUTHORIZED) } returns true
every { response.bufferFactory().wrap(any() as ByteArray) } returns mockk()
every { response.writeWith(any()) } returns Mono.empty()
every {
mutate()
.principal(any())
Expand All @@ -93,7 +96,8 @@ internal class ReactiveAuthorizationFilterTest {
verify {
authorization.authorize(any(), any())
exchange.response.statusCode = HttpStatus.UNAUTHORIZED
exchange.response.setComplete()
exchange.response.bufferFactory().wrap(any() as ByteArray)
exchange.response.writeWith(any())
}
}

Expand All @@ -114,8 +118,9 @@ internal class ReactiveAuthorizationFilterTest {
every { request.headers.getFirst(RequestTenantIdParser.TENANT_ID_KEY) } returns "tenantId"
every { request.path.value() } returns "/path"
every { request.methodValue } returns "GET"
every { response.setComplete() } returns Mono.empty()
every { response.setStatusCode(HttpStatus.FORBIDDEN) } returns true
every { response.bufferFactory().wrap(any() as ByteArray) } returns mockk()
every { response.writeWith(any()) } returns Mono.empty()
every {
mutate()
.principal(any())
Expand All @@ -127,7 +132,8 @@ internal class ReactiveAuthorizationFilterTest {
verify {
authorization.authorize(any(), any())
exchange.response.statusCode = HttpStatus.FORBIDDEN
exchange.response.setComplete()
exchange.response.bufferFactory().wrap(any() as ByteArray)
exchange.response.writeWith(any())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import me.ahoo.cosec.context.SecurityContext
import me.ahoo.cosec.context.SecurityContextHolder
import me.ahoo.cosec.context.SecurityContextParser
import me.ahoo.cosec.context.request.RequestParser
import me.ahoo.cosec.policy.serialization.CoSecJsonSerializer
import me.ahoo.cosec.servlet.ServletRequests.setSecurityContext
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
Expand Down Expand Up @@ -61,6 +62,8 @@ abstract class AbstractAuthorizationInterceptor(
} else {
response.status = HttpStatus.FORBIDDEN.value()
}
response.outputStream.write(CoSecJsonSerializer.writeValueAsBytes(it))
response.outputStream.flush()
return@map false
}
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import me.ahoo.cosec.context.SecurityContext
import me.ahoo.cosec.context.SecurityContextHolder
import me.ahoo.cosec.context.request.RequestTenantIdParser
import me.ahoo.cosec.jwt.Jwts
import me.ahoo.cosec.policy.serialization.CoSecJsonSerializer
import me.ahoo.cosec.servlet.ServletRequests.setSecurityContext
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
Expand Down Expand Up @@ -74,8 +75,10 @@ internal class AuthorizationFilterTest {
every { getHeader(Jwts.AUTHORIZATION_KEY) } returns null
every { setSecurityContext(any()) } returns Unit
}
val servletResponse = mockk<HttpServletResponse>() {
val servletResponse = mockk<HttpServletResponse> {
every { status = HttpStatus.UNAUTHORIZED.value() } returns Unit
every { outputStream.write(any() as ByteArray) } returns Unit
every { outputStream.flush() } returns Unit
}
val filterChain = mockk<FilterChain>() {
every { doFilter(servletRequest, any()) } returns Unit
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# limitations under the License.
#
group=me.ahoo.cosec
version=0.8.9
version=0.9.0
description=RBAC-based And Policy-based Multi-Tenant Security Framework
website=https://github.com/Ahoo-Wang/CoSec
issues=https://github.com/Ahoo-Wang/CoSec/issues
Expand Down
1 change: 0 additions & 1 deletion k8s/deployment/cosec-gateway.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ metadata:
app: cosec-gateway
spec:
replicas: 1

selector:
matchLabels:
app: cosec-gateway
Expand Down

0 comments on commit a8f2aae

Please sign in to comment.