Skip to content

Commit

Permalink
Handle HTTP Gone responses from Hydra
Browse files Browse the repository at this point in the history
This is a common error if a user resubmits a form.
  • Loading branch information
Brutus5000 committed Jul 22, 2022
1 parent a087ab1 commit c55d03e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
35 changes: 33 additions & 2 deletions src/main/kotlin/com/faforever/userservice/domain/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import com.faforever.userservice.hydra.HydraService
import com.faforever.userservice.security.OAuthScope
import io.micronaut.context.annotation.ConfigurationProperties
import io.micronaut.context.annotation.Context
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.http.uri.UriBuilder
import jakarta.inject.Singleton
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.security.crypto.password.PasswordEncoder
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.onErrorResume
import reactor.kotlin.core.publisher.switchIfEmpty
import reactor.kotlin.core.publisher.toMono
import reactor.kotlin.core.util.function.component1
Expand All @@ -19,6 +22,7 @@ import sh.ory.hydra.model.AcceptLoginRequest
import sh.ory.hydra.model.ConsentRequestSession
import sh.ory.hydra.model.GenericError
import sh.ory.hydra.model.LoginRequest
import sh.ory.hydra.model.RequestWasHandledResponse
import java.time.LocalDateTime
import java.time.OffsetDateTime
import javax.validation.constraints.NotNull
Expand Down Expand Up @@ -71,7 +75,10 @@ class UserService(
fun findUserBySubject(subject: String) =
userRepository.findById(subject.toInt())

private fun checkLoginThrottlingRequired(ip: String) = loginLogRepository.findFailedAttemptsByIpAfterDate(ip, LocalDateTime.now().minusDays(securityProperties.failedLoginDaysToCheck))
private fun checkLoginThrottlingRequired(ip: String) = loginLogRepository.findFailedAttemptsByIpAfterDate(
ip,
LocalDateTime.now().minusDays(securityProperties.failedLoginDaysToCheck)
)
.map {
val accountsAffected = it.accountsAffected ?: 0
val totalFailedAttempts = it.totalAttempts ?: 0
Expand All @@ -83,7 +90,7 @@ class UserService(
) {
val lastAttempt = it.lastAttemptAt!!
if (LocalDateTime.now().minusMinutes(securityProperties.failedLoginThrottlingMinutes)
.isBefore(lastAttempt)
.isBefore(lastAttempt)
) {
LOG.debug("IP '$ip' is trying again to early -> throttle it")
true
Expand Down Expand Up @@ -112,6 +119,18 @@ class UserService(
internalLogin(challenge, usernameOrEmail, password, ip, loginRequest)
}
}
}.onErrorResume(HttpClientResponseException::class) {
if (it.status == HttpStatus.GONE) {
LOG.debug("Login challenge $challenge was already solved, following Ory redirect")

it.response.getBody(RequestWasHandledResponse::class.java)
.map { LoginResult.SuccessfulLogin(it.redirectTo) }
.orElseThrow()
.toMono()
} else {
// pass through unknown error
Mono.error(it)
}
}
.onErrorResume { error ->
LOG.debug("Login failed with technical error for challenge $challenge", error)
Expand Down Expand Up @@ -233,5 +252,17 @@ class UserService(
}
}.map {
it.redirectTo
}.onErrorResume(HttpClientResponseException::class) {
if (it.status == HttpStatus.GONE) {
LOG.debug("Consent challenge $challenge was already solved, following Ory redirect")

it.response.getBody(RequestWasHandledResponse::class.java)
.map(RequestWasHandledResponse::redirectTo)
.orElseThrow()
.toMono()
} else {
// pass through unknown error
Mono.error(it)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class RequiredRoleAndScopeRule : SecurityRule {
authentication: Authentication?
): Publisher<SecurityRuleResult> {
if (authentication == null) {
LOG.debug("No authentication available")
return SecurityRuleResult.REJECTED.toMono()
}

Expand Down
23 changes: 23 additions & 0 deletions src/main/kotlin/sh/ory/hydra/model/RequestWasHandledResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* ORY Hydra
* Welcome to the ORY Hydra HTTP API documentation. You will find documentation for all HTTP APIs here.
*
* The version of the OpenAPI document: latest
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package sh.ory.hydra.model

import com.fasterxml.jackson.annotation.JsonProperty

/**
* * @param redirectTo Original request URL to which you should redirect the user if request was already handled.
*/

data class RequestWasHandledResponse(
/* Original request URL to which you should redirect the user if request was already handled. */
@field:JsonProperty("redirect_to")
val redirectTo: kotlin.String
)

0 comments on commit c55d03e

Please sign in to comment.