 88fa7e37dc
			
		
	
	88fa7e37dc
	
	
	
		
			
			* outpost: promote session end signal to non-provider specific Signed-off-by: Jens Langhammer <jens@goauthentik.io> * implement server-side logout in ldap Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix previous import Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use better retry logic Signed-off-by: Jens Langhammer <jens@goauthentik.io> * log Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make more generic if we switch from ws to something else Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make it possible to e2e test WS Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix ldap session id Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ok I actually need to go to bed this took me an hour to fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format; add ldap test Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix leftover state Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove thread Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use ws base for radius Signed-off-by: Jens Langhammer <jens@goauthentik.io> * separate test utils Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix missing super calls Signed-off-by: Jens Langhammer <jens@goauthentik.io> * websocket tests with browser 🎉 Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add proxy test for sign out Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix install_id issue with channels tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix proxy basic auth test Signed-off-by: Jens Langhammer <jens@goauthentik.io> * big code dedupe Signed-off-by: Jens Langhammer <jens@goauthentik.io> * allow passing go build args Signed-off-by: Jens Langhammer <jens@goauthentik.io> * improve waiting for outpost Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rewrite ldap tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * ok actually fix the tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * undo a couple things that need more time to cook Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove unused lockfile-lint dependency since we use a shell script and SFE does not have a lockfile Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix session id for ldap Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix missing createTimestamp and modifyTimestamp ldap attributes closes #10474 Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
		
			
				
	
	
		
			146 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package ldap
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"crypto/tls"
 | |
| 	"net"
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/pires/go-proxyproto"
 | |
| 	log "github.com/sirupsen/logrus"
 | |
| 	"goauthentik.io/internal/config"
 | |
| 	"goauthentik.io/internal/crypto"
 | |
| 	"goauthentik.io/internal/outpost/ak"
 | |
| 	"goauthentik.io/internal/outpost/ldap/metrics"
 | |
| 	"goauthentik.io/internal/utils"
 | |
| 
 | |
| 	"beryju.io/ldap"
 | |
| )
 | |
| 
 | |
| type LDAPServer struct {
 | |
| 	s               *ldap.Server
 | |
| 	log             *log.Entry
 | |
| 	ac              *ak.APIController
 | |
| 	cs              *ak.CryptoStore
 | |
| 	defaultCert     *tls.Certificate
 | |
| 	providers       []*ProviderInstance
 | |
| 	connections     map[string]net.Conn
 | |
| 	connectionsSync sync.Mutex
 | |
| }
 | |
| 
 | |
| func NewServer(ac *ak.APIController) ak.Outpost {
 | |
| 	ls := &LDAPServer{
 | |
| 		log:             log.WithField("logger", "authentik.outpost.ldap"),
 | |
| 		ac:              ac,
 | |
| 		cs:              ak.NewCryptoStore(ac.Client.CryptoApi),
 | |
| 		providers:       []*ProviderInstance{},
 | |
| 		connections:     map[string]net.Conn{},
 | |
| 		connectionsSync: sync.Mutex{},
 | |
| 	}
 | |
| 	ac.AddEventHandler(ls.handleWSSessionEnd)
 | |
| 	s := ldap.NewServer()
 | |
| 	s.EnforceLDAP = true
 | |
| 
 | |
| 	tlsConfig := utils.GetTLSConfig()
 | |
| 	tlsConfig.GetCertificate = ls.getCertificates
 | |
| 	s.StartTLS = tlsConfig
 | |
| 
 | |
| 	ls.s = s
 | |
| 
 | |
| 	defaultCert, err := crypto.GenerateSelfSignedCert()
 | |
| 	if err != nil {
 | |
| 		log.Warning(err)
 | |
| 	}
 | |
| 	ls.defaultCert = &defaultCert
 | |
| 	s.BindFunc("", ls)
 | |
| 	s.UnbindFunc("", ls)
 | |
| 	s.SearchFunc("", ls)
 | |
| 	s.CloseFunc("", ls)
 | |
| 	return ls
 | |
| }
 | |
| 
 | |
| func (ls *LDAPServer) Type() string {
 | |
| 	return "ldap"
 | |
| }
 | |
| 
 | |
| func (ls *LDAPServer) StartLDAPServer() error {
 | |
| 	listen := config.Get().Listen.LDAP
 | |
| 
 | |
| 	ln, err := net.Listen("tcp", listen)
 | |
| 	if err != nil {
 | |
| 		ls.log.WithField("listen", listen).WithError(err).Warning("Failed to listen (SSL)")
 | |
| 		return err
 | |
| 	}
 | |
| 	proxyListener := &proxyproto.Listener{Listener: ln, ConnPolicy: utils.GetProxyConnectionPolicy()}
 | |
| 	defer func() {
 | |
| 		err := proxyListener.Close()
 | |
| 		if err != nil {
 | |
| 			ls.log.WithError(err).Warning("failed to close proxy listener")
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	ls.log.WithField("listen", listen).Info("Starting LDAP server")
 | |
| 	err = ls.s.Serve(proxyListener)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	ls.log.WithField("listen", listen).Info("Stopping LDAP server")
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (ls *LDAPServer) Start() error {
 | |
| 	wg := sync.WaitGroup{}
 | |
| 	wg.Add(3)
 | |
| 	go func() {
 | |
| 		defer wg.Done()
 | |
| 		metrics.RunServer()
 | |
| 	}()
 | |
| 	go func() {
 | |
| 		defer wg.Done()
 | |
| 		err := ls.StartLDAPServer()
 | |
| 		if err != nil {
 | |
| 			panic(err)
 | |
| 		}
 | |
| 	}()
 | |
| 	go func() {
 | |
| 		defer wg.Done()
 | |
| 		err := ls.StartLDAPTLSServer()
 | |
| 		if err != nil {
 | |
| 			panic(err)
 | |
| 		}
 | |
| 	}()
 | |
| 	wg.Wait()
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (ls *LDAPServer) Stop() error {
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (ls *LDAPServer) TimerFlowCacheExpiry(ctx context.Context) {
 | |
| 	for _, p := range ls.providers {
 | |
| 		ls.log.WithField("flow", p.authenticationFlowSlug).Debug("Pre-heating flow cache")
 | |
| 		p.binder.TimerFlowCacheExpiry(ctx)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (ls *LDAPServer) handleWSSessionEnd(ctx context.Context, msg ak.Event) error {
 | |
| 	if msg.Instruction != ak.EventKindSessionEnd {
 | |
| 		return nil
 | |
| 	}
 | |
| 	mmsg := ak.EventArgsSessionEnd{}
 | |
| 	err := msg.ArgsAs(&mmsg)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	ls.connectionsSync.Lock()
 | |
| 	defer ls.connectionsSync.Unlock()
 | |
| 	ls.log.Info("Disconnecting session due to session end event")
 | |
| 	conn, ok := ls.connections[mmsg.SessionID]
 | |
| 	if !ok {
 | |
| 		return nil
 | |
| 	}
 | |
| 	delete(ls.connections, mmsg.SessionID)
 | |
| 	return conn.Close()
 | |
| }
 |