mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-16 12:05:49 -06:00
Removing SdJwtFacade
closes #44525 Signed-off-by: mposolda <mposolda@gmail.com>
This commit is contained in:
@@ -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 <a href="mailto:rodrick.awambeng@adorsys.com">Rodrick Awambeng</a>
|
||||
*/
|
||||
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<SignatureVerifierContext> 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();
|
||||
}
|
||||
}
|
||||
@@ -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 <a href="mailto:rodrick.awambeng@adorsys.com">Rodrick Awambeng</a>
|
||||
*/
|
||||
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<SignatureVerifierContext> 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<SignatureVerifierContext> 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<ClaimVerifier.Predicate<ObjectNode>> headerVerifierList = new ArrayList<>();
|
||||
List<ClaimVerifier.Predicate<ObjectNode>> bodyVerifierList = new ArrayList<>();
|
||||
return new IssuerSignedJwtVerificationOpts(headerVerifierList, bodyVerifierList);
|
||||
}
|
||||
}
|
||||
@@ -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 <a href="mailto:rodrick.awambeng@adorsys.com">Rodrick Awambeng</a>
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -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 <a href="mailto:rodrick.awambeng@adorsys.com">Rodrick Awambeng</a>
|
||||
*/
|
||||
public class ElytronCryptoSdJwtFacadeTest extends SdJwtFacadeTest {
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user