make certificate configurable

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer
2025-05-16 15:59:10 +02:00
parent fa06c9fe4e
commit 3ada3a7e0e
13 changed files with 117 additions and 32 deletions

View File

@ -51,6 +51,7 @@ func (rs *RadiusServer) Refresh() error {
MFASupport: provider.GetMfaSupport(),
appSlug: provider.ApplicationSlug,
flowSlug: provider.AuthFlowSlug,
certId: provider.GetCertificate(),
providerId: provider.Pk,
s: rs,
log: logger,

View File

@ -42,7 +42,7 @@ func NewBuffConn(initialData []byte, ctx context.Context) *BuffConn {
var errStall = errors.New("Stall")
func (conn BuffConn) OutboundData() []byte {
d, err := retry.DoWithData(
d, _ := retry.DoWithData(
func() ([]byte, error) {
b := conn.writer.Bytes()
if len(b) < 1 {
@ -52,9 +52,6 @@ func (conn BuffConn) OutboundData() []byte {
},
conn.retryOptions...,
)
if err != nil {
return []byte{}
}
return d
}

View File

@ -8,6 +8,7 @@ import (
"slices"
"time"
"github.com/avast/retry-go/v4"
log "github.com/sirupsen/logrus"
"goauthentik.io/internal/outpost/radius/eap/debug"
"goauthentik.io/internal/outpost/radius/eap/protocol"
@ -104,7 +105,21 @@ func (p *Payload) Handle(ctx protocol.Context) protocol.Payload {
}
if p.st.Conn.writer.Len() == 0 && p.st.HandshakeDone {
defer p.st.ContextCancel()
ctx.EndInnerProtocol(protocol.StatusSuccess, func(r *radius.Packet) *radius.Packet {
// If we don't have a final status from the handshake finished function, stall for time
pst, _ := retry.DoWithData(
func() (protocol.Status, error) {
if p.st.FinalStatus == protocol.StatusUnknown {
return p.st.FinalStatus, errStall
}
return p.st.FinalStatus, nil
},
retry.Context(p.st.Context),
retry.Delay(10*time.Microsecond),
retry.DelayType(retry.BackOffDelay),
retry.MaxDelay(100*time.Millisecond),
retry.Attempts(0),
)
ctx.EndInnerProtocol(pst, func(r *radius.Packet) *radius.Packet {
microsoft.MSMPPERecvKey_Set(r, p.st.MPPEKey[:32])
microsoft.MSMPPESendKey_Set(r, p.st.MPPEKey[64:64+32])
return r
@ -129,6 +144,7 @@ func (p *Payload) tlsInit(ctx protocol.Context) {
err := p.st.TLS.HandshakeContext(p.st.Context)
if err != nil {
ctx.Log().WithError(err).Debug("TLS: Handshake error")
p.st.FinalStatus = protocol.StatusError
ctx.EndInnerProtocol(protocol.StatusError, func(p *radius.Packet) *radius.Packet {
return p
})
@ -159,7 +175,7 @@ func (p *Payload) tlsHandshakeFinished(ctx protocol.Context) {
ctx.Log().Debugf("TLS: ksm % x %v", ksm, err)
p.st.MPPEKey = ksm
p.st.HandshakeDone = true
ctx.ProtocolSettings().(Settings).HandshakeSuccessful(ctx, cs.PeerCertificates)
p.st.FinalStatus = ctx.ProtocolSettings().(Settings).HandshakeSuccessful(ctx, cs.PeerCertificates)
}
func (p *Payload) startChunkedTransfer(data []byte) *Payload {

View File

@ -9,5 +9,5 @@ import (
type Settings struct {
Config *tls.Config
HandshakeSuccessful func(ctx protocol.Context, certs []*x509.Certificate)
HandshakeSuccessful func(ctx protocol.Context, certs []*x509.Certificate) protocol.Status
}

View File

@ -11,6 +11,7 @@ type State struct {
HasStarted bool
RemainingChunks [][]byte
HandshakeDone bool
FinalStatus protocol.Status
ClientHello *tls.ClientHelloInfo
MPPEKey []byte
TotalPayloadSize int

View File

@ -128,13 +128,18 @@ func (pi *ProviderInstance) SetEAPState(key string, state *eap.State) {
}
func (pi *ProviderInstance) GetEAPSettings() eap.Settings {
// Testing
cert, err := ttls.LoadX509KeyPair(
"../t/ca/out/cert_jens-mbp.lab.beryju.org.pem",
"../t/ca/out/cert_jens-mbp.lab.beryju.org.key",
)
if err != nil {
panic(err)
certId := pi.certId
if certId == "" {
return eap.Settings{
ProtocolsToOffer: []protocol.Type{},
}
}
cert := pi.s.cryptoStore.Get(certId)
if cert == nil {
return eap.Settings{
ProtocolsToOffer: []protocol.Type{},
}
}
return eap.Settings{
@ -142,19 +147,18 @@ func (pi *ProviderInstance) GetEAPSettings() eap.Settings {
ProtocolSettings: map[protocol.Type]interface{}{
tls.TypeTLS: tls.Settings{
Config: &ttls.Config{
Certificates: []ttls.Certificate{cert},
Certificates: []ttls.Certificate{*cert},
ClientAuth: ttls.RequireAnyClientCert,
},
HandshakeSuccessful: func(ctx protocol.Context, certs []*x509.Certificate) {
HandshakeSuccessful: func(ctx protocol.Context, certs []*x509.Certificate) protocol.Status {
ctx.Log().Debug("Starting authn flow")
pem := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: certs[0].Raw,
})
fe := flow.NewFlowExecutor(context.Background(), pi.flowSlug, pi.s.ac.Client.GetConfig(), log.Fields{
// "username": username,
// "client": r.RemoteAddr(),
// "requestId": r.ID(),
"client": utils.GetIP(ctx.Packet().RemoteAddr),
})
fe.DelegateClientIP(utils.GetIP(ctx.Packet().RemoteAddr))
fe.Params.Add("goauthentik.io/outpost/radius", "true")
@ -162,16 +166,14 @@ func (pi *ProviderInstance) GetEAPSettings() eap.Settings {
passed, err := fe.Execute()
if err != nil {
panic(err)
ctx.Log().WithError(err).Warning("failed to execute flow")
return protocol.StatusError
}
ctx.Log().WithField("passed", passed).Debug("Finished flow")
if passed {
ctx.EndInnerProtocol(protocol.StatusSuccess, func(p *radius.Packet) *radius.Packet {
return p
})
return protocol.StatusSuccess
} else {
ctx.EndInnerProtocol(protocol.StatusError, func(p *radius.Packet) *radius.Packet {
return p
})
return protocol.StatusError
}
},
},

View File

@ -23,24 +23,27 @@ type ProviderInstance struct {
appSlug string
flowSlug string
providerId int32
certId string
s *RadiusServer
log *log.Entry
eapState map[string]*eap.State
}
type RadiusServer struct {
s radius.PacketServer
log *log.Entry
ac *ak.APIController
s radius.PacketServer
log *log.Entry
ac *ak.APIController
cryptoStore *ak.CryptoStore
providers []*ProviderInstance
}
func NewServer(ac *ak.APIController) ak.Outpost {
rs := &RadiusServer{
log: log.WithField("logger", "authentik.outpost.radius"),
ac: ac,
providers: []*ProviderInstance{},
log: log.WithField("logger", "authentik.outpost.radius"),
ac: ac,
providers: []*ProviderInstance{},
cryptoStore: ak.NewCryptoStore(ac.Client.CryptoApi),
}
rs.s = radius.PacketServer{
Handler: rs,