import pki-core-10.9.4-3.module+el8.3.0+10353+73f6df5b
This commit is contained in:
parent
41013f3800
commit
4a7a035137
@ -0,0 +1,170 @@
|
||||
From 8b3cb80954a932867c2d4d96eb1cced83fa78996 Mon Sep 17 00:00:00 2001
|
||||
From: Fraser Tweedale <ftweedal@redhat.com>
|
||||
Date: Wed, 13 Jan 2021 18:27:46 +1100
|
||||
Subject: [PATCH] Fix renewal profile approval process
|
||||
|
||||
Due to a recent change in PKI CLI, the CLI now passes along user
|
||||
authentication with submissions to the renewal endpoint. Unlike the EE
|
||||
pages, the REST API has passed along this authentication for a while.
|
||||
Due to a bug in the RenewalProcessor, requests with credentials against
|
||||
profiles with no authentication method and no ACLs result in the
|
||||
certificiate automatically being approved. This occurs because, when
|
||||
an earlier commit (cb9eb967b5e24f5fde8bbf8ae87aa615b7033db7) modified
|
||||
the code to allow Light-Weight SubCAs to issue certificates, validation
|
||||
wasn't done on the passed principal, to see if it was a trusted agent.
|
||||
Because profiles requring Agent approval have an empty ACL list (as, no
|
||||
user should be able to submit a certificate request and have it
|
||||
automatically signed without agent approval), authorize allows any user
|
||||
to approve this request and thus accepts the AuthToken.
|
||||
|
||||
Critical analysis: the RenewalProcessor code interprets (authToken
|
||||
!= null) as evidence that the authenticated user is /authorized/ to
|
||||
immediately issue the certificate. This mismatch of concerns (authn
|
||||
vs authz) resulted in a misunderstanding of system behaviour. The
|
||||
"latent" AuthToken (from the HTTP request) was assigned to authToken
|
||||
without realising that authorization needed to be performed.
|
||||
|
||||
We fix this by splitting the logic on whether the profile defines an
|
||||
authenticator. If so, we (re)authenticate and authorize the user
|
||||
according to the profile configuration.
|
||||
|
||||
If the profile does not define an authenticator but there is a
|
||||
principal in the HTTP request, if (and only if) the user has
|
||||
permission to approve certificate requests *and* the requested
|
||||
renewal profile is caManualRenewal (which is hardcoded to be used
|
||||
for LWCA renewal), then we issue the certificate immediately. This
|
||||
special case ensures that LWCA renewal keeps working.
|
||||
|
||||
Otherwise, if there is no principal in the HTTP request or the
|
||||
principal does not have permission to approve certificate requests,
|
||||
we leave the authToken unset. The resulting renewal request will be
|
||||
created with status PENDING, i.e. enqueued for agent review.
|
||||
|
||||
Signed-off-by: Fraser Tweedale <ftweedal@redhat.com>
|
||||
Signed-off-by: Alexander Scheel <ascheel@redhat.com>
|
||||
---
|
||||
.../com/netscape/ca/CertificateAuthority.java | 10 +++
|
||||
.../cms/servlet/cert/RenewalProcessor.java | 75 +++++++++++++++++--
|
||||
2 files changed, 79 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
|
||||
index 07f29fead..50292201b 100644
|
||||
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
|
||||
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
|
||||
@@ -2962,6 +2962,16 @@ public class CertificateAuthority
|
||||
}
|
||||
|
||||
ProfileSubsystem ps = engine.getProfileSubsystem();
|
||||
+ /* NOTE: hard-coding the profile to use for Lightweight CA renewal
|
||||
+ * might be OK, but caManualRenewal was not the right one to use.
|
||||
+ * As a consequence, we have an undesirable special case in
|
||||
+ * RenewalProcessor.processRenewal().
|
||||
+ *
|
||||
+ * We should introduce a new profile specifically for LWCA renewal,
|
||||
+ * with an authenticator and ACLs to match the authz requirements
|
||||
+ * for the renewAuthority REST resource itself. Then we can use
|
||||
+ * it here, and remove the workaround from RenewalProcessor.
|
||||
+ */
|
||||
Profile profile = ps.getProfile("caManualRenewal");
|
||||
CertEnrollmentRequest req = CertEnrollmentRequestFactory.create(
|
||||
new ArgBlock(), profile, httpReq.getLocale());
|
||||
diff --git a/base/ca/src/com/netscape/cms/servlet/cert/RenewalProcessor.java b/base/ca/src/com/netscape/cms/servlet/cert/RenewalProcessor.java
|
||||
index 917c64856..75677b5e4 100644
|
||||
--- a/base/ca/src/com/netscape/cms/servlet/cert/RenewalProcessor.java
|
||||
+++ b/base/ca/src/com/netscape/cms/servlet/cert/RenewalProcessor.java
|
||||
@@ -31,6 +31,7 @@ import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
+import org.dogtagpki.server.authorization.AuthzToken;
|
||||
import org.mozilla.jss.netscape.security.x509.BasicConstraintsExtension;
|
||||
import org.mozilla.jss.netscape.security.x509.X509CertImpl;
|
||||
|
||||
@@ -267,16 +268,78 @@ public class RenewalProcessor extends CertProcessor {
|
||||
|
||||
// before creating the request, authenticate the request
|
||||
IAuthToken authToken = null;
|
||||
- Principal principal = request.getUserPrincipal();
|
||||
- if (principal instanceof PKIPrincipal)
|
||||
- authToken = ((PKIPrincipal) principal).getAuthToken();
|
||||
- if (authToken == null && authenticator != null) {
|
||||
- authToken = authenticate(request, origReq, authenticator, context, true, credentials);
|
||||
+
|
||||
+ if (authenticator != null) {
|
||||
+ /* The profile specifies an authenticator. Use it to
|
||||
+ * authenticate the user. Ignore the "latent" session
|
||||
+ * principal (if any).
|
||||
+ */
|
||||
+ authToken = authenticate(
|
||||
+ request,
|
||||
+ origReq,
|
||||
+ authenticator,
|
||||
+ context,
|
||||
+ true /* isRenewal */,
|
||||
+ credentials);
|
||||
+ } else {
|
||||
+ /* When authenticator is null, we expect manual agent
|
||||
+ * review (leave authToken as null).
|
||||
+ *
|
||||
+ * But as a special case to ensure Lightweight CA (LWCA)
|
||||
+ * renewal works, if there is a latent user in the HTTP
|
||||
+ * request, we use that user (i.e. set authToken to the
|
||||
+ * principal's IAuthToken) if and only if:
|
||||
+ *
|
||||
+ * - The renewal profile is caManualRenewal (LWCA renewal
|
||||
+ * is hardcoded to use this profile); AND
|
||||
+ *
|
||||
+ * - The latent user is authorized to "execute"
|
||||
+ * certificate requests (i.e. agent approval)
|
||||
+ *
|
||||
+ * See also CertificateAuthority.renewAuthority().
|
||||
+ */
|
||||
+
|
||||
+ Principal principal = request.getUserPrincipal();
|
||||
+ if (
|
||||
+ renewProfileId.equals("caManualRenewal")
|
||||
+ && principal instanceof PKIPrincipal
|
||||
+ ) {
|
||||
+ IAuthToken latentToken = ((PKIPrincipal) principal).getAuthToken();
|
||||
+ AuthzToken authzToken = authorize(
|
||||
+ "DirAclAuthz", latentToken, "certServer.ca.certrequests", "execute");
|
||||
+ if (authzToken != null) {
|
||||
+ // Success (no exception); user is authorized to approve
|
||||
+ // cert requests. Set the authToken.
|
||||
+ //
|
||||
+ // NOTE: This authz does not replace or subsume the
|
||||
+ // profile-specific authz check below.
|
||||
+ authToken = latentToken;
|
||||
+ } else {
|
||||
+ // leave authToken as null to enqueue a pending request.
|
||||
+ }
|
||||
+ } else {
|
||||
+ // not caManualRenewal or no latent principal;
|
||||
+ // leave authToken as null to enqueue a pending request.
|
||||
+ }
|
||||
}
|
||||
|
||||
- // authentication success, now authorize
|
||||
+ /* Authorize the request.
|
||||
+ *
|
||||
+ * If authToken != null, it will be checked against ACLs specified
|
||||
+ * in the profile (if any). If ACLs are defined and authToken does
|
||||
+ * not match, throws an authorization exception.
|
||||
+ *
|
||||
+ * If authToken == null, no check is performed (even if the profile
|
||||
+ * defines ACLs). This is fine, because null authToken will cause
|
||||
+ * the request status to be 'pending' [agent approval].
|
||||
+ */
|
||||
authorize(profileId, renewProfile, authToken);
|
||||
|
||||
+ /* At this point, the request will be created. If authToken
|
||||
+ * is non-null, then the certificate will be issued
|
||||
+ * immediately. Otherwise the request will be pending. */
|
||||
+
|
||||
+
|
||||
///////////////////////////////////////////////
|
||||
// create and populate requests
|
||||
///////////////////////////////////////////////
|
||||
--
|
||||
2.29.2
|
||||
|
@ -0,0 +1,80 @@
|
||||
From d17df6f22376753b5cd156f1b7f51837cae1f522 Mon Sep 17 00:00:00 2001
|
||||
From: jmagne <jmagne@redhat.com>
|
||||
Date: Mon, 22 Feb 2021 13:44:20 -0800
|
||||
Subject: [PATCH] pkispawn fails against 389-ds 1.4.3.19 #3458 (#3465)
|
||||
|
||||
Add suggested patch from stanislavlevin to solve this issue.
|
||||
Also add f34 to the ipa tests,this time really add the tests.
|
||||
Upon further review, back out of f34 tests until the infractructure
|
||||
supports it.
|
||||
|
||||
Also hardcode tomcat app setting in spec file for the moment to
|
||||
avoid possible glitches on certain platform.
|
||||
|
||||
Co-authored-by: Jack Magne <jmagne@localhost.localdomain>
|
||||
---
|
||||
.../com/netscape/cmscore/apps/CMSEngine.java | 18 +++++++-----------
|
||||
1 file changed, 7 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/base/server/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/src/com/netscape/cmscore/apps/CMSEngine.java
|
||||
index 295c4d4cc..f40f99136 100644
|
||||
--- a/base/server/src/com/netscape/cmscore/apps/CMSEngine.java
|
||||
+++ b/base/server/src/com/netscape/cmscore/apps/CMSEngine.java
|
||||
@@ -156,9 +156,8 @@ public class CMSEngine {
|
||||
|
||||
private static final int PW_OK =0;
|
||||
//private static final int PW_BAD_SETUP = 1;
|
||||
- private static final int PW_INVALID_PASSWORD = 2;
|
||||
+ private static final int PW_INVALID_CREDENTIALS = 2;
|
||||
private static final int PW_CANNOT_CONNECT = 3;
|
||||
- private static final int PW_NO_USER = 4;
|
||||
private static final int PW_MAX_ATTEMPTS = 3;
|
||||
|
||||
|
||||
@@ -332,16 +331,16 @@ public class CMSEngine {
|
||||
}
|
||||
|
||||
int iteration = 0;
|
||||
- int result = PW_INVALID_PASSWORD;
|
||||
+ int result = PW_INVALID_CREDENTIALS;
|
||||
|
||||
do {
|
||||
String passwd = mPasswordStore.getPassword(tag, iteration);
|
||||
result = testLDAPConnection(tag, connInfo, binddn, passwd);
|
||||
iteration++;
|
||||
- } while ((result == PW_INVALID_PASSWORD) && (iteration < PW_MAX_ATTEMPTS));
|
||||
+ } while ((result == PW_INVALID_CREDENTIALS) && (iteration < PW_MAX_ATTEMPTS));
|
||||
|
||||
if (result != PW_OK) {
|
||||
- if ((result == PW_NO_USER) && (tag.equals("replicationdb"))) {
|
||||
+ if ((result == PW_INVALID_CREDENTIALS) && (tag.equals("replicationdb"))) {
|
||||
logger.warn(
|
||||
"CMSEngine: password test execution failed for replicationdb " +
|
||||
"with NO_SUCH_USER. This may not be a latest instance. Ignoring ..");
|
||||
@@ -364,7 +363,7 @@ public class CMSEngine {
|
||||
int ret = PW_OK;
|
||||
|
||||
if (StringUtils.isEmpty(pwd)) {
|
||||
- return PW_INVALID_PASSWORD;
|
||||
+ return PW_INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
String host = info.getHost();
|
||||
@@ -383,12 +382,9 @@ public class CMSEngine {
|
||||
|
||||
switch (e.getLDAPResultCode()) {
|
||||
case LDAPException.NO_SUCH_OBJECT:
|
||||
- logger.debug("CMSEngine: user does not exist: " + binddn);
|
||||
- ret = PW_NO_USER;
|
||||
- break;
|
||||
case LDAPException.INVALID_CREDENTIALS:
|
||||
- logger.debug("CMSEngine: invalid password");
|
||||
- ret = PW_INVALID_PASSWORD;
|
||||
+ logger.debug("CMSEngine: invalid credentials");
|
||||
+ ret = PW_INVALID_CREDENTIALS;
|
||||
break;
|
||||
default:
|
||||
logger.debug("CMSEngine: unable to connect to " + name + ": " + e.getMessage());
|
||||
--
|
||||
2.29.2
|
||||
|
@ -13,7 +13,7 @@ License: GPLv2 and LGPLv2
|
||||
# For development (unsupported) releases, use x.y.z-0.n.unstable with alpha/beta phase.
|
||||
# For official (supported) releases, use x.y.z-r where r >=1 without alpha/beta phase.
|
||||
Version: 10.9.4
|
||||
Release: 1%{?_timestamp}%{?_commit_id}%{?dist}
|
||||
Release: 3%{?_timestamp}%{?_commit_id}%{?dist}
|
||||
#global _phase -a1
|
||||
|
||||
# To create a tarball from a version tag:
|
||||
@ -36,6 +36,8 @@ Source: https://github.com/dogtagpki/pki/archive/v%{version}%{?_phase}/pki-%{ver
|
||||
# BUILDSTDERR: Download error on https://pypi.org/simple/pytest-runner/:
|
||||
# [Errno 111] Connection refused -- Some packages may not be found!
|
||||
Patch1: 0001-Removed-dependency-on-pytest-runner.patch
|
||||
Patch2: 0001-CVE-2021-20179-Fix-renewal-profile-approval-process.patch
|
||||
Patch3: 0004-pkispawn-fails-against-389-ds-1.4.3.19-3458-3465.patch
|
||||
|
||||
################################################################################
|
||||
# NSS
|
||||
@ -1363,6 +1365,12 @@ fi
|
||||
|
||||
################################################################################
|
||||
%changelog
|
||||
* Thu Mar 11 2021 Red Hat PKI Team <rhcs-maint@redhat.com> 10.9.4-3
|
||||
- Bug # 1933146 - PKI instance creation failed with new 389-ds-base build
|
||||
|
||||
* Thu Feb 11 2021 Red Hat PKI Team <rhcs-maint@redhat.com> 10.9.4-2
|
||||
- CVE-2021-20179: Fix unprivileged users can renew any certificate
|
||||
|
||||
* Fri Sep 11 2020 Red Hat PKI Team <rhcs-maint@redhat.com> 10.9.4-1
|
||||
- Rebased to PKI 10.9.4
|
||||
- Red Hat Bugzilla #1873235 - Fix SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT in pki ca-user-cert-add
|
||||
|
Loading…
Reference in New Issue
Block a user