From f8d417dc03175f3de9cbe372732d80594c891954 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 21 Apr 2025 08:32:07 -0600 Subject: [PATCH] Preserve Encrypted Elements Closes gh-16367 --- .../saml2/internal/OpenSaml4Template.java | 12 +--- .../authentication/OpenSaml4Template.java | 12 +--- .../logout/OpenSaml4Template.java | 12 +--- .../service/metadata/OpenSaml4Template.java | 12 +--- .../registration/OpenSaml4Template.java | 12 +--- .../service/web/OpenSaml4Template.java | 12 +--- .../web/authentication/OpenSaml4Template.java | 12 +--- .../logout/OpenSaml4Template.java | 12 +--- .../OpenSaml4AuthenticationProviderTests.java | 60 ++++++++++++++++++- .../saml2/internal/OpenSaml5Template.java | 12 +--- .../authentication/OpenSaml5Template.java | 12 +--- .../logout/OpenSaml5Template.java | 12 +--- .../service/metadata/OpenSaml5Template.java | 12 +--- .../registration/OpenSaml5Template.java | 12 +--- .../service/web/OpenSaml5Template.java | 12 +--- .../web/authentication/OpenSaml5Template.java | 12 +--- .../logout/OpenSaml5Template.java | 12 +--- .../OpenSaml5AuthenticationProviderTests.java | 60 ++++++++++++++++++- 18 files changed, 134 insertions(+), 178 deletions(-) diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java index 002c0862e1..c8df5a3649 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/internal/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java index f529b8b4a0..4892b7593a 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java index 5344d080dc..f177502cc4 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java index 8cd40194fe..dd1197f95c 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java index a56bcf8100..bb6201b423 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java index b2ca1e1111..db7810cf06 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java index 9ca1253379..62949ae27a 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java index eee4fc8242..399072fc2c 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml4Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml4Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml4Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml4Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml4Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java index ef45985419..cdccc13c13 100644 --- a/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -386,6 +386,24 @@ public class OpenSaml4AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAssertionWithSignatureThenEncryptedAssertionStillAvailable() { + Response response = response(); + Assertion assertion = TestOpenSamlObjects.signed(assertion(), + TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID); + EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + response.getEncryptedAssertions().add(encryptedAssertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + provider.setResponseValidator((t) -> { + assertThat(t.getResponse().getEncryptedAssertions()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAssertionWithResponseSignatureThenItSucceeds() { Response response = response(); @@ -410,6 +428,26 @@ public class OpenSaml4AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedNameIdWithSignatureThenEncryptedNameIdStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + NameID nameId = assertion.getSubject().getNameID(); + EncryptedID encryptedID = TestOpenSamlObjects.encrypted(nameId, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + assertion.getSubject().setNameID(null); + assertion.getSubject().setEncryptedID(encryptedID); + response.getAssertions().add(signed(assertion)); + Saml2AuthenticationToken token = token(response, decrypting(verifying(registration()))); + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getSubject().getEncryptedID()).isNotNull(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAttributeThenDecrypts() { Response response = response(); @@ -426,6 +464,26 @@ public class OpenSaml4AuthenticationProviderTests { assertThat(principal.getAttribute("name")).containsExactly("value"); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAttributeThenEncryptedAttributesStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + EncryptedAttribute attribute = TestOpenSamlObjects.encrypted("name", "value", + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + AttributeStatement statement = build(AttributeStatement.DEFAULT_ELEMENT_NAME); + statement.getEncryptedAttributes().add(attribute); + assertion.getAttributeStatements().add(statement); + response.getAssertions().add(assertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getAttributeStatements().get(0).getEncryptedAttributes()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() { Response response = response(); diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java index ef74e61c97..fdeffc915a 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/internal/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java index b2003af461..c5b6ff98ae 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java index d0add4c54c..576bee21dc 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java index e5a39122a3..99b18df8ae 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/metadata/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java index 50f60e5a0d..399fedf577 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/registration/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java index 73b3d9f391..62da91197a 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java index db40f084ee..305dd60440 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java index 2d095694f5..c7abef6236 100644 --- a/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java +++ b/saml2/saml2-service-provider/src/opensaml5Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml5Template.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -482,7 +482,6 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptResponse(Response response) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); int count = 0; int size = response.getEncryptedAssertions().size(); @@ -492,7 +491,6 @@ final class OpenSaml5Template implements OpenSamlOperations { try { Assertion decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } count++; @@ -502,7 +500,6 @@ final class OpenSaml5Template implements OpenSamlOperations { } } - response.getEncryptedAssertions().removeAll(encrypteds); response.getAssertions().addAll(decrypteds); // Re-marshall the response so that any ID attributes within the decrypted @@ -534,7 +531,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(d.getEncryptedID()); if (decrypted != null) { d.setNameID(decrypted); - d.setEncryptedID(null); } } catch (DecryptionException ex) { @@ -548,12 +544,10 @@ final class OpenSaml5Template implements OpenSamlOperations { private void decryptAttributes(AttributeStatement statement) { Collection decrypteds = new ArrayList<>(); - Collection encrypteds = new ArrayList<>(); for (EncryptedAttribute encrypted : statement.getEncryptedAttributes()) { try { Attribute decrypted = this.decrypter.decrypt(encrypted); if (decrypted != null) { - encrypteds.add(encrypted); decrypteds.add(decrypted); } } @@ -561,7 +555,6 @@ final class OpenSaml5Template implements OpenSamlOperations { throw new Saml2Exception(ex); } } - statement.getEncryptedAttributes().removeAll(encrypteds); statement.getAttributes().addAll(decrypteds); } @@ -572,7 +565,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(subject.getEncryptedID()); if (decrypted != null) { subject.setNameID(decrypted); - subject.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -586,7 +578,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(sc.getEncryptedID()); if (decrypted != null) { sc.setNameID(decrypted); - sc.setEncryptedID(null); } } catch (final DecryptionException ex) { @@ -603,7 +594,6 @@ final class OpenSaml5Template implements OpenSamlOperations { NameID decrypted = (NameID) this.decrypter.decrypt(request.getEncryptedID()); if (decrypted != null) { request.setNameID(decrypted); - request.setEncryptedID(null); } } catch (DecryptionException ex) { diff --git a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java index 22ed0e89b6..284c7a90c3 100644 --- a/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java +++ b/saml2/saml2-service-provider/src/opensaml5Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml5AuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -386,6 +386,24 @@ public class OpenSaml5AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAssertionWithSignatureThenEncryptedAssertionStillAvailable() { + Response response = response(); + Assertion assertion = TestOpenSamlObjects.signed(assertion(), + TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID); + EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + response.getEncryptedAssertions().add(encryptedAssertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setResponseValidator((t) -> { + assertThat(t.getResponse().getEncryptedAssertions()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAssertionWithResponseSignatureThenItSucceeds() { Response response = response(); @@ -410,6 +428,26 @@ public class OpenSaml5AuthenticationProviderTests { this.provider.authenticate(token); } + // gh-16367 + @Test + public void authenticateWhenEncryptedNameIdWithSignatureThenEncryptedNameIdStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + NameID nameId = assertion.getSubject().getNameID(); + EncryptedID encryptedID = TestOpenSamlObjects.encrypted(nameId, + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + assertion.getSubject().setNameID(null); + assertion.getSubject().setEncryptedID(encryptedID); + response.getAssertions().add(signed(assertion)); + Saml2AuthenticationToken token = token(response, decrypting(verifying(registration()))); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getSubject().getEncryptedID()).isNotNull(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenEncryptedAttributeThenDecrypts() { Response response = response(); @@ -426,6 +464,26 @@ public class OpenSaml5AuthenticationProviderTests { assertThat(principal.getAttribute("name")).containsExactly("value"); } + // gh-16367 + @Test + public void authenticateWhenEncryptedAttributeThenEncryptedAttributesStillAvailable() { + Response response = response(); + Assertion assertion = assertion(); + EncryptedAttribute attribute = TestOpenSamlObjects.encrypted("name", "value", + TestSaml2X509Credentials.assertingPartyEncryptingCredential()); + AttributeStatement statement = build(AttributeStatement.DEFAULT_ELEMENT_NAME); + statement.getEncryptedAttributes().add(attribute); + assertion.getAttributeStatements().add(statement); + response.getAssertions().add(assertion); + Saml2AuthenticationToken token = token(signed(response), decrypting(verifying(registration()))); + OpenSaml5AuthenticationProvider provider = new OpenSaml5AuthenticationProvider(); + provider.setAssertionValidator((t) -> { + assertThat(t.getAssertion().getAttributeStatements().get(0).getEncryptedAttributes()).isNotEmpty(); + return Saml2ResponseValidatorResult.success(); + }); + provider.authenticate(token); + } + @Test public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() { Response response = response();