mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-01 11:26:29 +02:00
* authorize: authorization module adds support for per-route access policy. In this release we support the most common forms of identity based access policy: `allowed_users`, `allowed_groups`, and `allowed_domains`. In future versions, the authorization module will also support context and device based authorization policy and decisions. See website documentation for more details. * docs: updated `env.example` to include a `POLICY` setting example. * docs: added `IDP_SERVICE_ACCOUNT` to `env.example` . * docs: removed `PROXY_ROOT_DOMAIN` settings which has been replaced by `POLICY`. * all: removed `ALLOWED_DOMAINS` settings which has been replaced by `POLICY`. Authorization is now handled by the authorization service and is defined in the policy configuration files. * proxy: `ROUTES` settings which has been replaced by `POLICY`. * internal/log: `http.Server` and `httputil.NewSingleHostReverseProxy` now uses pomerium's logging package instead of the standard library's built in one. Closes #54 Closes #41 Closes #61 Closes #58
127 lines
3.4 KiB
Go
127 lines
3.4 KiB
Go
package authorize // import "github.com/pomerium/pomerium/authorize"
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/internal/policy"
|
|
)
|
|
|
|
// Identity contains a user's identity information.
|
|
type Identity struct {
|
|
User string
|
|
Email string
|
|
Groups []string
|
|
}
|
|
|
|
// EmailDomain returns the domain of the identity's email.
|
|
func (i *Identity) EmailDomain() string {
|
|
if i.Email == "" {
|
|
return ""
|
|
}
|
|
comp := strings.Split(i.Email, "@")
|
|
if len(comp) != 2 || comp[0] == "" {
|
|
return ""
|
|
}
|
|
return comp[1]
|
|
}
|
|
|
|
// IdentityValidator provides an interface to check whether a user has access
|
|
// to a given route.
|
|
type IdentityValidator interface {
|
|
Valid(string, *Identity) bool
|
|
}
|
|
|
|
type identityWhitelist struct {
|
|
sync.RWMutex
|
|
m map[string]bool
|
|
}
|
|
|
|
// newIdentityWhitelistMap takes a slice of policies and creates a hashmap of identity
|
|
// authorizations per-route for each allowed group, domain, and email.
|
|
func newIdentityWhitelistMap(policies []policy.Policy) *identityWhitelist {
|
|
var im identityWhitelist
|
|
im.m = make(map[string]bool, len(policies)*3)
|
|
for _, p := range policies {
|
|
for _, group := range p.AllowedGroups {
|
|
log.Debug().Str("route", p.From).Str("group", group).Msg("add group")
|
|
im.PutGroup(p.From, group)
|
|
}
|
|
for _, domain := range p.AllowedDomains {
|
|
im.PutDomain(p.From, domain)
|
|
log.Debug().Str("route", p.From).Str("group", domain).Msg("add domain")
|
|
|
|
}
|
|
for _, email := range p.AllowedEmails {
|
|
im.PutEmail(p.From, email)
|
|
log.Debug().Str("route", p.From).Str("group", email).Msg("add email")
|
|
}
|
|
}
|
|
return &im
|
|
}
|
|
|
|
// Valid reports whether an identity has valid access for a given route.
|
|
func (m *identityWhitelist) Valid(route string, i *Identity) bool {
|
|
if ok := m.Domain(route, i.EmailDomain()); ok {
|
|
return ok
|
|
}
|
|
if ok := m.Email(route, i.Email); ok {
|
|
return ok
|
|
}
|
|
for _, group := range i.Groups {
|
|
if ok := m.Group(route, group); ok {
|
|
return ok
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Group retrieves per-route access given a group name.
|
|
func (m *identityWhitelist) Group(route, group string) bool {
|
|
m.RLock()
|
|
defer m.RUnlock()
|
|
return m.m[fmt.Sprintf("%s|group:%s", route, group)]
|
|
}
|
|
|
|
// PutGroup adds an access entry for a route given a group name.
|
|
func (m *identityWhitelist) PutGroup(route, group string) {
|
|
m.Lock()
|
|
m.m[fmt.Sprintf("%s|group:%s", route, group)] = true
|
|
m.Unlock()
|
|
}
|
|
|
|
// Domain retrieves per-route access given a domain name.
|
|
func (m *identityWhitelist) Domain(route, domain string) bool {
|
|
m.RLock()
|
|
defer m.RUnlock()
|
|
return m.m[fmt.Sprintf("%s|domain:%s", route, domain)]
|
|
}
|
|
|
|
// PutDomain adds an access entry for a route given a domain name.
|
|
func (m *identityWhitelist) PutDomain(route, domain string) {
|
|
m.Lock()
|
|
m.m[fmt.Sprintf("%s|domain:%s", route, domain)] = true
|
|
m.Unlock()
|
|
}
|
|
|
|
// Email retrieves per-route access given a user's email.
|
|
func (m *identityWhitelist) Email(route, email string) bool {
|
|
m.RLock()
|
|
defer m.RUnlock()
|
|
return m.m[fmt.Sprintf("%s|email:%s", route, email)]
|
|
}
|
|
|
|
// PutEmail adds an access entry for a route given a user's email.
|
|
func (m *identityWhitelist) PutEmail(route, email string) {
|
|
m.Lock()
|
|
m.m[fmt.Sprintf("%s|email:%s", route, email)] = true
|
|
m.Unlock()
|
|
}
|
|
|
|
// MockIdentityValidator is a mock implementation of IdentityValidator
|
|
type MockIdentityValidator struct{ ValidResponse bool }
|
|
|
|
// Valid is a mock implementation IdentityValidator's Valid method
|
|
func (mv *MockIdentityValidator) Valid(u string, i *Identity) bool { return mv.ValidResponse }
|