Skip to content

Commit

Permalink
feat: implement entity configuration metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
jcmelati committed Aug 21, 2024
1 parent f92b63e commit 4f946b8
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ DATASOURCE_USER=openid-federation-db-user
DATASOURCE_PASSWORD=openid-federation-db-password
DATASOURCE_DB=openid-federation-db
APP_KEY=Nit5tWts42QeCynT1Q476LyStDeSd4xb
ROOT_IDENTIFIER=http://localhost:8080
ROOT_IDENTIFIER=http://localhost:8080
1 change: 1 addition & 0 deletions modules/admin-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies {
testImplementation(libs.testcontainer.postgres)
runtimeOnly(libs.postgres)
runtimeOnly(libs.springboot.devtools)
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.11")
}

kotlin {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.sphereon.oid.fed.server.admin.controllers

import com.sphereon.oid.fed.openapi.models.CreateMetadataDTO
import com.sphereon.oid.fed.persistence.models.EntityConfigurationMetadata
import com.sphereon.oid.fed.services.EntityConfigurationMetadataService
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/accounts/{accountUsername}/metadata")
class EntityConfigurationMetadataController {
private val entityConfigurationMetadataService = EntityConfigurationMetadataService()

@GetMapping
fun get(
@PathVariable accountUsername: String
): Array<EntityConfigurationMetadata> {
return entityConfigurationMetadataService.findByAccountUsername(accountUsername)
}

@PostMapping
fun create(
@PathVariable accountUsername: String,
@RequestBody metadata: CreateMetadataDTO
): EntityConfigurationMetadata {
return entityConfigurationMetadataService.createEntityConfigurationMetadata(
accountUsername,
metadata.key,
metadata.value
)
}

@DeleteMapping("/{id}")
fun delete(
@PathVariable accountUsername: String,
@PathVariable id: Int
): EntityConfigurationMetadata {
return entityConfigurationMetadataService.deleteEntityConfigurationMetadata(accountUsername, id)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ class FederationController {

@GetMapping("/{username}/.well-known/openid-federation")
fun getAccountEntityConfigurationStatement(@PathVariable username: String): String {
throw NotImplementedError()
val account = accountQueries.findByUsername(username).executeAsOneOrNull()
?: throw IllegalArgumentException("Account not found")
val entityConfigurationStatement =
entityConfigurationStatementQueries.findLatestByAccountId(account.id).executeAsOneOrNull()
?: throw IllegalArgumentException("Entity Configuration Statement not found")

return entityConfigurationStatement.statement
}

@GetMapping("/list")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2488,6 +2488,21 @@ components:
- code
- token

CreateMetadataDTO:
type: object
properties:
key:
type: string
description: The metadata key.
example: openid_relying_party
value:
additionalProperties: true
description: The metadata object.
required:
- key
- value


OAuthDynamicClientMetadata:
type:
object
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.sphereon.oid.fed.persistence

import com.sphereon.oid.fed.persistence.models.AccountQueries
import com.sphereon.oid.fed.persistence.models.EntityConfigurationStatementQueries
import com.sphereon.oid.fed.persistence.models.KeyQueries
import com.sphereon.oid.fed.persistence.models.SubordinateQueries
import com.sphereon.oid.fed.persistence.models.*

expect object Persistence {
val entityConfigurationStatementQueries: EntityConfigurationStatementQueries
val accountQueries: AccountQueries
val keyQueries: KeyQueries
val subordinateQueries: SubordinateQueries
val entityConfigurationMetadataQueries: EntityConfigurationMetadataQueries
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ CREATE TABLE entityConfigurationStatement (
CONSTRAINT FK_ParentEntityConfigurationStatement FOREIGN KEY (account_id) REFERENCES account (id)
);

CREATE INDEX entity_statement_account_id_index ON subordinate (account_id);
CREATE INDEX entity_configuraion_statement_account_id_index ON subordinate (account_id);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE entityConfigurationMetadata (
id SERIAL PRIMARY KEY,
account_id INT NOT NULL,
key TEXT NOT NULL,
value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
CONSTRAINT FK_ParentEntityConfigurationMetadata FOREIGN KEY (account_id) REFERENCES account (id)
);

CREATE INDEX entity_configuration_metadata_account_id_index ON subordinate (account_id);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
create:
INSERT INTO entityConfigurationMetadata (
account_id,
key,
value
) VALUES (?, ?, ?) RETURNING *;

delete:
UPDATE entityConfigurationMetadata SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL RETURNING *;

findByAccountId:
SELECT * FROM entityConfigurationMetadata WHERE account_id = ? AND deleted_at IS NULL;

findByAccountIdAndKey:
SELECT * FROM entityConfigurationMetadata WHERE account_id = ? AND key = ? AND deleted_at IS NULL;

findById:
SELECT * FROM entityConfigurationMetadata WHERE id = ? AND deleted_at IS NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ import app.cash.sqldelight.db.QueryResult
import app.cash.sqldelight.db.SqlCursor
import app.cash.sqldelight.db.SqlDriver
import com.sphereon.oid.fed.persistence.database.PlatformSqlDriver
import com.sphereon.oid.fed.persistence.models.AccountQueries
import com.sphereon.oid.fed.persistence.models.EntityConfigurationStatementQueries
import com.sphereon.oid.fed.persistence.models.KeyQueries
import com.sphereon.oid.fed.persistence.models.SubordinateQueries
import com.sphereon.oid.fed.persistence.models.*

actual object Persistence {
actual val entityConfigurationStatementQueries: EntityConfigurationStatementQueries
actual val accountQueries: AccountQueries
actual val keyQueries: KeyQueries
actual val subordinateQueries: SubordinateQueries
actual val entityConfigurationMetadataQueries: EntityConfigurationMetadataQueries

init {
val driver = getDriver()
Expand All @@ -24,6 +22,7 @@ actual object Persistence {
entityConfigurationStatementQueries = database.entityConfigurationStatementQueries
keyQueries = database.keyQueries
subordinateQueries = database.subordinateQueries
entityConfigurationMetadataQueries = database.entityConfigurationMetadataQueries
}

private fun getDriver(): SqlDriver {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.sphereon.oid.fed.services

import com.sphereon.oid.fed.persistence.Persistence
import com.sphereon.oid.fed.persistence.models.EntityConfigurationMetadata
import kotlinx.serialization.json.JsonObject

class EntityConfigurationMetadataService {
fun createEntityConfigurationMetadata(
accountUsername: String,
key: String,
metadata: JsonObject
): EntityConfigurationMetadata {
val account = Persistence.accountQueries.findByUsername(accountUsername).executeAsOneOrNull()
?: throw IllegalArgumentException("Account not found")

val metadataAlreadyExists =
Persistence.entityConfigurationMetadataQueries.findByAccountIdAndKey(account.id, key).executeAsOneOrNull()

if (metadataAlreadyExists != null) {
throw IllegalStateException("Entity configuration metadata already exists")
}

return Persistence.entityConfigurationMetadataQueries.create(account.id, key, metadata.toString())
.executeAsOneOrNull()
?: throw IllegalStateException("Failed to create entity configuration metadata")
}

fun findByAccountId(accountId: Int): Array<EntityConfigurationMetadata> {
return Persistence.entityConfigurationMetadataQueries.findByAccountId(accountId).executeAsList().toTypedArray()
}

fun findByAccountUsername(accountUsername: String): Array<EntityConfigurationMetadata> {
val account = Persistence.accountQueries.findByUsername(accountUsername).executeAsOneOrNull()
?: throw IllegalArgumentException("Account not found")
return Persistence.entityConfigurationMetadataQueries.findByAccountId(account.id).executeAsList().toTypedArray()
}

fun deleteEntityConfigurationMetadata(accountUsername: String, id: Int): EntityConfigurationMetadata {
val account = Persistence.accountQueries.findByUsername(accountUsername).executeAsOneOrNull()
?: throw IllegalArgumentException("Account not found")

val metadata =
Persistence.entityConfigurationMetadataQueries.findById(id).executeAsOneOrNull()
?: throw IllegalArgumentException("Entity configuration metadata not found")

if (metadata.account_id != account.id) {
throw IllegalArgumentException("Entity configuration metadata not found")
}

return Persistence.entityConfigurationMetadataQueries.delete(id).executeAsOneOrNull()
?: throw IllegalArgumentException("Entity configuration metadata not found")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ class EntityStatementService {
)
}

val metadata = Persistence.entityConfigurationMetadataQueries.findByAccountId(account.id).executeAsList()

metadata.forEach {
entityConfigurationStatement.metadata(
Pair(it.key, Json.parseToJsonElement(it.value_).jsonObject)
)
}

return entityConfigurationStatement.build()
}

Expand Down

0 comments on commit 4f946b8

Please sign in to comment.