Update module lib/pq to v1.6.0 (#572)
Update module lib/pq to v1.6.0 Reviewed-on: https://kolaente.dev/vikunja/api/pulls/572
This commit is contained in:
61
vendor/github.com/jcmturner/gokrb5/v8/service/APExchange.go
generated
vendored
Normal file
61
vendor/github.com/jcmturner/gokrb5/v8/service/APExchange.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jcmturner/gokrb5/v8/credentials"
|
||||
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
|
||||
"github.com/jcmturner/gokrb5/v8/messages"
|
||||
)
|
||||
|
||||
// VerifyAPREQ verifies an AP_REQ sent to the service. Returns a boolean for if the AP_REQ is valid and the client's principal name and realm.
|
||||
func VerifyAPREQ(APReq *messages.APReq, s *Settings) (bool, *credentials.Credentials, error) {
|
||||
var creds *credentials.Credentials
|
||||
ok, err := APReq.Verify(s.Keytab, s.MaxClockSkew(), s.ClientAddress(), s.KeytabPrincipal())
|
||||
if err != nil || !ok {
|
||||
return false, creds, err
|
||||
}
|
||||
|
||||
if s.RequireHostAddr() && len(APReq.Ticket.DecryptedEncPart.CAddr) < 1 {
|
||||
return false, creds,
|
||||
messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "ticket does not contain HostAddress values required")
|
||||
}
|
||||
|
||||
// Check for replay
|
||||
rc := GetReplayCache(s.MaxClockSkew())
|
||||
if rc.IsReplay(APReq.Ticket.SName, APReq.Authenticator) {
|
||||
return false, creds,
|
||||
messages.NewKRBError(APReq.Ticket.SName, APReq.Ticket.Realm, errorcode.KRB_AP_ERR_REPEAT, "replay detected")
|
||||
}
|
||||
|
||||
c := credentials.NewFromPrincipalName(APReq.Authenticator.CName, APReq.Authenticator.CRealm)
|
||||
creds = c
|
||||
creds.SetAuthTime(time.Now().UTC())
|
||||
creds.SetAuthenticated(true)
|
||||
creds.SetValidUntil(APReq.Ticket.DecryptedEncPart.EndTime)
|
||||
|
||||
//PAC decoding
|
||||
if !s.disablePACDecoding {
|
||||
isPAC, pac, err := APReq.Ticket.GetPACType(s.Keytab, s.KeytabPrincipal(), s.Logger())
|
||||
if isPAC && err != nil {
|
||||
return false, creds, err
|
||||
}
|
||||
if isPAC {
|
||||
// There is a valid PAC. Adding attributes to creds
|
||||
creds.SetADCredentials(credentials.ADCredentials{
|
||||
GroupMembershipSIDs: pac.KerbValidationInfo.GetGroupMembershipSIDs(),
|
||||
LogOnTime: pac.KerbValidationInfo.LogOnTime.Time(),
|
||||
LogOffTime: pac.KerbValidationInfo.LogOffTime.Time(),
|
||||
PasswordLastSet: pac.KerbValidationInfo.PasswordLastSet.Time(),
|
||||
EffectiveName: pac.KerbValidationInfo.EffectiveName.Value,
|
||||
FullName: pac.KerbValidationInfo.FullName.Value,
|
||||
UserID: int(pac.KerbValidationInfo.UserID),
|
||||
PrimaryGroupID: int(pac.KerbValidationInfo.PrimaryGroupID),
|
||||
LogonServer: pac.KerbValidationInfo.LogonServer.Value,
|
||||
LogonDomainName: pac.KerbValidationInfo.LogonDomainName.Value,
|
||||
LogonDomainID: pac.KerbValidationInfo.LogonDomainID.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return true, creds, nil
|
||||
}
|
118
vendor/github.com/jcmturner/gokrb5/v8/service/authenticator.go
generated
vendored
Normal file
118
vendor/github.com/jcmturner/gokrb5/v8/service/authenticator.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
goidentity "github.com/jcmturner/goidentity/v6"
|
||||
"github.com/jcmturner/gokrb5/v8/client"
|
||||
"github.com/jcmturner/gokrb5/v8/config"
|
||||
"github.com/jcmturner/gokrb5/v8/credentials"
|
||||
)
|
||||
|
||||
// NewKRB5BasicAuthenticator creates a new NewKRB5BasicAuthenticator
|
||||
func NewKRB5BasicAuthenticator(headerVal string, krb5conf *config.Config, serviceSettings *Settings, clientSettings *client.Settings) KRB5BasicAuthenticator {
|
||||
return KRB5BasicAuthenticator{
|
||||
BasicHeaderValue: headerVal,
|
||||
clientConfig: krb5conf,
|
||||
serviceSettings: serviceSettings,
|
||||
clientSettings: clientSettings,
|
||||
}
|
||||
}
|
||||
|
||||
// KRB5BasicAuthenticator implements gokrb5.com/jcmturner/goidentity.Authenticator interface.
|
||||
// It takes username and password so can be used for basic authentication.
|
||||
type KRB5BasicAuthenticator struct {
|
||||
BasicHeaderValue string
|
||||
serviceSettings *Settings
|
||||
clientSettings *client.Settings
|
||||
clientConfig *config.Config
|
||||
realm string
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
// Authenticate and return the identity. The boolean indicates if the authentication was successful.
|
||||
func (a KRB5BasicAuthenticator) Authenticate() (i goidentity.Identity, ok bool, err error) {
|
||||
a.realm, a.username, a.password, err = parseBasicHeaderValue(a.BasicHeaderValue)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not parse basic authentication header: %v", err)
|
||||
return
|
||||
}
|
||||
cl := client.NewWithPassword(a.username, a.realm, a.password, a.clientConfig)
|
||||
err = cl.Login()
|
||||
if err != nil {
|
||||
// Username and/or password could be wrong
|
||||
err = fmt.Errorf("error with user credentials during login: %v", err)
|
||||
return
|
||||
}
|
||||
tkt, _, err := cl.GetServiceTicket(a.serviceSettings.SName())
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not get service ticket: %v", err)
|
||||
return
|
||||
}
|
||||
err = tkt.DecryptEncPart(a.serviceSettings.Keytab, a.serviceSettings.KeytabPrincipal())
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not decrypt service ticket: %v", err)
|
||||
return
|
||||
}
|
||||
cl.Credentials.SetAuthTime(time.Now().UTC())
|
||||
cl.Credentials.SetAuthenticated(true)
|
||||
isPAC, pac, err := tkt.GetPACType(a.serviceSettings.Keytab, a.serviceSettings.KeytabPrincipal(), a.serviceSettings.Logger())
|
||||
if isPAC && err != nil {
|
||||
err = fmt.Errorf("error processing PAC: %v", err)
|
||||
return
|
||||
}
|
||||
if isPAC {
|
||||
// There is a valid PAC. Adding attributes to creds
|
||||
cl.Credentials.SetADCredentials(credentials.ADCredentials{
|
||||
GroupMembershipSIDs: pac.KerbValidationInfo.GetGroupMembershipSIDs(),
|
||||
LogOnTime: pac.KerbValidationInfo.LogOnTime.Time(),
|
||||
LogOffTime: pac.KerbValidationInfo.LogOffTime.Time(),
|
||||
PasswordLastSet: pac.KerbValidationInfo.PasswordLastSet.Time(),
|
||||
EffectiveName: pac.KerbValidationInfo.EffectiveName.Value,
|
||||
FullName: pac.KerbValidationInfo.FullName.Value,
|
||||
UserID: int(pac.KerbValidationInfo.UserID),
|
||||
PrimaryGroupID: int(pac.KerbValidationInfo.PrimaryGroupID),
|
||||
LogonServer: pac.KerbValidationInfo.LogonServer.Value,
|
||||
LogonDomainName: pac.KerbValidationInfo.LogonDomainName.Value,
|
||||
LogonDomainID: pac.KerbValidationInfo.LogonDomainID.String(),
|
||||
})
|
||||
}
|
||||
ok = true
|
||||
i = cl.Credentials
|
||||
return
|
||||
}
|
||||
|
||||
// Mechanism returns the authentication mechanism.
|
||||
func (a KRB5BasicAuthenticator) Mechanism() string {
|
||||
return "Kerberos Basic"
|
||||
}
|
||||
|
||||
func parseBasicHeaderValue(s string) (domain, username, password string, err error) {
|
||||
b, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
v := string(b)
|
||||
vc := strings.SplitN(v, ":", 2)
|
||||
password = vc[1]
|
||||
// Domain and username can be specified in 2 formats:
|
||||
// <Username> - no domain specified
|
||||
// <Domain>\<Username>
|
||||
// <Username>@<Domain>
|
||||
if strings.Contains(vc[0], `\`) {
|
||||
u := strings.SplitN(vc[0], `\`, 2)
|
||||
domain = u[0]
|
||||
username = u[1]
|
||||
} else if strings.Contains(vc[0], `@`) {
|
||||
u := strings.SplitN(vc[0], `@`, 2)
|
||||
domain = u[1]
|
||||
username = u[0]
|
||||
} else {
|
||||
username = vc[0]
|
||||
}
|
||||
return
|
||||
}
|
128
vendor/github.com/jcmturner/gokrb5/v8/service/cache.go
generated
vendored
Normal file
128
vendor/github.com/jcmturner/gokrb5/v8/service/cache.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
// Package service provides server side integrations for Kerberos authentication.
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/jcmturner/gokrb5/v8/types"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Replay cache is required as specified in RFC 4120 section 3.2.3
|
||||
|
||||
// Cache for tickets received from clients keyed by fully qualified client name. Used to track replay of tickets.
|
||||
type Cache struct {
|
||||
entries map[string]clientEntries
|
||||
mux sync.RWMutex
|
||||
}
|
||||
|
||||
// clientEntries holds entries of client details sent to the service.
|
||||
type clientEntries struct {
|
||||
replayMap map[time.Time]replayCacheEntry
|
||||
seqNumber int64
|
||||
subKey types.EncryptionKey
|
||||
}
|
||||
|
||||
// Cache entry tracking client time values of tickets sent to the service.
|
||||
type replayCacheEntry struct {
|
||||
presentedTime time.Time
|
||||
sName types.PrincipalName
|
||||
cTime time.Time // This combines the ticket's CTime and Cusec
|
||||
}
|
||||
|
||||
func (c *Cache) getClientEntries(cname types.PrincipalName) (clientEntries, bool) {
|
||||
c.mux.RLock()
|
||||
defer c.mux.RUnlock()
|
||||
ce, ok := c.entries[cname.PrincipalNameString()]
|
||||
return ce, ok
|
||||
}
|
||||
|
||||
func (c *Cache) getClientEntry(cname types.PrincipalName, t time.Time) (replayCacheEntry, bool) {
|
||||
if ce, ok := c.getClientEntries(cname); ok {
|
||||
c.mux.RLock()
|
||||
defer c.mux.RUnlock()
|
||||
if e, ok := ce.replayMap[t]; ok {
|
||||
return e, true
|
||||
}
|
||||
}
|
||||
return replayCacheEntry{}, false
|
||||
}
|
||||
|
||||
// Instance of the ServiceCache. This needs to be a singleton.
|
||||
var replayCache Cache
|
||||
var once sync.Once
|
||||
|
||||
// GetReplayCache returns a pointer to the Cache singleton.
|
||||
func GetReplayCache(d time.Duration) *Cache {
|
||||
// Create a singleton of the ReplayCache and start a background thread to regularly clean out old entries
|
||||
once.Do(func() {
|
||||
replayCache = Cache{
|
||||
entries: make(map[string]clientEntries),
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
// TODO consider using a context here.
|
||||
time.Sleep(d)
|
||||
replayCache.ClearOldEntries(d)
|
||||
}
|
||||
}()
|
||||
})
|
||||
return &replayCache
|
||||
}
|
||||
|
||||
// AddEntry adds an entry to the Cache.
|
||||
func (c *Cache) AddEntry(sname types.PrincipalName, a types.Authenticator) {
|
||||
ct := a.CTime.Add(time.Duration(a.Cusec) * time.Microsecond)
|
||||
if ce, ok := c.getClientEntries(a.CName); ok {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
ce.replayMap[ct] = replayCacheEntry{
|
||||
presentedTime: time.Now().UTC(),
|
||||
sName: sname,
|
||||
cTime: ct,
|
||||
}
|
||||
ce.seqNumber = a.SeqNumber
|
||||
ce.subKey = a.SubKey
|
||||
} else {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
c.entries[a.CName.PrincipalNameString()] = clientEntries{
|
||||
replayMap: map[time.Time]replayCacheEntry{
|
||||
ct: {
|
||||
presentedTime: time.Now().UTC(),
|
||||
sName: sname,
|
||||
cTime: ct,
|
||||
},
|
||||
},
|
||||
seqNumber: a.SeqNumber,
|
||||
subKey: a.SubKey,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearOldEntries clears entries from the Cache that are older than the duration provided.
|
||||
func (c *Cache) ClearOldEntries(d time.Duration) {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
for ke, ce := range c.entries {
|
||||
for k, e := range ce.replayMap {
|
||||
if time.Now().UTC().Sub(e.presentedTime) > d {
|
||||
delete(ce.replayMap, k)
|
||||
}
|
||||
}
|
||||
if len(ce.replayMap) == 0 {
|
||||
delete(c.entries, ke)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsReplay tests if the Authenticator provided is a replay within the duration defined. If this is not a replay add the entry to the cache for tracking.
|
||||
func (c *Cache) IsReplay(sname types.PrincipalName, a types.Authenticator) bool {
|
||||
ct := a.CTime.Add(time.Duration(a.Cusec) * time.Microsecond)
|
||||
if e, ok := c.getClientEntry(a.CName, ct); ok {
|
||||
if e.sName.Equal(sname) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
c.AddEntry(sname, a)
|
||||
return false
|
||||
}
|
163
vendor/github.com/jcmturner/gokrb5/v8/service/settings.go
generated
vendored
Normal file
163
vendor/github.com/jcmturner/gokrb5/v8/service/settings.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jcmturner/gokrb5/v8/keytab"
|
||||
"github.com/jcmturner/gokrb5/v8/types"
|
||||
)
|
||||
|
||||
// Settings defines service side configuration settings.
|
||||
type Settings struct {
|
||||
Keytab *keytab.Keytab
|
||||
ktprinc *types.PrincipalName
|
||||
sname string
|
||||
requireHostAddr bool
|
||||
disablePACDecoding bool
|
||||
cAddr types.HostAddress
|
||||
maxClockSkew time.Duration
|
||||
logger *log.Logger
|
||||
sessionMgr SessionMgr
|
||||
}
|
||||
|
||||
// NewSettings creates a new service Settings.
|
||||
func NewSettings(kt *keytab.Keytab, settings ...func(*Settings)) *Settings {
|
||||
s := new(Settings)
|
||||
s.Keytab = kt
|
||||
for _, set := range settings {
|
||||
set(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// RequireHostAddr used to configure service side to required host addresses to be specified in Kerberos tickets.
|
||||
//
|
||||
// s := NewSettings(kt, RequireHostAddr(true))
|
||||
func RequireHostAddr(b bool) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.requireHostAddr = b
|
||||
}
|
||||
}
|
||||
|
||||
// RequireHostAddr indicates if the service should require the host address to be included in the ticket.
|
||||
func (s *Settings) RequireHostAddr() bool {
|
||||
return s.requireHostAddr
|
||||
}
|
||||
|
||||
// DecodePAC used to configure service side to enable/disable PAC decoding if the PAC is present.
|
||||
// Defaults to enabled if not specified.
|
||||
//
|
||||
// s := NewSettings(kt, DecodePAC(false))
|
||||
func DecodePAC(b bool) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.disablePACDecoding = !b
|
||||
}
|
||||
}
|
||||
|
||||
// DecodePAC indicates whether the service should decode any PAC information present in the ticket.
|
||||
func (s *Settings) DecodePAC() bool {
|
||||
return !s.disablePACDecoding
|
||||
}
|
||||
|
||||
// ClientAddress used to configure service side with the clients host address to be used during validation.
|
||||
//
|
||||
// s := NewSettings(kt, ClientAddress(h))
|
||||
func ClientAddress(h types.HostAddress) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.cAddr = h
|
||||
}
|
||||
}
|
||||
|
||||
// ClientAddress returns the client host address which has been provided to the service.
|
||||
func (s *Settings) ClientAddress() types.HostAddress {
|
||||
return s.cAddr
|
||||
}
|
||||
|
||||
// Logger used to configure service side with a logger.
|
||||
//
|
||||
// s := NewSettings(kt, Logger(l))
|
||||
func Logger(l *log.Logger) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.logger = l
|
||||
}
|
||||
}
|
||||
|
||||
// Logger returns the logger instances configured for the service. If none is configured nill will be returned.
|
||||
func (s *Settings) Logger() *log.Logger {
|
||||
return s.logger
|
||||
}
|
||||
|
||||
// KeytabPrincipal used to override the principal name used to find the key in the keytab.
|
||||
//
|
||||
// s := NewSettings(kt, KeytabPrincipal("someaccount"))
|
||||
func KeytabPrincipal(p string) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
pn, _ := types.ParseSPNString(p)
|
||||
s.ktprinc = &pn
|
||||
}
|
||||
}
|
||||
|
||||
// KeytabPrincipal returns the principal name used to find the key in the keytab if it has been overridden.
|
||||
func (s *Settings) KeytabPrincipal() *types.PrincipalName {
|
||||
return s.ktprinc
|
||||
}
|
||||
|
||||
// MaxClockSkew used to configure service side with the maximum acceptable clock skew
|
||||
// between the service and the issue time of kerberos tickets
|
||||
//
|
||||
// s := NewSettings(kt, MaxClockSkew(d))
|
||||
func MaxClockSkew(d time.Duration) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.maxClockSkew = d
|
||||
}
|
||||
}
|
||||
|
||||
// MaxClockSkew returns the maximum acceptable clock skew between the service and the issue time of kerberos tickets.
|
||||
// If none is defined a duration of 5 minutes is returned.
|
||||
func (s *Settings) MaxClockSkew() time.Duration {
|
||||
if s.maxClockSkew.Nanoseconds() == 0 {
|
||||
return time.Duration(5) * time.Minute
|
||||
}
|
||||
return s.maxClockSkew
|
||||
}
|
||||
|
||||
// SName used provide a specific service name to the service settings.
|
||||
//
|
||||
// s := NewSettings(kt, SName("HTTP/some.service.com"))
|
||||
func SName(sname string) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.sname = sname
|
||||
}
|
||||
}
|
||||
|
||||
// SName returns the specific service name to the service.
|
||||
func (s *Settings) SName() string {
|
||||
return s.sname
|
||||
}
|
||||
|
||||
// SessionManager configures a session manager to establish sessions with clients to avoid excessive authentication challenges.
|
||||
//
|
||||
// s := NewSettings(kt, SessionManager(sm))
|
||||
func SessionManager(sm SessionMgr) func(*Settings) {
|
||||
return func(s *Settings) {
|
||||
s.sessionMgr = sm
|
||||
}
|
||||
}
|
||||
|
||||
// SessionManager returns any configured session manager.
|
||||
func (s *Settings) SessionManager() SessionMgr {
|
||||
return s.sessionMgr
|
||||
}
|
||||
|
||||
// SessionMgr must provide a ways to:
|
||||
//
|
||||
// - Create new sessions and in the process add a value to the session under the key provided.
|
||||
//
|
||||
// - Get an existing session returning the value in the session under the key provided.
|
||||
// Return nil bytes and/or error if there is no session.
|
||||
type SessionMgr interface {
|
||||
New(w http.ResponseWriter, r *http.Request, k string, v []byte) error
|
||||
Get(r *http.Request, k string) ([]byte, error)
|
||||
}
|
Reference in New Issue
Block a user