Ensure that unset Context.Name only allowed on base route
If Context.Name is not set, the acceess controller may allow an unintended request through. By only allowing a request to proceed without a name on the base route, we provide some protection if future bugs forget to set the context properly.
This commit is contained in:
parent
e50fcc0ab9
commit
b1f36c3fe5
3 changed files with 55 additions and 30 deletions
78
app.go
78
app.go
|
@ -172,36 +172,56 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont
|
|||
}
|
||||
|
||||
var accessRecords []auth.Access
|
||||
resource := auth.Resource{
|
||||
Type: "repository",
|
||||
Name: context.Name,
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case "GET", "HEAD":
|
||||
accessRecords = append(accessRecords,
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "pull",
|
||||
})
|
||||
case "POST", "PUT", "PATCH":
|
||||
accessRecords = append(accessRecords,
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "pull",
|
||||
},
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "push",
|
||||
})
|
||||
case "DELETE":
|
||||
// DELETE access requires full admin rights, which is represented
|
||||
// as "*". This may not be ideal.
|
||||
accessRecords = append(accessRecords,
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "*",
|
||||
})
|
||||
if context.Name != "" {
|
||||
resource := auth.Resource{
|
||||
Type: "repository",
|
||||
Name: context.Name,
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case "GET", "HEAD":
|
||||
accessRecords = append(accessRecords,
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "pull",
|
||||
})
|
||||
case "POST", "PUT", "PATCH":
|
||||
accessRecords = append(accessRecords,
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "pull",
|
||||
},
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "push",
|
||||
})
|
||||
case "DELETE":
|
||||
// DELETE access requires full admin rights, which is represented
|
||||
// as "*". This may not be ideal.
|
||||
accessRecords = append(accessRecords,
|
||||
auth.Access{
|
||||
Resource: resource,
|
||||
Action: "*",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Only allow the name not to be set on the base route.
|
||||
route := mux.CurrentRoute(r)
|
||||
|
||||
if route == nil || route.GetName() != v2.RouteNameBase {
|
||||
// For this to be properly secured, context.Name must always be set
|
||||
// for a resource that may make a modification. The only condition
|
||||
// under which name is not set and we still allow access is when the
|
||||
// base route is accessed. This section prevents us from making that
|
||||
// mistake elsewhere in the code, allowing any operation to proceed.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
|
||||
var errs v2.Errors
|
||||
errs.Push(v2.ErrorCodeUnauthorized)
|
||||
serveJSON(w, errs)
|
||||
}
|
||||
}
|
||||
|
||||
if err := app.accessController.Authorized(r, accessRecords...); err != nil {
|
||||
|
|
|
@ -177,6 +177,11 @@ func TestNewApp(t *testing.T) {
|
|||
t.Fatalf("unexpected content-type: %v != %v", req.Header.Get("Content-Type"), "application/json")
|
||||
}
|
||||
|
||||
expectedAuthHeader := "Bearer realm=\"realm-test\",service=\"service-test\""
|
||||
if req.Header.Get("Authorization") != expectedAuthHeader {
|
||||
t.Fatalf("unexpected authorization header: %q != %q", req.Header.Get("Authorization"), expectedAuthHeader)
|
||||
}
|
||||
|
||||
var errs v2.Errors
|
||||
dec := json.NewDecoder(req.Body)
|
||||
if err := dec.Decode(&errs); err != nil {
|
||||
|
|
|
@ -51,7 +51,7 @@ func (ac *accessController) Authorized(req *http.Request, accessRecords ...auth.
|
|||
if len(accessRecords) > 0 {
|
||||
var scopes []string
|
||||
for _, access := range accessRecords {
|
||||
scopes = append(scopes, fmt.Sprintf("%s:%s:%s", access.Type, access.Resource, access.Action))
|
||||
scopes = append(scopes, fmt.Sprintf("%s:%s:%s", access.Type, access.Resource.Name, access.Action))
|
||||
}
|
||||
challenge.scope = strings.Join(scopes, " ")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue