From 3ad1c3f212b732c0705c115165ff427e41ff4735 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 16:28:14 +0200 Subject: [PATCH 01/13] web/admin: fix AuthenticatorValidationStage's form not setting notConfiguredAction Signed-off-by: Jens Langhammer #802 --- .../authenticator_validate/AuthenticatorValidateStageForm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts b/web/src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts index 5d38d8276..8314a5f08 100644 --- a/web/src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts +++ b/web/src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts @@ -70,7 +70,7 @@ export class AuthenticatorValidateStageForm extends ModelForm + name="notConfiguredAction"> @@ -80,7 +80,7 @@ export class RuleForm extends ModelForm { ${until(new EventsApi(DEFAULT_CONFIG).eventsTransportsList({}).then(transports => { return transports.results.map(transport => { const selected = Array.from(this.instance?.transports || []).some(su => { - return su.uuid == transport.pk; + return su == transport.pk; }); return html``; }); diff --git a/web/src/pages/events/RuleListPage.ts b/web/src/pages/events/RuleListPage.ts index 7ffcd4d30..3852fd293 100644 --- a/web/src/pages/events/RuleListPage.ts +++ b/web/src/pages/events/RuleListPage.ts @@ -55,7 +55,7 @@ export class RuleListPage extends TablePage { return [ html`${item.name}`, html`${item.severity}`, - html`${item.group?.name || t`None (rule disabled)`}`, + html`${item.groupObj?.name || t`None (rule disabled)`}`, html` From 8e5d03cb8614ae89a6e5bea990fd2d0fb12edc6b Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 16:41:54 +0200 Subject: [PATCH 04/13] outposts: remove legacy API Signed-off-by: Jens Langhammer --- authentik/outposts/api/outposts.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/authentik/outposts/api/outposts.py b/authentik/outposts/api/outposts.py index 7268cfdf6..d026fa503 100644 --- a/authentik/outposts/api/outposts.py +++ b/authentik/outposts/api/outposts.py @@ -18,8 +18,6 @@ class OutpostSerializer(ModelSerializer): """Outpost Serializer""" config = JSONField(validators=[is_dict], source="_config") - # TODO: Remove _config again, this is only here for legacy with older outposts - _config = JSONField(validators=[is_dict], read_only=True) providers_obj = ProviderSerializer(source="providers", many=True, read_only=True) def validate_config(self, config) -> dict: @@ -42,7 +40,6 @@ class OutpostSerializer(ModelSerializer): "service_connection", "token_identifier", "config", - "_config", ] From 52cf4890cfce53e2069cc5fa5db8e3a257a4f17b Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 17:53:23 +0200 Subject: [PATCH 05/13] root: remove servername from backup files Signed-off-by: Jens Langhammer --- authentik/root/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/authentik/root/settings.py b/authentik/root/settings.py index 63314ab06..064516571 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -320,6 +320,7 @@ CELERY_RESULT_BACKEND = ( # Database backup DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage" DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"} +DBBACKUP_FILENAME_TEMPLATE = 'authentik-backup-{datetime}.sql' if CONFIG.y("postgresql.s3_backup"): DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" DBBACKUP_STORAGE_OPTIONS = { From 34ab68a1694abeedc2776a26f31fd47342d0be00 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 18:01:46 +0200 Subject: [PATCH 06/13] outposts: cleanup logging Signed-off-by: Jens Langhammer --- outpost/pkg/ak/api_ws.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/outpost/pkg/ak/api_ws.go b/outpost/pkg/ak/api_ws.go index fb5526961..365c36336 100644 --- a/outpost/pkg/ak/api_ws.go +++ b/outpost/pkg/ak/api_ws.go @@ -76,7 +76,7 @@ func (ac *APIController) startWSHandler() { var wsMsg websocketMessage err := ac.wsConn.ReadJSON(&wsMsg) if err != nil { - logger.Println("read:", err) + logger.WithError(err).Warning("ws write error, reconnecting") ac.wsConn.CloseAndReconnect() continue } @@ -107,7 +107,7 @@ func (ac *APIController) startWSHealth() { err := ac.wsConn.WriteJSON(aliveMsg) ac.logger.WithField("loop", "ws-health").Trace("hello'd") if err != nil { - ac.logger.WithField("loop", "ws-health").Println("write:", err) + ac.logger.WithField("loop", "ws-health").WithError(err).Warning("ws write error, reconnecting") ac.wsConn.CloseAndReconnect() continue } From 9a0aa4c79b62bb3b07836b535731e664b7b2fc0f Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 18:31:44 +0200 Subject: [PATCH 07/13] outposts/ldap: add infinite loop prevention Signed-off-by: Jens Langhammer --- authentik/root/settings.py | 2 +- outpost/pkg/ldap/instance_bind.go | 13 ++++++++++--- web/src/pages/outposts/OutpostHealth.ts | 5 ++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/authentik/root/settings.py b/authentik/root/settings.py index 064516571..5060215fe 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -320,7 +320,7 @@ CELERY_RESULT_BACKEND = ( # Database backup DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage" DBBACKUP_STORAGE_OPTIONS = {"location": "./backups" if DEBUG else "/backups"} -DBBACKUP_FILENAME_TEMPLATE = 'authentik-backup-{datetime}.sql' +DBBACKUP_FILENAME_TEMPLATE = "authentik-backup-{datetime}.sql" if CONFIG.y("postgresql.s3_backup"): DBBACKUP_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" DBBACKUP_STORAGE_OPTIONS = { diff --git a/outpost/pkg/ldap/instance_bind.go b/outpost/pkg/ldap/instance_bind.go index e9cb527f0..6ba7d1d4b 100644 --- a/outpost/pkg/ldap/instance_bind.go +++ b/outpost/pkg/ldap/instance_bind.go @@ -67,7 +67,7 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn) } params := url.Values{} params.Add("goauthentik.io/outpost/ldap", "true") - passed, err := pi.solveFlowChallenge(username, bindPW, client, params.Encode()) + passed, err := pi.solveFlowChallenge(username, bindPW, client, params.Encode(), 1) if err != nil { pi.log.WithField("boundDN", username).WithError(err).Warning("failed to solve challenge") return ldap.LDAPResultOperationsError, nil @@ -139,7 +139,7 @@ func (pi *ProviderInstance) delayDeleteUserInfo(dn string) { }() } -func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *http.Client, urlParams string) (bool, error) { +func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, client *http.Client, urlParams string, depth int) (bool, error) { challenge, err := pi.s.ac.Client.Flows.FlowsExecutorGet(&flows.FlowsExecutorGetParams{ FlowSlug: pi.flowSlug, Query: urlParams, @@ -169,6 +169,10 @@ func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, c } response, err := pi.s.ac.Client.Flows.FlowsExecutorSolve(responseParams, pi.s.ac.Auth) pi.log.WithField("component", response.Payload.Component).WithField("type", *response.Payload.Type).Debug("Got response") + switch response.Payload.Component { + case "ak-stage-access-denied": + return false, errors.New("got ak-stage-access-denied") + } if *response.Payload.Type == "redirect" { return true, nil } @@ -184,5 +188,8 @@ func (pi *ProviderInstance) solveFlowChallenge(bindDN string, password string, c } } } - return pi.solveFlowChallenge(bindDN, password, client, urlParams) + if depth >= 10 { + return false, errors.New("exceeded stage recursion depth") + } + return pi.solveFlowChallenge(bindDN, password, client, urlParams, depth+1) } diff --git a/web/src/pages/outposts/OutpostHealth.ts b/web/src/pages/outposts/OutpostHealth.ts index 9ec2654c2..eee784756 100644 --- a/web/src/pages/outposts/OutpostHealth.ts +++ b/web/src/pages/outposts/OutpostHealth.ts @@ -42,13 +42,12 @@ export class OutpostHealthElement extends LitElement { return html``; } if (this.outpostHealth.length === 0) { - return html`
  • + return html`
    • -
    -
  • `; + `; } return html`
      ${this.outpostHealth.map((h) => { return html`
    • From e9aa37ba673ba9200d30f8fe832183125a7a03eb Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 18:49:15 +0200 Subject: [PATCH 08/13] outposts/ldap: fix user info caching, fix mixed case DN Signed-off-by: Jens Langhammer #864 --- outpost/pkg/ldap/bind.go | 8 +++++--- outpost/pkg/ldap/instance_bind.go | 19 ++++++++++--------- outpost/pkg/ldap/instance_search.go | 3 +++ outpost/pkg/ldap/ldap.go | 2 +- outpost/pkg/ldap/search.go | 6 +++--- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/outpost/pkg/ldap/bind.go b/outpost/pkg/ldap/bind.go index 1fcc6e781..c050b7184 100644 --- a/outpost/pkg/ldap/bind.go +++ b/outpost/pkg/ldap/bind.go @@ -2,20 +2,22 @@ package ldap import ( "net" + "strings" "github.com/nmcclain/ldap" ) func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) { - ls.log.WithField("boundDN", bindDN).Info("bind") + ls.log.WithField("bindDN", bindDN).Info("bind") + bindDN = strings.ToLower(bindDN) for _, instance := range ls.providers { username, err := instance.getUsername(bindDN) if err == nil { - return instance.Bind(username, bindPW, conn) + return instance.Bind(username, bindDN, bindPW, conn) } else { ls.log.WithError(err).Debug("Username not for instance") } } - ls.log.WithField("boundDN", bindDN).WithField("request", "bind").Warning("No provider found for request") + ls.log.WithField("bindDN", bindDN).WithField("request", "bind").Warning("No provider found for request") return ldap.LDAPResultOperationsError, nil } diff --git a/outpost/pkg/ldap/instance_bind.go b/outpost/pkg/ldap/instance_bind.go index 6ba7d1d4b..b9a860854 100644 --- a/outpost/pkg/ldap/instance_bind.go +++ b/outpost/pkg/ldap/instance_bind.go @@ -47,7 +47,7 @@ func (pi *ProviderInstance) getUsername(dn string) (string, error) { return "", errors.New("failed to find cn") } -func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) { +func (pi *ProviderInstance) Bind(username string, bindDN, bindPW string, conn net.Conn) (ldap.LDAPResultCode, error) { jar, err := cookiejar.New(nil) if err != nil { pi.log.WithError(err).Warning("Failed to create cookiejar") @@ -69,7 +69,7 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn) params.Add("goauthentik.io/outpost/ldap", "true") passed, err := pi.solveFlowChallenge(username, bindPW, client, params.Encode(), 1) if err != nil { - pi.log.WithField("boundDN", username).WithError(err).Warning("failed to solve challenge") + pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to solve challenge") return ldap.LDAPResultOperationsError, nil } if !passed { @@ -82,25 +82,25 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn) }, httptransport.PassThroughAuth) if err != nil { if _, denied := err.(*core.CoreApplicationsCheckAccessForbidden); denied { - pi.log.WithField("boundDN", username).Info("Access denied for user") + pi.log.WithField("bindDN", bindDN).Info("Access denied for user") return ldap.LDAPResultInsufficientAccessRights, nil } - pi.log.WithField("boundDN", username).WithError(err).Warning("failed to check access") + pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to check access") return ldap.LDAPResultOperationsError, nil } - pi.log.WithField("boundDN", username).Info("User has access") + pi.log.WithField("bindDN", bindDN).Info("User has access") // Get user info to store in context userInfo, err := pi.s.ac.Client.Core.CoreUsersMe(&core.CoreUsersMeParams{ Context: context.Background(), HTTPClient: client, }, httptransport.PassThroughAuth) if err != nil { - pi.log.WithField("boundDN", username).WithError(err).Warning("failed to get user info") + pi.log.WithField("bindDN", bindDN).WithError(err).Warning("failed to get user info") return ldap.LDAPResultOperationsError, nil } pi.boundUsersMutex.Lock() - pi.boundUsers[username] = UserFlags{ - UserInfo: userInfo.Payload.User, + pi.boundUsers[bindDN] = UserFlags{ + UserInfo: *userInfo.Payload.User, CanSearch: pi.SearchAccessCheck(userInfo.Payload.User), } defer pi.boundUsersMutex.Unlock() @@ -112,7 +112,8 @@ func (pi *ProviderInstance) Bind(username string, bindPW string, conn net.Conn) func (pi *ProviderInstance) SearchAccessCheck(user *models.User) bool { for _, group := range user.Groups { for _, allowedGroup := range pi.searchAllowedGroups { - if &group.Pk == allowedGroup { + pi.log.WithField("userGroup", group.Pk).WithField("allowedGroup", allowedGroup).Trace("Checking search access") + if group.Pk.String() == allowedGroup.String() { pi.log.WithField("group", group.Name).Info("Allowed access to search") return true } diff --git a/outpost/pkg/ldap/instance_search.go b/outpost/pkg/ldap/instance_search.go index b7102c347..913adcbb2 100644 --- a/outpost/pkg/ldap/instance_search.go +++ b/outpost/pkg/ldap/instance_search.go @@ -29,10 +29,13 @@ func (pi *ProviderInstance) Search(bindDN string, searchReq ldap.SearchRequest, pi.boundUsersMutex.RLock() defer pi.boundUsersMutex.RUnlock() flags, ok := pi.boundUsers[bindDN] + pi.log.WithField("bindDN", bindDN).WithField("ok", ok).Debugf("%+v\n", flags) if !ok { + pi.log.Debug("User info not cached") return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") } if !flags.CanSearch { + pi.log.Debug("User can't search") return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, errors.New("access denied") } diff --git a/outpost/pkg/ldap/ldap.go b/outpost/pkg/ldap/ldap.go index a22348639..f7253108e 100644 --- a/outpost/pkg/ldap/ldap.go +++ b/outpost/pkg/ldap/ldap.go @@ -31,7 +31,7 @@ type ProviderInstance struct { } type UserFlags struct { - UserInfo *models.User + UserInfo models.User CanSearch bool } diff --git a/outpost/pkg/ldap/search.go b/outpost/pkg/ldap/search.go index ecc5f35e6..ab00a71bc 100644 --- a/outpost/pkg/ldap/search.go +++ b/outpost/pkg/ldap/search.go @@ -8,8 +8,8 @@ import ( "github.com/nmcclain/ldap" ) -func (ls *LDAPServer) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { - ls.log.WithField("boundDN", boundDN).WithField("baseDN", searchReq.BaseDN).Info("search") +func (ls *LDAPServer) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) { + ls.log.WithField("bindDN", bindDN).WithField("baseDN", searchReq.BaseDN).Info("search") if searchReq.BaseDN == "" { return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultSuccess}, nil } @@ -21,7 +21,7 @@ func (ls *LDAPServer) Search(boundDN string, searchReq ldap.SearchRequest, conn for _, provider := range ls.providers { providerBase, _ := goldap.ParseDN(provider.BaseDN) if providerBase.AncestorOf(bd) { - return provider.Search(boundDN, searchReq, conn) + return provider.Search(bindDN, searchReq, conn) } } return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, errors.New("no provider could handle request") From 37b57ac28f19cd1712a952e95149a054bb1714a8 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 18:56:44 +0200 Subject: [PATCH 09/13] outposts: include git commit hash in build from git branch Signed-off-by: Jens Langhammer --- outpost/azure-pipelines.yml | 2 ++ outpost/ldap.Dockerfile | 2 ++ outpost/pkg/ak/global.go | 3 ++- outpost/proxy.Dockerfile | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/outpost/azure-pipelines.yml b/outpost/azure-pipelines.yml index c3df49c67..a17cdf95f 100644 --- a/outpost/azure-pipelines.yml +++ b/outpost/azure-pipelines.yml @@ -117,6 +117,7 @@ stages: Dockerfile: 'outpost/proxy.Dockerfile' buildContext: 'outpost/' tags: "gh-$(branchName)" + arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)' - job: ldap_build_docker pool: vmImage: 'ubuntu-latest' @@ -142,3 +143,4 @@ stages: Dockerfile: 'outpost/ldap.Dockerfile' buildContext: 'outpost/' tags: "gh-$(branchName)" + arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)' diff --git a/outpost/ldap.Dockerfile b/outpost/ldap.Dockerfile index 08149fe05..a204c15be 100644 --- a/outpost/ldap.Dockerfile +++ b/outpost/ldap.Dockerfile @@ -1,4 +1,6 @@ FROM golang:1.16.4 AS builder +ARG GIT_BUILD_HASH +ENV GIT_BUILD_HASH=$GIT_BUILD_HASH WORKDIR /work diff --git a/outpost/pkg/ak/global.go b/outpost/pkg/ak/global.go index 108803ec3..c9417dd70 100644 --- a/outpost/pkg/ak/global.go +++ b/outpost/pkg/ak/global.go @@ -33,7 +33,8 @@ func doGlobalSetup(config map[string]interface{}) { default: log.SetLevel(log.DebugLevel) } - log.WithField("version", pkg.VERSION).Info("Starting authentik outpost") + buildHash := os.Getenv("GIT_BUILD_HASH") + log.WithField("buildHash", buildHash).WithField("version", pkg.VERSION).Info("Starting authentik outpost") var dsn string if config[ConfigErrorReportingEnabled].(bool) { diff --git a/outpost/proxy.Dockerfile b/outpost/proxy.Dockerfile index 8943b5a51..15861aed0 100644 --- a/outpost/proxy.Dockerfile +++ b/outpost/proxy.Dockerfile @@ -1,4 +1,6 @@ FROM golang:1.16.4 AS builder +ARG GIT_BUILD_HASH +ENV GIT_BUILD_HASH=$GIT_BUILD_HASH WORKDIR /work From 901cea14536f4164d81f7df1f1f250375d0d4ec7 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 19:02:04 +0200 Subject: [PATCH 10/13] outposts: send build hash as part of hello Signed-off-by: Jens Langhammer --- outpost/pkg/ak/api.go | 3 +-- outpost/pkg/ak/api_ws.go | 12 +++++++----- outpost/pkg/ak/global.go | 3 +-- outpost/pkg/version.go | 13 +++++++++++++ 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/outpost/pkg/ak/api.go b/outpost/pkg/ak/api.go index c897003a4..413a8afaf 100644 --- a/outpost/pkg/ak/api.go +++ b/outpost/pkg/ak/api.go @@ -1,7 +1,6 @@ package ak import ( - "fmt" "math/rand" "net/url" "os" @@ -43,7 +42,7 @@ type APIController struct { // NewAPIController initialise new API Controller instance from URL and API token func NewAPIController(akURL url.URL, token string) *APIController { transport := httptransport.New(akURL.Host, client.DefaultBasePath, []string{akURL.Scheme}) - transport.Transport = SetUserAgent(getTLSTransport(), fmt.Sprintf("authentik-proxy@%s", pkg.VERSION)) + transport.Transport = SetUserAgent(getTLSTransport(), pkg.UserAgent()) // create the transport auth := httptransport.BearerToken(token) diff --git a/outpost/pkg/ak/api_ws.go b/outpost/pkg/ak/api_ws.go index 365c36336..898579418 100644 --- a/outpost/pkg/ak/api_ws.go +++ b/outpost/pkg/ak/api_ws.go @@ -23,7 +23,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) { header := http.Header{ "Authorization": []string{authHeader}, - "User-Agent": []string{fmt.Sprintf("authentik-proxy@%s", pkg.VERSION)}, + "User-Agent": []string{pkg.UserAgent()}, } value, set := os.LookupEnv("AUTHENTIK_INSECURE") @@ -46,8 +46,9 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) { msg := websocketMessage{ Instruction: WebsocketInstructionHello, Args: map[string]interface{}{ - "version": pkg.VERSION, - "uuid": ac.instanceUUID.String(), + "version": pkg.VERSION, + "buildHash": pkg.BUILD(), + "uuid": ac.instanceUUID.String(), }, } err := ws.WriteJSON(msg) @@ -100,8 +101,9 @@ func (ac *APIController) startWSHealth() { aliveMsg := websocketMessage{ Instruction: WebsocketInstructionHello, Args: map[string]interface{}{ - "version": pkg.VERSION, - "uuid": ac.instanceUUID.String(), + "version": pkg.VERSION, + "buildHash": pkg.BUILD(), + "uuid": ac.instanceUUID.String(), }, } err := ac.wsConn.WriteJSON(aliveMsg) diff --git a/outpost/pkg/ak/global.go b/outpost/pkg/ak/global.go index c9417dd70..b446075c5 100644 --- a/outpost/pkg/ak/global.go +++ b/outpost/pkg/ak/global.go @@ -33,8 +33,7 @@ func doGlobalSetup(config map[string]interface{}) { default: log.SetLevel(log.DebugLevel) } - buildHash := os.Getenv("GIT_BUILD_HASH") - log.WithField("buildHash", buildHash).WithField("version", pkg.VERSION).Info("Starting authentik outpost") + log.WithField("buildHash", pkg.BUILD()).WithField("version", pkg.VERSION).Info("Starting authentik outpost") var dsn string if config[ConfigErrorReportingEnabled].(bool) { diff --git a/outpost/pkg/version.go b/outpost/pkg/version.go index b68db357a..32075e595 100644 --- a/outpost/pkg/version.go +++ b/outpost/pkg/version.go @@ -1,3 +1,16 @@ package pkg +import ( + "fmt" + "os" +) + const VERSION = "2021.5.1-rc7" + +func BUILD() string { + return os.Getenv("GIT_BUILD_HASH") +} + +func UserAgent() string { + return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD()) +} From bdf9f26d07b8eb79f05925364aae717b93e61d7a Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 19:05:29 +0200 Subject: [PATCH 11/13] outposts: compare build hash in outdated check Signed-off-by: Jens Langhammer --- authentik/outposts/channels.py | 1 + authentik/outposts/models.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/authentik/outposts/channels.py b/authentik/outposts/channels.py index 918b79881..f084b4a3d 100644 --- a/authentik/outposts/channels.py +++ b/authentik/outposts/channels.py @@ -82,6 +82,7 @@ class OutpostConsumer(AuthJsonConsumer): ) if msg.instruction == WebsocketMessageInstruction.HELLO: state.version = msg.args.get("version", None) + state.build_hash = msg.args.get("buildHash", "") elif msg.instruction == WebsocketMessageInstruction.ACK: return state.save(timeout=OUTPOST_HELLO_INTERVAL * 1.5) diff --git a/authentik/outposts/models.py b/authentik/outposts/models.py index ed21eca3d..c7de05794 100644 --- a/authentik/outposts/models.py +++ b/authentik/outposts/models.py @@ -1,6 +1,7 @@ """Outpost models""" from dataclasses import asdict, dataclass, field from datetime import datetime +from os import environ from typing import Iterable, Optional, Union from uuid import uuid4 @@ -26,7 +27,7 @@ from packaging.version import LegacyVersion, Version, parse from structlog.stdlib import get_logger from urllib3.exceptions import HTTPError -from authentik import __version__ +from authentik import ENV_GIT_HASH_KEY, __version__ from authentik.core.models import USER_ATTRIBUTE_SA, Provider, Token, TokenIntents, User from authentik.crypto.models import CertificateKeyPair from authentik.lib.config import CONFIG @@ -411,6 +412,7 @@ class OutpostState: last_seen: Optional[datetime] = field(default=None) version: Optional[str] = field(default=None) version_should: Union[Version, LegacyVersion] = field(default=OUR_VERSION) + build_hash: str = field(default="") _outpost: Optional[Outpost] = field(default=None) @@ -419,6 +421,8 @@ class OutpostState: """Check if outpost version matches our version""" if not self.version: return False + if self.build_hash != environ.get(ENV_GIT_HASH_KEY, ""): + return False return parse(self.version) < OUR_VERSION @staticmethod From a3fccbdaff257c26f410b5fd0e53ffa3d787ed93 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 20:36:18 +0200 Subject: [PATCH 12/13] outposts: add build_hash for docker image Signed-off-by: Jens Langhammer --- authentik/lib/default.yml | 1 + authentik/outposts/controllers/base.py | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/authentik/lib/default.yml b/authentik/lib/default.yml index 6f4aa46e8..24d3fcf2c 100644 --- a/authentik/lib/default.yml +++ b/authentik/lib/default.yml @@ -42,6 +42,7 @@ outposts: # Placeholders: # %(type)s: Outpost type; proxy, ldap, etc # %(version)s: Current version; 2021.4.1 + # %(build_hash)s: Build hash if you're running a beta version docker_image_base: "beryju/authentik-%(type)s:%(version)s" authentik: diff --git a/authentik/outposts/controllers/base.py b/authentik/outposts/controllers/base.py index ef22b79d5..fe342cb0f 100644 --- a/authentik/outposts/controllers/base.py +++ b/authentik/outposts/controllers/base.py @@ -1,11 +1,12 @@ """Base Controller""" from dataclasses import dataclass +from os import environ from typing import Optional from structlog.stdlib import get_logger from structlog.testing import capture_logs -from authentik import __version__ +from authentik import ENV_GIT_HASH_KEY, __version__ from authentik.lib.config import CONFIG from authentik.lib.sentry import SentryIgnoredException from authentik.outposts.models import Outpost, OutpostServiceConnection @@ -69,4 +70,8 @@ class BaseController: def get_container_image(self) -> str: """Get container image to use for this outpost""" image_name_template: str = CONFIG.y("outposts.docker_image_base") - return image_name_template % {"type": self.outpost.type, "version": __version__} + return image_name_template % { + "type": self.outpost.type, + "version": __version__, + "build_hash": environ.get(ENV_GIT_HASH_KEY, ""), + } From dc942b2f4c9269ddda02216388707b92588636eb Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 12 May 2021 20:37:55 +0200 Subject: [PATCH 13/13] outposts: build as gh- Signed-off-by: Jens Langhammer --- outpost/azure-pipelines.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/outpost/azure-pipelines.yml b/outpost/azure-pipelines.yml index a17cdf95f..0417353bd 100644 --- a/outpost/azure-pipelines.yml +++ b/outpost/azure-pipelines.yml @@ -116,7 +116,9 @@ stages: command: 'buildAndPush' Dockerfile: 'outpost/proxy.Dockerfile' buildContext: 'outpost/' - tags: "gh-$(branchName)" + tags: | + gh-$(branchName) + gh-$(Build.SourceVersion) arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)' - job: ldap_build_docker pool: @@ -142,5 +144,7 @@ stages: command: 'buildAndPush' Dockerfile: 'outpost/ldap.Dockerfile' buildContext: 'outpost/' - tags: "gh-$(branchName)" + tags: | + gh-$(branchName) + gh-$(Build.SourceVersion) arguments: '--build-arg GIT_BUILD_HASH=$(Build.SourceVersion)'