blob: e6856349feade516c44b2aaec675ae89ed591bbe [file] [log] [blame]
// Copyright 2019 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package ipaddr implements IP allowlist check.
package ipaddr
import (
"fmt"
"net"
"go.chromium.org/luci/auth/identity"
"go.chromium.org/luci/server/auth/service/protocol"
)
// Allowlist holds all named IP allowlist and the allowlist assignment map.
type Allowlist struct {
assignments map[identity.Identity]string // identity => IP allowlist for it
allowlists map[string][]net.IPNet // IP allowlist => subnets
}
// NewAllowlist creates new populated IP allowlist set.
func NewAllowlist(wl []*protocol.AuthIPWhitelist, as []*protocol.AuthIPWhitelistAssignment) (Allowlist, error) {
assignments := make(map[identity.Identity]string, len(as))
for _, a := range as {
assignments[identity.Identity(a.Identity)] = a.IpWhitelist
}
allowlists := make(map[string][]net.IPNet, len(wl))
for _, w := range wl {
if len(w.Subnets) == 0 {
continue
}
nets := make([]net.IPNet, len(w.Subnets))
for i, subnet := range w.Subnets {
_, ipnet, err := net.ParseCIDR(subnet)
if err != nil {
return Allowlist{}, fmt.Errorf("bad subnet %q in IP list %q - %s", subnet, w.Name, err)
}
nets[i] = *ipnet
}
allowlists[w.Name] = nets
}
return Allowlist{assignments, allowlists}, nil
}
// GetAllowlistForIdentity returns name of the IP allowlist to use to check
// IP of requests from given `ident`.
//
// Returns an empty string if the identity is not IP-restricted.
func (l Allowlist) GetAllowlistForIdentity(ident identity.Identity) string {
return l.assignments[ident]
}
// IsAllowedIP returns true if IP address belongs to given named IP allowlist.
func (l Allowlist) IsAllowedIP(ip net.IP, allowlist string) bool {
for _, ipnet := range l.allowlists[allowlist] {
if ipnet.Contains(ip) {
return true
}
}
return false
}