1
0

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:
renovate
2020-05-29 17:47:28 +00:00
committed by konrad
parent 5a04f1ecf4
commit 54b18b3c59
161 changed files with 19472 additions and 7 deletions

View 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
}

View 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
View 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
}

View 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)
}