From f8366c2f09c77a55dc53038cae0b101263488867 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 10 Oct 2019 14:37:27 -0600 Subject: http: authentication module; hash-password cmd; http_basic provider This implements HTTP basicauth into Caddy 2. The basic auth module will not work with passwords that are not securely hashed, so a subcommand hash-password was added to make it convenient to produce those hashes. Also included is Caddyfile support. Closes #2747. --- modules/caddyhttp/caddyauth/caddyauth.go | 102 +++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 modules/caddyhttp/caddyauth/caddyauth.go (limited to 'modules/caddyhttp/caddyauth/caddyauth.go') diff --git a/modules/caddyhttp/caddyauth/caddyauth.go b/modules/caddyhttp/caddyauth/caddyauth.go new file mode 100644 index 0000000..48d4fba --- /dev/null +++ b/modules/caddyhttp/caddyauth/caddyauth.go @@ -0,0 +1,102 @@ +// Copyright 2015 Matthew Holt and The Caddy 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 caddyauth + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" +) + +func init() { + caddy.RegisterModule(Authentication{}) +} + +// Authentication is a middleware which provides user authentication. +type Authentication struct { + ProvidersRaw map[string]json.RawMessage `json:"providers,omitempty"` + + Providers map[string]Authenticator `json:"-"` +} + +// CaddyModule returns the Caddy module information. +func (Authentication) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "http.handlers.authentication", + New: func() caddy.Module { return new(Authentication) }, + } +} + +// Provision sets up a. +func (a *Authentication) Provision(ctx caddy.Context) error { + a.Providers = make(map[string]Authenticator) + for modName, rawMsg := range a.ProvidersRaw { + val, err := ctx.LoadModule("http.handlers.authentication.providers."+modName, rawMsg) + if err != nil { + return fmt.Errorf("loading authentication provider module '%s': %v", modName, err) + } + a.Providers[modName] = val.(Authenticator) + } + a.ProvidersRaw = nil // allow GC to deallocate + + return nil +} + +func (a Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { + var user User + var authed bool + var err error + for provName, prov := range a.Providers { + user, authed, err = prov.Authenticate(w, r) + if err != nil { + log.Printf("[ERROR] Authenticating with %s: %v", provName, err) + continue + } + if authed { + break + } + } + if !authed { + return caddyhttp.Error(http.StatusUnauthorized, fmt.Errorf("not authenticated")) + } + + repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer) + repl.Set("http.handlers.authentication.user.id", user.ID) + + return next.ServeHTTP(w, r) +} + +// Authenticator is a type which can authenticate a request. +// If a request was not authenticated, it returns false. An +// error is only returned if authenticating the request fails +// for a technical reason (not for bad/missing credentials). +type Authenticator interface { + Authenticate(http.ResponseWriter, *http.Request) (User, bool, error) +} + +// User represents an authenticated user. +type User struct { + ID string +} + +// Interface guards +var ( + _ caddy.Provisioner = (*Authentication)(nil) + _ caddyhttp.MiddlewareHandler = (*Authentication)(nil) +) -- cgit v1.2.3