app/config/AMIableConfig.scala (98 lines of code) (raw):
package config
import java.io.FileInputStream
import com.google.auth.oauth2.ServiceAccountCredentials
import com.gu.googleauth.{
AntiForgeryChecker,
GoogleAuthConfig,
GoogleGroupChecker
}
import controllers.routes
import javax.inject.Inject
import play.api.Configuration
import play.api.http.HttpConfiguration
import play.api.libs.ws.WSClient
import scala.util.Try
case class AMIableConfig(
prismUrl: String,
amigoUrl: String,
wsClient: WSClient,
mailAddress: String,
ownerNotificationCron: Option[String],
overrideToAddress: Option[String],
amiableUrl: String
)
case class AuthConfig(
googleAuthConfig: GoogleAuthConfig,
googleGroupChecker: GoogleGroupChecker,
requiredGoogleGroups: Set[String]
)
class AmiableConfigProvider @Inject() (
val ws: WSClient,
val playConfig: Configuration,
val httpConfiguration: HttpConfiguration
) {
val amiableUrl: String = requiredString(playConfig, "host")
val conf = AMIableConfig(
playConfig.get[String]("prism.url"),
playConfig.get[String]("amigo.url"),
ws,
playConfig.get[String]("amiable.mailClient.fromAddress"),
playConfig.getOptional[String]("amiable.owner.notification.cron"),
playConfig.getOptional[String](
"amiable.owner.notification.overrideToAddress"
),
amiableUrl
)
val stage: String = requiredString(
playConfig,
"stage"
)
/** Cloudwatch metrics are expensive. Our pre-PROD environments do not get
* much traffic, so in order to reduce AWS spend, only create metrics in
* PROD.
*/
val shouldCreateCloudwatchMetrics: Boolean = stage == "PROD"
/** If our pre-PROD environments are not creating metrics, have them read
* PROD's so the app can be fully tested.
* @see
* [[`shouldCreateCloudwatchMetrics`]]
*/
val cloudwatchReadNamespace: String =
if (shouldCreateCloudwatchMetrics) s"AMIable-$stage" else s"AMIable-PROD"
val cloudwatchWriteNamespace: String = s"AMIable-$stage"
val cloudwatchSecurityHqNamespace: String = "SecurityHQ"
val requiredGoogleGroups: Set[String] = Set(
requiredString(playConfig, "auth.google.2faGroupId"),
requiredString(playConfig, "auth.google.departmentGroupId")
)
val googleAuthConfig: GoogleAuthConfig = {
// Different constructors depending on whether domain is available or not
playConfig
.getOptional[String]("auth.google.apps-domain")
.map(domain => {
GoogleAuthConfig(
clientId = requiredString(playConfig, "auth.google.clientId"),
clientSecret = requiredString(playConfig, "auth.google.clientSecret"),
redirectUrl = s"$amiableUrl${routes.Login.oauth2Callback.url}",
domains = List(domain),
antiForgeryChecker =
AntiForgeryChecker.borrowSettingsFromPlay(httpConfiguration)
)
})
.getOrElse(
GoogleAuthConfig.withNoDomainRestriction(
clientId = requiredString(playConfig, "auth.google.clientId"),
clientSecret = requiredString(playConfig, "auth.google.clientSecret"),
redirectUrl = s"$amiableUrl${routes.Login.oauth2Callback.url}",
antiForgeryChecker =
AntiForgeryChecker.borrowSettingsFromPlay(httpConfiguration)
)
)
}
val googleGroupChecker: GoogleGroupChecker = {
val serviceAccountCertPath =
requiredString(playConfig, "auth.google.serviceAccountCertPath")
val creds = ServiceAccountCredentials.fromStream(
new FileInputStream(serviceAccountCertPath)
)
new GoogleGroupChecker(
impersonatedUser = requiredString(playConfig, "auth.google.2faUser"),
serviceAccountCredentials = creds
)
}
private def requiredString(config: Configuration, key: String): String = {
config.getOptional[String](key).getOrElse {
throw new RuntimeException(s"Missing required config property $key")
}
}
}