in sources/src/main/java/com/google/solutions/jitaccess/web/ApplicationConfiguration.java [170:287]
public ApplicationConfiguration(@NotNull Map<String, String> settingsData) {
super(settingsData);
//
// Read required settings.
//
// NB. CustomerIDs, primary domains, organization IDs can be translated
// into each other by using the organization.search API, but this
// API requires the `resourcemanager.organizations.get` permission.
//
// Service accounts don't have this permission by default, and granting
// the corresponding `Organization Viewer` role requires changing the
// organization's IAM policy, which is a lot to ask for.
//
// Therefore, we require the configuration to contain all 3 pieces of
// information, even if it's somewhat redundant.
//
this.customerId = readStringSetting(
"CUSTOMER_ID",
"RESOURCE_CUSTOMER_ID") // Name used in 1.x
.map(CustomerId::new)
.orElseThrow(() -> new IllegalStateException(
"The environment variable 'CUSTOMER_ID' must contain the customer ID " +
"of a Cloud Identity or Workspace account, see" +
"https://support.google.com/a/answer/10070793"));
this.primaryDomain = readStringSetting("PRIMARY_DOMAIN")
.map(d -> new Domain(d, Domain.Type.PRIMARY))
.orElseThrow(() -> new IllegalStateException(
"The environment variable 'PRIMARY_DOMAIN' must contain the primary domain name " +
"of a Cloud Identity/Workspace account, see https://support.google.com/a/answer/182080"));
this.organizationId = readStringSetting("ORGANIZATION_ID")
.map(OrganizationId::new)
.orElseThrow(() -> new IllegalStateException(
"The environment variable 'ORGANIZATION_ID' must contain the organization ID of " +
"a Google Cloud organization, see " +
"https://cloud.google.com/resource-manager/docs/creating-managing-organization"));
//
// Read optional settings.
//
this.groupsDomain = readStringSetting("GROUPS_DOMAIN")
.map(d -> new Domain(d, d.equalsIgnoreCase(this.primaryDomain.name())
? Domain.Type.PRIMARY
: Domain.Type.SECONDARY))
.orElse(this.primaryDomain);
this.proposalTimeout = readDurationSetting(
ChronoUnit.MINUTES,
"APPROVAL_TIMEOUT",
"ACTIVATION_REQUEST_TIMEOUT") // Name used in 1.x
.orElse(Duration.ofHours(1));
this.environments = readStringSetting("ENVIRONMENTS").stream()
.flatMap(s -> Arrays.stream(s.split(",")))
.map(String::trim)
.filter(s -> !s.isBlank())
.toList();
this.environmentCacheTimeout = readDurationSetting(
ChronoUnit.SECONDS,
"RESOURCE_CACHE_TIMEOUT")
.orElse(Duration.ofMinutes(5));
//
// SMTP settings.
//
this.smtpAddressMapping = readStringSetting("SMTP_ADDRESS_MAPPING");
this.smtpHost = readStringSetting("SMTP_HOST")
.orElse("smtp.gmail.com");
this.smtpPort = readSetting(Integer::parseInt, "SMTP_PORT")
.orElse(587);
this.smtpEnableStartTls = readSetting(Boolean::parseBoolean, "SMTP_ENABLE_STARTTLS")
.orElse(true);
this.smtpSenderName = readStringSetting("SMTP_SENDER_NAME")
.orElse("JIT Groups");
this.smtpSenderAddress = readStringSetting("SMTP_SENDER_ADDRESS");
this.smtpUsername = readStringSetting("SMTP_USERNAME");
this.smtpPassword = readStringSetting("SMTP_PASSWORD");
this.smtpSecret = readStringSetting("SMTP_SECRET");
this.smtpExtraOptions = readStringSetting("SMTP_OPTIONS");
//
// Notification settings.
//
this.notificationTimeZone = readSetting(ZoneId::of, "NOTIFICATION_TIMEZONE")
.orElse(ZoneOffset.UTC);
//
// Backend service id (Cloud Run only).
//
this.backendServiceId = readStringSetting("IAP_BACKEND_SERVICE_ID");
this.verifyIapAudience = readSetting(Boolean::parseBoolean, "IAP_VERIFY_AUDIENCE")
.orElse(true);
//
// Backend settings.
//
this.backendConnectTimeout = readDurationSetting(ChronoUnit.SECONDS, "BACKEND_CONNECT_TIMEOUT")
.orElse(Duration.ofSeconds(5));
this.backendReadTimeout = readDurationSetting(ChronoUnit.SECONDS, "BACKEND_READ_TIMEOUT")
.orElse(Duration.ofSeconds(20));
this.backendWriteTimeout = readDurationSetting(ChronoUnit.SECONDS, "BACKEND_WRITE_TIMEOUT")
.orElse(Duration.ofSeconds(5));
//
// Legacy settings.
//
this.legacyCatalog = readStringSetting("RESOURCE_CATALOG").orElse("AssetInventory");
this.legacyScope = readStringSetting("RESOURCE_SCOPE");
this.legacyActivationTimeout = readDurationSetting(
ChronoUnit.MINUTES,
"ACTIVATION_TIMEOUT",
"ELEVATION_DURATION")
.orElse(Duration.ofHours(2));
this.legacyJustificationPattern = readStringSetting("JUSTIFICATION_PATTERN")
.orElse(".*");
this.legacyJustificationHint = readStringSetting("JUSTIFICATION_HINT")
.orElse("Bug or case number");
this.legacyProjectsQuery = readStringSetting("AVAILABLE_PROJECTS_QUERY")
.orElse("state:ACTIVE");
}