From cc10b141341632374f53a175c13b1a7b835e0f2c Mon Sep 17 00:00:00 2001 From: Ilja Neumann Date: Wed, 18 Mar 2020 20:18:52 +0100 Subject: [PATCH 1/2] Change default settings to be able to run ocis server without any configuration - Konnectd uses no TLS as it is behind the proxy - Glauth generates dev-certificates for ldap on startup if none are provided, - Glauth can launch unencrypted (9125) and encrypted (9126) port in parallel --- pkg/command/server.go | 28 ++++++++++ pkg/crypto/gencert.go | 123 +++++++++++++++++++++++++++++++++++++++++ pkg/flagset/flagset.go | 6 +- 3 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 pkg/crypto/gencert.go diff --git a/pkg/command/server.go b/pkg/command/server.go index 221e5da..1e066e0 100644 --- a/pkg/command/server.go +++ b/pkg/command/server.go @@ -2,6 +2,7 @@ package command import ( "context" + "github.com/owncloud/ocis-glauth/pkg/crypto" "os" "os/signal" "strings" @@ -245,6 +246,14 @@ func Server(cfg *config.Config) *cli.Command { }, }, } + + if cfg.LDAPS.Enabled { + // GenCert has side effects as it writes 2 files to the binary running location + if err := crypto.GenCert("ldap.crt", "ldap.key", logger); err != nil { + logger.Fatal().Err(err).Msgf("Could not generate test-certificate") + } + } + server, err := glauth.NewServer( glauth.Logger(log), glauth.Config(&cfg), @@ -267,6 +276,7 @@ func Server(cfg *config.Config) *cli.Command { case err <- server.ListenAndServe(): return <-err } + }, func(_ error) { logger.Info(). Str("transport", "ldap"). @@ -276,6 +286,24 @@ func Server(cfg *config.Config) *cli.Command { cancel() }) + gr.Add(func() error { + err := make(chan error) + select { + case <-ctx.Done(): + return nil + case err <- server.ListenAndServeTLS(): + return <-err + } + + }, func(_ error) { + logger.Info(). + Str("transport", "ldaps"). + Msg("Shutting down server") + + server.Shutdown() + cancel() + }) + } { diff --git a/pkg/crypto/gencert.go b/pkg/crypto/gencert.go new file mode 100644 index 0000000..cb4be95 --- /dev/null +++ b/pkg/crypto/gencert.go @@ -0,0 +1,123 @@ +package crypto + +import ( + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "net" + "os" + "time" + + "github.com/owncloud/ocis-pkg/v2/log" +) + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func pemBlockForKey(priv interface{}, l log.Logger) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + l.Fatal().Err(err).Msg("Unable to marshal ECDSA private key") + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} + +// GenCert generates TLS-Certificates +func GenCert(certName string, keyName string, l log.Logger) error { + var priv interface{} + var err error + + priv, err = rsa.GenerateKey(rand.Reader, 2048) + + if err != nil { + l.Fatal().Err(err).Msg("Failed to generate private key") + } + + notBefore := time.Now() + notAfter := notBefore.Add(24 * time.Hour * 365) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + l.Fatal().Err(err).Msg("Failed to generate serial number") + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Acme Corp"}, + CommonName: "OCIS", + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + hosts := []string{"127.0.0.1", "localhost"} + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + //template.IsCA = true + //template.KeyUsage |= x509.KeyUsageCertSign + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) + if err != nil { + l.Fatal().Err(err).Msg("Failed to create certificate") + } + + certOut, err := os.Create(certName) + if err != nil { + l.Fatal().Err(err).Msgf("Failed to open %v for writing", certName) + } + err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + if err != nil { + l.Fatal().Err(err).Msg("Failed to encode certificate") + } + err = certOut.Close() + if err != nil { + l.Fatal().Err(err).Msg("Failed to write cert") + } + l.Info().Msg("Written server.crt") + + keyOut, err := os.OpenFile(keyName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + l.Fatal().Err(err).Msgf("Failed to open %v for writing", keyName) + } + err = pem.Encode(keyOut, pemBlockForKey(priv, l)) + if err != nil { + l.Fatal().Err(err).Msg("Failed to encode key") + } + err = keyOut.Close() + if err != nil { + l.Fatal().Err(err).Msg("Failed to write key") + } + l.Info().Msgf("Written %v", keyName) + return nil +} diff --git a/pkg/flagset/flagset.go b/pkg/flagset/flagset.go index 6104698..acc52ac 100644 --- a/pkg/flagset/flagset.go +++ b/pkg/flagset/flagset.go @@ -140,21 +140,21 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag { }, &cli.BoolFlag{ Name: "ldaps-enabled", - Value: false, + Value: true, Usage: "Enable ldap server", EnvVars: []string{"GLAUTH_LDAPS_ENABLED"}, Destination: &cfg.Ldaps.Enabled, }, &cli.StringFlag{ Name: "ldaps-cert", - Value: "certs/server.crt", + Value: "./ldap.crt", Usage: "path to ldaps certificate in PEM format", EnvVars: []string{"GLAUTH_LDAPS_CERT"}, Destination: &cfg.Ldaps.Cert, }, &cli.StringFlag{ Name: "ldaps-key", - Value: "certs/server.key", + Value: "./ldap.key", Usage: "path to ldaps key in PEM format", EnvVars: []string{"GLAUTH_LDAPS_KEY"}, Destination: &cfg.Ldaps.Key, From 7962c3a867fc15280534e31b30c4cab1fb285b89 Mon Sep 17 00:00:00 2001 From: Ilja Neumann Date: Wed, 18 Mar 2020 21:05:53 +0100 Subject: [PATCH 2/2] changelog --- changelog/unreleased/default-settings.md | 5 +++++ changelog/unreleased/generate-dev-certs.md | 5 +++++ changelog/unreleased/tls-endpoint.md | 6 ++++++ 3 files changed, 16 insertions(+) create mode 100644 changelog/unreleased/default-settings.md create mode 100644 changelog/unreleased/generate-dev-certs.md create mode 100644 changelog/unreleased/tls-endpoint.md diff --git a/changelog/unreleased/default-settings.md b/changelog/unreleased/default-settings.md new file mode 100644 index 0000000..e207a44 --- /dev/null +++ b/changelog/unreleased/default-settings.md @@ -0,0 +1,5 @@ +Enhancement: Improve default settings + +This helps achieve zero-config in single-binary. + +https://github.com/owncloud/ocis-glauth/pull/12 diff --git a/changelog/unreleased/generate-dev-certs.md b/changelog/unreleased/generate-dev-certs.md new file mode 100644 index 0000000..407d9f1 --- /dev/null +++ b/changelog/unreleased/generate-dev-certs.md @@ -0,0 +1,5 @@ +Enhancement: Generate temporary ldap certificates if LDAPS is enabled + +This change helps to achieve zero-configuration in single-binary mode. + +https://github.com/owncloud/ocis-glauth/pull/12 diff --git a/changelog/unreleased/tls-endpoint.md b/changelog/unreleased/tls-endpoint.md new file mode 100644 index 0000000..dac7d1a --- /dev/null +++ b/changelog/unreleased/tls-endpoint.md @@ -0,0 +1,6 @@ +Enhancement: Provide additional tls-endpoint + +ocis-glauth is now able to concurrently serve a encrypted and an unencrypted ldap-port. Please note that only +SSL (no StarTLS) is supported at the moment. + +https://github.com/owncloud/ocis-glauth/pull/12