Skip to content

Commit

Permalink
feat: add support for http authorization & authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
OpenSrcerer committed Feb 15, 2024
1 parent 0b8cc59 commit d42f5b0
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 230 deletions.
11 changes: 5 additions & 6 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@ val quarkusPlatformVersion: String by project
dependencies {
implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))

// implementation("io.quarkus:quarkus-hibernate-orm")
// implementation("io.quarkus:quarkus-hibernate-orm-panache")
// implementation("io.quarkus:quarkus-reactive-pg-client")

implementation("org.neo4j:neo4j-ogm-quarkus:3.6.0")
implementation("io.quarkiverse.neo4j:quarkus-neo4j:3.6.0")
// Java-JWT
implementation("com.auth0:java-jwt:4.4.0")

// Reactive REST
implementation("io.quarkus:quarkus-resteasy-reactive-jackson")
implementation("io.quarkus:quarkus-resteasy-reactive")
implementation("io.quarkus:quarkus-config-yaml")

// Kotlin-Specific
implementation("io.quarkus:quarkus-kotlin")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

// Quarkus Support
implementation("io.quarkus:quarkus-arc")

testImplementation("io.quarkus:quarkus-junit5")
Expand Down
15 changes: 14 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,17 @@ services:
- node1.emqx.io
ports:
- "1883:1883"
- "18083:18083"
- "18083:18083"

neo4j:
image: neo4j:5.16.0
container_name: neo4j
restart: on-failure
volumes:
- /home/chronos/neo4j/data:/data
- /home/chronos/neo4j/logs:/logs
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=neo4j/bonkersdbobcat

This file was deleted.

This file was deleted.

This file was deleted.

10 changes: 0 additions & 10 deletions src/main/kotlin/online/danielstefani/paddy/db/device/Device.kt

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package online.danielstefani.paddy.security

import io.quarkus.logging.Log
import online.danielstefani.paddy.security.dto.AuthorizationResultDto
import online.danielstefani.paddy.security.dto.AuthorizationResultDto.*
import org.jboss.resteasy.reactive.RestResponse
import org.jboss.resteasy.reactive.RestResponse.*

abstract class AbstractAuthorizationController {

fun allow(principal: String, resource: String): RestResponse<AuthorizationResultDto> {
Log.info("Allowing <$principal>'s access to <$resource>.")
return ResponseBuilder.ok(AuthorizationResultDto(AuthorizationResult.ALLOW, resource))
.status(Status.OK)
.build()
}

fun forbid(principal: String, resource: String): RestResponse<AuthorizationResultDto> {
Log.info("Forbidding <$principal>'s access to <$resource>.")
return ResponseBuilder.ok(AuthorizationResultDto(AuthorizationResult.DENY, resource))
.status(Status.OK)
.build()
}

fun ignore(principal: String, resource: String): RestResponse<AuthorizationResultDto> {
Log.info("Sending <$principal>'s access to <$resource> to next authorizer in chain.")
return ResponseBuilder.ok(AuthorizationResultDto(AuthorizationResult.IGNORE, resource))
.status(Status.OK)
.build()
}
}
48 changes: 23 additions & 25 deletions src/main/kotlin/online/danielstefani/paddy/security/JwtService.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
package online.danielstefani.paddy.security

import io.quarkus.logging.Log
import io.vertx.core.json.JsonObject
import io.vertx.ext.auth.impl.jose.JWT
import jakarta.enterprise.context.ApplicationScoped
import online.danielstefani.paddy.configuration.JwksConfiguration
import java.nio.charset.StandardCharsets
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.PublicKey
import java.security.Signature
import java.security.interfaces.RSAPrivateCrtKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.RSAPublicKeySpec
import java.time.Instant
import java.util.*

@ApplicationScoped
class JwtService(
private val jwksConfiguration: JwksConfiguration
private val keychainHolder: KeychainHolder
) {
fun makeJwt(
sub: String,
jwtLifetimeSeconds: Long = 31540000
): String {
val (privateKey, _) = makeKeyPair()
val (privateKey, _) = keychainHolder.keypair()

val jwtHeader: String = Base64.getUrlEncoder().withoutPadding().encodeToString(
"""
Expand Down Expand Up @@ -66,7 +62,7 @@ class JwtService(
}

fun makeJwks(): String {
val rsaPublicKey = makeKeyPair().second as RSAPublicKey
val rsaPublicKey = keychainHolder.keypair().second as RSAPublicKey

val jwksResponse = java.lang.String.format(
"""
Expand All @@ -91,22 +87,24 @@ class JwtService(
return jwksResponse
}

private fun makeKeyPair(): Pair<PrivateKey, PublicKey> {
val keyFactory = KeyFactory.getInstance("RSA")

val privateKey = with(Base64.getDecoder().decode(jwksConfiguration.privateKey())) {
keyFactory.generatePrivate(PKCS8EncodedKeySpec(this))
}
fun parseJwt(jwt: String): JsonObject? {
return try {
JWT.parse(jwt)
} catch (ex: Exception) {
Log.debug("Received invalid JWT: <${jwt}>.")
null
}
}

val publicKey = with(
RSAPublicKeySpec(
(privateKey as RSAPrivateCrtKey).modulus,
privateKey.publicExponent
)
) {
keyFactory.generatePublic(this)
/*
Check the signature of the JWT.
*/
fun isJwtValid(jwt: String): Boolean {
try {
keychainHolder.verifier().verify(jwt)
return true
} catch (ex: Exception) {
return false
}

return Pair(privateKey, publicKey)
}
}
Loading

0 comments on commit d42f5b0

Please sign in to comment.