Skip to content

Commit

Permalink
v4.0.0
Browse files Browse the repository at this point in the history
V4
  • Loading branch information
jona7o authored May 1, 2021
2 parents f0e02c4 + 1e6b55f commit e761799
Show file tree
Hide file tree
Showing 78 changed files with 1,583 additions and 849 deletions.
Binary file modified .DS_Store
Binary file not shown.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion local-runner/runFor.sh → .bin/runFor.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

NAME="Dark Lord Toni"
NAME="Development"
REMOVE=0

RED='\033[0;31m'
Expand Down
2 changes: 1 addition & 1 deletion local-runner/runForDoc.md → .bin/runForDoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The runFor.sh Script will start a Docker Postgis Container with [docker-compose.

The Postgis data volume will be mounted to:

- __local-runner/postgis-volume__
- __.bin/postgis-volume__

so that even if the container is deleted no data will be lost!

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion .bsp/sbt.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"name":"sbt","version":"1.4.4","bspVersion":"2.0.0-M5","languages":["scala"],"argv":["/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java","-Xms100m","-Xmx100m","-classpath","/Users/patrickstadler/Library/Application Support/JetBrains/IntelliJIdea2020.3/plugins/Scala/launcher/sbt-launch.jar","xsbt.boot.Boot","-bsp"]}
{"name":"sbt","version":"1.5.0","bspVersion":"2.0.0-M5","languages":["scala"],"argv":["/Applications/IntelliJ IDEA.app/Contents/jbr/Contents/Home/bin/java","-Xms100m","-Xmx100m","-classpath","/Users/patrickstadler/Library/Application Support/JetBrains/IntelliJIdea2020.3/plugins/Scala/launcher/sbt-launch.jar","xsbt.boot.Boot","-bsp","--sbt-launch-jar=/Users/patrickstadler/Library/Application%20Support/JetBrains/IntelliJIdea2020.3/plugins/Scala/launcher/sbt-launch.jar"]}
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ server.pid
*.eml
/dist/


test.mv.db

#Firebase
Expand All @@ -49,10 +48,12 @@ pubSub-dev.json
.circleci/k8sdeploy.yaml-e
.metals/*

.bsp/*

#puml
out/doc

.DS_Store

local-runner/postgis-volume
.bin/postgis-volume
.bloop/
111 changes: 92 additions & 19 deletions app/Module.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import java.util.Properties
import com.google.auth.Credentials
import com.google.auth.oauth2.GoogleCredentials

import java.util.Properties
import javax.inject.{ Inject, Provider, Singleton }
import com.typesafe.config.Config
import play.api.inject.ApplicationLifecycle
import play.api.{ Configuration, Environment, Logger, Mode }
import slick.jdbc.JdbcBackend.Database
import com.google.inject.AbstractModule
import de.innfactory.auth.firebase.FirebaseBase
import de.innfactory.auth.firebase.FirebaseBase.getClass
import de.innfactory.auth.firebase.validator.{ JWTValidatorMock, JwtValidator, JwtValidatorImpl }
import de.innfactory.bootstrapplay2.db.{ CompaniesDAO, LocationsDAO }
import de.innfactory.play.flyway.FlywayMigrator
import io.opencensus.exporter.trace.jaeger.{ JaegerExporterConfiguration, JaegerTraceExporter }
import io.opencensus.exporter.trace.logging.LoggingTraceExporter
import io.opencensus.exporter.trace.stackdriver.{ StackdriverTraceConfiguration, StackdriverTraceExporter }
import io.opencensus.trace.AttributeValue
import play.api.libs.concurrent.AkkaGuiceSupport

import java.io.InputStream
import scala.concurrent.Future
import scala.jdk.CollectionConverters.MapHasAsJava

/**
* This module handles the bindings for the API to the Slick implementation.
Expand All @@ -24,30 +34,97 @@ class Module(environment: Environment, configuration: Configuration) extends Abs

override def configure(): Unit = {
logger.info(s"Configuring ${environment.mode}")

bind(classOf[Database]).toProvider(classOf[DatabaseProvider])
bind(classOf[firebaseCreationService]).asEagerSingleton()
bind(classOf[firebaseDeletionService]).asEagerSingleton()
bind(classOf[FlywayMigratorImpl]).asEagerSingleton()
bind(classOf[LocationsDAOCloseHook]).asEagerSingleton()
bind(classOf[CompaniesDAOCloseHook]).asEagerSingleton()
bind(classOf[DAOCloseHook]).asEagerSingleton()

/**
* Inject Modules depended on environment (Test, Prod, Dev)
*/
if (environment.mode == Mode.Test) {

logger.info(s"- - - Binding Services for for Test Mode - - -")
bind(classOf[JwtValidator])
.to(classOf[JWTValidatorMock]) // Bind Mock JWT Validator for Test Mode

// Bind Mock JWT Validator for Test Mode
bind(classOf[JwtValidator]).to(classOf[JWTValidatorMock])

} else if (environment.mode == Mode.Dev) {

logger.info(s"- - - Binding Services for for Dev Mode - - -")

// Firebase
bind(classOf[firebaseCreationService]).asEagerSingleton()
bind(classOf[firebaseDeletionService]).asEagerSingleton()

// Bind Prod JWT Validator for Prod/Dev Mode
bind(classOf[JwtValidator]).to(classOf[JwtValidatorImpl])

// Optional Jaeger Exporter bind(classOf[JaegerTracingCreator]).asEagerSingleton()

} else {
logger.info(s"- - - Binding Services for for Prod/Dev Mode - - -")
bind(classOf[JwtValidator])
.to(classOf[JwtValidatorImpl]) // Bind Prod JWT Validator for Prod/Dev Mode

logger.info(s"- - - Binding Services for for Prod Mode - - -")

bind(classOf[firebaseCreationService]).asEagerSingleton()
bind(classOf[firebaseDeletionService]).asEagerSingleton()

// Bind Prod JWT Validator for Prod/Dev Mode
bind(classOf[JwtValidator]).to(classOf[JwtValidatorImpl])

// Tracing
bind(classOf[StackdriverTracingCreator]).asEagerSingleton()
bind(classOf[LoggingTracingCreator]).asEagerSingleton()

}

}

}

@Singleton
class LoggingTracingCreator @Inject() (lifecycle: ApplicationLifecycle) {
LoggingTraceExporter.register()
lifecycle.addStopHook { () =>
Future.successful(LoggingTraceExporter.unregister())
}
}

@Singleton
class JaegerTracingCreator @Inject() (lifecycle: ApplicationLifecycle) {
val jaegerExporterConfiguration: JaegerExporterConfiguration = JaegerExporterConfiguration
.builder()
.setServiceName("bootstrap-play2")
.setThriftEndpoint("http://127.0.0.1:14268/api/traces")
.build()
JaegerTraceExporter.createAndRegister(jaegerExporterConfiguration)

lifecycle.addStopHook { () =>
Future.successful(JaegerTraceExporter.unregister())
}
}

@Singleton
class StackdriverTracingCreator @Inject() (lifecycle: ApplicationLifecycle, config: Config) {
val serviceAccount: InputStream = getClass.getClassLoader.getResourceAsStream(config.getString("firebase.file"))
val credentials: GoogleCredentials = GoogleCredentials.fromStream(serviceAccount)
val stackDriverTraceExporterConfig: StackdriverTraceConfiguration = StackdriverTraceConfiguration
.builder()
.setProjectId(config.getString("project.id"))
.setCredentials(credentials)
.setFixedAttributes(
Map(
("/component", AttributeValue.stringAttributeValue("PlayServer"))
).asJava
)
.build()

StackdriverTraceExporter.createAndRegister(stackDriverTraceExporterConfig)
lifecycle.addStopHook { () =>
Future.successful(StackdriverTraceExporter.unregister())
}
}

/** Migrate Flyway on application start */
class FlywayMigratorImpl @Inject() (env: Environment, configuration: Configuration)
extends FlywayMigrator(configuration, env, configIdentifier = "bootstrap-play2")
Expand All @@ -72,15 +149,11 @@ class DatabaseProvider @Inject() (config: Config) extends Provider[Database] {
}

/** Closes DAO. Important on dev restart. */
class CompaniesDAOCloseHook @Inject() (dao: CompaniesDAO, lifecycle: ApplicationLifecycle) {
lifecycle.addStopHook { () =>
Future.successful(dao.close())
}
}

/** Closes DAO. Important on dev restart. */
class LocationsDAOCloseHook @Inject() (dao: LocationsDAO, lifecycle: ApplicationLifecycle) {
class DAOCloseHook @Inject() (companiesDAO: CompaniesDAO, locationsDAO: LocationsDAO, lifecycle: ApplicationLifecycle) {
lifecycle.addStopHook { () =>
Future.successful(dao.close())
Future.successful({
companiesDAO.close()
locationsDAO.close()
})
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,61 @@
package de.innfactory.bootstrapplay2.actions

import cats.implicits.catsSyntaxEitherId
import com.google.inject.Inject
import de.innfactory.bootstrapplay2.common.authorization.FirebaseEmailExtractor
import de.innfactory.bootstrapplay2.common.request.TraceContext
import de.innfactory.bootstrapplay2.common.results.ErrorResponse
import de.innfactory.bootstrapplay2.db.CompaniesDAO
import de.innfactory.bootstrapplay2.models.api.Company
import play.api.mvc.{ ActionBuilder, ActionTransformer, AnyContent, BodyParsers, Request, WrappedRequest }
import de.innfactory.play.tracing.{ RequestWithTrace, TraceRequest, UserExtractionActionBase }
import io.opencensus.trace.Span
import play.api.Environment
import play.api.mvc.Results.Forbidden
import play.api.mvc.{ BodyParsers, Request, Result, WrappedRequest }

import scala.concurrent.{ ExecutionContext, Future }

class RequestWithCompany[A](val company: Option[Company], val email: Option[String], request: Request[A])
extends WrappedRequest[A](request)
class RequestWithCompany[A](
val company: Company,
val email: Option[String],
val request: Request[A],
val traceSpan: Span
) extends WrappedRequest[A](request)
with TraceRequest[A]

class CompanyForUserExtractAction @Inject() (
val parser: BodyParsers.Default,
companiesDAO: CompaniesDAO,
firebaseEmailExtractor: FirebaseEmailExtractor[Any]
)(implicit val executionContext: ExecutionContext)
extends ActionBuilder[RequestWithCompany, AnyContent]
with ActionTransformer[Request, RequestWithCompany] {
def transform[A](request: Request[A]): Future[RequestWithCompany[A]] =
)(implicit executionContext: ExecutionContext, parser: BodyParsers.Default, environment: Environment)
extends UserExtractionActionBase[RequestWithTrace, RequestWithCompany] {

override def extractUserAndCreateNewRequest[A](request: RequestWithTrace[A])(implicit
environment: Environment,
parser: BodyParsers.Default,
executionContext: ExecutionContext
): Future[Either[Result, RequestWithCompany[A]]] =
Future.successful {
val result: Option[Future[Option[Company]]] = for {
email <- firebaseEmailExtractor.extractEmail(request)
} yield for {
user <- companiesDAO.internal_lookupByEmail(email)
user <- companiesDAO.internal_lookupByEmail(email)(new TraceContext(request.traceSpan))
} yield user

result match {
case Some(v) =>
v.map(new RequestWithCompany(_, firebaseEmailExtractor.extractEmail(request), request))
case None => Future(new RequestWithCompany(None, firebaseEmailExtractor.extractEmail(request), request))
v.map {
case Some(value) =>
new RequestWithCompany(
value,
firebaseEmailExtractor.extractEmail(request),
request.request,
request.traceSpan
).asRight[Result]
case None => Forbidden(ErrorResponse.fromMessage("Forbidden")).asLeft[RequestWithCompany[A]]
}
case None =>
Future(
Forbidden(ErrorResponse.fromMessage("Forbidden")).asLeft[RequestWithCompany[A]]
)
}
}.flatten
}
68 changes: 20 additions & 48 deletions app/de/innfactory/bootstrapplay2/actions/JwtValidationAction.scala
Original file line number Diff line number Diff line change
@@ -1,56 +1,28 @@
package de.innfactory.bootstrapplay2.actions

import com.google.inject.Inject
import com.nimbusds.jwt.proc.BadJWTException
import de.innfactory.auth.firebase.validator.{ JwtToken, JwtValidator }
import play.api.Environment
import play.api.mvc.Results.Forbidden
import play.api.mvc.Results.Unauthorized
import de.innfactory.auth.firebase.validator.JwtValidator
import de.innfactory.bootstrapplay2.common.implicits.JWT.JwtTokenGenerator
import de.innfactory.play.tracing.{ BaseAuthHeaderRefineAction, RequestWithTrace }
import play.api.mvc.BodyParsers

import scala.concurrent.{ ExecutionContext, Future }
import play.api.mvc._
import scala.concurrent.ExecutionContext

class JwtValidationAction @Inject() (parser: BodyParsers.Default, jwtValidator: JwtValidator, environment: Environment)(
implicit ec: ExecutionContext
) extends ActionBuilderImpl(parser) {
override def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) =
if (extractAndCheckAuthHeader(request.headers).getOrElse(false))
block(request)
else if (request.headers.get("Authorization").isEmpty)
Future.successful(Unauthorized("Unauthorized"))
else
Future.successful(Forbidden("Forbidden"))
class JwtValidationAction @Inject() (
parser: BodyParsers.Default,
jwtValidator: JwtValidator
)(implicit
ec: ExecutionContext
) extends BaseAuthHeaderRefineAction[RequestWithTrace](parser) {

/**
* Extract auth header from requestHeaders
* @param requestHeader
* @return
*/
def extractAndCheckAuthHeader(requestHeader: Headers) =
for {
header <- requestHeader.get("Authorization")
} yield checkAuthHeader(header)

/**
* check and validate auth header
* @param authHeader
* @return
*/
def checkAuthHeader(authHeader: String): Boolean =
// In Test env, jwt will not be validated
if (environment.mode.toString != "Test") {
val jwtToken = authHeader match {
case token: String if token.startsWith("Bearer") =>
JwtToken(token.splitAt(7)._2)
case token => JwtToken(token)
}

jwtValidator.validate(jwtToken) match {
case Left(error: BadJWTException) =>
false
case Right(_) => true
}
} else
true
override def checkAuthHeader(authHeader: String): Boolean = {
val jwtToken = authHeader.toJwtToken
val res = jwtValidator.validate(jwtToken) match {
case Left(_) => false
case Right(_) => true
}
println("Auth Header Check on " + authHeader + " " + res)
res
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package de.innfactory.bootstrapplay2.actions

import com.google.inject.Inject
import de.innfactory.play.tracing.TracingAction
import play.api.Environment
import play.api.mvc._

import scala.concurrent.ExecutionContext

class TracingCompanyAction @Inject() (
val parser: BodyParsers.Default,
companyAction: CompanyForUserExtractAction,
jwtValidationAction: JwtValidationAction,
traceAction: TracingAction,
implicit val environment: Environment
)(implicit val executionContext: ExecutionContext) {
def apply(traceString: String): ActionBuilder[RequestWithCompany, AnyContent] =
traceAction(traceString).andThen(jwtValidationAction).andThen(companyAction)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ trait HelloWorldService {
class HelloWorldServiceImpl @Inject() (
)(implicit ec: ExecutionContext, system: ActorSystem)
extends HelloWorldService {
// asking someone requires a timeout if the timeout hits without response
// // asking someone requires a timeout if the timeout hits without response
// the ask is failed with a TimeoutException
private implicit val timeout: Timeout = 10.seconds

Expand Down
Loading

0 comments on commit e761799

Please sign in to comment.