Skip to content

Commit

Permalink
#2309 Add API to reset failed attempts counter
Browse files Browse the repository at this point in the history
  • Loading branch information
To-om committed Jan 13, 2022
1 parent 80d49a9 commit c7fbabe
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 3 deletions.
1 change: 1 addition & 0 deletions thehive/app/org/thp/thehive/controllers/v1/Router.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class Router @Inject() (
case DELETE(p"/user/$userId/key") => userCtrl.removeKey(userId)
case POST(p"/user/$userId/key/renew") => userCtrl.renewKey(userId)
case GET(p"/user/$userId/avatar$file*") => userCtrl.avatar(userId)
case POST(p"/user/$userId/reset") => userCtrl.resetFailedAttempts(userId)

case POST(p"/organisation") => organisationCtrl.create
case GET(p"/organisation/$organisationId") => organisationCtrl.get(organisationId)
Expand Down
26 changes: 24 additions & 2 deletions thehive/app/org/thp/thehive/controllers/v1/UserCtrl.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.thp.thehive.controllers.v1

import org.thp.scalligraph.auth.AuthSrv
import org.thp.scalligraph.auth.{AuthSrv, MultiAuthSrv}
import org.thp.scalligraph.controllers.{Entrypoint, FieldsParser}
import org.thp.scalligraph.models.Database
import org.thp.scalligraph.query.{ParamQuery, PublicProperties, Query}
import org.thp.scalligraph.traversal.TraversalOps._
import org.thp.scalligraph.traversal.{IteratorOutput, Traversal}
import org.thp.scalligraph.{AuthorizationError, BadRequestError, EntityIdOrName, NotFoundError, RichOptionTry}
import org.thp.scalligraph.{AuthorizationError, BadRequestError, EntityIdOrName, NotFoundError, NotSupportedError, RichOptionTry}
import org.thp.thehive.controllers.v1.Conversion._
import org.thp.thehive.dto.v1.InputUser
import org.thp.thehive.models._
Expand Down Expand Up @@ -123,6 +123,28 @@ class UserCtrl @Inject() (
} yield Results.NoContent
}

lazy val localPasswordAuthSrv: Try[LocalPasswordAuthSrv] = {
def getLocalPasswordAuthSrv(authSrv: AuthSrv): Option[LocalPasswordAuthSrv] =
authSrv match {
case lpas: LocalPasswordAuthSrv => Some(lpas)
case mas: MultiAuthSrv => mas.authProviders.flatMap(getLocalPasswordAuthSrv).headOption
}
getLocalPasswordAuthSrv(authSrv) match {
case Some(lpas) => Success(lpas)
case None => Failure(NotSupportedError("The local password authentication is not enabled"))
}
}

def resetFailedAttempts(userIdOrName: String): Action[AnyContent] =
entrypoint("reset user")
.authTransaction(db) { implicit request => implicit graph =>
for {
lpas <- localPasswordAuthSrv
user <- userSrv.current.organisations(Permissions.manageUser).users.get(EntityIdOrName(userIdOrName)).getOrFail("User")
_ <- lpas.resetFailedAttempts(user)
} yield Results.NoContent
}

def delete(userIdOrName: String, organisation: Option[String]): Action[AnyContent] =
entrypoint("delete user")
.authTransaction(db) { implicit request => implicit graph =>
Expand Down
11 changes: 10 additions & 1 deletion thehive/app/org/thp/thehive/services/LocalPasswordAuthSrv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.thp.thehive.services
import io.github.nremond.SecureHash
import org.thp.scalligraph.auth.{AuthCapability, AuthContext, AuthSrv, AuthSrvProvider}
import org.thp.scalligraph.models.{Database, Entity}
import org.thp.scalligraph.traversal.Graph
import org.thp.scalligraph.traversal.TraversalOps._
import org.thp.scalligraph.utils.Hasher
import org.thp.scalligraph.{AuthenticationError, AuthorizationError, EntityIdOrName}
Expand Down Expand Up @@ -67,7 +68,15 @@ class LocalPasswordAuthSrv(db: Database, userSrv: UserSrv, localUserSrv: LocalUs
.getOrFail("User")
}
isValid
} else false
} else {
logger.warn(
s"Authentication of ${user.login} is refused because the max attempts is reached (${user.failedAttempts.orNull}/${maxAttempts.orNull})"
)
false
}

def resetFailedAttempts(user: User with Entity)(implicit graph: Graph): Try[Unit] =
userSrv.get(user).update(_.failedAttempts, None).update(_.lastFailed, None).getOrFail("User").map(_ => ())

override def authenticate(username: String, password: String, organisation: Option[EntityIdOrName], code: Option[String])(implicit
request: RequestHeader
Expand Down

0 comments on commit c7fbabe

Please sign in to comment.