From 12c04a9198292f5ec14bc520fb2e292fab3b103e Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Sat, 3 May 2014 20:15:08 +0200 Subject: [PATCH] Cleaned up implementation of certificates handler and added bunch of config files options. --- server.conf.in | 9 ++- src/app/spreed-speakfreely-server/main.go | 30 ++------ src/app/spreed-speakfreely-server/users.go | 90 ++++++++++++++-------- 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/server.conf.in b/server.conf.in index 3c757b54..f5ad0862 100644 --- a/server.conf.in +++ b/server.conf.in @@ -130,10 +130,12 @@ enabled = false ; set then the server will act as a CA and sign incoming user registrations and ; return certificates to users as registration. ;certificate_certificate = usersca.crt -; The HTTP header name where to find if the TLS lient authentication was +; The HTTP header name where to find if the TLS client authentication was ; successfull. The value of this header is matched to ; certificate_verifiedHeaderValue and only if there is a match, the proxy -; handled TLS client authentication is accepted as success. +; handled TLS client authentication is accepted as success. Make sure to secure +; these headers with your front end proxy (always set them). Do not use these +; settings when not using a front end proxy. ;certificate_verifiedHeader = x-verified ;certificate_verifiedHeaderValue = SUCCESS ; The HTTP header name where to find the userid extracted by a proxy after @@ -145,6 +147,9 @@ enabled = false ; certificate_useridHeader value and the front end TLS proxy does inject the ; userid into that header. ;certificate_certificateHeader = x-certificate +; The valid duration of generated certificates created in certificate mode when +; allowRegistration is enabled. +;certificate_validForDays = 365 ; If enabled the server can create new userids. Set allowRegistration to true to ; enable userid creation/registration. Users are created according the settings ; of the currently configured mode (see above). diff --git a/src/app/spreed-speakfreely-server/main.go b/src/app/spreed-speakfreely-server/main.go index 8f32fb11..cadac032 100644 --- a/src/app/spreed-speakfreely-server/main.go +++ b/src/app/spreed-speakfreely-server/main.go @@ -24,8 +24,6 @@ package main import ( "app/spreed-speakfreely-server/sleepy" "bytes" - "crypto/tls" - "crypto/x509" "flag" "fmt" "github.com/gorilla/mux" @@ -358,6 +356,12 @@ func runner(runtime phoenix.Runtime) error { // Create router. router := mux.NewRouter() r := router.PathPrefix(basePath).Subrouter().StrictSlash(true) + + // Prepare listeners. + runtime.DefaultHTTPHandler(r) + runtime.DefaultHTTPSHandler(r) + + // Add handlers. r.HandleFunc("/", httputils.MakeGzipHandler(mainHandler)) r.Handle("/static/img/buddy/{flags}/{imageid}/{idx:.*}", http.StripPrefix(basePath, makeImageHandler(hub, time.Duration(24)*time.Hour))) r.Handle("/static/{path:.*}", http.StripPrefix(basePath, httputils.FileStaticServer(http.Dir(rootFolder)))) @@ -393,28 +397,6 @@ func runner(runtime phoenix.Runtime) error { } } - runtime.DefaultHTTPHandler(r) - runtime.DefaultHTTPSHandler(r) - - if tlsConfig, err := runtime.TLSConfig(); err == nil { - tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven - // Create cert pool. - pool := x509.NewCertPool() - if certificateFn, err := runtime.GetString("users", "certificate_certificate"); err == nil { - if certificate, err := loadX509Certificate(certificateFn); err == nil { - for _, derCert := range certificate.Certificate { - cert, err := x509.ParseCertificate(derCert) - if err != nil { - continue - } - pool.AddCert(cert) - } - } - log.Printf("Initialized TLS auth pool with %d certtificates.", len(pool.Subjects())) - } - tlsConfig.ClientCAs = pool - } - return runtime.Start() } diff --git a/src/app/spreed-speakfreely-server/users.go b/src/app/spreed-speakfreely-server/users.go index 0a27c0e5..f60b0bf7 100644 --- a/src/app/spreed-speakfreely-server/users.go +++ b/src/app/spreed-speakfreely-server/users.go @@ -26,6 +26,7 @@ import ( "crypto/hmac" "crypto/rand" "crypto/sha256" + "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/base64" @@ -253,17 +254,41 @@ type Users struct { func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users { + var users = &Users{ + hub: hub, + realm: realm, + } + var handler UsersHandler var err error + // Create handler based on mode. mode, _ := runtime.GetString("users", "mode") + if handler, err = users.createHandler(mode, runtime); err == nil { + users.handler = handler + // Register handler Get at the hub. + users.hub.useridRetriever = func(request *http.Request) (userid string, err error) { + userid, err = handler.Get(request) + if userid != "" { + log.Printf("Users handler get success: %s\n", userid) + } + return + } + log.Printf("Enabled users handler '%s'\n", mode) + } + + return users +} + +func (users *Users) createHandler(mode string, runtime phoenix.Runtime) (handler UsersHandler, err error) { + switch mode { case "sharedsecret": secret, _ := runtime.GetString("users", "sharedsecret_secret") if secret != "" { handler = &UsersSharedsecretHandler{secret: []byte(secret)} } else { - log.Println("Cannot enable sharedsecret users handler: No secret.") + err = errors.New("Cannot enable sharedsecret users handler: No secret.") } case "httpheader": headerName, _ := runtime.GetString("users", "httpheader_header") @@ -272,57 +297,58 @@ func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users { } handler = &UsersHTTPHeaderHandler{headerName: headerName} case "certificate": + var err2 error uh := &UsersCertificateHandler{} - // TODO(longsleep): Add validFor to configuration. - uh.validFor = 24 * time.Hour * 365 + validForDays, _ := runtime.GetInt("users", "certificate_validForDays") + if validForDays == 0 { + validForDays = 365 + } + uh.validFor = time.Duration(validForDays) * 24 * time.Hour keyFn, _ := runtime.GetString("users", "certificate_key") certificateFn, _ := runtime.GetString("users", "certificate_certificate") if keyFn != "" && certificateFn != "" { - if uh.privateKey, err = loadX509PrivateKey(keyFn); err == nil { + // Load private key from file and use it for signing, + if uh.privateKey, err2 = loadX509PrivateKey(keyFn); err2 == nil { log.Printf("Users certificate private key loaded from %s\n", keyFn) } else { - log.Printf("Failed to load certificat private key: %s\n", err) + log.Printf("Failed to load certificat private key: %s\n", err2) } } if certificateFn != "" { + // Load Certificate from file. if certificate, err := loadX509Certificate(certificateFn); err == nil { + // Parse first certificate in file. if certificates, err := x509.ParseCertificates(certificate.Certificate[0]); err == nil { + // Use first parsed certificate as CA. uh.certificate = certificates[0] log.Printf("Users certificate loaded from %s\n", certificateFn) handler = uh - } else { - log.Printf("Failed to parse users certificate: %s\n", err) + // Get TLS config if the server has one. + if tlsConfig, err2 := runtime.TLSConfig(); err2 == nil { + // Enable TLS client certificate authentication. + tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven + // Create cert pool. + pool := x509.NewCertPool() + // Add CA certificate to pool for TLS client authentication. + for _, derCert := range certificate.Certificate { + cert, err2 := x509.ParseCertificate(derCert) + if err2 != nil { + continue + } + pool.AddCert(cert) + } + // Add pool to config. + tlsConfig.ClientCAs = pool + log.Printf("Initialized TLS auth pool with %d certificates.", len(pool.Subjects())) + } } - } else { - log.Printf("Failed to load users certificate: %s\n", err) } } else { - log.Println("Cannot enable certificate users handler: No certificate.") + err = errors.New("Cannot enable certificate users handler: No certificate.") } - default: - mode = "" - } - - if handler != nil { - - // Register handler Get at the hub. - hub.useridRetriever = func(request *http.Request) (userid string, err error) { - userid, err = handler.Get(request) - if userid != "" { - log.Printf("Users handler get success: %s\n", userid) - } - return - } - - log.Printf("Enabled users handler '%s'\n", mode) - } - return &Users{ - hub: hub, - realm: realm, - handler: handler, - } + return }