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:
parent
a3a7df91e3
commit
ea022ede46
@ -144,26 +144,28 @@ func (auth *Authorizer) HasPermissions(group string, perms ...Permission) bool {
|
|||||||
return groupAuth.Has(perms...)
|
return groupAuth.Has(perms...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middleware returns an HTTP handler which verifies if the request is performed by a user with a
|
// IsRejected verifies that r is from a user who belongs to a group that has all perms and returns
|
||||||
// role that allows all the passed permissions.
|
// false, otherwise responds with http.StatusUnauthorized using
|
||||||
func (auth *Authorizer) Middleware(next http.Handler, perms ...Permission) http.Handler {
|
// storj.io/storj/private.api.ServeError and returns true.
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
//
|
||||||
|
// 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")
|
groupsh := r.Header.Get("X-Forwarded-Groups")
|
||||||
if groupsh == "" {
|
if groupsh == "" {
|
||||||
err := Error.Wrap(ErrAuthorizer.New("You do not belong to any group"))
|
err := Error.Wrap(ErrAuthorizer.New("You do not belong to any group"))
|
||||||
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
|
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
groups := strings.Split(groupsh, ",")
|
groups := strings.Split(groupsh, ",")
|
||||||
for _, g := range groups {
|
for _, g := range groups {
|
||||||
if auth.HasPermissions(g, perms...) {
|
if auth.HasPermissions(g, perms...) {
|
||||||
next.ServeHTTP(w, r)
|
return false
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := Error.Wrap(ErrAuthorizer.New("Not enough permissions (your groups: %s)", groupsh))
|
err := Error.Wrap(ErrAuthorizer.New("Not enough permissions (your groups: %s)", groupsh))
|
||||||
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
|
api.ServeError(auth.log, w, http.StatusUnauthorized, err)
|
||||||
})
|
return true
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ func TestAuthorizer(t *testing.T) {
|
|||||||
require.Equal(t, c.hasAccess, auth.HasPermissions(c.group, c.permissions...))
|
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)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req.Header.Add("X-Forwarded-Groups", c.group)
|
req.Header.Add("X-Forwarded-Groups", c.group)
|
||||||
@ -163,19 +163,17 @@ func TestAuthorizer(t *testing.T) {
|
|||||||
wbuff := &bytes.Buffer{}
|
wbuff := &bytes.Buffer{}
|
||||||
w.Body = wbuff
|
w.Body = wbuff
|
||||||
|
|
||||||
nextCalled := false
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
if auth.IsRejected(w, r, c.permissions...) {
|
||||||
nextCalled = true
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
handler := auth.Middleware(next, c.permissions...)
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
|
|
||||||
if c.hasAccess {
|
if c.hasAccess {
|
||||||
assert.True(t, nextCalled, "Next handler is called")
|
|
||||||
assert.Equal(t, http.StatusOK, w.Code, "HTTP Status Code")
|
assert.Equal(t, http.StatusOK, w.Code, "HTTP Status Code")
|
||||||
} else {
|
} else {
|
||||||
assert.False(t, nextCalled, "Next handler is called")
|
|
||||||
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
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))
|
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)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req.Header.Add("X-Forwarded-Groups", "everyone-else,super")
|
req.Header.Add("X-Forwarded-Groups", "everyone-else,super")
|
||||||
@ -191,18 +189,18 @@ func TestAuthorizer(t *testing.T) {
|
|||||||
wbuff := &bytes.Buffer{}
|
wbuff := &bytes.Buffer{}
|
||||||
w.Body = wbuff
|
w.Body = wbuff
|
||||||
|
|
||||||
nextCalled := false
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
|
||||||
nextCalled = true
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
assert.True(t, nextCalled, "Next handler is called")
|
|
||||||
assert.Equal(t, http.StatusOK, w.Code, "HTTP Status Code")
|
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)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req.Header.Add("X-Forwarded-Groups", "customers-troubleshooter,everyone-else")
|
req.Header.Add("X-Forwarded-Groups", "customers-troubleshooter,everyone-else")
|
||||||
@ -210,19 +208,19 @@ func TestAuthorizer(t *testing.T) {
|
|||||||
wbuff := &bytes.Buffer{}
|
wbuff := &bytes.Buffer{}
|
||||||
w.Body = wbuff
|
w.Body = wbuff
|
||||||
|
|
||||||
nextCalled := false
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
|
||||||
nextCalled = true
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
assert.False(t, nextCalled, "Next handler is called")
|
|
||||||
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
||||||
assert.Contains(t, wbuff.String(), `Not enough permissions (your groups: customers-troubleshooter,everyone-else)`)
|
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)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req.Header.Add("X-Forwarded-Groups", "engineering")
|
req.Header.Add("X-Forwarded-Groups", "engineering")
|
||||||
@ -230,33 +228,33 @@ func TestAuthorizer(t *testing.T) {
|
|||||||
wbuff := &bytes.Buffer{}
|
wbuff := &bytes.Buffer{}
|
||||||
w.Body = wbuff
|
w.Body = wbuff
|
||||||
|
|
||||||
nextCalled := false
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
|
||||||
nextCalled = true
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
assert.False(t, nextCalled, "Next handler is called")
|
|
||||||
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
||||||
assert.Contains(t, wbuff.String(), `Not enough permissions (your groups: engineering)`)
|
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)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.test", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
wbuff := &bytes.Buffer{}
|
wbuff := &bytes.Buffer{}
|
||||||
w.Body = wbuff
|
w.Body = wbuff
|
||||||
|
|
||||||
nextCalled := false
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
if auth.IsRejected(w, r, admin.PermAccountDeleteWithData) {
|
||||||
nextCalled = true
|
return
|
||||||
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
})
|
})
|
||||||
handler := auth.Middleware(next, admin.PermAccountDeleteWithData)
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
assert.False(t, nextCalled, "Next handler is called")
|
|
||||||
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
assert.Equal(t, http.StatusUnauthorized, w.Code, "HTTP Status Code")
|
||||||
assert.Contains(t, wbuff.String(), "You do not belong to any group")
|
assert.Contains(t, wbuff.String(), "You do not belong to any group")
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user