diff --git a/Dockerfile b/Dockerfile index ef9aea24c..3a8da4261 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1 +1,38 @@ -FROM ghcr.io/dataswift/base:v0.3.5 \ No newline at end of file +FROM adoptopenjdk/openjdk11:jdk-11.0.6_10-alpine + +ARG FILE_PATH +ENV FILE_PATH=$FILE_PATH +ARG STRING +ENV STRING=$STRING +ARG DELIMITER +ENV DELIMITER=$DELIMITER +ARG KEYWORD +ENV KEYWORD=$KEYWORD + +ARG SBT_VERSION=1.3.10 + +RUN set -x \ + && apk --update add --no-cache --virtual .build-deps curl \ + && ESUM="3060065764193651aa3fe860a17ff8ea9afc1e90a3f9570f0584f2d516c34380" \ + && SBT_URL="https://github.com/sbt/sbt/releases/download/v1.3.10/sbt-1.3.10.tgz" \ + && apk add bash \ + && curl -Ls ${SBT_URL} > /tmp/sbt-${SBT_VERSION}.tgz \ + && sha256sum /tmp/sbt-${SBT_VERSION}.tgz \ + && (echo "${ESUM} /tmp/sbt-${SBT_VERSION}.tgz" | sha256sum -c -) \ + && tar -zxf /tmp/sbt-${SBT_VERSION}.tgz -C /opt/ \ + && sed -i -r 's#run \"\$\@\"#unset JAVA_TOOL_OPTIONS\nrun \"\$\@\"#g' /opt/sbt/bin/sbt \ + && apk del --purge .build-deps \ + && rm -rf /tmp/sbt-${SBT_VERSION}.tgz /var/cache/apk/* + + +ENV PATH="/opt/sbt/bin:$PATH" \ + JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" \ + SBT_OPTS="-Xmx2048M -Xss2M" + +WORKDIR /app +ADD . /app + +RUN ["chmod", "-R", "777", "start.sh"] + +CMD ./start.sh + diff --git a/copilot/.workspace b/copilot/.workspace new file mode 100644 index 000000000..8ed6d04be --- /dev/null +++ b/copilot/.workspace @@ -0,0 +1 @@ +application: hat-application diff --git a/copilot/environments/staging/manifest.yml b/copilot/environments/staging/manifest.yml new file mode 100644 index 000000000..432645395 --- /dev/null +++ b/copilot/environments/staging/manifest.yml @@ -0,0 +1,21 @@ +# The manifest for the "staging" environment. +# Read the full specification for the "Environment" type at: +# https://aws.github.io/copilot-cli/docs/manifest/environment/ + +# Your environment name will be used in naming your resources like VPC, cluster, etc. +name: staging +type: Environment + +# Import your own VPC and subnets or configure how they should be created. +# network: +# vpc: +# id: + +# Configure the load balancers in your environment, once created. +# http: +# public: +# private: + +# Configure observability for your environment resources. +observability: + container_insights: false diff --git a/copilot/hat-service/manifest.yml b/copilot/hat-service/manifest.yml new file mode 100644 index 000000000..0776958c6 --- /dev/null +++ b/copilot/hat-service/manifest.yml @@ -0,0 +1,41 @@ +# The manifest for the "hat-service" service. +# Read the full specification for the "Load Balanced Web Service" type at: +# https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/ + +name: hat-service +type: Load Balanced Web Service + +# Distribute traffic to your service. +http: + path: '/' + healthcheck: + path: '/' + success_codes: '200,301' + healthy_threshold: 3 + unhealthy_threshold: 2 + interval: 30s + timeout: 10s + grace_period: 5m + deregistration_delay: 5s + +image: + build: Dockerfile + port: 9000 + +cpu: 4096 # Number of CPU units for the task. +memory: 8192 # Amount of memory in MiB used by the task. +count: 1 # Number of tasks that should be running in your service. +exec: true # Enable running commands in your container. +network: + connect: true # Enable Service Connect for intra-environment traffic between services. + +variables: # Pass environment variables as key value pairs. + LOG_LEVEL: debug + + +# You can override any of the values defined above by environment. +environments: + staging: + count: 1 # Number of tasks to run for the "test" environment. + deployment: # The deployment strategy for the "test" environment. + rolling: 'recreate' # Stops existing tasks before new ones are started for faster deployments. \ No newline at end of file diff --git a/hat/app/org/hatdex/hat/api/controllers/Authentication.scala b/hat/app/org/hatdex/hat/api/controllers/Authentication.scala index 94b163bf0..832f5280e 100644 --- a/hat/app/org/hatdex/hat/api/controllers/Authentication.scala +++ b/hat/app/org/hatdex/hat/api/controllers/Authentication.scala @@ -52,6 +52,8 @@ import java.net.{ URLDecoder, URLEncoder } import javax.inject.Inject import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future +import com.mohiva.play.silhouette.api.LoginInfo +import org.checkerframework.checker.units.qual.A class Authentication @Inject() ( components: ControllerComponents, @@ -77,9 +79,9 @@ class Authentication @Inject() ( import HatJsonFormats._ - private val indefiniteSuccessCaching: CachedBuilder = cached - .status(req => s"${req.host}${req.path}", 200) - .includeStatus(404, 600) + // private val indefiniteSuccessCaching: CachedBuilder = cached + // .status(req => s"${req.host}${req.path}", 200) + // .includeStatus(404, 600) private val emailScheme = "https://" @@ -134,12 +136,18 @@ class Authentication @Inject() ( ) def publicKey(): EssentialAction = - indefiniteSuccessCaching { - UserAwareAction.async { implicit request => + // indefiniteSuccessCaching { + UserAwareAction.async { implicit request => { + logger.info(s"request: ${request.toString()}") + logger.info(s"dynEnv : ${request.dynamicEnvironment.toString()}") + val publicKey = hatServerProvider.toString(request.dynamicEnvironment.publicKey) + + Future.successful(Ok(publicKey)) } + // } } // TODO: Should this remove tokens? @@ -196,6 +204,7 @@ class Authentication @Inject() ( // Trade username and password for an access_token def accessToken(): Action[AnyContent] = (UserAwareAction andThen limiter.UserAwareRateLimit).async { implicit request => + // pull details from the headers val eventuallyAuthenticatedUser = for { usernameParam <- request.headers.get("username") @@ -203,14 +212,40 @@ class Authentication @Inject() ( } yield { val username = URLDecoder.decode(usernameParam, "UTF-8") val password = URLDecoder.decode(passwordParam, "UTF-8") + + logger.info(s"Processing login request for user ${username}") + logger.info(s"Processing login request for pass ${password}") + logger.info(s"request: ${request}") + + logger.info(s"About to run credentialsProvider.authenticate") + val credentials = Credentials(username, password) + + val authenticated = credentialsProvider.authenticate(credentials).flatMap { (o) => + logger.info(s"loginInfo: $o") + Future.successful("WTF") + } + logger.info(s"authenticated: ${authenticated}") + + // val authenticated = Future.await (credentialsProvider.authenticate(Credentials(username, password))) + // flatMap { loginInfo: LoginInfo => + // logger.info(s"loginInfo: $loginInfo") + // logger.info(s"loginInfo.providerID: ${loginInfo.providerID}") + // Future.failed(new IdentityNotFoundException("Broken")) + // } + credentialsProvider .authenticate(Credentials(username, password)) .map(_.copy(request.dynamicEnvironment.id)) .flatMap { loginInfo => + + logger.info(s"User ${username} authenticated"); + logger.info(s"loginInfo ${loginInfo}"); + userService.getUser(loginInfo.providerKey).flatMap { // If we find a user, create and return an access token (JWT) case Some(user) => val customClaims = hatServicesService.generateUserTokenClaims(user, hatService) + for { // JWT Authenticator authenticator <- env.authenticatorService.create(loginInfo) @@ -244,6 +279,7 @@ class Authentication @Inject() ( // AuthenticatorResult result } + // No user found case None => Future.failed(new IdentityNotFoundException("Couldn't find user")) @@ -333,6 +369,7 @@ class Authentication @Inject() ( // Store that token tokenService.create(token).map { _ => mailer.passwordReset(email, passwordResetLink(request.host, token.id)) + response } // The user was not found, but return the "If we found an email address, we'll send the link." diff --git a/hat/app/org/hatdex/hat/api/controllers/SystemStatus.scala b/hat/app/org/hatdex/hat/api/controllers/SystemStatus.scala index d922e5267..847b336fb 100644 --- a/hat/app/org/hatdex/hat/api/controllers/SystemStatus.scala +++ b/hat/app/org/hatdex/hat/api/controllers/SystemStatus.scala @@ -67,18 +67,18 @@ class SystemStatus @Inject() ( private val logger = Logger(this.getClass) - private val indefiniteSuccessCaching = cached - .status(req => s"${req.host}${req.path}", 200) - .includeStatus(404, 600) + // private val indefiniteSuccessCaching = cached + // .status(req => s"${req.host}${req.path}", 200) + // .includeStatus(404, 600) def update(): EssentialAction = - indefiniteSuccessCaching { + // indefiniteSuccessCaching { UserAwareAction.async { implicit request => logger.debug(s"Updating HAT ${request.dynamicEnvironment.id}") hatDatabaseProvider.update(request.dynamicEnvironment.db) map { _ => Ok(Json.toJson(SuccessResponse("Database updated"))) } - } + // } } def healthReport(): Action[AnyContent] = { diff --git a/hat/app/org/hatdex/hat/api/service/UserServiceImpl.scala b/hat/app/org/hatdex/hat/api/service/UserServiceImpl.scala index 51b5c3404..c963d9b40 100644 --- a/hat/app/org/hatdex/hat/api/service/UserServiceImpl.scala +++ b/hat/app/org/hatdex/hat/api/service/UserServiceImpl.scala @@ -51,35 +51,62 @@ class UserServiceImpl @Inject() ( override def listUsers()(implicit server: HatServer): Future[Seq[HatUser]] = queryUser(UserUser) - override def getUser(userId: UUID)(implicit server: HatServer): Future[Option[HatUser]] = - cache - .get[HatUser](s"${server.domain}:user:$userId") - .flatMap { - case Some(cached) => Future.successful(Some(cached)) - case None => - queryUser(UserUser.filter(_.userId === userId)) - .map(_.headOption) - .andThen({ - case Success(Some(u)) => - cache.set(s"${server.domain}:user:${u.userId}", u) - cache.set(s"${server.domain}:user:${u.email}", u) - }) - } + override def getUser(userId: UUID)(implicit server: HatServer): Future[Option[HatUser]] = { + logger.info(s"Getting user $userId @${server.domain}") + + queryUser(UserUser.filter(_.userId === userId)) + .map(_.headOption) + .andThen({ + case Success(Some(u)) => { + logger.info(s"setting the cache for ${u.email}") + cache.set(s"${server.domain}:user:${u.userId}", u) + cache.set(s"${server.domain}:user:${u.email}", u) + } + }) - override def getUser(username: String)(implicit server: HatServer): Future[Option[HatUser]] = - cache - .get[HatUser](s"${server.domain}:user:$username") - .flatMap { - case Some(cached) => Future.successful(Some(cached)) - case None => - queryUser(UserUser.filter(_.email === username)) - .map(_.headOption) - .andThen({ - case Success(Some(u)) => - cache.set(s"${server.domain}:user:${u.userId}", u) - cache.set(s"${server.domain}:user:${u.email}", u) - }) - } + // cache + // .get[HatUser](s"${server.domain}:user:$userId") + // .flatMap { + // case Some(cached) => Future.successful(Some(cached)) + // case None => + // queryUser(UserUser.filter(_.userId === userId)) + // .map(_.headOption) + // .andThen({ + // case Success(Some(u)) => { + // logger.info(s"setting the cache for ${u.email}") + // cache.set(s"${server.domain}:user:${u.userId}", u) + // cache.set(s"${server.domain}:user:${u.email}", u) + // } + // }) + // } + + } + + override def getUser(username: String)(implicit server: HatServer): Future[Option[HatUser]] = { + logger.info(s"Getting username $username @${server.domain}") + + queryUser(UserUser.filter(_.email === username)) + .map(_.headOption) + .andThen({ + case Success(Some(u)) => + cache.set(s"${server.domain}:user:${u.userId}", u) + cache.set(s"${server.domain}:user:${u.email}", u) + }) + + // cache + // .get[HatUser](s"${server.domain}:user:$username") + // .flatMap { + // case Some(cached) => Future.successful(Some(cached)) + // case None => + // queryUser(UserUser.filter(_.email === username)) + // .map(_.headOption) + // .andThen({ + // case Success(Some(u)) => + // cache.set(s"${server.domain}:user:${u.userId}", u) + // cache.set(s"${server.domain}:user:${u.email}", u) + // }) + // } + } def getUserByRole( role: UserRole diff --git a/hat/app/org/hatdex/hat/authentication/HatApiController.scala b/hat/app/org/hatdex/hat/authentication/HatApiController.scala index 38b930e64..e8424a88b 100644 --- a/hat/app/org/hatdex/hat/authentication/HatApiController.scala +++ b/hat/app/org/hatdex/hat/authentication/HatApiController.scala @@ -54,8 +54,11 @@ abstract class HatController[T <: HatAuthEnvironment]( silhouette.securedAction(env) def UnsecuredAction: UnsecuredActionBuilder[T, AnyContent] = silhouette.unsecuredAction(env) - def UserAwareAction: UserAwareActionBuilder[T, AnyContent] = + def UserAwareAction: UserAwareActionBuilder[T, AnyContent] = { + println("UserAwareAction") + // println(s"env: ${env}") silhouette.userAwareAction(env) + } implicit def securedRequest2User[A]( implicit request: SecuredRequest[T, A]): HatUser = request.identity diff --git a/hat/app/org/hatdex/hat/modules/AppModule.scala b/hat/app/org/hatdex/hat/modules/AppModule.scala index 44437b98e..ede81280c 100644 --- a/hat/app/org/hatdex/hat/modules/AppModule.scala +++ b/hat/app/org/hatdex/hat/modules/AppModule.scala @@ -14,6 +14,7 @@ import javax.inject.{ Singleton => JSingleton } class AppModule extends ScalaModule { override def configure(): Unit = { + println("*** AppModule.configure() ***") bind[UserService].to[UserServiceImpl].in(classOf[JSingleton]) bind[ContractAction].to[ContractActionImpl].in(classOf[JSingleton]) } diff --git a/hat/app/org/hatdex/hat/modules/DataMonitoringModule.scala b/hat/app/org/hatdex/hat/modules/DataMonitoringModule.scala index e3105dc3f..4a1bbf87c 100644 --- a/hat/app/org/hatdex/hat/modules/DataMonitoringModule.scala +++ b/hat/app/org/hatdex/hat/modules/DataMonitoringModule.scala @@ -32,6 +32,7 @@ import play.api.libs.concurrent.AkkaGuiceSupport class DataMonitoringModule extends AbstractModule with ScalaModule with AkkaGuiceSupport { override protected def configure(): Unit = { + println("*** DataMonitoringModule.configure() ***") bindActor[HatDataStatsProcessorActor]("hatDataStatsProcessor") bind[HatDataEventRouter].to[HatDataEventRouterImpl].asEagerSingleton() () diff --git a/hat/app/org/hatdex/hat/modules/DevHatInitializationModule.scala b/hat/app/org/hatdex/hat/modules/DevHatInitializationModule.scala index fc28b9880..04dd83993 100644 --- a/hat/app/org/hatdex/hat/modules/DevHatInitializationModule.scala +++ b/hat/app/org/hatdex/hat/modules/DevHatInitializationModule.scala @@ -43,8 +43,10 @@ class DevHatInitializationModule extends ScalaModule with AkkaGuiceSupport { /** * Configures the module. */ - override protected def configure(): Unit = + override protected def configure(): Unit = { + println("*** DevHatInitializationModule.configure() ***") bind[DevHatInitializer].asEagerSingleton() + } } class DevHatInitializer @Inject() ( @@ -57,7 +59,8 @@ class DevHatInitializer @Inject() ( import DevHatConfig.configLoader val devHats: Map[String, DevHatConfig] = configuration.get[Map[String, DevHatConfig]]("devhats") - val devHatMigrations: Seq[String] = configuration.get[Seq[String]]("devhatMigrations") + // val devHatMigrations: Seq[String] = configuration.get[Seq[String]]("devhatMigrations") + val devHatMigrations: Seq[String] = Seq.empty logger.info(s"Initializing HATs: $devHats") devHats.values.map(initializeHat) diff --git a/hat/app/org/hatdex/hat/modules/FileManagerModule.scala b/hat/app/org/hatdex/hat/modules/FileManagerModule.scala index 7671aad88..139dd1472 100644 --- a/hat/app/org/hatdex/hat/modules/FileManagerModule.scala +++ b/hat/app/org/hatdex/hat/modules/FileManagerModule.scala @@ -42,6 +42,7 @@ import javax.inject.{ Singleton => JSingleton } class FileManagerModule extends ScalaModule { override def configure(): Unit = { + println("*** FileManagerModule.configure() ***") bind[FileUploadService].to[FileUploadServiceImpl] bind[FileMetadataRepository].to[FileMetadataRepositorySlick] bind[FileManager].to[FileManagerS3] diff --git a/hat/app/org/hatdex/hat/modules/HatServerProviderModule.scala b/hat/app/org/hatdex/hat/modules/HatServerProviderModule.scala index e8efbe8f4..5ef41da5b 100644 --- a/hat/app/org/hatdex/hat/modules/HatServerProviderModule.scala +++ b/hat/app/org/hatdex/hat/modules/HatServerProviderModule.scala @@ -40,6 +40,7 @@ import play.api.{ Configuration, Environment } class HatServerProviderModule extends AbstractModule with ScalaModule with AkkaGuiceSupport { override def configure(): Unit = { + println("*** HatServerProviderModule.configure() ***") bindActor[HatServerProviderActor]("hatServerProviderActor") bindActorFactory[HatServerActor, HatServerActor.Factory] diff --git a/hat/app/org/hatdex/hat/modules/HatTestServerProviderModule.scala b/hat/app/org/hatdex/hat/modules/HatTestServerProviderModule.scala index 7257dcc53..6791c487f 100644 --- a/hat/app/org/hatdex/hat/modules/HatTestServerProviderModule.scala +++ b/hat/app/org/hatdex/hat/modules/HatTestServerProviderModule.scala @@ -40,6 +40,7 @@ import play.api.{ Configuration, Environment } class HatTestServerProviderModule extends AbstractModule with ScalaModule with AkkaGuiceSupport { override def configure(): Unit = { + println("*** HatTestServerProviderModule.configure() ***") bindActor[HatServerProviderActor]("hatServerProviderActor") bindActorFactory[HatServerActor, HatServerActor.Factory] diff --git a/hat/app/org/hatdex/hat/modules/SHEModule.scala b/hat/app/org/hatdex/hat/modules/SHEModule.scala index 0a95cc37e..3b7ea45e6 100644 --- a/hat/app/org/hatdex/hat/modules/SHEModule.scala +++ b/hat/app/org/hatdex/hat/modules/SHEModule.scala @@ -42,6 +42,7 @@ class SHEModule extends AbstractModule with ScalaModule with AkkaGuiceSupport { val logger: Logger = Logger(this.getClass) override def configure(): Unit = { + println("*** SHEModule.configure() ***") bind[FunctionExecutionTriggerHandler].asEagerSingleton() () } diff --git a/hat/app/org/hatdex/hat/modules/SilhouetteModule.scala b/hat/app/org/hatdex/hat/modules/SilhouetteModule.scala index 87d72afdb..1cbdc1923 100644 --- a/hat/app/org/hatdex/hat/modules/SilhouetteModule.scala +++ b/hat/app/org/hatdex/hat/modules/SilhouetteModule.scala @@ -64,6 +64,7 @@ class SilhouetteModule extends ScalaModule with SilhouetteConfigLoaders { * Configures the module. */ override def configure(): Unit = { + println("*** SilhouetteModule.configure() ***") bind[DynamicEnvironmentProviderService[HatServer]].to[HatServerProvider] bind[Silhouette[HatApiAuthEnvironment]] diff --git a/hat/app/org/hatdex/hat/phata/controllers/Phata.scala b/hat/app/org/hatdex/hat/phata/controllers/Phata.scala index 574729428..8722d8979 100644 --- a/hat/app/org/hatdex/hat/phata/controllers/Phata.scala +++ b/hat/app/org/hatdex/hat/phata/controllers/Phata.scala @@ -53,9 +53,9 @@ class Phata @Inject() ( private val logger = Logger(this.getClass) - val indefiniteSuccessCaching: CachedBuilder = cached - .status(req => s"${req.host}${req.path}", 200) - .includeStatus(404, 600) + // val indefiniteSuccessCaching: CachedBuilder = cached + // .status(req => s"${req.host}${req.path}", 200) + // .includeStatus(404, 600) val csp: Map[String, String] = configuration .get[String]("play.filters.headers.contentSecurityPolicy") @@ -74,6 +74,8 @@ class Phata @Inject() ( def profile: Action[AnyContent] = UserAwareAction.async { implicit request => + logger.info(s"config: ${configuration}") + val defaultBundleDefinition = Json .parse(configuration.get[String]("phata.defaultBundle")) .as[EndpointDataBundle] diff --git a/hat/app/org/hatdex/hat/resourceManagement/HatDatabaseProvider.scala b/hat/app/org/hatdex/hat/resourceManagement/HatDatabaseProvider.scala index 5a4a690db..f83e666b4 100644 --- a/hat/app/org/hatdex/hat/resourceManagement/HatDatabaseProvider.scala +++ b/hat/app/org/hatdex/hat/resourceManagement/HatDatabaseProvider.scala @@ -98,6 +98,13 @@ class HatDatabaseProviderMilliner @Inject() ( "portNumber" -> signup.databaseServer.get.port.toString, "serverName" -> signup.databaseServer.get.host ).asJava, + // "properties" -> Map[String, String]( + // "user" -> "masteruser", + // "password" -> "YFgbCbN8PWIilIJmMINv", + // "databaseName" -> "hatAdmin", + // "portNumber" -> "5432", + // "serverName" -> "dataswift-staging-pds-eu-hat-n1.cdgbpyaamcol.eu-west-1.rds.amazonaws.com" + // ).asJava, "numThreads" -> configuration .get[Int]("resourceManagement.hatDBThreads") .toString, diff --git a/hat/app/org/hatdex/hat/resourceManagement/HatKeyProvider.scala b/hat/app/org/hatdex/hat/resourceManagement/HatKeyProvider.scala index 60e5bd5f1..5130c0294 100644 --- a/hat/app/org/hatdex/hat/resourceManagement/HatKeyProvider.scala +++ b/hat/app/org/hatdex/hat/resourceManagement/HatKeyProvider.scala @@ -52,9 +52,11 @@ trait HatKeyProvider { def toString(rsaPublicKey: RSAPublicKey): String = { val pemObject = new PemObject("PUBLIC KEY", rsaPublicKey.getEncoded) val stringPemWriter = new StringWriter() + val pemWriter: PemWriter = new PemWriter(stringPemWriter) pemWriter.writeObject(pemObject) pemWriter.flush() + val pemPublicKey = stringPemWriter.toString pemPublicKey } @@ -91,8 +93,10 @@ trait HatKeyProvider { @Singleton class HatKeyProviderConfig @Inject() (configuration: Configuration) extends HatKeyProvider { def publicKey( - hat: String - )(implicit ec: ExecutionContext): Future[RSAPublicKey] = + hat: String + )(implicit ec: ExecutionContext): Future[RSAPublicKey] = { + println(s"Fetching public Key for hat: $hat") + println(configuration.getOptional[String](s"hat.${hat.replace(':', '.')}.publicKey")) configuration.getOptional[String]( s"hat.${hat.replace(':', '.')}.publicKey" ) map { confPublicKey => @@ -102,10 +106,13 @@ class HatKeyProviderConfig @Inject() (configuration: Configuration) extends HatK new HatServerDiscoveryException(s"Public Key for $hat not found") ) } + } def privateKey( hat: String - )(implicit ec: ExecutionContext): Future[RSAPrivateKey] = + )(implicit ec: ExecutionContext): Future[RSAPrivateKey] = { + println(s"Fetching private Key for hat: $hat") + println(configuration.getOptional[String](s"hat.${hat.replace(':', '.')}.privateKey")) configuration.getOptional[String]( s"hat.${hat.replace(':', '.')}.privateKey" ) map { confPrivateKey => @@ -115,6 +122,7 @@ class HatKeyProviderConfig @Inject() (configuration: Configuration) extends HatK new HatServerDiscoveryException(s"Private Key for $hat not found in the configuration") ) } + } def ownerEmail(hat: String)(implicit ec: ExecutionContext): Future[String] = configuration.getOptional[String]( @@ -141,12 +149,14 @@ class HatKeyProviderMilliner @Inject() ( hat: String )(implicit ec: ExecutionContext): Future[RSAPublicKey] = getHatSignup(hat) flatMap { signup => + logger.debug( s"Received signup info, parsing public key ${signup.keys.map(_.publicKey)}" ) readRsaPublicKey(signup.keys.get.publicKey) } recoverWith { - case e => + case e => + logger.debug(s"publicKey.Hat: ${hat}") Future.failed( new HatServerDiscoveryException(s"Public Key for $hat not found", e) ) diff --git a/hat/app/org/hatdex/hat/resourceManagement/HatServerProvider.scala b/hat/app/org/hatdex/hat/resourceManagement/HatServerProvider.scala index 89f53d373..5972ab438 100644 --- a/hat/app/org/hatdex/hat/resourceManagement/HatServerProvider.scala +++ b/hat/app/org/hatdex/hat/resourceManagement/HatServerProvider.scala @@ -51,6 +51,7 @@ trait HatServerProvider extends DynamicEnvironmentProviderService[HatServer] { val pemWriter: PemWriter = new PemWriter(stringPemWriter) pemWriter.writeObject(pemObject) pemWriter.flush() + val pemPublicKey = stringPemWriter.toString pemPublicKey } @@ -81,13 +82,16 @@ class HatServerProviderImpl @Inject() ( configuration.get[FiniteDuration]("resourceManagement.serverIdleTimeout") def retrieve(hatAddress: String): Future[Option[HatServer]] = { + logger.info(s"HatServiceProvider.retrieve: looking up hatAddress: server:${hatAddress}") - cache - .get[HatServer](s"server:$hatAddress") - .flatMap { - case Some(server) => Future.successful(Some(server)) - case _ => + // cache + // .get[HatServer](s"server:$hatAddress") + // .flatMap { + // // found in cache + // case Some(server) => Future.successful(Some(server)) + // // not found in cache + // case _ => (serverProviderActor ? HatServerProviderActor.HatServerRetrieve( hatAddress )) map { @@ -106,15 +110,16 @@ class HatServerProviderImpl @Inject() ( throw error } recoverWith { case e => - logger.warn( - s"Error while retrieving HAT $hatAddress info: ${e.getMessage} ${e.getStackTrace()}" + logger.error( + s"Error while retrieving HAT $hatAddress info: ${e.getMessage} ${e.getStackTrace().mkString("Array(", ", ", ")")}" ) + logger.error(e.toString()) val error = new HatServerDiscoveryException( "HAT Server info retrieval failed", e ) throw error } - } + // } } } diff --git a/hat/app/org/hatdex/hat/resourceManagement/MillinerHatSignup.scala b/hat/app/org/hatdex/hat/resourceManagement/MillinerHatSignup.scala index a0300ae3b..ed40bb799 100644 --- a/hat/app/org/hatdex/hat/resourceManagement/MillinerHatSignup.scala +++ b/hat/app/org/hatdex/hat/resourceManagement/MillinerHatSignup.scala @@ -48,9 +48,12 @@ trait MillinerHatSignup { def getHatSignup( hatAddress: String - )(implicit ec: ExecutionContext): Future[HatSignup] = + )(implicit ec: ExecutionContext): Future[HatSignup] = { // Cache the signup information for subsequent calls (For private/public key and database details) - cache.getOrElseUpdate[HatSignup](s"configuration:$hatAddress") { + //cache.getOrElseUpdate[HatSignup](s"configuration:$hatAddress") { + logger.info("getHatSignup") + logger.info(s"$millinerAddress/api/manage/configuration/$hatAddress") + val request: WSRequest = ws .url(s"$millinerAddress/api/manage/configuration/$hatAddress") .withHttpHeaders( @@ -59,6 +62,7 @@ trait MillinerHatSignup { ) val futureResponse: Future[WSResponse] = request.get() + futureResponse.map { response => response.status match { case OK => diff --git a/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerActor.scala b/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerActor.scala index aa1292396..88549c4cc 100644 --- a/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerActor.scala +++ b/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerActor.scala @@ -126,7 +126,8 @@ class HatServerActor @Inject() ( } private def server(hat: String): Future[HatServer] = { - log.debug(s"fetching hat keys for hat: $hat") + log.info(s"fetching hat keys for hat: $hat") + val server = for { privateKey <- hatKeyProvider.privateKey(hat) publicKey <- hatKeyProvider.publicKey(hat) diff --git a/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerProviderActor.scala b/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerProviderActor.scala index 553a7a538..810206986 100644 --- a/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerProviderActor.scala +++ b/hat/app/org/hatdex/hat/resourceManagement/actors/HatServerProviderActor.scala @@ -49,6 +49,7 @@ class HatServerProviderActor @Inject() ( import HatServerProviderActor._ private val activeServers = mutable.HashMap[String, ActorRef]() + implicit private val hatServerTimeout: Timeout = configuration.get[FiniteDuration]( "resourceManagement.serverProvisioningTimeout" @@ -57,14 +58,18 @@ class HatServerProviderActor @Inject() ( def receive: Receive = { case HatServerRetrieve(hat) => log.info(s"Retrieve HAT server $hat for $sender") + val retrievingSender = sender + getHatServerActor(hat) map { hatServerActor => log.info( s"Success: Got HAT server provider actor, forwarding retrieval message with sender $sender $retrievingSender" ) hatServerActor tell (HatServerActor.HatRetrieve(), retrievingSender) } onComplete { - case Success(_) => () + case Success(_) => + log.info(s"HatServerRetrieve.Success") + () case Failure(e) => log.warn( s"Failure: Error while getting HAT server provider actor: ${e.getMessage}" @@ -89,6 +94,8 @@ class HatServerProviderActor @Inject() ( hat: String, timeout: FiniteDuration, depth: Int = 0): Future[ActorRef] = { + log.info(s">>> doFindOrCreate(${hat}) called") + if (depth >= maxAttempts) { log.error(s"HAT server actor for $hat not resolved") throw new RuntimeException( @@ -111,7 +118,9 @@ class HatServerProviderActor @Inject() ( props = (props: Props) => props.withDispatcher("hat-server-provider-actor-dispatcher") ) activeServers(hat) = hatServerActor + log.warn(s"Injected actor $hatServerActor") + doFindOrCreate(hat, timeout, depth + 1) } } @@ -120,7 +129,6 @@ class HatServerProviderActor @Inject() ( object HatServerProviderActor { case class HatServerRetrieve(hat: String) - case class HatServerStarted(hat: String) case class HatServerStopped(hat: String) } diff --git a/hat/app/org/hatdex/hat/utils/Mailer.scala b/hat/app/org/hatdex/hat/utils/Mailer.scala index 9cd4aef5e..bfacd22aa 100644 --- a/hat/app/org/hatdex/hat/utils/Mailer.scala +++ b/hat/app/org/hatdex/hat/utils/Mailer.scala @@ -61,7 +61,9 @@ trait Mailer { if (!mock) { val message = new Message(content(subject), new Body(content(bodyText)).withHtml(content(bodyHtml))) val request = new SendEmailRequest(from, new Destination(recipients.asJava), message) - Future(mailerClient.sendEmail(request)).map(_ => Done) + val mailSendResult = mailerClient.sendEmail(request) + println(mailSendResult.toString()) + Future(Done) } else { logger.info(s"mocking enabled, not sending email about '$subject' to ${recipients.mkString(", ")}") Future.successful(Done) diff --git a/hat/conf/application.conf b/hat/conf/application.conf index 2468b6449..11a07c3ca 100644 --- a/hat/conf/application.conf +++ b/hat/conf/application.conf @@ -80,10 +80,11 @@ silhouette { } hat { - version = "v2.8.18" + version = "v2.8.19" version = ${?HAT_VERSION} tls = false - schemaMigrations = ["evolutions/hat-database-schema/13_liveEvolutions.sql", "evolutions/hat-database-schema/14_newHat.sql"] + schemaMigrations = [ + "evolutions/hat-database-schema/13_liveEvolutions.sql", "evolutions/hat-database-schema/14_newHat.sql"] serverProviderModule = "org.hatdex.hat.modules.HatTestServerProviderModule" serverProviderModule = ${?HAT_SERVER_PROVIDER} serverProvider { diff --git a/hat/conf/cache.conf b/hat/conf/cache.conf index ccac4d83d..e164f11f5 100644 --- a/hat/conf/cache.conf +++ b/hat/conf/cache.conf @@ -1,6 +1,7 @@ play.cache.redis { prefix = hat${?APP_VERSION} host = ${?REDIS_HOST} + host="hatstagingredis-0001-001.onquve.0001.euw1.cache.amazonaws.com" } application-cache-ttl = "10 minutes" diff --git a/hat/conf/routes b/hat/conf/routes index 716ca3801..ef4d14d9a 100644 --- a/hat/conf/routes +++ b/hat/conf/routes @@ -1,14 +1,14 @@ # Utility routes GET /assets/*file controllers.Assets.at(file) -GET /.well-known/apple-app-site-association org.hatdex.hat.phata.controllers.WellKnown.appleAppSiteAssociation +GET /.well-known/apple-app-site-association org.hatdex.hat.phata.controllers.WellKnown.appleAppSiteAssociation() # USER Routes -GET /users/user org.hatdex.hat.api.controllers.Users.listUsers -POST /users/user org.hatdex.hat.api.controllers.Users.createUser -GET /publickey org.hatdex.hat.api.controllers.Authentication.publicKey -GET /users/access_token/validate org.hatdex.hat.api.controllers.Authentication.validateToken +GET /users/user org.hatdex.hat.api.controllers.Users.listUsers() +POST /users/user org.hatdex.hat.api.controllers.Users.createUser() +GET /publickey org.hatdex.hat.api.controllers.Authentication.publicKey() +GET /users/access_token/validate org.hatdex.hat.api.controllers.Authentication.validateToken() GET /users/application_token org.hatdex.hat.api.controllers.Authentication.applicationToken(name: String, resource: String) -GET /users/access_token org.hatdex.hat.api.controllers.Authentication.accessToken +GET /users/access_token org.hatdex.hat.api.controllers.Authentication.accessToken() PUT /users/user/:userId/enable org.hatdex.hat.api.controllers.Users.enableUser(userId: java.util.UUID) PUT /users/user/:userId/disable org.hatdex.hat.api.controllers.Users.disableUser(userId: java.util.UUID) PUT /users/user/:userId/delete org.hatdex.hat.api.controllers.Users.deleteUser(userId: java.util.UUID) @@ -20,15 +20,15 @@ GET /healthz org.hatdex.hat. # AUTHENTICATION routes GET /control/v2/auth/hatlogin org.hatdex.hat.api.controllers.Authentication.hatLogin(name: String, redirect: String) -POST /control/v2/auth/password org.hatdex.hat.api.controllers.Authentication.passwordChangeProcess -POST /control/v2/auth/passwordReset org.hatdex.hat.api.controllers.Authentication.handleForgotPassword +POST /control/v2/auth/password org.hatdex.hat.api.controllers.Authentication.passwordChangeProcess() +POST /control/v2/auth/passwordReset org.hatdex.hat.api.controllers.Authentication.handleForgotPassword() POST /control/v2/auth/passwordreset/confirm/:token org.hatdex.hat.api.controllers.Authentication.handleResetPassword(token: String) POST /control/v2/auth/claim org.hatdex.hat.api.controllers.Authentication.handleVerificationRequest(lang: Option[String], sendEmailToUser: Option[Boolean]) POST /control/v2/auth/request-verification org.hatdex.hat.api.controllers.Authentication.handleVerificationRequest(lang: Option[String], sendEmailToUser: Option[Boolean]) POST /control/v2/auth/claim/complete/:verificationToken org.hatdex.hat.api.controllers.Authentication.handleVerification(verificationToken: String) # Metrics -GET /metrics com.github.stijndehaes.playprometheusfilters.controllers.PrometheusController.getMetrics +GET /metrics com.github.stijndehaes.playprometheusfilters.controllers.PrometheusController.getMetrics() -> /api/v2 v20.Routes -> /api/v2.0 v20.Routes diff --git a/hat/test/resources/application.conf b/hat/test/resources/application.conf index 4f681683e..9ccba01ae 100644 --- a/hat/test/resources/application.conf +++ b/hat/test/resources/application.conf @@ -3,7 +3,6 @@ she.aws.mock = true resourceManagement.hatDBIdleTimeout = 30 seconds - hat { hat.hubofallthings.net { ownerEmail = "user@hat.org" diff --git a/start.sh b/start.sh new file mode 100644 index 000000000..025147d24 --- /dev/null +++ b/start.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +export ADJUDICATOR_ADDRESS="https://contracts.hubat.net" +export AWS_REGION="eu-west-1" +export APPLICATION_CACHE_TTL="10 seconds" +export DEX_ADDRESS="https://dex.dataswift.io" +export DROPS_SHE_BASE_URL="drops-she-sandbox" +export REDIS_HOST="hatstagingredis-0001-001.onquve.0001.euw1.cache.amazonaws.com:6379" +export HAT_ADMIN_EMAIL="systems@vault.dataswift.dev" +export HAT_BETA="true" +export HAT_DB_IDLE_TIMEOUT="60 seconds" +export HAT_DB_THREADS="15" +export HAT_DOMAIN=".hubat.net" +export HAT_SERVER_PROVIDER="org.hatdex.hat.modules.HatServerProviderModule" +export HAT_STORAGE_S3_BUCKET="dataswift-sandbox-pds-eu-hat" +export JAVA_OPTS="-Xmx1000m -Xms512m" +export MAILER_FROM="Dataswift " +export MILLINER_ADDRESS="https://milliner.hubat.net" +export PDA_REGISTRY_HOST="https://hatters.dataswift.io" +export RESOURCE_MGMT_SERVER_IDLE_TIMEOUT="180 seconds" +export SHE_BASE_URL="dswift-she-sandbox" +export DBUSER=masteruser +export DBPASS=YFgbCbN8PWIilIJmMINv +export DATABASE=postgresql://dataswift-staging-pds-eu-hat-n1.cdgbpyaamcol.eu-west-1.rds.amazonaws.com:5432/hatAdmin +export POSTGRES_PORT=5432 + + +sbt "project hat" run -Denv=prod