From dd1c8484082c0d110066170f9e70de2ba3814391 Mon Sep 17 00:00:00 2001 From: Ilja Neumann Date: Wed, 5 Feb 2020 16:26:17 +0100 Subject: [PATCH] - Generate certs if none configured (#10) - Use devldap ldap-defaults --- pkg/crypto/gencert.go | 122 ++++++++++++++++++++++++++++++++++++++ pkg/server/http/server.go | 17 ++++++ pkg/service/v0/service.go | 28 +++++++++ 3 files changed, 167 insertions(+) create mode 100644 pkg/crypto/gencert.go diff --git a/pkg/crypto/gencert.go b/pkg/crypto/gencert.go new file mode 100644 index 000000000..0ce0e8a54 --- /dev/null +++ b/pkg/crypto/gencert.go @@ -0,0 +1,122 @@ +package crypto + +import ( + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "github.com/owncloud/ocis-pkg/log" + "math/big" + "net" + "os" + "time" +) + +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(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("server.crt") + if err != nil { + l.Fatal().Err(err).Msg("Failed to open server.crt for writing") + } + 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("server.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + l.Fatal().Err(err).Msg("Failed to open server.key for writing") + } + 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().Msg("Written server.key") + return nil +} diff --git a/pkg/server/http/server.go b/pkg/server/http/server.go index 375c73e3e..21b06b71e 100644 --- a/pkg/server/http/server.go +++ b/pkg/server/http/server.go @@ -2,6 +2,7 @@ package http import ( "crypto/tls" + "github.com/owncloud/ocis-konnectd/pkg/crypto" svc "github.com/owncloud/ocis-konnectd/pkg/service/v0" "github.com/owncloud/ocis-konnectd/pkg/version" "github.com/owncloud/ocis-pkg/middleware" @@ -13,6 +14,22 @@ import ( func Server(opts ...Option) (http.Service, error) { options := newOptions(opts...) + if options.Config.HTTP.TLSCert == "" || options.Config.HTTP.TLSKey == "" { + _, certErr := os.Stat("server.crt") + _, keyErr := os.Stat("server.key") + + if !os.IsExist(certErr) || !os.IsExist(keyErr) { + options.Logger.Info().Msgf("Generating certs") + if err := crypto.GenCert(options.Logger); err != nil { + options.Logger.Fatal().Err(err).Msg("Could not setup TLS") + os.Exit(1) + } + } + + options.Config.HTTP.TLSCert = "server.crt" + options.Config.HTTP.TLSKey = "server.key" + } + cer, err := tls.LoadX509KeyPair(options.Config.HTTP.TLSCert, options.Config.HTTP.TLSKey) if err != nil { options.Logger.Fatal().Err(err).Msg("Could not setup TLS") diff --git a/pkg/service/v0/service.go b/pkg/service/v0/service.go index e26bbefbd..0a1ac92b8 100644 --- a/pkg/service/v0/service.go +++ b/pkg/service/v0/service.go @@ -6,7 +6,9 @@ import ( "github.com/gorilla/mux" "github.com/owncloud/ocis-konnectd/pkg/config" "github.com/owncloud/ocis-konnectd/pkg/log" + "github.com/rs/zerolog" "net/http" + "os" "stash.kopano.io/kc/konnect/bootstrap" kcconfig "stash.kopano.io/kc/konnect/config" "stash.kopano.io/kc/konnect/server" @@ -29,6 +31,7 @@ func NewService(opts ...Option) Service { ctx := context.Background() options := newOptions(opts...) logger := options.Logger.Logger + initKonnectInternalEnvVars(logger) bs, err := bootstrap.Boot(ctx, &options.Config.Konnectd, &kcconfig.Config{ Logger: log.Wrap(logger), @@ -47,6 +50,31 @@ func NewService(opts ...Option) Service { } } +// Init vars which are currently not accessible via konnectd api +func initKonnectInternalEnvVars(l zerolog.Logger) { + var defaults = map[string]string{ + "LDAP_URI": "ldap://localhost:9125", + "LDAP_BINDDN": "cn=admin,dc=example,dc=org", + "LDAP_BINDPW": "admin", + "LDAP_BASEDN": "ou=users,dc=example,dc=org", + "LDAP_SCOPE": "sub", + "LDAP_LOGIN_ATTRIBUTE": "uid", + "LDAP_EMAIL_ATTRIBUTE": "mail", + "LDAP_NAME_ATTRIBUTE": "cn", + "LDAP_UUID_ATTRIBUTE": "customuid", + "LDAP_UUID_ATTRIBUTE_TYPE": "text", + "LDAP_FILTER": "(objectClass=person)", + } + + for k, v := range defaults { + if _, exists := os.LookupEnv(k); !exists { + if err := os.Setenv(k, v); err != nil { + l.Fatal().Err(err).Msgf("Could not set env var %s=%s", k, v) + } + } + } +} + // newMux initializes the internal konnectd gorilla mux and mounts it in to a ocis chi-router func newMux(ctx context.Context, r []server.WithRoutes, h http.Handler, middleware []func(http.Handler) http.Handler) http.Handler { gm := mux.NewRouter()