-
+
+
+
+
+ ) : (
+ logo
+ )}
+
-
+
+
);
};
diff --git a/vendor/github.com/go-asn1-ber/asn1-ber/ber.go b/vendor/github.com/go-asn1-ber/asn1-ber/ber.go
index 71b3c3ac27..f27229ed60 100644
--- a/vendor/github.com/go-asn1-ber/asn1-ber/ber.go
+++ b/vendor/github.com/go-asn1-ber/asn1-ber/ber.go
@@ -412,7 +412,7 @@ func readPacket(reader io.Reader) (*Packet, int, error) {
p.Value = val
}
case TagRelativeOID:
- oid, err := parseObjectIdentifier(content)
+ oid, err := parseRelativeObjectIdentifier(content)
if err == nil {
p.Value = OIDToString(oid)
}
@@ -560,16 +560,14 @@ func NewBoolean(classType Class, tagType Type, tag Tag, value bool, description
// NewLDAPBoolean returns a RFC 4511-compliant Boolean packet.
func NewLDAPBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet {
- intValue := int64(0)
-
- if value {
- intValue = 255
- }
-
p := Encode(classType, tagType, tag, nil, description)
p.Value = value
- p.Data.Write(encodeInteger(intValue))
+ if value {
+ p.Data.Write([]byte{255})
+ } else {
+ p.Data.Write([]byte{0})
+ }
return p
}
@@ -663,6 +661,25 @@ func NewOID(classType Class, tagType Type, tag Tag, value interface{}, descripti
return p
}
+func NewRelativeOID(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet {
+ p := Encode(classType, tagType, tag, nil, description)
+
+ switch v := value.(type) {
+ case string:
+ encoded, err := encodeRelativeOID(v)
+ if err != nil {
+ fmt.Printf("failed writing %v", err)
+ return nil
+ }
+ p.Value = v
+ p.Data.Write(encoded)
+ // TODO: support []int already ?
+ default:
+ panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v))
+ }
+ return p
+}
+
// encodeOID takes a string representation of an OID and returns its DER-encoded byte slice along with any error.
func encodeOID(oidString string) ([]byte, error) {
// Convert the string representation to an asn1.ObjectIdentifier
@@ -688,6 +705,26 @@ func encodeOID(oidString string) ([]byte, error) {
return encoded, nil
}
+func encodeRelativeOID(oidString string) ([]byte, error) {
+ parts := strings.Split(oidString, ".")
+ oid := make([]int, len(parts))
+ for i, part := range parts {
+ var val int
+ if _, err := fmt.Sscanf(part, "%d", &val); err != nil {
+ return nil, fmt.Errorf("invalid RELATIVE OID part '%s': %w", part, err)
+ }
+ oid[i] = val
+ }
+
+ encoded := make([]byte, 0)
+
+ for i := 0; i < len(oid); i++ {
+ encoded = appendBase128Int(encoded, int64(oid[i]))
+ }
+
+ return encoded, nil
+}
+
func appendBase128Int(dst []byte, n int64) []byte {
l := base128IntLength(n)
@@ -772,6 +809,27 @@ func parseObjectIdentifier(bytes []byte) (s []int, err error) {
return
}
+func parseRelativeObjectIdentifier(bytes []byte) (s []int, err error) {
+ if len(bytes) == 0 {
+ err = fmt.Errorf("zero length RELATIVE OBJECT IDENTIFIER")
+ return
+ }
+
+ s = make([]int, len(bytes)+1)
+
+ var v, offset int
+ i := 0
+ for ; offset < len(bytes); i++ {
+ v, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ s[i] = v
+ }
+ s = s[0:i]
+ return
+}
+
// parseBase128Int parses a base-128 encoded int from the given offset in the
// given byte slice. It returns the value and the new offset.
func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
diff --git a/vendor/github.com/go-ldap/ldap/v3/bind.go b/vendor/github.com/go-ldap/ldap/v3/bind.go
index a37f8e2c73..6cfd37ebeb 100644
--- a/vendor/github.com/go-ldap/ldap/v3/bind.go
+++ b/vendor/github.com/go-ldap/ldap/v3/bind.go
@@ -3,15 +3,19 @@ package ldap
import (
"bytes"
"crypto/md5"
+ "encoding/binary"
+ "encoding/hex"
enchex "encoding/hex"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"strings"
+ "unicode/utf16"
"github.com/Azure/go-ntlmssp"
ber "github.com/go-asn1-ber/asn1-ber"
+ "golang.org/x/crypto/md4" //nolint:staticcheck
)
// SimpleBindRequest represents a username/password bind operation
@@ -216,7 +220,7 @@ func (l *Conn) DigestMD5Bind(digestMD5BindRequest *DigestMD5BindRequest) (*Diges
}
}
- if params != nil {
+ if len(params) > 0 {
resp := computeResponse(
params,
"ldap/"+strings.ToLower(digestMD5BindRequest.Host),
@@ -249,6 +253,34 @@ func (l *Conn) DigestMD5Bind(digestMD5BindRequest *DigestMD5BindRequest) (*Diges
if err != nil {
return nil, fmt.Errorf("read packet: %s", err)
}
+
+ if len(packet.Children) == 2 {
+ response := packet.Children[1]
+ if response == nil {
+ return result, GetLDAPError(packet)
+ }
+ if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
+ if ber.Type(response.Children[0].Tag) == ber.Type(ber.TagInteger) || ber.Type(response.Children[0].Tag) == ber.Type(ber.TagEnumerated) {
+ resultCode := uint16(response.Children[0].Value.(int64))
+ if resultCode == 14 {
+ msgCtx, err := l.doRequest(digestMD5BindRequest)
+ if err != nil {
+ return nil, err
+ }
+ defer l.finishMessage(msgCtx)
+ packetResponse, ok := <-msgCtx.responses
+ if !ok {
+ return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
+ }
+ packet, err = packetResponse.ReadPacket()
+ l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
+ if err != nil {
+ return nil, fmt.Errorf("read packet: %s", err)
+ }
+ }
+ }
+ }
+ }
}
err = GetLDAPError(packet)
@@ -406,17 +438,36 @@ type NTLMBindRequest struct {
Hash string
// Controls are optional controls to send with the bind request
Controls []Control
+ // Negotiator allows to specify a custom NTLM negotiator.
+ Negotiator NTLMNegotiator
}
-func (req *NTLMBindRequest) appendTo(envelope *ber.Packet) error {
+// NTLMNegotiator is an abstraction of an NTLM implementation that produces and
+// processes NTLM binary tokens.
+type NTLMNegotiator interface {
+ Negotiate(domain string, workstation string) ([]byte, error)
+ ChallengeResponse(challenge []byte, username string, hash string) ([]byte, error)
+}
+
+func (req *NTLMBindRequest) appendTo(envelope *ber.Packet) (err error) {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "User Name"))
+ var negMessage []byte
+
// generate an NTLMSSP Negotiation message for the specified domain (it can be blank)
- negMessage, err := ntlmssp.NewNegotiateMessage(req.Domain, "")
- if err != nil {
- return fmt.Errorf("err creating negmessage: %s", err)
+ switch {
+ case req.Negotiator == nil:
+ negMessage, err = ntlmssp.NewNegotiateMessage(req.Domain, "")
+ if err != nil {
+ return fmt.Errorf("create NTLM negotiate message: %s", err)
+ }
+ default:
+ negMessage, err = req.Negotiator.Negotiate(req.Domain, "")
+ if err != nil {
+ return fmt.Errorf("create NTLM negotiate message with custom negotiator: %s", err)
+ }
}
// append the generated NTLMSSP message as a TagEnumerated BER value
@@ -514,18 +565,29 @@ func (l *Conn) NTLMChallengeBind(ntlmBindRequest *NTLMBindRequest) (*NTLMBindRes
if ntlmsspChallenge != nil {
var err error
var responseMessage []byte
- // generate a response message to the challenge with the given Username/Password if password is provided
- if ntlmBindRequest.Hash != "" {
+
+ switch {
+ case ntlmBindRequest.Hash == "" && ntlmBindRequest.Password == "" && !ntlmBindRequest.AllowEmptyPassword:
+ err = fmt.Errorf("need a password or hash to generate reply")
+ case ntlmBindRequest.Negotiator == nil && ntlmBindRequest.Hash != "":
responseMessage, err = ntlmssp.ProcessChallengeWithHash(ntlmsspChallenge, ntlmBindRequest.Username, ntlmBindRequest.Hash)
- } else if ntlmBindRequest.Password != "" || ntlmBindRequest.AllowEmptyPassword {
+ case ntlmBindRequest.Negotiator == nil && (ntlmBindRequest.Password != "" || ntlmBindRequest.AllowEmptyPassword):
+ // generate a response message to the challenge with the given Username/Password if password is provided
_, _, domainNeeded := ntlmssp.GetDomain(ntlmBindRequest.Username)
responseMessage, err = ntlmssp.ProcessChallenge(ntlmsspChallenge, ntlmBindRequest.Username, ntlmBindRequest.Password, domainNeeded)
- } else {
- err = fmt.Errorf("need a password or hash to generate reply")
+ default:
+ hash := ntlmBindRequest.Hash
+ if len(hash) == 0 {
+ hash = ntHash(ntlmBindRequest.Password)
+ }
+
+ responseMessage, err = ntlmBindRequest.Negotiator.ChallengeResponse(ntlmsspChallenge, ntlmBindRequest.Username, hash)
}
+
if err != nil {
- return result, fmt.Errorf("parsing ntlm-challenge: %s", err)
+ return result, fmt.Errorf("process NTLM challenge: %s", err)
}
+
packet = ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
@@ -559,6 +621,18 @@ func (l *Conn) NTLMChallengeBind(ntlmBindRequest *NTLMBindRequest) (*NTLMBindRes
return result, err
}
+func ntHash(pass string) string {
+ runes := utf16.Encode([]rune(pass))
+
+ b := bytes.Buffer{}
+ _ = binary.Write(&b, binary.LittleEndian, &runes)
+
+ hash := md4.New()
+ _, _ = hash.Write(b.Bytes())
+
+ return hex.EncodeToString(hash.Sum(nil))
+}
+
// GSSAPIClient interface is used as the client-side implementation for the
// GSSAPI SASL mechanism.
// Interface inspired by GSSAPIClient from golang.org/x/crypto/ssh
@@ -577,6 +651,9 @@ type GSSAPIClient interface {
// to InitSecContext via the token parameters.
// See RFC 4752 section 3.1.
InitSecContext(target string, token []byte) (outputToken []byte, needContinue bool, err error)
+ // InitSecContextWithOptions is the same as InitSecContext but allows for additional options to be passed to the context establishment.
+ // See RFC 4752 section 3.1.
+ InitSecContextWithOptions(target string, token []byte, options []int) (outputToken []byte, needContinue bool, err error)
// NegotiateSaslAuth performs the last step of the Sasl handshake.
// It takes a token, which, when unwrapped, describes the servers supported
// security layers (first octet) and maximum receive buffer (remaining
@@ -614,6 +691,11 @@ func (l *Conn) GSSAPIBind(client GSSAPIClient, servicePrincipal, authzid string)
// GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client.
func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) error {
+ return l.GSSAPIBindRequestWithAPOptions(client, req, []int{})
+}
+
+// GSSAPIBindRequest performs the GSSAPI SASL bind using the provided GSSAPI client.
+func (l *Conn) GSSAPIBindRequestWithAPOptions(client GSSAPIClient, req *GSSAPIBindRequest, APOptions []int) error {
//nolint:errcheck
defer client.DeleteSecContext()
@@ -624,7 +706,7 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) er
for {
if needInit {
// Establish secure context between client and server.
- reqToken, needInit, err = client.InitSecContext(req.ServicePrincipalName, recvToken)
+ reqToken, needInit, err = client.InitSecContextWithOptions(req.ServicePrincipalName, recvToken, APOptions)
if err != nil {
return err
}
diff --git a/vendor/github.com/go-ldap/ldap/v3/control.go b/vendor/github.com/go-ldap/ldap/v3/control.go
index ab75c34239..f1c2746ba6 100644
--- a/vendor/github.com/go-ldap/ldap/v3/control.go
+++ b/vendor/github.com/go-ldap/ldap/v3/control.go
@@ -709,7 +709,7 @@ func (c *ControlDirSync) Encode() *ber.Packet {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeDirSync, "Control Type ("+ControlTypeMap[ControlTypeDirSync]+")"))
- packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) // must be true always
+ packet.AppendChild(ber.NewLDAPBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) // must be true always
val := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (DirSync)")
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "DirSync Control Value")
@@ -755,7 +755,7 @@ func NewControlServerSideSorting(value *ber.Packet) (*ControlServerSideSorting,
sequences := val[0].Children
for i, sequence := range sequences {
- sortKey := &SortKey{}
+ sortKey := new(SortKey)
if len(sequence.Children) < 2 {
return nil, fmt.Errorf("attributeType or matchingRule is missing from sequence %d", i)
@@ -864,10 +864,14 @@ func (c ControlServerSideSortingCode) Valid() error {
}
func NewControlServerSideSortingResult(pkt *ber.Packet) (*ControlServerSideSortingResult, error) {
- control := &ControlServerSideSortingResult{}
+ control := new(ControlServerSideSortingResult)
if pkt == nil || len(pkt.Children) == 0 {
- return nil, fmt.Errorf("bad packet")
+ // This is currently not compliant with the ServerSideSorting RFC (see https://datatracker.ietf.org/doc/html/rfc2891#section-1.2).
+ // but it's necessary because there seems to be a bug in the implementation of the popular OpenLDAP server.
+ //
+ // See: https://github.com/go-ldap/ldap/pull/546
+ return control, nil
}
codeInt, err := ber.ParseInt64(pkt.Children[0].Data.Bytes())
@@ -875,8 +879,7 @@ func NewControlServerSideSortingResult(pkt *ber.Packet) (*ControlServerSideSorti
return nil, err
}
- code := ControlServerSideSortingCode(codeInt)
- if err := code.Valid(); err != nil {
+ if err = ControlServerSideSortingCode(codeInt).Valid(); err != nil {
return nil, err
}
diff --git a/vendor/github.com/jonboulle/clockwork/README.md b/vendor/github.com/jonboulle/clockwork/README.md
index cad6083572..5e9d472ea3 100644
--- a/vendor/github.com/jonboulle/clockwork/README.md
+++ b/vendor/github.com/jonboulle/clockwork/README.md
@@ -2,9 +2,9 @@
[](https://github.com/avelino/awesome-go#utilities)
-[](https://github.com/jonboulle/clockwork/actions?query=workflow%3ACI)
+[](https://github.com/jonboulle/clockwork/actions?query=workflow%3ACI)
[](https://goreportcard.com/report/github.com/jonboulle/clockwork)
-
+
[](https://pkg.go.dev/mod/github.com/jonboulle/clockwork)
**A simple fake clock for Go.**
@@ -36,6 +36,7 @@ Now you can easily test `myFunc` with a `FakeClock`:
```go
func TestMyFunc(t *testing.T) {
+ ctx := context.Background()
c := clockwork.NewFakeClock()
// Start our sleepy function
@@ -46,8 +47,12 @@ func TestMyFunc(t *testing.T) {
wg.Done()
}()
- // Ensure we wait until myFunc is sleeping
- c.BlockUntil(1)
+ // Ensure we wait until myFunc is waiting on the clock.
+ // Use a context to avoid blocking forever if something
+ // goes wrong.
+ ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
+ defer cancel()
+ c.BlockUntilContext(ctx, 1)
assertState()
diff --git a/vendor/github.com/jonboulle/clockwork/SECURITY.md b/vendor/github.com/jonboulle/clockwork/SECURITY.md
new file mode 100644
index 0000000000..0efcad9f68
--- /dev/null
+++ b/vendor/github.com/jonboulle/clockwork/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+If you have discovered a security vulnerability in this project, please report it
+privately. **Do not disclose it as a public issue.** This gives me time to work with you
+to fix the issue before public exposure, reducing the chance that the exploit will be
+used before a patch is released.
+
+You may submit the report in the following ways:
+
+- send an email to ???@???; and/or
+- send a [private vulnerability report](https://github.com/jonboulle/clockwork/security/advisories/new)
+
+Please provide the following information in your report:
+
+- A description of the vulnerability and its impact
+- How to reproduce the issue
+
+This project is maintained by a single maintainer on a reasonable-effort basis. As such,
+please give me 90 days to work on a fix before public exposure.
diff --git a/vendor/github.com/jonboulle/clockwork/clockwork.go b/vendor/github.com/jonboulle/clockwork/clockwork.go
index 1018051f4a..85a993467d 100644
--- a/vendor/github.com/jonboulle/clockwork/clockwork.go
+++ b/vendor/github.com/jonboulle/clockwork/clockwork.go
@@ -1,30 +1,25 @@
+// Package clockwork contains a simple fake clock for Go.
package clockwork
import (
+ "context"
+ "errors"
+ "slices"
"sync"
"time"
)
-// Clock provides an interface that packages can use instead of directly
-// using the time module, so that chronology-related behavior can be tested
+// Clock provides an interface that packages can use instead of directly using
+// the [time] module, so that chronology-related behavior can be tested.
type Clock interface {
After(d time.Duration) <-chan time.Time
Sleep(d time.Duration)
Now() time.Time
Since(t time.Time) time.Duration
+ Until(t time.Time) time.Duration
NewTicker(d time.Duration) Ticker
-}
-
-// FakeClock provides an interface for a clock which can be
-// manually advanced through time
-type FakeClock interface {
- Clock
- // Advance advances the FakeClock to a new point in time, ensuring any existing
- // sleepers are notified appropriately before returning
- Advance(d time.Duration)
- // BlockUntil will block until the FakeClock has the given number of
- // sleepers (callers of Sleep or After)
- BlockUntil(n int)
+ NewTimer(d time.Duration) Timer
+ AfterFunc(d time.Duration, f func()) Timer
}
// NewRealClock returns a Clock which simply delegates calls to the actual time
@@ -33,21 +28,6 @@ func NewRealClock() Clock {
return &realClock{}
}
-// NewFakeClock returns a FakeClock implementation which can be
-// manually advanced through time for testing. The initial time of the
-// FakeClock will be an arbitrary non-zero time.
-func NewFakeClock() FakeClock {
- // use a fixture that does not fulfill Time.IsZero()
- return NewFakeClockAt(time.Date(1984, time.April, 4, 0, 0, 0, 0, time.UTC))
-}
-
-// NewFakeClockAt returns a FakeClock initialised at the given time.Time.
-func NewFakeClockAt(t time.Time) FakeClock {
- return &fakeClock{
- time: t,
- }
-}
-
type realClock struct{}
func (rc *realClock) After(d time.Duration) <-chan time.Time {
@@ -66,130 +46,274 @@ func (rc *realClock) Since(t time.Time) time.Duration {
return rc.Now().Sub(t)
}
-func (rc *realClock) NewTicker(d time.Duration) Ticker {
- return &realTicker{time.NewTicker(d)}
+func (rc *realClock) Until(t time.Time) time.Duration {
+ return t.Sub(rc.Now())
}
-type fakeClock struct {
- sleepers []*sleeper
+func (rc *realClock) NewTicker(d time.Duration) Ticker {
+ return realTicker{time.NewTicker(d)}
+}
+
+func (rc *realClock) NewTimer(d time.Duration) Timer {
+ return realTimer{time.NewTimer(d)}
+}
+
+func (rc *realClock) AfterFunc(d time.Duration, f func()) Timer {
+ return realTimer{time.AfterFunc(d, f)}
+}
+
+// FakeClock provides an interface for a clock which can be manually advanced
+// through time.
+//
+// FakeClock maintains a list of "waiters," which consists of all callers
+// waiting on the underlying clock (i.e. Tickers and Timers including callers of
+// Sleep or After). Users can call BlockUntil to block until the clock has an
+// expected number of waiters.
+type FakeClock struct {
+ // l protects all attributes of the clock, including all attributes of all
+ // waiters and blockers.
+ l sync.RWMutex
+ waiters []expirer
blockers []*blocker
time time.Time
-
- l sync.RWMutex
}
-// sleeper represents a caller of After or Sleep
-type sleeper struct {
- until time.Time
- done chan time.Time
+// NewFakeClock returns a FakeClock implementation which can be
+// manually advanced through time for testing. The initial time of the
+// FakeClock will be the current system time.
+//
+// Tests that require a deterministic time must use NewFakeClockAt.
+func NewFakeClock() *FakeClock {
+ return NewFakeClockAt(time.Now())
}
-// blocker represents a caller of BlockUntil
+// NewFakeClockAt returns a FakeClock initialised at the given time.Time.
+func NewFakeClockAt(t time.Time) *FakeClock {
+ return &FakeClock{
+ time: t,
+ }
+}
+
+// blocker is a caller of BlockUntil.
type blocker struct {
count int
- ch chan struct{}
+
+ // ch is closed when the underlying clock has the specified number of blockers.
+ ch chan struct{}
}
-// After mimics time.After; it waits for the given duration to elapse on the
+// expirer is a timer or ticker that expires at some point in the future.
+type expirer interface {
+ // expire the expirer at the given time, returning the desired duration until
+ // the next expiration, if any.
+ expire(now time.Time) (next *time.Duration)
+
+ // Get and set the expiration time.
+ expiration() time.Time
+ setExpiration(time.Time)
+}
+
+// After mimics [time.After]; it waits for the given duration to elapse on the
// fakeClock, then sends the current time on the returned channel.
-func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
- fc.l.Lock()
- defer fc.l.Unlock()
- now := fc.time
- done := make(chan time.Time, 1)
- if d.Nanoseconds() <= 0 {
- // special case - trigger immediately
- done <- now
- } else {
- // otherwise, add to the set of sleepers
- s := &sleeper{
- until: now.Add(d),
- done: done,
- }
- fc.sleepers = append(fc.sleepers, s)
- // and notify any blockers
- fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
- }
- return done
+func (fc *FakeClock) After(d time.Duration) <-chan time.Time {
+ return fc.NewTimer(d).Chan()
}
-// notifyBlockers notifies all the blockers waiting until the
-// given number of sleepers are waiting on the fakeClock. It
-// returns an updated slice of blockers (i.e. those still waiting)
-func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
- for _, b := range blockers {
- if b.count == count {
- close(b.ch)
- } else {
- newBlockers = append(newBlockers, b)
- }
- }
- return
-}
-
-// Sleep blocks until the given duration has passed on the fakeClock
-func (fc *fakeClock) Sleep(d time.Duration) {
+// Sleep blocks until the given duration has passed on the fakeClock.
+func (fc *FakeClock) Sleep(d time.Duration) {
<-fc.After(d)
}
-// Time returns the current time of the fakeClock
-func (fc *fakeClock) Now() time.Time {
+// Now returns the current time of the fakeClock
+func (fc *FakeClock) Now() time.Time {
fc.l.RLock()
- t := fc.time
- fc.l.RUnlock()
- return t
+ defer fc.l.RUnlock()
+ return fc.time
}
-// Since returns the duration that has passed since the given time on the fakeClock
-func (fc *fakeClock) Since(t time.Time) time.Duration {
+// Since returns the duration that has passed since the given time on the
+// fakeClock.
+func (fc *FakeClock) Since(t time.Time) time.Duration {
return fc.Now().Sub(t)
}
-func (fc *fakeClock) NewTicker(d time.Duration) Ticker {
- ft := &fakeTicker{
- c: make(chan time.Time, 1),
- stop: make(chan bool, 1),
- clock: fc,
- period: d,
+// Until returns the duration that has to pass from the given time on the fakeClock
+// to reach the given time.
+func (fc *FakeClock) Until(t time.Time) time.Duration {
+ return t.Sub(fc.Now())
+}
+
+// NewTicker returns a Ticker that will expire only after calls to
+// FakeClock.Advance() have moved the clock past the given duration.
+//
+// The duration d must be greater than zero; if not, NewTicker will panic.
+func (fc *FakeClock) NewTicker(d time.Duration) Ticker {
+ // Maintain parity with
+ // https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/time/tick.go;l=23-25
+ if d <= 0 {
+ panic(errors.New("non-positive interval for NewTicker"))
}
- ft.runTickThread()
+ ft := newFakeTicker(fc, d)
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ fc.setExpirer(ft, d)
return ft
}
-// Advance advances fakeClock to a new point in time, ensuring channels from any
-// previous invocations of After are notified appropriately before returning
-func (fc *fakeClock) Advance(d time.Duration) {
+// NewTimer returns a Timer that will fire only after calls to
+// fakeClock.Advance() have moved the clock past the given duration.
+func (fc *FakeClock) NewTimer(d time.Duration) Timer {
+ t, _ := fc.newTimer(d, nil)
+ return t
+}
+
+// AfterFunc mimics [time.AfterFunc]; it returns a Timer that will invoke the
+// given function only after calls to fakeClock.Advance() have moved the clock
+// past the given duration.
+func (fc *FakeClock) AfterFunc(d time.Duration, f func()) Timer {
+ t, _ := fc.newTimer(d, f)
+ return t
+}
+
+// newTimer returns a new timer using an optional afterFunc and the time that
+// timer expires.
+func (fc *FakeClock) newTimer(d time.Duration, afterfunc func()) (*fakeTimer, time.Time) {
+ ft := newFakeTimer(fc, afterfunc)
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ fc.setExpirer(ft, d)
+ return ft, ft.expiration()
+}
+
+// newTimerAtTime is like newTimer, but uses a time instead of a duration.
+//
+// It is used to ensure FakeClock's lock is held constant through calling
+// fc.After(t.Sub(fc.Now())). It should not be exposed externally.
+func (fc *FakeClock) newTimerAtTime(t time.Time, afterfunc func()) *fakeTimer {
+ ft := newFakeTimer(fc, afterfunc)
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ fc.setExpirer(ft, t.Sub(fc.time))
+ return ft
+}
+
+// Advance advances fakeClock to a new point in time, ensuring waiters and
+// blockers are notified appropriately before returning.
+func (fc *FakeClock) Advance(d time.Duration) {
fc.l.Lock()
defer fc.l.Unlock()
end := fc.time.Add(d)
- var newSleepers []*sleeper
- for _, s := range fc.sleepers {
- if end.Sub(s.until) >= 0 {
- s.done <- end
- } else {
- newSleepers = append(newSleepers, s)
+ // Expire the earliest waiter until the earliest waiter's expiration is after
+ // end.
+ //
+ // We don't iterate because the callback of the waiter might register a new
+ // waiter, so the list of waiters might change as we execute this.
+ for len(fc.waiters) > 0 && !end.Before(fc.waiters[0].expiration()) {
+ w := fc.waiters[0]
+ fc.waiters = fc.waiters[1:]
+
+ // Use the waiter's expiration as the current time for this expiration.
+ now := w.expiration()
+ fc.time = now
+ if d := w.expire(now); d != nil {
+ // Set the new expiration if needed.
+ fc.setExpirer(w, *d)
}
}
- fc.sleepers = newSleepers
- fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
fc.time = end
}
-// BlockUntil will block until the fakeClock has the given number of sleepers
-// (callers of Sleep or After)
-func (fc *fakeClock) BlockUntil(n int) {
- fc.l.Lock()
- // Fast path: current number of sleepers is what we're looking for
- if len(fc.sleepers) == n {
- fc.l.Unlock()
- return
+// BlockUntil blocks until the FakeClock has the given number of waiters.
+//
+// Prefer BlockUntilContext in new code, which offers context cancellation to
+// prevent deadlock.
+//
+// Deprecated: New code should prefer BlockUntilContext.
+func (fc *FakeClock) BlockUntil(n int) {
+ fc.BlockUntilContext(context.TODO(), n)
+}
+
+// BlockUntilContext blocks until the fakeClock has the given number of waiters
+// or the context is cancelled.
+func (fc *FakeClock) BlockUntilContext(ctx context.Context, n int) error {
+ b := fc.newBlocker(n)
+ if b == nil {
+ return nil
}
- // Otherwise, set up a new blocker
+
+ select {
+ case <-b.ch:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
+
+func (fc *FakeClock) newBlocker(n int) *blocker {
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ // Fast path: we already have >= n waiters.
+ if len(fc.waiters) >= n {
+ return nil
+ }
+ // Set up a new blocker to wait for more waiters.
b := &blocker{
count: n,
ch: make(chan struct{}),
}
fc.blockers = append(fc.blockers, b)
- fc.l.Unlock()
- <-b.ch
+ return b
+}
+
+// stop stops an expirer, returning true if the expirer was stopped.
+func (fc *FakeClock) stop(e expirer) bool {
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ return fc.stopExpirer(e)
+}
+
+// stopExpirer stops an expirer, returning true if the expirer was stopped.
+//
+// The caller must hold fc.l.
+func (fc *FakeClock) stopExpirer(e expirer) bool {
+ idx := slices.Index(fc.waiters, e)
+ if idx == -1 {
+ return false
+ }
+ // Remove element, maintaining order, setting inaccessible elements to nil so
+ // they can be garbage collected.
+ copy(fc.waiters[idx:], fc.waiters[idx+1:])
+ fc.waiters[len(fc.waiters)-1] = nil
+ fc.waiters = fc.waiters[:len(fc.waiters)-1]
+ return true
+}
+
+// setExpirer sets an expirer to expire at a future point in time.
+//
+// The caller must hold fc.l.
+func (fc *FakeClock) setExpirer(e expirer, d time.Duration) {
+ if d.Nanoseconds() <= 0 {
+ // Special case for timers with duration <= 0: trigger immediately, never
+ // reset.
+ //
+ // Tickers never get here, they panic if d is < 0.
+ e.expire(fc.time)
+ return
+ }
+ // Add the expirer to the set of waiters and notify any blockers.
+ e.setExpiration(fc.time.Add(d))
+ fc.waiters = append(fc.waiters, e)
+ slices.SortFunc(fc.waiters, func(a, b expirer) int {
+ return a.expiration().Compare(b.expiration())
+ })
+
+ // Notify blockers of our new waiter.
+ count := len(fc.waiters)
+ fc.blockers = slices.DeleteFunc(fc.blockers, func(b *blocker) bool {
+ if b.count <= count {
+ close(b.ch)
+ return true
+ }
+ return false
+ })
}
diff --git a/vendor/github.com/jonboulle/clockwork/context.go b/vendor/github.com/jonboulle/clockwork/context.go
new file mode 100644
index 0000000000..59242619e7
--- /dev/null
+++ b/vendor/github.com/jonboulle/clockwork/context.go
@@ -0,0 +1,169 @@
+package clockwork
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+)
+
+// contextKey is private to this package so we can ensure uniqueness here. This
+// type identifies context values provided by this package.
+type contextKey string
+
+// keyClock provides a clock for injecting during tests. If absent, a real clock
+// should be used.
+var keyClock = contextKey("clock") // clockwork.Clock
+
+// AddToContext creates a derived context that references the specified clock.
+//
+// Be aware this doesn't change the behavior of standard library functions, such
+// as [context.WithTimeout] or [context.WithDeadline]. For this reason, users
+// should prefer passing explicit [clockwork.Clock] variables rather can passing
+// the clock via the context.
+func AddToContext(ctx context.Context, clock Clock) context.Context {
+ return context.WithValue(ctx, keyClock, clock)
+}
+
+// FromContext extracts a clock from the context. If not present, a real clock
+// is returned.
+func FromContext(ctx context.Context) Clock {
+ if clock, ok := ctx.Value(keyClock).(Clock); ok {
+ return clock
+ }
+ return NewRealClock()
+}
+
+// ErrFakeClockDeadlineExceeded is the error returned by [context.Context] when
+// the deadline passes on a context which uses a [FakeClock].
+//
+// It wraps a [context.DeadlineExceeded] error, i.e.:
+//
+// // The following is true for any Context whose deadline has been exceeded,
+// // including contexts made with clockwork.WithDeadline or clockwork.WithTimeout.
+//
+// errors.Is(ctx.Err(), context.DeadlineExceeded)
+//
+// // The following can only be true for contexts made
+// // with clockwork.WithDeadline or clockwork.WithTimeout.
+//
+// errors.Is(ctx.Err(), clockwork.ErrFakeClockDeadlineExceeded)
+var ErrFakeClockDeadlineExceeded error = fmt.Errorf("clockwork.FakeClock: %w", context.DeadlineExceeded)
+
+// WithDeadline returns a context with a deadline based on a [FakeClock].
+//
+// The returned context ignores parent cancelation if the parent was cancelled
+// with a [context.DeadlineExceeded] error. Any other error returned by the
+// parent is treated normally, cancelling the returned context.
+//
+// If the parent is cancelled with a [context.DeadlineExceeded] error, the only
+// way to then cancel the returned context is by calling the returned
+// context.CancelFunc.
+func WithDeadline(parent context.Context, clock Clock, t time.Time) (context.Context, context.CancelFunc) {
+ if fc, ok := clock.(*FakeClock); ok {
+ return newFakeClockContext(parent, t, fc.newTimerAtTime(t, nil).Chan())
+ }
+ return context.WithDeadline(parent, t)
+}
+
+// WithTimeout returns a context with a timeout based on a [FakeClock].
+//
+// The returned context follows the same behaviors as [WithDeadline].
+func WithTimeout(parent context.Context, clock Clock, d time.Duration) (context.Context, context.CancelFunc) {
+ if fc, ok := clock.(*FakeClock); ok {
+ t, deadline := fc.newTimer(d, nil)
+ return newFakeClockContext(parent, deadline, t.Chan())
+ }
+ return context.WithTimeout(parent, d)
+}
+
+// fakeClockContext implements context.Context, using a fake clock for its
+// deadline.
+//
+// It ignores parent cancellation if the parent is cancelled with
+// context.DeadlineExceeded.
+type fakeClockContext struct {
+ parent context.Context
+ deadline time.Time // The user-facing deadline based on the fake clock's time.
+
+ // Tracks timeout/deadline cancellation.
+ timerDone <-chan time.Time
+
+ // Tracks manual calls to the cancel function.
+ cancel func() // Closes cancelCalled wrapped in a sync.Once.
+ cancelCalled chan struct{}
+
+ // The user-facing data from the context.Context interface.
+ ctxDone chan struct{} // Returned by Done().
+ err error // nil until ctxDone is ready to be closed.
+}
+
+func newFakeClockContext(parent context.Context, deadline time.Time, timer <-chan time.Time) (context.Context, context.CancelFunc) {
+ cancelCalled := make(chan struct{})
+ ctx := &fakeClockContext{
+ parent: parent,
+ deadline: deadline,
+ timerDone: timer,
+ cancelCalled: cancelCalled,
+ ctxDone: make(chan struct{}),
+ cancel: sync.OnceFunc(func() {
+ close(cancelCalled)
+ }),
+ }
+ ready := make(chan struct{}, 1)
+ go ctx.runCancel(ready)
+ <-ready // Wait until the cancellation goroutine is running.
+ return ctx, ctx.cancel
+}
+
+func (c *fakeClockContext) Deadline() (time.Time, bool) {
+ return c.deadline, true
+}
+
+func (c *fakeClockContext) Done() <-chan struct{} {
+ return c.ctxDone
+}
+
+func (c *fakeClockContext) Err() error {
+ <-c.Done() // Don't return the error before it is ready.
+ return c.err
+}
+
+func (c *fakeClockContext) Value(key any) any {
+ return c.parent.Value(key)
+}
+
+// runCancel runs the fakeClockContext's cancel goroutine and returns the
+// fakeClockContext's cancel function.
+//
+// fakeClockContext is then cancelled when any of the following occur:
+//
+// - The fakeClockContext.done channel is closed by its timer.
+// - The returned CancelFunc is executed.
+// - The fakeClockContext's parent context is cancelled with an error other
+// than context.DeadlineExceeded.
+func (c *fakeClockContext) runCancel(ready chan struct{}) {
+ parentDone := c.parent.Done()
+
+ // Close ready when done, just in case the ready signal races with other
+ // branches of our select statement below.
+ defer close(ready)
+
+ for c.err == nil {
+ select {
+ case <-c.timerDone:
+ c.err = ErrFakeClockDeadlineExceeded
+ case <-c.cancelCalled:
+ c.err = context.Canceled
+ case <-parentDone:
+ c.err = c.parent.Err()
+
+ case ready <- struct{}{}:
+ // Signals the cancellation goroutine has begun, in an attempt to minimize
+ // race conditions related to goroutine startup time.
+ ready = nil // This case statement can only fire once.
+ }
+ }
+ close(c.ctxDone)
+ return
+}
diff --git a/vendor/github.com/jonboulle/clockwork/ticker.go b/vendor/github.com/jonboulle/clockwork/ticker.go
index 32b5d01e75..aa56952e71 100644
--- a/vendor/github.com/jonboulle/clockwork/ticker.go
+++ b/vendor/github.com/jonboulle/clockwork/ticker.go
@@ -1,72 +1,71 @@
package clockwork
-import (
- "time"
-)
+import "time"
-// Ticker provides an interface which can be used instead of directly
-// using the ticker within the time module. The real-time ticker t
-// provides ticks through t.C which becomes now t.Chan() to make
-// this channel requirement definable in this interface.
+// Ticker provides an interface which can be used instead of directly using
+// [time.Ticker]. The real-time ticker t provides ticks through t.C which
+// becomes t.Chan() to make this channel requirement definable in this
+// interface.
type Ticker interface {
Chan() <-chan time.Time
+ Reset(d time.Duration)
Stop()
}
type realTicker struct{ *time.Ticker }
-func (rt *realTicker) Chan() <-chan time.Time {
- return rt.C
+func (r realTicker) Chan() <-chan time.Time {
+ return r.C
}
type fakeTicker struct {
- c chan time.Time
- stop chan bool
- clock FakeClock
- period time.Duration
+ // The channel associated with the firer, used to send expiration times.
+ c chan time.Time
+
+ // The time when the ticker expires. Only meaningful if the ticker is currently
+ // one of a FakeClock's waiters.
+ exp time.Time
+
+ // reset and stop provide the implementation of the respective exported
+ // functions.
+ reset func(d time.Duration)
+ stop func()
+
+ // The duration of the ticker.
+ d time.Duration
}
-func (ft *fakeTicker) Chan() <-chan time.Time {
- return ft.c
+func newFakeTicker(fc *FakeClock, d time.Duration) *fakeTicker {
+ var ft *fakeTicker
+ ft = &fakeTicker{
+ c: make(chan time.Time, 1),
+ d: d,
+ reset: func(d time.Duration) {
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ ft.d = d
+ fc.setExpirer(ft, d)
+ },
+ stop: func() { fc.stop(ft) },
+ }
+ return ft
}
-func (ft *fakeTicker) Stop() {
- ft.stop <- true
+func (f *fakeTicker) Chan() <-chan time.Time { return f.c }
+
+func (f *fakeTicker) Reset(d time.Duration) { f.reset(d) }
+
+func (f *fakeTicker) Stop() { f.stop() }
+
+func (f *fakeTicker) expire(now time.Time) *time.Duration {
+ // Never block on expiration.
+ select {
+ case f.c <- now:
+ default:
+ }
+ return &f.d
}
-// runTickThread initializes a background goroutine to send the tick time to the ticker channel
-// after every period. Tick events are discarded if the underlying ticker channel does not have
-// enough capacity.
-func (ft *fakeTicker) runTickThread() {
- nextTick := ft.clock.Now().Add(ft.period)
- next := ft.clock.After(ft.period)
- go func() {
- for {
- select {
- case <-ft.stop:
- return
- case <-next:
- // We send the time that the tick was supposed to occur at.
- tick := nextTick
- // Before sending the tick, we'll compute the next tick time and star the clock.After call.
- now := ft.clock.Now()
- // First, figure out how many periods there have been between "now" and the time we were
- // supposed to have trigged, then advance over all of those.
- skipTicks := (now.Sub(tick) + ft.period - 1) / ft.period
- nextTick = nextTick.Add(skipTicks * ft.period)
- // Now, keep advancing until we are past now. This should happen at most once.
- for !nextTick.After(now) {
- nextTick = nextTick.Add(ft.period)
- }
- // Figure out how long between now and the next scheduled tick, then wait that long.
- remaining := nextTick.Sub(now)
- next = ft.clock.After(remaining)
- // Finally, we can actually send the tick.
- select {
- case ft.c <- tick:
- default:
- }
- }
- }
- }()
-}
+func (f *fakeTicker) expiration() time.Time { return f.exp }
+
+func (f *fakeTicker) setExpiration(t time.Time) { f.exp = t }
diff --git a/vendor/github.com/jonboulle/clockwork/timer.go b/vendor/github.com/jonboulle/clockwork/timer.go
new file mode 100644
index 0000000000..e7e1d40010
--- /dev/null
+++ b/vendor/github.com/jonboulle/clockwork/timer.go
@@ -0,0 +1,79 @@
+package clockwork
+
+import "time"
+
+// Timer provides an interface which can be used instead of directly using
+// [time.Timer]. The real-time timer t provides events through t.C which becomes
+// t.Chan() to make this channel requirement definable in this interface.
+type Timer interface {
+ Chan() <-chan time.Time
+ Reset(d time.Duration) bool
+ Stop() bool
+}
+
+type realTimer struct{ *time.Timer }
+
+func (r realTimer) Chan() <-chan time.Time {
+ return r.C
+}
+
+type fakeTimer struct {
+ // The channel associated with the firer, used to send expiration times.
+ c chan time.Time
+
+ // The time when the firer expires. Only meaningful if the firer is currently
+ // one of a FakeClock's waiters.
+ exp time.Time
+
+ // reset and stop provide the implementation of the respective exported
+ // functions.
+ reset func(d time.Duration) bool
+ stop func() bool
+
+ // If present when the timer fires, the timer calls afterFunc in its own
+ // goroutine rather than sending the time on Chan().
+ afterFunc func()
+}
+
+func newFakeTimer(fc *FakeClock, afterfunc func()) *fakeTimer {
+ var ft *fakeTimer
+ ft = &fakeTimer{
+ c: make(chan time.Time, 1),
+ reset: func(d time.Duration) bool {
+ fc.l.Lock()
+ defer fc.l.Unlock()
+ // fc.l must be held across the calls to stopExpirer & setExpirer.
+ stopped := fc.stopExpirer(ft)
+ fc.setExpirer(ft, d)
+ return stopped
+ },
+ stop: func() bool { return fc.stop(ft) },
+
+ afterFunc: afterfunc,
+ }
+ return ft
+}
+
+func (f *fakeTimer) Chan() <-chan time.Time { return f.c }
+
+func (f *fakeTimer) Reset(d time.Duration) bool { return f.reset(d) }
+
+func (f *fakeTimer) Stop() bool { return f.stop() }
+
+func (f *fakeTimer) expire(now time.Time) *time.Duration {
+ if f.afterFunc != nil {
+ go f.afterFunc()
+ return nil
+ }
+
+ // Never block on expiration.
+ select {
+ case f.c <- now:
+ default:
+ }
+ return nil
+}
+
+func (f *fakeTimer) expiration() time.Time { return f.exp }
+
+func (f *fakeTimer) setExpiration(t time.Time) { f.exp = t }
diff --git a/vendor/github.com/libregraph/lico/bootstrap/backends/ldap/ldap.go b/vendor/github.com/libregraph/lico/bootstrap/backends/ldap/ldap.go
index 943a55e703..7b8604d373 100644
--- a/vendor/github.com/libregraph/lico/bootstrap/backends/ldap/ldap.go
+++ b/vendor/github.com/libregraph/lico/bootstrap/backends/ldap/ldap.go
@@ -143,10 +143,11 @@ func NewIdentityManager(bs bootstrap.Bootstrap) (identity.Manager, error) {
AuthorizationEndpointURI: fullAuthorizationEndpointURL,
SignedOutEndpointURI: fullSignedOutEndpointURL,
- DefaultBannerLogo: config.IdentifierDefaultBannerLogo,
- DefaultSignInPageText: config.IdentifierDefaultSignInPageText,
- DefaultUsernameHintText: config.IdentifierDefaultUsernameHintText,
- UILocales: config.IdentifierUILocales,
+ DefaultBannerLogo: config.IdentifierDefaultBannerLogo,
+ DefaultSignInPageText: config.IdentifierDefaultSignInPageText,
+ DefaultSignInPageLogoURI: config.IdentifierDefaultLogoTargetURI,
+ DefaultUsernameHintText: config.IdentifierDefaultUsernameHintText,
+ UILocales: config.IdentifierUILocales,
Backend: identifierBackend,
})
diff --git a/vendor/github.com/libregraph/lico/bootstrap/backends/libregraph/libregraph.go b/vendor/github.com/libregraph/lico/bootstrap/backends/libregraph/libregraph.go
index 0fe760c041..ded47b49c8 100644
--- a/vendor/github.com/libregraph/lico/bootstrap/backends/libregraph/libregraph.go
+++ b/vendor/github.com/libregraph/lico/bootstrap/backends/libregraph/libregraph.go
@@ -126,10 +126,11 @@ func NewIdentityManager(bs bootstrap.Bootstrap) (identity.Manager, error) {
AuthorizationEndpointURI: fullAuthorizationEndpointURL,
SignedOutEndpointURI: fullSignedOutEndpointURL,
- DefaultBannerLogo: config.IdentifierDefaultBannerLogo,
- DefaultSignInPageText: config.IdentifierDefaultSignInPageText,
- DefaultUsernameHintText: config.IdentifierDefaultUsernameHintText,
- UILocales: config.IdentifierUILocales,
+ DefaultBannerLogo: config.IdentifierDefaultBannerLogo,
+ DefaultSignInPageText: config.IdentifierDefaultSignInPageText,
+ DefaultSignInPageLogoURI: config.IdentifierDefaultLogoTargetURI,
+ DefaultUsernameHintText: config.IdentifierDefaultUsernameHintText,
+ UILocales: config.IdentifierUILocales,
Backend: identifierBackend,
})
diff --git a/vendor/github.com/libregraph/lico/bootstrap/bootstrap.go b/vendor/github.com/libregraph/lico/bootstrap/bootstrap.go
index 9002c16904..a06ac94671 100644
--- a/vendor/github.com/libregraph/lico/bootstrap/bootstrap.go
+++ b/vendor/github.com/libregraph/lico/bootstrap/bootstrap.go
@@ -33,7 +33,7 @@ import (
"strings"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/longsleep/rndm"
"github.com/sirupsen/logrus"
@@ -260,6 +260,9 @@ func (bs *bootstrap) initialize(settings *Settings) error {
if settings.IdentifierDefaultSignInPageText != "" {
bs.config.IdentifierDefaultSignInPageText = &settings.IdentifierDefaultSignInPageText
}
+ if settings.IdentifierDefaultLogoTargetURI != "" {
+ bs.config.IdentifierDefaultLogoTargetURI = &settings.IdentifierDefaultLogoTargetURI
+ }
if settings.IdentifierDefaultUsernameHintText != "" {
bs.config.IdentifierDefaultUsernameHintText = &settings.IdentifierDefaultUsernameHintText
}
diff --git a/vendor/github.com/libregraph/lico/bootstrap/config.go b/vendor/github.com/libregraph/lico/bootstrap/config.go
index de42e711e0..8abe40ffb3 100644
--- a/vendor/github.com/libregraph/lico/bootstrap/config.go
+++ b/vendor/github.com/libregraph/lico/bootstrap/config.go
@@ -24,7 +24,7 @@ import (
"net/http"
"net/url"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/config"
)
@@ -51,6 +51,7 @@ type Config struct {
IdentifierScopesConf string
IdentifierDefaultBannerLogo []byte
IdentifierDefaultSignInPageText *string
+ IdentifierDefaultLogoTargetURI *string
IdentifierDefaultUsernameHintText *string
IdentifierUILocales []string
diff --git a/vendor/github.com/libregraph/lico/bootstrap/settings.go b/vendor/github.com/libregraph/lico/bootstrap/settings.go
index a5cdc434c4..549831ff56 100644
--- a/vendor/github.com/libregraph/lico/bootstrap/settings.go
+++ b/vendor/github.com/libregraph/lico/bootstrap/settings.go
@@ -44,6 +44,7 @@ type Settings struct {
IdentifierScopesConf string
IdentifierDefaultBannerLogo string
IdentifierDefaultSignInPageText string
+ IdentifierDefaultLogoTargetURI string
IdentifierDefaultUsernameHintText string
IdentifierUILocales []string
SigningKid string
diff --git a/vendor/github.com/libregraph/lico/bootstrap/utils.go b/vendor/github.com/libregraph/lico/bootstrap/utils.go
index 615b207020..8fe6abc66c 100644
--- a/vendor/github.com/libregraph/lico/bootstrap/utils.go
+++ b/vendor/github.com/libregraph/lico/bootstrap/utils.go
@@ -16,10 +16,8 @@ import (
"strings"
"github.com/go-jose/go-jose/v3"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/sirupsen/logrus"
-
- "github.com/libregraph/lico/signing"
)
func parseJSONWebKey(jsonBytes []byte) (*jose.JSONWebKey, error) {
@@ -297,7 +295,7 @@ func validateSigners(bs *bootstrap) error {
if !haveECDSA {
return fmt.Errorf("no private key for signing method: %s", bs.config.SigningMethod.Alg())
}
- case *signing.SigningMethodEdwardsCurve:
+ case *jwt.SigningMethodEd25519:
if !haveEd25519 {
return fmt.Errorf("no private key for signing method: %s", bs.config.SigningMethod.Alg())
}
diff --git a/vendor/github.com/libregraph/lico/claims.go b/vendor/github.com/libregraph/lico/claims.go
index a72955b57b..91a12d9f6e 100644
--- a/vendor/github.com/libregraph/lico/claims.go
+++ b/vendor/github.com/libregraph/lico/claims.go
@@ -20,7 +20,7 @@ package lico
import (
"errors"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/oidc"
"github.com/libregraph/lico/oidc/payload"
@@ -67,7 +67,7 @@ const (
// AccessTokenClaims define the claims found in access tokens issued.
type AccessTokenClaims struct {
- jwt.StandardClaims
+ jwt.RegisteredClaims
TokenType TokenTypeValue `json:"lg.t"`
@@ -81,20 +81,16 @@ type AccessTokenClaims struct {
*oidc.SessionClaims
}
-// Valid implements the jwt.Claims interface.
-func (c AccessTokenClaims) Valid() error {
- if err := c.StandardClaims.Valid(); err != nil {
- return err
+// Validate implements the jwt.ClaimsValidator interface.
+func (c AccessTokenClaims) Validate() error {
+ if !c.TokenType.Is(TokenTypeAccessToken) {
+ return errors.New("not an access token")
}
- if c.IdentityClaims != nil {
- if err := c.IdentityClaims.Valid(); err != nil {
- return err
- }
+ if len(c.Audience) != 1 {
+ return errors.New("access token must have exactly one audience value")
}
- if c.TokenType.Is(TokenTypeAccessToken) {
- return nil
- }
- return errors.New("not an access token")
+
+ return nil
}
// AuthorizedScopes returns a map with scope keys and true value of all scopes
@@ -110,7 +106,7 @@ func (c AccessTokenClaims) AuthorizedScopes() map[string]bool {
// RefreshTokenClaims define the claims used by refresh tokens.
type RefreshTokenClaims struct {
- jwt.StandardClaims
+ jwt.RegisteredClaims
TokenType TokenTypeValue `json:"lg.t"`
@@ -123,20 +119,17 @@ type RefreshTokenClaims struct {
IdentityProvider string `json:"lg.p,omitempty"`
}
-// Valid implements the jwt.Claims interface.
-func (c RefreshTokenClaims) Valid() error {
- if err := c.StandardClaims.Valid(); err != nil {
- return err
+// Validate implements the jwt.ClaimsValidator interface.
+func (c RefreshTokenClaims) Validate() error {
+ if !c.TokenType.Is(TokenTypeRefreshToken) {
+ return errors.New("not a refresh token")
}
- if c.IdentityClaims != nil {
- if err := c.IdentityClaims.Valid(); err != nil {
- return err
- }
+
+ if len(c.Audience) != 1 {
+ return errors.New("refresh token must have exactly one audience value")
}
- if c.TokenType.Is(TokenTypeRefreshToken) {
- return nil
- }
- return errors.New("not a refresh token")
+
+ return nil
}
// NumericIDClaims define the claims used with the konnect/id scope.
@@ -147,8 +140,8 @@ type NumericIDClaims struct {
NumericIDUsername string `json:"username,omitempty"`
}
-// Valid implements the jwt.Claims interface.
-func (c NumericIDClaims) Valid() error {
+// Validate implements the jwt.ClaimsValidator interface.
+func (c NumericIDClaims) Validate() error {
if c.NumericIDUsername == "" {
return errors.New("username claim not valid")
}
@@ -160,8 +153,8 @@ type UniqueUserIDClaims struct {
UniqueUserID string `json:"lg.uuid,omitempty"`
}
-// Valid implements the jwt.Claims interface.
-func (c UniqueUserIDClaims) Valid() error {
+// Validate implements the jwt.ClaimsValidator interface.
+func (c UniqueUserIDClaims) Validate() error {
if c.UniqueUserID == "" {
return errors.New("lg.uuid claim not valid")
}
diff --git a/vendor/github.com/libregraph/lico/context.go b/vendor/github.com/libregraph/lico/context.go
index e755c1c507..cba3db4719 100644
--- a/vendor/github.com/libregraph/lico/context.go
+++ b/vendor/github.com/libregraph/lico/context.go
@@ -21,7 +21,7 @@ import (
"context"
"net/http"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
)
// key is an unexported type for keys defined in this package.
diff --git a/vendor/github.com/libregraph/lico/identifier/api.go b/vendor/github.com/libregraph/lico/identifier/api.go
index ea553dedfe..74c158e036 100644
--- a/vendor/github.com/libregraph/lico/identifier/api.go
+++ b/vendor/github.com/libregraph/lico/identifier/api.go
@@ -47,10 +47,11 @@ func (i Identifier) writeHelloResponse(rw http.ResponseWriter, req *http.Request
response := &HelloResponse{
State: r.State,
Branding: &meta.Branding{
- BannerLogo: i.defaultBannerLogo,
- UsernameHintText: i.Config.DefaultUsernameHintText,
- SignInPageText: i.Config.DefaultSignInPageText,
- Locales: i.Config.UILocales,
+ BannerLogo: i.defaultBannerLogo,
+ UsernameHintText: i.Config.DefaultUsernameHintText,
+ SignInPageText: i.Config.DefaultSignInPageText,
+ SignInPageLogoURI: i.Config.DefaultSignInPageLogoURI,
+ Locales: i.Config.UILocales,
},
}
diff --git a/vendor/github.com/libregraph/lico/identifier/config.go b/vendor/github.com/libregraph/lico/identifier/config.go
index 715560f40e..2750f599b8 100644
--- a/vendor/github.com/libregraph/lico/identifier/config.go
+++ b/vendor/github.com/libregraph/lico/identifier/config.go
@@ -46,10 +46,11 @@ type Config struct {
AuthorizationEndpointURI *url.URL
SignedOutEndpointURI *url.URL
- DefaultBannerLogo []byte
- DefaultSignInPageText *string
- DefaultUsernameHintText *string
- UILocales []string
+ DefaultBannerLogo []byte
+ DefaultSignInPageText *string
+ DefaultSignInPageLogoURI *string
+ DefaultUsernameHintText *string
+ UILocales []string
Backend backends.Backend
}
diff --git a/vendor/github.com/libregraph/lico/identifier/meta/branding.go b/vendor/github.com/libregraph/lico/identifier/meta/branding.go
index af59894471..f6778da89e 100644
--- a/vendor/github.com/libregraph/lico/identifier/meta/branding.go
+++ b/vendor/github.com/libregraph/lico/identifier/meta/branding.go
@@ -19,8 +19,9 @@ package meta
// Branding is a container to hold identifier branding meta data.
type Branding struct {
- BannerLogo *string `json:"bannerLogo,omitempty"`
- SignInPageText *string `json:"signinPageText,omitempty"`
- UsernameHintText *string `json:"usernameHintText,omitempty"`
- Locales []string `json:"locales,omitempty"`
+ BannerLogo *string `json:"bannerLogo,omitempty"`
+ SignInPageText *string `json:"signinPageText,omitempty"`
+ UsernameHintText *string `json:"usernameHintText,omitempty"`
+ SignInPageLogoURI *string `json:"signinPageLogoURI,omitempty"`
+ Locales []string `json:"locales,omitempty"`
}
diff --git a/vendor/github.com/libregraph/lico/identifier/models.go b/vendor/github.com/libregraph/lico/identifier/models.go
index 0521545d1a..34d02abf90 100644
--- a/vendor/github.com/libregraph/lico/identifier/models.go
+++ b/vendor/github.com/libregraph/lico/identifier/models.go
@@ -23,7 +23,7 @@ import (
"strings"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/identifier/meta"
"github.com/libregraph/lico/identity/clients"
diff --git a/vendor/github.com/libregraph/lico/identifier/oauth2.go b/vendor/github.com/libregraph/lico/identifier/oauth2.go
index 84369a560d..1c9742a4e1 100644
--- a/vendor/github.com/libregraph/lico/identifier/oauth2.go
+++ b/vendor/github.com/libregraph/lico/identifier/oauth2.go
@@ -27,7 +27,7 @@ import (
"strings"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
"golang.org/x/oauth2"
diff --git a/vendor/github.com/libregraph/lico/identifier/package.json b/vendor/github.com/libregraph/lico/identifier/package.json
index 7400e18a65..4254aacfe5 100644
--- a/vendor/github.com/libregraph/lico/identifier/package.json
+++ b/vendor/github.com/libregraph/lico/identifier/package.json
@@ -65,7 +65,7 @@
"source-map-explorer": "^2.5.3",
"terser": "^5.30.4",
"typescript": "^5.2.2",
- "vite": "^4.5.2",
+ "vite": "^4.5.13",
"vite-plugin-checker": "^0.6.2",
"vite-plugin-eslint": "^1.8.1",
"vitest": "^0.34.6"
diff --git a/vendor/github.com/libregraph/lico/identifier/user.go b/vendor/github.com/libregraph/lico/identifier/user.go
index dcdc41615c..97db734c6e 100644
--- a/vendor/github.com/libregraph/lico/identifier/user.go
+++ b/vendor/github.com/libregraph/lico/identifier/user.go
@@ -22,7 +22,7 @@ import (
"errors"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
konnect "github.com/libregraph/lico"
"github.com/libregraph/lico/identifier/backends"
diff --git a/vendor/github.com/libregraph/lico/identity/auth.go b/vendor/github.com/libregraph/lico/identity/auth.go
index 2a5edeea3c..0cc4e7daaf 100644
--- a/vendor/github.com/libregraph/lico/identity/auth.go
+++ b/vendor/github.com/libregraph/lico/identity/auth.go
@@ -20,7 +20,7 @@ package identity
import (
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/oidc/payload"
)
diff --git a/vendor/github.com/libregraph/lico/identity/authorities/authorities.go b/vendor/github.com/libregraph/lico/identity/authorities/authorities.go
index 48492c7403..afe631e7d5 100644
--- a/vendor/github.com/libregraph/lico/identity/authorities/authorities.go
+++ b/vendor/github.com/libregraph/lico/identity/authorities/authorities.go
@@ -24,7 +24,7 @@ import (
"net/http"
"net/url"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
)
diff --git a/vendor/github.com/libregraph/lico/identity/authorities/oidc.go b/vendor/github.com/libregraph/lico/identity/authorities/oidc.go
index 2beab8740f..710f254fcb 100644
--- a/vendor/github.com/libregraph/lico/identity/authorities/oidc.go
+++ b/vendor/github.com/libregraph/lico/identity/authorities/oidc.go
@@ -28,7 +28,7 @@ import (
"sync"
"github.com/go-jose/go-jose/v3"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/sirupsen/logrus"
diff --git a/vendor/github.com/libregraph/lico/identity/authrecord.go b/vendor/github.com/libregraph/lico/identity/authrecord.go
index b58e1246ab..83391b09e9 100644
--- a/vendor/github.com/libregraph/lico/identity/authrecord.go
+++ b/vendor/github.com/libregraph/lico/identity/authrecord.go
@@ -20,7 +20,7 @@ package identity
import (
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/oidc/payload"
)
diff --git a/vendor/github.com/libregraph/lico/identity/clients/claims.go b/vendor/github.com/libregraph/lico/identity/clients/claims.go
index d62d0d8a94..8b9a7d5c1f 100644
--- a/vendor/github.com/libregraph/lico/identity/clients/claims.go
+++ b/vendor/github.com/libregraph/lico/identity/clients/claims.go
@@ -18,17 +18,12 @@
package clients
import (
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
)
// RegistrationClaims are claims used to with dynamic clients.
type RegistrationClaims struct {
- jwt.StandardClaims
+ jwt.RegisteredClaims
*ClientRegistration
}
-
-// Valid implements the jwt claims interface.
-func (crc RegistrationClaims) Valid() error {
- return crc.StandardClaims.Valid()
-}
diff --git a/vendor/github.com/libregraph/lico/identity/clients/models.go b/vendor/github.com/libregraph/lico/identity/clients/models.go
index 03e7ce3698..5a167e5a77 100644
--- a/vendor/github.com/libregraph/lico/identity/clients/models.go
+++ b/vendor/github.com/libregraph/lico/identity/clients/models.go
@@ -25,7 +25,7 @@ import (
"fmt"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/longsleep/rndm"
"github.com/mendsley/gojwk"
"golang.org/x/crypto/blake2b"
@@ -54,9 +54,9 @@ type ClientRegistration struct {
ImplicitScopes []string `yaml:"implicit_scopes" json:"-"`
- Dynamic bool `yaml:"-" json:"-"`
- IDIssuedAt int64 `yaml:"-" json:"-"`
- SecretExpiresAt int64 `yaml:"-" json:"-"`
+ Dynamic bool `yaml:"-" json:"-"`
+ IDIssuedAt time.Time `yaml:"-" json:"-"`
+ SecretExpiresAt time.Time `yaml:"-" json:"-"`
Contacts []string `yaml:"contacts,flow" json:"contacts,omitempty"`
Name string `yaml:"name" json:"name,omitempty"`
@@ -153,9 +153,9 @@ func (cr *ClientRegistration) SetDynamic(ctx context.Context, creator func(ctx c
}
// Initialize basic client registration data for dynamic client.
- cr.IDIssuedAt = time.Now().Unix()
+ cr.IDIssuedAt = time.Now()
if registry.dynamicClientSecretDuration > 0 {
- cr.SecretExpiresAt = time.Now().Add(registry.dynamicClientSecretDuration).Unix()
+ cr.SecretExpiresAt = time.Now().Add(registry.dynamicClientSecretDuration)
}
cr.Dynamic = true
@@ -168,10 +168,10 @@ func (cr *ClientRegistration) SetDynamic(ctx context.Context, creator func(ctx c
// client_id. See https://openid.net/specs/openid-connect-registration-1_0.html#StatelessRegistration
// for more information. We use a JWT as client_id.
claims := &RegistrationClaims{
- StandardClaims: jwt.StandardClaims{
+ RegisteredClaims: jwt.RegisteredClaims{
Subject: sub,
- IssuedAt: cr.IDIssuedAt,
- ExpiresAt: cr.SecretExpiresAt,
+ IssuedAt: jwt.NewNumericDate(cr.IDIssuedAt),
+ ExpiresAt: jwt.NewNumericDate(cr.SecretExpiresAt),
},
ClientRegistration: cr,
}
diff --git a/vendor/github.com/libregraph/lico/identity/clients/registry.go b/vendor/github.com/libregraph/lico/identity/clients/registry.go
index f6baa04acc..c30a08304a 100644
--- a/vendor/github.com/libregraph/lico/identity/clients/registry.go
+++ b/vendor/github.com/libregraph/lico/identity/clients/registry.go
@@ -27,7 +27,7 @@ import (
"sync"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
@@ -358,7 +358,7 @@ func (r *Registry) getDynamicClient(clientID string) (*ClientRegistration, bool)
// TODO(longsleep): Add secure client secret.
registration = claims.ClientRegistration
registration.ID = clientID
- registration.Secret = claims.StandardClaims.Subject
+ registration.Secret = claims.RegisteredClaims.Subject
registration.Dynamic = true
}
}
diff --git a/vendor/github.com/libregraph/lico/identity/managers/cookie.go b/vendor/github.com/libregraph/lico/identity/managers/cookie.go
index c3fc1ae255..f9771dab2f 100644
--- a/vendor/github.com/libregraph/lico/identity/managers/cookie.go
+++ b/vendor/github.com/libregraph/lico/identity/managers/cookie.go
@@ -27,7 +27,7 @@ import (
"strings"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/gorilla/mux"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
diff --git a/vendor/github.com/libregraph/lico/identity/managers/dummy.go b/vendor/github.com/libregraph/lico/identity/managers/dummy.go
index 1125d6949b..b7dbdbce78 100644
--- a/vendor/github.com/libregraph/lico/identity/managers/dummy.go
+++ b/vendor/github.com/libregraph/lico/identity/managers/dummy.go
@@ -23,7 +23,7 @@ import (
"net/http"
"strings"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/gorilla/mux"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
diff --git a/vendor/github.com/libregraph/lico/identity/managers/guest.go b/vendor/github.com/libregraph/lico/identity/managers/guest.go
index f61f342b83..1e7d34ec85 100644
--- a/vendor/github.com/libregraph/lico/identity/managers/guest.go
+++ b/vendor/github.com/libregraph/lico/identity/managers/guest.go
@@ -22,7 +22,7 @@ import (
"fmt"
"net/http"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/gorilla/mux"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
diff --git a/vendor/github.com/libregraph/lico/identity/managers/identifier.go b/vendor/github.com/libregraph/lico/identity/managers/identifier.go
index c832b38c63..156d274398 100644
--- a/vendor/github.com/libregraph/lico/identity/managers/identifier.go
+++ b/vendor/github.com/libregraph/lico/identity/managers/identifier.go
@@ -415,10 +415,14 @@ func (im *IdentifierIdentityManager) EndSession(ctx context.Context, rw http.Res
origin := utils.OriginFromRequestHeaders(req.Header)
+ clientID := ""
if esr.IDTokenHint != nil {
// Extended request, verify IDTokenHint and its claims if available.
esrClaims = esr.IDTokenHint.Claims.(*konnectoidc.IDTokenClaims)
- clientDetails, err = im.clients.Lookup(ctx, esrClaims.Audience, "", esr.PostLogoutRedirectURI, origin, true)
+ if len(esrClaims.Audience) == 1 {
+ clientID = esrClaims.Audience[0]
+ }
+ clientDetails, err = im.clients.Lookup(ctx, clientID, "", esr.PostLogoutRedirectURI, origin, true)
if err != nil {
// This error is not fatal since according to
// the spec in https://openid.net/specs/openid-connect-session-1_0.html#RPLogout the
@@ -471,7 +475,7 @@ func (im *IdentifierIdentityManager) EndSession(ctx context.Context, rw http.Res
query.Add("flow", identifier.FlowOIDC)
}
if esrClaims != nil {
- query.Add("client_id", esrClaims.Audience)
+ query.Add("client_id", clientID)
}
u.RawQuery = query.Encode()
diff --git a/vendor/github.com/libregraph/lico/identity/user.go b/vendor/github.com/libregraph/lico/identity/user.go
index a75c33c78f..64f9c586b1 100644
--- a/vendor/github.com/libregraph/lico/identity/user.go
+++ b/vendor/github.com/libregraph/lico/identity/user.go
@@ -18,7 +18,7 @@
package identity
import (
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
)
// User defines a most simple user with an id defined as subject.
diff --git a/vendor/github.com/libregraph/lico/identity/utils.go b/vendor/github.com/libregraph/lico/identity/utils.go
index 71ba296f5e..a4d61d5ba2 100644
--- a/vendor/github.com/libregraph/lico/identity/utils.go
+++ b/vendor/github.com/libregraph/lico/identity/utils.go
@@ -20,7 +20,7 @@ package identity
import (
"fmt"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
konnectoidc "github.com/libregraph/lico/oidc"
diff --git a/vendor/github.com/libregraph/lico/oidc/claims.go b/vendor/github.com/libregraph/lico/oidc/claims.go
index cf0980db74..1c921d32c1 100644
--- a/vendor/github.com/libregraph/lico/oidc/claims.go
+++ b/vendor/github.com/libregraph/lico/oidc/claims.go
@@ -18,12 +18,12 @@
package oidc
import (
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
)
// IDTokenClaims define the claims found in OIDC ID Tokens.
type IDTokenClaims struct {
- jwt.StandardClaims
+ jwt.RegisteredClaims
Nonce string `json:"nonce,omitempty"`
AuthTime int64 `json:"auth_time,omitempty"`
@@ -36,14 +36,10 @@ type IDTokenClaims struct {
*SessionClaims
}
-// Valid implements the jwt.Claims interface.
-func (c IDTokenClaims) Valid() (err error) {
- return c.StandardClaims.Valid()
-}
-
// ProfileClaims define the claims for the OIDC profile scope.
// https://openid.net/specs/openid-connect-basic-1_0.html#Scopes
type ProfileClaims struct {
+ jwt.RegisteredClaims
Name string `json:"name,omitempty"`
FamilyName string `json:"family_name,omitempty"`
GivenName string `json:"given_name,omitempty"`
@@ -60,14 +56,10 @@ func NewProfileClaims(claims jwt.Claims) *ProfileClaims {
return claims.(*ProfileClaims)
}
-// Valid implements the jwt.Claims interface.
-func (c ProfileClaims) Valid() error {
- return nil
-}
-
// EmailClaims define the claims for the OIDC email scope.
// https://openid.net/specs/openid-connect-basic-1_0.html#Scopes
type EmailClaims struct {
+ jwt.RegisteredClaims
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified"`
}
@@ -82,22 +74,12 @@ func NewEmailClaims(claims jwt.Claims) *EmailClaims {
return claims.(*EmailClaims)
}
-// Valid implements the jwt.Claims interface.
-func (c EmailClaims) Valid() error {
- return nil
-}
-
// UserInfoClaims define the claims defined by the OIDC UserInfo
// endpoint.
type UserInfoClaims struct {
Subject string `json:"sub,omitempty"`
}
-// Valid implements the jwt.Claims interface.
-func (c UserInfoClaims) Valid() error {
- return nil
-}
-
// SessionClaims define claims related to front end sessions, for example as
// specified by https://openid.net/specs/openid-connect-frontchannel-1_0.html
type SessionClaims struct {
diff --git a/vendor/github.com/libregraph/lico/oidc/payload/authentication.go b/vendor/github.com/libregraph/lico/oidc/payload/authentication.go
index 0aef0f94cf..3e22d07328 100644
--- a/vendor/github.com/libregraph/lico/oidc/payload/authentication.go
+++ b/vendor/github.com/libregraph/lico/oidc/payload/authentication.go
@@ -25,7 +25,7 @@ import (
"strings"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
konnectoidc "github.com/libregraph/lico/oidc"
@@ -337,9 +337,7 @@ func (ar *AuthenticationRequest) Validate(keyFunc jwt.Keyfunc) error {
}
if ar.RawIDTokenHint != "" {
- parser := &jwt.Parser{
- SkipClaimsValidation: true,
- }
+ parser := jwt.NewParser(jwt.WithoutClaimsValidation())
idTokenHint, err := parser.ParseWithClaims(ar.RawIDTokenHint, &konnectoidc.IDTokenClaims{}, func(token *jwt.Token) (interface{}, error) {
if keyFunc != nil {
return keyFunc(token)
diff --git a/vendor/github.com/libregraph/lico/oidc/payload/endsession.go b/vendor/github.com/libregraph/lico/oidc/payload/endsession.go
index 559f3b0f05..0f510f64e1 100644
--- a/vendor/github.com/libregraph/lico/oidc/payload/endsession.go
+++ b/vendor/github.com/libregraph/lico/oidc/payload/endsession.go
@@ -22,7 +22,7 @@ import (
"net/http"
"net/url"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
konnectoidc "github.com/libregraph/lico/oidc"
@@ -67,9 +67,7 @@ func NewEndSessionRequest(values url.Values, providerMetadata *oidc.WellKnown) (
// Validate validates the request data of the accociated endSession request.
func (esr *EndSessionRequest) Validate(keyFunc jwt.Keyfunc) error {
if esr.RawIDTokenHint != "" {
- parser := &jwt.Parser{
- SkipClaimsValidation: true,
- }
+ parser := jwt.NewParser(jwt.WithoutClaimsValidation())
idTokenHint, err := parser.ParseWithClaims(esr.RawIDTokenHint, &konnectoidc.IDTokenClaims{}, func(token *jwt.Token) (interface{}, error) {
if keyFunc != nil {
return keyFunc(token)
diff --git a/vendor/github.com/libregraph/lico/oidc/payload/registration.go b/vendor/github.com/libregraph/lico/oidc/payload/registration.go
index cddf99b512..bf30dea4b6 100644
--- a/vendor/github.com/libregraph/lico/oidc/payload/registration.go
+++ b/vendor/github.com/libregraph/lico/oidc/payload/registration.go
@@ -24,7 +24,7 @@ import (
"net/url"
"strings"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/mendsley/gojwk"
diff --git a/vendor/github.com/libregraph/lico/oidc/payload/request.go b/vendor/github.com/libregraph/lico/oidc/payload/request.go
index de4119967a..e497cdc22f 100644
--- a/vendor/github.com/libregraph/lico/oidc/payload/request.go
+++ b/vendor/github.com/libregraph/lico/oidc/payload/request.go
@@ -20,7 +20,7 @@ package payload
import (
"errors"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/identity/clients"
)
@@ -30,7 +30,7 @@ import (
// requests specified at
// https://openid.net/specs/openid-connect-core-1_0.html#JWTRequests
type RequestObjectClaims struct {
- jwt.StandardClaims
+ jwt.RegisteredClaims
RawScope string `json:"scope"`
Claims *ClaimsRequest `json:"claims"`
diff --git a/vendor/github.com/libregraph/lico/oidc/payload/token.go b/vendor/github.com/libregraph/lico/oidc/payload/token.go
index f20483e6b2..5422423054 100644
--- a/vendor/github.com/libregraph/lico/oidc/payload/token.go
+++ b/vendor/github.com/libregraph/lico/oidc/payload/token.go
@@ -24,7 +24,7 @@ import (
"net/url"
"strings"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
konnectoidc "github.com/libregraph/lico/oidc"
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/handlers.go b/vendor/github.com/libregraph/lico/oidc/provider/handlers.go
index 250f31cad4..b65a30f741 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/handlers.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/handlers.go
@@ -24,7 +24,7 @@ import (
"strings"
"github.com/go-jose/go-jose/v3"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
"github.com/sirupsen/logrus"
@@ -429,14 +429,14 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
claims := tr.RefreshToken.Claims.(*konnect.RefreshTokenClaims)
// Ensure that the authorization code was issued to the client id.
- if claims.Audience != tr.ClientID {
+ if claims.Audience[0] != tr.ClientID {
err = konnectoidc.NewOAuth2Error(oidc.ErrorCodeOAuth2InvalidGrant, "client_id mismatch")
goto done
}
// TODO(longsleep): Compare standard claims issuer.
- userID, sessionRef := p.getUserIDAndSessionRefFromClaims(&claims.StandardClaims, nil, claims.IdentityClaims)
+ userID, sessionRef := p.getUserIDAndSessionRefFromClaims(&claims.RegisteredClaims, nil, claims.IdentityClaims)
if userID == "" {
err = konnectoidc.NewOAuth2Error(oidc.ErrorCodeOAuth2InvalidToken, "missing data in kc.identity claim")
goto done
@@ -496,7 +496,7 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
// Create fake request for token generation.
ar = &payload.AuthenticationRequest{
- ClientID: claims.Audience,
+ ClientID: claims.Audience[0],
}
// Remember refresh token claims, for use in access and id token generators later on.
@@ -602,7 +602,7 @@ func (p *Provider) UserInfoHandler(rw http.ResponseWriter, req *http.Request) {
var requestedClaimsMap []*payload.ClaimsRequestMap
var authorizedScopes map[string]bool
- userID, sessionRef := p.getUserIDAndSessionRefFromClaims(&claims.StandardClaims, claims.SessionClaims, claims.IdentityClaims)
+ userID, sessionRef := p.getUserIDAndSessionRefFromClaims(&claims.RegisteredClaims, claims.SessionClaims, claims.IdentityClaims)
ctx := konnect.NewClaimsContext(konnect.NewRequestContext(req.Context(), req), claims)
@@ -628,7 +628,7 @@ func (p *Provider) UserInfoHandler(rw http.ResponseWriter, req *http.Request) {
found = false
}
if !found {
- p.logger.WithField("sub", claims.StandardClaims.Subject).Debugln("userinfo request user not found")
+ p.logger.WithField("sub", claims.RegisteredClaims.Subject).Debugln("userinfo request user not found")
p.ErrorPage(rw, http.StatusNotFound, "", "user not found")
return
}
@@ -721,7 +721,7 @@ done:
// Support returning signed user info if the registered client requested it
// as specified in https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse and
// https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
- registration, _ := p.clients.Get(ctx, claims.Audience)
+ registration, _ := p.clients.Get(ctx, claims.Audience[0])
if registration != nil {
if registration.RawUserInfoSignedResponseAlg != "" {
// Get alg.
@@ -934,8 +934,8 @@ done:
ClientID: cr.ID,
ClientSecret: cr.Secret,
- ClientIDIssuedAt: cr.IDIssuedAt,
- ClientSecretExpiresAt: cr.SecretExpiresAt,
+ ClientIDIssuedAt: cr.IDIssuedAt.Unix(),
+ ClientSecretExpiresAt: cr.SecretExpiresAt.Unix(),
ClientRegistrationRequest: *crr,
}
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/identity.go b/vendor/github.com/libregraph/lico/oidc/provider/identity.go
index 9648821e48..4e71a9aa1b 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/identity.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/identity.go
@@ -20,7 +20,7 @@ package provider
import (
"errors"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/lico/identity"
"github.com/libregraph/lico/oidc/payload"
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/provider.go b/vendor/github.com/libregraph/lico/oidc/provider/provider.go
index e0e0394853..4638022188 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/provider.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/provider.go
@@ -29,7 +29,7 @@ import (
"strings"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/rs/cors"
"github.com/sirupsen/logrus"
@@ -42,7 +42,6 @@ import (
"github.com/libregraph/lico/managers"
konnectoidc "github.com/libregraph/lico/oidc"
"github.com/libregraph/lico/oidc/code"
- "github.com/libregraph/lico/signing"
"github.com/libregraph/lico/utils"
)
@@ -208,7 +207,7 @@ func (p *Provider) SetSigningKey(id string, key crypto.Signer) error {
case *ecdsa.PrivateKey:
signingMethod = jwt.SigningMethodES256
case ed25519.PrivateKey:
- signingMethod = signing.SigningMethodEdDSA
+ signingMethod = jwt.SigningMethodEdDSA
default:
return fmt.Errorf("unsupported signer type: %v", s)
}
@@ -307,7 +306,7 @@ func (p *Provider) SetSigningKey(id string, key crypto.Signer) error {
PrivateKey: key,
SigningMethod: jwt.SigningMethodPS512,
}
- case *signing.SigningMethodEdwardsCurve:
+ case *jwt.SigningMethodEd25519:
p.signingKeys[signingMethod] = &SigningKey{
ID: id,
PrivateKey: key,
@@ -429,7 +428,7 @@ func (p *Provider) InitializeMetadata() error {
jwt.SigningMethodPS384.Alg(),
jwt.SigningMethodPS512.Alg(),
jwt.SigningMethodNone.Alg(),
- signing.SigningMethodEdDSA.Alg(),
+ jwt.SigningMethodEdDSA.Alg(),
}
p.metadata.TokenEndpointAuthMethodsSupported = []string{
oidc.AuthMethodClientSecretBasic,
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/session.go b/vendor/github.com/libregraph/lico/oidc/provider/session.go
index fd1655e5bf..2d89b7cbc9 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/session.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/session.go
@@ -23,7 +23,7 @@ import (
"encoding/gob"
"net/http"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/longsleep/rndm"
konnect "github.com/libregraph/lico"
@@ -112,11 +112,16 @@ func (p *Provider) unserializeSession(value string) (*payload.Session, error) {
return &session, nil
}
-func (p *Provider) getUserIDAndSessionRefFromClaims(claims *jwt.StandardClaims, sessionClaims *oidc.SessionClaims, identityClaims jwt.MapClaims) (string, *string) {
+func (p *Provider) getUserIDAndSessionRefFromClaims(claims *jwt.RegisteredClaims, sessionClaims *oidc.SessionClaims, identityClaims jwt.MapClaims) (string, *string) {
if claims == nil || identityClaims == nil {
return "", nil
}
+ if len(claims.Audience) != 1 {
+ return "", nil
+ }
+ audience := claims.Audience[0]
+
userIDClaim, _ := identityClaims[konnect.IdentifiedUserIDClaim].(string)
if userIDClaim == "" {
return userIDClaim, nil
@@ -136,5 +141,5 @@ func (p *Provider) getUserIDAndSessionRefFromClaims(claims *jwt.StandardClaims,
// NOTE(longsleep): Return the userID from claims and generate a session ref
// for it. Session refs use the userClaim if available and set by the
// underlaying backend.
- return userIDClaim, identity.GetSessionRef(p.identityManager.Name(), claims.Audience, userClaim)
+ return userIDClaim, identity.GetSessionRef(p.identityManager.Name(), audience, userClaim)
}
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/signing.go b/vendor/github.com/libregraph/lico/oidc/provider/signing.go
index 0e6b373221..04293d1b6f 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/signing.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/signing.go
@@ -20,7 +20,7 @@ package provider
import (
"crypto"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
)
// A SigningKey bundles a signer with meta data and a signign method.
diff --git a/vendor/github.com/libregraph/lico/oidc/provider/tokens.go b/vendor/github.com/libregraph/lico/oidc/provider/tokens.go
index ba5d6d5ea7..440e99d2a3 100644
--- a/vendor/github.com/libregraph/lico/oidc/provider/tokens.go
+++ b/vendor/github.com/libregraph/lico/oidc/provider/tokens.go
@@ -22,7 +22,7 @@ import (
"fmt"
"time"
- "github.com/golang-jwt/jwt/v4"
+ "github.com/golang-jwt/jwt/v5"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
@@ -51,13 +51,13 @@ func (p *Provider) makeAccessToken(ctx context.Context, audience string, auth id
TokenType: konnect.TokenTypeAccessToken,
AuthorizedScopesList: authorizedScopesList,
AuthorizedClaimsRequest: auth.AuthorizedClaims(),
- StandardClaims: jwt.StandardClaims{
+ RegisteredClaims: jwt.RegisteredClaims{
Issuer: p.issuerIdentifier,
Subject: auth.Subject(),
- Audience: audience,
- ExpiresAt: time.Now().Add(p.accessTokenDuration).Unix(),
- IssuedAt: time.Now().Unix(),
- Id: rndm.GenerateRandomString(24),
+ Audience: jwt.ClaimStrings{audience},
+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(p.accessTokenDuration)),
+ IssuedAt: jwt.NewNumericDate(time.Now()),
+ ID: rndm.GenerateRandomString(24),
},
}
@@ -137,12 +137,12 @@ func (p *Provider) makeIDToken(ctx context.Context, ar *payload.AuthenticationRe
idTokenClaims := &konnectoidc.IDTokenClaims{
Nonce: ar.Nonce,
- StandardClaims: jwt.StandardClaims{
+ RegisteredClaims: jwt.RegisteredClaims{
Issuer: p.issuerIdentifier,
Subject: publicSubject,
- Audience: ar.ClientID,
- ExpiresAt: time.Now().Add(p.idTokenDuration).Unix(),
- IssuedAt: time.Now().Unix(),
+ Audience: jwt.ClaimStrings{ar.ClientID},
+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(p.idTokenDuration)),
+ IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
@@ -327,13 +327,13 @@ func (p *Provider) makeRefreshToken(ctx context.Context, audience string, auth i
ApprovedScopesList: approvedScopesList,
ApprovedClaimsRequest: auth.AuthorizedClaims(),
Ref: ref,
- StandardClaims: jwt.StandardClaims{
+ RegisteredClaims: jwt.RegisteredClaims{
Issuer: p.issuerIdentifier,
Subject: auth.Subject(),
- Audience: audience,
- ExpiresAt: time.Now().Add(p.refreshTokenDuration).Unix(),
- IssuedAt: time.Now().Unix(),
- Id: rndm.GenerateRandomString(24),
+ Audience: jwt.ClaimStrings{audience},
+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(p.refreshTokenDuration)),
+ IssuedAt: jwt.NewNumericDate(time.Now()),
+ ID: rndm.GenerateRandomString(24),
},
}
diff --git a/vendor/github.com/libregraph/lico/signing/jwk.go b/vendor/github.com/libregraph/lico/signing/jwk.go
deleted file mode 100644
index 7ce95b97ea..0000000000
--- a/vendor/github.com/libregraph/lico/signing/jwk.go
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2017-2019 Kopano and its licensors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package signing
-
-import (
- "crypto"
- "encoding/base64"
-
- jwk "github.com/mendsley/gojwk"
- "golang.org/x/crypto/ed25519"
-)
-
-// JWKFromPublicKey creates a JWK from a public key
-func JWKFromPublicKey(key crypto.PublicKey) (*jwk.Key, error) {
- switch key := key.(type) {
- case ed25519.PublicKey:
- jwt := &jwk.Key{
- Kty: "OKP",
- Crv: "Ed25519",
- X: base64.RawURLEncoding.EncodeToString(key),
- }
-
- return jwt, nil
-
- default:
- return jwk.PublicKey(key)
- }
-
-}
diff --git a/vendor/github.com/libregraph/lico/signing/jwt.go b/vendor/github.com/libregraph/lico/signing/jwt.go
deleted file mode 100644
index 3e1fdd791c..0000000000
--- a/vendor/github.com/libregraph/lico/signing/jwt.go
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2017-2019 Kopano and its licensors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package signing
-
-import (
- "crypto"
- "crypto/rand"
- "errors"
-
- "github.com/golang-jwt/jwt/v4"
- "golang.org/x/crypto/ed25519"
-)
-
-// Errors used by this package.
-var (
- ErrEdDSAVerification = errors.New("eddsa: verification error")
-)
-
-// SigningMethodEdwardsCurve implements the EdDSA family of signing methods.
-type SigningMethodEdwardsCurve struct {
- Name string
-}
-
-// Specific instances for EdDSA
-var (
- SigningMethodEdDSA *SigningMethodEdwardsCurve
-)
-
-func init() {
- // EdDSA with Ed25519 https://tools.ietf.org/html/rfc8037#section-3.1.
- SigningMethodEdDSA = &SigningMethodEdwardsCurve{"EdDSA"}
- jwt.RegisterSigningMethod(SigningMethodEdDSA.Alg(), func() jwt.SigningMethod {
- return SigningMethodEdDSA
- })
-}
-
-// Alg implements the jwt.SigningMethod interface.
-func (m *SigningMethodEdwardsCurve) Alg() string {
- return m.Name
-}
-
-// Verify implements the jwt.SigningMethod interface.
-func (m *SigningMethodEdwardsCurve) Verify(signingString, signature string, key interface{}) error {
- var err error
-
- // Decode the signature
- var sig []byte
- if sig, err = jwt.DecodeSegment(signature); err != nil {
- return err
- }
-
- // Get the key
- switch k := key.(type) {
- case ed25519.PublicKey:
- if len(k) != ed25519.PublicKeySize {
- return jwt.ErrInvalidKey
- }
- if verifystatus := ed25519.Verify(k, []byte(signingString), sig); verifystatus == true {
- return nil
- } else {
- return ErrEdDSAVerification
- }
-
- default:
- return jwt.ErrInvalidKeyType
- }
-}
-
-// Sign implements the jwt.SigningMethod interface.
-func (m *SigningMethodEdwardsCurve) Sign(signingString string, key interface{}) (string, error) {
- switch k := key.(type) {
- case ed25519.PrivateKey:
- if len(k) != ed25519.PrivateKeySize {
- return "", jwt.ErrInvalidKey
- }
- if s, err := k.Sign(rand.Reader, []byte(signingString), crypto.Hash(0)); err == nil {
- // We serialize the signature.
- return jwt.EncodeSegment(s), nil
- } else {
- return "", err
- }
-
- default:
- return "", jwt.ErrInvalidKeyType
- }
-}
diff --git a/vendor/github.com/russellhaering/goxmldsig/.travis.yml b/vendor/github.com/russellhaering/goxmldsig/.travis.yml
deleted file mode 100644
index 8ad33f7db4..0000000000
--- a/vendor/github.com/russellhaering/goxmldsig/.travis.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-arch:
- - amd64
- - ppc64le
-
-language: go
-
-go:
- - "1.14.x"
- - "1.15.x"
- - "1.17.x"
- - master
diff --git a/vendor/github.com/russellhaering/goxmldsig/SECURITY.md b/vendor/github.com/russellhaering/goxmldsig/SECURITY.md
new file mode 100644
index 0000000000..f1442253da
--- /dev/null
+++ b/vendor/github.com/russellhaering/goxmldsig/SECURITY.md
@@ -0,0 +1,5 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+Security vulnerabilities can be reported using GitHub's [private vulnerability reporting tool](https://github.com/russellhaering/goxmldsig/security/advisories/new).
diff --git a/vendor/github.com/russellhaering/goxmldsig/validate.go b/vendor/github.com/russellhaering/goxmldsig/validate.go
index 3d0fc97393..e64891ccc3 100644
--- a/vendor/github.com/russellhaering/goxmldsig/validate.go
+++ b/vendor/github.com/russellhaering/goxmldsig/validate.go
@@ -4,6 +4,7 @@ import (
"bytes"
"crypto/x509"
"encoding/base64"
+ "encoding/xml"
"errors"
"fmt"
"regexp"
@@ -169,6 +170,7 @@ func (ctx *ValidationContext) transform(
return el, canonicalizer, nil
}
+// deprecated
func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string, canonicalizer Canonicalizer) ([]byte, error) {
data, err := canonicalizer.Canonicalize(el)
if err != nil {
@@ -189,6 +191,33 @@ func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string
return hash.Sum(nil), nil
}
+func (ctx *ValidationContext) getCanonicalSignedInfo(sig *types.Signature) ([]byte, error) {
+ signatureElement := sig.UnderlyingElement()
+
+ nsCtx, err := etreeutils.NSBuildParentContext(signatureElement)
+ if err != nil {
+ return nil, err
+ }
+
+ signedInfo, err := etreeutils.NSFindOneChildCtx(nsCtx, signatureElement, Namespace, SignedInfoTag)
+ if err != nil {
+ return nil, err
+ }
+
+ if signedInfo == nil {
+ return nil, errors.New("Missing SignedInfo")
+ }
+
+ // Canonicalize the xml
+ canonical, err := canonicalSerialize(signedInfo)
+ if err != nil {
+ return nil, err
+ }
+
+ return canonical, nil
+}
+
+// deprecated
func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, decodedSignature []byte) error {
signatureElement := sig.UnderlyingElement()
@@ -226,44 +255,24 @@ func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicaliz
}
func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Signature, cert *x509.Certificate) (*etree.Element, error) {
- idAttrEl := el.SelectAttr(ctx.IdAttribute)
- idAttr := ""
- if idAttrEl != nil {
- idAttr = idAttrEl.Value
- }
- var ref *types.Reference
+ // Actually verify the 'SignedInfo' was signed by a trusted source
+ signatureMethod := sig.SignedInfo.SignatureMethod.Algorithm
- // Find the first reference which references the top-level element
- for _, _ref := range sig.SignedInfo.References {
- if _ref.URI == "" || _ref.URI[1:] == idAttr {
- ref = &_ref
- }
- }
-
- // Perform all transformations listed in the 'SignedInfo'
- // Basically, this means removing the 'SignedInfo'
- transformed, canonicalizer, err := ctx.transform(el, sig, ref)
+ canonicalSignedInfoBytes, err := ctx.getCanonicalSignedInfo(sig)
if err != nil {
- return nil, err
+ return nil, errors.New("Could not obtain canonical signed info bytes")
}
- digestAlgorithm := ref.DigestAlgo.Algorithm
-
- // Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
- digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer)
- if err != nil {
- return nil, err
+ if canonicalSignedInfoBytes == nil {
+ return nil, errors.New("Missing SignedInfo")
}
- decodedDigestValue, err := base64.StdEncoding.DecodeString(ref.DigestValue)
- if err != nil {
- return nil, err
+ algo, ok := x509SignatureAlgorithmByIdentifier[signatureMethod]
+ if !ok {
+ return nil, errors.New("Unknown signature method: " + signatureMethod)
}
- if !bytes.Equal(digest, decodedDigestValue) {
- return nil, errors.New("Signature could not be verified")
- }
if sig.SignatureValue == nil {
return nil, errors.New("Signature could not be verified")
}
@@ -274,14 +283,92 @@ func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Si
return nil, errors.New("Could not decode signature")
}
- // Actually verify the 'SignedInfo' was signed by a trusted source
- signatureMethod := sig.SignedInfo.SignatureMethod.Algorithm
- err = ctx.verifySignedInfo(sig, canonicalizer, signatureMethod, cert, decodedSignature)
+ err = cert.CheckSignature(algo, canonicalSignedInfoBytes, decodedSignature)
if err != nil {
return nil, err
}
- return transformed, nil
+ // only use the verified canonicalSignedInfoBytes
+ // unmarshal canonicalSignedInfoBytes into a new SignedInfo type
+ // to obtain the reference
+ signedInfo := &types.SignedInfo{}
+ err = xml.Unmarshal(canonicalSignedInfoBytes, signedInfo)
+ if err != nil {
+ return nil, err
+ }
+
+ idAttrEl := el.SelectAttr(ctx.IdAttribute)
+ idAttr := ""
+ if idAttrEl != nil {
+ idAttr = idAttrEl.Value
+ }
+
+ var ref *types.Reference
+
+ // Find the first reference which references the top-level element
+ for _, _ref := range signedInfo.References {
+ if _ref.URI == "" || _ref.URI[1:] == idAttr {
+ ref = &_ref
+ }
+ }
+
+ // prevents null pointer deref
+ if ref == nil {
+ return nil, errors.New("Missing reference")
+ }
+
+ digestAlgorithmId := ref.DigestAlgo.Algorithm
+ signedDigestValue, err := base64.StdEncoding.DecodeString(ref.DigestValue)
+ if err != nil {
+ return nil, err
+ }
+
+ // Perform all transformations listed in the 'SignedInfo'
+ // Basically, this means removing the 'SignedInfo'
+ transformed, canonicalizer, err := ctx.transform(el, sig, ref)
+ if err != nil {
+ return nil, err
+ }
+
+ referencedBytes, err := canonicalizer.Canonicalize(transformed)
+ if err != nil {
+ return nil, err
+ }
+
+ // use a known digest hashing algorithm
+ hashAlgorithm, ok := digestAlgorithmsByIdentifier[digestAlgorithmId]
+ if !ok {
+ return nil, errors.New("Unknown digest algorithm: " + digestAlgorithmId)
+ }
+
+ hash := hashAlgorithm.New()
+ _, err = hash.Write(referencedBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ computedDigest := hash.Sum(nil)
+ /* Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
+ digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer)
+ */
+
+ if !bytes.Equal(computedDigest, signedDigestValue) {
+ return nil, errors.New("Signature could not be verified")
+ }
+
+ if !(len(computedDigest) >= 20) {
+ return nil, errors.New("Computed digest is less than 20 something went wrong")
+ }
+
+ // now only the referencedBytes is verified,
+ // unmarshal into new etree
+ doc := etree.NewDocument()
+ err = doc.ReadFromBytes(referencedBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ return doc.Root(), nil
}
func contains(roots []*x509.Certificate, cert *x509.Certificate) bool {
@@ -425,7 +512,7 @@ func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Cer
return nil, err
}
- var cert *x509.Certificate
+ var untrustedCert *x509.Certificate
if sig.KeyInfo != nil {
// If the Signature includes KeyInfo, extract the certificate from there
@@ -439,29 +526,40 @@ func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Cer
return nil, errors.New("Failed to parse certificate")
}
- cert, err = x509.ParseCertificate(certData)
+ untrustedCert, err = x509.ParseCertificate(certData)
if err != nil {
return nil, err
}
} else {
// If the Signature doesn't have KeyInfo, Use the root certificate if there is only one
if len(roots) == 1 {
- cert = roots[0]
+ untrustedCert = roots[0]
} else {
return nil, errors.New("Missing x509 Element")
}
}
- // Verify that the certificate is one we trust
- if !contains(roots, cert) {
- return nil, errors.New("Could not verify certificate against trusted certs")
+ rootIdx := -1
+ for i, root := range roots {
+ if root.Equal(untrustedCert) {
+ rootIdx = i
+ }
}
- if now.Before(cert.NotBefore) || now.After(cert.NotAfter) {
+ if rootIdx == -1 {
+ return nil, errors.New("Could not verify certificate against trusted certs")
+ }
+ var trustedCert *x509.Certificate
+
+ trustedCert = roots[rootIdx]
+
+ // Verify that the certificate is one we trust
+
+ if now.Before(trustedCert.NotBefore) || now.After(trustedCert.NotAfter) {
return nil, errors.New("Cert is not valid at this time")
}
- return cert, nil
+ return trustedCert, nil
}
// Validate verifies that the passed element contains a valid enveloped signature
@@ -475,6 +573,7 @@ func (ctx *ValidationContext) Validate(el *etree.Element) (*etree.Element, error
return nil, err
}
+ // function to get the trusted certificate
cert, err := ctx.verifyCertificate(sig)
if err != nil {
return nil, err
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c0dcc855ab..787d809104 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -433,7 +433,7 @@ github.com/ggwhite/go-masker
## explicit; go 1.15
github.com/go-acme/lego/v4/acme
github.com/go-acme/lego/v4/challenge
-# github.com/go-asn1-ber/asn1-ber v1.5.7
+# github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667
## explicit; go 1.13
github.com/go-asn1-ber/asn1-ber
# github.com/go-chi/chi/v5 v5.2.1
@@ -523,8 +523,8 @@ github.com/go-jose/go-jose/v4/json
## explicit; go 1.17
github.com/go-kit/log
github.com/go-kit/log/level
-# github.com/go-ldap/ldap/v3 v3.4.10
-## explicit; go 1.14
+# github.com/go-ldap/ldap/v3 v3.4.11
+## explicit; go 1.23.0
github.com/go-ldap/ldap/v3
# github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
## explicit; go 1.14
@@ -814,8 +814,8 @@ github.com/jinzhu/now
# github.com/jmespath/go-jmespath v0.4.0
## explicit; go 1.14
github.com/jmespath/go-jmespath
-# github.com/jonboulle/clockwork v0.2.2
-## explicit; go 1.13
+# github.com/jonboulle/clockwork v0.5.0
+## explicit; go 1.21
github.com/jonboulle/clockwork
# github.com/json-iterator/go v1.1.12
## explicit; go 1.12
@@ -870,8 +870,8 @@ github.com/libregraph/idm/server
github.com/libregraph/idm/server/handler
github.com/libregraph/idm/server/handler/boltdb
github.com/libregraph/idm/server/handler/ldif
-# github.com/libregraph/lico v0.65.1
-## explicit; go 1.18
+# github.com/libregraph/lico v0.65.2-0.20250428103211-356e98f98457
+## explicit; go 1.23.0
github.com/libregraph/lico
github.com/libregraph/lico/bootstrap
github.com/libregraph/lico/bootstrap/backends/guest
@@ -897,7 +897,6 @@ github.com/libregraph/lico/oidc/code/managers
github.com/libregraph/lico/oidc/payload
github.com/libregraph/lico/oidc/provider
github.com/libregraph/lico/server
-github.com/libregraph/lico/signing
github.com/libregraph/lico/utils
github.com/libregraph/lico/version
# github.com/libregraph/oidc-go v1.1.0
@@ -1703,8 +1702,8 @@ github.com/rs/zerolog/internal/cbor
github.com/rs/zerolog/internal/json
github.com/rs/zerolog/log
github.com/rs/zerolog/pkgerrors
-# github.com/russellhaering/goxmldsig v1.4.0
-## explicit; go 1.15
+# github.com/russellhaering/goxmldsig v1.5.0
+## explicit; go 1.21.0
github.com/russellhaering/goxmldsig
github.com/russellhaering/goxmldsig/etreeutils
github.com/russellhaering/goxmldsig/types