mirror of
https://github.com/nais/wonderwall.git
synced 2026-08-23 21:16:14 +00:00
fix: check or explicitly ignore returned errors
Satisfies errcheck. Errors that carry no actionable information are ignored explicitly: writes to an already-committed response, and closing a fully read response body or file. Test fixture setup asserts with require.NoError instead, since a failure there means the fixture itself is broken.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/nais/wonderwall/internal/crypto"
|
||||
)
|
||||
@@ -61,6 +62,7 @@ func BenchmarkEncrypt(b *testing.B) {
|
||||
crypter := crypto.NewCrypter(key)
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
crypter.Encrypt(plaintext)
|
||||
_, err := crypter.Encrypt(plaintext)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func DisallowNonNavigationalRequests(next http.Handler) http.Handler {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"error": "unauthenticated", "error_description": "this is an interactive endpoint; user-agents must be navigated to this endpoint", "error_path": "` + r.URL.Path + `"}`))
|
||||
_, _ = w.Write([]byte(`{"error": "unauthenticated", "error_description": "this is an interactive endpoint; user-agents must be navigated to this endpoint", "error_path": "` + r.URL.Path + `"}`))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -91,16 +91,16 @@ func openidFlags() {
|
||||
func resolveOpenIdProvider() {
|
||||
switch Provider(viper.GetString(OpenIDProvider)) {
|
||||
case ProviderIDPorten:
|
||||
viper.BindEnv(OpenIDClientID, "IDPORTEN_CLIENT_ID")
|
||||
viper.BindEnv(OpenIDClientJWK, "IDPORTEN_CLIENT_JWK")
|
||||
viper.BindEnv(OpenIDWellKnownURL, "IDPORTEN_WELL_KNOWN_URL")
|
||||
_ = viper.BindEnv(OpenIDClientID, "IDPORTEN_CLIENT_ID")
|
||||
_ = viper.BindEnv(OpenIDClientJWK, "IDPORTEN_CLIENT_JWK")
|
||||
_ = viper.BindEnv(OpenIDWellKnownURL, "IDPORTEN_WELL_KNOWN_URL")
|
||||
|
||||
viper.SetDefault(OpenIDACRValues, acr.IDPortenLevelHigh)
|
||||
viper.SetDefault(OpenIDUILocales, "nb")
|
||||
case ProviderAzure:
|
||||
viper.BindEnv(OpenIDClientID, "AZURE_APP_CLIENT_ID")
|
||||
viper.BindEnv(OpenIDClientJWK, "AZURE_APP_JWK")
|
||||
viper.BindEnv(OpenIDWellKnownURL, "AZURE_APP_WELL_KNOWN_URL")
|
||||
_ = viper.BindEnv(OpenIDClientID, "AZURE_APP_CLIENT_ID")
|
||||
_ = viper.BindEnv(OpenIDClientJWK, "AZURE_APP_JWK")
|
||||
_ = viper.BindEnv(OpenIDWellKnownURL, "AZURE_APP_WELL_KNOWN_URL")
|
||||
default:
|
||||
viper.Set(OpenIDProvider, ProviderOpenID)
|
||||
}
|
||||
|
||||
@@ -652,7 +652,7 @@ func request(t *testing.T, client *http.Client, method, url string, headers ...h
|
||||
}
|
||||
|
||||
func body(t *testing.T, resp *http.Response) string {
|
||||
defer resp.Body.Close()
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -209,10 +209,10 @@ func handleAutologin(src ReverseProxySource, w http.ResponseWriter, r *http.Requ
|
||||
if httpinternal.Accepts(r, "*/*", "application/json") {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(`{"error": "unauthenticated, please log in"}`))
|
||||
_, _ = w.Write([]byte(`{"error": "unauthenticated, please log in"}`))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte("unauthenticated, please log in"))
|
||||
_, _ = w.Write([]byte("unauthenticated, please log in"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-28
@@ -347,7 +347,7 @@ func (ip *IdentityProviderHandler) parseAuthorizationRequest(query url.Values) (
|
||||
|
||||
func (ip *IdentityProviderHandler) Jwks(w http.ResponseWriter, r *http.Request) {
|
||||
jwks, _ := ip.Provider.GetPublicJwkSet(r.Context())
|
||||
json.NewEncoder(w).Encode(jwks)
|
||||
_ = json.NewEncoder(w).Encode(jwks)
|
||||
}
|
||||
|
||||
func (ip *IdentityProviderHandler) PushedAuthorizationRequest(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -391,7 +391,7 @@ func (ip *IdentityProviderHandler) PushedAuthorizationRequest(w http.ResponseWri
|
||||
|
||||
w.Header().Set("content-type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(openid.PushedAuthorizationResponse{
|
||||
_ = json.NewEncoder(w).Encode(openid.PushedAuthorizationResponse{
|
||||
RequestUri: requestUri,
|
||||
ExpiresIn: 60,
|
||||
})
|
||||
@@ -480,13 +480,13 @@ func (ip *IdentityProviderHandler) TokenCodeGrant(w http.ResponseWriter, r *http
|
||||
sub := uuid.New().String()
|
||||
|
||||
accessToken := jwt.New()
|
||||
accessToken.Set("sub", sub)
|
||||
accessToken.Set("iss", ip.Config.Provider().Issuer())
|
||||
accessToken.Set("acr", auth.AcrLevel)
|
||||
accessToken.Set("iat", iat.Unix())
|
||||
accessToken.Set("exp", exp.Unix())
|
||||
accessToken.Set("jti", uuid.NewString())
|
||||
accessToken.Set("aud", auth.ClientID)
|
||||
_ = accessToken.Set("sub", sub)
|
||||
_ = accessToken.Set("iss", ip.Config.Provider().Issuer())
|
||||
_ = accessToken.Set("acr", auth.AcrLevel)
|
||||
_ = accessToken.Set("iat", iat.Unix())
|
||||
_ = accessToken.Set("exp", exp.Unix())
|
||||
_ = accessToken.Set("jti", uuid.NewString())
|
||||
_ = accessToken.Set("aud", auth.ClientID)
|
||||
signedAccessToken, err := ip.signToken(accessToken)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -495,19 +495,19 @@ func (ip *IdentityProviderHandler) TokenCodeGrant(w http.ResponseWriter, r *http
|
||||
}
|
||||
|
||||
idToken := jwt.New()
|
||||
idToken.Set("sub", sub)
|
||||
idToken.Set("iss", ip.Config.Provider().Issuer())
|
||||
idToken.Set("aud", auth.ClientID)
|
||||
idToken.Set("locale", auth.Locale)
|
||||
idToken.Set("nonce", auth.Nonce)
|
||||
idToken.Set("acr", auth.AcrLevel)
|
||||
idToken.Set("iat", iat.Unix())
|
||||
idToken.Set("exp", exp.Unix())
|
||||
idToken.Set("jti", uuid.NewString())
|
||||
_ = idToken.Set("sub", sub)
|
||||
_ = idToken.Set("iss", ip.Config.Provider().Issuer())
|
||||
_ = idToken.Set("aud", auth.ClientID)
|
||||
_ = idToken.Set("locale", auth.Locale)
|
||||
_ = idToken.Set("nonce", auth.Nonce)
|
||||
_ = idToken.Set("acr", auth.AcrLevel)
|
||||
_ = idToken.Set("iat", iat.Unix())
|
||||
_ = idToken.Set("exp", exp.Unix())
|
||||
_ = idToken.Set("jti", uuid.NewString())
|
||||
|
||||
// If the sid claim should be in token and in active session
|
||||
if ip.Config.Provider().SidClaimRequired() {
|
||||
idToken.Set("sid", auth.SessionID)
|
||||
_ = idToken.Set("sid", auth.SessionID)
|
||||
}
|
||||
|
||||
signedIdToken, err := ip.signToken(idToken)
|
||||
@@ -536,7 +536,7 @@ func (ip *IdentityProviderHandler) TokenCodeGrant(w http.ResponseWriter, r *http
|
||||
|
||||
w.Header().Set("content-type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(token)
|
||||
_ = json.NewEncoder(w).Encode(token)
|
||||
}
|
||||
|
||||
func (ip *IdentityProviderHandler) RefreshTokenGrant(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -570,11 +570,11 @@ func (ip *IdentityProviderHandler) RefreshTokenGrant(w http.ResponseWriter, r *h
|
||||
}
|
||||
|
||||
accessToken := jwt.New()
|
||||
accessToken.Set("sub", sub)
|
||||
accessToken.Set("iss", ip.Config.Provider().Issuer())
|
||||
accessToken.Set("iat", iat.Unix())
|
||||
accessToken.Set("exp", exp.Unix())
|
||||
accessToken.Set("jti", uuid.NewString())
|
||||
_ = accessToken.Set("sub", sub)
|
||||
_ = accessToken.Set("iss", ip.Config.Provider().Issuer())
|
||||
_ = accessToken.Set("iat", iat.Unix())
|
||||
_ = accessToken.Set("exp", exp.Unix())
|
||||
_ = accessToken.Set("jti", uuid.NewString())
|
||||
signedAccessToken, err := ip.signToken(accessToken)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -604,7 +604,7 @@ func (ip *IdentityProviderHandler) RefreshTokenGrant(w http.ResponseWriter, r *h
|
||||
|
||||
w.Header().Set("content-type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(token)
|
||||
_ = json.NewEncoder(w).Encode(token)
|
||||
}
|
||||
|
||||
func (ip *IdentityProviderHandler) validateClientAuthentication(w http.ResponseWriter, r *http.Request, expectedClientID string) error {
|
||||
@@ -627,7 +627,7 @@ func (ip *IdentityProviderHandler) validateClientAuthentication(w http.ResponseW
|
||||
|
||||
clientJwk := ip.Config.Client().ClientJWK()
|
||||
clientJwkSet := jwk.NewSet()
|
||||
clientJwkSet.AddKey(clientJwk)
|
||||
_ = clientJwkSet.AddKey(clientJwk)
|
||||
publicClientJwkSet, err := jwk.PublicSetOf(clientJwkSet)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -705,7 +705,7 @@ func (in *relyingPartyServer) SetHandler(handler http.Handler) {
|
||||
|
||||
func oauthError(w http.ResponseWriter, err error) {
|
||||
w.Header().Set("content-type", "application/json")
|
||||
json.NewEncoder(w).Encode(openid.TokenErrorResponse{
|
||||
_ = json.NewEncoder(w).Encode(openid.TokenErrorResponse{
|
||||
Error: "invalid_request",
|
||||
ErrorDescription: err.Error(),
|
||||
})
|
||||
|
||||
@@ -213,7 +213,7 @@ func (c *Client) oauthPostRequest(ctx context.Context, endpoint string, payload
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("performing request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
|
||||
@@ -88,7 +88,7 @@ func NewProviderConfig(cfg *config.Config) (Provider, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching well known configuration: %w", err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
defer func() { _ = response.Body.Close() }()
|
||||
|
||||
providerCfg := new(ProviderMetadata)
|
||||
if err := json.NewDecoder(response.Body).Decode(providerCfg); err != nil {
|
||||
|
||||
@@ -115,7 +115,7 @@ func New(src Source, cfg *config.Config) chi.Router {
|
||||
|
||||
r.Get(paths.Ping, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("pong"))
|
||||
_, _ = w.Write([]byte("pong"))
|
||||
})
|
||||
|
||||
r.Route(paths.Session, func(r chi.Router) {
|
||||
|
||||
@@ -118,7 +118,7 @@ func newProbeServer(cfg *config.Config) *http.Server {
|
||||
mux := http.NewServeMux()
|
||||
healthz := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok"))
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
})
|
||||
mux.HandleFunc("/", healthz)
|
||||
mux.HandleFunc("/healthz", healthz)
|
||||
|
||||
+23
-24
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
jwtlib "github.com/lestrrat-go/jwx/v3/jwt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/mock"
|
||||
"github.com/nais/wonderwall/pkg/openid"
|
||||
@@ -29,7 +30,7 @@ func TestExternalID(t *testing.T) {
|
||||
{
|
||||
name: "Support for front channel session with required sid claim",
|
||||
config: sidRequired(),
|
||||
idToken: idTokenWithSid("some-sid"),
|
||||
idToken: idTokenWithSid(t, "some-sid"),
|
||||
want: "some-sid",
|
||||
exactMatch: true,
|
||||
},
|
||||
@@ -37,20 +38,20 @@ func TestExternalID(t *testing.T) {
|
||||
name: "Support for front channel session with required sid claim and session_state in param",
|
||||
config: sidRequired(),
|
||||
params: params("session_state", "some-session-state"),
|
||||
idToken: idTokenWithSid("some-sid"),
|
||||
idToken: idTokenWithSid(t, "some-sid"),
|
||||
want: "some-sid",
|
||||
exactMatch: true,
|
||||
},
|
||||
{
|
||||
name: "Support for front channel session without required sid claim",
|
||||
config: sidRequired(),
|
||||
idToken: idToken(),
|
||||
idToken: idToken(t),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "Support for session management with required param",
|
||||
config: sessionStateRequired(),
|
||||
idToken: idToken(),
|
||||
idToken: idToken(t),
|
||||
params: params("session_state", "some-session"),
|
||||
want: "some-session",
|
||||
exactMatch: true,
|
||||
@@ -58,7 +59,7 @@ func TestExternalID(t *testing.T) {
|
||||
{
|
||||
name: "Support for session management with required param and sid in id_token",
|
||||
config: sessionStateRequired(),
|
||||
idToken: idTokenWithSid("some-sid"),
|
||||
idToken: idTokenWithSid(t, "some-sid"),
|
||||
params: params("session_state", "some-session"),
|
||||
want: "some-sid",
|
||||
exactMatch: true,
|
||||
@@ -66,28 +67,28 @@ func TestExternalID(t *testing.T) {
|
||||
{
|
||||
name: "Support for session management with missing required param",
|
||||
config: sessionStateRequired(),
|
||||
idToken: idToken(),
|
||||
idToken: idToken(t),
|
||||
params: params("not_session_state", "some-session"),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "No support for front-channel logout nor session management should generate session ID",
|
||||
config: standardConfig(),
|
||||
idToken: idToken(),
|
||||
idToken: idToken(t),
|
||||
want: "some-generated-id",
|
||||
exactMatch: false,
|
||||
},
|
||||
{
|
||||
name: "No support for front-channel logout nor session management, sid in id_token",
|
||||
config: standardConfig(),
|
||||
idToken: idTokenWithSid("some-sid"),
|
||||
idToken: idTokenWithSid(t, "some-sid"),
|
||||
want: "some-sid",
|
||||
exactMatch: true,
|
||||
},
|
||||
{
|
||||
name: "No support for front-channel logout nor session management, session_state in param",
|
||||
config: standardConfig(),
|
||||
idToken: idToken(),
|
||||
idToken: idToken(t),
|
||||
params: params("session_state", "some-session-state"),
|
||||
want: "some-session-state",
|
||||
exactMatch: true,
|
||||
@@ -95,7 +96,7 @@ func TestExternalID(t *testing.T) {
|
||||
{
|
||||
name: "No support for front-channel logout nor session management, sid in id_token and session_state in param, sid should take precedence",
|
||||
config: standardConfig(),
|
||||
idToken: idTokenWithSid("some-sid"),
|
||||
idToken: idTokenWithSid(t, "some-sid"),
|
||||
params: params("session_state", "some-session-state"),
|
||||
want: "some-sid",
|
||||
exactMatch: true,
|
||||
@@ -159,36 +160,34 @@ func params(key, value string) url.Values {
|
||||
return values
|
||||
}
|
||||
|
||||
func newIDToken(extraClaims map[string]string) *openid.IDToken {
|
||||
func newIDToken(t *testing.T, extraClaims map[string]string) *openid.IDToken {
|
||||
now := time.Now().Truncate(time.Second)
|
||||
|
||||
idToken := jwtlib.New()
|
||||
idToken.Set("sub", "test")
|
||||
idToken.Set("iss", "test")
|
||||
idToken.Set("aud", "test")
|
||||
idToken.Set("iat", now.Unix())
|
||||
idToken.Set("exp", now.Add(time.Hour).Unix())
|
||||
require.NoError(t, idToken.Set("sub", "test"))
|
||||
require.NoError(t, idToken.Set("iss", "test"))
|
||||
require.NoError(t, idToken.Set("aud", "test"))
|
||||
require.NoError(t, idToken.Set("iat", now.Unix()))
|
||||
require.NoError(t, idToken.Set("exp", now.Add(time.Hour).Unix()))
|
||||
|
||||
for claim, value := range extraClaims {
|
||||
if len(claim) > 0 {
|
||||
idToken.Set(claim, value)
|
||||
require.NoError(t, idToken.Set(claim, value))
|
||||
}
|
||||
}
|
||||
|
||||
serialized, err := jwtlib.NewSerializer().Serialize(idToken)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
return openid.NewIDToken(string(serialized), idToken)
|
||||
}
|
||||
|
||||
func idTokenWithSid(sid string) *openid.IDToken {
|
||||
return newIDToken(map[string]string{
|
||||
func idTokenWithSid(t *testing.T, sid string) *openid.IDToken {
|
||||
return newIDToken(t, map[string]string{
|
||||
"sid": sid,
|
||||
})
|
||||
}
|
||||
|
||||
func idToken() *openid.IDToken {
|
||||
return newIDToken(nil)
|
||||
func idToken(t *testing.T) *openid.IDToken {
|
||||
return newIDToken(t, nil)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestMemory(t *testing.T) {
|
||||
crypter := makeCrypter(t)
|
||||
data := makeData()
|
||||
data := makeData(t)
|
||||
encryptedData, err := data.Encrypt(crypter)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func TestRedis(t *testing.T) {
|
||||
crypter := makeCrypter(t)
|
||||
data := makeData()
|
||||
data := makeData(t)
|
||||
encryptedData, err := data.Encrypt(crypter)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
jwtlib "github.com/lestrrat-go/jwx/v3/jwt"
|
||||
"github.com/nais/liberator/pkg/keygen"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/nais/wonderwall/internal/crypto"
|
||||
"github.com/nais/wonderwall/pkg/openid"
|
||||
@@ -32,9 +33,9 @@ func makeCrypter(t *testing.T) crypto.Crypter {
|
||||
return crypto.NewCrypter(key)
|
||||
}
|
||||
|
||||
func makeData() *session.Data {
|
||||
func makeData(t *testing.T) *session.Data {
|
||||
idToken := jwtlib.New()
|
||||
idToken.Set("jti", "id-token-jti")
|
||||
require.NoError(t, idToken.Set("jti", "id-token-jti"))
|
||||
|
||||
accessToken := "some-access-token"
|
||||
refreshToken := "some-refresh-token"
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestAbsoluteValidator_IsValidRedirect(t *testing.T) {
|
||||
t.Run("open redirects list", func(t *testing.T) {
|
||||
file, err := os.Open("testdata/open-redirects.txt")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
@@ -143,7 +143,7 @@ func TestRelativeValidator_IsValidRedirect(t *testing.T) {
|
||||
t.Run("open redirects list", func(t *testing.T) {
|
||||
file, err := os.Open("testdata/open-redirects.txt")
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
|
||||
Reference in New Issue
Block a user