-
Notifications
You must be signed in to change notification settings - Fork 175
vicadmin redirect/force TLS #7960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
d9b8c10
2dd22dd
9be9175
713c7bc
d9223dd
fad2dc7
33572e4
592089d
adf6c29
312ffac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,9 @@ import ( | |
| "compress/gzip" | ||
| "crypto/tls" | ||
| "crypto/x509" | ||
| "fmt" | ||
| "html/template" | ||
| "io" | ||
| "net" | ||
| "net/http" | ||
| "net/url" | ||
|
|
@@ -75,6 +77,80 @@ const ( | |
| genericErrorMessage = "Internal Server Error; see /var/log/vic/vicadmin.log for details" // for http errors that shouldn't be displayed in the browser to the user | ||
| ) | ||
|
|
||
| //wrapper struct around net.Conn for our custom funcs | ||
| type Conn struct { | ||
| net.Conn | ||
| b byte | ||
| err error | ||
| oneTimeSwitch bool | ||
| } | ||
|
|
||
| //Returns number of bytes read | ||
| func (c *Conn) Read(b []byte) (int, error) { | ||
| //oneTimeSwitch bool of first conn starts off as true so we do the TLS check once | ||
| if c.oneTimeSwitch { | ||
| c.oneTimeSwitch = false | ||
| b[0] = c.b | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just for the sake of sanity, before this access we probably want to check the length of |
||
| // if there's more bytes to read | ||
| if len(b) > 1 && c.err == nil { | ||
| //recurse on next byte | ||
| n, e := c.Conn.Read(b[1:]) | ||
| //close connection if error during reading | ||
| if e != nil { | ||
| c.Conn.Close() | ||
| } | ||
| //return total num of bytes read (+ current) and pass error e | ||
| return n + 1, e | ||
| } | ||
| //only one byte read | ||
| return 1, c.err | ||
| } | ||
| //using the default Conn read | ||
| return c.Conn.Read(b) | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| //wrapper struct for our custom funcs | ||
|
||
| type ReqListener struct { | ||
|
||
| net.Listener | ||
| addr string | ||
| config *tls.Config | ||
| } | ||
|
|
||
| //override default listener Accept function and add TLS check | ||
| func (l *ReqListener) Accept() (net.Conn, error) { | ||
| //call default net.listener.Accept first | ||
|
||
| c, err := l.Listener.Accept() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| //create slice of size 1 for storing the first byte | ||
| b := make([]byte, 1) | ||
| //regular conn read, b will be updated with byte val | ||
| _, err = c.Read(b) | ||
| if err != nil { | ||
| c.Close() | ||
| if err != io.EOF { | ||
| return nil, err | ||
| } | ||
| } | ||
| //wrap Conn in our custom struct | ||
| con := &Conn{ | ||
| Conn: c, | ||
| b: b[0], | ||
| err: err, | ||
| oneTimeSwitch: true, | ||
| } | ||
| //the first byte is the hex byte 0x16 = 22 | ||
| //which means that this is a TLS “handshake” record | ||
| if b[0] == 22 { | ||
| //HTTPS creates Conn from our custom con/tls config | ||
| return tls.Server(con, l.config), nil | ||
| } | ||
|
|
||
| //regular HTTP connection, return con | ||
| return con, nil | ||
| } | ||
|
|
||
| func (s *server) listen() error { | ||
| defer trace.End(trace.Begin("")) | ||
|
|
||
|
|
@@ -95,7 +171,6 @@ func (s *server) listen() error { | |
| } | ||
| if err != nil { | ||
| log.Errorf("Could not load certificate from config - running without TLS: %s", err) | ||
|
|
||
| s.l, err = net.Listen("tcp", s.addr) | ||
| return err | ||
| } | ||
|
|
@@ -145,7 +220,7 @@ func (s *server) listen() error { | |
| return err | ||
| } | ||
|
|
||
| s.l = tls.NewListener(innerListener, tlsconfig) | ||
| s.l = &ReqListener{Listener: innerListener, config: tlsconfig} | ||
| return nil | ||
| } | ||
|
|
||
|
|
@@ -158,16 +233,33 @@ func (s *server) AuthenticatedHandle(link string, h http.Handler) { | |
| s.Authenticated(link, h.ServeHTTP) | ||
| } | ||
|
|
||
| //Redirects HTTP to HTTPS | ||
| func HTTPSRedirectHandle(h http.Handler) http.Handler { | ||
| redirectToHTTPS := func(w http.ResponseWriter, r *http.Request) { | ||
| //If TLS is nil, request is not HTTPS, so we must redirect | ||
| if r.TLS == nil { | ||
|
|
||
|
||
| http.Redirect(w, r, fmt.Sprintf("https://%s%s", r.Host, r.RequestURI), http.StatusMovedPermanently) | ||
| return | ||
| } | ||
| h.ServeHTTP(w, r) | ||
| return | ||
|
||
|
|
||
| } | ||
| return http.HandlerFunc(redirectToHTTPS) | ||
| } | ||
|
|
||
| func (s *server) Handle(link string, h http.Handler) { | ||
| log.Debugf("%s --- %s", time.Now().String(), link) | ||
| s.mux.Handle(link, gorillacontext.ClearHandler(h)) | ||
| s.mux.Handle(link, gorillacontext.ClearHandler(HTTPSRedirectHandle(h))) | ||
| } | ||
|
|
||
| // Enforces authentication on route `link` and runs `handler` on successful auth | ||
| func (s *server) Authenticated(link string, handler func(http.ResponseWriter, *http.Request)) { | ||
| defer trace.End(trace.Begin("")) | ||
|
|
||
| authHandler := func(w http.ResponseWriter, r *http.Request) { | ||
|
|
||
|
||
| // #nosec: Errors unhandled because it is okay if the cookie doesn't exist. | ||
| websession, _ := s.uss.cookies.Get(r, sessionCookieKey) | ||
|
|
||
|
|
@@ -211,6 +303,7 @@ func (s *server) Authenticated(link string, handler func(http.ResponseWriter, *h | |
| } | ||
|
|
||
| // user was authenticated via cert | ||
|
|
||
|
||
| handler(w, r) | ||
| return | ||
| } | ||
|
|
@@ -259,7 +352,6 @@ func (s *server) Authenticated(link string, handler func(http.ResponseWriter, *h | |
| s.logoutHandler(w, r) | ||
| return | ||
| } | ||
|
|
||
| // if the date & remote IP on the cookie were valid, then the user is authenticated | ||
| log.Infof("User with a valid auth cookie at %s is authenticated.", connectingAddr[0]) | ||
| handler(w, r) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
c.UncertainTLSfor this flag (sorry to have you keep renaming it)? Then the code has some semantic meaning: "if c.UncertainTLSthen determine whether TLS is present on this connection or not"Hopefully you agree that makes the flag's purpose clearer?