Added POST /users/verify-credentials

This commit is contained in:
simonredfern 2026-01-28 17:00:00 +01:00
parent 69c8970c27
commit e3ae001ac5
3 changed files with 80 additions and 1 deletions

View File

@ -200,6 +200,9 @@ object ApiRole extends MdcLoggable{
case class CanGetAnyUser (requiresBankId: Boolean = false) extends ApiRole
lazy val canGetAnyUser = CanGetAnyUser()
case class CanVerifyUserCredentials(requiresBankId: Boolean = false) extends ApiRole
lazy val canVerifyUserCredentials = CanVerifyUserCredentials()
case class CanCreateAnyTransactionRequest(requiresBankId: Boolean = true) extends ApiRole
lazy val canCreateAnyTransactionRequest = CanCreateAnyTransactionRequest()

View File

@ -30,7 +30,7 @@ import code.api.v5_0_0.{ViewJsonV500, ViewsJsonV500}
import code.api.v5_1_0.{JSONFactory510, PostCustomerLegalNameJsonV510}
import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
import code.api.v6_0_0.JSONFactory600.{AddUserToGroupResponseJsonV600, DynamicEntityDiagnosticsJsonV600, DynamicEntityIssueJsonV600, GroupEntitlementJsonV600, GroupEntitlementsJsonV600, GroupJsonV600, GroupsJsonV600, PostGroupJsonV600, PostGroupMembershipJsonV600, PostResetPasswordUrlJsonV600, PutGroupJsonV600, ReferenceTypeJsonV600, ReferenceTypesJsonV600, ResetPasswordUrlJsonV600, RoleWithEntitlementCountJsonV600, RolesWithEntitlementCountsJsonV600, ScannedApiVersionJsonV600, UpdateViewJsonV600, UserGroupMembershipJsonV600, UserGroupMembershipsJsonV600, ValidateUserEmailJsonV600, ValidateUserEmailResponseJsonV600, ViewJsonV600, ViewPermissionJsonV600, ViewPermissionsJsonV600, ViewsJsonV600, createAbacRuleJsonV600, createAbacRulesJsonV600, createActiveRateLimitsJsonV600, createCallLimitJsonV600, createRedisCallCountersJson}
import code.api.v6_0_0.{AbacRuleJsonV600, AbacRuleResultJsonV600, AbacRulesJsonV600, CacheConfigJsonV600, CacheInfoJsonV600, CacheNamespaceInfoJsonV600, CreateAbacRuleJsonV600, CreateDynamicEntityRequestJsonV600, CurrentConsumerJsonV600, DynamicEntityDefinitionJsonV600, DynamicEntityDefinitionWithCountJsonV600, DynamicEntitiesWithCountJsonV600, DynamicEntityLinksJsonV600, ExecuteAbacRuleJsonV600, InMemoryCacheStatusJsonV600, MyDynamicEntitiesJsonV600, RedisCacheStatusJsonV600, RelatedLinkJsonV600, UpdateAbacRuleJsonV600, UpdateDynamicEntityRequestJsonV600}
import code.api.v6_0_0.{AbacRuleJsonV600, AbacRuleResultJsonV600, AbacRulesJsonV600, CacheConfigJsonV600, CacheInfoJsonV600, CacheNamespaceInfoJsonV600, CreateAbacRuleJsonV600, CreateDynamicEntityRequestJsonV600, CurrentConsumerJsonV600, DynamicEntityDefinitionJsonV600, DynamicEntityDefinitionWithCountJsonV600, DynamicEntitiesWithCountJsonV600, DynamicEntityLinksJsonV600, ExecuteAbacRuleJsonV600, InMemoryCacheStatusJsonV600, MyDynamicEntitiesJsonV600, PostVerifyUserCredentialsJsonV600, RedisCacheStatusJsonV600, RelatedLinkJsonV600, UpdateAbacRuleJsonV600, UpdateDynamicEntityRequestJsonV600}
import code.api.v6_0_0.OBPAPI6_0_0
import code.abacrule.{AbacRuleEngine, MappedAbacRuleProvider}
import code.metrics.APIMetrics
@ -7084,6 +7084,76 @@ trait APIMethods600 {
}
}
staticResourceDocs += ResourceDoc(
verifyUserCredentials,
implementedInApiVersion,
nameOf(verifyUserCredentials),
"POST",
"/users/verify-credentials",
"Verify User Credentials",
s"""Verify a user's credentials (username, password, provider) and return user information if valid.
|
|This endpoint validates the provided credentials without creating a token or session.
|It can be used to verify user credentials in external systems.
|
|${userAuthenticationMessage(true)}
|
|""",
PostVerifyUserCredentialsJsonV600(
username = "username",
password = "password",
provider = Constant.localIdentityProvider
),
userJsonV200,
List(
$AuthenticatedUserIsRequired,
UserHasMissingRoles,
InvalidJsonFormat,
InvalidLoginCredentials,
UsernameHasBeenLocked,
UnknownError
),
List(apiTagUser),
Some(List(canVerifyUserCredentials))
)
lazy val verifyUserCredentials: OBPEndpoint = {
case "users" :: "verify-credentials" :: Nil JsonPost json -> _ => {
cc => implicit val ec = EndpointContext(Some(cc))
for {
(Full(u), callContext) <- authenticatedAccess(cc)
_ <- NewStyle.function.hasEntitlement("", u.userId, canVerifyUserCredentials, callContext)
postedData <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the PostVerifyUserCredentialsJsonV600", 400, callContext) {
json.extract[PostVerifyUserCredentialsJsonV600]
}
// Validate credentials using the existing AuthUser mechanism
resourceUserIdBox = code.model.dataAccess.AuthUser.getResourceUserId(postedData.username, postedData.password)
// Check if account is locked
_ <- Helper.booleanToFuture(UsernameHasBeenLocked, 401, callContext) {
resourceUserIdBox != Full(code.model.dataAccess.AuthUser.usernameLockedStateCode)
}
// Check if credentials are valid
resourceUserId <- Future {
resourceUserIdBox
} map {
x => unboxFullOrFail(x, callContext, InvalidLoginCredentials, 401)
}
// Get the user object
user <- Future {
Users.users.vend.getUserByResourceUserId(resourceUserId)
} map {
x => unboxFullOrFail(x, callContext, InvalidLoginCredentials, 401)
}
// Verify provider matches if specified and not empty
_ <- Helper.booleanToFuture(InvalidLoginCredentials, 401, callContext) {
postedData.provider.isEmpty || user.provider == postedData.provider
}
} yield {
(JSONFactory200.createUserJSON(user), HttpCode.`200`(callContext))
}
}
}
}
}

View File

@ -206,6 +206,12 @@ case class CreateUserJsonV600(
validating_application: Option[String] = None
)
case class PostVerifyUserCredentialsJsonV600(
username: String,
password: String,
provider: String
)
case class MigrationScriptLogJsonV600(
migration_script_log_id: String,
name: String,