diff --git a/core/src/main/java/org/keycloak/sdjwt/SdJwtFacade.java b/core/src/main/java/org/keycloak/sdjwt/SdJwtFacade.java deleted file mode 100644 index 8a025988605..00000000000 --- a/core/src/main/java/org/keycloak/sdjwt/SdJwtFacade.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2024 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.sdjwt; - -import java.util.List; - -import org.keycloak.common.VerificationException; -import org.keycloak.crypto.SignatureSignerContext; -import org.keycloak.crypto.SignatureVerifierContext; - -import com.fasterxml.jackson.databind.node.ObjectNode; - - -/** - * Simplified service for creating and managing SD-JWTs with easy-to-use methods. - * - * @author Rodrick Awambeng - */ -public class SdJwtFacade { - - private final SignatureSignerContext signer; - private final String hashAlgorithm; - private final String jwsType; - - public SdJwtFacade(SignatureSignerContext signer, String hashAlgorithm, String jwsType) { - this.signer = signer; - this.hashAlgorithm = hashAlgorithm; - this.jwsType = jwsType; - } - - /** - * Create a new SD-JWT with the provided claim set and disclosure specification. - * - * @param claimSet The claim set in JSON format. - * @param disclosureSpec The disclosure specification. - * @return A new SD-JWT. - */ - public SdJwt createSdJwt(ObjectNode claimSet, DisclosureSpec disclosureSpec) { - IssuerSignedJWT issuerSignedJWT = new IssuerSignedJWT(disclosureSpec, claimSet, null, - hashAlgorithm, true); - return SdJwt.builder() - .withIssuerSignedJwt(issuerSignedJWT) - .build(signer); - } - - /** - * Verify the SD-JWT using the provided signature verification keys. - * - * @param sdJwt The SD-JWT to verify. - * @param issuerVerifyingKeys List of issuer verifying keys. - * @param verificationOpts Options for verification. - * @throws VerificationException if verification fails. - */ - public void verifySdJwt(SdJwt sdJwt, List issuerVerifyingKeys, - IssuerSignedJwtVerificationOpts verificationOpts - ) throws VerificationException { - try { - sdJwt.verify(issuerVerifyingKeys, verificationOpts); - } catch (VerificationException e) { - throw new VerificationException("SD-JWT verification failed: " + e.getMessage(), e); - } - } - - /** - * Retrieve the SD-JWT as a string representation. - * - * @param sdJwt The SD-JWT to convert. - * @return The string representation of the SD-JWT. - */ - public String getSdJwtString(SdJwt sdJwt) { - return sdJwt.toString(); - } -} diff --git a/core/src/test/java/org/keycloak/sdjwt/SdJwtFacadeTest.java b/core/src/test/java/org/keycloak/sdjwt/SdJwtFacadeTest.java deleted file mode 100644 index 4e6cedfa609..00000000000 --- a/core/src/test/java/org/keycloak/sdjwt/SdJwtFacadeTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2024 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.sdjwt; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.keycloak.OID4VCConstants; -import org.keycloak.common.VerificationException; -import org.keycloak.crypto.SignatureSignerContext; -import org.keycloak.crypto.SignatureVerifierContext; -import org.keycloak.rule.CryptoInitRule; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Tests for SdJwtFacade. - * - * @author Rodrick Awambeng - */ -public abstract class SdJwtFacadeTest { - - @ClassRule - public static CryptoInitRule cryptoInitRule = new CryptoInitRule(); - - private static final String HASH_ALGORITHM = OID4VCConstants.SD_HASH_DEFAULT_ALGORITHM; - private static final String JWS_TYPE = "JWS_TYPE"; - - private SdJwtFacade sdJwtFacade; - - private ObjectNode claimSet; - private DisclosureSpec disclosureSpec; - - @Before - public void setUp() { - SignatureSignerContext signer = TestSettings.getInstance().getIssuerSignerContext(); - - sdJwtFacade = new SdJwtFacade(signer, HASH_ALGORITHM, JWS_TYPE); - - claimSet = TestUtils.readClaimSet(getClass(), "sdjwt/a1.example2-holder-claims.json"); - disclosureSpec = DisclosureSpec.builder() - .withUndisclosedClaim("sub", "2GLC42sKQveCfGfryNRN9w") - .withUndisclosedClaim("given_name", "eluV5Og3gSNII8EYnsxA_A") - .withUndisclosedClaim("family_name", "6Ij7tM-a5iVPGboS5tmvVA") - .build(); - } - - @Test - public void shouldCreateSdJwtSuccessfully() { - SdJwt createdSdJwt = sdJwtFacade.createSdJwt(claimSet, disclosureSpec); - - assertNotNull(createdSdJwt); - } - - @Test - public void shouldVerifySdJwtSuccessfullyWithValidKeys() { - claimSet = TestUtils.readClaimSet(getClass(), "sdjwt/a1.example2-issuer-claims.json"); - - SdJwt sdJwt = sdJwtFacade.createSdJwt(claimSet, disclosureSpec); - - List verifyingKeys = Collections.singletonList( - createSignatureVerifierContext("doc-signer-05-25-2022", "ES256", true) - ); - IssuerSignedJwtVerificationOpts verificationOpts = createVerificationOptions(); - - try { - sdJwtFacade.verifySdJwt(sdJwt, verifyingKeys, verificationOpts); - } catch (VerificationException e) { - fail("Verification failed: " + e.getMessage()); - } - } - - @Test - public void shouldReturnSdJwtString() { - SdJwt sdJwt = sdJwtFacade.createSdJwt(claimSet, disclosureSpec); - - String sdJwtString = sdJwtFacade.getSdJwtString(sdJwt); - - assertNotNull(sdJwtString); - assertEquals(sdJwt.toString(), sdJwtString); - } - - @Test - public void shouldFailVerificationWithInvalidKeys() { - claimSet = TestUtils.readClaimSet(getClass(), "sdjwt/a1.example2-issuer-claims.json"); - SdJwt sdJwt = sdJwtFacade.createSdJwt(claimSet, disclosureSpec); - - List invalidKeys = Collections.singletonList( - createSignatureVerifierContext("invalid-key-id", "invalid-algorithm", false) - ); - IssuerSignedJwtVerificationOpts verificationOpts = createVerificationOptions(); - - VerificationException exception = assertThrows( - VerificationException.class, - () -> sdJwtFacade.verifySdJwt(sdJwt, invalidKeys, verificationOpts) - ); - - assertTrue(exception.getMessage().contains("Signature could not be verified")); - } - - private SignatureVerifierContext createSignatureVerifierContext(String kid, String algorithm, boolean verificationResult) { - return new SignatureVerifierContext() { - @Override - public String getKid() { - return kid; - } - - @Override - public String getAlgorithm() { - return algorithm; - } - - @Override - public boolean verify(byte[] data, byte[] signature) { - return verificationResult; - } - }; - } - - private IssuerSignedJwtVerificationOpts createVerificationOptions() { - List> headerVerifierList = new ArrayList<>(); - List> bodyVerifierList = new ArrayList<>(); - return new IssuerSignedJwtVerificationOpts(headerVerifierList, bodyVerifierList); - } -} diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/sdjwt/DefaultCryptoSdJwtFacadeTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/sdjwt/DefaultCryptoSdJwtFacadeTest.java deleted file mode 100644 index f7e27bd68f1..00000000000 --- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/sdjwt/DefaultCryptoSdJwtFacadeTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.crypto.def.test.sdjwt; - -import org.keycloak.common.util.Environment; -import org.keycloak.sdjwt.SdJwtFacadeTest; - -import org.junit.Assume; -import org.junit.Before; - -/** - * @author Rodrick Awambeng - */ -public class DefaultCryptoSdJwtFacadeTest extends SdJwtFacadeTest { - - @Before - public void before() { - // Run this test just if java is not in FIPS mode - Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode()); - } -} diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/sdjwt/ElytronCryptoSdJwtFacadeTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/sdjwt/ElytronCryptoSdJwtFacadeTest.java deleted file mode 100644 index 59477f113fd..00000000000 --- a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/sdjwt/ElytronCryptoSdJwtFacadeTest.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.keycloak.crypto.elytron.test.sdjwt; - -import org.keycloak.sdjwt.SdJwtFacadeTest; - -/** - * @author Rodrick Awambeng - */ -public class ElytronCryptoSdJwtFacadeTest extends SdJwtFacadeTest { -} diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/sdjwt/FIPS1402SdJwtFacadeTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/sdjwt/FIPS1402SdJwtFacadeTest.java deleted file mode 100644 index 7f9f94ada25..00000000000 --- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/sdjwt/FIPS1402SdJwtFacadeTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.keycloak.crypto.fips.test.sdjwt; - -import org.keycloak.common.util.Environment; -import org.keycloak.sdjwt.SdJwtFacadeTest; - -import org.junit.Assume; -import org.junit.Before; - -public class FIPS1402SdJwtFacadeTest extends SdJwtFacadeTest { - - @Before - public void before() { - // Run this test just if java is not in FIPS mode - Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode()); - } -}