Configure Single-Sign-On for the web server
This commit is contained in:
committed by
Arthur Barr
parent
77eb7381e7
commit
149915d587
@@ -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()
|
||||
}()
|
||||
|
||||
@@ -21,9 +21,12 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"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 {
|
||||
@@ -75,6 +78,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 {
|
||||
|
||||
@@ -134,6 +134,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)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<server>
|
||||
<featureManager>
|
||||
<feature>openidConnectClient-1.0</feature>
|
||||
<feature>ssl-1.0</feature>
|
||||
</featureManager>
|
||||
<enterpriseApplication id="com.ibm.mq.console">
|
||||
<application-bnd>
|
||||
<security-role name="MQWebAdmin">
|
||||
<group name="MQWebUI" realm="defaultRealm"/>
|
||||
{{- range $index, $element := .AdminUser}}
|
||||
<user name="admin{{$index}}" access-id="{{.}}"/>
|
||||
{{- end}}
|
||||
</security-role>
|
||||
</application-bnd>
|
||||
</enterpriseApplication>
|
||||
<enterpriseApplication id="com.ibm.mq.rest">
|
||||
<application-bnd>
|
||||
<security-role name="MQWebAdmin">
|
||||
<group name="MQWebUI" realm="defaultRealm"/>
|
||||
</security-role>
|
||||
<security-role name="MQWebUser">
|
||||
<group name="MQWebMessaging" realm="defaultRealm"/>
|
||||
</security-role>
|
||||
</application-bnd>
|
||||
</enterpriseApplication>
|
||||
<openidConnectClient id="mqclient"
|
||||
clientId="${env.MQ_OIDC_CLIENT_ID}"
|
||||
clientSecret="${env.MQ_OIDC_CLIENT_SECRET}"
|
||||
authorizationEndpointUrl="${env.MQ_OIDC_AUTHORIZATION_ENDPOINT}"
|
||||
tokenEndpointUrl="${env.MQ_OIDC_TOKEN_ENDPOINT}"
|
||||
scope="openid profile email"
|
||||
inboundPropagation="supported"
|
||||
jwkEndpointUrl="${env.MQ_OIDC_JWK_ENDPOINT}"
|
||||
signatureAlgorithm="RS256"
|
||||
issuerIdentifier="${env.MQ_OIDC_ISSUER_IDENTIFIER}">
|
||||
</openidConnectClient>
|
||||
<variable name="httpHost" value="*"/>
|
||||
<keyStore id="MQWebKeyStore" location="/run/tls/key.jks" type="JKS" password="password"/>
|
||||
<keyStore id="MQWebTrustStore" location="/run/tls/trust.jks" type="JKS" password="password"/>
|
||||
<ssl id="thisSSLConfig" clientAuthenticationSupported="true" keyStoreRef="MQWebKeyStore" trustStoreRef="MQWebTrustStore" sslProtocol="TLSv1.2" serverKeyAlias="default"/>
|
||||
<sslDefault sslRef="thisSSLConfig"/>
|
||||
<httpDispatcher enableWelcomePage="false" appOrContextRootMissingMessage='<script>document.location.href="/ibmmq/console";</script>' />
|
||||
</server>
|
||||
Reference in New Issue
Block a user