providers/ldap: add StartTLS support (#5861)
* providers/ldap: add StartTLS support Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add starttls test Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update form and docs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * re-add tls server name Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update release notes Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
69f0460f69
commit
0ce41a1b2d
2
go.mod
2
go.mod
|
@ -3,6 +3,7 @@ module goauthentik.io
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
beryju.io/ldap v0.1.0
|
||||
github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/garyburd/redigo v1.6.4
|
||||
|
@ -20,7 +21,6 @@ require (
|
|||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,3 +1,5 @@
|
|||
beryju.io/ldap v0.1.0 h1:rPjGE3qR1Klbvn9N+iECWdzt/tK87XHgz8W5wZJg9B8=
|
||||
beryju.io/ldap v0.1.0/go.mod h1:sOrYV+ZlDTDu/IvIiEiuAaXzjcpMBE+XXr4V+NJ0pWI=
|
||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
|
@ -165,8 +167,6 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ
|
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 h1:D9EvfGQvlkKaDr2CRKN++7HbSXbefUNDrPq60T+g24s=
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484/go.mod h1:O1EljZ+oHprtxDDPHiMWVo/5dBT6PlvWX5PSwj80aBA=
|
||||
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba h1:DO8NFYdcRv1dnyAINJIBm6Bw2XibtLvQniNFGzf2W8E=
|
||||
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba/go.mod h1:4S0XndRL8HNOaQBfdViJ2F/GPCgL524xlXRuXFH12/U=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
|
|
|
@ -3,8 +3,8 @@ package ldap
|
|||
import (
|
||||
"net"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/ldap/bind"
|
||||
|
|
|
@ -3,7 +3,7 @@ package bind
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
)
|
||||
|
||||
type Binder interface {
|
||||
|
|
|
@ -3,8 +3,8 @@ package direct
|
|||
import (
|
||||
"context"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/flow"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package direct
|
||||
|
||||
import (
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/flow"
|
||||
"goauthentik.io/internal/outpost/ldap/bind"
|
||||
|
|
|
@ -3,8 +3,8 @@ package memory
|
|||
import (
|
||||
"time"
|
||||
|
||||
"beryju.io/ldap"
|
||||
ttlcache "github.com/jellydator/ttlcache/v3"
|
||||
"github.com/nmcclain/ldap"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/ldap/bind"
|
||||
"goauthentik.io/internal/outpost/ldap/bind/direct"
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
"goauthentik.io/api/v3"
|
||||
"goauthentik.io/internal/outpost/ldap/constants"
|
||||
"goauthentik.io/internal/outpost/ldap/utils"
|
||||
|
|
|
@ -3,7 +3,7 @@ package group
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
"goauthentik.io/api/v3"
|
||||
"goauthentik.io/internal/outpost/ldap/constants"
|
||||
"goauthentik.io/internal/outpost/ldap/server"
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/nmcclain/ldap"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"goauthentik.io/api/v3"
|
||||
|
|
|
@ -12,8 +12,9 @@ import (
|
|||
"goauthentik.io/internal/crypto"
|
||||
"goauthentik.io/internal/outpost/ak"
|
||||
"goauthentik.io/internal/outpost/ldap/metrics"
|
||||
"goauthentik.io/internal/utils"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
)
|
||||
|
||||
type LDAPServer struct {
|
||||
|
@ -26,15 +27,21 @@ type LDAPServer struct {
|
|||
}
|
||||
|
||||
func NewServer(ac *ak.APIController) *LDAPServer {
|
||||
s := ldap.NewServer()
|
||||
s.EnforceLDAP = true
|
||||
ls := &LDAPServer{
|
||||
s: s,
|
||||
log: log.WithField("logger", "authentik.outpost.ldap"),
|
||||
ac: ac,
|
||||
cs: ak.NewCryptoStore(ac.Client.CryptoApi),
|
||||
providers: []*ProviderInstance{},
|
||||
}
|
||||
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)
|
||||
|
@ -67,7 +74,7 @@ func (ls *LDAPServer) StartLDAPServer() error {
|
|||
return err
|
||||
}
|
||||
ls.log.WithField("listen", listen).Info("Stopping LDAP server")
|
||||
return ls.s.ListenAndServe(listen)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ls *LDAPServer) Start() error {
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"net"
|
||||
"strings"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/getsentry/sentry-go"
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/ldap/metrics"
|
||||
|
@ -37,24 +37,24 @@ func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn n
|
|||
}()
|
||||
|
||||
if searchReq.BaseDN == "" {
|
||||
return ldap.ServerSearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "objectClass",
|
||||
Values: []string{"top", "OpenLDAProotDSE"},
|
||||
},
|
||||
{
|
||||
Name: "subschemaSubentry",
|
||||
Values: []string{"cn=subschema"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess,
|
||||
}, nil
|
||||
return ldap.ServerSearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "objectClass",
|
||||
Values: []string{"top", "OpenLDAProotDSE"},
|
||||
},
|
||||
{
|
||||
Name: "subschemaSubentry",
|
||||
Values: []string{"cn=subschema"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess,
|
||||
}, nil
|
||||
}
|
||||
bd, err := goldap.ParseDN(strings.ToLower(searchReq.BaseDN))
|
||||
if err != nil {
|
||||
|
@ -68,7 +68,7 @@ func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn n
|
|||
return provider.searcher.Search(req)
|
||||
}
|
||||
}
|
||||
return ldap.ServerSearchResult{
|
||||
return ldap.ServerSearchResult{
|
||||
Entries: []*ldap.Entry{
|
||||
{
|
||||
DN: "",
|
||||
|
|
|
@ -3,7 +3,7 @@ package direct
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
"goauthentik.io/internal/constants"
|
||||
"goauthentik.io/internal/outpost/ldap/search"
|
||||
)
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"goauthentik.io/api/v3"
|
||||
"goauthentik.io/internal/outpost/ldap/constants"
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/api/v3"
|
||||
|
|
|
@ -6,9 +6,9 @@ import (
|
|||
"net"
|
||||
"strings"
|
||||
|
||||
"beryju.io/ldap"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nmcclain/ldap"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/utils"
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
)
|
||||
|
||||
type Searcher interface {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"beryju.io/ldap"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/api/v3"
|
||||
"goauthentik.io/internal/outpost/ldap/flags"
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/internal/outpost/ldap/bind"
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nmcclain/ldap"
|
||||
"beryju.io/ldap"
|
||||
ldapConstants "goauthentik.io/internal/outpost/ldap/constants"
|
||||
)
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package utils
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"beryju.io/ldap"
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
ber "github.com/nmcclain/asn1-ber"
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/api/v3"
|
||||
"goauthentik.io/internal/outpost/ldap/constants"
|
||||
)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"beryju.io/ldap"
|
||||
goldap "github.com/go-ldap/ldap/v3"
|
||||
ber "github.com/nmcclain/asn1-ber"
|
||||
"github.com/nmcclain/ldap"
|
||||
"goauthentik.io/api/v3"
|
||||
"goauthentik.io/internal/outpost/ldap/constants"
|
||||
)
|
||||
|
|
|
@ -133,6 +133,34 @@ class TestProviderLDAP(SeleniumTestCase):
|
|||
)
|
||||
)
|
||||
|
||||
@retry()
|
||||
@apply_blueprint(
|
||||
"default/flow-default-authentication-flow.yaml",
|
||||
"default/flow-default-invalidation-flow.yaml",
|
||||
)
|
||||
def test_ldap_bind_success_starttls(self):
|
||||
"""Test simple bind with ssl"""
|
||||
self._prepare()
|
||||
server = Server("ldap://localhost:3389")
|
||||
_connection = Connection(
|
||||
server,
|
||||
raise_exceptions=True,
|
||||
user=f"cn={self.user.username},ou=users,DC=ldap,DC=goauthentik,DC=io",
|
||||
password=self.user.username,
|
||||
)
|
||||
_connection.start_tls()
|
||||
_connection.bind()
|
||||
self.assertTrue(
|
||||
Event.objects.filter(
|
||||
action=EventAction.LOGIN,
|
||||
user={
|
||||
"pk": self.user.pk,
|
||||
"email": self.user.email,
|
||||
"username": self.user.username,
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@retry()
|
||||
@apply_blueprint(
|
||||
"default/flow-default-authentication-flow.yaml",
|
||||
|
|
|
@ -52,7 +52,6 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
|
|||
lDAPProviderRequest: data,
|
||||
});
|
||||
} else {
|
||||
data.tlsServerName = "";
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersLdapCreate({
|
||||
lDAPProviderRequest: data,
|
||||
});
|
||||
|
@ -240,12 +239,24 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
|
|||
</ak-search-select>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate.",
|
||||
"The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${msg("TLS Server name")}
|
||||
?required=${true}
|
||||
name="tlsServerName"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value="${first(this.instance?.tlsServerName, "")}"
|
||||
class="pf-c-form-control"
|
||||
required
|
||||
/>
|
||||
<p class="pf-c-form__helper-text">
|
||||
${msg(
|
||||
"If multiple providers share an outpost, a self-signed certificate is used.",
|
||||
"DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged.",
|
||||
)}
|
||||
</p>
|
||||
</ak-form-element-horizontal>
|
||||
|
|
|
@ -56,11 +56,13 @@ Starting with 2021.9.1, custom attributes will override the inbuilt attributes.
|
|||
Starting with 2023.3, periods and slashes in custom attributes will be sanitized.
|
||||
:::
|
||||
|
||||
## SSL
|
||||
## SSL / StartTLS
|
||||
|
||||
You can also configure SSL for your LDAP Providers by selecting a certificate and a server name in the provider settings.
|
||||
|
||||
This enables you to bind on port 636 using LDAPS, StartTLS is not supported.
|
||||
Starting with authentik 2023.6, StartTLS is supported, and the provider will pick the correct certificate based on the DN a bind attempt is made with.
|
||||
|
||||
This enables you to bind on port 636 using LDAPS.
|
||||
|
||||
## Integrations
|
||||
|
||||
|
|
45
website/docs/releases/2023/v2023.6.md
Normal file
45
website/docs/releases/2023/v2023.6.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title: Release 2023.6
|
||||
slug: "/releases/2023.6"
|
||||
---
|
||||
|
||||
<!-- ## Breaking changes -->
|
||||
|
||||
## New features
|
||||
|
||||
- LDAP StartTLS support
|
||||
|
||||
authentik's [LDAP Provider](../../providers/ldap/index.md) now supports StartTLS in addition to supporting SSL. The StartTLS is a more modern method of encrypting LDAP traffic. With this added support, the LDAP [Outpost](../../outposts/index.mdx) can now support multiple certificates.
|
||||
|
||||
## Upgrading
|
||||
|
||||
This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
To upgrade, download the new docker-compose file and update the Docker stack with the new version, using these commands:
|
||||
|
||||
```
|
||||
wget -O docker-compose.yml https://goauthentik.io/version/2023.6/docker-compose.yml
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
The `-O` flag retains the downloaded file's name, overwriting any existing local file with the same name.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Update your values to use the new images:
|
||||
|
||||
```yaml
|
||||
image:
|
||||
repository: ghcr.io/goauthentik/server
|
||||
tag: 2023.6.0
|
||||
```
|
||||
|
||||
## Minor changes/fixes
|
||||
|
||||
<!-- _Insert the output of `make gen-changelog` here_ -->
|
||||
|
||||
## API Changes
|
||||
|
||||
<!-- _Insert output of `make gen-diff` here_ -->
|
|
@ -3,7 +3,7 @@ title: Release xxxx.x
|
|||
slug: "/releases/xxxx.x"
|
||||
---
|
||||
|
||||
## Breaking changes
|
||||
<!-- ## Breaking changes -->
|
||||
|
||||
## New features
|
||||
|
||||
|
@ -34,8 +34,8 @@ image:
|
|||
|
||||
## Minor changes/fixes
|
||||
|
||||
_Insert the output of `make gen-changelog` here_
|
||||
<!-- _Insert the output of `make gen-changelog` here_ -->
|
||||
|
||||
## API Changes
|
||||
|
||||
_Insert output of `make gen-diff` here_
|
||||
<!-- _Insert output of `make gen-diff` here_ -->
|
||||
|
|
Reference in a new issue