Rename Authenticator to Authenticate.

Rename single-constructor packages NewProxy and NewAuthenticator to New
Removed unused upstreamTransport.
This commit is contained in:
Bobby DeSimone 2019-01-20 12:15:29 -08:00
parent 2c7a7f2e02
commit 44527662fd
No known key found for this signature in database
GPG key ID: AEE4CF12FE86D07E
10 changed files with 55 additions and 89 deletions

View file

@ -103,8 +103,8 @@ func (o *Options) Validate() error {
return nil
}
// Authenticator stores all the information associated with proxying the request.
type Authenticator struct {
// Authenticate stores all the information associated with proxying the request.
type Authenticate struct {
RedirectURL *url.URL
Validator func(string) bool
@ -125,8 +125,8 @@ type Authenticator struct {
provider providers.Provider
}
// NewAuthenticator creates a Authenticator struct and applies the optional functions slice to the struct.
func NewAuthenticator(opts *Options, optionFuncs ...func(*Authenticator) error) (*Authenticator, error) {
// New creates a Authenticate struct and applies the optional functions slice to the struct.
func New(opts *Options, optionFuncs ...func(*Authenticate) error) (*Authenticate, error) {
if opts == nil {
return nil, errors.New("options cannot be nil")
}
@ -159,7 +159,7 @@ func NewAuthenticator(opts *Options, optionFuncs ...func(*Authenticator) error)
return nil, err
}
p := &Authenticator{
p := &Authenticate{
SharedKey: opts.SharedKey,
AllowedDomains: opts.AllowedDomains,
ProxyRootDomains: dotPrependDomains(opts.ProxyRootDomains),

View file

@ -27,7 +27,7 @@ var securityHeaders = map[string]string{
}
// Handler returns the Http.Handlers for authentication, callback, and refresh
func (p *Authenticator) Handler() http.Handler {
func (p *Authenticate) Handler() http.Handler {
mux := http.NewServeMux()
// we setup global endpoints that should respond to any hostname
mux.HandleFunc("/ping", m.WithMethods(p.PingPage, "GET"))
@ -58,31 +58,31 @@ func (p *Authenticator) Handler() http.Handler {
}
// validateSignature wraps a common collection of middlewares to validate signatures
func (p *Authenticator) validateSignature(f http.HandlerFunc) http.HandlerFunc {
func (p *Authenticate) validateSignature(f http.HandlerFunc) http.HandlerFunc {
return validateRedirectURI(validateSignature(f, p.SharedKey), p.ProxyRootDomains)
}
// validateSignature wraps a common collection of middlewares to validate
// a (presumably) existing user session
func (p *Authenticator) validateExisting(f http.HandlerFunc) http.HandlerFunc {
func (p *Authenticate) validateExisting(f http.HandlerFunc) http.HandlerFunc {
return m.ValidateClientSecret(f, p.SharedKey)
}
// RobotsTxt handles the /robots.txt route.
func (p *Authenticator) RobotsTxt(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) RobotsTxt(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
fmt.Fprintf(rw, "User-agent: *\nDisallow: /")
}
// PingPage handles the /ping route
func (p *Authenticator) PingPage(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) PingPage(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
fmt.Fprintf(rw, "OK")
}
// SignInPage directs the user to the sign in page. Takes a `redirect_uri` param.
func (p *Authenticator) SignInPage(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) SignInPage(rw http.ResponseWriter, req *http.Request) {
requestLog := log.WithRequest(req, "authenticate.SignInPage")
redirectURL := p.RedirectURL.ResolveReference(req.URL)
// validateRedirectURI middleware already ensures that this is a valid URL
@ -110,7 +110,7 @@ func (p *Authenticator) SignInPage(rw http.ResponseWriter, req *http.Request) {
p.templates.ExecuteTemplate(rw, "sign_in.html", t)
}
func (p *Authenticator) authenticate(rw http.ResponseWriter, req *http.Request) (*sessions.SessionState, error) {
func (p *Authenticate) authenticate(rw http.ResponseWriter, req *http.Request) (*sessions.SessionState, error) {
requestLog := log.WithRequest(req, "authenticate.authenticate")
session, err := p.sessionStore.LoadSession(req)
if err != nil {
@ -173,7 +173,7 @@ func (p *Authenticator) authenticate(rw http.ResponseWriter, req *http.Request)
// SignIn handles the /sign_in endpoint. It attempts to authenticate the user,
// and if the user is not authenticated, it renders a sign in page.
func (p *Authenticator) SignIn(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) SignIn(rw http.ResponseWriter, req *http.Request) {
// We attempt to authenticate the user. If they cannot be authenticated, we render a sign-in
// page.
//
@ -203,7 +203,7 @@ func (p *Authenticator) SignIn(rw http.ResponseWriter, req *http.Request) {
}
// ProxyOAuthRedirect redirects the user back to sso proxy's redirection endpoint.
func (p *Authenticator) ProxyOAuthRedirect(rw http.ResponseWriter, req *http.Request, session *sessions.SessionState) {
func (p *Authenticate) ProxyOAuthRedirect(rw http.ResponseWriter, req *http.Request, session *sessions.SessionState) {
// This workflow corresponds to Section 3.1.2 of the OAuth2 RFC.
// See https://tools.ietf.org/html/rfc6749#section-3.1.2 for more specific information.
//
@ -263,7 +263,7 @@ func getAuthCodeRedirectURL(redirectURL *url.URL, state, authCode string) string
}
// SignOut signs the user out.
func (p *Authenticator) SignOut(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) SignOut(rw http.ResponseWriter, req *http.Request) {
redirectURI := req.Form.Get("redirect_uri")
if req.Method == "GET" {
p.SignOutPage(rw, req, "")
@ -296,7 +296,7 @@ func (p *Authenticator) SignOut(rw http.ResponseWriter, req *http.Request) {
}
// SignOutPage renders a sign out page with a message
func (p *Authenticator) SignOutPage(rw http.ResponseWriter, req *http.Request, message string) {
func (p *Authenticate) SignOutPage(rw http.ResponseWriter, req *http.Request, message string) {
// validateRedirectURI middleware already ensures that this is a valid URL
redirectURI := req.Form.Get("redirect_uri")
session, err := p.sessionStore.LoadSession(req)
@ -337,7 +337,7 @@ func (p *Authenticator) SignOutPage(rw http.ResponseWriter, req *http.Request, m
// OAuthStart starts the authentication process by redirecting to the provider. It provides a
// `redirectURI`, allowing the provider to redirect back to the sso proxy after authentication.
func (p *Authenticator) OAuthStart(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) OAuthStart(rw http.ResponseWriter, req *http.Request) {
nonce := fmt.Sprintf("%x", cryptutil.GenerateKey())
p.csrfStore.SetCSRF(rw, req, nonce)
@ -368,7 +368,7 @@ func (p *Authenticator) OAuthStart(rw http.ResponseWriter, req *http.Request) {
http.Redirect(rw, req, signInURL, http.StatusFound)
}
func (p *Authenticator) redeemCode(host, code string) (*sessions.SessionState, error) {
func (p *Authenticate) redeemCode(host, code string) (*sessions.SessionState, error) {
session, err := p.provider.Redeem(code)
if err != nil {
return nil, err
@ -382,7 +382,7 @@ func (p *Authenticator) redeemCode(host, code string) (*sessions.SessionState, e
}
// getOAuthCallback completes the oauth cycle from an identity provider's callback
func (p *Authenticator) getOAuthCallback(rw http.ResponseWriter, req *http.Request) (string, error) {
func (p *Authenticate) getOAuthCallback(rw http.ResponseWriter, req *http.Request) (string, error) {
requestLog := log.WithRequest(req, "authenticate.getOAuthCallback")
// finish the oauth cycle
err := req.ParseForm()
@ -428,7 +428,7 @@ func (p *Authenticator) getOAuthCallback(rw http.ResponseWriter, req *http.Reque
return "", httputil.HTTPError{Code: http.StatusForbidden, Message: "Invalid Redirect URI"}
}
// Set cookie, or deny: The authenticator validates the session email and group
// Set cookie, or deny: validates the session email and group
// - for p.Validator see validator.go#newValidatorImpl for more info
// - for p.provider.ValidateGroup see providers/google.go#ValidateGroup for more info
if !p.Validator(session.Email) {
@ -446,7 +446,7 @@ func (p *Authenticator) getOAuthCallback(rw http.ResponseWriter, req *http.Reque
// OAuthCallback handles the callback from the provider, and returns an error response if there is an error.
// If there is no error it will redirect to the redirect url.
func (p *Authenticator) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
redirect, err := p.getOAuthCallback(rw, req)
switch h := err.(type) {
case nil:
@ -462,7 +462,7 @@ func (p *Authenticator) OAuthCallback(rw http.ResponseWriter, req *http.Request)
}
// Redeem has a signed access token, and provides the user information associated with the access token.
func (p *Authenticator) Redeem(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) Redeem(rw http.ResponseWriter, req *http.Request) {
// The auth code is redeemed by the sso proxy for an access token, refresh token,
// expiration, and email.
requestLog := log.WithRequest(req, "authenticate.Redeem")
@ -518,7 +518,7 @@ func (p *Authenticator) Redeem(rw http.ResponseWriter, req *http.Request) {
}
// Refresh takes a refresh token and returns a new access token
func (p *Authenticator) Refresh(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) Refresh(rw http.ResponseWriter, req *http.Request) {
err := req.ParseForm()
if err != nil {
http.Error(rw, fmt.Sprintf("Bad Request: %s", err.Error()), http.StatusBadRequest)
@ -557,7 +557,7 @@ func (p *Authenticator) Refresh(rw http.ResponseWriter, req *http.Request) {
}
// GetProfile gets a list of groups of which a user is a member.
func (p *Authenticator) GetProfile(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) GetProfile(rw http.ResponseWriter, req *http.Request) {
// The sso proxy sends the user's email to this endpoint to get a list of Google groups that
// the email is a member of. The proxy will compare these groups to the list of allowed
// groups for the upstream service the user is trying to access.
@ -599,7 +599,7 @@ func (p *Authenticator) GetProfile(rw http.ResponseWriter, req *http.Request) {
// ValidateToken validates the X-Access-Token from the header and returns an error response
// if it's invalid
func (p *Authenticator) ValidateToken(rw http.ResponseWriter, req *http.Request) {
func (p *Authenticate) ValidateToken(rw http.ResponseWriter, req *http.Request) {
accessToken := req.Header.Get("X-Access-Token")
idToken := req.Header.Get("X-Id-Token")

View file

@ -12,8 +12,8 @@ import (
"github.com/pomerium/pomerium/internal/templates"
)
func testAuthenticator() *Authenticator {
var auth Authenticator
func testAuthenticate() *Authenticate {
var auth Authenticate
auth.RedirectURL, _ = url.Parse("https://auth.example.com/oauth/callback")
auth.SharedKey = "IzY7MOZwzfOkmELXgozHDKTxoT3nOYhwkcmUVINsRww="
auth.AllowedDomains = []string{"*"}
@ -23,8 +23,8 @@ func testAuthenticator() *Authenticator {
return &auth
}
func TestAuthenticator_PingPage(t *testing.T) {
auth := testAuthenticator()
func TestAuthenticate_PingPage(t *testing.T) {
auth := testAuthenticate()
req, err := http.NewRequest("GET", "/ping", nil)
if err != nil {
t.Fatal(err)
@ -41,8 +41,8 @@ func TestAuthenticator_PingPage(t *testing.T) {
}
}
func TestAuthenticator_RobotsTxt(t *testing.T) {
auth := testAuthenticator()
func TestAuthenticate_RobotsTxt(t *testing.T) {
auth := testAuthenticate()
req, err := http.NewRequest("GET", "/robots.txt", nil)
if err != nil {
t.Fatal(err)
@ -60,8 +60,8 @@ func TestAuthenticator_RobotsTxt(t *testing.T) {
}
}
func TestAuthenticator_SignInPage(t *testing.T) {
auth := testAuthenticator()
func TestAuthenticate_SignInPage(t *testing.T) {
auth := testAuthenticate()
v := url.Values{}
v.Set("request_uri", "this-is-a-test-uri")
url := fmt.Sprintf("/signin?%s", v.Encode())

View file

@ -1,12 +0,0 @@
# Authorize
## What's this package do?
The authorize packages makes a binary determination of access.
Authorization is on trust from:
- Device state (vulnerability scanned?, MDM?, BYOD? Encrypted?)
- User standing (HR status, Groups, etc)
- Context (time, location, role)
Driven by:
- Dynamic "policy as code", fine grained policy
- Machine Learning & anomaly detection based on multiple input sources

View file

@ -35,21 +35,21 @@ func main() {
}
log.Debug().Str("version", version.FullVersion()).Str("user-agent", version.UserAgent()).Msg("cmd/pomerium")
var authenticator *authenticate.Authenticator
var auth *authenticate.Authenticate
var authHost string
if mainOpts.Services == "all" || mainOpts.Services == "authenticator" {
if mainOpts.Services == "all" || mainOpts.Services == "authenticate" {
authOpts, err := authenticate.OptionsFromEnvConfig()
if err != nil {
log.Fatal().Err(err).Msg("cmd/pomerium: failed to parse authenticator settings")
log.Fatal().Err(err).Msg("cmd/pomerium: failed to parse authenticate settings")
}
emailValidator := func(p *authenticate.Authenticator) error {
emailValidator := func(p *authenticate.Authenticate) error {
p.Validator = options.NewEmailValidator(authOpts.AllowedDomains)
return nil
}
authenticator, err = authenticate.NewAuthenticator(authOpts, emailValidator)
auth, err = authenticate.New(authOpts, emailValidator)
if err != nil {
log.Fatal().Err(err).Msg("cmd/pomerium: failed to create authenticator")
log.Fatal().Err(err).Msg("cmd/pomerium: failed to create authenticate")
}
authHost = authOpts.RedirectURL.Host
}
@ -61,20 +61,20 @@ func main() {
log.Fatal().Err(err).Msg("cmd/pomerium: failed to parse proxy settings")
}
p, err = proxy.NewProxy(proxyOpts)
p, err = proxy.New(proxyOpts)
if err != nil {
log.Fatal().Err(err).Msg("cmd/pomerium: failed to create proxy")
}
}
topMux := http.NewServeMux()
if authenticator != nil {
if auth != nil {
// Need to handle ping without host lookup for LB
topMux.HandleFunc("/ping", func(rw http.ResponseWriter, _ *http.Request) {
rw.WriteHeader(http.StatusOK)
fmt.Fprintf(rw, "OK")
})
topMux.Handle(authHost+"/", authenticator.Handler())
topMux.Handle(authHost+"/", auth.Handler())
}
if p != nil {
topMux.Handle("/", p.Handler())
@ -124,7 +124,7 @@ func optionsFromEnvConfig() (*Options, error) {
return nil, err
}
if !isValidService(o.Services) {
return nil, fmt.Errorf("%s is an invalid service type",o.Services)
return nil, fmt.Errorf("%s is an invalid service type", o.Services)
}
return o, nil
}

View file

@ -23,7 +23,7 @@ services:
pomerium-authenticate:
image: pomerium/pomerium:latest
environment:
- SERVICES=authenticator
- SERVICES=authenticate
# auth settings
- REDIRECT_URL=https://sso-auth.corp.beyondperimeter.com/oauth2/callback
# Identity Provider Settings (Must be changed!)

View file

@ -56,8 +56,8 @@ type AuthenticateClient struct {
GracePeriodTTL time.Duration
}
// NewAuthenticateClient instantiates a new AuthenticateClient with provider data
func NewAuthenticateClient(uri *url.URL, sharedKey string, sessionValid, sessionLifetime, gracePeriod time.Duration) *AuthenticateClient {
// NewClient instantiates a new AuthenticateClient with provider data
func NewClient(uri *url.URL, sharedKey string, sessionValid, sessionLifetime, gracePeriod time.Duration) *AuthenticateClient {
return &AuthenticateClient{
AuthenticateServiceURL: uri,

View file

@ -435,25 +435,6 @@ func (p *Proxy) Authenticate(rw http.ResponseWriter, req *http.Request) (err err
return nil
}
// upstreamTransport is used to ensure that upstreams cannot override the
// security headers applied by sso_proxy
type upstreamTransport struct {
transport *http.Transport
}
// RoundTrip round trips the request and deletes security headers before returning the response.
func (t *upstreamTransport) RoundTrip(req *http.Request) (*http.Response, error) {
resp, err := t.transport.RoundTrip(req)
if err != nil {
log.Error().Err(err).Msg("proxy.RoundTrip")
return nil, err
}
for key := range securityHeaders {
resp.Header.Del(key)
}
return resp, err
}
// Handle constructs a route from the given host string and matches it to the provided http.Handler and UpstreamConfig
func (p *Proxy) Handle(host string, handler http.Handler) {
p.mux[host] = &handler

View file

@ -126,9 +126,9 @@ type StateParameter struct {
RedirectURI string `json:"redirect_uri"`
}
// NewProxy takes a Proxy service from options and a validation function.
// New takes a Proxy service from options and a validation function.
// Function returns an error if options fail to validate.
func NewProxy(opts *Options) (*Proxy, error) {
func New(opts *Options) (*Proxy, error) {
if opts == nil {
return nil, errors.New("options cannot be nil")
}
@ -156,7 +156,7 @@ func NewProxy(opts *Options) (*Proxy, error) {
return nil, err
}
authClient := authenticator.NewAuthenticateClient(
authClient := authenticator.NewClient(
opts.AuthenticateServiceURL,
opts.SharedKey,
// todo(bdd): fields below should be passed as function args
@ -185,7 +185,7 @@ func NewProxy(opts *Options) (*Proxy, error) {
reverseProxy := NewReverseProxy(toURL)
handler := NewReverseProxyHandler(opts, reverseProxy, toURL.String())
p.Handle(fromURL.Host, handler)
log.Info().Str("from", fromURL.Host).Str("to", toURL.String()).Msg("proxy.NewProxy : route")
log.Info().Str("from", fromURL.Host).Str("to", toURL.String()).Msg("proxy.New : route")
}
return p, nil
@ -231,8 +231,6 @@ func (u *UpstreamProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// NewReverseProxy creates a reverse proxy to a specified url.
// It adds an X-Forwarded-Host header that is the request's host.
//
// todo(bdd): when would we ever want to preserve host?
func NewReverseProxy(to *url.URL) *httputil.ReverseProxy {
proxy := httputil.NewSingleHostReverseProxy(to)
proxy.Transport = defaultUpstreamTransport
@ -240,7 +238,6 @@ func NewReverseProxy(to *url.URL) *httputil.ReverseProxy {
director := proxy.Director
proxy.Director = func(req *http.Request) {
req.Header.Add("X-Forwarded-Host", req.Host)
director(req)
req.Host = to.Host
}

View file

@ -183,7 +183,7 @@ func TestOptions_Validate(t *testing.T) {
}
}
func TestNewProxy(t *testing.T) {
func TestNew(t *testing.T) {
good := testOptions()
shortCookieLength := testOptions()
shortCookieLength.CookieSecret = "gN3xnvfsAwfCXxnJorGLKUG4l2wC8sS8nfLMhcStPg=="
@ -203,16 +203,16 @@ func TestNewProxy(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewProxy(tt.opts)
got, err := New(tt.opts)
if (err != nil) != tt.wantErr {
t.Errorf("NewProxy() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got == nil && tt.wantProxy == true {
t.Errorf("NewProxy() expected valid proxy struct")
t.Errorf("New() expected valid proxy struct")
}
if got != nil && len(got.mux) != tt.numMuxes {
t.Errorf("NewProxy() = num muxes %v, want %v", got, tt.numMuxes)
t.Errorf("New() = num muxes %v, want %v", got, tt.numMuxes)
}
})
}