authenticate: support hot reloaded config (#984)

By implementinng OptionsUpdater interface.

Fixes #982
This commit is contained in:
Cuong Manh Le 2020-06-24 00:18:20 +07:00 committed by GitHub
parent eaa0c980d2
commit 17ba595ced
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 9 deletions

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"html/template" "html/template"
"net/url" "net/url"
"sync"
"gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2"
@ -25,6 +26,7 @@ import (
"github.com/pomerium/pomerium/internal/httputil" "github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/identity" "github.com/pomerium/pomerium/internal/identity"
"github.com/pomerium/pomerium/internal/identity/oauth" "github.com/pomerium/pomerium/internal/identity/oauth"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/sessions" "github.com/pomerium/pomerium/internal/sessions"
"github.com/pomerium/pomerium/internal/sessions/cookie" "github.com/pomerium/pomerium/internal/sessions/cookie"
"github.com/pomerium/pomerium/internal/sessions/header" "github.com/pomerium/pomerium/internal/sessions/header"
@ -105,6 +107,8 @@ type Authenticate struct {
// userClient is used to update users // userClient is used to update users
userClient user.UserServiceClient userClient user.UserServiceClient
// guard administrator below.
administratorMu sync.Mutex
// administrators keeps track of administrator users. // administrators keeps track of administrator users.
administrator map[string]struct{} administrator map[string]struct{}
@ -184,10 +188,6 @@ func New(opts config.Options) (*Authenticate, error) {
return nil, err return nil, err
} }
administrator := make(map[string]struct{}, len(opts.Administrators))
for _, admin := range opts.Administrators {
administrator[admin] = struct{}{}
}
a := &Authenticate{ a := &Authenticate{
RedirectURL: redirectURL, RedirectURL: redirectURL,
// shared state // shared state
@ -208,7 +208,6 @@ func New(opts config.Options) (*Authenticate, error) {
dataBrokerClient: dataBrokerClient, dataBrokerClient: dataBrokerClient,
sessionClient: sessionClient, sessionClient: sessionClient,
userClient: userClient, userClient: userClient,
administrator: administrator,
jwk: &jose.JSONWebKeySet{}, jwk: &jose.JSONWebKeySet{},
templates: template.Must(frontend.NewTemplates()), templates: template.Must(frontend.NewTemplates()),
} }
@ -227,3 +226,26 @@ func New(opts config.Options) (*Authenticate, error) {
return a, nil return a, nil
} }
func (a *Authenticate) setAdminUsers(opts *config.Options) {
a.administratorMu.Lock()
defer a.administratorMu.Unlock()
a.administrator = make(map[string]struct{}, len(opts.Administrators))
for _, admin := range opts.Administrators {
a.administrator[admin] = struct{}{}
}
}
// UpdateOptions implements the OptionsUpdater interface and updates internal
// structures based on config.Options
func (a *Authenticate) UpdateOptions(opts config.Options) error {
if a == nil {
return nil
}
log.Info().Str("checksum", fmt.Sprintf("%x", opts.Checksum())).Msg("authenticate: updating options")
a.setAdminUsers(&opts)
return nil
}

View file

@ -156,6 +156,7 @@ func TestIsAdmin(t *testing.T) {
opts := newTestOptions(t) opts := newTestOptions(t)
opts.Administrators = tc.admins opts.Administrators = tc.admins
a, err := New(*opts) a, err := New(*opts)
assert.NoError(t, a.UpdateOptions(*opts))
require.NoError(t, err) require.NoError(t, err)
assert.True(t, a.isAdmin(tc.user) == tc.isAdmin) assert.True(t, a.isAdmin(tc.user) == tc.isAdmin)
}) })

View file

@ -459,6 +459,9 @@ func (a *Authenticate) deleteSession(ctx context.Context, sessionID string) erro
} }
func (a *Authenticate) isAdmin(user string) bool { func (a *Authenticate) isAdmin(user string) bool {
a.administratorMu.Lock()
defer a.administratorMu.Unlock()
_, ok := a.administrator[user] _, ok := a.administrator[user]
return ok return ok
} }

View file

@ -4,13 +4,14 @@
### New ### New
- config: add remove_request_headers @cuonglm [GH-702] - config: add remove_request_headers @cuonglm [GH-822]
- config: change default log level to INFO @cuonglm [GH-902] - config: change default log level to INFO @cuonglm [GH-902]
- config: add pass_identity_headers @cuonglm [GH-903] - config: add pass_identity_headers @cuonglm [GH-903]
- authenticate: allow hot reloaded admin users config @cuonglm [GH-984]
### Changes ### Changes
- proxy: do not set X-Pomerium-Jwt-Assertion/X-Pomerium-Claim-* headers by default [GH-903] - proxy: do not set X-Pomerium-Jwt-Assertion/X-Pomerium-Claim-* headers by default @cuonglm [GH-903]
## v0.9.1 ## v0.9.1

View file

@ -72,7 +72,7 @@ func Run(ctx context.Context, configFile string) error {
} }
// add services // add services
if err := setupAuthenticate(opt, controlPlane); err != nil { if err := setupAuthenticate(opt, controlPlane, &optionsUpdaters); err != nil {
return err return err
} }
var authorizeServer *authorize.Authorize var authorizeServer *authorize.Authorize
@ -132,7 +132,7 @@ func Run(ctx context.Context, configFile string) error {
return eg.Wait() return eg.Wait()
} }
func setupAuthenticate(opt *config.Options, controlPlane *controlplane.Server) error { func setupAuthenticate(opt *config.Options, controlPlane *controlplane.Server, optionsUpdaters *[]config.OptionsUpdater) error {
if !config.IsAuthenticate(opt.Services) { if !config.IsAuthenticate(opt.Services) {
return nil return nil
} }
@ -141,6 +141,11 @@ func setupAuthenticate(opt *config.Options, controlPlane *controlplane.Server) e
if err != nil { if err != nil {
return fmt.Errorf("error creating authenticate service: %w", err) return fmt.Errorf("error creating authenticate service: %w", err)
} }
*optionsUpdaters = append(*optionsUpdaters, svc)
err = svc.UpdateOptions(*opt)
if err != nil {
return fmt.Errorf("error updating authenticate options: %w", err)
}
host := urlutil.StripPort(opt.GetAuthenticateURL().Host) host := urlutil.StripPort(opt.GetAuthenticateURL().Host)
sr := controlPlane.HTTPRouter.Host(host).Subrouter() sr := controlPlane.HTTPRouter.Host(host).Subrouter()
svc.Mount(sr) svc.Mount(sr)