diff --git a/openam-documentation/openam-doc-services-ref/pom.xml b/openam-documentation/openam-doc-services-ref/pom.xml
new file mode 100644
index 0000000000..f6bc062290
--- /dev/null
+++ b/openam-documentation/openam-doc-services-ref/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+ 4.0.0
+
+ org.openidentityplatform.openam
+ openam-documentation
+ 15.2.2-SNAPSHOT
+
+ openam-doc-services-ref
+
+
+ org.openidentityplatform.openam
+ openam-server-only
+ ${project.version}
+ pom
+
+
+ org.jsoup
+ jsoup
+ 1.21.2
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.5.1
+
+
+
+ java
+
+ prepare-package
+
+
+
+ org.openidentityplatform.openam.docs.services.Generator
+
+ ${project.basedir}/../../openam-server-only/target/OpenAM-ServerOnly-${project.version}
+ ${build.outputDirectory}
+
+
+
+
+
+
+
diff --git a/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/Generator.java b/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/Generator.java
new file mode 100644
index 0000000000..c71a0ec624
--- /dev/null
+++ b/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/Generator.java
@@ -0,0 +1,329 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2025 3A Systems LLC.
+ */
+
+package org.openidentityplatform.openam.docs.services;
+
+import org.apache.commons.text.TextStringBuilder;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class Generator {
+
+ final HtmlConverter htmlConverter;
+
+ final DocumentBuilder builder;
+
+ final XPath xpath;
+
+ final Locale BUNDLE_LOCALE = Locale.forLanguageTag("en");
+
+ final String AUTH_CLASS_NAME_REGEX = "^(iPlanetAMAuth|sunAMAuth)(.*?)Service$";
+
+ public Generator() throws Exception {
+ htmlConverter = new HtmlConverter();
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+ builder = factory.newDocumentBuilder();
+ builder.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));
+
+ xpath = XPathFactory.newInstance().newXPath();
+ }
+
+ public static void main(String[] args) throws Exception {
+ String serverPath = args[0];
+ String targetPath = args[1];
+
+ Generator generator = new Generator();
+
+ generator.generateServicesDoc(serverPath, targetPath);
+
+ }
+
+ private void generateServicesDoc(String serverPath, String targetPath) throws Exception {
+
+ try(WarClassLoader cl = new WarClassLoader(serverPath)) {
+
+ Map xmlServicesMap = fetchServicesMapFromWar(cl);
+
+ Path dirPath = Paths.get(targetPath);
+ Files.createDirectories(dirPath);
+
+ generateAuthModulesDoc(xmlServicesMap, cl, dirPath);
+
+ generateDataStoreDoc(xmlServicesMap, cl, dirPath);
+ }
+
+ }
+
+ private Map fetchServicesMapFromWar(WarClassLoader cl) throws Exception {
+ Properties serviceNamesProps = cl.loadProperties("serviceNames.properties");
+ String serviceNamesStr = serviceNamesProps.getProperty("serviceNames");
+ String[] serviceNames = serviceNamesStr.split("\\s+");
+ List errors = new ArrayList<>();
+ final Pattern INVALID_FILENAME_CHARACTERS_PATTERN = Pattern.compile("[<>:\"/|?*]");
+ List xmlServices = Arrays.stream(serviceNames).map(String::trim)
+ .filter(s -> {
+ Matcher m = INVALID_FILENAME_CHARACTERS_PATTERN.matcher(s);
+ return !m.find();
+ })
+ .map(s -> {
+ try(InputStream is = cl.getResourceAsStream(s)) {
+ if (is == null) {
+ return null;
+ }
+ return builder.parse(is);
+ } catch (Exception e) {
+ errors.add(e);
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ if (!errors.isEmpty()) {
+ String errMessage = "Errors occurred while parsing service files:" + errors;
+ System.out.println(errMessage);
+ throw new Exception(errMessage);
+ }
+
+ return xmlServices.stream().collect(Collectors.toMap(xmlService -> {
+ Element service = (Element) xmlService.getElementsByTagName("Service").item(0);
+ return service.getAttribute("name");
+ }, xmlService -> xmlService, (existing, replacement) -> existing, LinkedHashMap::new));
+ }
+
+
+ private void generateAuthModulesDoc(Map xmlServicesMap, WarClassLoader cl, Path targetPath) throws Exception {
+
+ Document iPlanetAMAuthService = xmlServicesMap.get("iPlanetAMAuthService");
+
+ Map authClassMap = getAuthClassMap(iPlanetAMAuthService);
+
+ TextStringBuilder asciidoc = new TextStringBuilder();
+ asciidoc.appendln(":table-caption!:").appendNewLine();
+ asciidoc.appendln("[#chap-auth-modules]");
+ asciidoc.append("== ").appendln("Authentication Modules Reference").appendNewLine();
+
+ for(Map.Entry entry : xmlServicesMap.entrySet()) {
+ Document xmlService = entry.getValue();
+ NodeList schema = xmlService.getElementsByTagName("Schema");
+ Element schemaElement = (Element) schema.item(0);
+ if(!isAuthService(xmlService, authClassMap)) {
+ continue;
+ }
+
+ String bundleName = schemaElement.getAttribute("i18nFileName");
+ ResourceBundle bundle = ResourceBundle.getBundle(bundleName, BUNDLE_LOCALE, cl);
+ generateModuleDoc(schemaElement, bundle, asciidoc, authClassMap);
+ }
+ Path filePath = targetPath.resolve("chap-auth-modules.adoc");
+
+ Files.write(filePath, asciidoc.toString().getBytes(StandardCharsets.UTF_8),
+ StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+
+ System.out.println("File written to: " + filePath.toAbsolutePath());
+ }
+
+ private Map getAuthClassMap(Document iPlanetAMAuthService) throws XPathExpressionException {
+ Map authClassMap = new HashMap<>();
+
+ final String authModuleClassesXpath = "/ServicesConfiguration/Service/Schema/Global/AttributeSchema[1]/DefaultValues/Value";
+
+ NodeList authClassNames = (NodeList) xpath.evaluate(authModuleClassesXpath, iPlanetAMAuthService, XPathConstants.NODESET);
+
+ for (int i = 0; i < authClassNames.getLength(); i++) {
+ String authClassName = authClassNames.item(i).getTextContent();
+ String[] tokenized = authClassName.split("\\.");
+ String classShortName = tokenized[tokenized.length - 1].toLowerCase();
+ authClassMap.put(classShortName, authClassName);
+ }
+ return authClassMap;
+ }
+
+ private boolean isAuthService(Document xmlService, Map authClassMap) {
+
+
+ NodeList schema = xmlService.getElementsByTagName("Schema");
+ Element schemaElement = (Element) schema.item(0);
+ String serviceHierarchy = schemaElement.getAttribute("serviceHierarchy");
+ if(!serviceHierarchy.startsWith("/DSAMEConfig/authentication/")) {
+ return false;
+ }
+ Element service = (Element) xmlService.getElementsByTagName("Service").item(0);
+ String serviceName = service.getAttribute("name");
+
+ if (!serviceName.matches(AUTH_CLASS_NAME_REGEX)) {
+ System.out.println(serviceName + " is not auth service");
+ return false;
+ }
+
+ String authServiceClassFullName = getAuthClassName(serviceName, authClassMap);
+ if(authServiceClassFullName == null) {
+ System.out.println(serviceName + " is not auth module");
+ return false;
+ }
+ return true;
+ }
+
+ private String getAuthClassName(String serviceName, Map authClassMap) {
+
+ String authServiceClassName = serviceName.replaceAll(AUTH_CLASS_NAME_REGEX, "$2").toLowerCase();
+ return authClassMap.get(authServiceClassName);
+ }
+
+ private void generateModuleDoc(Element schemaElement, ResourceBundle bundle, TextStringBuilder asciidoc, Map authClassMap) {
+
+ String moduleNameKey = schemaElement.getAttribute("i18nKey");
+ String moduleName = bundle.getString(moduleNameKey);
+ asciidoc.append(String.format("[#%s-module-ref]", moduleName.toLowerCase().replace(" ", "-"))).appendNewLine();
+ asciidoc.append("=== ").append(moduleName)
+ .appendNewLine().appendNewLine();
+
+ String serviceName = ((Element) schemaElement.getParentNode()).getAttribute("name");
+
+ String className = getAuthClassName(serviceName, authClassMap);
+ String classLink = String.format("link:../apidocs/index.html?%s.html[%s, window=\\_blank]",
+ className.replaceAll("\\.", "/"), className);
+ asciidoc.appendln(String.format("Java class: `%s`", classLink))
+ .appendNewLine();
+
+ asciidoc.appendln(String.format("`ssoadm` service name: `%s`", ((Element) schemaElement.getParentNode()).getAttribute("name")));
+ asciidoc.appendNewLine();
+
+ Element orgElement = (Element) schemaElement.getElementsByTagName("Organization").item(0);
+ NodeList attributes = orgElement.getElementsByTagName("AttributeSchema");
+ for (int i = 0; i < attributes.getLength(); i++) {
+ Element attrElement = (Element) attributes.item(i);
+ printAttributeElement(bundle, asciidoc, attrElement);
+ }
+ System.out.printf("generated doc for %s module%n", moduleName);
+ }
+
+ private void generateDataStoreDoc(Map xmlServicesMap, WarClassLoader cl, Path targetPath) throws Exception {
+ TextStringBuilder asciidoc = new TextStringBuilder();
+ asciidoc.appendln(":table-caption!:").appendNewLine();
+ asciidoc.appendln("[#chap-user-data-stores]");
+ asciidoc.append("== ").appendln("User Data Stores Reference").appendNewLine();
+
+ Document xmlService = xmlServicesMap.get("sunIdentityRepositoryService");
+ NodeList schema = xmlService.getElementsByTagName("Schema");
+ Element schemaElement = (Element) schema.item(0);
+ String bundleName = schemaElement.getAttribute("i18nFileName");
+
+ ResourceBundle bundle = ResourceBundle.getBundle(bundleName, BUNDLE_LOCALE, cl);
+
+ String expression = "/ServicesConfiguration/Service/Schema/Organization/SubSchema";
+ NodeList dataStoreList = (NodeList) xpath.evaluate(expression, xmlService, XPathConstants.NODESET);
+
+ for (int i = 0; i < dataStoreList.getLength(); i++) {
+ Element dataStore = (Element)dataStoreList.item(i);
+
+ String i18nKey = dataStore.getAttribute("i18nKey");
+ String dataStoreName;
+ if(i18nKey.trim().isEmpty()) {
+ dataStoreName = dataStore.getAttribute("name");
+ } else if(bundle.containsKey(i18nKey)) {
+ dataStoreName = bundle.getString(i18nKey);
+ } else {
+ dataStoreName = i18nKey;
+ }
+ asciidoc.appendln(String.format("[#%s-datastore-ref]", dataStoreName.toLowerCase().replace(" ", "-")));
+ asciidoc.append("=== ").append(dataStoreName)
+ .appendNewLine().appendNewLine();
+
+ NodeList attributes = dataStore.getElementsByTagName("AttributeSchema");
+ for (int j = 0; j < attributes.getLength(); j++) {
+ Element attrElement = (Element) attributes.item(j);
+ printAttributeElement(bundle, asciidoc, attrElement);
+ }
+ }
+
+ Path filePath = targetPath.resolve("chap-user-data-stores.adoc");
+
+ Files.write(filePath, asciidoc.toString().getBytes(StandardCharsets.UTF_8),
+ StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+
+ System.out.println("File written to: " + filePath.toAbsolutePath());
+ }
+
+
+
+ private void printAttributeElement(ResourceBundle bundle, TextStringBuilder asciidoc, Element attrElement) {
+ String type = attrElement.getAttribute("type");
+ if (type.equals("validator")) {
+ return;
+ }
+ String i18Key = attrElement.getAttribute("i18nKey");
+ if ("".equals(i18Key.trim())) {
+ return;
+ }
+ String attrName = i18Key;
+ if(bundle.containsKey(i18Key)) {
+ attrName = bundle.getString(i18Key);
+ }
+ asciidoc.append(attrName).append("::").appendNewLine()
+ .append("+").appendNewLine().appendln("--");
+ if (bundle.containsKey(i18Key.concat(".help"))) {
+ asciidoc.appendNewLine();
+ String attrHelp = bundle.getString(i18Key.concat(".help"));
+ htmlConverter.convertToAsciidoc(attrHelp, asciidoc);
+ asciidoc.appendNewLine();
+ }
+ if (bundle.containsKey(i18Key.concat(".help.txt"))) {
+
+ String attrHelpTxt = bundle.getString(i18Key.concat(".help.txt"));
+ asciidoc.appendNewLine();
+ htmlConverter.convertToAsciidoc(attrHelpTxt, asciidoc);
+ asciidoc.appendNewLine();
+ }
+ asciidoc.appendNewLine();
+ asciidoc.appendln(String.format("`ssoadm` attribute: `%s`", attrElement.getAttribute("name")));
+ asciidoc.appendNewLine();
+ asciidoc.appendln("--");
+ asciidoc.appendNewLine();
+
+ }
+}
\ No newline at end of file
diff --git a/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/HtmlConverter.java b/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/HtmlConverter.java
new file mode 100644
index 0000000000..033812c64f
--- /dev/null
+++ b/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/HtmlConverter.java
@@ -0,0 +1,100 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2022-2025 3A Systems LLC.
+ */
+
+package org.openidentityplatform.openam.docs.services;
+
+import org.apache.commons.text.TextStringBuilder;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+
+import java.util.List;
+
+public class HtmlConverter {
+ public void convertToAsciidoc(String html, TextStringBuilder builder) {
+ html = html.replaceAll("(?i)(
\\s*){2,}", "
");
+ Document doc = Jsoup.parse(html);
+
+ convertNodesToAsciidoc(doc.body().childNodes(), builder);
+
+ }
+
+ private void convertNodesToAsciidoc(List nodes, TextStringBuilder builder) {
+ for(Node node : nodes) {
+ if (node instanceof TextNode) {
+ builder.append(((TextNode) node).text());
+ } else if (node instanceof Element) {
+ Element element = (Element)node;
+ switch (element.nodeName().toLowerCase()) {
+ case "br":
+ builder.appendNewLine().appendNewLine();
+ break;
+ case "code":
+ case "pre":
+ builder.append("`");
+ convertNodesToAsciidoc(node.childNodes(), builder);
+ builder.append("`");
+ break;
+ case "i":
+ builder.append("__");
+ convertNodesToAsciidoc(node.childNodes(), builder);
+ builder.append("__");
+ break;
+ case "a":
+ String text = element.text();
+
+ String href = element.attr("href");
+ String window = "";
+ String targetAttr = element.attr("target");
+ if (targetAttr.trim().isEmpty()) {
+ if(targetAttr.startsWith("_")) {
+ targetAttr = "\\" + targetAttr;
+ }
+ window = ", window=" + targetAttr;
+ }
+ builder.append(href).append("[").append(text).append(window).append("]");
+ break;
+ case "ul":
+ builder.appendNewLine();
+ for (Element ul: element.children()) {
+ builder.append("* ");
+ convertNodesToAsciidoc(ul.childNodes(), builder);
+ builder.appendNewLine();
+ }
+ break;
+ case "ol":
+ builder.appendNewLine();
+ for (Element ul: element.children()) {
+ builder.append(". ");
+ convertNodesToAsciidoc(ul.childNodes(), builder);
+ builder.appendNewLine();
+ }
+ break;
+ case "b":
+ builder.append("*");
+ convertNodesToAsciidoc(node.childNodes(), builder);
+ builder.append("*");
+ break;
+ default:
+ System.err.println("Unhandled tag: " + node.nodeName());
+ throw new RuntimeException(node.nodeName());
+ }
+ }
+ }
+ }
+}
diff --git a/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/WarClassLoader.java b/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/WarClassLoader.java
new file mode 100644
index 0000000000..e8effe234f
--- /dev/null
+++ b/openam-documentation/openam-doc-services-ref/src/main/java/org/openidentityplatform/openam/docs/services/WarClassLoader.java
@@ -0,0 +1,99 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2025 3A Systems LLC.
+ */
+
+package org.openidentityplatform.openam.docs.services;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class WarClassLoader extends URLClassLoader {
+
+ private final Path webInfPath;
+ private final Path classesPath;
+ private final Path libPath;
+ public WarClassLoader(String extractedPath) throws IOException {
+ super(new URL[0]);
+ this.webInfPath = Paths.get(extractedPath, "WEB-INF");
+ this.classesPath = webInfPath.resolve("classes");
+ this.libPath = webInfPath.resolve("lib");
+
+ if(Files.exists(classesPath)) {
+ addURL(classesPath.toUri().toURL());
+ }
+
+ if (Files.exists(libPath)) {
+ try (DirectoryStream stream = Files.newDirectoryStream(libPath, "*.jar")) {
+ for (Path jarPath : stream) {
+ addURL(jarPath.toUri().toURL());
+ }
+ }
+ }
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String name) {
+ try {
+ Path resourcePath = classesPath.resolve(name);
+ if (Files.exists(resourcePath)) {
+ return Files.newInputStream(resourcePath);
+ }
+
+ if (Files.exists(libPath)) {
+ try (DirectoryStream stream = Files.newDirectoryStream(libPath, "*.jar")) {
+ for (Path jarPath : stream) {
+ try (JarFile jarFile = new JarFile(jarPath.toFile())) {
+ JarEntry entry = jarFile.getJarEntry(name);
+ if (entry != null) {
+ // Need to read the entire stream since we're closing the JAR file
+ try (InputStream is = jarFile.getInputStream(entry)) {
+ return new ByteArrayInputStream(IOUtils.toByteArray(is));
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return super.getResourceAsStream(name);
+ }
+
+ public Properties loadProperties(String propertiesPath) throws IOException {
+ Properties props = new Properties();
+ try (InputStream is = getResourceAsStream(propertiesPath)) {
+ if (is != null) {
+ props.load(is);
+ } else {
+ throw new FileNotFoundException("Properties file not found: " + propertiesPath);
+ }
+ }
+ return props;
+ }
+}
diff --git a/openam-documentation/openam-doc-source/pom.xml b/openam-documentation/openam-doc-source/pom.xml
index 56a730bdcb..b90fa79fb1 100644
--- a/openam-documentation/openam-doc-source/pom.xml
+++ b/openam-documentation/openam-doc-source/pom.xml
@@ -13,7 +13,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2011-2016 ForgeRock AS.
- * Portions copyright 2024 3A Systems LLC.
+ * Portions copyright 2024-2025 3A Systems LLC.
-->
4.0.0
@@ -62,6 +62,25 @@
+
+ add-external-docs
+
+ unpack
+
+ prepare-package
+
+
+
+ org.openidentityplatform.openam
+ openam-doc-services-ref
+ ${project.version}
+ jar
+ *.adoc
+ ${project.build.directory}/asciidoc/source/reference
+
+
+
+
diff --git a/openam-documentation/openam-doc-source/src/main/asciidoc/reference/index.adoc b/openam-documentation/openam-doc-source/src/main/asciidoc/reference/index.adoc
index 6d3d50bb6b..3c7d4f4993 100644
--- a/openam-documentation/openam-doc-source/src/main/asciidoc/reference/index.adoc
+++ b/openam-documentation/openam-doc-source/src/main/asciidoc/reference/index.adoc
@@ -40,3 +40,5 @@ include::./chap-endpoints.adoc[]
include::./chap-xui-parameters.adoc[]
include::./chap-cts-oids.adoc[]
include::./chap-log-messages.adoc[]
+include::./chap-auth-modules.adoc[]
+include::./chap-user-data-stores.adoc[]
diff --git a/openam-documentation/pom.xml b/openam-documentation/pom.xml
index 4ccb891344..d897fc7689 100644
--- a/openam-documentation/pom.xml
+++ b/openam-documentation/pom.xml
@@ -13,6 +13,7 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2011-2016 ForgeRock AS.
+ * Portions copyright 2025 3A Systems LLC.
-->
4.0.0
@@ -32,13 +33,14 @@
2011
pom
- Generated DocBook XML sources for OpenAM core user documentation.
+ Generated AsciiDoc sources for OpenAM core user documentation.
Java API reference documentation is generated from OpenAM source code.
- http://openam.forgerock.org/
+ https://doc.openidentityplatform.org/
+ openam-doc-services-ref
openam-doc-log-message-ref
openam-doc-ssoadm-ref
openam-doc-source