You've already forked oauth2-proxy
mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-06-23 00:40:46 +02:00
Add support for systemd.socket
When using sockets to pass data between e.g. nginx and oauth2-proxy it's simpler to use sockets. Systemd can even facilitate this and pass the actual socket directly. This also means that only the socket runs with the same group as nginx while the service runs with DynamicUser. Does not support TLS yet. nginx ``` server { location /oauth2/ { proxy_pass http://unix:/run/oauth2-proxy/oauth2.sock; } ``` oauth2-proxy.socket ``` [Socket] ListenStream=%t/oauth2.sock SocketGroup=www-data SocketMode=0660 ``` Start oauth2-proxy with the parameter `--http-address=fd:3`. Signed-off-by: Josef Johansson <josef@oderland.se>
This commit is contained in:
committed by
Josef Johansson
parent
bc8e7162db
commit
6743a9cc89
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
@ -17,16 +18,17 @@ import (
|
||||
const hello = "Hello World!"
|
||||
|
||||
var _ = Describe("Server", func() {
|
||||
|
||||
handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.Write([]byte(hello))
|
||||
})
|
||||
|
||||
Context("NewServer", func() {
|
||||
type newServerTableInput struct {
|
||||
opts Opts
|
||||
expectedErr error
|
||||
expectHTTPListener bool
|
||||
expectTLSListener bool
|
||||
fdAddr string
|
||||
ipv6 bool
|
||||
}
|
||||
|
||||
@ -34,6 +36,15 @@ var _ = Describe("Server", func() {
|
||||
if in.ipv6 {
|
||||
skipDevContainer()
|
||||
}
|
||||
|
||||
if in.fdAddr != "" {
|
||||
l, err := net.Listen("tcp", in.fdAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f, err := l.(*net.TCPListener).File()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
in.opts.fdFiles = []*os.File{f}
|
||||
}
|
||||
|
||||
srv, err := NewServer(in.opts)
|
||||
if in.expectedErr != nil {
|
||||
Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error())))
|
||||
@ -55,6 +66,46 @@ var _ = Describe("Server", func() {
|
||||
Expect(s.tlsListener.Close()).To(Succeed())
|
||||
}
|
||||
},
|
||||
Entry("with a valid non-lowercase fd IPv4 bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "Fd:3",
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: false,
|
||||
fdAddr: "127.0.0.1:0",
|
||||
}),
|
||||
Entry("with a valid fd IPv4 bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: false,
|
||||
fdAddr: "127.0.0.1:0",
|
||||
}),
|
||||
Entry("with a invalid fd named bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:hello",
|
||||
},
|
||||
expectedErr: fmt.Errorf("error setting up listener: listen (file, %s) failed: listen failed: fd with name is not implemented yet", "hello"),
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: false,
|
||||
fdAddr: "127.0.0.1:0",
|
||||
}),
|
||||
Entry("with a invalid fd IPv4 bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:4",
|
||||
},
|
||||
expectedErr: fmt.Errorf("error setting up listener: listen (file, %d) failed: listen failed: fd outside of range of available file descriptors", 4),
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: false,
|
||||
fdAddr: "127.0.0.1:0",
|
||||
}),
|
||||
Entry("with an ipv4 valid http bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
@ -86,6 +137,21 @@ var _ = Describe("Server", func() {
|
||||
expectHTTPListener: false,
|
||||
expectTLSListener: true,
|
||||
}),
|
||||
Entry("with a both a fd valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
SecureBindAddress: "127.0.0.1:0",
|
||||
TLS: &options.TLS{
|
||||
Key: &ipv4KeyDataSource,
|
||||
Cert: &ipv4CertDataSource,
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: true,
|
||||
fdAddr: "127.0.0.1:0",
|
||||
}),
|
||||
Entry("with a both a ipv4 valid http and ipv4 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
@ -300,6 +366,27 @@ var _ = Describe("Server", func() {
|
||||
expectHTTPListener: false,
|
||||
expectTLSListener: true,
|
||||
}),
|
||||
Entry("with valid fd IPv6 bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: false,
|
||||
fdAddr: "[::1]:0",
|
||||
ipv6: true,
|
||||
}),
|
||||
Entry("with a invalid fd IPv6 bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:4",
|
||||
},
|
||||
expectedErr: fmt.Errorf("error setting up listener: listen (file, %d) failed: listen failed: fd outside of range of available file descriptors", 4),
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: false,
|
||||
fdAddr: "[::1]:0",
|
||||
}),
|
||||
Entry("with an ipv6 valid http bind address", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
@ -334,6 +421,22 @@ var _ = Describe("Server", func() {
|
||||
expectTLSListener: true,
|
||||
ipv6: true,
|
||||
}),
|
||||
Entry("with a both a fd valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
SecureBindAddress: "[::1]:0",
|
||||
TLS: &options.TLS{
|
||||
Key: &ipv6KeyDataSource,
|
||||
Cert: &ipv6CertDataSource,
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
expectHTTPListener: true,
|
||||
expectTLSListener: true,
|
||||
fdAddr: "[::1]:0",
|
||||
ipv6: true,
|
||||
}),
|
||||
Entry("with a both a ipv6 valid http and ipv6 valid https bind address, and valid TLS config", &newServerTableInput{
|
||||
opts: Opts{
|
||||
Handler: handler,
|
||||
@ -563,6 +666,58 @@ var _ = Describe("Server", func() {
|
||||
|
||||
})
|
||||
|
||||
Context("with an fd ipv4 http server", func() {
|
||||
var listenAddr string
|
||||
|
||||
BeforeEach(func() {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f, err := l.(*net.TCPListener).File()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
srv, err = NewServer(Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
fdFiles: []*os.File{f},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
|
||||
})
|
||||
|
||||
It("Starts the server and serves the handler", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
resp, err := httpGet(ctx, listenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(string(body)).To(Equal(hello))
|
||||
})
|
||||
|
||||
It("Stops the server when the context is cancelled", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
_, err := httpGet(ctx, listenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cancel()
|
||||
|
||||
Eventually(func() error {
|
||||
_, err := httpGet(ctx, listenAddr)
|
||||
return err
|
||||
}).Should(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with an ipv4 http server", func() {
|
||||
var listenAddr string
|
||||
|
||||
@ -682,6 +837,88 @@ var _ = Describe("Server", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("with a fd ipv4 http and an ipv4 https server", func() {
|
||||
var listenAddr, secureListenAddr string
|
||||
|
||||
BeforeEach(func() {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f, err := l.(*net.TCPListener).File()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
srv, err = NewServer(Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
fdFiles: []*os.File{f},
|
||||
SecureBindAddress: "127.0.0.1:0",
|
||||
TLS: &options.TLS{
|
||||
Key: &ipv4KeyDataSource,
|
||||
Cert: &ipv4CertDataSource,
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
s, ok := srv.(*server)
|
||||
Expect(ok).To(BeTrue())
|
||||
|
||||
listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
|
||||
secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
|
||||
})
|
||||
|
||||
It("Starts the server and serves the handler on http", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
resp, err := httpGet(ctx, listenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(string(body)).To(Equal(hello))
|
||||
})
|
||||
|
||||
It("Starts the server and serves the handler on https", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
resp, err := httpGet(ctx, secureListenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(string(body)).To(Equal(hello))
|
||||
})
|
||||
|
||||
It("Stops both servers when the context is cancelled", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
_, err := httpGet(ctx, listenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = httpGet(ctx, secureListenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cancel()
|
||||
|
||||
Eventually(func() error {
|
||||
_, err := httpGet(ctx, listenAddr)
|
||||
return err
|
||||
}).Should(HaveOccurred())
|
||||
Eventually(func() error {
|
||||
_, err := httpGet(ctx, secureListenAddr)
|
||||
return err
|
||||
}).Should(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with both an ipv4 http and an ipv4 https server", func() {
|
||||
var listenAddr, secureListenAddr string
|
||||
|
||||
@ -880,6 +1117,89 @@ var _ = Describe("Server", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("with an fd ipv6 http and an ipv6 https server", func() {
|
||||
var listenAddr, secureListenAddr string
|
||||
|
||||
BeforeEach(func() {
|
||||
skipDevContainer()
|
||||
l, err := net.Listen("tcp", "[::1]:0")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
f, err := l.(*net.TCPListener).File()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
srv, err = NewServer(Opts{
|
||||
Handler: handler,
|
||||
BindAddress: "fd:3",
|
||||
fdFiles: []*os.File{f},
|
||||
SecureBindAddress: "[::1]:0",
|
||||
TLS: &options.TLS{
|
||||
Key: &ipv6KeyDataSource,
|
||||
Cert: &ipv6CertDataSource,
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
s, ok := srv.(*server)
|
||||
Expect(ok).To(BeTrue())
|
||||
|
||||
listenAddr = fmt.Sprintf("http://%s/", l.Addr().String())
|
||||
secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
|
||||
})
|
||||
|
||||
It("Starts the server and serves the handler on http", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
resp, err := httpGet(ctx, listenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(string(body)).To(Equal(hello))
|
||||
})
|
||||
|
||||
It("Starts the server and serves the handler on https", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
resp, err := httpGet(ctx, secureListenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(http.StatusOK))
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(string(body)).To(Equal(hello))
|
||||
})
|
||||
|
||||
It("Stops both servers when the context is cancelled", func() {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
Expect(srv.Start(ctx)).To(Succeed())
|
||||
}()
|
||||
|
||||
_, err := httpGet(ctx, listenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = httpGet(ctx, secureListenAddr)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cancel()
|
||||
|
||||
Eventually(func() error {
|
||||
_, err := httpGet(ctx, listenAddr)
|
||||
return err
|
||||
}).Should(HaveOccurred())
|
||||
Eventually(func() error {
|
||||
_, err := httpGet(ctx, secureListenAddr)
|
||||
return err
|
||||
}).Should(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with both an ipv6 http and an ipv6 https server", func() {
|
||||
var listenAddr, secureListenAddr string
|
||||
|
||||
|
Reference in New Issue
Block a user