httputil: remove error details (#3703)

This commit is contained in:
Caleb Doxsey 2022-10-25 08:00:21 -06:00 committed by GitHub
parent 9482dba049
commit 63b210e51d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 33 additions and 33 deletions

View file

@ -294,7 +294,7 @@ func TestAuthenticate_SignOut(t *testing.T) {
identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))}, identity.MockProvider{LogOutResponse: (*uriParseHelper("https://microsoft.com"))},
&mstore.Store{Encrypted: true, Session: &sessions.State{}}, &mstore.Store{Encrypted: true, Session: &sessions.State{}},
http.StatusOK, http.StatusOK,
"{\"Status\":200,\"Error\":\"OK: user logged out\"}\n", "{\"Status\":200}\n",
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View file

@ -5,6 +5,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry/requestid" "github.com/pomerium/pomerium/internal/telemetry/requestid"
"github.com/pomerium/pomerium/pkg/contextutil" "github.com/pomerium/pomerium/pkg/contextutil"
"github.com/pomerium/pomerium/ui" "github.com/pomerium/pomerium/ui"
@ -52,7 +53,6 @@ func (e *HTTPError) ErrorResponse(ctx context.Context, w http.ResponseWriter, r
} }
response := struct { response := struct {
Status int Status int
Error string
StatusText string `json:"-"` StatusText string `json:"-"`
RequestID string `json:",omitempty"` RequestID string `json:",omitempty"`
CanDebug bool `json:"-"` CanDebug bool `json:"-"`
@ -61,7 +61,6 @@ func (e *HTTPError) ErrorResponse(ctx context.Context, w http.ResponseWriter, r
}{ }{
Status: e.Status, Status: e.Status,
StatusText: StatusText(e.Status), StatusText: StatusText(e.Status),
Error: e.Error(),
RequestID: reqID, RequestID: reqID,
CanDebug: e.Status/100 == 4 && (e.DebugURL != nil || reqID != ""), CanDebug: e.Status/100 == 4 && (e.DebugURL != nil || reqID != ""),
DebugURL: e.DebugURL, DebugURL: e.DebugURL,
@ -70,6 +69,13 @@ func (e *HTTPError) ErrorResponse(ctx context.Context, w http.ResponseWriter, r
// indicate to clients that the error originates from Pomerium, not the app // indicate to clients that the error originates from Pomerium, not the app
w.Header().Set(HeaderPomeriumResponse, "true") w.Header().Set(HeaderPomeriumResponse, "true")
log.Error(ctx).
Err(e.Err).
Int("status", e.Status).
Str("status-text", StatusText(e.Status)).
Str("request-id", reqID).
Msg("httputil: error")
if r.Header.Get("Accept") == "application/json" { if r.Header.Get("Accept") == "application/json" {
RenderJSON(w, e.Status, response) RenderJSON(w, e.Status, response)
return return
@ -77,7 +83,6 @@ func (e *HTTPError) ErrorResponse(ctx context.Context, w http.ResponseWriter, r
m := map[string]any{ m := map[string]any{
"canDebug": response.CanDebug, "canDebug": response.CanDebug,
"error": response.Error,
"requestId": response.RequestID, "requestId": response.RequestID,
"status": response.Status, "status": response.Status,
"statusText": response.StatusText, "statusText": response.StatusText,

View file

@ -19,7 +19,7 @@ func TestHTTPError_ErrorResponse(t *testing.T) {
wantStatus int wantStatus int
wantBody string wantBody string
}{ }{
{"404 json", http.StatusNotFound, errors.New("route not known"), "application/json", http.StatusNotFound, "{\"Status\":404,\"Error\":\"Not Found: route not known\"}\n"}, {"404 json", http.StatusNotFound, errors.New("route not known"), "application/json", http.StatusNotFound, "{\"Status\":404}\n"},
{"404 html", http.StatusNotFound, errors.New("route not known"), "", http.StatusNotFound, ""}, {"404 html", http.StatusNotFound, errors.New("route not known"), "", http.StatusNotFound, ""},
} }
for _, tt := range tests { for _, tt := range tests {

View file

@ -75,8 +75,8 @@ func TestHandlerFunc_ServeHTTP(t *testing.T) {
f HandlerFunc f HandlerFunc
wantBody string wantBody string
}{ }{
{"good http error", func(w http.ResponseWriter, r *http.Request) error { return NewError(404, errors.New("404")) }, "{\"Status\":404,\"Error\":\"Not Found: 404\"}\n"}, {"good http error", func(w http.ResponseWriter, r *http.Request) error { return NewError(404, errors.New("404")) }, "{\"Status\":404}\n"},
{"good std error", func(w http.ResponseWriter, r *http.Request) error { return errors.New("404") }, "{\"Status\":500,\"Error\":\"Internal Server Error: 404\"}\n"}, {"good std error", func(w http.ResponseWriter, r *http.Request) error { return errors.New("404") }, "{\"Status\":500}\n"},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -55,7 +55,7 @@ func TestValidateSignature(t *testing.T) {
wantBody string wantBody string
}{ }{
{"good", []byte("secret"), []byte("secret"), http.StatusOK, http.StatusText(http.StatusOK)}, {"good", []byte("secret"), []byte("secret"), http.StatusOK, http.StatusText(http.StatusOK)},
{"secret mistmatch", []byte("secret"), []byte("hunter42"), http.StatusBadRequest, "{\"Status\":400,\"Error\":\"Bad Request: internal/urlutil: hmac failed\"}\n"}, {"secret mistmatch", []byte("secret"), []byte("hunter42"), http.StatusBadRequest, "{\"Status\":400}\n"},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

View file

@ -63,9 +63,9 @@ func TestProxy_ForwardAuth(t *testing.T) {
wantBody string wantBody string
}{ }{
{"good verify only, no redirect", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/verify", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusOK, ""}, {"good verify only, no redirect", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/verify", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusOK, ""},
{"bad empty domain uri", opts, nil, http.MethodGet, nil, map[string]string{"uri": ""}, "https://some.domain.example/", "", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400,\"Error\":\"Bad Request: https: url does contain a valid hostname\"}\n"}, {"bad empty domain uri", opts, nil, http.MethodGet, nil, map[string]string{"uri": ""}, "https://some.domain.example/", "", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400}\n"},
{"bad naked domain uri", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/", "a.naked.domain", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400,\"Error\":\"Bad Request: a.naked.domain url does contain a valid scheme\"}\n"}, {"bad naked domain uri", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/", "a.naked.domain", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400}\n"},
{"bad empty verification uri", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/", " ", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400,\"Error\":\"Bad Request: %20 url does contain a valid scheme\"}\n"}, {"bad empty verification uri", opts, nil, http.MethodGet, nil, nil, "https://some.domain.example/", " ", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, "{\"Status\":400}\n"},
// traefik // traefik
{"good traefik callback", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: "https://some.domain.example?" + urlutil.QuerySessionEncrypted + "=" + goodEncryptionString}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusFound, ""}, {"good traefik callback", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: "https://some.domain.example?" + urlutil.QuerySessionEncrypted + "=" + goodEncryptionString}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusFound, ""},
{"bad traefik callback bad session", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: "https://some.domain.example?" + urlutil.QuerySessionEncrypted + "=" + goodEncryptionString + "garbage"}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, ""}, {"bad traefik callback bad session", opts, nil, http.MethodGet, map[string]string{httputil.HeaderForwardedURI: "https://some.domain.example?" + urlutil.QuerySessionEncrypted + "=" + goodEncryptionString + "garbage"}, nil, "https://some.domain.example/", "https://some.domain.example", &mock.Encoder{}, &mstore.Store{Session: &sessions.State{}}, allowClient, http.StatusBadRequest, ""},

View file

@ -331,14 +331,14 @@ func TestProxy_ProgrammaticLogin(t *testing.T) {
opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{urlutil.QueryRedirectURI: "localhost"}, map[string]string{urlutil.QueryRedirectURI: "localhost"},
http.StatusBadRequest, http.StatusBadRequest,
"{\"Status\":400,\"Error\":\"Bad Request: localhost url does contain a valid scheme\"}\n", "{\"Status\":400}\n",
}, },
{ {
"bad redirect_uri not whitelisted", "bad redirect_uri not whitelisted",
opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil, opts, http.MethodGet, "https", "corp.example.example", "/.pomerium/api/v1/login", nil,
map[string]string{urlutil.QueryRedirectURI: "https://example.com"}, map[string]string{urlutil.QueryRedirectURI: "https://example.com"},
http.StatusBadRequest, http.StatusBadRequest,
"{\"Status\":400,\"Error\":\"Bad Request: invalid redirect uri\"}\n", "{\"Status\":400}\n",
}, },
{ {
"bad http method", "bad http method",

View file

@ -1,30 +1,31 @@
import {ErrorPageData, PolicyEvaluationTrace} from "../types"; import { ListItemProps, TableCell } from "@mui/material";
import SectionFooter from "./SectionFooter";
import Alert from "@mui/material/Alert"; import Alert from "@mui/material/Alert";
import AlertTitle from "@mui/material/AlertTitle"; import AlertTitle from "@mui/material/AlertTitle";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import Container from "@mui/material/Container"; import Container from "@mui/material/Container";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack"; import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import React, { FC } from "react";
import Markdown from "markdown-to-jsx";
import {ListItemProps, TableCell} from "@mui/material";
import {CheckCircle, MinusCircle, XCircle} from "react-feather";
import Table from "@mui/material/Table"; import Table from "@mui/material/Table";
import TableRow from "@mui/material/TableRow";
import TableHead from "@mui/material/TableHead"; import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography";
import Markdown from "markdown-to-jsx";
import React, { FC } from "react";
import { CheckCircle, MinusCircle, XCircle } from "react-feather";
import { ErrorPageData, PolicyEvaluationTrace } from "../types";
import SectionFooter from "./SectionFooter";
type PolicyEvaluationTraceDetailsProps = { type PolicyEvaluationTraceDetailsProps = {
trace: PolicyEvaluationTrace; trace: PolicyEvaluationTrace;
} & ListItemProps; } & ListItemProps;
const PolicyEvaluationTraceDetails: FC<PolicyEvaluationTraceDetailsProps> = ({ const PolicyEvaluationTraceDetails: FC<PolicyEvaluationTraceDetailsProps> = ({
trace, trace,
...props ...props
}) => { }) => {
return ( return (
<TableRow> <TableRow>
<TableCell align={'center'}> <TableCell align={"center"}>
{trace.deny ? ( {trace.deny ? (
<XCircle color="red" /> <XCircle color="red" />
) : trace.allow ? ( ) : trace.allow ? (
@ -34,9 +35,7 @@ const PolicyEvaluationTraceDetails: FC<PolicyEvaluationTraceDetailsProps> = ({
)} )}
</TableCell> </TableCell>
<TableCell> <TableCell>
<Markdown> <Markdown>{trace.explanation || trace.id}</Markdown>
{trace.explanation || trace.id}
</Markdown>
</TableCell> </TableCell>
<TableCell> <TableCell>
<Markdown> <Markdown>
@ -63,14 +62,11 @@ export const ErrorPage: FC<ErrorPageProps> = ({ data }) => {
{data?.status || 500}{" "} {data?.status || 500}{" "}
{data?.statusText || "Internal Server Error"} {data?.statusText || "Internal Server Error"}
</AlertTitle> </AlertTitle>
{data?.error || "Internal Server Error"}
</Alert> </Alert>
</Box> </Box>
{!!data?.errorMessageFirstParagraph && ( {!!data?.errorMessageFirstParagraph && (
<Box sx={{p: 4}}> <Box sx={{ p: 4 }}>
<Markdown> <Markdown>{data.errorMessageFirstParagraph}</Markdown>
{data.errorMessageFirstParagraph}
</Markdown>
</Box> </Box>
)} )}
{traces?.length > 0 && ( {traces?.length > 0 && (

View file

@ -92,7 +92,6 @@ export type ErrorPageData = BasePageData & {
canDebug?: boolean; canDebug?: boolean;
debugUrl?: string; debugUrl?: string;
error?: string;
requestId?: string; requestId?: string;
status?: number; status?: number;
statusText?: string; statusText?: string;