feat: allow bypassing of basic auth from a list of authorized cidrs (#50)
All checks were successful
Cadoles/bouncer/pipeline/head This commit looks good
All checks were successful
Cadoles/bouncer/pipeline/head This commit looks good
This commit is contained in:
@ -1,16 +1,13 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"forge.cadoles.com/cadoles/bouncer/internal/cidr"
|
||||
"forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/authn"
|
||||
"forge.cadoles.com/cadoles/bouncer/internal/store"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
type Authenticator struct {
|
||||
@ -18,14 +15,12 @@ type Authenticator struct {
|
||||
|
||||
// Authenticate implements authn.Authenticator.
|
||||
func (a *Authenticator) Authenticate(w http.ResponseWriter, r *http.Request, layer *store.Layer) (*authn.User, error) {
|
||||
ctx := r.Context()
|
||||
|
||||
options, err := fromStoreOptions(layer.Options)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
matches, err := a.matchAnyAuthorizedCIDRs(ctx, r.RemoteAddr, options.AuthorizedCIDRs)
|
||||
matches, err := cidr.MatchAny(r.RemoteAddr, options.AuthorizedCIDRs...)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
@ -49,42 +44,6 @@ func (a *Authenticator) Authenticate(w http.ResponseWriter, r *http.Request, lay
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (a *Authenticator) matchAnyAuthorizedCIDRs(ctx context.Context, remoteHostPort string, CIDRs []string) (bool, error) {
|
||||
var remoteHost string
|
||||
if strings.Contains(remoteHostPort, ":") {
|
||||
var err error
|
||||
remoteHost, _, err = net.SplitHostPort(remoteHostPort)
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
} else {
|
||||
remoteHost = remoteHostPort
|
||||
}
|
||||
|
||||
remoteAddr := net.ParseIP(remoteHost)
|
||||
if remoteAddr == nil {
|
||||
return false, errors.Errorf("remote host '%s' is not a valid ip address", remoteHost)
|
||||
}
|
||||
|
||||
for _, rawCIDR := range CIDRs {
|
||||
_, net, err := net.ParseCIDR(rawCIDR)
|
||||
if err != nil {
|
||||
return false, errors.WithStack(err)
|
||||
}
|
||||
|
||||
match := net.Contains(remoteAddr)
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
logger.Debug(ctx, "comparing remote host with authorized cidrs", logger.F("remoteAddr", remoteAddr))
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ authn.Authenticator = &Authenticator{}
|
||||
)
|
||||
|
@ -1,77 +0,0 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestMatchAuthorizedCIDRs(t *testing.T) {
|
||||
|
||||
type testCase struct {
|
||||
RemoteHostPort string
|
||||
AuthorizedCIDRs []string
|
||||
ExpectedResult bool
|
||||
ExpectedError error
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
RemoteHostPort: "192.168.1.15",
|
||||
AuthorizedCIDRs: []string{
|
||||
"192.168.1.0/24",
|
||||
},
|
||||
ExpectedResult: true,
|
||||
},
|
||||
{
|
||||
RemoteHostPort: "192.168.1.15:43349",
|
||||
AuthorizedCIDRs: []string{
|
||||
"192.168.1.0/24",
|
||||
},
|
||||
ExpectedResult: true,
|
||||
},
|
||||
{
|
||||
RemoteHostPort: "192.168.1.15:43349",
|
||||
AuthorizedCIDRs: []string{
|
||||
"192.168.1.5/32",
|
||||
},
|
||||
ExpectedResult: false,
|
||||
},
|
||||
{
|
||||
RemoteHostPort: "192.168.1.15:43349",
|
||||
AuthorizedCIDRs: []string{
|
||||
"192.168.1.5/32",
|
||||
"192.168.1.0/24",
|
||||
},
|
||||
ExpectedResult: true,
|
||||
},
|
||||
{
|
||||
RemoteHostPort: "192.168.1.15:43349",
|
||||
AuthorizedCIDRs: []string{
|
||||
"192.168.1.5/32",
|
||||
"192.168.1.6/32",
|
||||
"192.168.1.7/32",
|
||||
},
|
||||
ExpectedResult: false,
|
||||
},
|
||||
}
|
||||
|
||||
auth := Authenticator{}
|
||||
ctx := context.Background()
|
||||
|
||||
for idx, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("Case #%d", idx), func(t *testing.T) {
|
||||
result, err := auth.matchAnyAuthorizedCIDRs(ctx, tc.RemoteHostPort, tc.AuthorizedCIDRs)
|
||||
|
||||
if g, e := result, tc.ExpectedResult; e != g {
|
||||
t.Errorf("result: expected '%v', got '%v'", e, g)
|
||||
}
|
||||
|
||||
if e, g := tc.ExpectedError, err; !errors.Is(err, tc.ExpectedError) {
|
||||
t.Errorf("err: expected '%v', got '%v'", e, g)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user