Skip to content

Commit

Permalink
fix(api): Fix create user endpoint
Browse files Browse the repository at this point in the history
The User data model includes also first name, last name and an e-mail
address, but the request object for creating new users was missing those,
in effect preventing to set the corr. attributes when creating new users.

Signed-off-by: Jyrki Keisala <[email protected]>
  • Loading branch information
Etsija committed Oct 23, 2024
1 parent 4744fea commit 227e108
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 8 deletions.
3 changes: 3 additions & 0 deletions api/v1/model/src/commonMain/kotlin/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ data class User(
@Serializable
data class CreateUser(
val username: String,
val firstName: String? = null,
val lastName: String? = null,
val email: String? = null,
val password: String? = null,

/** Specifies whether the password is for one-time use only */
Expand Down
9 changes: 8 additions & 1 deletion core/src/main/kotlin/api/AdminRoute.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,14 @@ fun Route.admin() = route("admin") {
requireSuperuser()

val createUser = call.receive<CreateUser>()
userService.createUser(createUser.username, createUser.password, createUser.temporary)
userService.createUser(
username = createUser.username,
firstName = createUser.firstName,
lastName = createUser.lastName,
email = createUser.email,
password = createUser.password,
temporary = createUser.temporary
)

call.respond(HttpStatusCode.Created)
}
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/kotlin/apiDocs/AdminDocs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,20 @@ val getUsers: OpenApiRoute.() -> Unit = {

val postUsers: OpenApiRoute.() -> Unit = {
operationId = "postUsers"
summary = "Create a user, possibly with a password. This is enabled for server administrators only."
summary = "Create a user, possibly with a password."
tags = listOf("Admin")

request {
jsonBody<CreateUser> {
example("Create User") {
value = CreateUser(username = "newUser", password = "password", temporary = true)
value = CreateUser(
username = "newUser",
firstName = "First",
lastName = "Last",
email = "[email protected]",
password = "password",
temporary = true
)
description = "temporary=true means the password is for one-time use only and needs to be changed " +
"on first login. If password is not set, temporary is ignored."
}
Expand Down
32 changes: 29 additions & 3 deletions core/src/test/kotlin/api/AdminRouteIntegrationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class AdminRouteIntegrationTest : AbstractIntegrationTest({
tags(Integration)

val testUsername = "test123"
val testFirstName = "FirstName"
val testLastName = "LastName"
val testEmail = "[email protected]"
val testPassword = "password123"
val testTemporary = true

Expand Down Expand Up @@ -89,7 +92,14 @@ class AdminRouteIntegrationTest : AbstractIntegrationTest({
"POST /admin/users" should {
"create a new user" {
integrationTestApplication {
val user = CreateUser(testUsername, testPassword, testTemporary)
val user = CreateUser(
username = testUsername,
firstName = testFirstName,
lastName = testLastName,
email = testEmail,
password = testPassword,
temporary = testTemporary
)

val response = superuserClient.post("/api/v1/admin/users") {
setBody(user)
Expand All @@ -101,7 +111,14 @@ class AdminRouteIntegrationTest : AbstractIntegrationTest({

"respond with an internal error if the user already exists" {
integrationTestApplication {
val user = CreateUser(testUsername, testPassword, testTemporary)
val user = CreateUser(
username = testUsername,
firstName = testFirstName,
lastName = testLastName,
email = testEmail,
password = testPassword,
temporary = testTemporary
)

superuserClient.post("/api/v1/admin/users") {
setBody(user)
Expand All @@ -117,7 +134,16 @@ class AdminRouteIntegrationTest : AbstractIntegrationTest({
"require superuser role" {
requestShouldRequireRole(Superuser.ROLE_NAME, HttpStatusCode.Created) {
post("/api/v1/admin/users") {
setBody(CreateUser(testUsername, testPassword, testTemporary))
setBody(
CreateUser(
username = testUsername,
firstName = testFirstName,
lastName = testLastName,
email = testEmail,
password = testPassword,
temporary = testTemporary
)
)
}
}
}
Expand Down
18 changes: 16 additions & 2 deletions services/authorization/src/main/kotlin/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,22 @@ class UserService(
/**
* Create a user. If "password" is null, then "temporary" is ignored.
*/
suspend fun createUser(username: String, password: String?, temporary: Boolean) = run {
keycloakClient.createUser(username = UserName(username), password = password, temporary = temporary)
suspend fun createUser(
username: String,
firstName: String?,
lastName: String?,
email: String?,
password: String?,
temporary: Boolean
) = run {
keycloakClient.createUser(
username = UserName(username),
firstName = firstName,
lastName = lastName,
email = email,
password = password,
temporary = temporary
)
}

/**
Expand Down

0 comments on commit 227e108

Please sign in to comment.