diff options
author | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2022-07-21 14:56:51 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2022-07-21 15:30:19 +0200 |
commit | f4965306b79f0015ca9e8e32072877e57f7f532c (patch) | |
tree | c3bc93a0916de30dcb70435531c1aa850b27c51c /security-utils/src/main | |
parent | d2864cf3be9a93d784ac98b6beee0813dc60b290 (diff) |
Move logic for capability checking/logging to ConnectionAuthContext
Diffstat (limited to 'security-utils/src/main')
3 files changed, 63 insertions, 9 deletions
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java b/security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java index ec402719efa..7e6c7f394cd 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/CapabilitySet.java @@ -30,15 +30,17 @@ public class CapabilitySet { ; private final String name; - private final EnumSet<Capability> caps; + private final CapabilitySet set; Predefined(String name, Capability... caps) { this.name = name; - this.caps = caps.length == 0 ? EnumSet.noneOf(Capability.class) : EnumSet.copyOf(List.of(caps)); } + this.set = caps.length == 0 ? CapabilitySet.none() : CapabilitySet.from(caps); } public static Optional<Predefined> fromName(String name) { return Arrays.stream(values()).filter(p -> p.name.equals(name)).findAny(); } + + public CapabilitySet capabilities() { return set; } } private static final CapabilitySet ALL_CAPABILITIES = new CapabilitySet(EnumSet.allOf(Capability.class)); @@ -52,7 +54,7 @@ public class CapabilitySet { EnumSet<Capability> caps = EnumSet.noneOf(Capability.class); for (String name : names) { Predefined predefined = Predefined.fromName(name).orElse(null); - if (predefined != null) caps.addAll(predefined.caps); + if (predefined != null) caps.addAll(predefined.set.caps); else caps.add(Capability.fromName(name)); } return new CapabilitySet(caps); diff --git a/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java b/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java index b4e8878fb01..a28dab16d08 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/ConnectionAuthContext.java @@ -7,28 +7,77 @@ import java.security.cert.X509Certificate; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; +import java.util.logging.Logger; import static com.yahoo.security.SubjectAlternativeName.Type.DNS; import static com.yahoo.security.SubjectAlternativeName.Type.URI; +import static com.yahoo.security.tls.CapabilityMode.DISABLE; +import static com.yahoo.security.tls.CapabilityMode.LOG_ONLY; /** * @author bjorncs */ public record ConnectionAuthContext(List<X509Certificate> peerCertificateChain, CapabilitySet capabilities, - Set<String> matchedPolicies) { + Set<String> matchedPolicies, + CapabilityMode capabilityMode) { - private static final ConnectionAuthContext DEFAULT_ALL_CAPABILITIES = new ConnectionAuthContext(List.of()); + private static final Logger log = Logger.getLogger(ConnectionAuthContext.class.getName()); public ConnectionAuthContext { peerCertificateChain = List.copyOf(peerCertificateChain); matchedPolicies = Set.copyOf(matchedPolicies); } - private ConnectionAuthContext(List<X509Certificate> certs) { this(certs, CapabilitySet.all(), Set.of()); } + private ConnectionAuthContext(List<X509Certificate> certs, CapabilityMode capabilityMode) { + this(certs, CapabilitySet.all(), Set.of(), capabilityMode); + } public boolean authorized() { return !capabilities.hasNone(); } + public boolean hasCapabilities(CapabilitySet requiredCapabilities) { + return hasCapabilities(requiredCapabilities, null, null, null); + } + + /** Provided strings are used for improved logging only */ + public boolean hasCapabilities(CapabilitySet requiredCapabilities, String action, String resource, String peer) { + if (capabilityMode == DISABLE) return authorized(); + boolean hasCapabilities = capabilities.has(requiredCapabilities); + if (!hasCapabilities) { + Supplier<String> errorMessageProvider = () -> + createPermissionDeniedErrorMessage(requiredCapabilities, action, resource, peer); + if (capabilityMode == LOG_ONLY) { + log.info(errorMessageProvider); + return true; + } else { + // Ideally log as warning but we have no mechanism for de-duplicating repeated log spamming. + log.fine(errorMessageProvider); + return false; + } + } + return true; + } + + String createPermissionDeniedErrorMessage( + CapabilitySet required, String action, String resource, String peer) { + StringBuilder b = new StringBuilder(); + if (capabilityMode == LOG_ONLY) b.append("Dry-run: "); + b.append("Permission denied"); + if (resource != null) { + b.append(" for '"); + if (action != null) { + b.append(action).append("' on '"); + } + b.append(resource).append("'"); + } + b.append(". Peer "); + if (peer != null) b.append("'").append(peer).append("' "); + return b.append("with ").append(peerCertificateString()).append(". Requires capabilities ") + .append(required.toNames()).append(" but peer has ").append(capabilities.toNames()) + .append(".").toString(); + } + public Optional<X509Certificate> peerCertificate() { return peerCertificateChain.isEmpty() ? Optional.empty() : Optional.of(peerCertificateChain.get(0)); } @@ -62,11 +111,11 @@ public record ConnectionAuthContext(List<X509Certificate> peerCertificateChain, } /** Construct instance with all capabilities */ - public static ConnectionAuthContext defaultAllCapabilities() { return DEFAULT_ALL_CAPABILITIES; } + public static ConnectionAuthContext defaultAllCapabilities() { return new ConnectionAuthContext(List.of(), DISABLE); } /** Construct instance with all capabilities */ public static ConnectionAuthContext defaultAllCapabilities(List<X509Certificate> certs) { - return new ConnectionAuthContext(certs); + return new ConnectionAuthContext(certs, DISABLE); } } diff --git a/security-utils/src/main/java/com/yahoo/security/tls/PeerAuthorizer.java b/security-utils/src/main/java/com/yahoo/security/tls/PeerAuthorizer.java index 44293de6eb7..951b5c57c9e 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/PeerAuthorizer.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/PeerAuthorizer.java @@ -47,7 +47,10 @@ public class PeerAuthorizer { grantedCapabilities.add(peerPolicy.capabilities()); } } - return new ConnectionAuthContext(certChain, CapabilitySet.unionOf(grantedCapabilities), matchedPolicies); + // TODO Pass this through constructor + CapabilityMode capabilityMode = TransportSecurityUtils.getCapabilityMode(); + return new ConnectionAuthContext( + certChain, CapabilitySet.unionOf(grantedCapabilities), matchedPolicies, capabilityMode); } private static boolean matchesPolicy(PeerPolicy peerPolicy, String cn, List<String> sans) { |