diff --git a/institutions-api/src/main/resources/application.conf b/institutions-api/src/main/resources/application.conf index 5f516445ab..935c9743bd 100644 --- a/institutions-api/src/main/resources/application.conf +++ b/institutions-api/src/main/resources/application.conf @@ -30,6 +30,8 @@ hmda { timeout = 5000 } } + runtime.mode = "dev" + runtime.mode = ${?HMDA_RUNTIME_MODE} } institution_db { diff --git a/institutions-api/src/main/scala/hmda/institution/HmdaInstitutionApi.scala b/institutions-api/src/main/scala/hmda/institution/HmdaInstitutionApi.scala index 36916de33c..e1822109d5 100644 --- a/institutions-api/src/main/scala/hmda/institution/HmdaInstitutionApi.scala +++ b/institutions-api/src/main/scala/hmda/institution/HmdaInstitutionApi.scala @@ -47,7 +47,6 @@ object HmdaInstitutionApi extends App { val kafkaConfig = system.settings.config.getConfig("akka.kafka.consumer") val jdbcUrl = config.getString("db.db.url") - log.info(s"Connection URL is \n\n$jdbcUrl\n") system.spawn[Nothing](HmdaInstitutionQueryApi(), HmdaInstitutionQueryApi.name) diff --git a/institutions-api/src/main/scala/hmda/institution/api/http/HmdaInstitutionQueryApi.scala b/institutions-api/src/main/scala/hmda/institution/api/http/HmdaInstitutionQueryApi.scala index 81f3bd311f..f4e969c4d2 100644 --- a/institutions-api/src/main/scala/hmda/institution/api/http/HmdaInstitutionQueryApi.scala +++ b/institutions-api/src/main/scala/hmda/institution/api/http/HmdaInstitutionQueryApi.scala @@ -7,6 +7,7 @@ import akka.actor.{ ActorSystem, CoordinatedShutdown } import akka.http.scaladsl.server.Directives._ import hmda.api.http.directives.HmdaTimeDirectives._ import hmda.api.http.routes.BaseHttpApi +import hmda.auth.OAuth2Authorization import scala.concurrent.ExecutionContext @@ -20,10 +21,13 @@ object HmdaInstitutionQueryApi { implicit val classic: ActorSystem = ctx.system.toClassic val shutdown: CoordinatedShutdown = CoordinatedShutdown(ctx.system) val config = classic.settings.config + val log = ctx.log + val oAuth2Authorization = OAuth2Authorization(log, config) val host: String = config.getString("hmda.institution.http.host") val port: Int = config.getInt("hmda.institution.http.port") + val institutionRoute = InstitutionQueryHttpApi.create(config) - val routes = BaseHttpApi.routes(name) ~ InstitutionQueryHttpApi.create(config) + val routes = BaseHttpApi.routes(name) ~ institutionRoute(oAuth2Authorization) BaseHttpApi.runServer(shutdown, name)(timed(routes), host, port) Behaviors.ignore diff --git a/institutions-api/src/main/scala/hmda/institution/api/http/InstitutionQueryHttpApi.scala b/institutions-api/src/main/scala/hmda/institution/api/http/InstitutionQueryHttpApi.scala index 0a2efdbcb3..570b250c0b 100644 --- a/institutions-api/src/main/scala/hmda/institution/api/http/InstitutionQueryHttpApi.scala +++ b/institutions-api/src/main/scala/hmda/institution/api/http/InstitutionQueryHttpApi.scala @@ -18,14 +18,16 @@ import slick.basic.DatabaseConfig import slick.jdbc.JdbcProfile import hmda.api.http.EmailUtils._ import org.slf4j.LoggerFactory +import hmda.auth.OAuth2Authorization import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} object InstitutionQueryHttpApi { - def create(config: Config)(implicit ec: ExecutionContext): Route = + def create(config: Config)(implicit ec: ExecutionContext): OAuth2Authorization => Route = new InstitutionQueryHttpApi(config)(ec).institutionPublicRoutes } + private class InstitutionQueryHttpApi(config: Config)(implicit ec: ExecutionContext) extends InstitutionEmailComponent with InstitutionNoteHistoryComponent{ val dbConfig = DatabaseConfig.forConfig[JdbcProfile]("institution_db") @@ -69,30 +71,17 @@ private class InstitutionQueryHttpApi(config: Config)(implicit ec: ExecutionCont } } - private val institutionByDomainPath = - path("institutions" / "year" / IntNumber) { year => - (extractUri & get) { uri => - isInstitutionsYearAllowed(yearsAvailable.contains(year.toString)){ - parameter('domain.as[String]) { domain => - val f = findByEmail(domain, year.toString) - completeInstitutionsFuture(f, uri) - } ~ - parameters('domain.as[String], 'lei.as[String], 'respondentName.as[String], 'taxId.as[String]) { - (domain, lei, respondentName, taxId) => - val f = findByFields(lei, respondentName, taxId, domain, year.toString) - completeInstitutionsFuture(f, uri) - } - } - } - } - - private val institutionHistoryPath = + private def institutionHistoryPath(oAuth2Authorization: OAuth2Authorization) = { + val hmdaAdminRole = "hmda-admin" path("institutions" / Segment / "year" / IntNumber / "history") { (lei, year) => (extractUri & get) { uri => - val f = institutionNoteHistoryRepository.findInstitutionHistory( year.toString,lei) - completeInstitutionsNoteHistoryFuture(f, uri) + oAuth2Authorization.authorizeTokenWithRole(hmdaAdminRole) { _ => + val f = institutionNoteHistoryRepository.findInstitutionHistory( year.toString,lei) + completeInstitutionsNoteHistoryFuture(f, uri) + } } } + } def completeInstitutionsNoteHistoryFuture(f: Future[Seq[InstitutionNoteHistoryEntity]], uri: Uri): Route = { val entityMarshaller: PartialFunction[Seq[InstitutionNoteHistoryEntity], ToResponseMarshallable] = { @@ -102,7 +91,7 @@ private class InstitutionQueryHttpApi(config: Config)(implicit ec: ExecutionCont completeFuture(f, uri, entityMarshaller) } - private val institutionByDomainDefaultPath = + private val institutionByDomainPath = path("institutions") { (extractUri & get) { uri => parameter('domain.as[String]) { domain => @@ -181,11 +170,11 @@ private class InstitutionQueryHttpApi(config: Config)(implicit ec: ExecutionCont complete(ToResponseMarshallable(StatusCodes.NotFound -> errorResponse)) } - def institutionPublicRoutes: Route = + def institutionPublicRoutes(oAuth2Authorization: OAuth2Authorization): Route = handleRejections(corsRejectionHandler) { cors() { encodeResponse { - institutionByIdPath ~ institutionByDomainPath ~ institutionHistoryPath ~ institutionByDomainDefaultPath ~ + institutionByIdPath ~ institutionByDomainPath ~ institutionHistoryPath(oAuth2Authorization) ~ quarterlyFilersLarCountsPath } } diff --git a/institutions-api/src/test/scala/hmda/institution/api/http/InstitutionQueryHttpApiSpec.scala b/institutions-api/src/test/scala/hmda/institution/api/http/InstitutionQueryHttpApiSpec.scala index ad6f597087..8daf240f49 100644 --- a/institutions-api/src/test/scala/hmda/institution/api/http/InstitutionQueryHttpApiSpec.scala +++ b/institutions-api/src/test/scala/hmda/institution/api/http/InstitutionQueryHttpApiSpec.scala @@ -11,6 +11,8 @@ import hmda.institution.query.InstitutionSetup import hmda.model.institution.Institution import io.circe.generic.auto._ import org.scalatest.{ BeforeAndAfterAll, MustMatchers, WordSpec } +import hmda.auth.{ KeycloakTokenVerifier, OAuth2Authorization } +import org.slf4j.{ Logger, LoggerFactory } import scala.concurrent.ExecutionContext @@ -19,7 +21,14 @@ class InstitutionQueryHttpApiSpec extends WordSpec with MustMatchers with Before val ec: ExecutionContext = system.dispatcher val config = ConfigFactory.load() implicit val timeout = Timeout(duration) - val institutionPublicRoutes: Route = InstitutionQueryHttpApi.create(config) + val log: Logger = LoggerFactory.getLogger(getClass) + + val oAuth2Authorization = OAuth2Authorization( + log, + new KeycloakTokenVerifier + ) + + val institutionPublicRoutes = InstitutionQueryHttpApi.create(config) override def beforeAll: Unit = { super.beforeAll() @@ -31,21 +40,23 @@ class InstitutionQueryHttpApiSpec extends WordSpec with MustMatchers with Before tearDown() } + + "Institution Query HTTP API" must { "search by LEI" in { - Get("/institutions/XXX/year/2018") ~> institutionPublicRoutes ~> check { + Get("/institutions/XXX/year/2018") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.NotFound } - Get("/institutions/XXX/year/2019") ~> institutionPublicRoutes ~> check { + Get("/institutions/XXX/year/2019") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.NotFound } - Get("/institutions/XXX/year/2020") ~> institutionPublicRoutes ~> check { + Get("/institutions/XXX/year/2020") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.NotFound } - Get(s"/institutions/AAA/year/2018") ~> institutionPublicRoutes ~> check { + Get(s"/institutions/AAA/year/2018") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.OK responseAs[Institution] mustBe InstitutionConverter.convert(instA, Seq("aaa.com", "bbb.com")) responseAs[Institution].emailDomains mustBe Seq("aaa.com", "bbb.com") @@ -53,37 +64,21 @@ class InstitutionQueryHttpApiSpec extends WordSpec with MustMatchers with Before } "search by email domain" in { - Get("/institutions/year/2018?domain=xxx.com") ~> institutionPublicRoutes ~> check { + Get("/institutions?domain=xxx.com") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.NotFound } - Get("/institutions/year/2018?domain=bbb.com") ~> institutionPublicRoutes ~> check { + Get("/institutions?domain=bbb.com") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.OK responseAs[InstitutionsResponse].institutions.size mustBe 2 } } - "search by fields values" in { - Get("/institutions/year/2018?domain=aaa.com&lei=AAA&respondentName=RespA&taxId=taxIdA") ~> institutionPublicRoutes ~> check { - status mustBe StatusCodes.OK - val institutions = responseAs[InstitutionsResponse].institutions - institutions.size mustBe 1 - institutions.head.LEI mustBe "AAA" - institutions.head.taxId mustBe Some("taxIdA") - institutions.head.respondent.name mustBe Some("RespA") - institutions.head.emailDomains mustBe List("aaa.com", "bbb.com") - } - - Get("/institutions/year/2018?domain=xxx.com&lei=XXX&respondentName=RespX&taxId=taxIdX") ~> institutionPublicRoutes ~> check { - status mustBe StatusCodes.NotFound - } - } - "search by institution" in { - Get("/institutions?domain=aaa.com") ~> institutionPublicRoutes ~> check { + Get("/institutions?domain=aaa.com") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.OK } - Get("/institutions?domain=aaa.com&lei=AAA&respondentName=RespA&taxId=taxIdA") ~> institutionPublicRoutes ~> check { + Get("/institutions?domain=aaa.com&lei=AAA&respondentName=RespA&taxId=taxIdA") ~> institutionPublicRoutes(oAuth2Authorization) ~> check { status mustBe StatusCodes.OK } } diff --git a/kubernetes/institutions-api/templates/deployment.yaml b/kubernetes/institutions-api/templates/deployment.yaml index 9b6f0a063b..c44536d14e 100644 --- a/kubernetes/institutions-api/templates/deployment.yaml +++ b/kubernetes/institutions-api/templates/deployment.yaml @@ -53,6 +53,8 @@ spec: - configMapRef: name: {{ template "institutions-api.fullname" . }}-config env: + - name: HMDA_RUNTIME_MODE + value: {{ .Values.hmda.runtimeMode }} - name: KAFKA_INSTITUTIONS_TOPIC value: {{.Values.kafka.institutionsTopic}} - name: KAFKA_INSTITUTIONS_GROUP diff --git a/kubernetes/institutions-api/values.yaml b/kubernetes/institutions-api/values.yaml index 82f97a74d2..c36d3bab6f 100644 --- a/kubernetes/institutions-api/values.yaml +++ b/kubernetes/institutions-api/values.yaml @@ -17,7 +17,8 @@ service: account: name: hmda-platform-irsa -#currentYear: 2018 +hmda: + runtimeMode: kubernetes kafka: institutionsGroup: institutions-group