Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lisätään sisäinen rajapinta palvelutuottajien suomi.fi-kirjautumiselle #6109

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions apigw/src/shared/service-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export interface EmployeeLoginRequest {
employeeNumber?: string
}

export interface EmployeeSuomiFiLoginRequest {
ssn: string
firstName: string
lastName: string
}

export interface EmployeeUser {
id: string
firstName: string
Expand Down Expand Up @@ -107,6 +113,19 @@ export async function employeeLogin(
return data
}

export async function employeeSuomiFiLogin(
employee: EmployeeSuomiFiLoginRequest
): Promise<EmployeeUser> {
const { data } = await client.post<EmployeeUser>(
`/system/employee-sfi-login`,
employee,
{
headers: createServiceRequestHeaders(undefined, systemUserHeader)
}
)
return data
}

export async function getEmployeeDetails(
req: express.Request,
employeeId: string
Expand Down
2 changes: 2 additions & 0 deletions service/src/main/kotlin/fi/espoo/evaka/Audit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ enum class Audit(
EmployeeDelete(securityEvent = true, securityLevel = "high"),
EmployeeDeleteDaycareRoles(securityEvent = true, securityLevel = "high"),
EmployeeLogin(securityEvent = true, securityLevel = "high"),
EmployeeSfiLoginAttempt(securityEvent = true, securityLevel = "high"),
EmployeeSfiLogin(securityEvent = true, securityLevel = "high"),
EmployeeRead(securityEvent = true),
EmployeeUpdateDaycareRoles(securityEvent = true, securityLevel = "high"),
EmployeeUpdateGlobalRoles(securityEvent = true, securityLevel = "high"),
Expand Down
23 changes: 23 additions & 0 deletions service/src/main/kotlin/fi/espoo/evaka/pis/EmployeeQueries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package fi.espoo.evaka.pis

import fi.espoo.evaka.Sensitive
import fi.espoo.evaka.identity.ExternalId
import fi.espoo.evaka.pairing.MobileDevice
import fi.espoo.evaka.pairing.deleteDevice
Expand Down Expand Up @@ -123,6 +124,28 @@ RETURNING id, preferred_first_name, first_name, last_name, email, external_id, c
.exactlyOne<Employee>()
}

data class EmployeeSuomiFiLoginRequest(
val firstName: String,
val lastName: String,
val ssn: Sensitive<String>,
)

fun Database.Transaction.loginEmployeeWithSuomiFi(
now: HelsinkiDateTime,
request: EmployeeSuomiFiLoginRequest,
): Employee =
createUpdate {
sql(
"""
UPDATE employee
SET last_login = ${bind(now)}, first_name = ${bind(request.firstName)}, last_name = ${bind(request.lastName)}, active = TRUE
WHERE social_security_number = ${bind(request.ssn.value)}
"""
)
}
.executeAndReturnGeneratedKeys()
.exactlyOne<Employee>()

fun Database.Read.getEmployeeRoles(id: EmployeeId): EmployeeRoles =
createQuery {
sql(
Expand Down
42 changes: 42 additions & 0 deletions service/src/main/kotlin/fi/espoo/evaka/pis/SystemController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,48 @@ class SystemController(
}
}

@PostMapping("/system/employee-sfi-login")
fun employeeSuomiFiLogin(
db: Database,
user: AuthenticatedUser.SystemInternalUser,
clock: EvakaClock,
@RequestBody request: EmployeeSuomiFiLoginRequest,
): EmployeeUser {
Audit.EmployeeSfiLoginAttempt.log(
targetId = AuditId(request.ssn.value),
meta = mapOf("lastName" to request.lastName, "firstName" to request.firstName),
)
return db.connect { dbc ->
dbc.transaction { tx ->
val employee = tx.loginEmployeeWithSuomiFi(clock.now(), request)
val roles = tx.getEmployeeRoles(employee.id)
val employeeUser =
EmployeeUser(
id = employee.id,
firstName = employee.preferredFirstName ?: employee.firstName,
lastName = employee.lastName,
globalRoles = roles.globalRoles,
allScopedRoles = roles.allScopedRoles,
active = employee.active,
)
tx.upsertEmployeeUser(employee.id)
employeeUser
}
}
.also {
Audit.EmployeeSfiLogin.log(
targetId = AuditId(request.ssn.value),
objectId = AuditId(it.id),
meta =
mapOf(
"lastName" to request.lastName,
"firstName" to request.firstName,
"globalRoles" to it.globalRoles,
),
)
}
}

@GetMapping("/system/employee/{id}")
fun employeeUser(
db: Database,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE employee ADD COLUMN social_security_number text CONSTRAINT uniq$employee_ssn UNIQUE;
1 change: 1 addition & 0 deletions service/src/main/resources/migrations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,4 @@ V468__citizen_user.sql
V469__income_statement_status.sql
V470__cascade_citizen_user_delete.sql
V471__application_confidentiality.sql
V472__employee_ssn.sql
Loading