Browse Source

Cleaned up implementation of certificates handler and added bunch of config files options.

pull/28/head
Simon Eisenmann 11 years ago
parent
commit
12c04a9198
  1. 9
      server.conf.in
  2. 30
      src/app/spreed-speakfreely-server/main.go
  3. 86
      src/app/spreed-speakfreely-server/users.go

9
server.conf.in

@ -130,10 +130,12 @@ enabled = false
; set then the server will act as a CA and sign incoming user registrations and ; set then the server will act as a CA and sign incoming user registrations and
; return certificates to users as registration. ; return certificates to users as registration.
;certificate_certificate = usersca.crt ;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 ; successfull. The value of this header is matched to
; certificate_verifiedHeaderValue and only if there is a match, the proxy ; 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_verifiedHeader = x-verified
;certificate_verifiedHeaderValue = SUCCESS ;certificate_verifiedHeaderValue = SUCCESS
; The HTTP header name where to find the userid extracted by a proxy after ; 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 ; certificate_useridHeader value and the front end TLS proxy does inject the
; userid into that header. ; userid into that header.
;certificate_certificateHeader = x-certificate ;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 ; If enabled the server can create new userids. Set allowRegistration to true to
; enable userid creation/registration. Users are created according the settings ; enable userid creation/registration. Users are created according the settings
; of the currently configured mode (see above). ; of the currently configured mode (see above).

30
src/app/spreed-speakfreely-server/main.go

@ -24,8 +24,6 @@ package main
import ( import (
"app/spreed-speakfreely-server/sleepy" "app/spreed-speakfreely-server/sleepy"
"bytes" "bytes"
"crypto/tls"
"crypto/x509"
"flag" "flag"
"fmt" "fmt"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -358,6 +356,12 @@ func runner(runtime phoenix.Runtime) error {
// Create router. // Create router.
router := mux.NewRouter() router := mux.NewRouter()
r := router.PathPrefix(basePath).Subrouter().StrictSlash(true) r := router.PathPrefix(basePath).Subrouter().StrictSlash(true)
// Prepare listeners.
runtime.DefaultHTTPHandler(r)
runtime.DefaultHTTPSHandler(r)
// Add handlers.
r.HandleFunc("/", httputils.MakeGzipHandler(mainHandler)) 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/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)))) 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() return runtime.Start()
} }

86
src/app/spreed-speakfreely-server/users.go

@ -26,6 +26,7 @@ import (
"crypto/hmac" "crypto/hmac"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"crypto/tls"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/base64" "encoding/base64"
@ -253,17 +254,41 @@ type Users struct {
func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users { func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users {
var users = &Users{
hub: hub,
realm: realm,
}
var handler UsersHandler var handler UsersHandler
var err error var err error
// Create handler based on mode.
mode, _ := runtime.GetString("users", "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 { switch mode {
case "sharedsecret": case "sharedsecret":
secret, _ := runtime.GetString("users", "sharedsecret_secret") secret, _ := runtime.GetString("users", "sharedsecret_secret")
if secret != "" { if secret != "" {
handler = &UsersSharedsecretHandler{secret: []byte(secret)} handler = &UsersSharedsecretHandler{secret: []byte(secret)}
} else { } else {
log.Println("Cannot enable sharedsecret users handler: No secret.") err = errors.New("Cannot enable sharedsecret users handler: No secret.")
} }
case "httpheader": case "httpheader":
headerName, _ := runtime.GetString("users", "httpheader_header") headerName, _ := runtime.GetString("users", "httpheader_header")
@ -272,57 +297,58 @@ func NewUsers(hub *Hub, realm string, runtime phoenix.Runtime) *Users {
} }
handler = &UsersHTTPHeaderHandler{headerName: headerName} handler = &UsersHTTPHeaderHandler{headerName: headerName}
case "certificate": case "certificate":
var err2 error
uh := &UsersCertificateHandler{} uh := &UsersCertificateHandler{}
// TODO(longsleep): Add validFor to configuration. validForDays, _ := runtime.GetInt("users", "certificate_validForDays")
uh.validFor = 24 * time.Hour * 365 if validForDays == 0 {
validForDays = 365
}
uh.validFor = time.Duration(validForDays) * 24 * time.Hour
keyFn, _ := runtime.GetString("users", "certificate_key") keyFn, _ := runtime.GetString("users", "certificate_key")
certificateFn, _ := runtime.GetString("users", "certificate_certificate") certificateFn, _ := runtime.GetString("users", "certificate_certificate")
if keyFn != "" && certificateFn != "" { 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) log.Printf("Users certificate private key loaded from %s\n", keyFn)
} else { } 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 != "" { if certificateFn != "" {
// Load Certificate from file.
if certificate, err := loadX509Certificate(certificateFn); err == nil { if certificate, err := loadX509Certificate(certificateFn); err == nil {
// Parse first certificate in file.
if certificates, err := x509.ParseCertificates(certificate.Certificate[0]); err == nil { if certificates, err := x509.ParseCertificates(certificate.Certificate[0]); err == nil {
// Use first parsed certificate as CA.
uh.certificate = certificates[0] uh.certificate = certificates[0]
log.Printf("Users certificate loaded from %s\n", certificateFn) log.Printf("Users certificate loaded from %s\n", certificateFn)
handler = uh handler = uh
} else { // Get TLS config if the server has one.
log.Printf("Failed to parse users certificate: %s\n", err) 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
} }
} else { pool.AddCert(cert)
log.Printf("Failed to load users certificate: %s\n", err)
} }
} else { // Add pool to config.
log.Println("Cannot enable certificate users handler: No certificate.") tlsConfig.ClientCAs = pool
log.Printf("Initialized TLS auth pool with %d certificates.", len(pool.Subjects()))
} }
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 } else {
err = errors.New("Cannot enable certificate users handler: No certificate.")
} }
log.Printf("Enabled users handler '%s'\n", mode)
} }
return &Users{ return
hub: hub,
realm: realm,
handler: handler,
}
} }

Loading…
Cancel
Save