Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/internal/auth/capi_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (c *CAPIClient) IsAuthorized(sourceId string, clientToken string) bool {
}

func (c *CAPIClient) HasApp(sourceID, authToken string) bool {
req, err := http.NewRequest(http.MethodGet, c.addr+"/v3/apps/"+sourceID, nil)
req, err := http.NewRequest(http.MethodGet, c.addr+"/v3/apps/"+sourceID, nil) //nolint:gosec // G704: URL from operator config only
if err != nil {
c.log.Printf("failed to build authorize log access request: %s", err)
return false
Expand All @@ -111,7 +111,7 @@ func (c *CAPIClient) HasApp(sourceID, authToken string) bool {
}

func (c *CAPIClient) HasService(sourceID, authToken string) bool {
req, err := http.NewRequest(http.MethodGet, c.addr+"/v3/service_instances/"+sourceID, nil)
req, err := http.NewRequest(http.MethodGet, c.addr+"/v3/service_instances/"+sourceID, nil) //nolint:gosec // G704: URL from operator config only
if err != nil {
c.log.Printf("failed to build authorize log access request: %s", err)
return false
Expand Down Expand Up @@ -171,7 +171,7 @@ func (c *CAPIClient) AvailableSourceIDs(authToken string) []string {

func (c *CAPIClient) sourceIDsForResourceType(resourceType, authToken string, metrics metrics.Gauge) ([]string, error) {
var sourceIDs []string
req, err := http.NewRequest(http.MethodGet, c.addr+"/v3/"+resourceType, nil)
req, err := http.NewRequest(http.MethodGet, c.addr+"/v3/"+resourceType, nil) //nolint:gosec // G704: URL from operator config only
if err != nil {
c.log.Printf("failed to build authorize service instance access request: %s", err)
return nil, err
Expand Down
49 changes: 42 additions & 7 deletions src/internal/auth/uaa_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (c *UAAClient) RefreshTokenKeys() error {
}
atomic.CompareAndSwapInt64(&c.lastQueryTime, lastQueryTime, time.Now().UnixNano())

req, err := http.NewRequest("GET", c.uaa.String(), nil)
req, err := http.NewRequest("GET", c.uaa.String(), nil) //nolint:gosec // G704: URL from operator config only
if err != nil {
panic(fmt.Sprintf("failed to create request to UAA: %s", err))
}
Expand Down Expand Up @@ -188,29 +188,64 @@ func (e UnknownTokenKeyError) Error() string {
return fmt.Sprintf("using unknown token key: %s", e.Kid)
}

// JWTKeyMaterialError is returned when the JWT alg header does not match the
// kind of key material UAA published for the token's kid (e.g. HS256 with an
// RSA public key). Returning a distinct type avoids spurious UAA key refresh
// and closes algorithm-confusion issues in the JOSE stack.
type JWTKeyMaterialError struct {
Alg string
Kid string
}

func (e JWTKeyMaterialError) Error() string {
return fmt.Sprintf("token algorithm %s is incompatible with UAA key material for kid %s", e.Alg, e.Kid)
}

func (c *UAAClient) Read(token string) (Oauth2ClientContext, error) {
if token == "" {
return Oauth2ClientContext{}, errors.New("missing token")
}

payload, _, err := jose.Decode(trimBearer(token), func(headers map[string]interface{}, payload string) interface{} {
if headers["alg"] != "RS256" && headers["alg"] != "HS256" {
return AlgorithmError{Alg: headers["alg"].(string)}
alg, ok := headers["alg"].(string)
if !ok {
return AlgorithmError{Alg: fmt.Sprintf("%v", headers["alg"])}
}
if alg != "RS256" && alg != "HS256" {
return AlgorithmError{Alg: alg}
}

keyId := headers["kid"].(string)
keyID, ok := headers["kid"].(string)
if !ok {
return UnknownTokenKeyError{Kid: fmt.Sprintf("%v", headers["kid"])}
}

publicKey, err := c.loadOrFetchPublicKey(keyId)
keyMaterial, err := c.loadOrFetchPublicKey(keyID)
if err != nil {
return err
}

return publicKey
switch alg {
case "RS256":
rsaKey, ok := keyMaterial.(*rsa.PublicKey)
if !ok {
return JWTKeyMaterialError{Alg: alg, Kid: keyID}
}
return rsaKey
case "HS256":
symmetricKey, ok := keyMaterial.([]byte)
if !ok {
return JWTKeyMaterialError{Alg: alg, Kid: keyID}
}
return symmetricKey
default:
return AlgorithmError{Alg: alg}
}
})

if err != nil {
switch err.(type) {
case AlgorithmError, UnknownTokenKeyError:
case AlgorithmError, UnknownTokenKeyError, JWTKeyMaterialError:
// no-op
default:
// we're specifically trying to catch "crypto/rsa: verification error",
Expand Down
14 changes: 14 additions & 0 deletions src/internal/auth/uaa_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -57,6 +58,19 @@ var _ = Describe("UAAClient", func() {
Expect(err.Error()).To(Equal("failed to decode token: unsupported algorithm: none"))
})

It("rejects HS256 JWTs when UAA only published an RSA key for that kid (algorithm confusion)", func() {
kid := tc.privateKeys[0].keyId
header := fmt.Sprintf(`{"alg":"HS256","kid":%q}`, kid)
payload := `{"scope":["logs.admin"],"exp":9999999999}`
enc := base64.RawURLEncoding.EncodeToString
forged := enc([]byte(header)) + "." + enc([]byte(payload)) + "."

_, err := tc.uaaClient.Read(withBearer(forged))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("failed to decode token"))
Expect(err.Error()).To(ContainSubstring("incompatible with UAA key material"))
})

It("returns IsAdmin == true when scopes include doppler.firehose", func() {
payload := tc.BuildValidPayload("doppler.firehose")
token := tc.CreateSignedToken(payload)
Expand Down
2 changes: 1 addition & 1 deletion src/internal/cache/log_cache.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cache

import (
"context"
"log"
"net"
"strconv"
Expand All @@ -9,7 +10,6 @@ import (

metrics "code.cloudfoundry.org/go-metric-registry"

"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

Expand Down
2 changes: 1 addition & 1 deletion src/internal/gateway/gateway.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gateway

import (
"context"
"fmt"
"io"
"log"
Expand All @@ -10,7 +11,6 @@ import (

"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/shirou/gopsutil/v4/host"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/protojson"
Expand Down
5 changes: 3 additions & 2 deletions src/internal/nozzle/nozzle.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nozzle

import (
"context"
"log"
"runtime"
"time"
Expand All @@ -11,7 +12,6 @@ import (
diodes "code.cloudfoundry.org/go-diodes"
"code.cloudfoundry.org/go-log-cache/v3/rpc/logcache_v1"
"code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
Expand Down Expand Up @@ -177,12 +177,13 @@ func (n *Nozzle) envelopeWriter(ch chan []*loggregator_v2.Envelope, client logca
for {
envelopes := <-ch

ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
_, err := client.Send(ctx, &logcache_v1.SendRequest{
Envelopes: &loggregator_v2.EnvelopeBatch{
Batch: envelopes,
},
})
cancel()

if err != nil {
n.errCounter.Add(1)
Expand Down
2 changes: 1 addition & 1 deletion src/internal/nozzle/nozzle_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nozzle_test

import (
"context"
"log"
"sync"

Expand All @@ -9,7 +10,6 @@ import (
"code.cloudfoundry.org/go-loggregator/v10"
"code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2"
. "code.cloudfoundry.org/log-cache/internal/nozzle"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
Expand Down
5 changes: 3 additions & 2 deletions src/internal/routing/batched_ingress_client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package routing

import (
"context"
"log"
"time"

Expand All @@ -10,7 +11,6 @@ import (
diodes "code.cloudfoundry.org/go-diodes"
rpc "code.cloudfoundry.org/go-log-cache/v3/rpc/logcache_v1"
"code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2"
"golang.org/x/net/context"
"google.golang.org/grpc"
)

Expand Down Expand Up @@ -96,11 +96,12 @@ func (b *BatchedIngressClient) write(batch []interface{}) {
e = append(e, i.(*loggregator_v2.Envelope))
}

ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
_, err := b.c.Send(ctx, &rpc.SendRequest{
LocalOnly: b.localOnly,
Envelopes: &loggregator_v2.EnvelopeBatch{Batch: e},
})
cancel()

if err != nil {
b.log.Printf("failed to write %d envelopes: %s", len(e), err)
Expand Down
5 changes: 2 additions & 3 deletions src/internal/routing/batched_ingress_client_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package routing_test

import (
"context"
"io"
"log"
"time"

"code.cloudfoundry.org/go-metric-registry/testhelpers"

metrics "code.cloudfoundry.org/go-metric-registry"
rpc "code.cloudfoundry.org/go-log-cache/v3/rpc/logcache_v1"
"code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2"
metrics "code.cloudfoundry.org/go-metric-registry"
"code.cloudfoundry.org/log-cache/internal/routing"
"golang.org/x/net/context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down
2 changes: 1 addition & 1 deletion src/internal/routing/local_store_reader.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package routing

import (
"context"
"fmt"
"regexp"
"time"

"code.cloudfoundry.org/go-log-cache/v3/rpc/logcache_v1"
"code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2"
"golang.org/x/net/context"
"google.golang.org/grpc"
)

Expand Down
2 changes: 1 addition & 1 deletion src/internal/routing/local_store_reader_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package routing_test

import (
"context"
"regexp"
"time"

"code.cloudfoundry.org/go-log-cache/v3/rpc/logcache_v1"
"code.cloudfoundry.org/go-loggregator/v10/rpc/loggregator_v2"
"code.cloudfoundry.org/log-cache/internal/routing"
"golang.org/x/net/context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down
5 changes: 3 additions & 2 deletions src/internal/routing/static_lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ func NewStaticLookup(numOfRoutes int, hasher func(string) uint64) *StaticLookup

// NOTE: 18446744073709551615 is 0xFFFFFFFFFFFFFFFF or the max value of a
// uint64.
x := (18446744073709551615 / uint64(numOfRoutes))
for i := uint64(0); i < uint64(numOfRoutes); i++ {
nr := uint64(numOfRoutes) //#nosec G115
x := 18446744073709551615 / nr
for i := uint64(0); i < nr; i++ {
t.Put(i*x, i)
}

Expand Down
12 changes: 5 additions & 7 deletions src/internal/syslog/server.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package syslog

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log"
"net"
"strconv"
"strings"
"sync"
"time"

"code.cloudfoundry.org/go-loggregator/v10"
Expand All @@ -15,13 +20,6 @@ import (
"github.com/leodido/go-syslog/v4/nontransparent"
"github.com/leodido/go-syslog/v4/octetcounting"
"github.com/leodido/go-syslog/v4/rfc5424"

"net"
"strconv"
"strings"
"sync"

"golang.org/x/net/context"
)

type Server struct {
Expand Down
Loading