diff --git a/.github/workflows/est-ds-realm-test.yml b/.github/workflows/est-ds-realm-test.yml
new file mode 100644
index 00000000000..39aa677097f
--- /dev/null
+++ b/.github/workflows/est-ds-realm-test.yml
@@ -0,0 +1,235 @@
+name: EST with ds realm
+
+on: workflow_call
+
+env:
+ DB_IMAGE: ${{ vars.DB_IMAGE || 'quay.io/389ds/dirsrv' }}
+
+jobs:
+ # docs/installation/ca/Installing_CA.md
+ test:
+ name: Test
+ runs-on: ubuntu-latest
+ env:
+ SHARED: /tmp/workdir/pki
+ steps:
+ - name: Clone repository
+ uses: actions/checkout@v4
+
+ - name: Retrieve PKI images
+ uses: actions/cache@v4
+ with:
+ key: pki-images-${{ github.sha }}
+ path: pki-images.tar
+
+ - name: Load PKI images
+ run: docker load --input pki-images.tar
+
+ - name: Create network
+ run: docker network create example
+
+ - name: Set up DS container
+ run: |
+ tests/bin/ds-create.sh \
+ --image=${{ env.DB_IMAGE }} \
+ --hostname=ds.example.com \
+ --password=Secret.123 \
+ ds
+
+ - name: Connect DS container to network
+ run: docker network connect example ds --alias ds.example.com
+
+ - name: Set up PKI container
+ run: |
+ tests/bin/runner-init.sh pki
+ env:
+ HOSTNAME: pki.example.com
+
+ - name: Connect PKI container to network
+ run: docker network connect example pki --alias pki.example.com
+
+ - name: Install CA
+ run: |
+ docker exec pki pkispawn \
+ -f /usr/share/pki/server/examples/installation/ca.cfg \
+ -s CA \
+ -D pki_ds_url=ldap://ds.example.com:3389 \
+ -v
+
+ - name: Initialize PKI client
+ run: |
+ docker exec pki pki-server cert-export ca_signing --cert-file ca_signing.crt
+
+ docker exec pki pki nss-cert-import \
+ --cert ca_signing.crt \
+ --trust CT,C,C \
+ ca_signing
+
+ docker exec pki pki pkcs12-import \
+ --pkcs12 /root/.dogtag/pki-tomcat/ca_admin_cert.p12 \
+ --pkcs12-password Secret.123
+
+ docker exec pki pki info
+
+ - name: Add CA EST user
+ run: |
+ docker exec pki pki -n caadmin ca-group-add "EST RA Agents"
+ docker exec pki pki -n caadmin ca-user-add \
+ est-ra-1 --fullName "EST RA 1" --password Secret.est
+ docker exec pki pki -n caadmin ca-group-member-add "EST RA Agents" est-ra-1
+
+ - name: Configure CA est profile
+ run: |
+ docker exec pki pki -n caadmin ca-profile-add \
+ --raw /usr/share/pki/ca/profiles/ca/estServiceCert.cfg
+ docker exec pki pki -n caadmin ca-profile-enable estServiceCert
+ docker exec pki pki-server restart --wait
+
+ - name: Install EST
+ run: |
+ docker exec pki pkispawn \
+ -f /usr/share/pki/server/examples/installation/est.cfg \
+ -s EST \
+ -D est_realm_url=ldap://ds.example.com:3389 \
+ -v
+
+ - name: Check EST backend config
+ if: always()
+ run: |
+ docker exec pki cat /etc/pki/pki-tomcat/est/backend.conf
+
+ - name: Check EST authorizer config
+ if: always()
+ run: |
+ docker exec pki cat /etc/pki/pki-tomcat/est/authorizer.conf
+
+ - name: Check EST realm config
+ if: always()
+ run: |
+ docker exec pki cat /etc/pki/pki-tomcat/est/realm.conf
+
+ - name: Check webapps
+ run: |
+ docker exec pki pki-server webapp-find | tee output
+
+ # CA instance should have ROOT, ca, and pki webapps
+ echo "ROOT" > expected
+ echo "ca" >> expected
+ echo "est" >> expected
+ echo "pki" >> expected
+ sed -n 's/^ *Webapp ID: *\(.*\)$/\1/p' output > actual
+ diff expected actual
+
+ docker exec pki pki-server webapp-show ROOT
+ docker exec pki pki-server webapp-show ca
+ docker exec pki pki-server webapp-show est
+ docker exec pki pki-server webapp-show pki
+
+ - name: Create EST users
+ run: |
+ docker exec -i pki ldapadd -x -H ldap://ds.example.com:3389 \
+ -D "cn=Directory Manager" -w Secret.123 << EOF
+ dn: dc=est,dc=pki,dc=example,dc=com
+ objectClass: domain
+ dc: est
+
+ dn: ou=people,dc=est,dc=pki,dc=example,dc=com
+ ou: people
+ objectClass: top
+ objectClass: organizationalUnit
+
+ dn: ou=groups,dc=est,dc=pki,dc=example,dc=com
+ ou: groups
+ objectClass: top
+ objectClass: organizationalUnit
+
+ dn: uid=est-test-user,ou=people,dc=est,dc=pki,dc=example,dc=com
+ objectClass: top
+ objectClass: person
+ objectClass: organizationalPerson
+ objectClass: inetOrgPerson
+ objectClass: cmsuser
+ uid: est-test-user
+ sn: EST TEST USER
+ cn: EST TEST USER
+ usertype: undefined
+ userPassword: Secret.123
+
+ dn: cn=estclient,ou=groups,dc=est,dc=pki,dc=example,dc=com
+ objectClass: top
+ objectClass: groupOfUniqueNames
+ cn: estclient
+ uniqueMember: uid=est-test-user,ou=People,dc=est,dc=pki,dc=example,dc=com
+ EOF
+
+ - name: Test CA certs
+ run: |
+ docker exec pki curl -o cacert.p7 -k https://pki.example.com:8443/.well-known/est/cacerts
+ docker exec pki openssl base64 -d --in cacert.p7 --out cacert.p7.der
+ docker exec pki openssl pkcs7 --in cacert.p7.der -inform DER -print_certs -out cacert.pem
+ docker exec pki openssl x509 -in cacert.pem -text -noout | tee actual
+ docker exec pki openssl x509 -in ca_signing.crt -text -noout | tee expected
+ diff expected actual
+
+ - name: Install est client
+ run: |
+ docker exec pki dnf copr enable -y @pki/libest
+ docker exec pki dnf install -y libest
+
+ - name: Enroll certificate
+ run: |
+ docker exec -e EST_OPENSSL_CACERT=cacert.pem pki estclient -e -s pki.example.com -p 8443 \
+ --common-name test.example.com -o . -u est-test-user -h Secret.123
+
+ docker exec pki openssl base64 -d --in cert-0-0.pkcs7 --out cert-0-0.pkcs7.der
+ docker exec pki openssl pkcs7 -in cert-0-0.pkcs7.der -inform DER -print_certs -out cert.pem
+ docker exec pki openssl x509 -in cert.pem -subject -noout | tee actual
+ echo "subject=CN=test.example.com" > expected
+ diff expected actual
+
+ - name: Remove EST
+ run: |
+ docker exec pki pki-server est-undeploy --wait
+ docker exec pki pki-server est-remove
+
+ - name: Remove CA
+ run: docker exec pki pkidestroy -i pki-tomcat -s CA -v
+
+ - name: Check DS server systemd journal
+ if: always()
+ run: |
+ docker exec ds journalctl -x --no-pager -u dirsrv@localhost.service
+
+ - name: Check DS container logs
+ if: always()
+ run: |
+ docker logs ds
+
+ - name: Check PKI server systemd journal
+ if: always()
+ run: |
+ docker exec pki journalctl -x --no-pager -u pki-tomcatd@pki-tomcat.service
+
+ - name: Check CA debug log
+ if: always()
+ run: |
+ docker exec pki find /var/lib/pki/pki-tomcat/logs/ca -name "debug.*" -exec cat {} \;
+
+ - name: Check EST debug log
+ if: always()
+ run: |
+ docker exec pki find /var/lib/pki/pki-tomcat/logs/est -name "debug.*" -exec cat {} \;
+
+ - name: Gather artifacts
+ if: always()
+ run: |
+ tests/bin/ds-artifacts-save.sh ds
+ tests/bin/pki-artifacts-save.sh pki
+ continue-on-error: true
+
+ - name: Upload artifacts
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: ca-basic
+ path: /tmp/artifacts
diff --git a/.github/workflows/est-tests.yml b/.github/workflows/est-tests.yml
index 0f195a24a61..4d052e56ad9 100644
--- a/.github/workflows/est-tests.yml
+++ b/.github/workflows/est-tests.yml
@@ -40,3 +40,9 @@ jobs:
ansible-playbook -e 'pki_subsystem="est"' tests/ansible/pki-playbook.yml
env:
ANSIBLE_CONFIG: ${{ github.workspace }}/tests/ansible/ansible.cfg
+
+
+ est-ds-realm-test:
+ name: EST with ds realm
+ needs: build
+ uses: ./.github/workflows/est-ds-realm-test.yml
diff --git a/base/est/CMakeLists.txt b/base/est/CMakeLists.txt
index 4cace31f0d2..73e7f756ef2 100644
--- a/base/est/CMakeLists.txt
+++ b/base/est/CMakeLists.txt
@@ -96,3 +96,24 @@ install(
DESTINATION
${DATA_INSTALL_DIR}/est/webapps/est/WEB-INF/lib
)
+
+install(
+ DIRECTORY
+ shared/
+ DESTINATION
+ ${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}/${PROJECT_NAME}/conf/
+ PATTERN
+ "CMakeLists.txt" EXCLUDE
+)
+
+install(
+ FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/bin/estauthz
+ DESTINATION
+ ${LIBEXEC_INSTALL_DIR}
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ
+
+)
diff --git a/base/est/bin/estauthz b/base/est/bin/estauthz
new file mode 100755
index 00000000000..3fce98cfa1c
--- /dev/null
+++ b/base/est/bin/estauthz
@@ -0,0 +1,7 @@
+#!/usr/bin/python3
+import json, sys
+ALLOWED_ROLE = 'estclient'
+obj = json.loads(sys.stdin.read())
+if not ALLOWED_ROLE in obj['authzData']['principal']['roles']:
+ print(f'Principal does not have required role {ALLOWED_ROLE!r}')
+ sys.exit(1)
diff --git a/base/est/conf/realm.conf b/base/est/conf/realm.conf
deleted file mode 100644
index ccfb9d62813..00000000000
--- a/base/est/conf/realm.conf
+++ /dev/null
@@ -1 +0,0 @@
-class=org.apache.catalina.realm.MemoryRealm
diff --git a/base/est/shared/authorizer.conf b/base/est/shared/authorizer.conf
new file mode 100644
index 00000000000..bb126819b72
--- /dev/null
+++ b/base/est/shared/authorizer.conf
@@ -0,0 +1,2 @@
+class=org.dogtagpki.est.ExternalProcessRequestAuthorizer
+executable=/usr/local/libexec/estauthz
diff --git a/base/est/shared/backend.conf b/base/est/shared/backend.conf
new file mode 100644
index 00000000000..83eeeaa7f64
--- /dev/null
+++ b/base/est/shared/backend.conf
@@ -0,0 +1,5 @@
+class=org.dogtagpki.est.DogtagRABackend
+url=https://fedora:8443
+profile=estServiceCert
+username=est-ra-1
+password=est4ever
diff --git a/base/est/shared/realm/ds.conf b/base/est/shared/realm/ds.conf
new file mode 100644
index 00000000000..150bebfa934
--- /dev/null
+++ b/base/est/shared/realm/ds.conf
@@ -0,0 +1,7 @@
+class=com.netscape.cms.realm.PKILDAPRealm
+url=ldap://localhost.localdomain:389
+authType=BasicAuth
+bindDN=cn=Directory Manager
+bindPassword=Secret.123
+usersDN=ou=people,dc=est,dc=pki,dc=example,dc=com
+groupsDN=ou=groups,dc=est,dc=pki,dc=example,dc=com
\ No newline at end of file
diff --git a/base/est/shared/realm/in-memory.conf b/base/est/shared/realm/in-memory.conf
new file mode 100644
index 00000000000..6182f91923d
--- /dev/null
+++ b/base/est/shared/realm/in-memory.conf
@@ -0,0 +1,4 @@
+class=com.netscape.cms.realm.PKIInMemoryRealm
+username=admin
+password=Secret.123
+roles=estclient
\ No newline at end of file
diff --git a/base/est/shared/realm/postgresql.conf b/base/est/shared/realm/postgresql.conf
new file mode 100644
index 00000000000..8be846d45a5
--- /dev/null
+++ b/base/est/shared/realm/postgresql.conf
@@ -0,0 +1,5 @@
+class=com.netscape.cms.realm.PKIPostgreSQLRealm
+url=jdbc:postgresql://localhost.localdomain:5432/est
+user=est
+password=Secret.123
+statements=/usr/share/pki/est/conf/realm/statements.conf
\ No newline at end of file
diff --git a/base/est/shared/realm/statements.conf b/base/est/shared/realm/statements.conf
new file mode 100644
index 00000000000..f8cc8132942
--- /dev/null
+++ b/base/est/shared/realm/statements.conf
@@ -0,0 +1,31 @@
+getUserByID=\
+SELECT \
+ "id", "full_name", "password" \
+FROM \
+ "users" \
+WHERE \
+ "id" = ?
+
+getUserByCertID=\
+SELECT \
+ u."id", u."full_name", u."password" \
+FROM \
+ "users" u, "user_certs" uc \
+WHERE \
+ u."id" = uc."user_id" AND uc."cert_id" = ?
+
+getUserCerts=\
+SELECT \
+ "data" \
+FROM \
+ "user_certs" \
+WHERE \
+ "user_id" = ?
+
+getUserRoles=\
+SELECT \
+ "group_id" \
+FROM \
+ "group_members" \
+WHERE \
+ "user_id" = ?
\ No newline at end of file
diff --git a/base/est/webapps/est/index.jsp b/base/est/webapps/est/index.jsp
new file mode 100644
index 00000000000..79dca917a14
--- /dev/null
+++ b/base/est/webapps/est/index.jsp
@@ -0,0 +1,25 @@
+
+
+
+ Enrollment over Secure Transport
+
+
+
+
+
diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg
index 642fb019f19..2f3a7605b40 100644
--- a/base/server/etc/default.cfg
+++ b/base/server/etc/default.cfg
@@ -36,8 +36,9 @@ sensitive_parameters=
acme_database_bind_password
acme_database_password
acme_issuer_password
- acme_realm_bind_password
- acme_realm_password
+ est_realm_bind_password
+ est_realm_password
+ est_ca_password
pki_instance_name=pki-tomcat
pki_http_port=8080
@@ -663,3 +664,27 @@ pki_registry_enable=False
# - acme_realm_groups_dn
#
# See /usr/share/pki/acme/realm//realm.conf
+[EST]
+pki_ds_setup=False
+pki_security_domain_setup=False
+pki_registry_enable=False
+pki_ca_uri=https://%(pki_hostname)s:%(pki_https_port)s
+est_ca_profile=estServiceCert
+est_ca_user_name=
+est_ca_user_password=
+est_ca_user_password_file=
+est_ca_user_certificate=
+est_realm_type=
+est_realm_custom=
+est_realm_url=
+est_realm_auth_type=BasicAuth
+est_realm_bind_dn=cn=Directory Manager
+est_realm_bind_password=
+est_realm_nickname=
+est_realm_user=
+est_realm_username=
+est_realm_password=
+est_realm_users_dn=ou=people,dc=est,dc=pki,dc=example,dc=com
+est_realm_groups_dn=ou=groups,dc=est,dc=pki,dc=example,dc=com
+est_realm_statements=/usr/share/pki/est/conf/realm/statements.conf
+est_authorizer_exec_path=/usr/libexec/estauthz
diff --git a/base/server/examples/installation/est.cfg b/base/server/examples/installation/est.cfg
new file mode 100644
index 00000000000..3a64da4694e
--- /dev/null
+++ b/base/server/examples/installation/est.cfg
@@ -0,0 +1,9 @@
+[DEFAULT]
+pki_server_database_password=Secret.123
+
+[EST]
+est_realm_type=ds
+est_realm_url=ldap://localhost.localdomain:3389
+est_realm_bind_password=Secret.123
+est_ca_user_name=est-ra-1
+est_ca_user_password=Secret.est
diff --git a/base/server/python/pki/server/deployment/__init__.py b/base/server/python/pki/server/deployment/__init__.py
index 84e189915c8..8bde79a1461 100644
--- a/base/server/python/pki/server/deployment/__init__.py
+++ b/base/server/python/pki/server/deployment/__init__.py
@@ -5376,15 +5376,135 @@ def spawn_acme(self):
self.deploy_acme_webapp(subsystem)
+ def create_est_subsystem(self):
+ '''
+ See also pki-server acme-create.
+ '''
+
+ logger.info('Creating EST subsystem')
+
+ subsystem = pki.server.subsystem.ESTSubsystem(self.instance)
+ subsystem.create()
+ return subsystem
+
+ def configure_est_backend(self, subsystem):
+ logger.info('Configuring EST backend')
+ props = subsystem.get_backend_config(True)
+ ca_uri = self.mdict.get('pki_ca_uri')
+ pki.util.set_property(props, 'url', ca_uri)
+
+ profile = self.mdict.get('est_ca_profile')
+ pki.util.set_property(props, 'profile', profile)
+
+ username = self.mdict.get('est_ca_user_name')
+ pki.util.set_property(props, 'username', username)
+
+ password = self.mdict.get('est_ca_user_password')
+ pki.util.set_property(props, 'password', password)
+
+ password_file = self.mdict.get('est_ca_user_password_file')
+ pki.util.set_property(props, 'passwordFile', password_file)
+
+ nickname = self.mdict.get('est_ca_user_certificate')
+ pki.util.set_property(props, 'nickname', nickname)
+ subsystem.update_backend_config(props)
+
+ def configure_est_authorizer(self, subsystem):
+
+ logger.info('Configuring EST authorizer')
+ props = subsystem.get_authorizer_config(True)
+
+ authorizer_exec = self.mdict.get('est_authorizer_exec_path')
+ pki.util.set_property(props, 'executable', authorizer_exec)
+ subsystem.update_authorizer_config(props)
+
+ def configure_est_realm(self, subsystem):
+ logger.info('Configuring EST realm')
+
+ if self.mdict['est_realm_custom']:
+ subsystem.replace_realm_config(self.mdict['est_realm_custom'])
+ return
+
+ realm_type = self.mdict['est_realm_type']
+ props = subsystem.get_realm_config(realm_type=realm_type)
+
+ if realm_type == 'in-memory':
+
+ username = self.mdict.get('est_realm_username')
+ pki.util.set_property(props, 'username', username)
+
+ password = self.mdict.get('est_realm_password')
+ pki.util.set_property(props, 'password', password)
+
+ elif realm_type == 'ds':
+
+ url = self.mdict.get('est_realm_url')
+ pki.util.set_property(props, 'url', url)
+
+ auth_type = props.get('authType')
+ auth_type = self.mdict.get('est_realm_auth_type', auth_type)
+ pki.util.set_property(props, 'authType', auth_type)
+
+ if auth_type == 'BasicAuth':
+ bind_dn = self.mdict.get('est_realm_bind_dn')
+ pki.util.set_property(props, 'bindDN', bind_dn)
+
+ bind_password = self.mdict.get('est_realm_bind_password')
+ pki.util.set_property(props, 'bindPassword', bind_password)
+
+ elif auth_type == 'SslClientAuth':
+ nickname = self.mdict.get('est_realm_nickname')
+ pki.util.set_property(props, 'nickname', nickname)
+
+ users_dn = self.mdict.get('est_realm_users_dn')
+ pki.util.set_property(props, 'usersDN', users_dn)
+
+ groups_dn = self.mdict.get('est_realm_groups_dn')
+ pki.util.set_property(props, 'groupsDN', groups_dn)
+
+ elif realm_type == 'postgresql':
+
+ url = self.mdict.get('est_realm_url')
+ pki.util.set_property(props, 'url', url)
+
+ user = self.mdict.get('est_realm_user')
+ pki.util.set_property(props, 'user', user)
+
+ password = self.mdict.get('est_realm_password')
+ pki.util.set_property(props, 'password', password)
+
+ statements = self.mdict.get('est_realm_statements')
+ pki.util.set_property(props, 'statements', statements)
+ subsystem.update_realm_config(props)
+
+ def deploy_est_webapp(self, subsystem):
+ '''
+ See also pki-server est-deploy.
+ '''
+
+ logger.info('Deploying EST webapp')
if len(self.instance.get_subsystems()) == 1:
- # if this is the first subsystem, start the server
- self.instance.start(
+ # if this is the first subsystem, deploy the subsystem without waiting
+ subsystem.enable()
+
+ else:
+ # otherwise, deploy the subsystem and wait until it starts
+ subsystem.enable(
wait=True,
max_wait=self.startup_timeout,
timeout=self.request_timeout)
- def spawn(self):
+ def spawn_est(self):
+ subsystem = self.create_est_subsystem()
+ self.instance.add_subsystem(subsystem)
+
+ self.configure_est_backend(subsystem)
+ self.configure_est_authorizer(subsystem)
+ self.configure_est_realm(subsystem)
+ self.deploy_est_webapp(subsystem)
+
+ def spawn(self):
print('Installing ' + self.subsystem_type + ' into ' + self.instance.base_dir + '.')
scriptlet = pki.server.deployment.scriptlets.initialization.PkiScriptlet()
@@ -5406,6 +5526,10 @@ def spawn(self):
self.spawn_acme()
return
+ if self.subsystem_type == 'EST':
+ self.spawn_est()
+ return
+
scriptlet = pki.server.deployment.scriptlets.subsystem_layout.PkiScriptlet()
scriptlet.deployer = self
scriptlet.instance = self.instance
diff --git a/base/server/python/pki/server/deployment/pkiconfig.py b/base/server/python/pki/server/deployment/pkiconfig.py
index 5793401436b..ae6be596fd8 100644
--- a/base/server/python/pki/server/deployment/pkiconfig.py
+++ b/base/server/python/pki/server/deployment/pkiconfig.py
@@ -36,7 +36,7 @@
PKI_DEPLOYMENT_DEFAULT_UID = 17
PKI_DEPLOYMENT_DEFAULT_USER = "pkiuser"
-PKI_SUBSYSTEMS = ['CA', 'KRA', 'OCSP', 'TKS', 'TPS', 'ACME']
+PKI_SUBSYSTEMS = ['CA', 'KRA', 'OCSP', 'TKS', 'TPS', 'ACME', 'EST']
PKI_BASE_RESERVED_NAMES = ["alias", "bin", "ca", "common", "conf", "kra",
"lib", "logs", "ocsp", "temp", "tks", "tps",
"webapps", "work"]
diff --git a/base/server/python/pki/server/deployment/scriptlets/initialization.py b/base/server/python/pki/server/deployment/scriptlets/initialization.py
index 5639b2448ff..b3d2e89f72c 100644
--- a/base/server/python/pki/server/deployment/scriptlets/initialization.py
+++ b/base/server/python/pki/server/deployment/scriptlets/initialization.py
@@ -41,8 +41,9 @@ def verify_sensitive_data(self, deployer):
configuration_file = deployer.configuration_file
# Verify existence of Admin Password (except for Clones)
- if configuration_file.subsystem != 'ACME' and \
- not configuration_file.clone:
+ if (configuration_file.subsystem != 'ACME' and
+ configuration_file.subsystem != 'EST' and not
+ configuration_file.clone):
configuration_file.confirm_data_exists('pki_admin_password')
# If HSM, verify absence of all PKCS #12 backup parameters
@@ -64,7 +65,8 @@ def verify_sensitive_data(self, deployer):
configuration_file.confirm_data_exists('pki_client_database_password')
# Verify existence of Client PKCS #12 Password for Admin Cert
- if configuration_file.subsystem != 'ACME':
+ if (configuration_file.subsystem != 'ACME' and
+ configuration_file.subsystem != 'EST'):
configuration_file.confirm_data_exists('pki_client_pkcs12_password')
if configuration_file.clone:
diff --git a/base/server/python/pki/server/pkispawn.py b/base/server/python/pki/server/pkispawn.py
index 43c76c38d52..f104416c9bf 100644
--- a/base/server/python/pki/server/pkispawn.py
+++ b/base/server/python/pki/server/pkispawn.py
@@ -190,8 +190,8 @@ def main(argv):
parser.indent = 0
deployer.subsystem_type = parser.read_text(
- 'Subsystem (CA/KRA/OCSP/TKS/TPS/ACME)',
- options=['CA', 'KRA', 'OCSP', 'TKS', 'TPS', 'ACME'],
+ 'Subsystem (CA/KRA/OCSP/TKS/TPS/ACME/EST)',
+ options=['CA', 'KRA', 'OCSP', 'TKS', 'TPS', 'ACME', 'EST'],
default='CA', case_sensitive=False).upper()
print()
else:
@@ -672,6 +672,9 @@ def main(argv):
elif deployer.subsystem_type == 'ACME':
print_acme_install_information()
+ elif deployer.subsystem_type == 'EST':
+ print_est_install_information()
+
else:
print_final_install_information(parser.mdict, deployer.instance)
@@ -693,7 +696,8 @@ def validate_user_deployment_cfg(user_deployment_cfg):
'[OCSP]',
'[TKS]',
'[TPS]',
- '[ACME]']:
+ '[ACME]',
+ '[EST]']:
raise Exception('Invalid deployment configuration section: %s' % line)
@@ -952,6 +956,16 @@ def print_acme_install_information():
print(log.PKI_SPAWN_INFORMATION_FOOTER)
+def print_est_install_information():
+
+ print(log.PKI_SPAWN_INFORMATION_HEADER)
+
+ print(log.PKI_ACCESS_URL % (deployer.mdict['pki_hostname'],
+ deployer.mdict['pki_https_port'],
+ '.well-known/%s' % deployer.subsystem_type.lower()))
+ print(log.PKI_SPAWN_INFORMATION_FOOTER)
+
+
def print_final_install_information(mdict, instance):
print(log.PKI_SPAWN_INFORMATION_HEADER)
diff --git a/base/server/python/pki/server/subsystem.py b/base/server/python/pki/server/subsystem.py
index dfa5cc28961..3908f93becd 100644
--- a/base/server/python/pki/server/subsystem.py
+++ b/base/server/python/pki/server/subsystem.py
@@ -2857,6 +2857,116 @@ def update_realm_config(self, config):
self.instance.store_properties(self.realm_conf, config)
+class ESTSubsystem(PKISubsystem):
+
+ def __init__(self, instance):
+ super().__init__(instance, 'est')
+
+ @property
+ def backend_conf(self):
+ return os.path.join(self.conf_dir, 'backend.conf')
+
+ @property
+ def authorizer_conf(self):
+ return os.path.join(self.conf_dir, 'authorizer.conf')
+
+ @property
+ def realm_conf(self):
+ return os.path.join(self.conf_dir, 'realm.conf')
+
+ def create(self, exist_ok=False, force=False):
+
+ self.instance.makedirs(self.conf_dir, exist_ok=exist_ok)
+
+ default_conf_dir = os.path.join(pki.server.PKIServer.SHARE_DIR, 'est', 'conf')
+
+ self.instance.copy(
+ os.path.join(default_conf_dir, 'backend.conf'),
+ self.backend_conf,
+ exist_ok=exist_ok,
+ force=force)
+
+ self.instance.copy(
+ os.path.join(default_conf_dir, 'authorizer.conf'),
+ self.authorizer_conf,
+ exist_ok=exist_ok,
+ force=force)
+
+ def get_backend_config(self, default=False):
+
+ if default:
+ backend_conf = os.path.join(
+ pki.server.PKIServer.SHARE_DIR,
+ 'est',
+ 'conf',
+ 'backend.conf')
+ else:
+ backend_conf = self.backend_conf
+
+ logger.info('Loading %s', backend_conf)
+ config = {}
+ pki.util.load_properties(backend_conf, config)
+ return config
+
+ def update_backend_config(self, config):
+
+ logger.info('Updating %s', self.backend_conf)
+ self.instance.store_properties(self.backend_conf, config)
+
+ def get_authorizer_config(self, default=False):
+
+ if default:
+ authorizer_conf = os.path.join(
+ pki.server.PKIServer.SHARE_DIR,
+ 'est',
+ 'conf',
+ 'authorizer.conf')
+ else:
+ authorizer_conf = self.authorizer_conf
+
+ logger.info('Loading %s', authorizer_conf)
+ config = {}
+ pki.util.load_properties(authorizer_conf, config)
+
+ return config
+
+ def update_authorizer_config(self, config):
+
+ logger.info('Updating %s', self.authorizer_conf)
+ self.instance.store_properties(self.authorizer_conf, config)
+
+ def get_realm_config(self, realm_type=None):
+
+ template_dir = os.path.join(pki.server.PKIServer.SHARE_DIR, 'est', 'conf', 'realm')
+
+ if realm_type:
+ # if realm type is specified, load the realm.conf template
+ realm_conf = os.path.join(template_dir, '%s.conf' % realm_type)
+ else:
+ # otherwise, load the current realm.conf in the instance
+ realm_conf = self.realm_conf
+
+ logger.info('Loading %s', realm_conf)
+ config = {}
+ pki.util.load_properties(realm_conf, config)
+
+ return config
+
+ def update_realm_config(self, config):
+
+ logger.info('Updating %s', self.realm_conf)
+ self.instance.store_properties(self.realm_conf, config)
+
+ def replace_realm_config(self, realm_path):
+
+ logger.info('Replace %s', self.realm_conf)
+ self.instance.copy(
+ realm_path,
+ self.realm_conf,
+ exist_ok=False,
+ force=True)
+
+
class PKISubsystemFactory(object):
@classmethod
diff --git a/pki.spec b/pki.spec
index e875d88e66a..47a2d6666cd 100644
--- a/pki.spec
+++ b/pki.spec
@@ -72,8 +72,8 @@ ExcludeArch: i686
%else
# Use Java 21 on Fedora 40+ and RHEL 10, otherwise use Java 17.
-%global java_devel java-devel >= 1:17
-%global java_headless java-headless >= 1:17
+%global java_devel java-devel >= 1:21
+%global java_headless java-headless >= 1:21
# Don't use find since it might not work well with local builds.
# find {_jvmdir} -maxdepth 1 | grep "jre-[0-9]\+$"
@@ -1867,6 +1867,7 @@ fi
################################################################################
%{_datadir}/pki/est/
+%{_libexecdir}/estauthz
%if %{without maven}
%{_datadir}/java/pki/pki-est.jar