Compare commits

..

2 Commits

Author SHA1 Message Date
d8607ab324 core: remove session migration
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-05-19 13:27:02 +02:00
3748781368 sources/kerberos: resolve logger warnings (#14540)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-05-18 01:31:41 +02:00
22 changed files with 105 additions and 329 deletions

View File

@ -1,126 +1,9 @@
# Generated by Django 5.0.11 on 2025-01-27 12:58
import uuid
import pickle # nosec
from django.core import signing
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY, SESSION_KEY
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
from django.contrib.sessions.backends.cache import KEY_PREFIX
from django.utils.timezone import now, timedelta
from authentik.lib.migrations import progress_bar
from authentik.root.middleware import ClientIPMiddleware
SESSION_CACHE_ALIAS = "default"
class PickleSerializer:
"""
Simple wrapper around pickle to be used in signing.dumps()/loads() and
cache backends.
"""
def __init__(self, protocol=None):
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
def dumps(self, obj):
"""Pickle data to be stored in redis"""
return pickle.dumps(obj, self.protocol)
def loads(self, data):
"""Unpickle data to be loaded from redis"""
try:
return pickle.loads(data) # nosec
except Exception:
return {}
def _migrate_session(
apps,
db_alias,
session_key,
session_data,
expires,
):
Session = apps.get_model("authentik_core", "Session")
OldAuthenticatedSession = apps.get_model("authentik_core", "OldAuthenticatedSession")
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
old_auth_session = (
OldAuthenticatedSession.objects.using(db_alias).filter(session_key=session_key).first()
)
args = {
"session_key": session_key,
"expires": expires,
"last_ip": ClientIPMiddleware.default_ip,
"last_user_agent": "",
"session_data": {},
}
for k, v in session_data.items():
if k == "authentik/stages/user_login/last_ip":
args["last_ip"] = v
elif k in ["last_user_agent", "last_used"]:
args[k] = v
elif args in [SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY]:
pass
else:
args["session_data"][k] = v
if old_auth_session:
args["last_user_agent"] = old_auth_session.last_user_agent
args["last_used"] = old_auth_session.last_used
args["session_data"] = pickle.dumps(args["session_data"])
session = Session.objects.using(db_alias).create(**args)
if old_auth_session:
AuthenticatedSession.objects.using(db_alias).create(
session=session,
user=old_auth_session.user,
)
def migrate_redis_sessions(apps, schema_editor):
from django.core.cache import caches
db_alias = schema_editor.connection.alias
cache = caches[SESSION_CACHE_ALIAS]
# Not a redis cache, skipping
if not hasattr(cache, "keys"):
return
print("\nMigrating Redis sessions to database, this might take a couple of minutes...")
for key, session_data in progress_bar(cache.get_many(cache.keys(f"{KEY_PREFIX}*")).items()):
_migrate_session(
apps=apps,
db_alias=db_alias,
session_key=key.removeprefix(KEY_PREFIX),
session_data=session_data,
expires=now() + timedelta(seconds=cache.ttl(key)),
)
def migrate_database_sessions(apps, schema_editor):
DjangoSession = apps.get_model("sessions", "Session")
db_alias = schema_editor.connection.alias
print("\nMigration database sessions, this might take a couple of minutes...")
for django_session in progress_bar(DjangoSession.objects.using(db_alias).all()):
session_data = signing.loads(
django_session.session_data,
salt="django.contrib.sessions.SessionStore",
serializer=PickleSerializer,
)
_migrate_session(
apps=apps,
db_alias=db_alias,
session_key=django_session.session_key,
session_data=session_data,
expires=django_session.expire_date,
)
class Migration(migrations.Migration):
@ -230,12 +113,4 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Authenticated Sessions",
},
),
migrations.RunPython(
code=migrate_redis_sessions,
reverse_code=migrations.RunPython.noop,
),
migrations.RunPython(
code=migrate_database_sessions,
reverse_code=migrations.RunPython.noop,
),
]

View File

@ -317,7 +317,7 @@ class KerberosSource(Source):
usage="accept", name=name, store=self.get_gssapi_store()
)
except gssapi.exceptions.GSSError as exc:
LOGGER.warn("GSSAPI credentials failure", exc=exc)
LOGGER.warning("GSSAPI credentials failure", exc=exc)
return None

View File

@ -3,11 +3,13 @@
* @import { StorybookConfig } from "@storybook/web-components-vite";
* @import { InlineConfig, Plugin } from "vite";
*/
import { createBundleDefinitions } from "@goauthentik/web/scripts/esbuild/environment";
import { cwd } from "process";
import postcssLit from "rollup-plugin-postcss-lit";
import tsconfigPaths from "vite-tsconfig-paths";
const CSSImportPattern = /import [\w$]+ from .+\.(css)/g;
const NODE_ENV = process.env.NODE_ENV || "development";
const CSSImportPattern = /import [\w\$]+ from .+\.(css)/g;
const JavaScriptFilePattern = /\.m?(js|ts|tsx)$/;
/**
@ -52,7 +54,11 @@ const config = {
*/
const mergedConfig = {
...config,
define: createBundleDefinitions(),
define: {
"process.env.NODE_ENV": JSON.stringify(NODE_ENV),
"process.env.CWD": JSON.stringify(cwd()),
"process.env.AK_API_BASE_PATH": JSON.stringify(process.env.AK_API_BASE_PATH || ""),
},
plugins: [inlineCSSPlugin, ...plugins, postcssLit(), tsconfigPaths()],
};

View File

@ -21,7 +21,7 @@ const log = console.debug.bind(console, logPrefix);
* ESBuild may tree-shake it out of production builds.
*
* ```ts
* if (import.meta.env.NODE_ENV=== "development") {
* if (process.env.NODE_ENV === "development") {
* await import("@goauthentik/esbuild-plugin-live-reload/client")
* .catch(() => console.warn("Failed to import watcher"))
* }

View File

@ -4,20 +4,15 @@
export {};
declare global {
/**
* Environment variables injected by ESBuild.
*/
interface ImportMetaEnv {
/**
* The injected watcher URL for ESBuild.
* This is used for live reloading in development mode.
*
* @format url
*/
readonly ESBUILD_WATCHER_URL?: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
readonly env: {
/**
* The injected watcher URL for ESBuild.
* This is used for live reloading in development mode.
*
* @format url
*/
ESBUILD_WATCHER_URL: string;
};
}
}

View File

@ -1,20 +1,6 @@
/**
* @file Utility functions for working with environment variables.
* @file Utility functions for building and copying files.
*/
/// <reference types="./types/global.js" />
//#region Constants
/**
* The current Node.js environment, defaulting to "development" when not set.
*
* Note, this should only be used during the build process.
*
* If you need to check the environment at runtime, use `process.env.NODE_ENV` to
* ensure that module tree-shaking works correctly.
*
*/
export const NodeEnvironment = process.env.NODE_ENV || "development";
/**
* A source environment variable, which can be a string, number, boolean, null, or undefined.
@ -28,26 +14,19 @@ export const NodeEnvironment = process.env.NODE_ENV || "development";
* @typedef {T extends string ? `"${T}"` : T} JSONify
*/
//#endregion
//#region Utilities
/**
* Given an object of environment variables, returns a new object with the same keys and values, but
* with the values serialized as strings.
*
* @template {Record<string, EnvironmentVariable>} EnvRecord
* @template {string} [Prefix='import.meta.env.']
* @template {string} [Prefix='process.env.']
*
* @param {EnvRecord} input
* @param {Prefix} [prefix='import.meta.env.']
* @param {Prefix} [prefix='process.env.']
*
* @returns {{[K in keyof EnvRecord as `${Prefix}${K}`]: JSONify<EnvRecord[K]>}}
*/
export function serializeEnvironmentVars(
input,
prefix = /** @type {Prefix} */ ("import.meta.env."),
) {
export function serializeEnvironmentVars(input, prefix = /** @type {Prefix} */ ("process.env.")) {
/**
* @type {Record<string, string>}
*/
@ -61,5 +40,3 @@ export function serializeEnvironmentVars(
return /** @type {any} */ (env);
}
//#endregion

View File

@ -0,0 +1,16 @@
/**
* @file Constants for JavaScript and TypeScript files.
*/
/// <reference types="../../types/global.js" />
/**
* The current Node.js environment, defaulting to "development" when not set.
*
* Note, this should only be used during the build process.
*
* If you need to check the environment at runtime, use `process.env.NODE_ENV` to
* ensure that module tree-shaking works correctly.
*
*/
export const NodeEnvironment = process.env.NODE_ENV || "development";

View File

@ -1,6 +1,7 @@
/// <reference types="./types/global.js" />
export * from "./paths.js";
export * from "./environment.js";
export * from "./constants.js";
export * from "./build.js";
export * from "./version.js";
export * from "./scripting.js";

View File

@ -1,32 +1,17 @@
import { spawnSync } from "child_process";
import fs from "fs";
import path from "path";
import process from "process";
/**
* @file Lit Localize build script.
*
* @remarks
* Determines if all the Xliff translation source files are present and if the Typescript source files generated from those sources are up-to-date.
*
* If they are not, it runs the locale building script,
* intercepting the long spew of "this string is not translated" and replacing it with a
* Determines if all the Xliff translation source files are present and if the Typescript source
* files generated from those sources are up-to-date. If they are not, it runs the locale building
* script, intercepting the long spew of "this string is not translated" and replacing it with a
* summary of how many strings are missing with respect to the source locale.
*
* @import { ConfigFile } from "@lit/localize-tools/lib/types/config"
*/
import { PackageRoot } from "@goauthentik/web/paths";
import { spawnSync } from "node:child_process";
import { readFileSync, statSync } from "node:fs";
import path from "node:path";
/**
* @type {ConfigFile}
*/
const localizeRules = JSON.parse(
readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8"),
);
const localizeRules = JSON.parse(fs.readFileSync("./lit-localize.json", "utf-8"));
/**
*
* @param {string} loc
* @returns {boolean}
*/
function generatedFileIsUpToDateWithXliffSource(loc) {
const xliff = path.join("./xliff", `${loc}.xlf`);
const gened = path.join("./src/locales", `${loc}.ts`);
@ -37,7 +22,7 @@ function generatedFileIsUpToDateWithXliffSource(loc) {
// generates a unique error message and halts the build.
try {
var xlfStat = statSync(xliff);
var xlfStat = fs.statSync(xliff);
} catch (_error) {
console.error(`lit-localize expected '${loc}.xlf', but XLF file is not present`);
process.exit(1);
@ -45,7 +30,7 @@ function generatedFileIsUpToDateWithXliffSource(loc) {
// If the generated file doesn't exist, of course it's not up to date.
try {
var genedStat = statSync(gened);
var genedStat = fs.statSync(gened);
} catch (_error) {
return false;
}

View File

@ -1,4 +1,3 @@
/// <reference types="../types/esbuild.js" />
/**
* @file ESBuild script for building the authentik web UI.
*
@ -10,6 +9,7 @@ import {
NodeEnvironment,
readBuildIdentifier,
resolvePackage,
serializeEnvironmentVars,
} from "@goauthentik/monorepo";
import { DistDirectory, DistDirectoryName, EntryPoint, PackageRoot } from "@goauthentik/web/paths";
import { deepmerge } from "deepmerge-ts";
@ -20,10 +20,15 @@ import * as fs from "node:fs/promises";
import * as path from "node:path";
import { mdxPlugin } from "./esbuild/build-mdx-plugin.mjs";
import { createBundleDefinitions } from "./esbuild/environment.mjs";
const logPrefix = "[Build]";
const definitions = serializeEnvironmentVars({
NODE_ENV: NodeEnvironment,
CWD: process.cwd(),
AK_API_BASE_PATH: process.env.AK_API_BASE_PATH,
});
const patternflyPath = resolvePackage("@patternfly/patternfly");
/**
@ -81,7 +86,7 @@ const BASE_ESBUILD_OPTIONS = {
root: MonoRepoRoot,
}),
],
define: createBundleDefinitions(),
define: definitions,
format: "esm",
logOverride: {
/**

View File

@ -1,29 +0,0 @@
/**
* @file ESBuild environment utilities.
*/
import { AuthentikVersion, NodeEnvironment, serializeEnvironmentVars } from "@goauthentik/monorepo";
/**
* Creates a mapping of environment variables to their respective runtime constants.
*/
export function createBundleDefinitions() {
const SerializedNodeEnvironment = /** @type {`"development"` | `"production"`} */ (
JSON.stringify(NodeEnvironment)
);
/**
* @satisfies {Record<ESBuildImportEnvKey, string>}
*/
const envRecord = {
AK_VERSION: AuthentikVersion,
AK_API_BASE_PATH: process.env.AK_API_BASE_PATH ?? "",
};
return {
...serializeEnvironmentVars(envRecord),
// We need to explicitly set this for NPM packages that use `process`
// to determine their environment.
"process.env.NODE_ENV": SerializedNodeEnvironment,
"import.meta.env.NODE_ENV": SerializedNodeEnvironment,
};
}

View File

@ -35,11 +35,6 @@ const __dirname = fileURLToPath(new URL(".", import.meta.url));
const projectRoot = path.join(__dirname, "..");
process.chdir(projectRoot);
/**
*
* @param {string[]} flags
* @returns
*/
const hasFlag = (flags) => process.argv.length > 1 && flags.includes(process.argv[2]);
const [configFile, files] = hasFlag(["-n", "--nightmare"])

View File

@ -1,36 +1,22 @@
/**
* @file Pseudo-localization script.
*
* @import { ConfigFile } from "@lit/localize-tools/lib/types/config.js"
* @import { Config } from '@lit/localize-tools/lib/types/config.js';
* @import { ProgramMessage } from "@lit/localize-tools/src/messages.js"
* @import { Locale } from "@lit/localize-tools/src/types/locale.js"
*/
import { PackageRoot } from "@goauthentik/web/paths";
import { readFileSync } from "node:fs";
import path from "node:path";
import { readFileSync } from "fs";
import path from "path";
import pseudolocale from "pseudolocale";
import { fileURLToPath } from "url";
import { makeFormatter } from "@lit/localize-tools/lib/formatters/index.js";
import { sortProgramMessages } from "@lit/localize-tools/lib/messages.js";
import { TransformLitLocalizer } from "@lit/localize-tools/lib/modes/transform.js";
const pseudoLocale = /** @type {Locale} */ ("pseudo-LOCALE");
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const pseudoLocale = "pseudo-LOCALE";
const targetLocales = [pseudoLocale];
/**
* @type {ConfigFile}
*/
const baseConfig = JSON.parse(readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8"));
const baseConfig = JSON.parse(readFileSync(path.join(__dirname, "../lit-localize.json"), "utf-8"));
// Need to make some internal specifications to satisfy the transformer. It doesn't actually matter
// which Localizer we use (transformer or runtime), because all of the functionality we care about
// is in their common parent class, but I had to pick one. Everything else here is just pure
// exploitation of the lit/localize-tools internals.
/**
* @satisfies {Config}
*/
const config = {
...baseConfig,
baseDir: path.join(__dirname, ".."),
@ -42,11 +28,6 @@ const config = {
resolve: (path) => path,
};
/**
*
* @param {ProgramMessage} message
* @returns
*/
const pseudoMessagify = (message) => ({
name: message.name,
contents: message.contents.map((content) =>
@ -55,7 +36,7 @@ const pseudoMessagify = (message) => ({
});
const localizer = new TransformLitLocalizer(config);
const { messages } = localizer.extractSourceMessages();
const messages = localizer.extractSourceMessages().messages;
const translations = messages.map(pseudoMessagify);
const sorted = sortProgramMessages([...messages]);
const formatter = makeFormatter(config);

View File

@ -43,7 +43,7 @@ import {
renderSidebarItems,
} from "./AdminSidebar.js";
if (import.meta.env.NODE_ENV === "development") {
if (process.env.NODE_ENV === "development") {
await import("@goauthentik/esbuild-plugin-live-reload/client");
}

View File

@ -223,7 +223,7 @@ export function inspectStyleSheetTree(element: ReactiveElement): InspectedStyleS
};
}
if (import.meta.env.NODE_ENV === "development") {
if (process.env.NODE_ENV === "development") {
Object.assign(window, {
inspectStyleSheetTree,
serializeStyleSheet,

View File

@ -5,11 +5,11 @@ import {
type StyleRoot,
createStyleSheetUnsafe,
setAdoptedStyleSheets,
} from "@goauthentik/web/common/stylesheets.js";
import { UIConfig } from "@goauthentik/web/common/ui/config.js";
} from "@goauthentik/common/stylesheets.js";
import { UIConfig } from "@goauthentik/common/ui/config.js";
import AKBase from "@goauthentik/web/common/styles/authentik.css";
import AKBaseDark from "@goauthentik/web/common/styles/theme-dark.css";
import AKBase from "@goauthentik/common/styles/authentik.css";
import AKBaseDark from "@goauthentik/common/styles/theme-dark.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { Config, CurrentBrand, UiThemeEnum } from "@goauthentik/api";

View File

@ -14,6 +14,6 @@ import "@goauthentik/flow/stages/password/PasswordStage";
// end of stage import
if (import.meta.env.NODE_ENV === "development") {
if (process.env.NODE_ENV === "development") {
await import("@goauthentik/esbuild-plugin-live-reload/client");
}

View File

@ -43,7 +43,7 @@ import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
import { CurrentBrand, EventsApi, SessionUser } from "@goauthentik/api";
if (import.meta.env.NODE_ENV === "development") {
if (process.env.NODE_ENV === "development") {
await import("@goauthentik/esbuild-plugin-live-reload/client");
}

View File

@ -2,9 +2,6 @@
{
"extends": "@goauthentik/tsconfig",
"compilerOptions": {
"checkJs": true,
"allowJs": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"emitDeclarationOnly": true,
"experimentalDecorators": true,

View File

@ -1,39 +0,0 @@
/**
* @file Import meta environment variables available via ESBuild.
*/
export {};
declare global {
interface ESBuildImportEnv {
/**
* The authentik version injected by ESBuild during build time.
*
* @format semver
*/
readonly AK_VERSION: string;
/**
* @todo Determine where this is used and if it is needed,
* give it a better name.
* @deprecated
*/
readonly AK_API_BASE_PATH: string;
}
type ESBuildImportEnvKey = keyof ESBuildImportEnv;
/**
* Environment variables injected by ESBuild.
*/
interface ImportMetaEnv extends ESBuildImportEnv {
/**
* An environment variable used to determine
* whether Node.js is running in production mode.
*/
readonly NODE_ENV: "development" | "production";
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
}

View File

@ -1,5 +1,5 @@
/**
* @file Global variables provided by Node.js
* @file Environment variables available via ESBuild.
*/
declare module "module" {
@ -14,8 +14,8 @@ declare module "module" {
* const relativeDirname = dirname(fileURLToPath(import.meta.url));
* ```
*/
const __dirname: string;
// eslint-disable-next-line no-var
var __dirname: string;
}
}
@ -23,16 +23,13 @@ declare module "process" {
global {
namespace NodeJS {
interface ProcessEnv {
/**
* Node environment, if any.
*/
readonly NODE_ENV?: "development" | "production";
CWD: string;
/**
* @todo Determine where this is used and if it is needed,
* give it a better name.
* @deprecated
*/
readonly AK_API_BASE_PATH?: string;
AK_API_BASE_PATH: string;
}
}
}

View File

@ -1,15 +1,17 @@
/// <reference types="@wdio/browser-runner" />
import replace from "@rollup/plugin-replace";
import { browser } from "@wdio/globals";
import type { Options } from "@wdio/types";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { createBundleDefinitions } from "scripts/esbuild/environment.mjs";
import type { InlineConfig } from "vite";
import litCSS from "vite-plugin-lit-css";
import path from "path";
import { cwd } from "process";
import { fileURLToPath } from "url";
import type { UserConfig } from "vite";
import litCss from "vite-plugin-lit-css";
import tsconfigPaths from "vite-tsconfig-paths";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const isProdBuild = process.env.NODE_ENV === "production";
const apiBasePath = process.env.AK_API_BASE_PATH || "";
const runHeadless = process.env.CI !== undefined;
const testSafari = process.env.WDIO_TEST_SAFARI !== undefined;
@ -70,9 +72,21 @@ export const config: Options.Testrunner = {
runner: [
"browser",
{
viteConfig: {
define: createBundleDefinitions(),
plugins: [litCSS(), tsconfigPaths()],
viteConfig: (userConfig: UserConfig = { plugins: [] }) => ({
...userConfig,
plugins: [
litCss(),
replace({
"process.env.NODE_ENV": JSON.stringify(
isProdBuild ? "production" : "development",
),
"process.env.CWD": JSON.stringify(cwd()),
"process.env.AK_API_BASE_PATH": JSON.stringify(apiBasePath),
"preventAssignment": true,
}),
...(userConfig?.plugins ?? []),
tsconfigPaths(),
],
resolve: {
alias: {
"@goauthentik/admin": path.resolve(__dirname, "src/admin"),
@ -87,7 +101,7 @@ export const config: Options.Testrunner = {
"@goauthentik/user": path.resolve(__dirname, "src/user"),
},
},
} satisfies InlineConfig,
}),
},
],