satellite/admin/back-office: Add method for auth middleware

Add a new method to the Authorizer to use it with the API midleware that
we are going to implement for injecting it into the handler generated by
the API generator.

This new method will reduce the lines of code to generate and avoiding
errors that are more difficult to test in generated code.

The commit deletes the Middleware method because we won't used due to
the API generator doesn't support "standard" middlewares and allows
their customization via code generated and injected inside the handler
base logic generated by the API generator.

Change-Id: Ie427eb2eea94797913e2c357cf097ecf1e2e63ef
This commit is contained in:
Ivan Fraixedes 2023-11-20 16:40:15 +01:00 committed by Storj Robot
parent a3a7df91e3
commit ea022ede46
2 changed files with 52 additions and 52 deletions

View File

@ -144,26 +144,28 @@ func (auth *Authorizer) HasPermissions(group string, perms ...Permission) bool {
return groupAuth.Has(perms...)
}
// Middleware returns an HTTP handler which verifies if the request is performed by a user with a
// role that allows all the passed permissions.
func (auth *Authorizer) Middleware(next http.Handler, perms ...Permission) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
groupsh := r.Header.Get("X-Forwarded-Groups")
if groupsh == "" {
err := Error.Wrap(ErrAuthorizer.New("You do not belong to any group"))
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
return
}
groups := strings.Split(groupsh, ",")
for _, g := range groups {
if auth.HasPermissions(g, perms...) {
next.ServeHTTP(w, r)
return
}
}
err := Error.Wrap(ErrAuthorizer.New("Not enough permissions (your groups: %s)", groupsh))
// IsRejected verifies that r is from a user who belongs to a group that has all perms and returns
// false, otherwise responds with http.StatusUnauthorized using
// storj.io/storj/private.api.ServeError and returns true.
//
// This method is convenient to inject it to the handlers generated by the API generator through a
// customized handler.
func (auth *Authorizer) IsRejected(w http.ResponseWriter, r *http.Request, perms ...Permission) bool {
groupsh := r.Header.Get("X-Forwarded-Groups")
if groupsh == "" {
err := Error.Wrap(ErrAuthorizer.New("You do not belong to any group"))
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
})
return true
}
groups := strings.Split(groupsh, ",")
for _, g := range groups {
if auth.HasPermissions(g, perms...) {
return false
}
}
err := Error.Wrap(ErrAuthorizer.New("Not enough permissions (your groups: %s)", groupsh))
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
return true
}

View File

@ -155,7 +155,7 @@ func TestAuthorizer(t *testing.T) {
require.Equal(t, c.hasAccess, auth.HasPermissions(c.group, c.permissions...))
})
t.Run("Middleware", func(t *testing.T) {
t.Run("isRejected", func(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
require.NoError(t, err)
req.Header.Add("X-Forwarded-Groups", c.group)
@ -163,19 +163,17 @@ func TestAuthorizer(t *testing.T) {
wbuff := &bytes.Buffer{}
w.Body = wbuff
nextCalled := false
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
nextCalled = true
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if auth.IsRejected(w, r, c.permissions...) {
return
}
w.WriteHeader(http.StatusOK)
})
handler := auth.Middleware(next, c.permissions...)
handler.ServeHTTP(w, req)
if c.hasAccess {
assert.True(t, nextCalled, "Next handler is called")
assert.Equal(t, http.StatusOK, w.Code, "HTTP Status Code")
} else {
assert.False(t, nextCalled, "Next handler is called")
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
assert.Contains(t, wbuff.String(), fmt.Sprintf(`Not enough permissions (your groups: %s)`, c.group))
}
@ -183,7 +181,7 @@ func TestAuthorizer(t *testing.T) {
})
}
t.Run("Middleware request with multiple groups one has the permissions", func(t *testing.T) {
t.Run("IsRejected request with multiple groups one has the permissions", func(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
require.NoError(t, err)
req.Header.Add("X-Forwarded-Groups", "everyone-else,super")
@ -191,18 +189,18 @@ func TestAuthorizer(t *testing.T) {
wbuff := &bytes.Buffer{}
w.Body = wbuff
nextCalled := false
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
nextCalled = true
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
return
}
w.WriteHeader(http.StatusOK)
})
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
handler.ServeHTTP(w, req)
assert.True(t, nextCalled, "Next handler is called")
assert.Equal(t, http.StatusOK, w.Code, "HTTP Status Code")
})
t.Run("Middleware request with multiple groups none has all the permissions", func(t *testing.T) {
t.Run("IsRejected request with multiple groups none has all the permissions", func(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
require.NoError(t, err)
req.Header.Add("X-Forwarded-Groups", "customers-troubleshooter,everyone-else")
@ -210,19 +208,19 @@ func TestAuthorizer(t *testing.T) {
wbuff := &bytes.Buffer{}
w.Body = wbuff
nextCalled := false
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
nextCalled = true
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
return
}
w.WriteHeader(http.StatusOK)
})
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
handler.ServeHTTP(w, req)
assert.False(t, nextCalled, "Next handler is called")
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
assert.Contains(t, wbuff.String(), `Not enough permissions (your groups: customers-troubleshooter,everyone-else)`)
})
t.Run("Middleware request with a unauthorized group", func(t *testing.T) {
t.Run("IsRejected request with a unauthorized group", func(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
require.NoError(t, err)
req.Header.Add("X-Forwarded-Groups", "engineering")
@ -230,33 +228,33 @@ func TestAuthorizer(t *testing.T) {
wbuff := &bytes.Buffer{}
w.Body = wbuff
nextCalled := false
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
nextCalled = true
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
return
}
w.WriteHeader(http.StatusOK)
})
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
handler.ServeHTTP(w, req)
assert.False(t, nextCalled, "Next handler is called")
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
assert.Contains(t, wbuff.String(), `Not enough permissions (your groups: engineering)`)
})
t.Run("Middleware request with no groups", func(t *testing.T) {
t.Run("IsRejected request with no groups", func(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
require.NoError(t, err)
w := httptest.NewRecorder()
wbuff := &bytes.Buffer{}
w.Body = wbuff
nextCalled := false
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
nextCalled = true
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
return
}
w.WriteHeader(http.StatusOK)
})
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
handler.ServeHTTP(w, req)
assert.False(t, nextCalled, "Next handler is called")
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
assert.Contains(t, wbuff.String(), "You do not belong to any group")
})