164 lines
4.6 KiB
Go
164 lines
4.6 KiB
Go
|
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)
|
||
|
}
|