Skip to content

Commit

Permalink
rename AuthErrorHttpHandler to AuthErrorHTTPHandler and fix related l…
Browse files Browse the repository at this point in the history
…int warnings
  • Loading branch information
cyb3r4nt committed Aug 2, 2024
1 parent 768a0a7 commit 6ec7d89
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 91 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ There are several ways to adjust functionality of the library:
1. `ClaimsUpdater` - interface with `Update(claims Claims) Claims` method. This is the primary way to alter a token at login time and add any attributes, set ip, email, admin status, roles and so on.
1. `Validator` - interface with `Validate(token string, claims Claims) bool` method. This is post-token hook and will be called on **each request** wrapped with `Auth` middleware. This will be the place for special logic to reject some tokens or users.
1. `UserUpdater` - interface with `Update(claims token.User) token.User` method. This method will be called on **each request** wrapped with `UpdateUser` middleware. This will be the place for special logic modify User Info in request context. [Example of usage.](https://github.com/go-pkgz/auth/blob/19c1b6d26608494955a4480f8f6165af85b1deab/_example/main.go#L189)
1. `AuthErrorHttpHandler` - interface with `ServeAuthError(w http.ResponseWriter, r *http.Request, and other params)` method. It is possible to change how authentication errors are written into HTTP responses by configuring custom implementations of this interface for the middlewares.
1. `AuthErrorHTTPHandler` - interface with `ServeAuthError(w http.ResponseWriter, r *http.Request, and other params)` method. It is possible to change how authentication errors are written into HTTP responses by configuring custom implementations of this interface for the middlewares.

Some of the interfaces above have corresponding Func adapters - `SecretFunc`, `ClaimsUpdFunc`, `ValidatorFunc` and `UserUpdFunc`.

Expand Down
4 changes: 2 additions & 2 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type Opts struct {
AudSecrets bool // allow multiple secrets (secret per aud)
Logger logger.L // logger interface, default is no logging at all
RefreshCache middleware.RefreshCache // optional cache to keep refreshed tokens
AuthErrorHttpHandler middleware.AuthErrorHttpHandler // optional HTTP handler for authentication errors
AuthErrorHTTPHandler middleware.AuthErrorHTTPHandler // optional HTTP handler for authentication errors
}

// NewService initializes everything
Expand All @@ -86,7 +86,7 @@ func NewService(opts Opts) (res *Service) {
AdminPasswd: opts.AdminPasswd,
BasicAuthChecker: opts.BasicAuthChecker,
RefreshCache: opts.RefreshCache,
AuthErrorHttpHandler: opts.AuthErrorHttpHandler,
AuthErrorHTTPHandler: opts.AuthErrorHTTPHandler,
},
issuer: opts.Issuer,
useGravatar: opts.UseGravatar,
Expand Down
22 changes: 11 additions & 11 deletions auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,16 +247,16 @@ func TestIntegrationList(t *testing.T) {
assert.Equal(t, `["dev","github","custom123"]`+"\n", string(b))
}

type testAuthErrorHttpHandler struct {
type testAuthErrorHTTPHandler struct {
wasCalled bool
statusCode int
contentType string
responseBody string
}

func (h *testAuthErrorHttpHandler) ServeAuthError(
func (h *testAuthErrorHTTPHandler) ServeAuthError(
w http.ResponseWriter,
r *http.Request,
_ *http.Request,
authError error,
reason string,
statusCode int,
Expand All @@ -268,22 +268,22 @@ func (h *testAuthErrorHttpHandler) ServeAuthError(
}

func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
testErrorHandler1 := &testAuthErrorHttpHandler{
testErrorHandler1 := &testAuthErrorHTTPHandler{
statusCode: 401,
contentType: "application/json",
responseBody: `{"code": 401, "message": "from general error handler"}`,
}
testErrorHandler2 := &testAuthErrorHttpHandler{
testErrorHandler2 := &testAuthErrorHTTPHandler{
statusCode: 403,
contentType: "text/html",
responseBody: `<html><body><h1>from private2 error handler</h1></body></html>`,
}
testErrorHandler3 := &testAuthErrorHttpHandler{
testErrorHandler3 := &testAuthErrorHTTPHandler{
statusCode: 403,
contentType: "application/json",
responseBody: `{"code": 401, "message": "from admin error handler"}`,
}
testErrorHandler4 := &testAuthErrorHttpHandler{
testErrorHandler4 := &testAuthErrorHTTPHandler{
statusCode: 403,
contentType: "text/html",
responseBody: `<html><body><h1>from RBAC error handler</h1></body></html>`,
Expand All @@ -297,7 +297,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {

svc := NewService(options)
svc.AddDevProvider("localhost", 18084) // add dev provider on 18084
svc.authMiddleware.AuthErrorHttpHandler = testErrorHandler1
svc.authMiddleware.AuthErrorHTTPHandler = testErrorHandler1

// setup http server
m := svc.Middleware()
Expand All @@ -312,7 +312,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
),
)
mux.Handle("/private2",
m.AuthWithErrorHttpHandler(
m.AuthWithErrorHTTPHandler(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { // token required
_, _ = w.Write([]byte("protected route2\n"))
Expand All @@ -331,7 +331,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
),
)
mux.Handle("/admin2",
m.AdminOnlyWithErrorHttpHandler(
m.AdminOnlyWithErrorHTTPHandler(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { // token required
_, _ = w.Write([]byte("admin route2\n"))
Expand All @@ -350,7 +350,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
),
)
mux.Handle("/rbac2",
m.RBACwithErrorHttpHandler(testErrorHandler4, "role1", "role2")(
m.RBACwithErrorHTTPHandler(testErrorHandler4, "role1", "role2")(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { // token required
_, _ = w.Write([]byte("rbac route2\n"))
Expand Down
66 changes: 34 additions & 32 deletions middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Authenticator struct {
AdminPasswd string
BasicAuthChecker BasicAuthFunc
RefreshCache RefreshCache
AuthErrorHttpHandler AuthErrorHttpHandler
AuthErrorHTTPHandler AuthErrorHTTPHandler
}

// RefreshCache defines interface storing and retrieving refreshed tokens
Expand All @@ -46,8 +46,8 @@ type TokenService interface {
// The second return parameter `User` need for add user claims into context of request.
type BasicAuthFunc func(user, passwd string) (ok bool, userInfo token.User, err error)

// AuthErrorHttpHandler defines interface for handling HTTP responses in case of authentication errors
type AuthErrorHttpHandler interface {
// AuthErrorHTTPHandler defines interface for handling HTTP responses in case of authentication errors
type AuthErrorHTTPHandler interface {
// Serves HTTP response in case of authentication error
// w - response writer
// r - original request
Expand All @@ -57,11 +57,13 @@ type AuthErrorHttpHandler interface {
ServeAuthError(w http.ResponseWriter, r *http.Request, authError error, reason string, statusCode int)
}

type DefaultAuthErrorHttpHandler struct {
// DefaultAuthErrorHTTPHandler is a default implementation, which writes text/plain responses using http.Error()
type DefaultAuthErrorHTTPHandler struct {
logger.L
}

func (h DefaultAuthErrorHttpHandler) ServeAuthError(w http.ResponseWriter, r *http.Request, authError error, reason string, statusCode int) {
// ServeAuthError writes text/plain responses using http.Error()
func (h DefaultAuthErrorHTTPHandler) ServeAuthError(w http.ResponseWriter, _ *http.Request, authError error, reason string, statusCode int) {
h.Logf("[DEBUG] auth failed, %v", authError)
http.Error(w, reason, statusCode)
}
Expand All @@ -77,29 +79,29 @@ var adminUser = token.User{

// Auth middleware adds auth from session and populates user info
func (a *Authenticator) Auth(next http.Handler) http.Handler {
return a.auth(true, a.getAuthErrorHttpHandler())(next)
return a.auth(true, a.getAuthErrorHTTPHandler())(next)
}

// Auth middleware adds auth from session and populates user info.
// AuthWithErrorHTTPHandler middleware adds auth from session and populates user info.
// errorHttpHandler parameter may be used to write custom HTTP responses in case of authentication error.
func (a *Authenticator) AuthWithErrorHttpHandler(next http.Handler, errorHttpHandler AuthErrorHttpHandler) http.Handler {
return a.auth(true, errorHttpHandler)(next)
func (a *Authenticator) AuthWithErrorHTTPHandler(next http.Handler, errorHTTPHandler AuthErrorHTTPHandler) http.Handler {
return a.auth(true, errorHTTPHandler)(next)
}

// Trace middleware doesn't require valid user but if user info presented populates info
func (a *Authenticator) Trace(next http.Handler) http.Handler {
return a.auth(false, a.getAuthErrorHttpHandler())(next)
return a.auth(false, a.getAuthErrorHTTPHandler())(next)
}

// auth implements all logic for authentication (reqAuth=true) and tracing (reqAuth=false)
func (a *Authenticator) auth(reqAuth bool, errorHttpHandler AuthErrorHttpHandler) func(http.Handler) http.Handler {
func (a *Authenticator) auth(reqAuth bool, errorHTTPHandler AuthErrorHTTPHandler) func(http.Handler) http.Handler {

onError := func(h http.Handler, w http.ResponseWriter, r *http.Request, err error) {
if !reqAuth { // if no auth required allow to proceeded on error
h.ServeHTTP(w, r)
return
}
errorHttpHandler.ServeAuthError(w, r, err, "Unauthorized", http.StatusUnauthorized)
errorHTTPHandler.ServeAuthError(w, r, err, "Unauthorized", http.StatusUnauthorized)
}

f := func(h http.Handler) http.Handler {
Expand Down Expand Up @@ -220,31 +222,31 @@ func (a *Authenticator) refreshExpiredToken(w http.ResponseWriter, claims token.
// AdminOnly middleware allows access for admins only.
// This handler internally wrapped with auth(true) to avoid situation if AdminOnly defined without prior Auth
func (a *Authenticator) AdminOnly(next http.Handler) http.Handler {
return a.adminOnly(next, a.getAuthErrorHttpHandler())
return a.adminOnly(next, a.getAuthErrorHTTPHandler())
}

// AdminOnly middleware allows access for admins only.
// AdminOnlyWithErrorHTTPHandler middleware allows access for admins only.
// This handler internally wrapped with auth(true) to avoid situation if AdminOnly defined without prior Auth.
// errorHttpHandler parameter may be used to write custom HTTP responses in case of authentication error.
func (a *Authenticator) AdminOnlyWithErrorHttpHandler(next http.Handler, errorHttpHandler AuthErrorHttpHandler) http.Handler {
return a.adminOnly(next, errorHttpHandler)
func (a *Authenticator) AdminOnlyWithErrorHTTPHandler(next http.Handler, errorHTTPHandler AuthErrorHTTPHandler) http.Handler {
return a.adminOnly(next, errorHTTPHandler)
}

func (a *Authenticator) adminOnly(next http.Handler, errorHttpHandler AuthErrorHttpHandler) http.Handler {
func (a *Authenticator) adminOnly(next http.Handler, errorHTTPHandler AuthErrorHTTPHandler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
user, err := token.GetUserInfo(r)
if err != nil {
errorHttpHandler.ServeAuthError(w, r, err, "Unauthorized", http.StatusUnauthorized)
errorHTTPHandler.ServeAuthError(w, r, err, "Unauthorized", http.StatusUnauthorized)
return
}

if !user.IsAdmin() {
errorHttpHandler.ServeAuthError(w, r, fmt.Errorf("user %s/%s is not admin", user.Name, user.ID), "Access denied", http.StatusForbidden)
errorHTTPHandler.ServeAuthError(w, r, fmt.Errorf("user %s/%s is not admin", user.Name, user.ID), "Access denied", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
}
return a.auth(true, errorHttpHandler)(http.HandlerFunc(fn)) // enforce auth
return a.auth(true, errorHTTPHandler)(http.HandlerFunc(fn)) // enforce auth
}

// basic auth for admin user
Expand All @@ -271,23 +273,23 @@ func (a *Authenticator) basicAdminUser(r *http.Request) bool {
// RBAC middleware allows role based control for routes
// this handler internally wrapped with auth(true) to avoid situation if RBAC defined without prior Auth
func (a *Authenticator) RBAC(roles ...string) func(http.Handler) http.Handler {
return a.rbac(a.getAuthErrorHttpHandler(), roles...)
return a.rbac(a.getAuthErrorHTTPHandler(), roles...)
}

// RBAC middleware allows role based control for routes
// RBACwithErrorHTTPHandler middleware allows role based control for routes
// this handler internally wrapped with auth(true) to avoid situation if RBAC defined without prior Auth
// errorHttpHandler parameter may be used to write custom HTTP responses in case of authentication error.
func (a *Authenticator) RBACwithErrorHttpHandler(errorHttpHandler AuthErrorHttpHandler, roles ...string) func(http.Handler) http.Handler {
return a.rbac(errorHttpHandler, roles...)
func (a *Authenticator) RBACwithErrorHTTPHandler(errorHTTPHandler AuthErrorHTTPHandler, roles ...string) func(http.Handler) http.Handler {
return a.rbac(errorHTTPHandler, roles...)
}

func (a *Authenticator) rbac(errorHttpHandler AuthErrorHttpHandler, roles ...string) func(http.Handler) http.Handler {
func (a *Authenticator) rbac(errorHTTPHandler AuthErrorHTTPHandler, roles ...string) func(http.Handler) http.Handler {

f := func(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
user, err := token.GetUserInfo(r)
if err != nil {
errorHttpHandler.ServeAuthError(w, r, err, "Unauthorized", http.StatusUnauthorized)
errorHTTPHandler.ServeAuthError(w, r, err, "Unauthorized", http.StatusUnauthorized)
return
}

Expand All @@ -299,7 +301,7 @@ func (a *Authenticator) rbac(errorHttpHandler AuthErrorHttpHandler, roles ...str
}
}
if !matched {
errorHttpHandler.ServeAuthError(
errorHTTPHandler.ServeAuthError(
w,
r,
fmt.Errorf("user %s/%s does not have any of required roles: %s", user.Name, user.ID, roles),
Expand All @@ -310,15 +312,15 @@ func (a *Authenticator) rbac(errorHttpHandler AuthErrorHttpHandler, roles ...str
}
h.ServeHTTP(w, r)
}
return a.auth(true, errorHttpHandler)(http.HandlerFunc(fn)) // enforce auth
return a.auth(true, errorHTTPHandler)(http.HandlerFunc(fn)) // enforce auth
}
return f
}

func (a *Authenticator) getAuthErrorHttpHandler() AuthErrorHttpHandler {
if a.AuthErrorHttpHandler != nil {
return a.AuthErrorHttpHandler
func (a *Authenticator) getAuthErrorHTTPHandler() AuthErrorHTTPHandler {
if a.AuthErrorHTTPHandler != nil {
return a.AuthErrorHTTPHandler
}

return DefaultAuthErrorHttpHandler{L: a.L}
return DefaultAuthErrorHTTPHandler{L: a.L}
}
4 changes: 2 additions & 2 deletions v2/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type Opts struct {
AudSecrets bool // allow multiple secrets (secret per aud)
Logger logger.L // logger interface, default is no logging at all
RefreshCache middleware.RefreshCache // optional cache to keep refreshed tokens
AuthErrorHttpHandler middleware.AuthErrorHttpHandler // optional HTTP handler for authentication errors
AuthErrorHTTPHandler middleware.AuthErrorHTTPHandler // optional HTTP handler for authentication errors
}

// NewService initializes everything
Expand All @@ -86,7 +86,7 @@ func NewService(opts Opts) (res *Service) {
AdminPasswd: opts.AdminPasswd,
BasicAuthChecker: opts.BasicAuthChecker,
RefreshCache: opts.RefreshCache,
AuthErrorHttpHandler: opts.AuthErrorHttpHandler,
AuthErrorHTTPHandler: opts.AuthErrorHTTPHandler,
},
issuer: opts.Issuer,
useGravatar: opts.UseGravatar,
Expand Down
22 changes: 11 additions & 11 deletions v2/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,16 +247,16 @@ func TestIntegrationList(t *testing.T) {
assert.Equal(t, `["dev","github","custom123"]`+"\n", string(b))
}

type testAuthErrorHttpHandler struct {
type testAuthErrorHTTPHandler struct {
wasCalled bool
statusCode int
contentType string
responseBody string
}

func (h *testAuthErrorHttpHandler) ServeAuthError(
func (h *testAuthErrorHTTPHandler) ServeAuthError(
w http.ResponseWriter,
r *http.Request,
_ *http.Request,
authError error,
reason string,
statusCode int,
Expand All @@ -268,22 +268,22 @@ func (h *testAuthErrorHttpHandler) ServeAuthError(
}

func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
testErrorHandler1 := &testAuthErrorHttpHandler{
testErrorHandler1 := &testAuthErrorHTTPHandler{
statusCode: 401,
contentType: "application/json",
responseBody: `{"code": 401, "message": "from general error handler"}`,
}
testErrorHandler2 := &testAuthErrorHttpHandler{
testErrorHandler2 := &testAuthErrorHTTPHandler{
statusCode: 403,
contentType: "text/html",
responseBody: `<html><body><h1>from private2 error handler</h1></body></html>`,
}
testErrorHandler3 := &testAuthErrorHttpHandler{
testErrorHandler3 := &testAuthErrorHTTPHandler{
statusCode: 403,
contentType: "application/json",
responseBody: `{"code": 401, "message": "from admin error handler"}`,
}
testErrorHandler4 := &testAuthErrorHttpHandler{
testErrorHandler4 := &testAuthErrorHTTPHandler{
statusCode: 403,
contentType: "text/html",
responseBody: `<html><body><h1>from RBAC error handler</h1></body></html>`,
Expand All @@ -297,7 +297,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {

svc := NewService(options)
svc.AddDevProvider("localhost", 18084) // add dev provider on 18084
svc.authMiddleware.AuthErrorHttpHandler = testErrorHandler1
svc.authMiddleware.AuthErrorHTTPHandler = testErrorHandler1

// setup http server
m := svc.Middleware()
Expand All @@ -312,7 +312,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
),
)
mux.Handle("/private2",
m.AuthWithErrorHttpHandler(
m.AuthWithErrorHTTPHandler(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { // token required
_, _ = w.Write([]byte("protected route2\n"))
Expand All @@ -331,7 +331,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
),
)
mux.Handle("/admin2",
m.AdminOnlyWithErrorHttpHandler(
m.AdminOnlyWithErrorHTTPHandler(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { // token required
_, _ = w.Write([]byte("admin route2\n"))
Expand All @@ -350,7 +350,7 @@ func TestIntegrationAuthErrorHttpHandler(t *testing.T) {
),
)
mux.Handle("/rbac2",
m.RBACwithErrorHttpHandler(testErrorHandler4, "role1", "role2")(
m.RBACwithErrorHTTPHandler(testErrorHandler4, "role1", "role2")(
http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { // token required
_, _ = w.Write([]byte("rbac route2\n"))
Expand Down
Loading

0 comments on commit 6ec7d89

Please sign in to comment.