From 4c1d124484849113af2faa5983b943d5917238d1 Mon Sep 17 00:00:00 2001 From: Stephen Marshall Date: Wed, 3 Oct 2018 13:19:09 +0100 Subject: [PATCH] Configure Single-Sign-On for the web server --- cmd/runmqserver/post_init.go | 14 ++- cmd/runmqserver/webserver.go | 98 +++++++++++++++++++ internal/keystore/keystore.go | 18 ++++ .../servers/mqweb/mqwebuser.xml.tpl | 44 +++++++++ 4 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 web/installations/Installation1/servers/mqweb/mqwebuser.xml.tpl diff --git a/cmd/runmqserver/post_init.go b/cmd/runmqserver/post_init.go index 59d6157..e2bae03 100644 --- a/cmd/runmqserver/post_init.go +++ b/cmd/runmqserver/post_init.go @@ -20,18 +20,26 @@ import ( ) // postInit is run after /var/mqm is set up -// This version of postInit is only included as part of the MQ Advanced for Developers build func postInit(name string) error { disable := os.Getenv("MQ_DISABLE_WEB_CONSOLE") if disable != "true" && disable != "1" { + + // Configure Single-Sign-On for the web server (if enabled) + enableSSO := os.Getenv("MQ_ENABLE_SSO") + if enableSSO == "true" || enableSSO == "1" { + err := configureSSO() + if err != nil { + return err + } + } + // Configure the web server (if installed) err := configureWebServer() if err != nil { return err } // Start the web server, in the background (if installed) - // WARNING: No error handling or health checking available for the web server, - // which is why it's limited to use with MQ Advanced for Developers only + // WARNING: No error handling or health checking available for the web server go func() { startWebServer() }() diff --git a/cmd/runmqserver/webserver.go b/cmd/runmqserver/webserver.go index c42849a..fab67fb 100644 --- a/cmd/runmqserver/webserver.go +++ b/cmd/runmqserver/webserver.go @@ -23,9 +23,12 @@ import ( "os/user" "path/filepath" "strconv" + "strings" "syscall" "github.com/ibm-messaging/mq-container/internal/command" + "github.com/ibm-messaging/mq-container/internal/keystore" + "github.com/ibm-messaging/mq-container/internal/mqtemplate" ) func startWebServer() error { @@ -88,6 +91,101 @@ func CopyFile(src, dest string) error { return err } +func configureSSO() error { + + // Ensure all required environment variables are set for SSO + requiredEnvVars := []string{ + "MQ_WEB_ADMIN_USERS", + "MQ_OIDC_CLIENT_ID", + "MQ_OIDC_CLIENT_SECRET", + "MQ_OIDC_AUTHORIZATION_ENDPOINT", + "MQ_OIDC_TOKEN_ENDPOINT", + "MQ_OIDC_JWK_ENDPOINT", + "MQ_OIDC_ISSUER_IDENTIFIER", + "MQ_OIDC_CERTIFICATE", + } + for _, envVar := range requiredEnvVars { + if len(os.Getenv(envVar)) == 0 { + return fmt.Errorf("%v must be set when MQ_ENABLE_SSO=true", envVar) + } + } + + // Check mqweb directory exists + const mqwebDir string = "/etc/mqm/web/installations/Installation1/servers/mqweb" + _, err := os.Stat(mqwebDir) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + + // Process SSO template for generating file mqwebuser.xml + adminUsers := strings.Split(os.Getenv("MQ_WEB_ADMIN_USERS"), ",") + err = mqtemplate.ProcessTemplateFile(mqwebDir+"/mqwebuser.xml.tpl", mqwebDir+"/mqwebuser.xml", map[string][]string{"AdminUser": adminUsers}, log) + if err != nil { + return err + } + + // Configure SSO TLS + return configureSSO_TLS() +} + +func configureSSO_TLS() error { + + // Create tls directory + dir := "/run/tls" + _, err := os.Stat(dir) + if err != nil { + if os.IsNotExist(err) { + err = os.MkdirAll(dir, 0770) + if err != nil { + return err + } + mqmUID, mqmGID, err := command.LookupMQM() + if err != nil { + log.Error(err) + return err + } + err = os.Chown(dir, mqmUID, mqmGID) + if err != nil { + log.Error(err) + return err + } + } else { + return err + } + } + + // Setup key store & trust store + ks := keystore.NewJKSKeyStore(filepath.Join(dir, "key.jks"), "password") + ts := keystore.NewJKSKeyStore(filepath.Join(dir, "trust.jks"), "password") + + log.Debug("Creating key store") + err = ks.Create(log) + if err != nil { + return err + } + log.Debug("Creating trust store") + err = ts.Create(log) + if err != nil { + return err + } + log.Debug("Creating self-signed certificate in key store") + err = ks.CreateSelfSignedCertificate("default", "CN=IBMMQWeb,O=IBM,OU=Platform,C=GB") + if err != nil { + return err + } + log.Debug("Importing self-signed certificate into trust store") + err = ts.Import(ks.Filename, ks.Password) + if err != nil { + return err + } + log.Debug("Adding OIDC CA certificate to trust store") + err = ts.Add(os.Getenv("MQ_OIDC_CERTIFICATE"), "OIDC") + return err +} + func configureWebServer() error { _, err := os.Stat("/opt/mqm/bin/strmqweb") if err != nil { diff --git a/internal/keystore/keystore.go b/internal/keystore/keystore.go index d8d97ea..44bf596 100644 --- a/internal/keystore/keystore.go +++ b/internal/keystore/keystore.go @@ -150,6 +150,24 @@ func (ks *KeyStore) Import(inputFile, password string) error { return nil } +// CreateSelfSignedCertificate creates a self-signed certificate in the keystore +func (ks *KeyStore) CreateSelfSignedCertificate(label, dn string) error { + out, _, err := command.Run(ks.command, "-cert", "-create", "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn) + if err != nil { + return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out) + } + return nil +} + +// Add adds a CA certificate to the keystore +func (ks *KeyStore) Add(inputFile, label string) error { + out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label) + if err != nil { + return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out) + } + return nil +} + // GetCertificateLabels returns the labels of all certificates in the key store func (ks *KeyStore) GetCertificateLabels() ([]string, error) { out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password) diff --git a/web/installations/Installation1/servers/mqweb/mqwebuser.xml.tpl b/web/installations/Installation1/servers/mqweb/mqwebuser.xml.tpl new file mode 100644 index 0000000..65a4b60 --- /dev/null +++ b/web/installations/Installation1/servers/mqweb/mqwebuser.xml.tpl @@ -0,0 +1,44 @@ + + + + openidConnectClient-1.0 + ssl-1.0 + + + + + + {{- range $index, $element := .AdminUser}} + + {{- end}} + + + + + + + + + + + + + + + + + + + + + +