diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 7f86a45b5..61d98079f 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -271,6 +271,7 @@ jobs: no no no + no $(pwd)/.dredd admin admin@localhost @@ -352,6 +353,7 @@ jobs: no no no + no $(pwd)/.dredd admin admin@localhost @@ -433,6 +435,7 @@ jobs: no no no + no $(pwd)/.dredd admin admin@localhost @@ -513,6 +516,7 @@ jobs: no no no + no $(pwd)/.dredd admin admin@localhost diff --git a/cli/setup/setup.go b/cli/setup/setup.go index da9790a8b..5eaddc698 100644 --- a/cli/setup/setup.go +++ b/cli/setup/setup.go @@ -49,7 +49,7 @@ func InteractiveSetup(conf *util.ConfigType) { askValue("Playbook path", defaultPlaybookPath, &conf.TmpPath) conf.TmpPath = filepath.Clean(conf.TmpPath) - askValue("Public URL (optional, example: https://example.com/semaphore)", "", &conf.WebHost) + askValue("Public URL (required for OIDC authentication, example: https://example.com/semaphore)", "", &conf.WebHost) askConfirmation("Enable email alerts?", false, &conf.EmailAlert) if conf.EmailAlert { @@ -72,7 +72,7 @@ func InteractiveSetup(conf *util.ConfigType) { askConfirmation("Enable Rocket.Chat alerts?", false, &conf.RocketChatAlert) if conf.RocketChatAlert { askValue("Rocket.Chat Webhook URL", "", &conf.RocketChatUrl) - } + } askConfirmation("Enable Microsoft Team Channel alerts?", false, &conf.MicrosoftTeamsAlert) if conf.MicrosoftTeamsAlert { @@ -92,6 +92,7 @@ func InteractiveSetup(conf *util.ConfigType) { askValue("LDAP mapping for full name field", "cn", &conf.LdapMappings.CN) askValue("LDAP mapping for email field", "mail", &conf.LdapMappings.Mail) } + scanOidcProviders(conf) } func scanBoltDb(conf *util.ConfigType) { @@ -123,6 +124,51 @@ func scanPostgres(conf *util.ConfigType) { } } +func scanOidcProviders(conf *util.ConfigType) { + conf.OidcProviders = map[string]util.OidcProvider{} + for { + var addOidcProvider bool + askConfirmation("Add another OIDC provider?", false, &addOidcProvider) + if !addOidcProvider { + break + } + providerId := "" + for providerId == "" { + askValue("Provider configuration id (used in redirect url)", "", &providerId) + } + provider := util.OidcProvider{} + + askValue("Display Name", "", &provider.DisplayName) + askValue("Client id", "", &provider.ClientID) + askValue("Client secret", "", &provider.ClientSecret) + askValue("Autodiscovery url", "", &provider.AutoDiscovery) + askValue("Issuer url", "", &provider.Endpoint.IssuerURL) + askValue("Auth url", "", &provider.Endpoint.AuthURL) + askValue("Token url", "", &provider.Endpoint.TokenURL) + askValue("User info url", "", &provider.Endpoint.UserInfoURL) + + defaultRedirectUrl := conf.WebHost + "/api/auth/oidc/" + providerId + "/redirect/" + askValue("Redirect url", defaultRedirectUrl, &provider.RedirectURL) + + rawScopes := "" + askValue("Scopes (comma separated)", "openid,profile,email", &rawScopes) + for _, scope := range strings.Split(rawScopes, ",") { + scope := strings.TrimSpace(scope) + provider.Scopes = append(provider.Scopes, scope) + } + + askValue("Color", "", &provider.Color) + askValue("Icon", "", &provider.Icon) + + askValue("Username claim", "", &provider.UsernameClaim) + askValue("Name claim", "", &provider.NameClaim) + askValue("Email claim", "", &provider.EmailClaim) + askValue("Order", "", &provider.Order) + + conf.OidcProviders[providerId] = provider + } +} + func scanErrorChecker(n int, err error) { if err != nil && err.Error() != "unexpected newline" { log.Warn("An input error occurred: " + err.Error()) diff --git a/deployment/docker/server/server-wrapper b/deployment/docker/server/server-wrapper index 75a3f224a..0598ae814 100755 --- a/deployment/docker/server/server-wrapper +++ b/deployment/docker/server/server-wrapper @@ -164,6 +164,54 @@ ${SEMAPHORE_LDAP_MAPPING_EMAIL} EOF fi; + oidcProviderNum=0 + while : + do + oidcProviderNum=$((oidcProviderNum+1)) + providerIdVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_ID" + providerDisplayNameVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_DISPLAY_NAME" + providerClientIdVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_CLIENT_ID" + providerClientSecretVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_CLIENT_SECRET" + providerAutodiscoveryUrlVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_AUTODISCOVERY_URL" + providerIssuerUrlVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_ISSUER_URL" + providerAuthUrlVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_AUTH_URL" + providerTokenUrlVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_TOKEN_URL" + providerUserInfoUrlVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_USER_INFO_URL" + providerRedirectUrlVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_REDIRECT_URL" + providerScopesVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_SCOPES" + providerColorVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_COLOR" + providerIconVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_ICON" + providerUsernameClaimVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_USERNAME_CLAIM" + providerNameClaimVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_NAME_CLAIM" + providerEmailClaimVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_EMAIL_CLAIM" + providerOrderVar="SEMAPHORE_OIDC_PROVIDER_${oidcProviderNum}_ORDER" + + if [ -z "$(eval echo \$$providerIdVar)" ]; then + echo "no" >> "${SEMAPHORE_TMP_PATH}/config.stdin" + break + fi + + echo "yes" >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerIdVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerDisplayNameVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerClientIdVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerClientSecretVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerAutodiscoveryUrlVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerIssuerUrlVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerAuthUrlVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerTokenUrlVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerUserInfoUrlVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerRedirectUrlVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerScopesVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerColorVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerIconVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerUsernameClaimVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerNameClaimVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$providerEmailClaimVar >> "${SEMAPHORE_TMP_PATH}/config.stdin" + eval echo \$$oidcProviderNum >> "${SEMAPHORE_TMP_PATH}/config.stdin" + done + + cat << EOF >> "${SEMAPHORE_TMP_PATH}/config.stdin" ${SEMAPHORE_CONFIG_PATH} ${SEMAPHORE_ADMIN}