2017-10-10 15:50:03 +03:00
package whitelist
2017-04-30 12:22:07 +03:00
import (
"net"
2018-03-23 19:40:04 +03:00
"net/http"
"net/http/httptest"
2017-04-30 12:22:07 +03:00
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
2018-03-23 19:40:04 +03:00
func TestIsAuthorized ( t * testing . T ) {
testCases := [ ] struct {
desc string
whiteList [ ] string
allowXForwardedFor bool
remoteAddr string
xForwardedForValues [ ] string
2018-04-23 17:20:05 +03:00
authorized bool
2018-03-23 19:40:04 +03:00
} {
{
desc : "allow UseXForwardedFor, remoteAddr not in range, UseXForwardedFor in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : true ,
remoteAddr : "10.2.3.1:123" ,
xForwardedForValues : [ ] string { "1.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : true ,
2018-03-23 19:40:04 +03:00
} ,
2018-05-30 10:26:03 +03:00
{
desc : "allow UseXForwardedFor, remoteAddr not in range, UseXForwardedFor in range (compact XFF)" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : true ,
remoteAddr : "10.2.3.1:123" ,
xForwardedForValues : [ ] string { "1.2.3.1, 10.2.3.1" } ,
authorized : true ,
} ,
2018-03-23 19:40:04 +03:00
{
desc : "allow UseXForwardedFor, remoteAddr in range, UseXForwardedFor in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : true ,
remoteAddr : "1.2.3.1:123" ,
xForwardedForValues : [ ] string { "1.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : true ,
2018-03-23 19:40:04 +03:00
} ,
{
desc : "allow UseXForwardedFor, remoteAddr in range, UseXForwardedFor not in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : true ,
remoteAddr : "1.2.3.1:123" ,
xForwardedForValues : [ ] string { "10.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : true ,
2018-03-23 19:40:04 +03:00
} ,
{
desc : "allow UseXForwardedFor, remoteAddr not in range, UseXForwardedFor not in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : true ,
remoteAddr : "10.2.3.1:123" ,
xForwardedForValues : [ ] string { "10.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : false ,
2018-03-23 19:40:04 +03:00
} ,
{
desc : "don't allow UseXForwardedFor, remoteAddr not in range, UseXForwardedFor in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : false ,
remoteAddr : "10.2.3.1:123" ,
xForwardedForValues : [ ] string { "1.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : false ,
2018-03-23 19:40:04 +03:00
} ,
{
desc : "don't allow UseXForwardedFor, remoteAddr in range, UseXForwardedFor in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : false ,
remoteAddr : "1.2.3.1:123" ,
xForwardedForValues : [ ] string { "1.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : true ,
2018-03-23 19:40:04 +03:00
} ,
{
desc : "don't allow UseXForwardedFor, remoteAddr in range, UseXForwardedFor not in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : false ,
remoteAddr : "1.2.3.1:123" ,
xForwardedForValues : [ ] string { "10.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : true ,
2018-03-23 19:40:04 +03:00
} ,
{
desc : "don't allow UseXForwardedFor, remoteAddr not in range, UseXForwardedFor not in range" ,
whiteList : [ ] string { "1.2.3.4/24" } ,
allowXForwardedFor : false ,
remoteAddr : "10.2.3.1:123" ,
xForwardedForValues : [ ] string { "10.2.3.1" , "10.2.3.1" } ,
2018-04-23 17:20:05 +03:00
authorized : false ,
2018-03-23 19:40:04 +03:00
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
req := NewRequest ( test . remoteAddr , test . xForwardedForValues )
whiteLister , err := NewIP ( test . whiteList , false , test . allowXForwardedFor )
require . NoError ( t , err )
2018-04-23 17:20:05 +03:00
err = whiteLister . IsAuthorized ( req )
if test . authorized {
require . NoError ( t , err )
} else {
require . Error ( t , err )
}
2018-03-23 19:40:04 +03:00
} )
}
}
2017-10-10 15:50:03 +03:00
func TestNew ( t * testing . T ) {
2017-04-30 12:22:07 +03:00
cases := [ ] struct {
desc string
2018-03-23 19:40:04 +03:00
whiteList [ ] string
2017-04-30 12:22:07 +03:00
expectedWhitelists [ ] * net . IPNet
errMessage string
} {
{
desc : "nil whitelist" ,
2018-03-23 19:40:04 +03:00
whiteList : nil ,
2017-04-30 12:22:07 +03:00
expectedWhitelists : nil ,
2018-03-08 17:08:03 +03:00
errMessage : "no white list provided" ,
2017-04-30 12:22:07 +03:00
} , {
desc : "empty whitelist" ,
2018-03-23 19:40:04 +03:00
whiteList : [ ] string { } ,
2017-04-30 12:22:07 +03:00
expectedWhitelists : nil ,
2018-03-08 17:08:03 +03:00
errMessage : "no white list provided" ,
2017-04-30 12:22:07 +03:00
} , {
desc : "whitelist containing empty string" ,
2018-03-23 19:40:04 +03:00
whiteList : [ ] string {
2017-04-30 12:22:07 +03:00
"1.2.3.4/24" ,
"" ,
"fe80::/16" ,
} ,
expectedWhitelists : nil ,
2018-03-23 19:40:04 +03:00
errMessage : "parsing CIDR white list <nil>: invalid CIDR address: " ,
2017-04-30 12:22:07 +03:00
} , {
desc : "whitelist containing only an empty string" ,
2018-03-23 19:40:04 +03:00
whiteList : [ ] string {
2017-04-30 12:22:07 +03:00
"" ,
} ,
expectedWhitelists : nil ,
2018-03-23 19:40:04 +03:00
errMessage : "parsing CIDR white list <nil>: invalid CIDR address: " ,
2017-04-30 12:22:07 +03:00
} , {
desc : "whitelist containing an invalid string" ,
2018-03-23 19:40:04 +03:00
whiteList : [ ] string {
2017-04-30 12:22:07 +03:00
"foo" ,
} ,
expectedWhitelists : nil ,
2018-03-23 19:40:04 +03:00
errMessage : "parsing CIDR white list <nil>: invalid CIDR address: foo" ,
2017-04-30 12:22:07 +03:00
} , {
desc : "IPv4 & IPv6 whitelist" ,
2018-03-23 19:40:04 +03:00
whiteList : [ ] string {
2017-04-30 12:22:07 +03:00
"1.2.3.4/24" ,
"fe80::/16" ,
} ,
expectedWhitelists : [ ] * net . IPNet {
{ IP : net . IPv4 ( 1 , 2 , 3 , 0 ) . To4 ( ) , Mask : net . IPv4Mask ( 255 , 255 , 255 , 0 ) } ,
{ IP : net . ParseIP ( "fe80::" ) , Mask : net . IPMask ( net . ParseIP ( "ffff::" ) ) } ,
} ,
errMessage : "" ,
} , {
desc : "IPv4 only" ,
2018-03-23 19:40:04 +03:00
whiteList : [ ] string {
2017-04-30 12:22:07 +03:00
"127.0.0.1/8" ,
} ,
expectedWhitelists : [ ] * net . IPNet {
{ IP : net . IPv4 ( 127 , 0 , 0 , 0 ) . To4 ( ) , Mask : net . IPv4Mask ( 255 , 0 , 0 , 0 ) } ,
} ,
errMessage : "" ,
} ,
}
for _ , test := range cases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2018-03-23 19:40:04 +03:00
whiteLister , err := NewIP ( test . whiteList , false , false )
2017-04-30 12:22:07 +03:00
if test . errMessage != "" {
require . EqualError ( t , err , test . errMessage )
} else {
require . NoError ( t , err )
2018-03-23 19:40:04 +03:00
for index , actual := range whiteLister . whiteListsNet {
2017-04-30 12:22:07 +03:00
expected := test . expectedWhitelists [ index ]
assert . Equal ( t , expected . IP , actual . IP )
assert . Equal ( t , expected . Mask . String ( ) , actual . Mask . String ( ) )
}
}
} )
}
}
2018-03-08 17:08:03 +03:00
func TestContainsIsAllowed ( t * testing . T ) {
2017-04-30 12:22:07 +03:00
cases := [ ] struct {
desc string
whitelistStrings [ ] string
passIPs [ ] string
rejectIPs [ ] string
} {
{
2018-03-23 19:40:04 +03:00
desc : "IPv4" ,
whitelistStrings : [ ] string { "1.2.3.4/24" } ,
2017-04-30 12:22:07 +03:00
passIPs : [ ] string {
"1.2.3.1" ,
"1.2.3.32" ,
"1.2.3.156" ,
"1.2.3.255" ,
} ,
rejectIPs : [ ] string {
"1.2.16.1" ,
"1.2.32.1" ,
"127.0.0.1" ,
"8.8.8.8" ,
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "IPv4 single IP" ,
whitelistStrings : [ ] string { "8.8.8.8" } ,
passIPs : [ ] string { "8.8.8.8" } ,
2017-10-10 15:50:03 +03:00
rejectIPs : [ ] string {
"8.8.8.7" ,
"8.8.8.9" ,
"8.8.8.0" ,
"8.8.8.255" ,
"4.4.4.4" ,
"127.0.0.1" ,
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "IPv4 Net single IP" ,
whitelistStrings : [ ] string { "8.8.8.8/32" } ,
passIPs : [ ] string { "8.8.8.8" } ,
2017-04-30 12:22:07 +03:00
rejectIPs : [ ] string {
"8.8.8.7" ,
"8.8.8.9" ,
"8.8.8.0" ,
"8.8.8.255" ,
"4.4.4.4" ,
"127.0.0.1" ,
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "multiple IPv4" ,
whitelistStrings : [ ] string { "1.2.3.4/24" , "8.8.8.8/8" } ,
2017-04-30 12:22:07 +03:00
passIPs : [ ] string {
"1.2.3.1" ,
"1.2.3.32" ,
"1.2.3.156" ,
"1.2.3.255" ,
"8.8.4.4" ,
"8.0.0.1" ,
"8.32.42.128" ,
"8.255.255.255" ,
} ,
rejectIPs : [ ] string {
"1.2.16.1" ,
"1.2.32.1" ,
"127.0.0.1" ,
"4.4.4.4" ,
"4.8.8.8" ,
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "IPv6" ,
whitelistStrings : [ ] string { "2a03:4000:6:d080::/64" } ,
2017-04-30 12:22:07 +03:00
passIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:6:d080::" ,
"2a03:4000:6:d080::1" ,
"2a03:4000:6:d080:dead:beef:ffff:ffff" ,
"2a03:4000:6:d080::42" ,
2017-04-30 12:22:07 +03:00
} ,
rejectIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:7:d080::" ,
"2a03:4000:7:d080::1" ,
"fe80::" ,
"4242::1" ,
2017-04-30 12:22:07 +03:00
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "IPv6 single IP" ,
whitelistStrings : [ ] string { "2a03:4000:6:d080::42/128" } ,
passIPs : [ ] string { "2a03:4000:6:d080::42" } ,
2017-04-30 12:22:07 +03:00
rejectIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:6:d080::1" ,
"2a03:4000:6:d080:dead:beef:ffff:ffff" ,
"2a03:4000:6:d080::43" ,
2017-04-30 12:22:07 +03:00
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "multiple IPv6" ,
whitelistStrings : [ ] string { "2a03:4000:6:d080::/64" , "fe80::/16" } ,
2017-04-30 12:22:07 +03:00
passIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:6:d080::" ,
"2a03:4000:6:d080::1" ,
"2a03:4000:6:d080:dead:beef:ffff:ffff" ,
"2a03:4000:6:d080::42" ,
"fe80::1" ,
"fe80:aa00:00bb:4232:ff00:eeee:00ff:1111" ,
"fe80::fe80" ,
2017-04-30 12:22:07 +03:00
} ,
rejectIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:7:d080::" ,
"2a03:4000:7:d080::1" ,
"4242::1" ,
2017-04-30 12:22:07 +03:00
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "multiple IPv6 & IPv4" ,
whitelistStrings : [ ] string { "2a03:4000:6:d080::/64" , "fe80::/16" , "1.2.3.4/24" , "8.8.8.8/8" } ,
2017-04-30 12:22:07 +03:00
passIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:6:d080::" ,
"2a03:4000:6:d080::1" ,
"2a03:4000:6:d080:dead:beef:ffff:ffff" ,
"2a03:4000:6:d080::42" ,
"fe80::1" ,
"fe80:aa00:00bb:4232:ff00:eeee:00ff:1111" ,
"fe80::fe80" ,
2017-04-30 12:22:07 +03:00
"1.2.3.1" ,
"1.2.3.32" ,
"1.2.3.156" ,
"1.2.3.255" ,
"8.8.4.4" ,
"8.0.0.1" ,
"8.32.42.128" ,
"8.255.255.255" ,
} ,
rejectIPs : [ ] string {
2017-10-10 15:50:03 +03:00
"2a03:4000:7:d080::" ,
"2a03:4000:7:d080::1" ,
"4242::1" ,
2017-04-30 12:22:07 +03:00
"1.2.16.1" ,
"1.2.32.1" ,
"127.0.0.1" ,
"4.4.4.4" ,
"4.8.8.8" ,
} ,
} ,
{
2018-03-23 19:40:04 +03:00
desc : "broken IP-addresses" ,
whitelistStrings : [ ] string { "127.0.0.1/32" } ,
passIPs : nil ,
2017-04-30 12:22:07 +03:00
} ,
}
for _ , test := range cases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2018-03-08 17:08:03 +03:00
2018-03-23 19:40:04 +03:00
whiteLister , err := NewIP ( test . whitelistStrings , false , false )
2017-04-30 12:22:07 +03:00
require . NoError ( t , err )
2017-10-10 15:50:03 +03:00
require . NotNil ( t , whiteLister )
2017-04-30 12:22:07 +03:00
for _ , testIP := range test . passIPs {
2018-04-23 17:20:05 +03:00
allowed , err := whiteLister . contains ( testIP )
2017-10-10 15:50:03 +03:00
require . NoError ( t , err )
2018-03-23 19:40:04 +03:00
assert . Truef ( t , allowed , "%s should have passed." , testIP )
2017-04-30 12:22:07 +03:00
}
for _ , testIP := range test . rejectIPs {
2018-04-23 17:20:05 +03:00
allowed , err := whiteLister . contains ( testIP )
2017-10-10 15:50:03 +03:00
require . NoError ( t , err )
2018-03-23 19:40:04 +03:00
assert . Falsef ( t , allowed , "%s should not have passed." , testIP )
2017-04-30 12:22:07 +03:00
}
} )
}
}
2017-10-10 15:50:03 +03:00
2018-03-08 17:08:03 +03:00
func TestContainsInsecure ( t * testing . T ) {
mustNewIP := func ( whitelistStrings [ ] string , insecure bool ) * IP {
2018-03-23 19:40:04 +03:00
ip , err := NewIP ( whitelistStrings , insecure , false )
2018-03-08 17:08:03 +03:00
if err != nil {
t . Fatal ( err )
}
return ip
}
testCases := [ ] struct {
desc string
whiteLister * IP
ip string
expected bool
} {
{
desc : "valid ip and insecure" ,
whiteLister : mustNewIP ( [ ] string { "1.2.3.4/24" } , true ) ,
ip : "1.2.3.1" ,
expected : true ,
} ,
{
desc : "invalid ip and insecure" ,
whiteLister : mustNewIP ( [ ] string { "1.2.3.4/24" } , true ) ,
ip : "10.2.3.1" ,
expected : true ,
} ,
{
desc : "invalid ip and secure" ,
whiteLister : mustNewIP ( [ ] string { "1.2.3.4/24" } , false ) ,
ip : "10.2.3.1" ,
expected : false ,
} ,
}
for _ , test := range testCases {
test := test
t . Run ( test . desc , func ( t * testing . T ) {
t . Parallel ( )
2018-04-23 17:20:05 +03:00
ok , err := test . whiteLister . contains ( test . ip )
2018-03-08 17:08:03 +03:00
require . NoError ( t , err )
assert . Equal ( t , test . expected , ok )
} )
}
}
func TestContainsBrokenIPs ( t * testing . T ) {
2017-10-10 15:50:03 +03:00
brokenIPs := [ ] string {
"foo" ,
"10.0.0.350" ,
"fe:::80" ,
"" ,
"\\&$§&/(" ,
}
2018-03-23 19:40:04 +03:00
whiteLister , err := NewIP ( [ ] string { "1.2.3.4/24" } , false , false )
2017-10-10 15:50:03 +03:00
require . NoError ( t , err )
for _ , testIP := range brokenIPs {
2018-04-23 17:20:05 +03:00
_ , err := whiteLister . contains ( testIP )
2017-10-10 15:50:03 +03:00
assert . Error ( t , err )
}
2018-03-23 19:40:04 +03:00
}
2017-10-10 15:50:03 +03:00
2018-03-23 19:40:04 +03:00
func NewRequest ( remoteAddr string , xForwardedFor [ ] string ) * http . Request {
req := httptest . NewRequest ( http . MethodGet , "http://example.com/foo" , nil )
if len ( remoteAddr ) > 0 {
req . RemoteAddr = remoteAddr
}
if len ( xForwardedFor ) > 0 {
for _ , xff := range xForwardedFor {
req . Header . Add ( XForwardedFor , xff )
}
}
return req
2017-10-10 15:50:03 +03:00
}