Merge pull request #1033 from jlhawn/api_spec_update_auth_errors

[api spec] Update authN and authZ errors
This commit is contained in:
Stephen Day 2015-10-13 13:52:18 -07:00
commit bfd1f423c5
4 changed files with 1554 additions and 554 deletions

View file

@ -53,6 +53,7 @@ func main() {
ErrorDescriptors: append(errcode.GetErrorCodeGroup("registry.api.v2"), ErrorDescriptors: append(errcode.GetErrorCodeGroup("registry.api.v2"),
// The following are part of the specification but provided by errcode default. // The following are part of the specification but provided by errcode default.
errcode.ErrorCodeUnauthorized.Descriptor(), errcode.ErrorCodeUnauthorized.Descriptor(),
errcode.ErrorCodeDenied.Descriptor(),
errcode.ErrorCodeUnsupported.Descriptor()), errcode.ErrorCodeUnsupported.Descriptor()),
} }

File diff suppressed because it is too large Load diff

View file

@ -33,16 +33,28 @@ var (
HTTPStatusCode: http.StatusMethodNotAllowed, HTTPStatusCode: http.StatusMethodNotAllowed,
}) })
// ErrorCodeUnauthorized is returned if a request is not authorized. // ErrorCodeUnauthorized is returned if a request requires
// authentication.
ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{ ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
Value: "UNAUTHORIZED", Value: "UNAUTHORIZED",
Message: "access to the requested resource is not authorized", Message: "authentication required",
Description: `The access controller denied access for the operation on Description: `The access controller was unable to authenticate
a resource. Often this will be accompanied by a 401 Unauthorized the client. Often this will be accompanied by a
response status.`, Www-Authenticate HTTP response header indicating how to
authenticate.`,
HTTPStatusCode: http.StatusUnauthorized, HTTPStatusCode: http.StatusUnauthorized,
}) })
// ErrorCodeDenied is returned if a client does not have sufficient
// permission to perform an action.
ErrorCodeDenied = Register("errcode", ErrorDescriptor{
Value: "DENIED",
Message: "requested access to the resource is denied",
Description: `The access controller denied access for the
operation on a resource.`,
HTTPStatusCode: http.StatusForbidden,
})
// ErrorCodeUnavailable provides a common error to report unavialability // ErrorCodeUnavailable provides a common error to report unavialability
// of a service or endpoint. // of a service or endpoint.
ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{ ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{

View file

@ -112,45 +112,67 @@ var (
}, },
} }
unauthorizedResponse = ResponseDescriptor{ unauthorizedResponseDescriptor = ResponseDescriptor{
Description: "The client does not have access to the repository.", Name: "Authentication Required",
StatusCode: http.StatusUnauthorized, StatusCode: http.StatusUnauthorized,
Description: "The client is not authenticated.",
Headers: []ParameterDescriptor{ Headers: []ParameterDescriptor{
authChallengeHeader, authChallengeHeader,
{ {
Name: "Content-Length", Name: "Content-Length",
Type: "integer", Type: "integer",
Description: "Length of the JSON error response body.", Description: "Length of the JSON response body.",
Format: "<length>", Format: "<length>",
}, },
}, },
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
Body: BodyDescriptor{ Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8", ContentType: "application/json; charset=utf-8",
Format: unauthorizedErrorsBody, Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
}, },
} }
unauthorizedResponsePush = ResponseDescriptor{ repositoryNotFoundResponseDescriptor = ResponseDescriptor{
Description: "The client does not have access to push to the repository.", Name: "No Such Repository Error",
StatusCode: http.StatusUnauthorized, StatusCode: http.StatusNotFound,
Description: "The repository is not known to the registry.",
Headers: []ParameterDescriptor{ Headers: []ParameterDescriptor{
authChallengeHeader,
{ {
Name: "Content-Length", Name: "Content-Length",
Type: "integer", Type: "integer",
Description: "Length of the JSON error response body.", Description: "Length of the JSON response body.",
Format: "<length>", Format: "<length>",
}, },
}, },
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized, ErrorCodeNameUnknown,
},
}
deniedResponseDescriptor = ResponseDescriptor{
Name: "Access Denied",
StatusCode: http.StatusForbidden,
Description: "The client does not have required access to the repository.",
Headers: []ParameterDescriptor{
{
Name: "Content-Length",
Type: "integer",
Description: "Length of the JSON response body.",
Format: "<length>",
},
}, },
Body: BodyDescriptor{ Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8", ContentType: "application/json; charset=utf-8",
Format: unauthorizedErrorsBody, Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeDenied,
}, },
} }
) )
@ -346,7 +368,7 @@ var routeDescriptors = []RouteDescriptor{
Name: RouteNameBase, Name: RouteNameBase,
Path: "/v2/", Path: "/v2/",
Entity: "Base", Entity: "Base",
Description: `Base V2 API route. Typically, this can be used for lightweight version checks and to validate registry authorization.`, Description: `Base V2 API route. Typically, this can be used for lightweight version checks and to validate registry authentication.`,
Methods: []MethodDescriptor{ Methods: []MethodDescriptor{
{ {
Method: "GET", Method: "GET",
@ -364,24 +386,11 @@ var routeDescriptors = []RouteDescriptor{
}, },
}, },
Failures: []ResponseDescriptor{ Failures: []ResponseDescriptor{
{
Description: "The client is not authorized to access the registry.",
StatusCode: http.StatusUnauthorized,
Headers: []ParameterDescriptor{
authChallengeHeader,
},
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
},
{ {
Description: "The registry does not implement the V2 API.", Description: "The registry does not implement the V2 API.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
}, },
unauthorizedResponseDescriptor,
}, },
}, },
}, },
@ -433,28 +442,9 @@ var routeDescriptors = []RouteDescriptor{
}, },
}, },
Failures: []ResponseDescriptor{ Failures: []ResponseDescriptor{
{ unauthorizedResponseDescriptor,
StatusCode: http.StatusNotFound, repositoryNotFoundResponseDescriptor,
Description: "The repository is not known to the registry.", deniedResponseDescriptor,
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
ErrorCodeNameUnknown,
},
},
{
StatusCode: http.StatusUnauthorized,
Description: "The client does not have access to the repository.",
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
},
}, },
}, },
{ {
@ -488,28 +478,9 @@ var routeDescriptors = []RouteDescriptor{
}, },
}, },
Failures: []ResponseDescriptor{ Failures: []ResponseDescriptor{
{ unauthorizedResponseDescriptor,
StatusCode: http.StatusNotFound, repositoryNotFoundResponseDescriptor,
Description: "The repository is not known to the registry.", deniedResponseDescriptor,
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
ErrorCodeNameUnknown,
},
},
{
StatusCode: http.StatusUnauthorized,
Description: "The client does not have access to the repository.",
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
},
}, },
}, },
}, },
@ -561,29 +532,9 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
{ unauthorizedResponseDescriptor,
StatusCode: http.StatusUnauthorized, repositoryNotFoundResponseDescriptor,
Description: "The client does not have access to the repository.", deniedResponseDescriptor,
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
},
{
Description: "The named manifest is not known to the registry.",
StatusCode: http.StatusNotFound,
ErrorCodes: []errcode.ErrorCode{
ErrorCodeNameUnknown,
ErrorCodeManifestUnknown,
},
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
},
}, },
}, },
}, },
@ -638,17 +589,9 @@ var routeDescriptors = []RouteDescriptor{
ErrorCodeBlobUnknown, ErrorCodeBlobUnknown,
}, },
}, },
{ unauthorizedResponseDescriptor,
StatusCode: http.StatusUnauthorized, repositoryNotFoundResponseDescriptor,
Description: "The client does not have permission to push to the repository.", deniedResponseDescriptor,
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
},
{ {
Name: "Missing Layer(s)", Name: "Missing Layer(s)",
Description: "One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.", Description: "One or more layers may be missing during a manifest upload. If so, the missing layers will be enumerated in the error response.",
@ -671,25 +614,6 @@ var routeDescriptors = []RouteDescriptor{
}`, }`,
}, },
}, },
{
StatusCode: http.StatusUnauthorized,
Headers: []ParameterDescriptor{
authChallengeHeader,
{
Name: "Content-Length",
Type: "integer",
Description: "Length of the JSON error response body.",
Format: "<length>",
},
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
},
{ {
Name: "Not allowed", Name: "Not allowed",
Description: "Manifest put is not allowed because the registry is configured as a pull-through cache or for some other reason", Description: "Manifest put is not allowed because the registry is configured as a pull-through cache or for some other reason",
@ -734,25 +658,9 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
{ unauthorizedResponseDescriptor,
StatusCode: http.StatusUnauthorized, repositoryNotFoundResponseDescriptor,
Headers: []ParameterDescriptor{ deniedResponseDescriptor,
authChallengeHeader,
{
Name: "Content-Length",
Type: "integer",
Description: "Length of the JSON error response body.",
Format: "<length>",
},
},
ErrorCodes: []errcode.ErrorCode{
errcode.ErrorCodeUnauthorized,
},
Body: BodyDescriptor{
ContentType: "application/json; charset=utf-8",
Format: errorsBody,
},
},
{ {
Name: "Unknown Manifest", Name: "Unknown Manifest",
Description: "The specified `name` or `reference` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.", Description: "The specified `name` or `reference` are unknown to the registry and the delete was unable to proceed. Clients can assume the manifest was already deleted if this response is returned.",
@ -846,7 +754,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponse,
{ {
Description: "The blob, identified by `name` and `digest`, is unknown to the registry.", Description: "The blob, identified by `name` and `digest`, is unknown to the registry.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
@ -859,6 +766,9 @@ var routeDescriptors = []RouteDescriptor{
ErrorCodeBlobUnknown, ErrorCodeBlobUnknown,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
{ {
@ -915,7 +825,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponse,
{ {
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
ErrorCodes: []errcode.ErrorCode{ ErrorCodes: []errcode.ErrorCode{
@ -931,6 +840,9 @@ var routeDescriptors = []RouteDescriptor{
Description: "The range specification cannot be satisfied for the requested content. This can happen when the range is not formatted correctly or if the range is outside of the valid size of the content.", Description: "The range specification cannot be satisfied for the requested content. This can happen when the range is not formatted correctly or if the range is outside of the valid size of the content.",
StatusCode: http.StatusRequestedRangeNotSatisfiable, StatusCode: http.StatusRequestedRangeNotSatisfiable,
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },
@ -994,6 +906,9 @@ var routeDescriptors = []RouteDescriptor{
errcode.ErrorCodeUnsupported, errcode.ErrorCodeUnsupported,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },
@ -1067,7 +982,6 @@ var routeDescriptors = []RouteDescriptor{
ErrorCodeNameInvalid, ErrorCodeNameInvalid,
}, },
}, },
unauthorizedResponsePush,
{ {
Name: "Not allowed", Name: "Not allowed",
Description: "Blob upload is not allowed because the registry is configured as a pull-through cache or for some other reason", Description: "Blob upload is not allowed because the registry is configured as a pull-through cache or for some other reason",
@ -1076,6 +990,9 @@ var routeDescriptors = []RouteDescriptor{
errcode.ErrorCodeUnsupported, errcode.ErrorCodeUnsupported,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
{ {
@ -1119,7 +1036,9 @@ var routeDescriptors = []RouteDescriptor{
ErrorCodeNameInvalid, ErrorCodeNameInvalid,
}, },
}, },
unauthorizedResponsePush, unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },
@ -1178,7 +1097,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponse,
{ {
Description: "The upload is unknown to the registry. The upload must be restarted.", Description: "The upload is unknown to the registry. The upload must be restarted.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
@ -1190,6 +1108,9 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },
@ -1250,7 +1171,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponsePush,
{ {
Description: "The upload is unknown to the registry. The upload must be restarted.", Description: "The upload is unknown to the registry. The upload must be restarted.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
@ -1262,6 +1182,9 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
{ {
@ -1329,7 +1252,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponsePush,
{ {
Description: "The upload is unknown to the registry. The upload must be restarted.", Description: "The upload is unknown to the registry. The upload must be restarted.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
@ -1345,6 +1267,9 @@ var routeDescriptors = []RouteDescriptor{
Description: "The `Content-Range` specification cannot be accepted, either because it does not overlap with the current progress or it is invalid.", Description: "The `Content-Range` specification cannot be accepted, either because it does not overlap with the current progress or it is invalid.",
StatusCode: http.StatusRequestedRangeNotSatisfiable, StatusCode: http.StatusRequestedRangeNotSatisfiable,
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },
@ -1421,7 +1346,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponsePush,
{ {
Description: "The upload is unknown to the registry. The upload must be restarted.", Description: "The upload is unknown to the registry. The upload must be restarted.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
@ -1433,6 +1357,9 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },
@ -1475,7 +1402,6 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponse,
{ {
Description: "The upload is unknown to the registry. The client may ignore this error and assume the upload has been deleted.", Description: "The upload is unknown to the registry. The client may ignore this error and assume the upload has been deleted.",
StatusCode: http.StatusNotFound, StatusCode: http.StatusNotFound,
@ -1487,6 +1413,9 @@ var routeDescriptors = []RouteDescriptor{
Format: errorsBody, Format: errorsBody,
}, },
}, },
unauthorizedResponseDescriptor,
repositoryNotFoundResponseDescriptor,
deniedResponseDescriptor,
}, },
}, },
}, },