[java-identity-provider] branch main updated: IDP-1716 - X509 flow within MFA and subject canonicalization

Scott Cantor cantor.2 at osu.edu
Fri Jan 22 00:50:30 UTC 2021


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=3e62435100aacd2330b92477d75994557aa2a3d1

The following commit(s) were added to refs/heads/main by this push:
       new  3e6243510 IDP-1716 - X509 flow within MFA and subject canonicalization
3e6243510 is described below

commit 3e62435100aacd2330b92477d75994557aa2a3d1
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Jan 21 19:50:26 2021 -0500

    IDP-1716 - X509 flow within MFA and subject canonicalization
    
    https://issues.shibboleth.net/jira/browse/IDP-1716
    
    Serialize certificates in authentication results.
---
 .../DefaultAuthenticationResultSerializer.java     | 47 +++++++++++++++++++---
 .../DefaultAuthenticationResultSerializerTest.java | 27 ++++++++++++-
 2 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
index 1b2339bcd..9e5eed795 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
@@ -21,6 +21,9 @@ import java.io.IOException;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.security.Principal;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -54,11 +57,14 @@ import net.shibboleth.idp.authn.principal.PrincipalServiceManager;
 import net.shibboleth.idp.authn.principal.impl.AuthenticationResultPrincipalSerializer;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.codec.Base64Support;
+import net.shibboleth.utilities.java.support.codec.EncodingException;
 import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
+import org.opensaml.security.x509.X509Support;
 import org.opensaml.storage.StorageSerializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -82,6 +88,9 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
     /** Field name of public credentials array. */
     @Nonnull @NotEmpty private static final String PUB_CREDS_ARRAY_FIELD = "pub";
 
+    /** Field name of X.509 certificates array. */
+    @Nonnull @NotEmpty private static final String X509_CREDS_ARRAY_FIELD = "x509";
+
     /** Field name of private credentials array. */
     @Nonnull @NotEmpty private static final String PRIV_CREDS_ARRAY_FIELD = "priv";
     
@@ -181,6 +190,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
         }
     }
 
+// Checkstyle: CyclomaticComplexity|MethodLength OFF
     /** {@inheritDoc} */
     @Nonnull @NotEmpty public String serialize(@Nonnull final AuthenticationResult instance) throws IOException {
         ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
@@ -222,7 +232,21 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
                 gen.writeEnd();
             }
             
-            // TODO handle custom creds
+            final Set<X509Certificate> x509Creds = instance.getSubject().getPublicCredentials(X509Certificate.class);
+            if (x509Creds != null && !x509Creds.isEmpty()) {
+                gen.writeStartArray(X509_CREDS_ARRAY_FIELD);
+                for (final X509Certificate x : x509Creds) {
+                    try {
+                        gen.write(Base64Support.encode(x.getEncoded(), false));
+                    } catch (final CertificateEncodingException|EncodingException e) {
+                        log.warn("Unable to serialize X.509 certificate with subject: {}",
+                                x.getSubjectDN().toString());
+                    }
+                }
+                gen.writeEnd();
+            }
+            
+            // TODO handle other creds
 
             gen.writeEnd().close();
 
@@ -231,8 +255,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             throw new IOException("Exception while serializing AuthenticationResult", e);
         }
     }
-    
-    // Checkstyle: CyclomaticComplexity OFF
+
     /** {@inheritDoc} */
     @Nonnull public AuthenticationResult deserialize(final long version, @Nonnull @NotEmpty final String context,
                     @Nonnull @NotEmpty final String key, @Nonnull @NotEmpty final String value,
@@ -294,8 +317,22 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
                     }
                 }
             }
+            
+            final JsonArray x509Creds = obj.getJsonArray(X509_CREDS_ARRAY_FIELD);
+            if (x509Creds != null) {
+                for (final JsonValue val : x509Creds) {
+                    if (val.getValueType() == ValueType.STRING) {
+                        try {
+                            final X509Certificate cert = X509Support.decodeCertificate(val.toString());
+                            result.getSubject().getPublicCredentials().add(cert);
+                        } catch (final CertificateException e) {
+                            log.warn("Unable to parse certificate", e);
+                        }
+                    }
+                }
+            }
 
-            // TODO handle custom creds
+            // TODO handle other creds
 
             return result;
 
@@ -303,7 +340,7 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
             throw new IOException("Found invalid data structure while parsing AuthenticationResult", e);
         }
     }
- // Checkstyle: CyclomaticComplexity ON
+ // Checkstyle: CyclomaticComplexity|MethodLength ON
 
     /**
      * Attempt to serialize a principal with the registered and default serializers.
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java
index 758df202d..db1071f1b 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java
@@ -62,6 +62,7 @@ import org.ldaptive.SortBehavior;
 import org.ldaptive.jaas.LdapPrincipal;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.testing.RequestContextBuilder;
+import org.opensaml.security.x509.X509Support;
 import org.springframework.core.io.ClassPathResource;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -80,7 +81,28 @@ public class DefaultAuthenticationResultSerializerTest {
     private static final Instant INSTANT = Instant.ofEpochMilli(1378827849463L);
     
     private static final long ACTIVITY = 1378827556778L;
-    
+
+    private static final String entityCertBase64 = 
+            "MIIDjDCCAnSgAwIBAgIBKjANBgkqhkiG9w0BAQUFADAtMRIwEAYDVQQKEwlJbnRl" +
+            "cm5ldDIxFzAVBgNVBAMTDmNhLmV4YW1wbGUub3JnMB4XDTA3MDQwOTA2MTIwOVoX" +
+            "DTE3MDQwNjA2MTIwOVowMTESMBAGA1UEChMJSW50ZXJuZXQyMRswGQYDVQQDExJm" +
+            "b29iYXIuZXhhbXBsZS5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB" +
+            "AQDNWnkFmhy1vYa6gN/xBRKkZxFy3sUq2V0LsYb6Q3pe9Qlb6+BzaM5DrN8uIqqr" +
+            "oBE3Wp0LtrgKuQTpDpNFBdS2p5afiUtOYLWBDtizTOzs3Z36MGMjIPUYQ4s03IP3" +
+            "yPh2ud6EKpDPiYqzNbkRaiIwmYSit5r+RMYvd6fuKvTOn6h7PZI5AD7Rda7VWh5O" +
+            "VSoZXlRx3qxFho+mZhW0q4fUfTi5lWwf4EhkfBlzgw/k5gf4cOi6rrGpRS1zxmbt" +
+            "X1RAg+I20z6d04g0N2WsK5stszgYKoIROJCiXwjraa8/SoFcILolWQpttVHBIUYl" +
+            "yDlm8mIFleZf4ReFpfm+nUYxAgMBAAGjgbIwga8wCQYDVR0TBAIwADAsBglghkgB" +
+            "hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE" +
+            "FDgRgTkjaKoK6DoZfUZ4g9LDJUWuMFUGA1UdIwROMEyAFNXuZVPeUdqHrULqQW7y" +
+            "r9buRpQLoTGkLzAtMRIwEAYDVQQKEwlJbnRlcm5ldDIxFzAVBgNVBAMTDmNhLmV4" +
+            "YW1wbGUub3JnggEBMA0GCSqGSIb3DQEBBQUAA4IBAQCPj3Si4Eiw9abNgPBUhBXW" +
+            "d6eRYlIHaHcnez6j6g7foAOyuVIUso9Q5c6pvL87lmasK55l09YPXw1qmiH+bHMc" +
+            "rwEPODpLx7xd3snlOCi7FyxahxwSs8yfTu8Pq95rWt0LNcfHxQK938Cpnav6jgDo" +
+            "2uH/ywAOFFSnoBzGHAfScHMfj8asZ6THosYsklII7FSU8j49GV2utkvGB3mcu4ST" +
+            "uLdeRCZmi93vq1D4JVGsXC4UaHjg114+a+9q0XZdz6a1UW4pt1ryXIPotCS62M71" +
+            "pkJf5neHUinKAqgoRfPXowudZg1Zl8DjzoOBn+MNHRrR5KYbVGvdHcxoJLCwVB/v";
+
     private PrincipalServiceManager manager;
     
     private DefaultAuthenticationResultSerializer serializer;
@@ -117,7 +139,7 @@ public class DefaultAuthenticationResultSerializerTest {
                 new GenericPrincipalService<>(ProxyAuthenticationPrincipal.class, proxySerializer);
         proxyService.setId("proxy");
         proxyService.initialize();
-
+        
         final ClassPathResource keystoreResource = new ClassPathResource("/net/shibboleth/idp/authn/impl/SealerKeyStore.jks");
         final ClassPathResource versionResource = new ClassPathResource("/net/shibboleth/idp/authn/impl/SealerKeyStore.kver");
 
@@ -255,6 +277,7 @@ public class DefaultAuthenticationResultSerializerTest {
         
         final AuthenticationResult result = createResult(flowDescriptor, new Subject());
         result.getSubject().getPrincipals().add(new UsernamePrincipal("bob"));
+        result.getSubject().getPublicCredentials().add(X509Support.decodeCertificate(entityCertBase64));
         result.getSubject().getPrivateCredentials().add(new PasswordPrincipal("bar"));
 
         final ProfileRequestContext prc = getProfileRequestContext(Collections.singletonList(flowDescriptor));

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list