diff --git a/api/server.go b/api/server.go index 264dff5..1ad3202 100644 --- a/api/server.go +++ b/api/server.go @@ -28,6 +28,18 @@ type Server struct { options string } +func responseCodeToHTTP(responseCode uint32) int { + // Plugin should return 200 on success, 400 for caller input errors, and 500 for everything else. + switch responseCode { + case 200: + return http.StatusOK + case 400: + return http.StatusBadRequest + default: + return http.StatusInternalServerError + } +} + func NewServer(logger *zap.SugaredLogger, manager plugin.IManager, options string) *Server { return &Server{ logger: logger, @@ -215,7 +227,7 @@ func (s *Server) RatsdChares(w http.ResponseWriter, r *http.Request, param Ratsd if !out.Status.Result { errMsg := fmt.Sprintf( "failed to get attestation report from %s: %s ", pn, out.Status.Error) - p := problems.NewDetailedProblem(http.StatusInternalServerError, errMsg) + p := problems.NewDetailedProblem(responseCodeToHTTP(out.StatusCode), errMsg) s.reportProblem(w, p) return false } diff --git a/attesters/mocktsm/mocktsm.go b/attesters/mocktsm/mocktsm.go index 58a658e..5da4cbd 100644 --- a/attesters/mocktsm/mocktsm.go +++ b/attesters/mocktsm/mocktsm.go @@ -5,6 +5,7 @@ package mocktsm import ( "encoding/json" "fmt" + "net/http" "strconv" "github.com/google/go-configfs-tsm/configfs/configfsi" @@ -39,11 +40,12 @@ type MockPlugin struct { client *faketsm.Client } -func getEvidenceError(e error) *compositor.EvidenceOut { +func getEvidenceError(e error, statusCode uint32) *compositor.EvidenceOut { return &compositor.EvidenceOut{ Status: &compositor.Status{ Result: false, Error: e.Error(), }, + StatusCode: statusCode, } } @@ -78,13 +80,13 @@ func (m *MockPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.Evidence errMsg := fmt.Errorf( "nonce size of the mockTSM attester should be %d, got %d", nonceSize, uint32(len(in.Nonce))) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } if in.ContentType != mediaType { errMsg := fmt.Errorf( "no supported format in mock TSM plugin matches the requested format") - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } req := &report.Request{ InBlob: in.Nonce, @@ -96,7 +98,7 @@ func (m *MockPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.Evidence if err := json.Unmarshal(in.Options, &options); err != nil { errMsg := fmt.Errorf( "failed to parse %s: %v", in.Options, err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } } @@ -105,7 +107,7 @@ func (m *MockPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.Evidence if err != nil || level < 0 { errMsg := fmt.Errorf("privilege_level %s is invalid", privlevel) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } req.Privilege = &report.Privilege{Level: uint(level)} } @@ -113,7 +115,7 @@ func (m *MockPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.Evidence resp, err := report.Get(m.client, req) if err != nil { errMsg := fmt.Errorf("failed to get mock TSM report: %v", err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusInternalServerError) } out := &tokens.TSMReport{ @@ -125,12 +127,13 @@ func (m *MockPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.Evidence outEncoded, err := out.ToJSON() if err != nil { errMsg := fmt.Errorf("failed to JSON encode mock TSM report: %v", err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusInternalServerError) } return &compositor.EvidenceOut{ Status: statusSucceeded, Evidence: outEncoded, + StatusCode: http.StatusOK, } } diff --git a/attesters/mocktsm/mocktsm_test.go b/attesters/mocktsm/mocktsm_test.go index 59a43d5..aba28fe 100644 --- a/attesters/mocktsm/mocktsm_test.go +++ b/attesters/mocktsm/mocktsm_test.go @@ -5,6 +5,7 @@ package mocktsm import ( "encoding/hex" "fmt" + "net/http" "testing" "github.com/stretchr/testify/assert" @@ -65,6 +66,7 @@ func Test_GetEvidence_wrong_nonce_size(t *testing.T) { Result: false, Error: errMsg, }, + StatusCode: http.StatusBadRequest, } assert.Equal(t, expected, p.GetEvidence(in)) @@ -82,6 +84,7 @@ func Test_GetEvidence_invalid_format(t *testing.T) { Result: false, Error: "no supported format in mock TSM plugin matches the requested format", }, + StatusCode: http.StatusBadRequest, } assert.Equal(t, expected, p.GetEvidence(in)) @@ -106,6 +109,7 @@ func Test_GetEvidence_No_Options(t *testing.T) { expected := &compositor.EvidenceOut{ Status: statusSucceeded, Evidence: outEncoded, + StatusCode: http.StatusOK, } assert.Equal(t, expected, p.GetEvidence(in)) @@ -134,6 +138,7 @@ func TestGetEvidence_With_Invalid_Options(t *testing.T) { Result: false, Error: tt.msg, }, + StatusCode: http.StatusBadRequest, } assert.Equal(t, expected, p.GetEvidence(in)) @@ -161,6 +166,7 @@ func Test_GetEvidence_With_Valid_Privilege_level(t *testing.T) { expected := &compositor.EvidenceOut{ Status: statusSucceeded, Evidence: outEncoded, + StatusCode: http.StatusOK, } assert.Equal(t, expected, p.GetEvidence(in)) diff --git a/attesters/tsm/tsm.go b/attesters/tsm/tsm.go index 65f6d1e..0a73b4e 100644 --- a/attesters/tsm/tsm.go +++ b/attesters/tsm/tsm.go @@ -5,6 +5,7 @@ package tsm import ( "encoding/json" "fmt" + "net/http" "strconv" "github.com/google/go-configfs-tsm/configfs/linuxtsm" @@ -41,11 +42,12 @@ var ( type TSMPlugin struct{} -func getEvidenceError(e error) *compositor.EvidenceOut { +func getEvidenceError(e error, statusCode uint32) *compositor.EvidenceOut { return &compositor.EvidenceOut{ Status: &compositor.Status{ Result: false, Error: e.Error(), }, + StatusCode: statusCode, } } @@ -88,7 +90,7 @@ func (t *TSMPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.EvidenceO errMsg := fmt.Errorf( "nonce size of the TSM attester should be %d, got %d", tsmNonceSize, uint32(len(in.Nonce))) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } for _, format := range supportedFormats { @@ -103,7 +105,7 @@ func (t *TSMPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.EvidenceO if err := json.Unmarshal(in.Options, &options); err != nil { errMsg := fmt.Errorf( "failed to parse %s: %v", in.Options, err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } } @@ -112,7 +114,7 @@ func (t *TSMPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.EvidenceO if err != nil || level < 0 { errMsg := fmt.Errorf("privilege_level %s is invalid", privlevel) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } req.Privilege = &report.Privilege{Level: uint(level)} } @@ -120,13 +122,13 @@ func (t *TSMPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.EvidenceO client, err := linuxtsm.MakeClient() if err != nil { errMsg := fmt.Errorf("failed to create config TSM client: %v", err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusInternalServerError) } resp, err := report.Get(client, req) if err != nil { errMsg := fmt.Errorf("failed to get TSM report: %v", err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusInternalServerError) } out := &tokens.TSMReport{ @@ -148,16 +150,17 @@ func (t *TSMPlugin) GetEvidence(in *compositor.EvidenceIn) *compositor.EvidenceO outEncoded, err := encodeOp() if err != nil { errMsg := fmt.Errorf("failed to encode TSM report as %s: %v", encodeAs, err) - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusInternalServerError) } return &compositor.EvidenceOut{ Status: statusSucceeded, Evidence: outEncoded, + StatusCode: http.StatusOK, } } } errMsg := fmt.Errorf("no supported format in tsm plugin matches the requested format") - return getEvidenceError(errMsg) + return getEvidenceError(errMsg, http.StatusBadRequest) } diff --git a/attesters/tsm/tsm_test.go b/attesters/tsm/tsm_test.go index 98efe79..cbea6f1 100644 --- a/attesters/tsm/tsm_test.go +++ b/attesters/tsm/tsm_test.go @@ -4,6 +4,7 @@ package tsm import ( "fmt" + "net/http" "testing" "github.com/google/go-configfs-tsm/configfs/linuxtsm" @@ -20,15 +21,19 @@ var ( ) func Test_getEvidenceError(t *testing.T) { - e := fmt.Errorf("sample error") + tests := []uint32 {http.StatusBadRequest, http.StatusBadRequest} + for _, tt := range tests { + e := fmt.Errorf("sample error") - expected := &compositor.EvidenceOut{ - Status: &compositor.Status{ - Result: false, Error: "sample error", - }, - } + expected := &compositor.EvidenceOut{ + Status: &compositor.Status{ + Result: false, Error: "sample error", + }, + StatusCode: tt, + } - assert.Equal(t, expected, getEvidenceError(e)) + assert.Equal(t, expected, getEvidenceError(e, tt)) + } } func Test_GetOptions(t *testing.T) { @@ -87,6 +92,7 @@ func Test_GetEvidence_wrong_nonce_size(t *testing.T) { Result: false, Error: errMsg, }, + StatusCode: http.StatusBadRequest, } assert.Equal(t, expected, p.GetEvidence(in)) @@ -104,6 +110,7 @@ func Test_GetEvidence_invalid_format(t *testing.T) { Result: false, Error: "no supported format in tsm plugin matches the requested format", }, + StatusCode: http.StatusBadRequest, } assert.Equal(t, expected, p.GetEvidence(in)) @@ -133,6 +140,7 @@ func TestGetEvidence_With_Invalid_Options(t *testing.T) { Result: false, Error: tt.msg, }, + StatusCode: http.StatusBadRequest, } assert.Equal(t, expected, p.GetEvidence(in)) diff --git a/proto/compositor.proto b/proto/compositor.proto index 5fdd576..ccc5606 100644 --- a/proto/compositor.proto +++ b/proto/compositor.proto @@ -60,5 +60,6 @@ message EvidenceIn { message EvidenceOut { Status status = 1; - bytes evidence = 2; + uint32 statusCode = 2; + bytes evidence = 3; } diff --git a/proto/compositor/compositor.pb.go b/proto/compositor/compositor.pb.go index 4e7ee2e..63ee48d 100644 --- a/proto/compositor/compositor.pb.go +++ b/proto/compositor/compositor.pb.go @@ -478,8 +478,9 @@ type EvidenceOut struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - Evidence []byte `protobuf:"bytes,2,opt,name=evidence,proto3" json:"evidence,omitempty"` + Status *Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + StatusCode uint32 `protobuf:"varint,2,opt,name=statusCode,proto3" json:"statusCode,omitempty"` + Evidence []byte `protobuf:"bytes,3,opt,name=evidence,proto3" json:"evidence,omitempty"` } func (x *EvidenceOut) Reset() { @@ -521,6 +522,13 @@ func (x *EvidenceOut) GetStatus() *Status { return nil } +func (x *EvidenceOut) GetStatusCode() uint32 { + if x != nil { + return x.StatusCode + } + return 0 +} + func (x *EvidenceOut) GetEvidence() []byte { if x != nil { return x.Evidence @@ -577,12 +585,14 @@ var file_compositor_proto_rawDesc = []byte{ 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x55, 0x0a, 0x0b, 0x45, 0x76, 0x69, 0x64, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x75, 0x0a, 0x0b, 0x45, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x75, 0x74, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x32, + 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x32, 0xa4, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x3c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,