diff --git a/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlConfiguration.java b/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlConfiguration.java index 6e2353225b0db9148d2f4007e536af46b4c5a3e4..49653afe48c0ca74dfc8ba9387f043d00c2538a6 100644 --- a/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlConfiguration.java +++ b/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlConfiguration.java @@ -37,7 +37,7 @@ public class SamlConfiguration { @Bean @DependsOn("xmlObjectProviderRegistry") - SamlServiceRegistry samServiceRegistry(TokenValidationProperties tokenValidationProperties) { + SamlServiceRegistry samlServiceRegistry(TokenValidationProperties tokenValidationProperties) { var registryBuilder = SamlServiceRegistry.builder(); for (var tokenEntity : tokenValidationProperties.getEntities()) { registryBuilder.samlService(tokenEntity.getIdpEntityId(), samlTokenService(tokenEntity)); diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/GrpcOtherFieldsTestFactory.java b/token-checker-server/src/test/java/de/ozgcloud/token/GrpcOtherFieldTestFactory.java similarity index 90% rename from token-checker-server/src/test/java/de/ozgcloud/token/GrpcOtherFieldsTestFactory.java rename to token-checker-server/src/test/java/de/ozgcloud/token/GrpcOtherFieldTestFactory.java index e9dcd4587a6c23cf37b04c5f1a0d6b2a9b09a383..6ddcb93f30f64d0c6a0ec883c9beb3a7f2aa06ee 100644 --- a/token-checker-server/src/test/java/de/ozgcloud/token/GrpcOtherFieldsTestFactory.java +++ b/token-checker-server/src/test/java/de/ozgcloud/token/GrpcOtherFieldTestFactory.java @@ -1,6 +1,6 @@ package de.ozgcloud.token; -public class GrpcOtherFieldsTestFactory { +public class GrpcOtherFieldTestFactory { public static final String VALUE = TokenAttributeTestFactory.VALUE; public static final String NAME = TokenAttributeTestFactory.NAME; diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/GrpcTokenAttributesTestFactory.java b/token-checker-server/src/test/java/de/ozgcloud/token/GrpcTokenAttributesTestFactory.java index d967e6b2e1503b09964d09a712a960b69d050f87..5c92d7c28d64a807bfd5c97a1ae246261a818d23 100644 --- a/token-checker-server/src/test/java/de/ozgcloud/token/GrpcTokenAttributesTestFactory.java +++ b/token-checker-server/src/test/java/de/ozgcloud/token/GrpcTokenAttributesTestFactory.java @@ -24,7 +24,7 @@ class GrpcTokenAttributesTestFactory { public static final String POSTFACH_ID = TokenAttributesTestFactory.POSTFACH_ID; public static final String TRUST_LEVEL = TokenAttributesTestFactory.TRUST_LEVEL; - public static final GrpcOtherField TOKEN_ATTRIBUTE = GrpcOtherFieldsTestFactory.create(); + public static final GrpcOtherField TOKEN_ATTRIBUTE = GrpcOtherFieldTestFactory.create(); public static GrpcTokenAttributes create() { return createBuilder().build(); diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/TokenCheckGrpcServiceITCase.java b/token-checker-server/src/test/java/de/ozgcloud/token/TokenCheckGrpcServiceITCase.java index c2c24b47fa6061b16a8157cc03190303dc1a0d3b..2aa772fb43a1bc08306f0085a3a93e95584f8935 100644 --- a/token-checker-server/src/test/java/de/ozgcloud/token/TokenCheckGrpcServiceITCase.java +++ b/token-checker-server/src/test/java/de/ozgcloud/token/TokenCheckGrpcServiceITCase.java @@ -32,25 +32,27 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; import de.ozgcloud.common.test.ITCase; import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.token.saml.SamlTrustEngineFactoryTestConfiguration; import net.devh.boot.grpc.client.inject.GrpcClient; -@ITCase -@SpringBootTest(properties = { - "grpc.server.inProcessName=test", - "grpc.client.token-checker.address=in-process:test", -}) -@Import(SamlTrustEngineFactoryTestConfiguration.class) public class TokenCheckGrpcServiceITCase { - @GrpcClient("token-checker") - private TokenCheckServiceGrpc.TokenCheckServiceBlockingStub tokenCheckerStub; - @Nested - class TestCheckToken { + @ITCase + @SpringBootTest(properties = { + "grpc.server.inProcessName=test", + "grpc.client.token-checker.address=in-process:test", + }) + @Import(SamlTrustEngineFactoryTestConfiguration.class) + @DirtiesContext + class TestCheckTokenSuccessfully { + + @GrpcClient("token-checker") + private TokenCheckServiceGrpc.TokenCheckServiceBlockingStub tokenCheckerStub; private static final String POSTFACH_ID = "28721c6f-b78f-4d5c-a048-19fd2fc429d2"; private static final String TRUST_LEVEL = "STORK-QAA-Level-1"; @@ -72,11 +74,7 @@ public class TokenCheckGrpcServiceITCase { assertThat(result.getTokenAttributes().getPostfachId()).isEqualTo(POSTFACH_ID); assertThat(result.getTokenAttributes().getTrustLevel()).isEqualTo(TRUST_LEVEL); - assertThat(getOtherFields(result)).isNotEmpty().doesNotContainKeys(TokenAttribute.POSTFACH_ID_KEY, TokenAttribute.TRUST_LEVEL_KEY); - } - - private GrpcCheckTokenRequest buildCheckTokenRequest(String token) { - return GrpcCheckTokenRequest.newBuilder().setToken(token).build(); + assertThat(getOtherFields(result)).isNotEmpty().doesNotContainKeys(TokenAttributes.POSTFACH_ID_KEY, TokenAttributes.TRUST_LEVEL_KEY); } private Map<String, String> getOtherFields(GrpcCheckTokenResponse result) { @@ -84,4 +82,33 @@ public class TokenCheckGrpcServiceITCase { .collect(Collectors.toMap(GrpcOtherField::getName, GrpcOtherField::getValue)); } } + + @Nested + @ITCase + @SpringBootTest(properties = { + "grpc.server.inProcessName=test", + "grpc.client.token-checker.address=in-process:test", + }) + @DirtiesContext + class TestCheckTokenFailure { + + @GrpcClient("token-checker") + private TokenCheckServiceGrpc.TokenCheckServiceBlockingStub tokenCheckerStub; + + @Test + void shouldAcceptToken() { + var token = TestUtils.loadTextFile("SamlResponseBayernId.xml"); + + var result = tokenCheckerStub.checkToken(buildCheckTokenRequest(token)); + + assertThat(result.getTokenValid()).isFalse(); + assertThat(result.getCheckErrors().getCheckErrorList()).hasSize(1).first().extracting(GrpcCheckError::getMessage).asString() + .contains("Invalid token signature"); + } + + } + + private GrpcCheckTokenRequest buildCheckTokenRequest(String token) { + return GrpcCheckTokenRequest.newBuilder().setToken(token).build(); + } } diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java index 9d22ec18ad28b2e656d23ffbdebe25f8d62c0a07..f5e1b1abb503f357700a849471afd5706340c372 100644 --- a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java +++ b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java @@ -31,15 +31,14 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Random; -import java.util.SimpleTimeZone; import java.util.UUID; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; @@ -58,21 +57,19 @@ import org.opensaml.saml.saml2.core.Statement; import org.opensaml.saml.saml2.encryption.Decrypter; import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; import org.opensaml.security.SecurityException; +import org.opensaml.xmlsec.encryption.support.DecryptionException; import org.opensaml.xmlsec.signature.Signature; import org.opensaml.xmlsec.signature.support.SignatureException; import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; -import org.testcontainers.shaded.org.checkerframework.checker.units.qual.N; import com.thedeanda.lorem.LoremIpsum; -import de.ozgcloud.token.TokenAttribute; import de.ozgcloud.token.TokenAttributeTestFactory; import de.ozgcloud.token.TokenAttributes; import de.ozgcloud.token.TokenAttributesTestFactory; import de.ozgcloud.token.TokenValidationProperties.TokenValidationProperty; import de.ozgcloud.token.common.errorhandling.TokenVerificationException; import de.ozgcloud.token.common.errorhandling.ValidationError; -import lombok.Builder; import lombok.SneakyThrows; import net.shibboleth.utilities.java.support.resolver.CriteriaSet; @@ -112,33 +109,33 @@ class SamlAttributeServiceTest { @Test void shouldCallValidateToken() { - validate(); + getAttributes(); - verify(service).getAttributes(token); + verify(service).validateToken(token); } @Test void shouldCallDecryptAttributes() { - validate(); + getAttributes(); verify(service).decryptSamlAttributes(token); } @Test void shouldCallBuildTokenAttributes() { - validate(); + getAttributes(); verify(service).buildTokenAttributes(TOKEN_ATTRIBUTES_MAP, token); } @Test void shouldReturnResult() { - var result = validate(); + var result = getAttributes(); assertThat(result).isSameAs(tokenAttributes); } - private TokenAttributes validate() { + private TokenAttributes getAttributes() { return service.getAttributes(token); } } @@ -410,26 +407,33 @@ class SamlAttributeServiceTest { @Mock private Assertion assertion; - @SneakyThrows - @BeforeEach - void init() { - doReturn(assertion).when(decrypter).decrypt(any(EncryptedAssertion.class)); - } - @Test @SneakyThrows void shouldDecryptAssertion() { + when(decrypter.decrypt(any(EncryptedAssertion.class))).thenReturn(assertion); + service.decryptAssertion(encryptedAssertion); verify(decrypter).decrypt(encryptedAssertion); } @Test + @SneakyThrows void shouldReturnResult() { + when(decrypter.decrypt(any(EncryptedAssertion.class))).thenReturn(assertion); + var result = service.decryptAssertion(encryptedAssertion); assertThat(result).isEqualTo(assertion); } + + @SneakyThrows + @Test + void shouldThrowException() { + when(decrypter.decrypt(any(EncryptedAssertion.class))).thenThrow(DecryptionException.class); + + assertThrows(TokenVerificationException.class, () -> service.decryptAssertion(encryptedAssertion)); + } } @Nested @@ -537,9 +541,10 @@ class SamlAttributeServiceTest { assertThat(result).isEqualTo(String.valueOf(value)); } - @Test - void shouldReturnWhenXSBoolean() { - var value = String.valueOf(new Random().nextBoolean()); + @DisplayName("should return value of XSBoolean when") + @ParameterizedTest(name = "value is {0}") + @ValueSource(strings = { "true", "false" }) + void shouldReturnWhenXSBoolean(String value) { XMLObject attrValue = when(mock(XSBoolean.class).getValue()).thenReturn(XSBooleanValue.valueOf(value)).getMock(); var result = service.getAttributeValue(attrValue); diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlConfigurationTest.java b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlConfigurationTest.java index cd5cf96edf55515ef3afcf887d3ece84049975a6..78d6ed09c04855e530418483ac6b45a271faffad 100644 --- a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlConfigurationTest.java +++ b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlConfigurationTest.java @@ -76,14 +76,14 @@ class SamlConfigurationTest { @Test void shouldCallSamlTokenService() { - configuration.samServiceRegistry(tokenValidationProperties); + configuration.samlServiceRegistry(tokenValidationProperties); verify(configuration).samlTokenService(tokenValidationProperty); } @Test void shouldAddService() { - var result = configuration.samServiceRegistry(tokenValidationProperties); + var result = configuration.samlServiceRegistry(tokenValidationProperties); assertThat(result.getService(IDP_ENTITY_ID)).contains(tokenValidationService); } diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlTrustEngineFactoryTest.java b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlTrustEngineFactoryTest.java index 5260ac4de919a94735df39ddbbe41279e63e6aee..7d40d60227a60a08535b84b5f1b81d85a0470984 100644 --- a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlTrustEngineFactoryTest.java +++ b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlTrustEngineFactoryTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.io.InputStream; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; import java.util.Optional; @@ -48,6 +49,7 @@ import org.opensaml.core.xml.XMLObject; import org.opensaml.core.xml.config.XMLObjectProviderRegistry; import org.opensaml.core.xml.io.Unmarshaller; import org.opensaml.core.xml.io.UnmarshallerFactory; +import org.opensaml.core.xml.io.UnmarshallingException; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml.saml2.metadata.EntityDescriptor; @@ -69,6 +71,7 @@ import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.token.TokenValidationProperties.TokenValidationProperty; import lombok.SneakyThrows; import net.shibboleth.utilities.java.support.xml.ParserPool; +import net.shibboleth.utilities.java.support.xml.XMLParserException; class SamlTrustEngineFactoryTest { @@ -270,43 +273,69 @@ class SamlTrustEngineFactoryTest { @Mock private Element element; - @BeforeEach - @SneakyThrows - void init() { - when(parserPool.parse(any(InputStream.class))).thenReturn(document); - when(document.getDocumentElement()).thenReturn(element); - doReturn(unmarshaller).when(factory).getUnmarshaller(any()); - when(unmarshaller.unmarshall(element)).thenReturn(xmlObject); - } + @Nested + class TestSuccessfully { + @BeforeEach + @SneakyThrows + void init() { + when(parserPool.parse(any(InputStream.class))).thenReturn(document); + when(document.getDocumentElement()).thenReturn(element); + doReturn(unmarshaller).when(factory).getUnmarshaller(any()); + when(unmarshaller.unmarshall(element)).thenReturn(xmlObject); + } - @Test - @SneakyThrows - void shouldCallParse() { - getXmlObject(); + @Test + @SneakyThrows + void shouldCallParse() { + getXmlObject(); - verify(parserPool).parse(inputStream); - } + verify(parserPool).parse(inputStream); + } - @Test - void shouldCallGetUnmarshaller() { - getXmlObject(); + @Test + void shouldCallGetUnmarshaller() { + getXmlObject(); - verify(factory).getUnmarshaller(element); - } + verify(factory).getUnmarshaller(element); + } - @Test - @SneakyThrows - void shouldCallUnmarshall() { - getXmlObject(); + @Test + @SneakyThrows + void shouldCallUnmarshall() { + getXmlObject(); + + verify(unmarshaller).unmarshall(element); + } - verify(unmarshaller).unmarshall(element); + @Test + void shouldReturnResult() { + var result = getXmlObject(); + + assertThat(result).isEqualTo(xmlObject); + } } - @Test - void shouldReturnResult() { - var result = getXmlObject(); + @Nested + class TestWithException { + + @SneakyThrows + @Test + void shouldThrowExceptionIfXMLParseException() { + when(parserPool.parse(any(InputStream.class))).thenThrow(XMLParserException.class); + + assertThrows(TechnicalException.class, TestGetXmlObject.this::getXmlObject); + } - assertThat(result).isEqualTo(xmlObject); + @SneakyThrows + @Test + void shouldThrowExceptionIfUnmarshallingException() { + when(parserPool.parse(any(InputStream.class))).thenReturn(document); + when(document.getDocumentElement()).thenReturn(element); + doReturn(unmarshaller).when(factory).getUnmarshaller(any()); + when(unmarshaller.unmarshall(element)).thenThrow(UnmarshallingException.class); + + assertThrows(TechnicalException.class, TestGetXmlObject.this::getXmlObject); + } } private XMLObject getXmlObject() { @@ -602,6 +631,17 @@ class SamlTrustEngineFactoryTest { } } + @Test + void shouldThrowException() { + try (var keyInfoSupportMock = mockStatic(KeyInfoSupport.class)) { + keyInfoSupportMock.when(() -> KeyInfoSupport.getCertificates(any(KeyInfo.class))).thenThrow(CertificateException.class); + + assertThrows(TechnicalException.class, this::getCertificates); + + keyInfoSupportMock.verify(() -> KeyInfoSupport.getCertificates(keyInfo)); + } + } + private List<X509Certificate> getCertificates() { return factory.getCertificates(keyDescriptor).toList(); }