From 06cc8cf203ba0edb3a7bea28d16a15f0fb17b992 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 2 Nov 2025 14:25:47 +0100 Subject: [PATCH 01/18] refactor(authentication): remove unused getAuth0User method and related tests --- .../autobank/service/AuthenticationService.kt | 4 ---- .../service/AuthenticationServiceTest.kt | 16 ---------------- 2 files changed, 20 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 066329c..ffaaf0d 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -37,10 +37,6 @@ class AuthenticationService( @Autowired lateinit var onlineUserRepository: OnlineUserRepository - fun getAuth0User(token: String): Auth0User { - return Auth0User("sub", "email", "name") - } - fun getSecondsUntilExpiration(): Long { val expiresAt = getExpiresAt() return if (expiresAt != null) { diff --git a/src/test/kotlin/com/example/autobank/service/AuthenticationServiceTest.kt b/src/test/kotlin/com/example/autobank/service/AuthenticationServiceTest.kt index fccfb24..2a85c9c 100644 --- a/src/test/kotlin/com/example/autobank/service/AuthenticationServiceTest.kt +++ b/src/test/kotlin/com/example/autobank/service/AuthenticationServiceTest.kt @@ -23,22 +23,6 @@ class AuthenticationServiceTest : FunSpec({ this.onlineUserRepository = onlineUserRepository } - context("getAuth0User") { - test("should return Auth0User with provided token") { - // Given - val token = "test-token" - - // When - val result = authenticationService.getAuth0User(token) - - // Then - result shouldNotBe null - result.sub shouldBe "sub" - result.email shouldBe "email" - result.name shouldBe "name" - } - } - context("getUserSub") { test("should return empty string when no authentication context") { // When From a4d88356d0ad0a55aec7f4fa1457c80789e3fe16 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 2 Nov 2025 14:38:11 +0100 Subject: [PATCH 02/18] fix(authentication): update Auth0User mapping and correct userinfo URL --- .../autobank/data/authentication/Auth0User.kt | 13 +++++++++++++ .../autobank/service/AuthenticationService.kt | 12 ++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt b/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt index 52491b9..da844bd 100644 --- a/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt +++ b/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt @@ -1,5 +1,6 @@ package com.example.autobank.data.authentication +import com.nimbusds.openid.connect.sdk.claims.Gender import org.jetbrains.annotations.NotNull import io.swagger.v3.oas.annotations.media.Schema @@ -12,4 +13,16 @@ class Auth0User( val email: String, @NotNull val name: String, + @NotNull + val given_name: String, + @NotNull + val family_name: String, + @NotNull + val nickname: String, + @NotNull + val picture: String, + @NotNull + val gender: String, + @NotNull + val email_verified: String, ) \ No newline at end of file diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index ffaaf0d..7af4cc6 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -76,7 +76,7 @@ class AuthenticationService( } val entity = HttpEntity(headers) val response: ResponseEntity> = restTemplate.exchange( - "${domain}/userinfo", + "https://${domain}/userinfo", HttpMethod.GET, entity, ) @@ -84,7 +84,13 @@ class AuthenticationService( return Auth0User( sub = response.body?.get("sub").toString(), email = response.body?.get("email").toString(), - name = response.body?.get("name").toString(), + given_name = response.body?.get("given_name").toString(), + family_name = response.body?.get("family_name").toString(), + nickname = response.body?.get("nickname").toString(), + picture = response.body?.get("picture").toString(), + gender = response.body?.get("gender").toString(), + email_verified = response.body?.get("email_verified").toString(), + name = response.body?.get("given_name").toString() + " " + response.body?.get("family_name").toString() ) } @@ -182,5 +188,3 @@ class AuthenticationService( ) } - - From cb179506e7af4f068b7389902928b41f46936bae Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 2 Nov 2025 14:52:14 +0100 Subject: [PATCH 03/18] Add detailed JWT validation logging --- .../autobank/security/AudienceValidator.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/security/AudienceValidator.kt b/src/main/kotlin/com/example/autobank/security/AudienceValidator.kt index 2b5742c..c1b9fcf 100644 --- a/src/main/kotlin/com/example/autobank/security/AudienceValidator.kt +++ b/src/main/kotlin/com/example/autobank/security/AudienceValidator.kt @@ -1,18 +1,27 @@ package com.example.autobank.security - import org.springframework.security.oauth2.core.OAuth2Error import org.springframework.security.oauth2.core.OAuth2TokenValidator import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult import org.springframework.security.oauth2.jwt.Jwt +import org.slf4j.LoggerFactory class AudienceValidator(private val audience: String) : OAuth2TokenValidator { + private val logger = LoggerFactory.getLogger(AudienceValidator::class.java) + override fun validate(jwt: Jwt): OAuth2TokenValidatorResult { + logger.info("=== Validating JWT Audience ===") + logger.info("Expected audience: $audience") + logger.info("Token audiences: ${jwt.audience}") + val error = OAuth2Error("invalid_token", "The required audience is missing", null) return if (jwt.audience.contains(audience)) { + logger.info("Audience validation: SUCCESS") OAuth2TokenValidatorResult.success() - } else OAuth2TokenValidatorResult.failure(error) + } else { + logger.error("Audience validation: FAILED - Required audience '$audience' not found in ${jwt.audience}") + OAuth2TokenValidatorResult.failure(error) + } } - } \ No newline at end of file From b7698bd8c3d07293f212f55803265d7c800d4201 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 2 Nov 2025 14:56:21 +0100 Subject: [PATCH 04/18] refactor(authentication): enhance logging in checkUser method and clean up code --- .../controller/AuthenticationController.kt | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/controller/AuthenticationController.kt b/src/main/kotlin/com/example/autobank/controller/AuthenticationController.kt index 325b67f..1924c22 100644 --- a/src/main/kotlin/com/example/autobank/controller/AuthenticationController.kt +++ b/src/main/kotlin/com/example/autobank/controller/AuthenticationController.kt @@ -1,35 +1,40 @@ package com.example.autobank.controller - import com.example.autobank.data.authentication.AuthenticatedUserResponse -import com.example.autobank.service.AuthenticationService import com.example.autobank.service.OnlineUserService -import jakarta.servlet.http.HttpServletRequest -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import org.springframework.http.ResponseCookie -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag - +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api/auth") @Tag(name = "Authentication Controller", description = "Endpoints for user authentication") class AuthenticationController { + + private val logger = LoggerFactory.getLogger(AuthenticationController::class.java) + @Autowired - lateinit var onlineUserService: OnlineUserService; + lateinit var onlineUserService: OnlineUserService @Operation(summary = "Check authenticated user", description = "Returns information about the currently authenticated user") @GetMapping("/getuser") fun checkUser(): ResponseEntity { - return try { - ResponseEntity.ok().body(onlineUserService.checkUser()) - } catch (e: Exception) { - print(e) - ResponseEntity.badRequest().build(); - } + return try { + logger.info("=== /api/auth/getuser called ===") + val result = onlineUserService.checkUser() + logger.info("checkUser result: success=${result.success}, isadmin=${result.isadmin}") + ResponseEntity.ok().body(result) + } catch (e: Exception) { + logger.error("=== Exception in /api/auth/getuser ===", e) + logger.error("Exception type: ${e.javaClass.name}") + logger.error("Exception message: ${e.message}") + logger.error("Stack trace:", e) + ResponseEntity.badRequest().build() } - + } } \ No newline at end of file From ab1861761c6a72b876dc16bc5c844ea34c57e685 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 14:57:53 +0100 Subject: [PATCH 05/18] update fetching to use trpc --- .../autobank/data/authentication/Auth0User.kt | 12 -- .../autobank/service/AuthenticationService.kt | 107 +++++++++--------- 2 files changed, 56 insertions(+), 63 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt b/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt index da844bd..de464a2 100644 --- a/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt +++ b/src/main/kotlin/com/example/autobank/data/authentication/Auth0User.kt @@ -13,16 +13,4 @@ class Auth0User( val email: String, @NotNull val name: String, - @NotNull - val given_name: String, - @NotNull - val family_name: String, - @NotNull - val nickname: String, - @NotNull - val picture: String, - @NotNull - val gender: String, - @NotNull - val email_verified: String, ) \ No newline at end of file diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 7af4cc6..ae82a23 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -2,6 +2,7 @@ package com.example.autobank.service import com.example.autobank.data.authentication.Auth0User import com.example.autobank.repository.user.OnlineUserRepository +import com.fasterxml.jackson.databind.ObjectMapper import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.core.ParameterizedTypeReference @@ -14,6 +15,8 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtAut import org.springframework.stereotype.Service import org.springframework.web.client.RestTemplate import org.springframework.web.client.exchange +import java.net.URLEncoder +import java.nio.charset.StandardCharsets import java.time.Duration import java.time.Instant import java.time.LocalDateTime @@ -24,14 +27,11 @@ class AuthenticationService( @Value("\${admincommittee}") private val adminCommittee: String, @Value("\${auth0.domain}") private val domain: String, @Value("\${environment}") private val environment: String, + @Value("\${api.base.domain}") private val apiBaseDomain: String, ) { private val restTemplate = RestTemplate() - private val fetchProfileUrl = "https://old.online.ntnu.no/api/v1/profile/" - - private val fetchUserCommitteesUrl = "https://old.online.ntnu.no/api/v1/group/online-groups/?members__user=" - private val adminRecheckTime = 24 * 60 * 60 * 1000; @Autowired @@ -76,21 +76,20 @@ class AuthenticationService( } val entity = HttpEntity(headers) val response: ResponseEntity> = restTemplate.exchange( - "https://${domain}/userinfo", + "$apiBaseDomain/user.getMe", HttpMethod.GET, entity, ) + // Navigate to the nested json object + val result = response.body?.get("result") as? Map<*, *> + val data = result?.get("data") as? Map<*, *> + val json = data?.get("json") as? Map<*, *> + return Auth0User( - sub = response.body?.get("sub").toString(), - email = response.body?.get("email").toString(), - given_name = response.body?.get("given_name").toString(), - family_name = response.body?.get("family_name").toString(), - nickname = response.body?.get("nickname").toString(), - picture = response.body?.get("picture").toString(), - gender = response.body?.get("gender").toString(), - email_verified = response.body?.get("email_verified").toString(), - name = response.body?.get("given_name").toString() + " " + response.body?.get("family_name").toString() + sub = json?.get("id")?.toString() ?: "", + email = json?.get("email")?.toString() ?: "", + name = json?.get("name")?.toString() ?: "" ) } @@ -100,7 +99,7 @@ class AuthenticationService( } val entity = HttpEntity(headers) val response: ResponseEntity> = restTemplate.exchange( - fetchProfileUrl, + apiBaseDomain, HttpMethod.GET, entity, ) @@ -111,63 +110,56 @@ class AuthenticationService( return response.body?.get("id").toString().toInt() } - fun fetchUserCommittees(): List { - if (environment != "prod") { - return listOf("Applikasjonskomiteen", "Trivselskomiteen") + return listOf("Applikasjonskomiteen") } + // fetch users id, should probably be stored in user object val userId = fetchOnlineuserId() + val input = mapOf("id" to userId) + val inputJson = ObjectMapper().writeValueAsString(input) + val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) + val endpoint = "${apiBaseDomain}group.allByMember?input=$encodedInput" - val headers = HttpHeaders() + val headers = HttpHeaders().apply { + set("Authorization", "Bearer ${getAccessToken()}") + } val entity = HttpEntity(headers) val response: ResponseEntity = restTemplate.exchange( - fetchUserCommitteesUrl + userId, + endpoint, HttpMethod.GET, entity, - object : ParameterizedTypeReference() {} - ) + object : ParameterizedTypeReference() {}) if (response.statusCode.isError || response.body == null) { throw Exception("Error fetching user committees") } - return response.body?.results?.map { it.name_long } ?: listOf() + return response.body?.result?.data?.json?.map { it.slug } ?: listOf() } fun checkAdmin(): Boolean { val user = onlineUserRepository.findByOnlineId(getUserSub()) ?: throw Exception("User not found"); - val currentTime = LocalDateTime.now() - if (Duration.between(user.lastUpdated, currentTime).toMillis() > adminRecheckTime) { - user.lastUpdated = currentTime - val isAdmin = checkBankomMembership() - user.isAdmin = isAdmin - onlineUserRepository.save(user) + // Time check for users last update isAdmin + if (Duration.between(user.lastUpdated, LocalDateTime.now()).toMillis() > adminRecheckTime) { + user.lastUpdated = LocalDateTime.now() - return isAdmin; - } else { - return user.isAdmin; - } - } + // Check if the user is admin and set bool accordingly + user.isAdmin = fetchUserCommittees().contains(adminCommittee) - private fun checkBankomMembership(): Boolean { - if (environment == "dev") { - return true + // I dont know what this is + onlineUserRepository.save(user) } - val userCommittees = fetchUserCommittees() - return userCommittees.contains(adminCommittee) - } + if (user.isAdmin) { + return true; + } - /* - fun checkSuperAdmin(): Boolean { - return superadminEmails.split(",").contains(getUserDetails().email) + return false; } - */ - fun getExpiresAt(): Instant? { val authentication = SecurityContextHolder.getContext().authentication @@ -179,12 +171,25 @@ class AuthenticationService( } } - data class Result( - val name_long: String = "" - ) + data class UserCommitteeResponse( + val result: Result + ) - data class UserCommitteeResponse( - val results: List = listOf() - ) + data class Result( + val data: Data + ) + + data class Data( + val json: List + ) + + data class Committee( + val slug: String, + val abbreviation: String, + val name: String, + val type: String, + val memberVisibility: String, + // Add other fields if needed + ) } From 2b8013480b29656bbaeb13fef4faf71bf9e33350 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:25:53 +0100 Subject: [PATCH 06/18] Update AuthenticationService.kt --- .../example/autobank/service/AuthenticationService.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index ae82a23..1987060 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -94,12 +94,21 @@ class AuthenticationService( } private fun fetchOnlineuserId(): Int { + + val input = mapOf("accessToken" to getAccessToken()) + val inputJson = ObjectMapper().writeValueAsString(input) + val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) + + // Include the procedure name in the URL + val endpoint = "${apiBaseDomain}user.getByAccessToken?input=$encodedInput" + val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") } val entity = HttpEntity(headers) + val response: ResponseEntity> = restTemplate.exchange( - apiBaseDomain, + endpoint, HttpMethod.GET, entity, ) From 5c1db20d0e5526af8a1b6b0d7a33d33a1d4db6fb Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:30:16 +0100 Subject: [PATCH 07/18] Update AuthenticationService.kt --- .../com/example/autobank/service/AuthenticationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 1987060..2e84859 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -100,7 +100,7 @@ class AuthenticationService( val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) // Include the procedure name in the URL - val endpoint = "${apiBaseDomain}user.getByAccessToken?input=$encodedInput" + val endpoint = "${domain}/userinfo" val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") From 5108706ee95e2f430e9e5887da76a58ed9906d95 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:38:29 +0100 Subject: [PATCH 08/18] Update AuthenticationService.kt --- .../autobank/service/AuthenticationService.kt | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 2e84859..e5cf77c 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -79,6 +79,7 @@ class AuthenticationService( "$apiBaseDomain/user.getMe", HttpMethod.GET, entity, + ) // Navigate to the nested json object @@ -93,39 +94,13 @@ class AuthenticationService( ) } - private fun fetchOnlineuserId(): Int { - - val input = mapOf("accessToken" to getAccessToken()) - val inputJson = ObjectMapper().writeValueAsString(input) - val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) - - // Include the procedure name in the URL - val endpoint = "${domain}/userinfo" - - val headers = HttpHeaders().apply { - set("Authorization", "Bearer ${getAccessToken()}") - } - val entity = HttpEntity(headers) - - val response: ResponseEntity> = restTemplate.exchange( - endpoint, - HttpMethod.GET, - entity, - ) - - if (response.statusCode.isError || response.body == null) { - throw Exception("Error fetching user id") - } - - return response.body?.get("id").toString().toInt() - } fun fetchUserCommittees(): List { if (environment != "prod") { return listOf("Applikasjonskomiteen") } // fetch users id, should probably be stored in user object - val userId = fetchOnlineuserId() + val userId = getUserDetails().sub val input = mapOf("id" to userId) val inputJson = ObjectMapper().writeValueAsString(input) val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) From 3bc4f727d566bf483a003c149d53b737504db3e0 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:41:31 +0100 Subject: [PATCH 09/18] Update AuthenticationService.kt --- .../example/autobank/service/AuthenticationService.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index e5cf77c..8becc82 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -15,6 +15,7 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtAut import org.springframework.stereotype.Service import org.springframework.web.client.RestTemplate import org.springframework.web.client.exchange +import org.springframework.web.util.UriComponentsBuilder import java.net.URLEncoder import java.nio.charset.StandardCharsets import java.time.Duration @@ -103,8 +104,12 @@ class AuthenticationService( val userId = getUserDetails().sub val input = mapOf("id" to userId) val inputJson = ObjectMapper().writeValueAsString(input) - val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) - val endpoint = "${apiBaseDomain}group.allByMember?input=$encodedInput" + + val endpoint = UriComponentsBuilder + .fromHttpUrl("${apiBaseDomain}group.allByMember") + .queryParam("input", inputJson) + .encode() // This handles proper encoding + .toUriString() val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") From 9061e79f56a0f9ec469959911d218e8ae1fd6cb9 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:47:38 +0100 Subject: [PATCH 10/18] Update AuthenticationService.kt --- .../com/example/autobank/service/AuthenticationService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 8becc82..9d7d735 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -77,7 +77,7 @@ class AuthenticationService( } val entity = HttpEntity(headers) val response: ResponseEntity> = restTemplate.exchange( - "$apiBaseDomain/user.getMe", + "https://onlineweb-prod.eu.auth0.com/user.getMe", HttpMethod.GET, entity, From aacb8f723d570109c86a1928ee561eb6a07def60 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:54:17 +0100 Subject: [PATCH 11/18] Update AuthenticationService.kt --- .../autobank/service/AuthenticationService.kt | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 9d7d735..998fb23 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -76,23 +76,19 @@ class AuthenticationService( set("Authorization", "Bearer ${getAccessToken()}") } val entity = HttpEntity(headers) - val response: ResponseEntity> = restTemplate.exchange( - "https://onlineweb-prod.eu.auth0.com/user.getMe", + val response: ResponseEntity = restTemplate.exchange( + "${domain}/user.getMe", HttpMethod.GET, entity, ) - // Navigate to the nested json object - val result = response.body?.get("result") as? Map<*, *> - val data = result?.get("data") as? Map<*, *> - val json = data?.get("json") as? Map<*, *> + if (response.statusCode.isError || response.body == null) { + throw Exception("Error fetching user committees") + } - return Auth0User( - sub = json?.get("id")?.toString() ?: "", - email = json?.get("email")?.toString() ?: "", - name = json?.get("name")?.toString() ?: "" - ) + val results = response.body?.result?.data?.json?.first() ?: throw Exception("User not found") + return Auth0User(results.id, results.email, results.name) } fun fetchUserCommittees(): List { @@ -181,4 +177,21 @@ class AuthenticationService( // Add other fields if needed ) + data class UserResponse( + val result: userResult + ) + + data class userResult( + val data: userData + ) + + data class userData( + val json: List + ) + + data class User ( + val id: String, + val email: String, + val name: String, + ) } From 1e2f0cc6c68ff083fc94a9c92e9184b60c0acd16 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 16:58:21 +0100 Subject: [PATCH 12/18] Update AuthenticationService.kt --- .../autobank/service/AuthenticationService.kt | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 998fb23..1ed91cb 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -72,23 +72,31 @@ class AuthenticationService( } fun getUserDetails(): Auth0User { + val endpoint = UriComponentsBuilder + .fromHttpUrl("${apiBaseDomain}user.getMe") + .encode() + .toUriString() + val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") } val entity = HttpEntity(headers) + val response: ResponseEntity = restTemplate.exchange( - "${domain}/user.getMe", + endpoint, HttpMethod.GET, entity, - + object : ParameterizedTypeReference() {} ) if (response.statusCode.isError || response.body == null) { - throw Exception("Error fetching user committees") + throw Exception("Error fetching user details") } - val results = response.body?.result?.data?.json?.first() ?: throw Exception("User not found") - return Auth0User(results.id, results.email, results.name) + val user = response.body?.result?.data?.json?.firstOrNull() + ?: throw Exception("User not found") + + return Auth0User(user.id, user.email, user.name) } fun fetchUserCommittees(): List { @@ -96,7 +104,6 @@ class AuthenticationService( return listOf("Applikasjonskomiteen") } - // fetch users id, should probably be stored in user object val userId = getUserDetails().sub val input = mapOf("id" to userId) val inputJson = ObjectMapper().writeValueAsString(input) @@ -104,24 +111,26 @@ class AuthenticationService( val endpoint = UriComponentsBuilder .fromHttpUrl("${apiBaseDomain}group.allByMember") .queryParam("input", inputJson) - .encode() // This handles proper encoding + .encode() .toUriString() val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") } val entity = HttpEntity(headers) + val response: ResponseEntity = restTemplate.exchange( endpoint, HttpMethod.GET, entity, - object : ParameterizedTypeReference() {}) + object : ParameterizedTypeReference() {} + ) if (response.statusCode.isError || response.body == null) { throw Exception("Error fetching user committees") } - return response.body?.result?.data?.json?.map { it.slug } ?: listOf() + return response.body?.result?.data?.json?.map { it.slug } ?: emptyList() } fun checkAdmin(): Boolean { From 8d594c70e43ec148cf9597444c41a9391aae5a04 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 17:02:53 +0100 Subject: [PATCH 13/18] Update AuthenticationService.kt --- .../autobank/service/AuthenticationService.kt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 1ed91cb..555de81 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -93,7 +93,7 @@ class AuthenticationService( throw Exception("Error fetching user details") } - val user = response.body?.result?.data?.json?.firstOrNull() + val user = response.body?.result?.data?.json ?: throw Exception("User not found") return Auth0User(user.id, user.email, user.name) @@ -185,22 +185,21 @@ class AuthenticationService( val memberVisibility: String, // Add other fields if needed ) - data class UserResponse( - val result: userResult + val result: UserResult ) - data class userResult( - val data: userData + data class UserResult( + val data: UserData ) - data class userData( - val json: List + data class UserData( + val json: User // Single User object, not List ) - data class User ( + data class User( val id: String, val email: String, - val name: String, + val name: String ) } From 6aac69bcffb12e27a716f0c08dfadf76a7b6f7d9 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 17:28:21 +0100 Subject: [PATCH 14/18] Update AuthenticationService.kt --- .../example/autobank/service/AuthenticationService.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 555de81..836dabc 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -98,7 +98,6 @@ class AuthenticationService( return Auth0User(user.id, user.email, user.name) } - fun fetchUserCommittees(): List { if (environment != "prod") { return listOf("Applikasjonskomiteen") @@ -107,12 +106,10 @@ class AuthenticationService( val userId = getUserDetails().sub val input = mapOf("id" to userId) val inputJson = ObjectMapper().writeValueAsString(input) + val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) - val endpoint = UriComponentsBuilder - .fromHttpUrl("${apiBaseDomain}group.allByMember") - .queryParam("input", inputJson) - .encode() - .toUriString() + // Build URL as a plain string to avoid template variable interpretation + val endpoint = "${apiBaseDomain}group.allByMember?input=$encodedInput" val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") From 8bef08dbefe28ca7e2b50785e749c4757299823f Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 17:31:27 +0100 Subject: [PATCH 15/18] Update AuthenticationService.kt --- .../com/example/autobank/service/AuthenticationService.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 836dabc..6bd6adf 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -104,11 +104,12 @@ class AuthenticationService( } val userId = getUserDetails().sub - val input = mapOf("id" to userId) + + // Wrap with "json" key, and the value is just the string ID (not an object) + val input = mapOf("json" to userId) val inputJson = ObjectMapper().writeValueAsString(input) val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) - // Build URL as a plain string to avoid template variable interpretation val endpoint = "${apiBaseDomain}group.allByMember?input=$encodedInput" val headers = HttpHeaders().apply { From c1fc7d9d71d05da67c99c84ba4c2a3cd6e1c90a7 Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 17:33:55 +0100 Subject: [PATCH 16/18] Update AuthenticationService.kt --- .../autobank/service/AuthenticationService.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index 6bd6adf..fcf9a2f 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -105,12 +105,15 @@ class AuthenticationService( val userId = getUserDetails().sub - // Wrap with "json" key, and the value is just the string ID (not an object) - val input = mapOf("json" to userId) - val inputJson = ObjectMapper().writeValueAsString(input) - val encodedInput = URLEncoder.encode(inputJson, StandardCharsets.UTF_8.toString()) + // Don't encode - pass as plain JSON string + val input = """{"json":"$userId"}""" - val endpoint = "${apiBaseDomain}group.allByMember?input=$encodedInput" + // Build URL using UriComponentsBuilder which will handle encoding properly + val uri = UriComponentsBuilder + .fromHttpUrl("${apiBaseDomain}group.allByMember") + .queryParam("input", input) + .build(false) // Important: false = don't encode yet + .toUri() val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") @@ -118,7 +121,7 @@ class AuthenticationService( val entity = HttpEntity(headers) val response: ResponseEntity = restTemplate.exchange( - endpoint, + uri, // Pass URI object, not string HttpMethod.GET, entity, object : ParameterizedTypeReference() {} From a8cde46bee632bfdce59a5425d5c83b34f074e1c Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 17:38:28 +0100 Subject: [PATCH 17/18] Update AuthenticationService.kt --- .../autobank/service/AuthenticationService.kt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index fcf9a2f..fcbab7f 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -16,6 +16,7 @@ import org.springframework.stereotype.Service import org.springframework.web.client.RestTemplate import org.springframework.web.client.exchange import org.springframework.web.util.UriComponentsBuilder +import java.net.URI import java.net.URLEncoder import java.nio.charset.StandardCharsets import java.time.Duration @@ -97,23 +98,19 @@ class AuthenticationService( ?: throw Exception("User not found") return Auth0User(user.id, user.email, user.name) - } - fun fetchUserCommittees(): List { + }fun fetchUserCommittees(): List { if (environment != "prod") { return listOf("Applikasjonskomiteen") } val userId = getUserDetails().sub - // Don't encode - pass as plain JSON string - val input = """{"json":"$userId"}""" + // Just stringify the ID directly, like SuperJSON.stringify(userInfo.id) + val input = """"$userId"""" // This creates: "auth0|..." + val encodedInput = URLEncoder.encode(input, StandardCharsets.UTF_8.toString()) + val urlString = "${apiBaseDomain}group.allByMember?input=$encodedInput" - // Build URL using UriComponentsBuilder which will handle encoding properly - val uri = UriComponentsBuilder - .fromHttpUrl("${apiBaseDomain}group.allByMember") - .queryParam("input", input) - .build(false) // Important: false = don't encode yet - .toUri() + val uri = URI(urlString) val headers = HttpHeaders().apply { set("Authorization", "Bearer ${getAccessToken()}") @@ -121,7 +118,7 @@ class AuthenticationService( val entity = HttpEntity(headers) val response: ResponseEntity = restTemplate.exchange( - uri, // Pass URI object, not string + uri, HttpMethod.GET, entity, object : ParameterizedTypeReference() {} From fbee4de475ed309a1634bcf296dc5610c5c9a22b Mon Sep 17 00:00:00 2001 From: Mads Hermansen Date: Sun, 16 Nov 2025 17:41:45 +0100 Subject: [PATCH 18/18] Update AuthenticationService.kt --- .../example/autobank/service/AuthenticationService.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt index fcbab7f..6c0ca3e 100644 --- a/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt +++ b/src/main/kotlin/com/example/autobank/service/AuthenticationService.kt @@ -98,18 +98,23 @@ class AuthenticationService( ?: throw Exception("User not found") return Auth0User(user.id, user.email, user.name) - }fun fetchUserCommittees(): List { + } + + fun fetchUserCommittees(): List { if (environment != "prod") { return listOf("Applikasjonskomiteen") } val userId = getUserDetails().sub - // Just stringify the ID directly, like SuperJSON.stringify(userInfo.id) - val input = """"$userId"""" // This creates: "auth0|..." + // tRPC format: {"json":""} + // The value itself is the user ID string + val input = """{"json":"$userId"}""" val encodedInput = URLEncoder.encode(input, StandardCharsets.UTF_8.toString()) val urlString = "${apiBaseDomain}group.allByMember?input=$encodedInput" + println("Final URL: $urlString") // Debug log + val uri = URI(urlString) val headers = HttpHeaders().apply {