Add ability to provision OIDC providers from ENV

PROVISION_OIDC_PROVIDER="name provider-url"
This commit is contained in:
Denis Arh
2019-07-17 13:41:24 +02:00
parent f75861c917
commit 0e1575f90f
7 changed files with 155 additions and 62 deletions
+50
View File
@@ -2,12 +2,16 @@ package system
import (
"context"
"errors"
"strings"
"github.com/spf13/cobra"
"github.com/titpetric/factory"
"go.uber.org/zap"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/pkg/cli/options"
"github.com/cortezaproject/corteza-server/system/internal/auth/external"
"github.com/cortezaproject/corteza-server/system/internal/repository"
"github.com/cortezaproject/corteza-server/system/internal/service"
"github.com/cortezaproject/corteza-server/system/types"
@@ -77,3 +81,49 @@ func makeDefaultApplications(ctx context.Context, cmd *cobra.Command, c *cli.Con
func discoverSettings(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
return service.DefaultSettings.With(ctx).AutoDiscovery()
}
func oidcAutoDiscovery(ctx context.Context, cmd *cobra.Command, c *cli.Config) (err error) {
var provider = strings.TrimSpace(options.EnvString("", "PROVISION_OIDC_PROVIDER", ""))
c.Log.Debug("OIDC auto discovery provision", zap.String("providers", provider))
if len(provider) == 0 {
return
}
var (
providers = strings.Split(provider, " ")
plen = len(providers)
name, purl string
eap *service.AuthSettingsExternalAuthProvider
)
if plen%2 == 1 {
return errors.New("expecting even number of providers")
}
for p := 0; p < plen; p = p + 2 {
name, purl = providers[p], providers[p+1]
eap, err = external.RegisterOidcProvider(ctx, name, purl, false, true, true)
if err != nil {
c.Log.Error(
"could not register oidc provider",
zap.String("url", purl),
zap.String("name", name),
zap.Error(err))
return
} else if eap == nil {
c.Log.Info("provider already exists",
zap.String("name", name))
} else {
c.Log.Info("provider successfuly registered",
zap.String("url", purl),
zap.String("key", eap.Key),
zap.String("name", name))
}
}
return
}
+7 -55
View File
@@ -2,16 +2,13 @@ package commands
import (
"context"
"net/url"
"regexp"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/titpetric/factory"
"github.com/cortezaproject/corteza-server/internal/auth"
"github.com/cortezaproject/corteza-server/internal/settings"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/system/internal/auth/external"
"github.com/cortezaproject/corteza-server/system/internal/repository"
@@ -38,45 +35,17 @@ func Auth(ctx context.Context, c *cli.Config) *cobra.Command {
Run: func(cmd *cobra.Command, args []string) {
c.InitServices(ctx, c)
var (
name, providerUrl = args[0], args[1]
es = service.DefaultAuthSettings
_, err := external.RegisterOidcProvider(
ctx,
args[0],
args[1],
true,
!skipValidationOnAutoDiscoveredProvider,
enableDiscoveredProvider,
)
if !skipValidationOnAutoDiscoveredProvider {
// Do basic validation of external auth settings
// will fail if secret or url are not set
cli.HandleError(es.StaticValidateExternal())
// Do full rediredct-URL check
cli.HandleError(es.ValidateExternalRedirectURL())
}
p, err := parseExternalProviderUrl(providerUrl)
cli.HandleError(err)
eap, err := external.RegisterNewOpenIdClient(ctx, es, name, p.String())
cli.HandleError(err)
vv, err := eap.MakeValueSet("openid-connect." + name)
cli.HandleError(err)
if enableDiscoveredProvider {
cli.HandleError(vv.Walk(func(value *settings.Value) error {
if strings.HasSuffix(value.Name, ".enabled") {
return value.SetValue(true)
}
return nil
}))
v := &settings.Value{Name: "auth.external.enabled"}
cli.HandleError(v.SetValue(true))
vv = append(vv, v)
}
cli.HandleError(service.DefaultIntSettings.BulkSet(vv))
if enableDiscoveredProvider {
cmd.Println("OIDC provider successfully added and enabled.")
} else {
@@ -171,20 +140,3 @@ func Auth(ctx context.Context, c *cli.Config) *cobra.Command {
return cmd
}
func parseExternalProviderUrl(in string) (p *url.URL, err error) {
if i := strings.Index(in, "://"); i == -1 {
// Add schema if missing
in = "https://" + in
}
if p, err = url.Parse(in); err != nil {
// Try to parse it
return
} else if i := strings.Index(p.Path, external.WellKnown); i > -1 {
// Cut off well-known-path
p.Path = p.Path[:i]
}
return
}
+4
View File
@@ -7,6 +7,10 @@ import (
"github.com/cortezaproject/corteza-server/system/internal/service"
)
const (
OIDC_PROVIDER_PREFIX = "openid-connect."
)
func Init() {
setupGoth(service.DefaultAuthSettings)
}
@@ -1,11 +1,9 @@
package commands
package external
import (
"net/url"
"reflect"
"testing"
"github.com/cortezaproject/corteza-server/system/internal/auth/external"
)
func Test_parseExternalProviderUrl(t *testing.T) {
@@ -48,7 +46,7 @@ func Test_parseExternalProviderUrl(t *testing.T) {
},
{
"add schema and remove well-known",
args{"cortezaproject.org/some-subdir/" + external.WellKnown},
args{"cortezaproject.org/some-subdir/" + WellKnown},
mustParseURL("https://cortezaproject.org/some-subdir/"),
false,
},
+1 -1
View File
@@ -77,7 +77,7 @@ func setupGothProviders(as service.AuthSettings) {
continue
}
if strings.Index(name, "openid-connect.") == 0 {
if strings.Index(name, OIDC_PROVIDER_PREFIX) == 0 {
if pc.IssuerUrl == "" {
log.Error("failed to discover OIDC provider, URL empty")
continue
+90 -2
View File
@@ -3,19 +3,22 @@ package external
import (
"context"
"fmt"
"net/url"
"strings"
"github.com/crusttech/go-oidc"
"github.com/cortezaproject/corteza-server/internal/settings"
"github.com/cortezaproject/corteza-server/system/internal/service"
)
// @todo remove dependency on github.com/crusttech/go-oidc (and github.com/coreos/go-oidc)
// and move client registration to corteza codebase
func RegisterNewOpenIdClient(ctx context.Context, eas service.AuthSettings, name, url string) (eap *service.AuthSettingsExternalAuthProvider, err error) {
func DiscoverOidcProvider(ctx context.Context, eas service.AuthSettings, name, url string) (eap *service.AuthSettingsExternalAuthProvider, err error) {
var (
provider *oidc.Provider
client *oidc.Client
redirectUrl = fmt.Sprintf(eas.ExternalRedirectUrl, "openid-connect."+name)
redirectUrl = fmt.Sprintf(eas.ExternalRedirectUrl, OIDC_PROVIDER_PREFIX+name)
)
if provider, err = oidc.NewProvider(ctx, url); err != nil {
@@ -41,3 +44,88 @@ func RegisterNewOpenIdClient(ctx context.Context, eas service.AuthSettings, name
return
}
func RegisterOidcProvider(ctx context.Context, name, providerUrl string, force, validate, enable bool) (eap *service.AuthSettingsExternalAuthProvider, err error) {
var (
as = service.DefaultAuthSettings
)
if !force {
if _, exists := as.ExternalProviders[OIDC_PROVIDER_PREFIX+name]; exists {
return
}
}
if validate {
// Do basic validation of external auth settings
// will fail if secret or url are not set
if err = as.StaticValidateExternal(); err != nil {
return
}
// Do full rediredct-URL check
if err = as.ValidateExternalRedirectURL(); err != nil {
return
}
}
p, err := parseExternalProviderUrl(providerUrl)
if err != nil {
return
}
eap, err = DiscoverOidcProvider(ctx, as, name, p.String())
if err != nil {
return
}
vv, err := eap.MakeValueSet(OIDC_PROVIDER_PREFIX + name)
if err != nil {
return
}
if enable {
err = vv.Walk(func(value *settings.Value) error {
if strings.HasSuffix(value.Name, ".enabled") {
return value.SetValue(true)
}
return nil
})
if err != nil {
return
}
v := &settings.Value{Name: "auth.external.enabled"}
err = v.SetValue(true)
if err != nil {
return
}
vv = append(vv, v)
}
err = service.DefaultIntSettings.BulkSet(vv)
if err != nil {
return
}
return
}
func parseExternalProviderUrl(in string) (p *url.URL, err error) {
if i := strings.Index(in, "://"); i == -1 {
// Add schema if missing
in = "https://" + in
}
if p, err = url.Parse(in); err != nil {
// Try to parse it
return
} else if i := strings.Index(p.Path, WellKnown); i > -1 {
// Cut off well-known-path
p.Path = p.Path[:i]
}
return
}
+1
View File
@@ -56,6 +56,7 @@ func Configure() *cli.Config {
cli.HandleError(accessControlSetup(ctx, cmd, c))
cli.HandleError(makeDefaultApplications(ctx, cmd, c))
cli.HandleError(discoverSettings(ctx, cmd, c))
cli.HandleError(oidcAutoDiscovery(ctx, cmd, c))
// Run auto configuration
commands.SettingsAutoConfigure(cmd)