diff --git a/backend/Dockerfile b/backend/Dockerfile index e87cf93ef..b8ebdd853 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -11,7 +11,6 @@ WORKDIR /app # Copy the built jar file from the build stage COPY --from=build /home/gradle/src/build/libs/*.jar /app/backend.jar -COPY application.properties /app/ COPY resources/. /app/resources/. # Specify the command to run the application diff --git a/backend/application.properties b/backend/application.properties deleted file mode 100644 index b5c665840..000000000 --- a/backend/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -metadataAddress=https://api.airtable.com/v0/meta/bases/appzJQ8Tkmm8DobrJ/tables -metodeverkAddress=https://api.airtable.com/v0/appzJQ8Tkmm8DobrJ/tblLZbUqA0XnUgC2v?view=viw2XliGUJu5448Hk -alleAddress=https://api.airtable.com/v0/appzJQ8Tkmm8DobrJ/tblLZbUqA0XnUgC2v -graphApiMemberOfAddress=https://graph.microsoft.com/v1.0/me/memberOf/microsoft.graph.group \ No newline at end of file diff --git a/backend/src/main/kotlin/no/bekk/Application.kt b/backend/src/main/kotlin/no/bekk/Application.kt index d1f4e5741..30c2ba402 100644 --- a/backend/src/main/kotlin/no/bekk/Application.kt +++ b/backend/src/main/kotlin/no/bekk/Application.kt @@ -4,33 +4,62 @@ import no.bekk.plugins.* import io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.config.* import no.bekk.authentication.initializeAuthentication import no.bekk.authentication.installSessions -import no.bekk.singletons.Env -import java.io.FileInputStream -import java.util.* - -fun loadConfig(filePath: String): Properties { - val props = Properties() - FileInputStream(filePath).use { props.load(it) } - return props -} -val airtableAccessToken = Env.get("AIRTABLE_ACCESS_TOKEN") -val applicationProperties = loadConfig("application.properties") -val metadataAddress = applicationProperties.getProperty("metadataAddress") -val metodeverkAddress = applicationProperties.getProperty("metodeverkAddress") -val alleAddress = applicationProperties.getProperty("alleAddress") -val graphApiMemberOfAddress = applicationProperties.getProperty("graphApiMemberOfAddress") +import no.bekk.configuration.* fun main(args: Array) { io.ktor.server.netty.EngineMain.main(args) } +private fun loadAppConfig(config: ApplicationConfig) { + // AirTable config + AppConfig.airTable = AirTableConfig.apply { + accessToken = config.propertyOrNull("airTable.accessToken")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"airTable.accessToken\"") + baseUrl = config.propertyOrNull("airTable.baseUrl")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"airTable.baseUrl\"") + metadataPath = config.propertyOrNull("airTable.metadataPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"airTable.metadataPath\"") + metodeVerkPath = config.propertyOrNull("airTable.metodeVerkPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"airTable.metodeVerkPath\"") + allePath = config.propertyOrNull("airTable.allePath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"airTable.allePath\"") + } + + // MicrosoftGraph config + AppConfig.microsoftGraph = MicrosoftGraphConfig.apply { + baseUrl = config.propertyOrNull("microsoftGraph.baseUrl")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"microsoftGraph.baseUrl\"") + memberOfPath = config.propertyOrNull("microsoftGraph.memberOfPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"microsoftGraph.memberOfPath\"") + } + + // OAuth config + AppConfig.oAuth = OAuthConfig.apply { + baseUrl = config.propertyOrNull("oAuth.baseUrl")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.baseurl\"") + tenantId = config.propertyOrNull("oAuth.tenantId")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.tenantId\"") + issuerPath = config.propertyOrNull("oAuth.issuerPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.issuerPath\"") + authPath = config.propertyOrNull("oAuth.authPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.authPath\"") + tokenPath = config.propertyOrNull("oAuth.tokenPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.tokenPath\"") + jwksPath = config.propertyOrNull("oAuth.jwksPath")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.jwksPath\"") + clientId = config.propertyOrNull("oAuth.clientId")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.clientId\"") + clientSecret = config.propertyOrNull("oAuth.clientSecret")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.clientSecret\"") + providerUrl = config.propertyOrNull("oAuth.providerUrl")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"oAuth.providerUrl\"") + } + + // Frontend config + AppConfig.frontend = FrontendConfig.apply { + host = config.propertyOrNull("frontend.host")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"frontend.host\"") + } + + // Db config + AppConfig.db = DbConfig.apply { + url = config.propertyOrNull("db.url")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"db.url\"") + username = config.propertyOrNull("db.username")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"db.username\"") + password = config.propertyOrNull("db.password")?.getString() ?: throw IllegalStateException("Unable to initialize app config \"db.password\"") + } +} + fun Application.module() { + loadAppConfig(environment.config) install(ContentNegotiation) { json() } - configureCors() runFlywayMigration() installSessions() diff --git a/backend/src/main/kotlin/no/bekk/authentication/Authentication.kt b/backend/src/main/kotlin/no/bekk/authentication/Authentication.kt index d6ab07138..3d685e469 100644 --- a/backend/src/main/kotlin/no/bekk/authentication/Authentication.kt +++ b/backend/src/main/kotlin/no/bekk/authentication/Authentication.kt @@ -12,9 +12,8 @@ import io.ktor.server.auth.* import io.ktor.server.auth.jwt.* import io.ktor.server.response.* import io.ktor.server.sessions.* -import no.bekk.plugins.Config +import no.bekk.configuration.* import no.bekk.services.MicrosoftService -import no.bekk.singletons.Env import java.net.URL import java.util.concurrent.TimeUnit @@ -37,9 +36,9 @@ fun Application.installSessions() { fun Application.initializeAuthentication(httpClient: HttpClient = applicationHttpClient) { val redirects = mutableMapOf() - val issuer = "https://login.microsoftonline.com/${Env.get("TENANT_ID")}/v2.0" - val clientId = Env.get("AUTH_CLIENT_ID") - val jwksUri = "https://login.microsoftonline.com/${Env.get("TENANT_ID")}/discovery/v2.0/keys" + val issuer = AppConfig.oAuth.getIssuer() + val clientId = AppConfig.oAuth.clientId + val jwksUri = AppConfig.oAuth.getJwksUrl() val jwkProvider = JwkProviderBuilder(URL(jwksUri)) .cached(10, 24, TimeUnit.HOURS) @@ -48,7 +47,7 @@ fun Application.initializeAuthentication(httpClient: HttpClient = applicationHtt install(Authentication) { jwt("auth-jwt") { - verifier(jwkProvider, issuer){ + verifier(jwkProvider, issuer) { withIssuer(issuer) acceptLeeway(3) withAudience(clientId) @@ -56,7 +55,7 @@ fun Application.initializeAuthentication(httpClient: HttpClient = applicationHtt validate { jwtCredential -> if (jwtCredential.audience.contains(clientId)) JWTPrincipal(jwtCredential.payload) else null } - challenge{_,_ -> + challenge { _, _ -> call.respond(HttpStatusCode.Unauthorized, "You are unauthenticated") } authHeader { call -> @@ -72,17 +71,16 @@ fun Application.initializeAuthentication(httpClient: HttpClient = applicationHtt } oauth("auth-oauth-azure") { - urlProvider = { Env.get("AUTH_PROVIDER_URL") } + urlProvider = { AppConfig.oAuth.providerUrl } providerLookup = { OAuthServerSettings.OAuth2ServerSettings( name = "azure", - authorizeUrl = "https://login.microsoftonline.com/${Env.get("TENANT_ID")}/oauth2/v2.0/authorize", - accessTokenUrl = "https://login.microsoftonline.com/${Env.get("TENANT_ID")}/oauth2/v2.0/token", + authorizeUrl = AppConfig.oAuth.getAuthUrl(), + accessTokenUrl = AppConfig.oAuth.getTokenUrl(), requestMethod = HttpMethod.Post, clientId = clientId, - clientSecret = Env.get("AUTH_CLIENT_SECRET"), + clientSecret = AppConfig.oAuth.clientSecret, defaultScopes = listOf("$clientId/.default"), - extraAuthParameters = listOf("audience" to clientId), onStateCreated = { call, state -> call.request.queryParameters["redirectUrl"]?.let { redirects[state] = it @@ -96,26 +94,20 @@ fun Application.initializeAuthentication(httpClient: HttpClient = applicationHtt } suspend fun getGroupsOrEmptyList(call: ApplicationCall): List { + val microsoftService = MicrosoftService() - if (Config.isDevelopment) { - // Return mock groups for local development - return listOf("Mock-Team-1", "Mock-Team-2") - } else { - val microsoftService = MicrosoftService() + val graphApiToken = call.sessions.get()?.let { + microsoftService.requestTokenOnBehalfOf(it) + } ?: throw IllegalStateException("Unable to retrieve on-behalf-of token") - val graphApiToken = call.sessions.get()?.let { - microsoftService.requestTokenOnBehalfOf(it) - } ?: throw IllegalStateException("Unable to retrieve on-behalf-of token") - - return microsoftService.fetchGroupNames(graphApiToken) - } + return microsoftService.fetchGroupNames(graphApiToken) } suspend fun hasTeamAccess(call: ApplicationCall, teamId: String?): Boolean { - if(teamId == null || teamId == "") return false + if (teamId == null || teamId == "") return false val groups = getGroupsOrEmptyList(call) - if(groups.isEmpty()) return false + if (groups.isEmpty()) return false return teamId in groups } diff --git a/backend/src/main/kotlin/no/bekk/configuration/AppConfig.kt b/backend/src/main/kotlin/no/bekk/configuration/AppConfig.kt new file mode 100644 index 000000000..bcc3c2a52 --- /dev/null +++ b/backend/src/main/kotlin/no/bekk/configuration/AppConfig.kt @@ -0,0 +1,49 @@ +package no.bekk.configuration + +object AppConfig { + lateinit var airTable: AirTableConfig + lateinit var microsoftGraph: MicrosoftGraphConfig + lateinit var oAuth: OAuthConfig + lateinit var frontend: FrontendConfig + lateinit var db: DbConfig +} + +object AirTableConfig { + lateinit var accessToken: String + lateinit var baseUrl: String + lateinit var metadataPath: String + lateinit var metodeVerkPath: String + lateinit var allePath: String +} + +object MicrosoftGraphConfig { + lateinit var baseUrl: String + lateinit var memberOfPath: String +} + +object OAuthConfig { + lateinit var baseUrl: String + lateinit var tenantId: String + lateinit var issuerPath: String + lateinit var authPath: String + lateinit var tokenPath: String + lateinit var jwksPath: String + lateinit var clientId: String + lateinit var clientSecret: String + lateinit var providerUrl: String +} + +fun OAuthConfig.getIssuer() = AppConfig.oAuth.baseUrl + "/" + AppConfig.oAuth.tenantId + AppConfig.oAuth.issuerPath +fun OAuthConfig.getAuthUrl() = AppConfig.oAuth.baseUrl + "/" + AppConfig.oAuth.tenantId + AppConfig.oAuth.authPath +fun OAuthConfig.getTokenUrl() = AppConfig.oAuth.baseUrl + "/" + AppConfig.oAuth.tenantId + AppConfig.oAuth.tokenPath +fun OAuthConfig.getJwksUrl() = AppConfig.oAuth.baseUrl + "/" + AppConfig.oAuth.tenantId + AppConfig.oAuth.jwksPath + +object FrontendConfig { + lateinit var host: String +} + +object DbConfig { + lateinit var url: String + lateinit var username: String + lateinit var password: String +} diff --git a/backend/src/main/kotlin/no/bekk/configuration/ConfigureDatabase.kt b/backend/src/main/kotlin/no/bekk/configuration/ConfigureDatabase.kt deleted file mode 100644 index 71043a00f..000000000 --- a/backend/src/main/kotlin/no/bekk/configuration/ConfigureDatabase.kt +++ /dev/null @@ -1,20 +0,0 @@ -package no.bekk.configuration -import java.sql.Connection -import java.sql.DriverManager -import com.typesafe.config.ConfigFactory - -fun getDatabaseConnection(): Connection { - val dbUser = getEnvVariableOrConfig("DB_USER", "ktor.database.user") - val dbPassword = getEnvVariableOrConfig("DB_PASSWORD", "ktor.database.password") - - val databaseUrl = "jdbc:postgresql://localhost:5432/regelrett?currentSchema=regelrett" - - return DriverManager.getConnection(databaseUrl, dbUser, dbPassword) -} - -fun getEnvVariableOrConfig(envVar: String, configPath: String): String { - val config = ConfigFactory.load() - return System.getenv(envVar) - ?: if (config.hasPath(configPath)) config.getString(configPath) - else throw IllegalArgumentException("$envVar or $configPath must be provided") -} \ No newline at end of file diff --git a/backend/src/main/kotlin/no/bekk/configuration/DbConfiguration.kt b/backend/src/main/kotlin/no/bekk/configuration/DbConfiguration.kt new file mode 100644 index 000000000..064236911 --- /dev/null +++ b/backend/src/main/kotlin/no/bekk/configuration/DbConfiguration.kt @@ -0,0 +1,15 @@ +package no.bekk.configuration + +import java.sql.Connection +import java.sql.DriverManager + +fun getDatabaseConnection(): Connection { + val dbConfig = AppConfig.db + val connection = DriverManager.getConnection( + dbConfig.url, + dbConfig.username, + dbConfig.password + ) + connection.schema = "regelrett" + return connection +} \ No newline at end of file diff --git a/backend/src/main/kotlin/no/bekk/database/DatabaseRepository.kt b/backend/src/main/kotlin/no/bekk/database/DatabaseRepository.kt index 732c19292..f0d19e052 100644 --- a/backend/src/main/kotlin/no/bekk/database/DatabaseRepository.kt +++ b/backend/src/main/kotlin/no/bekk/database/DatabaseRepository.kt @@ -8,15 +8,6 @@ import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Table class DatabaseRepository { - fun connectToDatabase() { - Database.connect( - url = "jdbc:postgresql://localhost:5432/kontrollere", - driver = "org.postgresql.Driver", - user = "username", - password = "password" - ) - } - object Users : Table() { val id = integer("id").autoIncrement() val name = varchar("name", length = 50) diff --git a/backend/src/main/kotlin/no/bekk/plugins/Config.kt b/backend/src/main/kotlin/no/bekk/plugins/Config.kt deleted file mode 100644 index 6db661248..000000000 --- a/backend/src/main/kotlin/no/bekk/plugins/Config.kt +++ /dev/null @@ -1,9 +0,0 @@ -package no.bekk.plugins - -import io.ktor.util.* -import no.bekk.singletons.Env - -object Config { - val isDevelopment: Boolean - get() = Env.get("ENVIRONMENT").toLowerCasePreservingASCIIRules() == "development" -} diff --git a/backend/src/main/kotlin/no/bekk/plugins/Cors.kt b/backend/src/main/kotlin/no/bekk/plugins/Cors.kt index 9d3e72d3c..e7310f25a 100644 --- a/backend/src/main/kotlin/no/bekk/plugins/Cors.kt +++ b/backend/src/main/kotlin/no/bekk/plugins/Cors.kt @@ -3,11 +3,11 @@ package no.bekk.plugins import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.plugins.cors.routing.* -import no.bekk.configuration.getEnvVariableOrConfig +import no.bekk.configuration.AppConfig fun Application.configureCors() { install(CORS) { - allowHost(getEnvVariableOrConfig("FRONTEND_URL_HOST", "ktor.deployment.frontendUrlHost")) + allowHost(AppConfig.frontend.host) allowCredentials = true allowSameOrigin = true allowHeader(HttpHeaders.ContentType) diff --git a/backend/src/main/kotlin/no/bekk/plugins/FlywayMigrate.kt b/backend/src/main/kotlin/no/bekk/plugins/FlywayMigrate.kt index 9c3ec64d4..147d64f40 100644 --- a/backend/src/main/kotlin/no/bekk/plugins/FlywayMigrate.kt +++ b/backend/src/main/kotlin/no/bekk/plugins/FlywayMigrate.kt @@ -1,22 +1,16 @@ package no.bekk.plugins -import io.ktor.server.application.* -import no.bekk.configuration.getEnvVariableOrConfig +import no.bekk.configuration.AppConfig import org.flywaydb.core.Flyway -fun Application.runFlywayMigration() { - val dbUser = getEnvVariableOrConfig("DB_USER", "ktor.database.user") - val dbPassword = getEnvVariableOrConfig("DB_PASSWORD", "ktor.database.password") - - val dbUrl = "jdbc:postgresql://localhost:5432/regelrett" - +fun runFlywayMigration() { val flyway = Flyway.configure() - .createSchemas(true) - .defaultSchema("regelrett") .dataSource( - dbUrl, dbUser, dbPassword + AppConfig.db.url, + AppConfig.db.username, + AppConfig.db.password ) - .locations("filesystem:src/main/resources/db/migration") + .schemas("regelrett") .load() flyway.migrate() } \ No newline at end of file diff --git a/backend/src/main/kotlin/no/bekk/plugins/Routing.kt b/backend/src/main/kotlin/no/bekk/plugins/Routing.kt index 67e870470..ac78e1293 100644 --- a/backend/src/main/kotlin/no/bekk/plugins/Routing.kt +++ b/backend/src/main/kotlin/no/bekk/plugins/Routing.kt @@ -20,18 +20,7 @@ fun Application.configureRouting() { authenticationRouting() - if (!Config.isDevelopment) { - authenticate("auth-jwt") { - alleRouting() - answerRouting() - commentRouting() - kontrollereRouting() - metodeverkRouting() - questionRouting() - tableRouting() - userInfoRouting() - } - } else { + authenticate("auth-jwt") { alleRouting() answerRouting() commentRouting() @@ -41,6 +30,5 @@ fun Application.configureRouting() { tableRouting() userInfoRouting() } - } } diff --git a/backend/src/main/kotlin/no/bekk/routes/AuthenticationRouting.kt b/backend/src/main/kotlin/no/bekk/routes/AuthenticationRouting.kt index 1d8871da9..7898fc555 100644 --- a/backend/src/main/kotlin/no/bekk/routes/AuthenticationRouting.kt +++ b/backend/src/main/kotlin/no/bekk/routes/AuthenticationRouting.kt @@ -7,29 +7,23 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.sessions.* import no.bekk.authentication.UserSession -import no.bekk.plugins.Config -import no.bekk.singletons.Env +import no.bekk.configuration.AppConfig + fun Route.authenticationRouting() { - get("/auth-status"){ - if(Config.isDevelopment) { + get("/auth-status") { + val userSession: UserSession? = call.sessions.get() + if (userSession != null) { call.respond(HttpStatusCode.OK, mapOf("authenticated" to true)) } else { - val userSession: UserSession? = call.sessions.get() - if (userSession != null){ - call.respond(HttpStatusCode.OK, mapOf("authenticated" to true)) - } else { - call.respond(HttpStatusCode.Unauthorized, mapOf("authenticated" to false)) - } + call.respond(HttpStatusCode.Unauthorized, mapOf("authenticated" to false)) } } - if (!Config.isDevelopment) { - authenticate ( "auth-oauth-azure" ) { - get("/login") { - call.respondText("Login endpoint") - } + authenticate("auth-oauth-azure") { + get("/login") { + call.respondText("Login endpoint") } get("/callback") { val currentPrincipal: OAuthAccessTokenResponse.OAuth2? = call.principal() @@ -45,8 +39,12 @@ fun Route.authenticationRouting() { } } } - call.respondRedirect("https://${Env.get("FRONTEND_URL_HOST")}") + val providerUrl = if (AppConfig.frontend.host.startsWith("localhost")) { + "http://${AppConfig.frontend.host}" + } else { + "https://${AppConfig.frontend.host}" + } + call.respondRedirect(providerUrl) } } - } \ No newline at end of file diff --git a/backend/src/main/kotlin/no/bekk/services/AirTableService.kt b/backend/src/main/kotlin/no/bekk/services/AirTableService.kt index 04651b188..3a9d25ecf 100644 --- a/backend/src/main/kotlin/no/bekk/services/AirTableService.kt +++ b/backend/src/main/kotlin/no/bekk/services/AirTableService.kt @@ -6,17 +6,15 @@ import io.ktor.client.engine.cio.* import io.ktor.client.plugins.auth.* import io.ktor.client.plugins.auth.providers.* import io.ktor.client.request.* -import io.ktor.client.request.headers import io.ktor.client.statement.* +import io.ktor.http.* import kotlinx.serialization.json.* -import no.bekk.airtableAccessToken -import no.bekk.alleAddress +import no.bekk.configuration.AppConfig import no.bekk.domain.AirtableResponse import no.bekk.domain.AlleResponse import no.bekk.domain.MetadataResponse import no.bekk.domain.Record -import no.bekk.metadataAddress -import no.bekk.metodeverkAddress + class AirTableService { @@ -27,7 +25,7 @@ class AirTableService { install(Auth) { bearer { loadTokens { - BearerTokens(airtableAccessToken, "") + BearerTokens(AppConfig.airTable.accessToken, "") } } } @@ -53,8 +51,7 @@ class AirTableService { } suspend fun fetchDataFromMetadata(): MetadataResponse { - - val response: HttpResponse = client.get(metadataAddress) + val response: HttpResponse = client.get(AppConfig.airTable.baseUrl + AppConfig.airTable.metadataPath) val responseBody = response.body() val metadataResponse: MetadataResponse = json.decodeFromString(responseBody) val filteredMetaData = filterDataOnStop(metadataResponse = metadataResponse) @@ -78,14 +75,14 @@ class AirTableService { private suspend fun fetchMetodeverkPage(offset: String? = null): AirtableResponse { val url = buildString { - append(metodeverkAddress) + append(AppConfig.airTable.baseUrl + AppConfig.airTable.metodeVerkPath) if (offset != null) { append("&offset=$offset") } } val response: HttpResponse = client.get(url) { headers { - append("Authorization", "Bearer $airtableAccessToken") + append("Authorization", "Bearer ${AppConfig.airTable.accessToken}") } } val responseBody = response.bodyAsText() @@ -93,7 +90,7 @@ class AirTableService { } suspend fun fetchDataFromAlle(): AlleResponse { - val response: HttpResponse = client.get(alleAddress) + val response: HttpResponse = client.get(AppConfig.airTable.baseUrl + AppConfig.airTable.allePath) val responseBody = response.body() val alleResponse: AlleResponse = json.decodeFromString(responseBody) return alleResponse diff --git a/backend/src/main/kotlin/no/bekk/services/MicrosoftService.kt b/backend/src/main/kotlin/no/bekk/services/MicrosoftService.kt index b958083f2..0cbfaf207 100644 --- a/backend/src/main/kotlin/no/bekk/services/MicrosoftService.kt +++ b/backend/src/main/kotlin/no/bekk/services/MicrosoftService.kt @@ -9,10 +9,10 @@ import io.ktor.client.statement.* import io.ktor.http.* import kotlinx.serialization.json.Json import no.bekk.authentication.UserSession +import no.bekk.configuration.AppConfig +import no.bekk.configuration.getTokenUrl import no.bekk.domain.MicrosoftGraphGroupDisplayNameResponse import no.bekk.domain.MicrosoftOnBehalfOfTokenResponse -import no.bekk.graphApiMemberOfAddress -import no.bekk.singletons.Env class MicrosoftService { @@ -22,14 +22,14 @@ class MicrosoftService { suspend fun requestTokenOnBehalfOf(userSession: UserSession?): String { val response: HttpResponse = userSession?.let { - client.post("https://login.microsoftonline.com/${Env.get("TENANT_ID")}/oauth2/v2.0/token") { + client.post(AppConfig.oAuth.getTokenUrl()) { contentType(ContentType.Application.FormUrlEncoded) setBody( FormDataContent( Parameters.build { append("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer") - append("client_id", Env.get("AUTH_CLIENT_ID")) - append("client_secret", Env.get("AUTH_CLIENT_SECRET")) + append("client_id", AppConfig.oAuth.clientId) + append("client_secret", AppConfig.oAuth.clientSecret) append("assertion", it.token) append("scope", "Group.Read.All") append("requested_token_use", "on_behalf_of") @@ -47,14 +47,16 @@ class MicrosoftService { suspend fun fetchGroupNames(bearerToken: String): List { // The relevant groups from Entra ID have a known prefix. val urlEncodedKnownGroupPrefix = "AAD - TF - TEAM - ".encodeURLPath() - val url = "$graphApiMemberOfAddress?\$count=true&\$select=displayName&\$filter=startswith(displayName,'$urlEncodedKnownGroupPrefix')" + val url = + "${AppConfig.microsoftGraph.baseUrl + AppConfig.microsoftGraph.memberOfPath}?\$count=true&\$select=displayName&\$filter=startswith(displayName,'$urlEncodedKnownGroupPrefix')" val response: HttpResponse = client.get(url) { bearerAuth(bearerToken) header("ConsistencyLevel", "eventual") } val responseBody = response.body() - val microsoftGraphGroupDisplayNameResponse: MicrosoftGraphGroupDisplayNameResponse = json.decodeFromString(responseBody) + val microsoftGraphGroupDisplayNameResponse: MicrosoftGraphGroupDisplayNameResponse = + json.decodeFromString(responseBody) return microsoftGraphGroupDisplayNameResponse.value.map { it.displayName.split("TEAM - ").last() } } } \ No newline at end of file diff --git a/backend/src/main/resources/application.conf.template b/backend/src/main/resources/application.conf.template deleted file mode 100644 index 3e52668e6..000000000 --- a/backend/src/main/resources/application.conf.template +++ /dev/null @@ -1,16 +0,0 @@ -ktor { - application { - modules = [ "no.bekk.ApplicationKt.module" ] - } - deployment { - port = 8080 - frontendUrlHost = "localhost:3000" - } - database { - host = "localhost" - port = 5432 - name = "kontrollere" - user = "insert_username_here" - password = "pwd" - } -} \ No newline at end of file diff --git a/backend/src/main/resources/application.yaml b/backend/src/main/resources/application.yaml index 12430d543..6021a9fec 100644 --- a/backend/src/main/resources/application.yaml +++ b/backend/src/main/resources/application.yaml @@ -1,6 +1,36 @@ ktor: - application: - modules: - - no.bekk.ApplicationKt.module - deployment: - port: 8080 \ No newline at end of file + application: + modules: + - no.bekk.ApplicationKt.module + deployment: + port: 8080 + +airTable: + accessToken: $AIRTABLE_ACCESS_TOKEN + baseUrl: "https://api.airtable.com" + metadataPath: "/v0/meta/bases/appzJQ8Tkmm8DobrJ/tables" + metodeVerkPath: "/v0/appzJQ8Tkmm8DobrJ/tblLZbUqA0XnUgC2v?view=viw2XliGUJu5448Hk" + allePath: "/v0/appzJQ8Tkmm8DobrJ/tblLZbUqA0XnUgC2v" + +microsoftGraph: + baseUrl: "https://graph.microsoft.com" + memberOfPath: "/v1.0/me/memberOf/microsoft.graph.group" + +oAuth: + baseUrl: "https://login.microsoftonline.com" + tenantId: $TENANT_ID + issuerPath: "/v2.0" + authPath: "/oauth2/v2.0/authorize" + tokenPath: "/oauth2/v2.0/token" + jwksPath: "/discovery/v2.0/keys" + clientId: $CLIENT_ID + clientSecret: $CLIENT_SECRET + providerUrl: "$AUTH_PROVIDER_URL:http://localhost:8080/callback" + +frontend: + host: "$FRONTEND_URL_HOST:localhost:3000" + +db: + url: "jdbc:postgresql://localhost:5432/regelrett" + username: "$DB_NAME:postgres" + password: "$DB_PASSWORD:pwd" diff --git a/frontend/beCompliant/.env b/frontend/beCompliant/.env new file mode 100644 index 000000000..e1167733d --- /dev/null +++ b/frontend/beCompliant/.env @@ -0,0 +1,2 @@ +VITE_FRONTEND_URL=http://localhost:3000 +VITE_BACKEND_URL=http://localhost:8080 \ No newline at end of file diff --git a/frontend/beCompliant/.gitignore b/frontend/beCompliant/.gitignore index 731b628cb..54f07af58 100644 --- a/frontend/beCompliant/.gitignore +++ b/frontend/beCompliant/.gitignore @@ -21,7 +21,4 @@ dist-ssr *.ntvs* *.njsproj *.sln -*.sw? - -# Env files -.env \ No newline at end of file +*.sw? \ No newline at end of file