Skip to content

Commit 1b60ab5

Browse files
committed
RoleCheckResult
1 parent a597b19 commit 1b60ab5

2 files changed

Lines changed: 45 additions & 24 deletions

File tree

src/main/scala/com/tesobe/oidc/auth/ObpApiCredentialsService.scala

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ class ObpApiCredentialsService(
576576
}
577577
case status =>
578578
response.as[String].flatMap { body =>
579-
logger.warn(s"User lookup via OBP API returned $status: $body")
579+
logger.warn(s"User lookup via OBP API: GET $uri returned $status: $body")
580580
IO.pure(None)
581581
}
582582
}
@@ -616,15 +616,26 @@ object ObpApiCredentialsService {
616616
private val logger = LoggerFactory.getLogger(getClass)
617617
private val RequiredRole = "CanVerifyUserCredentials"
618618

619+
/** Result of checking required roles, including per-role status. */
620+
case class RoleCheckResult(
621+
userRoles: Set[String],
622+
requiredRoles: List[String]
623+
) {
624+
def roleStatus(role: String): Boolean = userRoles.contains(role)
625+
def missing: List[String] = requiredRoles.filterNot(userRoles.contains)
626+
def allPresent: Boolean = missing.isEmpty
627+
}
628+
619629
/** Check that the OBP API user has all the specified required roles.
620-
* Returns Right with success message if all roles are present,
621-
* or Left with error message listing missing roles.
622-
* This is intended as a hard startup check - callers should abort on Left.
630+
* Returns Right with RoleCheckResult if entitlements could be fetched
631+
* (even if some roles are missing), or Left with error message if
632+
* the check itself failed.
633+
* Callers should inspect RoleCheckResult.allPresent to decide whether to abort.
623634
*/
624635
def checkRequiredRoles(
625636
config: OidcConfig,
626637
requiredRoles: List[String]
627-
): IO[Either[String, String]] = {
638+
): IO[Either[String, RoleCheckResult]] = {
628639
val username = config.obpApiUsername.getOrElse("unknown")
629640
val baseUrl = config.obpApiUrl.getOrElse("unknown")
630641

@@ -659,20 +670,7 @@ object ObpApiCredentialsService {
659670
case Right(entitlements) => entitlements.map(_.role_name).toSet
660671
case Left(_) => Set.empty[String]
661672
}
662-
val present = requiredRoles.filter(userRoles.contains)
663-
val missing = requiredRoles.filterNot(userRoles.contains)
664-
if (missing.isEmpty) {
665-
Right(
666-
s"Role check passed: OBP API user '$username' has all ${requiredRoles.size} required roles: ${requiredRoles.mkString(", ")}"
667-
)
668-
} else {
669-
Left(
670-
s"STARTUP ABORTED: OBP API user '$username' is missing required role(s): ${missing.mkString(", ")}. " +
671-
s"Please grant these roles to user '$username' at $baseUrl and restart. " +
672-
s"Roles present: ${if (present.nonEmpty) present.mkString(", ") else "none"}. " +
673-
s"All required roles: ${requiredRoles.mkString(", ")}"
674-
)
675-
}
673+
Right(RoleCheckResult(userRoles, requiredRoles))
676674
}
677675
case status =>
678676
response.as[String].map { body =>

src/main/scala/com/tesobe/oidc/server/OidcServer.scala

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ object OidcServer extends IOApp {
158158
} else IO.unit
159159

160160
// Test OBP API connection and verify all required roles
161+
roleCheckRef <- cats.effect.Ref.of[IO, Option[ObpApiCredentialsService.RoleCheckResult]](None)
161162
_ <- {
162163
val requiredRoles = List.empty[String] ++
163164
(config.verifyCredentialsMethod match {
@@ -179,7 +180,18 @@ object OidcServer extends IOApp {
179180
).flatMap(msg => IO(println(msg))) *>
180181
// Step 2: Check all required roles (abort immediately if any are missing)
181182
ObpApiCredentialsService.checkRequiredRoles(config, requiredRoles).flatMap {
182-
case Right(msg) => IO(println(msg))
183+
case Right(roleCheck) =>
184+
val username = config.obpApiUsername.getOrElse("unknown")
185+
val baseUrl = config.obpApiUrl.getOrElse("unknown")
186+
roleCheckRef.set(Some(roleCheck)) *>
187+
(if (roleCheck.allPresent) {
188+
IO(println(s"Role check passed: OBP API user '$username' has all ${requiredRoles.size} required roles"))
189+
} else {
190+
IO.raiseError(new RuntimeException(
191+
s"STARTUP ABORTED: OBP API user '$username' is missing required role(s): ${roleCheck.missing.mkString(", ")}. " +
192+
s"Please grant these roles to user '$username' at $baseUrl and restart."
193+
))
194+
})
183195
case Left(error) => IO.raiseError(new RuntimeException(error))
184196
}
185197
} else {
@@ -951,13 +963,24 @@ object OidcServer extends IOApp {
951963
IO(println(s"USE_VERIFY_ENDPOINTS: ${config.useVerifyEndpoints}")) *>
952964
(if (config.useVerifyEndpoints) {
953965
val username = config.obpApiUsername.getOrElse("unknown")
966+
val roleEndpoints = List(
967+
("CanVerifyUserCredentials", "POST /obp/v6.0.0/users/verify-credentials"),
968+
("CanGetAnyUser", "GET /obp/v6.0.0/users/provider/PROVIDER/username/USERNAME"),
969+
("CanGetOidcClient", "GET /obp/v6.0.0/oidc/clients/CLIENT_ID"),
970+
("CanGetConsumers", "GET /obp/v6.0.0/management/consumers")
971+
)
954972
IO(println(" All verification methods use OBP API endpoints")) *>
955973
IO(println(s" OBP API Username: $username")) *>
956974
IO(println(s" Required roles for OBP_API_USERNAME '$username':")) *>
957-
IO(println(s" - CanVerifyUserCredentials (for POST /obp/v6.0.0/users/verify-credentials)")) *>
958-
IO(println(s" - CanGetAnyUser (for GET /obp/v6.0.0/users/provider/PROVIDER/username/USERNAME)")) *>
959-
IO(println(s" - CanGetOidcClient (for GET /obp/v6.0.0/oidc/clients/CLIENT_ID)")) *>
960-
IO(println(s" - CanGetConsumers (for GET /obp/v6.0.0/management/consumers)")) *>
975+
roleCheckRef.get.flatMap { roleCheckOpt =>
976+
roleEndpoints.foldLeft(IO.unit) { case (acc, (role, endpoint)) =>
977+
val status = roleCheckOpt match {
978+
case Some(rc) => if (rc.roleStatus(role)) "OK" else "NOT OK"
979+
case None => "UNKNOWN"
980+
}
981+
acc *> IO(println(s" - $role (for $endpoint) ... $status"))
982+
}
983+
} *>
961984
IO(println(s" No special role required for GET /obp/v6.0.0/providers (just authentication)"))
962985
} else {
963986
IO(println(" Credential verification: v_oidc_users (database view)")) *>

0 commit comments

Comments
 (0)