Skip to content

Commit

Permalink
Revert "PIN-3516 Bulk update Client and Keys (One shot) (#229)"
Browse files Browse the repository at this point in the history
This reverts commit 7483084.
  • Loading branch information
galales authored Nov 8, 2023
1 parent 35c0247 commit 1216a3c
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 179 deletions.
1 change: 1 addition & 0 deletions src/main/resources/interface-specification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,7 @@ components:
type: string
format: date-time
required:
- relationshipId
- kid
- name
- encodedPem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ object Adapters {
description = p.description,
consumerId = p.consumerId,
purposes = p.purposes.map(_.toApi),
relationshipsIds = if (showRelationShips) p.users else Set.empty,
relationshipsIds = if (showRelationShips) p.relationships else Set.empty,
kind = p.kind.toApi,
createdAt = p.createdAt
)
Expand Down Expand Up @@ -138,9 +138,9 @@ object Adapters {
}

implicit class KeySeedWrapper(private val keySeed: KeySeed) extends AnyVal {
def toDependency(userId: UUID, createdAt: OffsetDateTime): AuthorizationManagementDependency.KeySeed =
def toDependency(relationshipId: UUID, createdAt: OffsetDateTime): AuthorizationManagementDependency.KeySeed =
AuthorizationManagementDependency.KeySeed(
userId = userId,
relationshipId = relationshipId,
key = keySeed.key,
use = keySeed.use.toDependency,
alg = keySeed.alg,
Expand Down Expand Up @@ -179,7 +179,7 @@ object Adapters {
use = key.use.toApi,
name = key.name,
createdAt = key.createdAt,
relationshipId = Some(key.userId)
relationshipId = key.relationshipId
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier
import it.pagopa.interop.authorizationmanagement.client.api.{
ClientApi => AuthorizationClientApi,
KeyApi => AuthorizationKeyApi,
MigrateApi,
PurposeApi => AuthorizationPurposeApi
}
import it.pagopa.interop.authorizationprocess.api.impl.{
Expand Down Expand Up @@ -80,7 +79,6 @@ trait Dependencies {
AuthorizationManagementInvoker(blockingEc)(actorSystem.classicSystem),
AuthorizationClientApi(ApplicationConfiguration.getAuthorizationManagementURL),
AuthorizationKeyApi(ApplicationConfiguration.getAuthorizationManagementURL),
MigrateApi(ApplicationConfiguration.getAuthorizationManagementURL),
AuthorizationPurposeApi(ApplicationConfiguration.getAuthorizationManagementURL)
)(blockingEc)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,110 +1,58 @@
package it.pagopa.interop.authorizationprocess.server.impl

import cats.syntax.all._
import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.Http
import akka.management.scaladsl.AkkaManagement
import buildinfo.BuildInfo
import cats.syntax.all._
import com.typesafe.scalalogging.Logger
import it.pagopa.interop.authorizationprocess.common.system.ApplicationConfiguration
import it.pagopa.interop.authorizationprocess.server.Controller
import it.pagopa.interop.commons.logging.renderBuildInfo
import it.pagopa.interop.commons.utils.CORSSupport
import scala.concurrent.{ExecutionContext, ExecutionContextExecutor}
import scala.util.{Failure, Success}
import akka.actor.typed.DispatcherSelector

import it.pagopa.interop.authorizationmanagement.model.client.PersistentClient
import it.pagopa.interop.authorizationmanagement.model.persistence.JsonFormats._
import it.pagopa.interop.authorizationmanagement.model.key.PersistentKey
import it.pagopa.interop.authorizationprocess.common.readmodel.model.ReadModelClientWithKeys
import it.pagopa.interop.authorizationprocess.common.readmodel.model.impl._
import it.pagopa.interop.authorizationprocess.service.{AuthorizationManagementService, PartyManagementService}

import org.mongodb.scala.model.Filters
import it.pagopa.interop.commons.utils.CORRELATION_ID_HEADER

import scala.concurrent.duration.Duration
import java.util.concurrent.{Executors, ExecutorService}
import scala.concurrent.{ExecutionContext, Future, Await}

import java.util.UUID
import scala.util.Failure

object Main extends App with Dependencies {
object Main extends App with CORSSupport with Dependencies {

val logger: Logger = Logger(this.getClass)

implicit val context: List[(String, String)] = (CORRELATION_ID_HEADER -> UUID.randomUUID().toString()) :: Nil

implicit val actorSystem: ActorSystem[Nothing] =
ActorSystem[Nothing](Behaviors.empty, "interop-be-authorization-process-alignment")
implicit val executionContext: ExecutionContext = actorSystem.executionContext

implicit val es: ExecutorService = Executors.newFixedThreadPool(1.max(Runtime.getRuntime.availableProcessors() - 1))
implicit val blockingEc = ExecutionContext.fromExecutor(es)
implicit val authorizationManagementService: AuthorizationManagementService = authorizationManagementService(
blockingEc
ActorSystem[Nothing](
Behaviors.setup[Nothing] { context =>
implicit val actorSystem: ActorSystem[_] = context.system
implicit val executionContext: ExecutionContext = actorSystem.executionContext
val selector: DispatcherSelector = DispatcherSelector.fromConfig("futures-dispatcher")
val blockingEc: ExecutionContextExecutor = actorSystem.dispatchers.lookup(selector)

AkkaManagement.get(actorSystem.classicSystem).start()

logger.info(renderBuildInfo(BuildInfo))

val serverBinding = for {
jwtReader <- getJwtValidator()
controller = new Controller(
clientApi(jwtReader, blockingEc),
healthApi,
operatorApi(jwtReader, blockingEc),
validationExceptionToRoute.some
)(actorSystem.classicSystem)
binding <- Http()(actorSystem.classicSystem)
.newServerAt("0.0.0.0", ApplicationConfiguration.serverPort)
.bind(corsHandler(controller.routes))
} yield binding

serverBinding.onComplete {
case Success(b) =>
logger.info(s"Started server at ${b.localAddress.getHostString()}:${b.localAddress.getPort()}")
case Failure(e) =>
actorSystem.terminate()
logger.error("Startup error: ", e)
}

Behaviors.empty[Nothing]
},
BuildInfo.name
)
implicit val partyManagementService: PartyManagementService = partyManagementService()

logger.info("Starting update")
logger.info(s"Retrieving clients")
Await.result(
execution()
.andThen { case Failure(ex) => logger.error("Houston we have a problem", ex) }
.andThen { _ =>
es.shutdown()
},
Duration.Inf
): Unit

logger.info("Completed update")

def execution(): Future[Unit] = for {
clients <- getClients()
_ = logger.info(s"Start update clients ${clients.size}")
_ <- clients.traverse(updateClient)
_ = logger.info(s"End update clients")
_ = logger.info(s"Retrieving keys")
keys <- clients.traverse(getClientKeys).map(_.flatten)
_ = logger.info(s"Start update keys ${keys.size}")
_ <- keys
.flatMap(client =>
client.keys.collect { case PersistentKey(Some(relationshipId), None, kid, _, _, _, _, _) =>
Parameter(client.id, kid, relationshipId)
}
)
.traverse(keys => updateKeys(keys))
_ = logger.info(s"End update keys")
} yield ()

def updateClient(client: PersistentClient): Future[Unit] = {
logger.info(s"Update client ${client.id}")
for {

relationship <- client.relationships.toList.traverse(partyManagementService.getRelationshipById)
_ <- relationship.traverse(rel => {
if (client.users.exists(_ == rel.from)) Future.unit
else authorizationManagementService.addUser(client.id, rel.from)
})
} yield ()
}

def getClients(): Future[Seq[PersistentClient]] =
getAll(50)(readModelService.find[PersistentClient]("clients", Filters.empty(), _, _))

def getClientKeys(client: PersistentClient): Future[Option[ReadModelClientWithKeys]] =
readModelService.findOne[ReadModelClientWithKeys]("clients", Filters.eq("data.id", client.id.toString))

def updateKeys(key: Parameter): Future[Unit] = {
logger.info(s"Update keys for client ${key.clientId}")
for {
relationship <- partyManagementService.getRelationshipById(key.relationShipId)
_ <- authorizationManagementService.migrateKeyRelationshipToUser(key.clientId, key.kid, relationship.from)
} yield ()
}

def getAll[T](limit: Int)(get: (Int, Int) => Future[Seq[T]]): Future[Seq[T]] = {
def go(offset: Int)(acc: Seq[T]): Future[Seq[T]] = {
get(offset, limit).flatMap(xs =>
if (xs.size < limit) Future.successful(xs ++ acc)
else go(offset + xs.size)(xs ++ acc)
)
}
go(0)(Nil)
}

final case class Parameter(clientId: UUID, kid: String, relationShipId: UUID)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ trait AuthorizationManagementService {

def deleteClient(clientId: UUID)(implicit contexts: Seq[(String, String)]): Future[Unit]

def addUser(clientId: UUID, userId: UUID)(implicit contexts: Seq[(String, String)]): Future[ManagementClient]

def migrateKeyRelationshipToUser(clientId: UUID, keyId: String, userId: UUID)(implicit
contexts: Seq[(String, String)]
): Future[Unit]

def addRelationship(clientId: UUID, relationshipId: UUID)(implicit
contexts: Seq[(String, String)]
): Future[ManagementClient]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package it.pagopa.interop.authorizationprocess.service.impl

import com.typesafe.scalalogging.{Logger, LoggerTakingImplicit}
import it.pagopa.interop.authorizationmanagement.client.api.{ClientApi, KeyApi, PurposeApi, MigrateApi}
import it.pagopa.interop.authorizationmanagement.client.api.{ClientApi, KeyApi, PurposeApi}
import it.pagopa.interop.authorizationmanagement.client.invoker.{ApiError, ApiRequest, BearerToken}
import it.pagopa.interop.authorizationmanagement.client.model._
import it.pagopa.interop.authorizationmanagement.model.client.{PersistentClient, PersistentClientKind}
Expand All @@ -25,12 +25,11 @@ final case class AuthorizationManagementServiceImpl(
invoker: AuthorizationManagementInvoker,
clientApi: ClientApi,
keyApi: KeyApi,
migrateApi: MigrateApi,
purposeApi: PurposeApi
)(implicit ec: ExecutionContext)
extends AuthorizationManagementService {

implicit val logger: LoggerTakingImplicit[ContextFieldsToLog] =
implicit val logger: LoggerTakingImplicit[ContextFieldsToLog] =
Logger.takingImplicit[ContextFieldsToLog](this.getClass)
override def createClient(
consumerId: UUID,
Expand All @@ -48,7 +47,7 @@ final case class AuthorizationManagementServiceImpl(
description = description,
kind = kind,
createdAt = createdAt,
users = members
members = members
)
)(BearerToken(bearerToken))
invoker.invoke(request, "Client creation")
Expand All @@ -57,7 +56,7 @@ final case class AuthorizationManagementServiceImpl(
clientId: UUID
)(implicit ec: ExecutionContext, readModel: ReadModelService): Future[PersistentClient] =
ReadModelAuthorizationQueries.getClientById(clientId).flatMap(_.toFuture(ClientNotFound(clientId)))
override def deleteClient(clientId: UUID)(implicit contexts: Seq[(String, String)]): Future[Unit] =
override def deleteClient(clientId: UUID)(implicit contexts: Seq[(String, String)]): Future[Unit] =
withHeaders[Unit] { (bearerToken, correlationId) =>
val request: ApiRequest[Unit] =
clientApi.deleteClient(xCorrelationId = correlationId, clientId.toString)(BearerToken(bearerToken))
Expand All @@ -67,35 +66,22 @@ final case class AuthorizationManagementServiceImpl(
case err: ApiError[_] if err.code == 404 => Future.failed(ClientNotFound(clientId))
}
}

override def migrateKeyRelationshipToUser(clientId: UUID, keyId: String, userId: UUID)(implicit
contexts: Seq[(String, String)]
): Future[Unit] = withHeaders[Unit] { (bearerToken, correlationId) =>
val request: ApiRequest[Unit] =
migrateApi.migrateKeyRelationshipToUser(xCorrelationId = correlationId, clientId, keyId, UserSeed(userId))(
BearerToken(bearerToken)
)
invoker.invoke(request, "Key user migration")
}

override def addUser(clientId: UUID, userId: UUID)(implicit contexts: Seq[(String, String)]): Future[Client] =
withHeaders[Client] { (bearerToken, correlationId) =>
val request: ApiRequest[Client] =
clientApi.addUser(xCorrelationId = correlationId, clientId, UserSeed(userId))(BearerToken(bearerToken))
invoker.invoke(request, "Operator addition to client")
}
override def addRelationship(clientId: UUID, relationshipId: UUID)(implicit
contexts: Seq[(String, String)]
): Future[Client] = withHeaders[Client] { (bearerToken, correlationId) =>
val request: ApiRequest[Client] =
clientApi.addUser(xCorrelationId = correlationId, clientId, UserSeed(relationshipId))(BearerToken(bearerToken))
clientApi.addRelationship(xCorrelationId = correlationId, clientId, PartyRelationshipSeed(relationshipId))(
BearerToken(bearerToken)
)
invoker.invoke(request, "Operator addition to client")
}
override def removeClientRelationship(clientId: UUID, relationshipId: UUID)(implicit
contexts: Seq[(String, String)]
): Future[Unit] = withHeaders[Unit] { (bearerToken, correlationId) =>
val request: ApiRequest[Unit] =
clientApi.removeClientUser(xCorrelationId = correlationId, clientId, relationshipId)(BearerToken(bearerToken))
clientApi.removeClientRelationship(xCorrelationId = correlationId, clientId, relationshipId)(
BearerToken(bearerToken)
)
invoker
.invoke(request, "Operator removal from client")
.recoverWith {
Expand All @@ -111,7 +97,7 @@ final case class AuthorizationManagementServiceImpl(
.flatMap(_.map(_.keys).toFuture(ClientKeyNotFound(clientId, kid)))
key <- keys.find(_.kid == kid).toFuture(ClientKeyNotFound(clientId, kid))
} yield key
override def deleteKey(clientId: UUID, kid: String)(implicit contexts: Seq[(String, String)]): Future[Unit] =
override def deleteKey(clientId: UUID, kid: String)(implicit contexts: Seq[(String, String)]): Future[Unit] =
withHeaders[Unit] { (bearerToken, correlationId) =>
val request: ApiRequest[Unit] =
keyApi.deleteClientKeyById(xCorrelationId = correlationId, clientId, kid)(BearerToken(bearerToken))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package it.pagopa.interop.authorizationprocess
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.testkit.ScalatestRouteTest
import it.pagopa.interop.authorizationmanagement
import it.pagopa.interop.authorizationmanagement.client.api.{ClientApi, KeyApi, PurposeApi, MigrateApi}
import it.pagopa.interop.authorizationmanagement.client.api.{ClientApi, KeyApi, PurposeApi}
import it.pagopa.interop.authorizationmanagement.model.client.{Api, PersistentClient, PersistentClientKind}
import it.pagopa.interop.authorizationprocess.api.impl.ClientApiServiceImpl
import it.pagopa.interop.authorizationprocess.common.readmodel.PaginatedResult
Expand Down Expand Up @@ -88,7 +88,6 @@ class ClientOperationSpec extends AnyWordSpecLike with MockFactory with SpecUtil
AuthorizationManagementInvoker(ExecutionContext.global),
ClientApi(),
KeyApi(),
MigrateApi(),
PurposeApi()
),
mockAgreementManagementService,
Expand Down Expand Up @@ -187,7 +186,6 @@ class ClientOperationSpec extends AnyWordSpecLike with MockFactory with SpecUtil
purposes = Seq.empty,
description = None,
relationships = Set.empty,
users = Set.empty,
kind = Api,
createdAt = timestamp
)
Expand Down Expand Up @@ -242,7 +240,6 @@ class ClientOperationSpec extends AnyWordSpecLike with MockFactory with SpecUtil
purposes = Seq.empty,
description = None,
relationships = Set.empty,
users = Set.empty,
kind = Api,
createdAt = timestamp
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package it.pagopa.interop.authorizationprocess

import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.testkit.ScalatestRouteTest
import it.pagopa.interop.authorizationmanagement.client.api.{ClientApi, KeyApi, PurposeApi, MigrateApi}
import it.pagopa.interop.authorizationmanagement.client.api.{ClientApi, KeyApi, PurposeApi}
import it.pagopa.interop.authorizationmanagement.client.{model => AuthorizationManagementDependency}
import it.pagopa.interop.authorizationprocess.api.impl.ClientApiMarshallerImpl._
import it.pagopa.interop.authorizationprocess.api.impl.{ClientApiServiceImpl, keyFormat, keysFormat}
Expand Down Expand Up @@ -66,7 +66,6 @@ class KeyOperationSpec
AuthorizationManagementInvoker(ExecutionContext.global),
ClientApi(),
KeyApi(),
MigrateApi(),
PurposeApi()
),
mockAgreementManagementService,
Expand Down Expand Up @@ -115,13 +114,13 @@ class KeyOperationSpec
.getClientKeys(_: UUID)(_: ExecutionContext, _: ReadModelService))
.expects(persistentClient.id, *, *)
.once()
.returns(Future.successful(Seq(persistentKey.copy(relationshipId = Some(relationship.id)))))
.returns(Future.successful(Seq(persistentKey.copy(relationshipId = relationship.id))))

val relationshipIds = relationship.id.toString

Get() ~> service.getClientKeys(relationshipIds, persistentClient.id.toString) ~> check {
status shouldEqual StatusCodes.OK
// entityAs[Keys] should haveTheSameKeys(Keys(Seq(expectedKey)))
entityAs[Keys] should haveTheSameKeys(Keys(Seq(expectedKey)))
}
}

Expand All @@ -133,7 +132,6 @@ class KeyOperationSpec
AuthorizationManagementInvoker(ExecutionContext.global),
ClientApi(),
KeyApi(),
MigrateApi(),
PurposeApi()
),
mockAgreementManagementService,
Expand Down Expand Up @@ -221,7 +219,6 @@ class KeyOperationSpec
AuthorizationManagementInvoker(ExecutionContext.global),
ClientApi(),
KeyApi(),
MigrateApi(),
PurposeApi()
),
mockAgreementManagementService,
Expand Down
Loading

0 comments on commit 1216a3c

Please sign in to comment.