diff options
author | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2022-07-13 16:53:43 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2022-07-15 15:35:10 +0200 |
commit | eed3e5deaf3fd13c353361e45420735a93d0f3d0 (patch) | |
tree | b4e738c5cf85775153237ec07ea08f4e97d224f1 /security-utils/src/main | |
parent | ff26daaf31ec0567dc6a9049d5e275cf7c4810dc (diff) |
Return granted capabilities from PeerAuthorizer
Introduce new ConnectionAuthContext as replacement for AuthorizationResult/SecurityContext.
Diffstat (limited to 'security-utils/src/main')
5 files changed, 46 insertions, 53 deletions
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/AuthorizationResult.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/AuthorizationResult.java deleted file mode 100644 index 6fa97e30d63..00000000000 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/AuthorizationResult.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.security.tls.authz; - -import java.util.Collections; -import java.util.Objects; -import java.util.Set; - -/** - * @author bjorncs - */ -public class AuthorizationResult { - private final Set<String> matchedPolicies; - - public AuthorizationResult(Set<String> matchedPolicies) { - this.matchedPolicies = Collections.unmodifiableSet(matchedPolicies); - } - - public Set<String> matchedPolicies() { - return matchedPolicies; - } - - public boolean succeeded() { - return matchedPolicies.size() > 0; - } - - @Override - public String toString() { - return "AuthorizationResult{" + - ", matchedPolicies=" + matchedPolicies + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - AuthorizationResult that = (AuthorizationResult) o; - return Objects.equals(matchedPolicies, that.matchedPolicies); - } - - @Override - public int hashCode() { - return Objects.hash(matchedPolicies); - } -} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java new file mode 100644 index 00000000000..a5fb51da763 --- /dev/null +++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/ConnectionAuthContext.java @@ -0,0 +1,23 @@ +package com.yahoo.security.tls.authz; + +import com.yahoo.security.tls.policy.CapabilitySet; + +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * @author bjorncs + */ +public record ConnectionAuthContext(List<X509Certificate> peerCertificate, + CapabilitySet capabilities, + SortedSet<String> matchedPolicies) { + + public ConnectionAuthContext { + matchedPolicies = new TreeSet<>(matchedPolicies); + } + + public boolean succeeded() { return matchedPolicies.size() > 0; } + +} diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java index 8c4e87c1de2..353f704b136 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizer.java @@ -4,6 +4,7 @@ package com.yahoo.security.tls.authz; import com.yahoo.security.SubjectAlternativeName; import com.yahoo.security.X509CertificateUtils; import com.yahoo.security.tls.policy.AuthorizedPeers; +import com.yahoo.security.tls.policy.CapabilitySet; import com.yahoo.security.tls.policy.PeerPolicy; import com.yahoo.security.tls.policy.RequiredPeerCredential; @@ -12,6 +13,8 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.logging.Logger; import static com.yahoo.security.SubjectAlternativeName.Type.DNS_NAME; @@ -34,17 +37,19 @@ public class PeerAuthorizer { this.authorizedPeers = authorizedPeers; } - public AuthorizationResult authorizePeer(X509Certificate peerCertificate) { - Set<String> matchedPolicies = new HashSet<>(); + public ConnectionAuthContext authorizePeer(X509Certificate peerCertificate) { + SortedSet<String> matchedPolicies = new TreeSet<>(); + Set<CapabilitySet> grantedCapabilities = new HashSet<>(); String cn = getCommonName(peerCertificate).orElse(null); List<String> sans = getSubjectAlternativeNames(peerCertificate); log.fine(() -> String.format("Subject info from x509 certificate: CN=[%s], 'SAN=%s", cn, sans)); for (PeerPolicy peerPolicy : authorizedPeers.peerPolicies()) { if (matchesPolicy(peerPolicy, cn, sans)) { matchedPolicies.add(peerPolicy.policyName()); + grantedCapabilities.add(peerPolicy.capabilities()); } } - return new AuthorizationResult(matchedPolicies); + return new ConnectionAuthContext(List.of(peerCertificate), CapabilitySet.unionOf(grantedCapabilities), matchedPolicies); } private static boolean matchesPolicy(PeerPolicy peerPolicy, String cn, List<String> sans) { diff --git a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java index e8d558205c4..925e21c63ff 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/authz/PeerAuthorizerTrustManager.java @@ -26,7 +26,7 @@ import java.util.logging.Logger; // Note: Implementation assumes that provided X509ExtendedTrustManager will throw IllegalArgumentException when chain is empty or null public class PeerAuthorizerTrustManager extends X509ExtendedTrustManager { - public static final String HANDSHAKE_SESSION_AUTHZ_RESULT_PROPERTY = "vespa.tls.authorization.result"; + public static final String HANDSHAKE_SESSION_AUTH_CONTEXT_PROPERTY = "vespa.tls.auth.ctx"; private static final Logger log = Logger.getLogger(PeerAuthorizerTrustManager.class.getName()); @@ -98,18 +98,18 @@ public class PeerAuthorizerTrustManager extends X509ExtendedTrustManager { /** * Note: The authorization result is only available during handshake. The underlying handshake session is removed once handshake is complete. */ - public static Optional<AuthorizationResult> getAuthorizationResult(SSLEngine sslEngine) { + public static Optional<ConnectionAuthContext> getAuthorizationResult(SSLEngine sslEngine) { return Optional.ofNullable(sslEngine.getHandshakeSession()) - .flatMap(session -> Optional.ofNullable((AuthorizationResult) session.getValue(HANDSHAKE_SESSION_AUTHZ_RESULT_PROPERTY))); + .flatMap(session -> Optional.ofNullable((ConnectionAuthContext) session.getValue(HANDSHAKE_SESSION_AUTH_CONTEXT_PROPERTY))); } private void authorizePeer(X509Certificate certificate, String authType, boolean isVerifyingClient, SSLEngine sslEngine) throws CertificateException { if (mode == AuthorizationMode.DISABLE) return; log.fine(() -> "Verifying certificate: " + createInfoString(certificate, authType, isVerifyingClient)); - AuthorizationResult result = authorizer.authorizePeer(certificate); + ConnectionAuthContext result = authorizer.authorizePeer(certificate); if (sslEngine != null) { // getHandshakeSession() will never return null in this context - sslEngine.getHandshakeSession().putValue(HANDSHAKE_SESSION_AUTHZ_RESULT_PROPERTY, result); + sslEngine.getHandshakeSession().putValue(HANDSHAKE_SESSION_AUTH_CONTEXT_PROPERTY, result); } if (result.succeeded()) { log.fine(() -> String.format("Verification result: %s", result)); diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java index 44ff1eedfb0..46a07972fc3 100644 --- a/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java +++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java @@ -3,10 +3,12 @@ package com.yahoo.security.tls.policy; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.stream.Collectors; @@ -56,6 +58,12 @@ public class CapabilitySet { return new CapabilitySet(caps); } + public static CapabilitySet unionOf(Collection<CapabilitySet> capSets) { + EnumSet<Capability> union = EnumSet.noneOf(Capability.class); + capSets.forEach(cs -> union.addAll(cs.caps)); + return new CapabilitySet(union); + } + public static CapabilitySet from(EnumSet<Capability> caps) { return new CapabilitySet(EnumSet.copyOf(caps)); } public static CapabilitySet from(Collection<Capability> caps) { return new CapabilitySet(EnumSet.copyOf(caps)); } public static CapabilitySet from(Capability... caps) { return new CapabilitySet(EnumSet.copyOf(List.of(caps))); } @@ -68,6 +76,8 @@ public class CapabilitySet { return caps.stream().map(Capability::asString).collect(Collectors.toCollection(TreeSet::new)); } + public Set<Capability> asSet() { return Collections.unmodifiableSet(caps); } + @Override public String toString() { return "CapabilitySet{" + |