Skip to content

Commit

Permalink
Merge pull request #6348 from espoon-voltti/auth-small-fixes-part-3
Browse files Browse the repository at this point in the history
Kirjautumisen pikkukorjauksia, osa 3
  • Loading branch information
Gekkio authored Feb 6, 2025
2 parents 4e73968 + 3c9bf83 commit fd1410b
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 9 deletions.
5 changes: 4 additions & 1 deletion apigw/src/enduser/routes/auth-weak-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { z } from 'zod'

import { EvakaSessionUser } from '../../shared/auth/index.js'
import { toRequestHandler } from '../../shared/express.js'
import { logAuditEvent } from '../../shared/logging.js'
import { logAuditEvent, logWarn } from '../../shared/logging.js'
import { RedisClient } from '../../shared/redis-client.js'
import { citizenWeakLogin } from '../../shared/service-client.js'
import { Sessions } from '../../shared/session.js'
Expand Down Expand Up @@ -45,6 +45,9 @@ export const authWeakLogin = (
const expirySeconds = 60 * 60
await redis.multi().incr(key).expire(key, expirySeconds).exec()
} else {
logWarn('Login request hit rate limit', req, {
username: body.username
})
res.sendStatus(429)
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ const WeakCredentialsFormModal = React.memo(function WeakCredentialsFormModal({
message={t.unacceptablePassword}
/>
)}
{isUsernameConflict && <AlertBox message={t.usernameConflict} />}
{isUsernameConflict && (
<AlertBox message={t.usernameConflict(username)} />
)}
</FixedSpaceColumn>
</form>
</MutateFormModal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
// SPDX-License-Identifier: LGPL-2.1-or-later

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import React, { useCallback, useContext } from 'react'
import React, { useCallback, useContext, useState } from 'react'
import styled from 'styled-components'

import { Failure } from 'lib-common/api'
import { boolean, string } from 'lib-common/form/fields'
import {
chained,
Expand Down Expand Up @@ -507,6 +508,14 @@ const EmailVerificationForm = React.memo(function EmailVerificationForm({
)
const verificationCode = useFormField(form, 'verificationCode')

const [isUsernameConflict, setUsernameConflict] = useState<boolean>(false)
const onFailure = useCallback(
(failure: Failure<unknown>) => {
setUsernameConflict(failure.statusCode === 409)
},
[setUsernameConflict]
)

return (
<FixedSpaceColumn>
<LabelLike>
Expand Down Expand Up @@ -541,11 +550,18 @@ const EmailVerificationForm = React.memo(function EmailVerificationForm({
close={closeInfo}
/>
)}
{isUsernameConflict && (
<AlertBox
message={i18n.personalDetails.loginDetailsSection.usernameConflict(
verification.email
)}
/>
)}
<Gap size="m" />
<MutateButton
data-qa="verify-email"
primary
disabled={!form.isValid()}
disabled={!form.isValid() || isUsernameConflict}
text={t.confirmVerification}
mutation={verifyEmailMutation}
onClick={() => ({
Expand All @@ -562,6 +578,7 @@ const EmailVerificationForm = React.memo(function EmailVerificationForm({
: t.verifyEmail.toast
})
}}
onFailure={onFailure}
/>
</FixedSpaceColumn>
)
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib-customizations/defaults/citizen/i18n/en.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,8 @@ const en: Translations = {
`at least ${v} ${v > 1 ? 'special characters' : 'special character'}`
},
unacceptablePassword: 'The password is too easy to guess',
usernameConflict: 'The username is already in use'
usernameConflict: (username: string): ReactNode =>
`The username ${username} is already in use by another person`
},
notificationsSection: {
title: 'Email notifications',
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib-customizations/defaults/citizen/i18n/fi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2129,7 +2129,8 @@ export default {
`vähintään ${v} ${v > 1 ? 'erikoismerkkiä' : 'erikoismerkki'}`
},
unacceptablePassword: 'Salasana on liian helposti arvattava',
usernameConflict: 'Käyttäjätunnus on jo käytössä'
usernameConflict: (username: string): ReactNode =>
`Käyttäjätunnus ${username} on jo käytössä toisella henkilöllä`
},
notificationsSection: {
title: 'Sähköposti-ilmoitukset',
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib-customizations/defaults/citizen/i18n/sv.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2127,7 +2127,8 @@ const sv: Translations = {
`${v} eller ${v > 1 ? 'flera specialtecken' : 'fler specialtecken'}`
},
unacceptablePassword: 'Lösenordet är för lätt att gissa',
usernameConflict: 'Användarnamnet är redan i bruk'
usernameConflict: (username: string): ReactNode =>
`Användarnamnet ${username} används redan av en annan person`
},
notificationsSection: {
title: 'E-postmeddelanden',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class SystemController(
}

tx.updateLastWeakLogin(clock, citizen.id)
tx.updateCitizenOnLogin(clock, citizen.id, keycloakEmail = null)
personService.getPersonWithChildren(tx, user, citizen.id)
CitizenUserIdentity(citizen.id)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import fi.espoo.evaka.shared.utils.EMAIL_PATTERN
import fi.espoo.evaka.shared.utils.PHONE_PATTERN
import fi.espoo.evaka.user.hasWeakCredentials
import fi.espoo.evaka.user.updateWeakLoginCredentials
import io.github.oshai.kotlinlogging.KotlinLogging
import java.security.SecureRandom
import java.time.Duration
import kotlin.random.asKotlinRandom
Expand All @@ -44,6 +45,7 @@ class PersonalDataControllerCitizen(
private val passwordSpecification: PasswordSpecification,
) {
private val secureRandom = SecureRandom()
private val logger = KotlinLogging.logger {}

@PutMapping
fun updatePersonalData(
Expand Down Expand Up @@ -270,7 +272,11 @@ class PersonalDataControllerCitizen(
user.id,
)
tx.verifyAndUpdateEmail(clock.now(), user.id, request.id, request.code)
tx.syncWeakLoginUsername(clock.now(), user.id)
try {
tx.syncWeakLoginUsername(clock.now(), user.id)
} catch (e: Exception) {
throw mapPSQLException(e)
}
}
}
Audit.CitizenVerifyEmail.log(targetId = AuditId(request.id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ enum class ScheduledJob(
ScheduledJobs::generateReplacementDraftInvoices,
ScheduledJobSettings(enabled = true, schedule = JobSchedule.daily(LocalTime.of(4, 15))),
),
ImportPasswordsBlacklists(
ImportPasswordBlacklists(
ScheduledJobs::importPasswordBlacklists,
ScheduledJobSettings(enabled = true, schedule = JobSchedule.daily(LocalTime.of(0, 20))),
),
Expand Down

0 comments on commit fd1410b

Please sign in to comment.