QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow f1d46718955078331817c6206b822a94bc7d769f] (pull_request) Successful in 9s
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 9s
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
Shared Java Maven CI with Docker / secrets (push) Successful in 38s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / secrets (pull_request) Successful in 38s
qbit release candidate / cut-rc (pull_request) Failing after 18s
Release candidate / release-rc (pull_request) Failing after 18s
qbit release candidate / tag-and-release (pull_request) Skipped
QRun-IO/ci-policy: Shared Java Maven CI with Docker / verify (pull_request) Failing after 15m39s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / gate (pull_request) Failing after 24s
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Failing after 1h14m34s
QRun-IO/ci-policy: ci / ci-result (pull_request) Failing after 10s
Shared Java Maven CI with Docker / verify (push) Failing after 17m19s
Shared Java Maven CI with Docker / gate (push) Failing after 24s
qrun-release / release (push) Failing after 1h16m30s
qrun-release / postpublish (push) Skipped
Add user and group QQQ application-role access editing, bounded catalogs, webhook inbox and SQL mirrors, refreshed session permissions, and deferred invitation assignments. Include the isolated local review host, browser acceptance scripts, documentation and the token-widget column mapping fix. User approved this RC checkpoint. Full 1.0 gates remain documented, including the schema-drift matcher and PostgreSQL integration errors from the full gate. Companion UI: QRun-IO/qqq-frontend-next#205. Co-Authored-By: GPT-6 <noreply@openai.com>
2043 lines
72 KiB
Java
2043 lines
72 KiB
Java
/*
|
|
* Copyright 2026 Kingsrook, LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.kingsrook.qbits.authentik;
|
|
|
|
|
|
import java.net.URI;
|
|
import java.util.ArrayList;
|
|
import java.util.EnumSet;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.regex.Pattern;
|
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
import com.kingsrook.qbits.authentik.policy.PolicyFormat;
|
|
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
|
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitConfig;
|
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
|
|
|
|
|
/*******************************************************************************
|
|
** Host-facing configuration of the Authentik QBit (DESIGN.md section 3.2).
|
|
**
|
|
** Secrets (apiToken, webhookSecret) may be given as ${env.NAME} references;
|
|
** the qbit resolves them itself (APIBackendMetaData.enrich() is disabled in
|
|
** QQQ), never serializes them, and redacts them in toString().
|
|
**
|
|
** validate() is list-based and never throws; the producer fails production
|
|
** with all collected errors.
|
|
*******************************************************************************/
|
|
public class AuthentikQBitConfig implements QBitConfig
|
|
{
|
|
/** Features implemented in this release. Others are refused by validate(). */
|
|
public static final Set<AuthentikFeature> AVAILABLE_FEATURES = EnumSet.of(AuthentikFeature.READ, AuthentikFeature.USERS, AuthentikFeature.GROUPS, AuthentikFeature.MEMBERSHIP,
|
|
AuthentikFeature.CREDENTIALS, AuthentikFeature.SESSIONS, AuthentikFeature.POLICIES, AuthentikFeature.DELETE, AuthentikFeature.TOKENS,
|
|
AuthentikFeature.MIRROR, AuthentikFeature.WEBHOOK);
|
|
|
|
/** Features that change Authentik data; they need a local backend for the audit trail. */
|
|
public static final Set<AuthentikFeature> WRITE_FEATURES = EnumSet.of(AuthentikFeature.USERS, AuthentikFeature.GROUPS, AuthentikFeature.MEMBERSHIP,
|
|
AuthentikFeature.CREDENTIALS, AuthentikFeature.SESSIONS, AuthentikFeature.POLICIES, AuthentikFeature.DELETE, AuthentikFeature.TOKENS);
|
|
|
|
private static final Pattern APP_KEY_PATTERN = Pattern.compile("[a-z0-9][a-z0-9-]{0,48}[a-z0-9]");
|
|
private static final Pattern PREFIX_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9]{0,30}");
|
|
|
|
private Boolean tokensEnabled = null;
|
|
private Integer tokenMaxDaysUser = 90;
|
|
private Integer tokenMaxDaysServiceAccount = 365;
|
|
private List<String> tokenProtectedGroups = new ArrayList<>(List.of("authentik Admins", "identity-admins"));
|
|
private Boolean tokenTwoPersonApproval = false;
|
|
private Boolean tokenScopesEnabled = false;
|
|
private String tokenScopeClaim = "qqq_token";
|
|
private String tokenReminderSchedulerName;
|
|
private String tokenBrokerClientId = "${env.AUTHENTIK_TOKEN_BROKER_CLIENT_ID}";
|
|
private String tokenBrokerClientSecret = "${env.AUTHENTIK_TOKEN_BROKER_CLIENT_SECRET}";
|
|
private String tokenEndpointUrl = null;
|
|
private String maintenancePrincipal = "maintenance";
|
|
private String appPublicUrl = null;
|
|
private String authentikPublicUrl = null;
|
|
private String appClientId = null;
|
|
private Integer tokenUnusedDays = 60;
|
|
private String serviceAccountTokenLifetime = "days=365";
|
|
private com.kingsrook.qbits.authentik.client.AuthentikSubjectTokenSource subjectTokenSource = new com.kingsrook.qbits.authentik.client.OAuth2SubjectTokenSource();
|
|
|
|
private String baseUrl;
|
|
private String apiToken;
|
|
private String appKey;
|
|
private String tableNamePrefix = "authentik";
|
|
private Set<AuthentikFeature> features = EnumSet.of(AuthentikFeature.READ);
|
|
private Boolean readOnly = false;
|
|
private String serviceAccountUsername;
|
|
private String userScopePathStartsWith;
|
|
private List<String> userScopeGroupNames = new ArrayList<>();
|
|
private String groupScopeNamePrefix;
|
|
private List<String> protectedUsernames = new ArrayList<>();
|
|
private String bootstrapOperatorSubjects = "${env.AUTHENTIK_QBIT_BOOTSTRAP_SUBJECTS}";
|
|
private List<String> applicationsInScope = new ArrayList<>();
|
|
private String localBackendName;
|
|
private Boolean twoPersonApproval = true;
|
|
private String schedulerName;
|
|
private String esbDestinationName;
|
|
private String linkPrefix = "/app";
|
|
private String recoveryEmailStage;
|
|
private String invitationFlow;
|
|
private String newUserPath = "users";
|
|
private String webhookSecret = "${env.AUTHENTIK_WEBHOOK_SECRET}";
|
|
private Integer throttleRequestsPerSecond = 10;
|
|
private Integer throttleBurst = 20;
|
|
private Integer bulkPacingMillis = 100;
|
|
private Integer listCacheTtlSeconds = 30;
|
|
private Integer groupCacheTtlSeconds = 60;
|
|
private Integer connectTimeoutMillis = 5_000;
|
|
private Integer socketTimeoutMillis = 30_000;
|
|
private String expectedServerVersion = "2026.8";
|
|
private Boolean allowInsecureHttp = false;
|
|
private String policySpec = PolicyFormat.DEFAULT_SPEC;
|
|
private String policyVersion = PolicyFormat.DEFAULT_VERSION;
|
|
private String policyAttribute = PolicyFormat.DEFAULT_ATTRIBUTE;
|
|
private String policyClaim = PolicyFormat.DEFAULT_CLAIM;
|
|
private Boolean policyTwoPersonApproval = false;
|
|
private Boolean mapperEnabled = false;
|
|
private Boolean mapperOverride = false;
|
|
private List<String> cutoverGuardGroups = new ArrayList<>();
|
|
private java.util.Map<String, List<String>> staticGroupPermissions = new java.util.LinkedHashMap<>();
|
|
@JsonIgnore
|
|
private com.kingsrook.qbits.authentik.permissions.AuthentikHostPermissionSource hostPermissionSource;
|
|
private java.util.function.Function<QInstance, java.util.Collection<String>> fullAccessHostPermissions;
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Collect configuration errors. Never throws; null-safe for a partially
|
|
** built QInstance.
|
|
*******************************************************************************/
|
|
@Override
|
|
public void validate(QInstance qInstance, List<String> errors)
|
|
{
|
|
if(tokenMaxDaysUser == null || tokenMaxDaysUser < 1)
|
|
{
|
|
errors.add("tokenMaxDaysUser must be at least 1");
|
|
}
|
|
if(tokenMaxDaysServiceAccount == null || tokenMaxDaysServiceAccount < 1)
|
|
{
|
|
errors.add("tokenMaxDaysServiceAccount must be at least 1");
|
|
}
|
|
if(tokenScopeClaim == null || tokenScopeClaim.isBlank())
|
|
{
|
|
errors.add("tokenScopeClaim must not be blank");
|
|
}
|
|
if(tokenUnusedDays == null || tokenUnusedDays < 1)
|
|
{
|
|
errors.add("tokenUnusedDays must be at least 1");
|
|
}
|
|
|
|
if(!StringUtils.hasContent(baseUrl))
|
|
{
|
|
errors.add("baseUrl is required (the Authentik host root, e.g. https://auth.example.com)");
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
URI uri = URI.create(baseUrl);
|
|
if(uri.getScheme() == null || !(uri.getScheme().equals("https") || uri.getScheme().equals("http")) || uri.getHost() == null)
|
|
{
|
|
errors.add("baseUrl must be an absolute http(s) URL: " + baseUrl);
|
|
}
|
|
else if(uri.getScheme().equals("http") && !Boolean.TRUE.equals(allowInsecureHttp) && !isLoopback(uri.getHost()))
|
|
{
|
|
errors.add("baseUrl must use https (the API token would travel in cleartext); http is allowed only for localhost or with allowInsecureHttp: " + baseUrl);
|
|
}
|
|
else if(uri.getPath() != null && uri.getPath().contains("/api/v3"))
|
|
{
|
|
errors.add("baseUrl must be the host root; /api/v3 is appended by the qbit: " + baseUrl);
|
|
}
|
|
}
|
|
catch(IllegalArgumentException e)
|
|
{
|
|
errors.add("baseUrl is not a valid URL: " + baseUrl);
|
|
}
|
|
}
|
|
|
|
if(!StringUtils.hasContent(getResolvedApiToken()))
|
|
{
|
|
errors.add("apiToken is required (usually ${env.AUTHENTIK_API_TOKEN}) and resolved to an empty value");
|
|
}
|
|
|
|
if(!StringUtils.hasContent(appKey) || !APP_KEY_PATTERN.matcher(appKey).matches())
|
|
{
|
|
errors.add("appKey is required: lower-case letters, digits and dashes, e.g. my-app-admin");
|
|
}
|
|
|
|
if(tableNamePrefix != null && !tableNamePrefix.isEmpty() && !PREFIX_PATTERN.matcher(tableNamePrefix).matches())
|
|
{
|
|
errors.add("tableNamePrefix must start with a letter and contain only letters and digits: " + tableNamePrefix);
|
|
}
|
|
|
|
if(StringUtils.hasContent(groupScopeNamePrefix))
|
|
{
|
|
errors.add("groupScopeNamePrefix is not available in this release of qbit-authentik");
|
|
}
|
|
|
|
Set<AuthentikFeature> requested = features == null ? EnumSet.noneOf(AuthentikFeature.class) : features;
|
|
if(!requested.contains(AuthentikFeature.READ))
|
|
{
|
|
errors.add("feature READ is required");
|
|
}
|
|
for(AuthentikFeature feature : requested)
|
|
{
|
|
if(!AVAILABLE_FEATURES.contains(feature))
|
|
{
|
|
errors.add("feature " + feature + " is not available in this release of qbit-authentik (available: " + AVAILABLE_FEATURES + ")");
|
|
}
|
|
}
|
|
|
|
boolean writes = requested.stream().anyMatch(WRITE_FEATURES::contains);
|
|
if(writes || StringUtils.hasContent(localBackendName))
|
|
{
|
|
if(!StringUtils.hasContent(localBackendName))
|
|
{
|
|
errors.add("features that change Authentik data need localBackendName (an RDBMS backend of the instance, for the audit trail)");
|
|
}
|
|
else if(qInstance != null && qInstance.getBackends() != null && qInstance.getBackend(localBackendName) == null)
|
|
{
|
|
errors.add("localBackendName: backend not found: " + localBackendName);
|
|
}
|
|
}
|
|
|
|
if((requested.contains(AuthentikFeature.USERS) || requested.contains(AuthentikFeature.CREDENTIALS)) && !StringUtils.hasContent(recoveryEmailStage))
|
|
{
|
|
errors.add("features USERS and CREDENTIALS need recoveryEmailStage");
|
|
}
|
|
|
|
if(requested.contains(AuthentikFeature.DELETE) && !requested.contains(AuthentikFeature.USERS) && !requested.contains(AuthentikFeature.GROUPS))
|
|
{
|
|
errors.add("feature DELETE needs USERS or GROUPS");
|
|
}
|
|
|
|
if(requested.contains(AuthentikFeature.POLICIES) && !requested.contains(AuthentikFeature.GROUPS))
|
|
{
|
|
errors.add("feature POLICIES needs GROUPS");
|
|
}
|
|
|
|
if(requested.contains(AuthentikFeature.WEBHOOK) && !StringUtils.hasContent(getResolvedWebhookSecret()))
|
|
{
|
|
errors.add("feature WEBHOOK needs webhookSecret");
|
|
}
|
|
|
|
if(requested.contains(AuthentikFeature.WEBHOOK) && !requested.contains(AuthentikFeature.MIRROR))
|
|
{
|
|
errors.add("feature WEBHOOK needs MIRROR");
|
|
}
|
|
if(requested.contains(AuthentikFeature.MIRROR))
|
|
{
|
|
try
|
|
{
|
|
com.kingsrook.qbits.authentik.sync.AuthentikSyncRegistration.validate(qInstance, this, errors);
|
|
}
|
|
catch(LinkageError missingDependency)
|
|
{
|
|
errors.add("MIRROR/WEBHOOK requires the host RDBMS and enabled middleware/ESB dependencies");
|
|
}
|
|
}
|
|
|
|
for(String subject : getResolvedBootstrapSubjects())
|
|
{
|
|
if(subject.contains("@"))
|
|
{
|
|
errors.add("bootstrapOperatorSubjects must be immutable ids (the token sub, or the Authentik user pk or uuid), never emails: users can change their own email");
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(Integer value : new Integer[] { throttleRequestsPerSecond, throttleBurst, listCacheTtlSeconds, groupCacheTtlSeconds, connectTimeoutMillis, socketTimeoutMillis })
|
|
{
|
|
if(value == null || value < 0)
|
|
{
|
|
errors.add("throttle, cache and timeout settings must be non-negative numbers");
|
|
break;
|
|
}
|
|
}
|
|
String policyProblem = getPolicyFormat().problem();
|
|
if(policyProblem != null)
|
|
{
|
|
errors.add(policyProblem);
|
|
}
|
|
|
|
if(throttleRequestsPerSecond != null && throttleRequestsPerSecond == 0)
|
|
{
|
|
errors.add("throttleRequestsPerSecond must be at least 1");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
**
|
|
*******************************************************************************/
|
|
private static boolean isLoopback(String host)
|
|
{
|
|
return ("localhost".equalsIgnoreCase(host) || "127.0.0.1".equals(host) || "[::1]".equals(host) || "::1".equals(host));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for allowInsecureHttp
|
|
*******************************************************************************/
|
|
public Boolean getAllowInsecureHttp()
|
|
{
|
|
return (this.allowInsecureHttp);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for allowInsecureHttp (plain http to a non-loopback host;
|
|
** for tests and private networks only)
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withAllowInsecureHttp(Boolean allowInsecureHttp)
|
|
{
|
|
this.allowInsecureHttp = allowInsecureHttp;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Prefix a non-table component name (app, widget, backend, process) with the
|
|
** tableNamePrefix (camel-cased join), e.g. "authentikAdmin". Table names use
|
|
** applyTablePrefix instead.
|
|
*******************************************************************************/
|
|
public String applyPrefix(String name)
|
|
{
|
|
if(!StringUtils.hasContent(tableNamePrefix))
|
|
{
|
|
return (name);
|
|
}
|
|
return (tableNamePrefix + Character.toUpperCase(name.charAt(0)) + name.substring(1));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Prefix a table name: lowercase snake_case, joined with "_", e.g. "user" ->
|
|
** "authentik_user", "groupMember" -> "authentik_group_member" (owner naming
|
|
** rule, 2026-10-12: table names are lowercase with "_", prefixed with the
|
|
** qbit's name).
|
|
*******************************************************************************/
|
|
public String applyTablePrefix(String name)
|
|
{
|
|
String snakeName = toSnakeCase(name);
|
|
if(!StringUtils.hasContent(tableNamePrefix))
|
|
{
|
|
return (snakeName);
|
|
}
|
|
return (toSnakeCase(tableNamePrefix) + "_" + snakeName);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** camelCase (or PascalCase) to lowercase snake_case: "groupMember" ->
|
|
** "group_member", "myAuth" -> "my_auth". Already-snake input is unchanged.
|
|
*******************************************************************************/
|
|
public static String toSnakeCase(String name)
|
|
{
|
|
if(name == null)
|
|
{
|
|
return (null);
|
|
}
|
|
|
|
StringBuilder rs = new StringBuilder(name.length() + 8);
|
|
for(int i = 0; i < name.length(); i++)
|
|
{
|
|
char c = name.charAt(i);
|
|
if(Character.isUpperCase(c))
|
|
{
|
|
boolean afterLowerOrDigit = i > 0 && (Character.isLowerCase(name.charAt(i - 1)) || Character.isDigit(name.charAt(i - 1)));
|
|
boolean endOfAcronym = i > 0 && i + 1 < name.length() && Character.isUpperCase(name.charAt(i - 1)) && Character.isLowerCase(name.charAt(i + 1));
|
|
if((afterLowerOrDigit || endOfAcronym) && rs.length() > 0 && rs.charAt(rs.length() - 1) != '_')
|
|
{
|
|
rs.append('_');
|
|
}
|
|
rs.append(Character.toLowerCase(c));
|
|
}
|
|
else
|
|
{
|
|
rs.append(c);
|
|
}
|
|
}
|
|
return (rs.toString());
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Name of the API backend the qbit produces.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getApiBackendName()
|
|
{
|
|
return (applyPrefix("api"));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** The API root: baseUrl without a trailing slash, plus /api/v3.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getApiRoot()
|
|
{
|
|
String root = baseUrl == null ? "" : baseUrl.trim();
|
|
while(root.endsWith("/"))
|
|
{
|
|
root = root.substring(0, root.length() - 1);
|
|
}
|
|
return (root + "/api/v3");
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** The service account's username: explicit, or qqq-{appKey}-idadmin.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getEffectiveServiceAccountUsername()
|
|
{
|
|
return (StringUtils.hasContent(serviceAccountUsername) ? serviceAccountUsername : "qqq-" + appKey + "-idadmin");
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** The API token with ${env.X} / ${prop.X} references resolved.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getResolvedApiToken()
|
|
{
|
|
return (resolve(apiToken));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** The webhook secret with references resolved.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getResolvedWebhookSecret()
|
|
{
|
|
return (resolve(webhookSecret));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Bootstrap operator subjects, resolved and split on commas. Each is an
|
|
** IMMUTABLE identifier (the token's sub, or the Authentik user pk or uuid);
|
|
** never an email, because users can change their own email.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public Set<String> getResolvedBootstrapSubjects()
|
|
{
|
|
Set<String> rs = new LinkedHashSet<>();
|
|
String resolved = resolve(bootstrapOperatorSubjects);
|
|
if(StringUtils.hasContent(resolved))
|
|
{
|
|
for(String part : resolved.split(","))
|
|
{
|
|
if(StringUtils.hasContent(part))
|
|
{
|
|
rs.add(part.trim());
|
|
}
|
|
}
|
|
}
|
|
return (rs);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** The features that are actually on: the configured set, plus TOKENS when it
|
|
** is on by default (writes enabled, not opted out), minus TOKENS when it is
|
|
** listed but off (read only or opted out). This is what hosts see in logs.
|
|
*******************************************************************************/
|
|
public java.util.Set<AuthentikFeature> getEffectiveFeatures()
|
|
{
|
|
java.util.EnumSet<AuthentikFeature> effective = java.util.EnumSet.noneOf(AuthentikFeature.class);
|
|
for(AuthentikFeature feature : AuthentikFeature.values())
|
|
{
|
|
if(hasFeature(feature))
|
|
{
|
|
effective.add(feature);
|
|
}
|
|
}
|
|
return (effective);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Whether a feature is enabled.
|
|
*******************************************************************************/
|
|
public boolean hasFeature(AuthentikFeature feature)
|
|
{
|
|
if(feature == AuthentikFeature.TOKENS)
|
|
{
|
|
return (!Boolean.TRUE.equals(readOnly) && Boolean.TRUE.equals(getTokensEnabled()) && features != null
|
|
&& features.stream().anyMatch(WRITE_FEATURES::contains));
|
|
}
|
|
return (features != null && features.contains(feature));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Resolve ${env.X} style references; a reference to an unset variable
|
|
** resolves to null rather than to its literal text.
|
|
*******************************************************************************/
|
|
static String resolve(String value)
|
|
{
|
|
if(value == null)
|
|
{
|
|
return (null);
|
|
}
|
|
String resolved = new QMetaDataVariableInterpreter().interpret(value);
|
|
if(resolved != null && resolved.startsWith("${") && resolved.endsWith("}"))
|
|
{
|
|
return (null);
|
|
}
|
|
return (resolved);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Never print secrets.
|
|
*******************************************************************************/
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return ("AuthentikQBitConfig{baseUrl=" + baseUrl + ", appKey=" + appKey + ", tableNamePrefix=" + tableNamePrefix
|
|
+ ", tokensEnabled=" + tokensEnabled
|
|
+ ", tokenMaxDaysUser=" + tokenMaxDaysUser
|
|
+ ", tokenMaxDaysServiceAccount=" + tokenMaxDaysServiceAccount
|
|
+ ", tokenProtectedGroups=" + tokenProtectedGroups
|
|
+ ", tokenTwoPersonApproval=" + tokenTwoPersonApproval
|
|
+ ", tokenScopesEnabled=" + tokenScopesEnabled
|
|
+ ", tokenBrokerClientId=" + tokenBrokerClientId
|
|
+ ", tokenEndpointUrl=" + tokenEndpointUrl
|
|
+ ", appPublicUrl=" + appPublicUrl
|
|
+ ", authentikPublicUrl=" + authentikPublicUrl
|
|
+ ", appClientId=" + appClientId
|
|
+ ", tokenUnusedDays=" + tokenUnusedDays
|
|
+ ", serviceAccountTokenLifetime=" + serviceAccountTokenLifetime
|
|
+ ", features=" + features + ", readOnly=" + readOnly + ", apiToken=" + (StringUtils.hasContent(apiToken) ? "******" : "(unset)") + "}");
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for baseUrl
|
|
*******************************************************************************/
|
|
public String getBaseUrl()
|
|
{
|
|
return (this.baseUrl);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for baseUrl
|
|
*******************************************************************************/
|
|
public void setBaseUrl(String baseUrl)
|
|
{
|
|
this.baseUrl = baseUrl;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for baseUrl
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withBaseUrl(String baseUrl)
|
|
{
|
|
this.baseUrl = baseUrl;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for apiToken (the raw, possibly ${env.X}, value). Never serialized.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getApiToken()
|
|
{
|
|
return (this.apiToken);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for apiToken
|
|
*******************************************************************************/
|
|
public void setApiToken(String apiToken)
|
|
{
|
|
this.apiToken = apiToken;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for apiToken
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withApiToken(String apiToken)
|
|
{
|
|
this.apiToken = apiToken;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for appKey
|
|
*******************************************************************************/
|
|
public String getAppKey()
|
|
{
|
|
return (this.appKey);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for appKey
|
|
*******************************************************************************/
|
|
public void setAppKey(String appKey)
|
|
{
|
|
this.appKey = appKey;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for appKey
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withAppKey(String appKey)
|
|
{
|
|
this.appKey = appKey;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tableNamePrefix
|
|
*******************************************************************************/
|
|
public String getTableNamePrefix()
|
|
{
|
|
return (this.tableNamePrefix);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tableNamePrefix
|
|
*******************************************************************************/
|
|
public void setTableNamePrefix(String tableNamePrefix)
|
|
{
|
|
this.tableNamePrefix = tableNamePrefix;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tableNamePrefix
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTableNamePrefix(String tableNamePrefix)
|
|
{
|
|
this.tableNamePrefix = tableNamePrefix;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for features
|
|
*******************************************************************************/
|
|
public Set<AuthentikFeature> getFeatures()
|
|
{
|
|
return (this.features);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for features
|
|
*******************************************************************************/
|
|
public void setFeatures(Set<AuthentikFeature> features)
|
|
{
|
|
this.features = features;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for features
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withFeatures(Set<AuthentikFeature> features)
|
|
{
|
|
this.features = features;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for readOnly
|
|
*******************************************************************************/
|
|
public Boolean getReadOnly()
|
|
{
|
|
return (this.readOnly);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for readOnly
|
|
*******************************************************************************/
|
|
public void setReadOnly(Boolean readOnly)
|
|
{
|
|
this.readOnly = readOnly;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for readOnly
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withReadOnly(Boolean readOnly)
|
|
{
|
|
this.readOnly = readOnly;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for serviceAccountUsername
|
|
*******************************************************************************/
|
|
public String getServiceAccountUsername()
|
|
{
|
|
return (this.serviceAccountUsername);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for serviceAccountUsername
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withServiceAccountUsername(String serviceAccountUsername)
|
|
{
|
|
this.serviceAccountUsername = serviceAccountUsername;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for userScopePathStartsWith
|
|
*******************************************************************************/
|
|
public String getUserScopePathStartsWith()
|
|
{
|
|
return (this.userScopePathStartsWith);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for userScopePathStartsWith
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withUserScopePathStartsWith(String userScopePathStartsWith)
|
|
{
|
|
this.userScopePathStartsWith = userScopePathStartsWith;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for userScopeGroupNames
|
|
*******************************************************************************/
|
|
public List<String> getUserScopeGroupNames()
|
|
{
|
|
return (this.userScopeGroupNames);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for userScopeGroupNames
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withUserScopeGroupNames(List<String> userScopeGroupNames)
|
|
{
|
|
this.userScopeGroupNames = userScopeGroupNames;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for groupScopeNamePrefix
|
|
*******************************************************************************/
|
|
public String getGroupScopeNamePrefix()
|
|
{
|
|
return (this.groupScopeNamePrefix);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for groupScopeNamePrefix
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withGroupScopeNamePrefix(String groupScopeNamePrefix)
|
|
{
|
|
this.groupScopeNamePrefix = groupScopeNamePrefix;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for protectedUsernames
|
|
*******************************************************************************/
|
|
public List<String> getProtectedUsernames()
|
|
{
|
|
return (this.protectedUsernames);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for protectedUsernames
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withProtectedUsernames(List<String> protectedUsernames)
|
|
{
|
|
this.protectedUsernames = protectedUsernames;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for bootstrapOperatorSubjects (raw value)
|
|
*******************************************************************************/
|
|
public String getBootstrapOperatorSubjects()
|
|
{
|
|
return (this.bootstrapOperatorSubjects);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for bootstrapOperatorSubjects (comma-separated emails or ${env.X})
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withBootstrapOperatorSubjects(String bootstrapOperatorSubjects)
|
|
{
|
|
this.bootstrapOperatorSubjects = bootstrapOperatorSubjects;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for applicationsInScope
|
|
*******************************************************************************/
|
|
public List<String> getApplicationsInScope()
|
|
{
|
|
return (this.applicationsInScope);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for applicationsInScope. Explicit slugs are required:
|
|
** Authentik lists to a non-superuser only the applications that user can
|
|
** itself access, so the qbit cannot discover them (phase 0 finding).
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withApplicationsInScope(List<String> applicationsInScope)
|
|
{
|
|
this.applicationsInScope = applicationsInScope;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for localBackendName: the RDBMS backend holding the qbit's own
|
|
** tables (admin actions, approval requests).
|
|
*******************************************************************************/
|
|
public String getLocalBackendName()
|
|
{
|
|
return (this.localBackendName);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for localBackendName
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withLocalBackendName(String localBackendName)
|
|
{
|
|
this.localBackendName = localBackendName;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for twoPersonApproval: whether adding authentik.* permissions to a
|
|
** group needs a second person (authentik.approve) to approve it.
|
|
*******************************************************************************/
|
|
public Boolean getTwoPersonApproval()
|
|
{
|
|
return (this.twoPersonApproval);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for twoPersonApproval
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTwoPersonApproval(Boolean twoPersonApproval)
|
|
{
|
|
this.twoPersonApproval = twoPersonApproval;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for linkPrefix: the path prefix of table and record links the home
|
|
** page renders (the Next UI serves tables at /app/{table}).
|
|
*******************************************************************************/
|
|
public String getLinkPrefix()
|
|
{
|
|
return (this.linkPrefix);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for linkPrefix
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withLinkPrefix(String linkPrefix)
|
|
{
|
|
this.linkPrefix = linkPrefix;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for schedulerName (optional; runs the reconcile/attention checks)
|
|
*******************************************************************************/
|
|
public String getSchedulerName()
|
|
{
|
|
return (this.schedulerName);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for schedulerName
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withSchedulerName(String schedulerName)
|
|
{
|
|
this.schedulerName = schedulerName;
|
|
return (this);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Optional host ESB destination; absent means inline inbox processing.
|
|
*******************************************************************************/
|
|
public String getEsbDestinationName()
|
|
{
|
|
return (esbDestinationName);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Select an existing host destination, without creating a broker or queue.
|
|
*******************************************************************************/
|
|
public void setEsbDestinationName(String value)
|
|
{
|
|
esbDestinationName = value;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Fluent optional destination selection.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withEsbDestinationName(String value)
|
|
{
|
|
esbDestinationName = value;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for recoveryEmailStage
|
|
*******************************************************************************/
|
|
public String getRecoveryEmailStage()
|
|
{
|
|
return (this.recoveryEmailStage);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for recoveryEmailStage
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withRecoveryEmailStage(String recoveryEmailStage)
|
|
{
|
|
this.recoveryEmailStage = recoveryEmailStage;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for invitationFlow
|
|
*******************************************************************************/
|
|
public String getInvitationFlow()
|
|
{
|
|
return (this.invitationFlow);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for invitationFlow
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withInvitationFlow(String invitationFlow)
|
|
{
|
|
this.invitationFlow = invitationFlow;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for newUserPath
|
|
*******************************************************************************/
|
|
public String getNewUserPath()
|
|
{
|
|
return (this.newUserPath);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for newUserPath
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withNewUserPath(String newUserPath)
|
|
{
|
|
this.newUserPath = newUserPath;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for webhookSecret (raw value). Never serialized.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getWebhookSecret()
|
|
{
|
|
return (this.webhookSecret);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for webhookSecret
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withWebhookSecret(String webhookSecret)
|
|
{
|
|
this.webhookSecret = webhookSecret;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for throttleRequestsPerSecond
|
|
*******************************************************************************/
|
|
public Integer getThrottleRequestsPerSecond()
|
|
{
|
|
return (this.throttleRequestsPerSecond);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for throttleRequestsPerSecond
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withThrottleRequestsPerSecond(Integer throttleRequestsPerSecond)
|
|
{
|
|
this.throttleRequestsPerSecond = throttleRequestsPerSecond;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for throttleBurst
|
|
*******************************************************************************/
|
|
public Integer getThrottleBurst()
|
|
{
|
|
return (this.throttleBurst);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for throttleBurst
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withThrottleBurst(Integer throttleBurst)
|
|
{
|
|
this.throttleBurst = throttleBurst;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for bulkPacingMillis
|
|
*******************************************************************************/
|
|
public Integer getBulkPacingMillis()
|
|
{
|
|
return (this.bulkPacingMillis);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for bulkPacingMillis
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withBulkPacingMillis(Integer bulkPacingMillis)
|
|
{
|
|
this.bulkPacingMillis = bulkPacingMillis;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for listCacheTtlSeconds
|
|
*******************************************************************************/
|
|
public Integer getListCacheTtlSeconds()
|
|
{
|
|
return (this.listCacheTtlSeconds);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for listCacheTtlSeconds (0 disables the list cache)
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withListCacheTtlSeconds(Integer listCacheTtlSeconds)
|
|
{
|
|
this.listCacheTtlSeconds = listCacheTtlSeconds;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for groupCacheTtlSeconds
|
|
*******************************************************************************/
|
|
public Integer getGroupCacheTtlSeconds()
|
|
{
|
|
return (this.groupCacheTtlSeconds);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for groupCacheTtlSeconds (0 disables the group cache)
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withGroupCacheTtlSeconds(Integer groupCacheTtlSeconds)
|
|
{
|
|
this.groupCacheTtlSeconds = groupCacheTtlSeconds;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for connectTimeoutMillis
|
|
*******************************************************************************/
|
|
public Integer getConnectTimeoutMillis()
|
|
{
|
|
return (this.connectTimeoutMillis);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for connectTimeoutMillis
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withConnectTimeoutMillis(Integer connectTimeoutMillis)
|
|
{
|
|
this.connectTimeoutMillis = connectTimeoutMillis;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for socketTimeoutMillis
|
|
*******************************************************************************/
|
|
public Integer getSocketTimeoutMillis()
|
|
{
|
|
return (this.socketTimeoutMillis);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for socketTimeoutMillis
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withSocketTimeoutMillis(Integer socketTimeoutMillis)
|
|
{
|
|
this.socketTimeoutMillis = socketTimeoutMillis;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for expectedServerVersion
|
|
*******************************************************************************/
|
|
public String getExpectedServerVersion()
|
|
{
|
|
return (this.expectedServerVersion);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for expectedServerVersion (major.minor, e.g. 2026.8)
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withExpectedServerVersion(String expectedServerVersion)
|
|
{
|
|
this.expectedServerVersion = expectedServerVersion;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for policySpec: the PolicySpec this app accepts and writes (docs/POLICY-FORMAT.md).
|
|
*******************************************************************************/
|
|
public String getPolicySpec()
|
|
{
|
|
return (this.policySpec);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for policySpec
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withPolicySpec(String policySpec)
|
|
{
|
|
this.policySpec = policySpec;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for policyVersion: the one supported PolicyVersion (semver).
|
|
*******************************************************************************/
|
|
public String getPolicyVersion()
|
|
{
|
|
return (this.policyVersion);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for policyVersion
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withPolicyVersion(String policyVersion)
|
|
{
|
|
this.policyVersion = policyVersion;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for policyAttribute: the Authentik group attribute that holds a group's policy document.
|
|
*******************************************************************************/
|
|
public String getPolicyAttribute()
|
|
{
|
|
return (this.policyAttribute);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for policyAttribute
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withPolicyAttribute(String policyAttribute)
|
|
{
|
|
this.policyAttribute = policyAttribute;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for policyClaim: the token claim that holds the merged policy document.
|
|
*******************************************************************************/
|
|
public String getPolicyClaim()
|
|
{
|
|
return (this.policyClaim);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for policyClaim
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withPolicyClaim(String policyClaim)
|
|
{
|
|
this.policyClaim = policyClaim;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for policyTwoPersonApproval: whether every policy save needs a second person (authentik.approve).
|
|
*******************************************************************************/
|
|
public Boolean getPolicyTwoPersonApproval()
|
|
{
|
|
return (this.policyTwoPersonApproval);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for policyTwoPersonApproval
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withPolicyTwoPersonApproval(Boolean policyTwoPersonApproval)
|
|
{
|
|
this.policyTwoPersonApproval = policyTwoPersonApproval;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** The policy names (spec, version, attribute, claim) as one value.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public PolicyFormat getPolicyFormat()
|
|
{
|
|
return (new PolicyFormat(policySpec, policyVersion, policyAttribute, policyClaim));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for mapperEnabled: whether the host uses the qbit mapper for sign-in permissions (its own flag, e.g. AUTHENTIK_QBIT_MAPPER); false shows "policies are not enforced" everywhere.
|
|
*******************************************************************************/
|
|
public Boolean getMapperEnabled()
|
|
{
|
|
return (this.mapperEnabled);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for mapperEnabled
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withMapperEnabled(Boolean mapperEnabled)
|
|
{
|
|
this.mapperEnabled = mapperEnabled;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for mapperOverride: activate the mapper even when the cut-over guard finds removed permissions (explicit owner override).
|
|
*******************************************************************************/
|
|
public Boolean getMapperOverride()
|
|
{
|
|
return (this.mapperOverride);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for mapperOverride
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withMapperOverride(Boolean mapperOverride)
|
|
{
|
|
this.mapperOverride = mapperOverride;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for cutoverGuardGroups: groups whose members must lose no permission at the cut-over (DESIGN.md section 12.8).
|
|
*******************************************************************************/
|
|
public List<String> getCutoverGuardGroups()
|
|
{
|
|
return (this.cutoverGuardGroups);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for cutoverGuardGroups
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withCutoverGuardGroups(List<String> cutoverGuardGroups)
|
|
{
|
|
this.cutoverGuardGroups = cutoverGuardGroups;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for staticGroupPermissions: permissions always granted to members of a group (the mapper floor, e.g. today's admin grant), so a cut-over cannot lock admins out.
|
|
*******************************************************************************/
|
|
public java.util.Map<String, List<String>> getStaticGroupPermissions()
|
|
{
|
|
return (this.staticGroupPermissions);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for staticGroupPermissions
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withStaticGroupPermissions(java.util.Map<String, List<String>> staticGroupPermissions)
|
|
{
|
|
this.staticGroupPermissions = staticGroupPermissions;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for hostPermissionSource: the host's current (pre-policy)
|
|
** permission source, or null (DESIGN.md section 12.8).
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public com.kingsrook.qbits.authentik.permissions.AuthentikHostPermissionSource getHostPermissionSource()
|
|
{
|
|
return (this.hostPermissionSource);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for hostPermissionSource
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withHostPermissionSource(com.kingsrook.qbits.authentik.permissions.AuthentikHostPermissionSource hostPermissionSource)
|
|
{
|
|
this.hostPermissionSource = hostPermissionSource;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for fullAccessHostPermissions: the host's own permission names
|
|
** (custom checkers, named permissions such as "cdn.purge") that QQQ
|
|
** metadata cannot list. Full access expands to these as well, computed at
|
|
** use time from the current instance. Null means none.
|
|
*******************************************************************************/
|
|
public java.util.function.Function<QInstance, java.util.Collection<String>> getFullAccessHostPermissions()
|
|
{
|
|
return (this.fullAccessHostPermissions);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for fullAccessHostPermissions.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withFullAccessHostPermissions(java.util.function.Function<QInstance, java.util.Collection<String>> fullAccessHostPermissions)
|
|
{
|
|
this.fullAccessHostPermissions = fullAccessHostPermissions;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokensEnabled.
|
|
*******************************************************************************/
|
|
public Boolean getTokensEnabled()
|
|
{
|
|
return (tokensEnabled == null ? !"false".equalsIgnoreCase(String.valueOf(resolve("${env.AUTHENTIK_QBIT_TOKENS}")).trim()) : tokensEnabled);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokensEnabled.
|
|
*******************************************************************************/
|
|
public void setTokensEnabled(Boolean tokensEnabled)
|
|
{
|
|
this.tokensEnabled = tokensEnabled;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokensEnabled.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokensEnabled(Boolean tokensEnabled)
|
|
{
|
|
this.tokensEnabled = tokensEnabled;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenMaxDaysUser.
|
|
*******************************************************************************/
|
|
public Integer getTokenMaxDaysUser()
|
|
{
|
|
return (tokenMaxDaysUser);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenMaxDaysUser.
|
|
*******************************************************************************/
|
|
public void setTokenMaxDaysUser(Integer tokenMaxDaysUser)
|
|
{
|
|
this.tokenMaxDaysUser = tokenMaxDaysUser;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenMaxDaysUser.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenMaxDaysUser(Integer tokenMaxDaysUser)
|
|
{
|
|
this.tokenMaxDaysUser = tokenMaxDaysUser;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenMaxDaysServiceAccount.
|
|
*******************************************************************************/
|
|
public Integer getTokenMaxDaysServiceAccount()
|
|
{
|
|
return (tokenMaxDaysServiceAccount);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenMaxDaysServiceAccount.
|
|
*******************************************************************************/
|
|
public void setTokenMaxDaysServiceAccount(Integer tokenMaxDaysServiceAccount)
|
|
{
|
|
this.tokenMaxDaysServiceAccount = tokenMaxDaysServiceAccount;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenMaxDaysServiceAccount.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenMaxDaysServiceAccount(Integer tokenMaxDaysServiceAccount)
|
|
{
|
|
this.tokenMaxDaysServiceAccount = tokenMaxDaysServiceAccount;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenProtectedGroups.
|
|
*******************************************************************************/
|
|
public List<String> getTokenProtectedGroups()
|
|
{
|
|
return (tokenProtectedGroups);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenProtectedGroups.
|
|
*******************************************************************************/
|
|
public void setTokenProtectedGroups(List<String> tokenProtectedGroups)
|
|
{
|
|
this.tokenProtectedGroups = tokenProtectedGroups;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenProtectedGroups.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenProtectedGroups(List<String> tokenProtectedGroups)
|
|
{
|
|
this.tokenProtectedGroups = tokenProtectedGroups;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenTwoPersonApproval.
|
|
*******************************************************************************/
|
|
public Boolean getTokenTwoPersonApproval()
|
|
{
|
|
return (tokenTwoPersonApproval);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenTwoPersonApproval.
|
|
*******************************************************************************/
|
|
public void setTokenTwoPersonApproval(Boolean tokenTwoPersonApproval)
|
|
{
|
|
this.tokenTwoPersonApproval = tokenTwoPersonApproval;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenTwoPersonApproval.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenTwoPersonApproval(Boolean tokenTwoPersonApproval)
|
|
{
|
|
this.tokenTwoPersonApproval = tokenTwoPersonApproval;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenScopesEnabled.
|
|
*******************************************************************************/
|
|
public Boolean getTokenScopesEnabled()
|
|
{
|
|
return (tokenScopesEnabled);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenScopesEnabled.
|
|
*******************************************************************************/
|
|
public void setTokenScopesEnabled(Boolean tokenScopesEnabled)
|
|
{
|
|
this.tokenScopesEnabled = tokenScopesEnabled;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenScopesEnabled.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenScopesEnabled(Boolean tokenScopesEnabled)
|
|
{
|
|
this.tokenScopesEnabled = tokenScopesEnabled;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenBrokerClientId.
|
|
*******************************************************************************/
|
|
public String getTokenBrokerClientId()
|
|
{
|
|
return (resolve(tokenBrokerClientId));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenBrokerClientId.
|
|
*******************************************************************************/
|
|
public void setTokenBrokerClientId(String tokenBrokerClientId)
|
|
{
|
|
this.tokenBrokerClientId = tokenBrokerClientId;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenBrokerClientId.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenBrokerClientId(String tokenBrokerClientId)
|
|
{
|
|
this.tokenBrokerClientId = tokenBrokerClientId;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenBrokerClientSecret.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public String getTokenBrokerClientSecret()
|
|
{
|
|
return (resolve(tokenBrokerClientSecret));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenBrokerClientSecret.
|
|
*******************************************************************************/
|
|
public void setTokenBrokerClientSecret(String tokenBrokerClientSecret)
|
|
{
|
|
this.tokenBrokerClientSecret = tokenBrokerClientSecret;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenBrokerClientSecret.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenBrokerClientSecret(String tokenBrokerClientSecret)
|
|
{
|
|
this.tokenBrokerClientSecret = tokenBrokerClientSecret;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenEndpointUrl.
|
|
*******************************************************************************/
|
|
public String getTokenEndpointUrl()
|
|
{
|
|
return (tokenEndpointUrl == null ? getBaseUrl().replaceAll("/+$", "") + "/application/o/token/" : resolve(tokenEndpointUrl));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenEndpointUrl.
|
|
*******************************************************************************/
|
|
public void setTokenEndpointUrl(String tokenEndpointUrl)
|
|
{
|
|
this.tokenEndpointUrl = tokenEndpointUrl;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenEndpointUrl.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenEndpointUrl(String tokenEndpointUrl)
|
|
{
|
|
this.tokenEndpointUrl = tokenEndpointUrl;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for maintenancePrincipal: the service principal (declared by the
|
|
** host, docs/SERVICE-IDENTITY.md in qqq) that AuthentikMaintenance runs as.
|
|
** Its Authentik policy must hold policies.manage and every grant it applies.
|
|
*******************************************************************************/
|
|
public String getMaintenancePrincipal()
|
|
{
|
|
return (this.maintenancePrincipal);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for maintenancePrincipal (default maintenance).
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withMaintenancePrincipal(String maintenancePrincipal)
|
|
{
|
|
this.maintenancePrincipal = maintenancePrincipal;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for appPublicUrl.
|
|
*******************************************************************************/
|
|
public String getAppPublicUrl()
|
|
{
|
|
return (resolve(appPublicUrl));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for appPublicUrl.
|
|
*******************************************************************************/
|
|
public void setAppPublicUrl(String appPublicUrl)
|
|
{
|
|
this.appPublicUrl = appPublicUrl;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for appPublicUrl.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withAppPublicUrl(String appPublicUrl)
|
|
{
|
|
this.appPublicUrl = appPublicUrl;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for authentikPublicUrl.
|
|
*******************************************************************************/
|
|
public String getAuthentikPublicUrl()
|
|
{
|
|
return (authentikPublicUrl == null ? getBaseUrl() : resolve(authentikPublicUrl));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for authentikPublicUrl.
|
|
*******************************************************************************/
|
|
public void setAuthentikPublicUrl(String authentikPublicUrl)
|
|
{
|
|
this.authentikPublicUrl = authentikPublicUrl;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for authentikPublicUrl.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withAuthentikPublicUrl(String authentikPublicUrl)
|
|
{
|
|
this.authentikPublicUrl = authentikPublicUrl;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for appClientId.
|
|
*******************************************************************************/
|
|
public String getAppClientId()
|
|
{
|
|
return (resolve(appClientId));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for appClientId.
|
|
*******************************************************************************/
|
|
public void setAppClientId(String appClientId)
|
|
{
|
|
this.appClientId = appClientId;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for appClientId.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withAppClientId(String appClientId)
|
|
{
|
|
this.appClientId = appClientId;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for tokenUnusedDays.
|
|
*******************************************************************************/
|
|
public Integer getTokenUnusedDays()
|
|
{
|
|
return (tokenUnusedDays);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for tokenUnusedDays.
|
|
*******************************************************************************/
|
|
public void setTokenUnusedDays(Integer tokenUnusedDays)
|
|
{
|
|
this.tokenUnusedDays = tokenUnusedDays;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for tokenUnusedDays.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenUnusedDays(Integer tokenUnusedDays)
|
|
{
|
|
this.tokenUnusedDays = tokenUnusedDays;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for serviceAccountTokenLifetime.
|
|
*******************************************************************************/
|
|
public String getServiceAccountTokenLifetime()
|
|
{
|
|
return (serviceAccountTokenLifetime);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for serviceAccountTokenLifetime.
|
|
*******************************************************************************/
|
|
public void setServiceAccountTokenLifetime(String serviceAccountTokenLifetime)
|
|
{
|
|
this.serviceAccountTokenLifetime = serviceAccountTokenLifetime;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for serviceAccountTokenLifetime.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withServiceAccountTokenLifetime(String serviceAccountTokenLifetime)
|
|
{
|
|
this.serviceAccountTokenLifetime = serviceAccountTokenLifetime;
|
|
return (this);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Getter for subjectTokenSource.
|
|
*******************************************************************************/
|
|
@JsonIgnore
|
|
public com.kingsrook.qbits.authentik.client.AuthentikSubjectTokenSource getSubjectTokenSource()
|
|
{
|
|
return (subjectTokenSource);
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Setter for subjectTokenSource.
|
|
*******************************************************************************/
|
|
public void setSubjectTokenSource(com.kingsrook.qbits.authentik.client.AuthentikSubjectTokenSource subjectTokenSource)
|
|
{
|
|
this.subjectTokenSource = subjectTokenSource;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
** Fluent setter for subjectTokenSource.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withSubjectTokenSource(com.kingsrook.qbits.authentik.client.AuthentikSubjectTokenSource subjectTokenSource)
|
|
{
|
|
this.subjectTokenSource = subjectTokenSource;
|
|
return (this);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Signed JWT claim identifying the Authentik token.
|
|
*******************************************************************************/
|
|
public String getTokenScopeClaim()
|
|
{
|
|
return (tokenScopeClaim);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Set the host's signed token claim name.
|
|
*******************************************************************************/
|
|
public void setTokenScopeClaim(String value)
|
|
{
|
|
tokenScopeClaim = value;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Fluent signed token claim name.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenScopeClaim(String value)
|
|
{
|
|
tokenScopeClaim = value;
|
|
return (this);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Optional scheduler; otherwise use the instance's first scheduler.
|
|
*******************************************************************************/
|
|
public String getTokenReminderSchedulerName()
|
|
{
|
|
return (tokenReminderSchedulerName);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Select a scheduler when the host defines several.
|
|
*******************************************************************************/
|
|
public void setTokenReminderSchedulerName(String value)
|
|
{
|
|
tokenReminderSchedulerName = value;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** Fluent scheduler selection.
|
|
*******************************************************************************/
|
|
public AuthentikQBitConfig withTokenReminderSchedulerName(String value)
|
|
{
|
|
tokenReminderSchedulerName = value;
|
|
return (this);
|
|
}
|
|
|
|
}
|