Enhance SupportedCredentialConfiguration to support optional claims object as defined in OpenID for Verifiable Credential Issuance specification (#30420)
closes #30419 Signed-off-by: Francis Pouatcha <francis.pouatcha@adorsys.com>
This commit is contained in:
parent
fc65c73106
commit
d4797e04a2
13 changed files with 618 additions and 79 deletions
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holding metadata on a claim of verifiable credential.
|
||||||
|
* <p>
|
||||||
|
* See: <a href="https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#appendix-A.2.2">openid-4-verifiable-credential-issuance-1_0.html#appendix-A.2.2</a>
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class Claim {
|
||||||
|
@JsonProperty("mandatory")
|
||||||
|
private Boolean mandatory;
|
||||||
|
@JsonProperty("value_type")
|
||||||
|
private String valueType;
|
||||||
|
@JsonProperty("display")
|
||||||
|
private List<ClaimDisplay> display;
|
||||||
|
|
||||||
|
public Boolean getMandatory() {
|
||||||
|
return mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Claim setMandatory(Boolean mandatory) {
|
||||||
|
this.mandatory = mandatory;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueType() {
|
||||||
|
return valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Claim setValueType(String valueType) {
|
||||||
|
this.valueType = valueType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClaimDisplay> getDisplay() {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Claim setDisplay(List<ClaimDisplay> display) {
|
||||||
|
this.display = display;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class ClaimDisplay {
|
||||||
|
@JsonProperty("name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@JsonProperty("locale")
|
||||||
|
private String locale;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClaimDisplay setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocale() {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClaimDisplay setLocale(String locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
public class Claims extends HashMap<String, Claim> {
|
||||||
|
|
||||||
|
public String toJsonString(){
|
||||||
|
try {
|
||||||
|
return JsonSerialization.writeValueAsString(this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Claims fromJsonString(String jsonString){
|
||||||
|
try {
|
||||||
|
return JsonSerialization.readValue(jsonString, Claims.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,17 +14,15 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.protocol.oid4vc.model;
|
package org.keycloak.protocol.oid4vc.model;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a DisplayObject, as used in the OID4VCI Credentials Issuer Metadata
|
* Represents a DisplayObject, as used in the OID4VCI Credentials Issuer Metadata
|
||||||
|
@ -126,26 +124,20 @@ public class DisplayObject {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> toDotNotation() {
|
public String toJsonString(){
|
||||||
Map<String, String> dotNotation = new HashMap<>();
|
try {
|
||||||
dotNotation.put(NAME_KEY, name);
|
return JsonSerialization.writeValueAsString(this);
|
||||||
dotNotation.put(LOCALE_KEY, locale);
|
} catch (IOException e) {
|
||||||
dotNotation.put(LOGO_KEY, logo);
|
throw new RuntimeException(e);
|
||||||
dotNotation.put(DESCRIPTION_KEY, description);
|
}
|
||||||
dotNotation.put(BG_COLOR_KEY, backgroundColor);
|
|
||||||
dotNotation.put(TEXT_COLOR_KEY, textColor);
|
|
||||||
return dotNotation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DisplayObject fromDotNotation(Map<String, String> dotNotated) {
|
public static DisplayObject fromJsonString(String jsonString){
|
||||||
DisplayObject displayObject = new DisplayObject();
|
try {
|
||||||
Optional.ofNullable(dotNotated.get(NAME_KEY)).ifPresent(displayObject::setName);
|
return JsonSerialization.readValue(jsonString, DisplayObject.class);
|
||||||
Optional.ofNullable(dotNotated.get(LOCALE_KEY)).ifPresent(displayObject::setLocale);
|
} catch (IOException e) {
|
||||||
Optional.ofNullable(dotNotated.get(LOGO_KEY)).ifPresent(displayObject::setLogo);
|
throw new RuntimeException(e);
|
||||||
Optional.ofNullable(dotNotated.get(DESCRIPTION_KEY)).ifPresent(displayObject::setDescription);
|
}
|
||||||
Optional.ofNullable(dotNotated.get(BG_COLOR_KEY)).ifPresent(displayObject::setBackgroundColor);
|
|
||||||
Optional.ofNullable(dotNotated.get(TEXT_COLOR_KEY)).ifPresent(displayObject::setTextColor);
|
|
||||||
return displayObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -173,4 +165,4 @@ public class DisplayObject {
|
||||||
result = 31 * result + (getTextColor() != null ? getTextColor().hashCode() : 0);
|
result = 31 * result + (getTextColor() != null ? getTextColor().hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-cwt-proof-type
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class ProofTypeCWT {
|
||||||
|
|
||||||
|
@JsonProperty("proof_signing_alg_values_supported")
|
||||||
|
private List<Integer> proofSigningAlgValuesSupported;
|
||||||
|
|
||||||
|
@JsonProperty("proof_alg_values_supported")
|
||||||
|
private List<Integer> proofAlgValuesSupported;
|
||||||
|
|
||||||
|
@JsonProperty("proof_crv_values_supported")
|
||||||
|
private List<Integer> proofCrvValuesSupported;
|
||||||
|
|
||||||
|
public List<Integer> getProofSigningAlgValuesSupported() {
|
||||||
|
return proofSigningAlgValuesSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypeCWT setProofSigningAlgValuesSupported(List<Integer> proofSigningAlgValuesSupported) {
|
||||||
|
this.proofSigningAlgValuesSupported = proofSigningAlgValuesSupported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getProofAlgValuesSupported() {
|
||||||
|
return proofAlgValuesSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypeCWT setProofAlgValuesSupported(List<Integer> proofAlgValuesSupported) {
|
||||||
|
this.proofAlgValuesSupported = proofAlgValuesSupported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getProofCrvValuesSupported() {
|
||||||
|
return proofCrvValuesSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypeCWT setProofCrvValuesSupported(List<Integer> proofCrvValuesSupported) {
|
||||||
|
this.proofCrvValuesSupported = proofCrvValuesSupported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ProofTypeCWT that = (ProofTypeCWT) o;
|
||||||
|
return Objects.equals(proofSigningAlgValuesSupported, that.proofSigningAlgValuesSupported) && Objects.equals(proofAlgValuesSupported, that.proofAlgValuesSupported) && Objects.equals(proofCrvValuesSupported, that.proofCrvValuesSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(proofSigningAlgValuesSupported, proofAlgValuesSupported, proofCrvValuesSupported);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-jwt-proof-type
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class ProofTypeJWT {
|
||||||
|
@JsonProperty("proof_signing_alg_values_supported")
|
||||||
|
private List<String> proofSigningAlgValuesSupported;
|
||||||
|
|
||||||
|
public List<String> getProofSigningAlgValuesSupported() {
|
||||||
|
return proofSigningAlgValuesSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypeJWT setProofSigningAlgValuesSupported(List<String> proofSigningAlgValuesSupported) {
|
||||||
|
this.proofSigningAlgValuesSupported = proofSigningAlgValuesSupported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ProofTypeJWT that = (ProofTypeJWT) o;
|
||||||
|
return Objects.equals(proofSigningAlgValuesSupported, that.proofSigningAlgValuesSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(proofSigningAlgValuesSupported);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-ldp_vp-proof-type
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class ProofTypeLdpVp {
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-proof-types
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class ProofTypesSupported {
|
||||||
|
@JsonProperty("jwt")
|
||||||
|
private ProofTypeJWT jwt;
|
||||||
|
@JsonProperty("cwt")
|
||||||
|
private ProofTypeCWT cwt;
|
||||||
|
|
||||||
|
@JsonProperty("ldp_vp")
|
||||||
|
private ProofTypeLdpVp ldpVp;
|
||||||
|
|
||||||
|
public ProofTypeJWT getJwt() {
|
||||||
|
return jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypesSupported setJwt(ProofTypeJWT jwt) {
|
||||||
|
this.jwt = jwt;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypeCWT getCwt() {
|
||||||
|
return cwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypesSupported setCwt(ProofTypeCWT cwt) {
|
||||||
|
this.cwt = cwt;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypeLdpVp getLdpVp() {
|
||||||
|
return ldpVp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypesSupported setLdpVp(ProofTypeLdpVp ldpVp) {
|
||||||
|
this.ldpVp = ldpVp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toJsonString(){
|
||||||
|
try {
|
||||||
|
return JsonSerialization.writeValueAsString(this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProofTypesSupported fromJsonString(String jsonString){
|
||||||
|
try {
|
||||||
|
return JsonSerialization.readValue(jsonString, ProofTypesSupported.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ProofTypesSupported that = (ProofTypesSupported) o;
|
||||||
|
return Objects.equals(jwt, that.jwt) && Objects.equals(cwt, that.cwt) && Objects.equals(ldpVp, that.ldpVp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(jwt, cwt, ldpVp);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.protocol.oid4vc.model;
|
package org.keycloak.protocol.oid4vc.model;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
@ -26,7 +25,9 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A supported credential, as used in the Credentials Issuer Metadata in OID4VCI
|
* A supported credential, as used in the Credentials Issuer Metadata in OID4VCI
|
||||||
|
@ -42,13 +43,19 @@ public class SupportedCredentialConfiguration {
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private static final String SCOPE_KEY = "scope";
|
private static final String SCOPE_KEY = "scope";
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private static final String CRYPTOGRAPHIC_BINDING_METHODS_SUPPORTED_KEY = " credential_signing_alg_values_supported";
|
private static final String CRYPTOGRAPHIC_BINDING_METHODS_SUPPORTED_KEY = "cryptographic_binding_methods_supported";
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private static final String CRYPTOGRAPHIC_SUITES_SUPPORTED_KEY = "cryptographic_suites_supported";
|
private static final String CRYPTOGRAPHIC_SUITES_SUPPORTED_KEY = "cryptographic_suites_supported";
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private static final String CREDENTIAL_SIGNING_ALG_VALUES_SUPPORTED_KEY = "credential_signing_alg_values_supported";
|
private static final String CREDENTIAL_SIGNING_ALG_VALUES_SUPPORTED_KEY = "credential_signing_alg_values_supported";
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private static final String DISPLAY_KEY = "display";
|
private static final String DISPLAY_KEY = "display";
|
||||||
|
@JsonIgnore
|
||||||
|
private static final String PROOF_TYPES_SUPPORTED_KEY = "proof_types_supported";
|
||||||
|
@JsonIgnore
|
||||||
|
private static final String CLAIMS_KEY = "claims";
|
||||||
|
@JsonIgnore
|
||||||
|
private static final String VERIFIABLE_CREDENTIAL_TYPE_KEY = "vct";
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@JsonProperty(FORMAT_KEY)
|
@JsonProperty(FORMAT_KEY)
|
||||||
|
@ -67,7 +74,16 @@ public class SupportedCredentialConfiguration {
|
||||||
private List<String> credentialSigningAlgValuesSupported;
|
private List<String> credentialSigningAlgValuesSupported;
|
||||||
|
|
||||||
@JsonProperty(DISPLAY_KEY)
|
@JsonProperty(DISPLAY_KEY)
|
||||||
private DisplayObject display;
|
private List<DisplayObject> display;
|
||||||
|
|
||||||
|
@JsonProperty(VERIFIABLE_CREDENTIAL_TYPE_KEY)
|
||||||
|
private String vct;
|
||||||
|
|
||||||
|
@JsonProperty(PROOF_TYPES_SUPPORTED_KEY)
|
||||||
|
private ProofTypesSupported proofTypesSupported;
|
||||||
|
|
||||||
|
@JsonProperty(CLAIMS_KEY)
|
||||||
|
private Claims claims;
|
||||||
|
|
||||||
public Format getFormat() {
|
public Format getFormat() {
|
||||||
return format;
|
return format;
|
||||||
|
@ -105,11 +121,11 @@ public class SupportedCredentialConfiguration {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayObject getDisplay() {
|
public List<DisplayObject> getDisplay() {
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SupportedCredentialConfiguration setDisplay(DisplayObject display) {
|
public SupportedCredentialConfiguration setDisplay(List<DisplayObject> display) {
|
||||||
this.display = display;
|
this.display = display;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -135,9 +151,37 @@ public class SupportedCredentialConfiguration {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Claims getClaims() {
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupportedCredentialConfiguration setClaims(Claims claims) {
|
||||||
|
this.claims = claims;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVct() {
|
||||||
|
return vct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupportedCredentialConfiguration setVct(String vct) {
|
||||||
|
this.vct = vct;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProofTypesSupported getProofTypesSupported() {
|
||||||
|
return proofTypesSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SupportedCredentialConfiguration setProofTypesSupported(ProofTypesSupported proofTypesSupported) {
|
||||||
|
this.proofTypesSupported = proofTypesSupported;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, String> toDotNotation() {
|
public Map<String, String> toDotNotation() {
|
||||||
Map<String, String> dotNotation = new HashMap<>();
|
Map<String, String> dotNotation = new HashMap<>();
|
||||||
Optional.ofNullable(format).ifPresent(format -> dotNotation.put(id + DOT_SEPARATOR + FORMAT_KEY, format.toString()));
|
Optional.ofNullable(format).ifPresent(format -> dotNotation.put(id + DOT_SEPARATOR + FORMAT_KEY, format.toString()));
|
||||||
|
Optional.ofNullable(vct).ifPresent(vct -> dotNotation.put(id + DOT_SEPARATOR + VERIFIABLE_CREDENTIAL_TYPE_KEY, vct));
|
||||||
Optional.ofNullable(scope).ifPresent(scope -> dotNotation.put(id + DOT_SEPARATOR + SCOPE_KEY, scope));
|
Optional.ofNullable(scope).ifPresent(scope -> dotNotation.put(id + DOT_SEPARATOR + SCOPE_KEY, scope));
|
||||||
Optional.ofNullable(cryptographicBindingMethodsSupported).ifPresent(types ->
|
Optional.ofNullable(cryptographicBindingMethodsSupported).ifPresent(types ->
|
||||||
dotNotation.put(id + DOT_SEPARATOR + CRYPTOGRAPHIC_BINDING_METHODS_SUPPORTED_KEY, String.join(",", cryptographicBindingMethodsSupported)));
|
dotNotation.put(id + DOT_SEPARATOR + CRYPTOGRAPHIC_BINDING_METHODS_SUPPORTED_KEY, String.join(",", cryptographicBindingMethodsSupported)));
|
||||||
|
@ -145,13 +189,16 @@ public class SupportedCredentialConfiguration {
|
||||||
dotNotation.put(id + DOT_SEPARATOR + CRYPTOGRAPHIC_SUITES_SUPPORTED_KEY, String.join(",", cryptographicSuitesSupported)));
|
dotNotation.put(id + DOT_SEPARATOR + CRYPTOGRAPHIC_SUITES_SUPPORTED_KEY, String.join(",", cryptographicSuitesSupported)));
|
||||||
Optional.ofNullable(cryptographicSuitesSupported).ifPresent(types ->
|
Optional.ofNullable(cryptographicSuitesSupported).ifPresent(types ->
|
||||||
dotNotation.put(id + DOT_SEPARATOR + CREDENTIAL_SIGNING_ALG_VALUES_SUPPORTED_KEY, String.join(",", credentialSigningAlgValuesSupported)));
|
dotNotation.put(id + DOT_SEPARATOR + CREDENTIAL_SIGNING_ALG_VALUES_SUPPORTED_KEY, String.join(",", credentialSigningAlgValuesSupported)));
|
||||||
|
Optional.ofNullable(claims).ifPresent(c -> dotNotation.put(id + DOT_SEPARATOR + CLAIMS_KEY, c.toJsonString()));
|
||||||
|
|
||||||
|
Optional.ofNullable(display)
|
||||||
|
.ifPresent(d -> d.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.forEach(o -> dotNotation.put(id + DOT_SEPARATOR + DISPLAY_KEY + DOT_SEPARATOR + d.indexOf(o), o.toJsonString())));
|
||||||
|
|
||||||
|
Optional.ofNullable(proofTypesSupported)
|
||||||
|
.ifPresent(p -> dotNotation.put(id + DOT_SEPARATOR + PROOF_TYPES_SUPPORTED_KEY, p.toJsonString()));
|
||||||
|
|
||||||
Map<String, String> dotNotatedDisplay = Optional.ofNullable(display)
|
|
||||||
.map(DisplayObject::toDotNotation)
|
|
||||||
.orElse(Map.of());
|
|
||||||
dotNotatedDisplay.entrySet().stream()
|
|
||||||
.filter(entry -> entry.getValue() != null)
|
|
||||||
.forEach(entry -> dotNotation.put(id + DOT_SEPARATOR + DISPLAY_KEY + "." + entry.getKey(), entry.getValue()));
|
|
||||||
return dotNotation;
|
return dotNotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +206,7 @@ public class SupportedCredentialConfiguration {
|
||||||
|
|
||||||
SupportedCredentialConfiguration supportedCredentialConfiguration = new SupportedCredentialConfiguration().setId(credentialId);
|
SupportedCredentialConfiguration supportedCredentialConfiguration = new SupportedCredentialConfiguration().setId(credentialId);
|
||||||
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + FORMAT_KEY)).map(Format::fromString).ifPresent(supportedCredentialConfiguration::setFormat);
|
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + FORMAT_KEY)).map(Format::fromString).ifPresent(supportedCredentialConfiguration::setFormat);
|
||||||
|
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + VERIFIABLE_CREDENTIAL_TYPE_KEY)).ifPresent(supportedCredentialConfiguration::setVct);
|
||||||
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + SCOPE_KEY)).ifPresent(supportedCredentialConfiguration::setScope);
|
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + SCOPE_KEY)).ifPresent(supportedCredentialConfiguration::setScope);
|
||||||
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + CRYPTOGRAPHIC_BINDING_METHODS_SUPPORTED_KEY))
|
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + CRYPTOGRAPHIC_BINDING_METHODS_SUPPORTED_KEY))
|
||||||
.map(cbms -> cbms.split(","))
|
.map(cbms -> cbms.split(","))
|
||||||
|
@ -172,45 +220,38 @@ public class SupportedCredentialConfiguration {
|
||||||
.map(css -> css.split(","))
|
.map(css -> css.split(","))
|
||||||
.map(Arrays::asList)
|
.map(Arrays::asList)
|
||||||
.ifPresent(supportedCredentialConfiguration::setCredentialSigningAlgValuesSupported);
|
.ifPresent(supportedCredentialConfiguration::setCredentialSigningAlgValuesSupported);
|
||||||
Map<String, String> displayMap = new HashMap<>();
|
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + CLAIMS_KEY))
|
||||||
dotNotated.entrySet().forEach(entry -> {
|
.map(Claims::fromJsonString)
|
||||||
String key = entry.getKey();
|
.ifPresent(supportedCredentialConfiguration::setClaims);
|
||||||
if (key.startsWith(credentialId + DOT_SEPARATOR + DISPLAY_KEY)) {
|
|
||||||
displayMap.put(key.substring((credentialId + DOT_SEPARATOR + DISPLAY_KEY).length() + 1), entry.getValue());
|
String displayKeyPrefix = credentialId + DOT_SEPARATOR + DISPLAY_KEY + DOT_SEPARATOR;
|
||||||
}
|
List<DisplayObject> displayList = dotNotated.entrySet().stream()
|
||||||
});
|
.filter(entry -> entry.getKey().startsWith(displayKeyPrefix))
|
||||||
if (!displayMap.isEmpty()) {
|
.sorted(Map.Entry.comparingByKey())
|
||||||
supportedCredentialConfiguration.setDisplay(DisplayObject.fromDotNotation(displayMap));
|
.map(entry -> DisplayObject.fromJsonString(entry.getValue()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if(!displayList.isEmpty()){
|
||||||
|
supportedCredentialConfiguration.setDisplay(displayList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Optional.ofNullable(dotNotated.get(credentialId + DOT_SEPARATOR + PROOF_TYPES_SUPPORTED_KEY))
|
||||||
|
.map(ProofTypesSupported::fromJsonString)
|
||||||
|
.ifPresent(supportedCredentialConfiguration::setProofTypesSupported);
|
||||||
|
|
||||||
return supportedCredentialConfiguration;
|
return supportedCredentialConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (!(o instanceof SupportedCredentialConfiguration that)) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
SupportedCredentialConfiguration that = (SupportedCredentialConfiguration) o;
|
||||||
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
|
return Objects.equals(id, that.id) && format == that.format && Objects.equals(scope, that.scope) && Objects.equals(cryptographicBindingMethodsSupported, that.cryptographicBindingMethodsSupported) && Objects.equals(cryptographicSuitesSupported, that.cryptographicSuitesSupported) && Objects.equals(credentialSigningAlgValuesSupported, that.credentialSigningAlgValuesSupported) && Objects.equals(display, that.display) && Objects.equals(vct, that.vct) && Objects.equals(proofTypesSupported, that.proofTypesSupported) && Objects.equals(claims, that.claims);
|
||||||
if (getFormat() != that.getFormat()) return false;
|
|
||||||
if (getScope() != null ? !getScope().equals(that.getScope()) : that.getScope() != null) return false;
|
|
||||||
if (getCryptographicBindingMethodsSupported() != null ? !getCryptographicBindingMethodsSupported().equals(that.getCryptographicBindingMethodsSupported()) : that.getCryptographicBindingMethodsSupported() != null)
|
|
||||||
return false;
|
|
||||||
if (getCryptographicSuitesSupported() != null ? !getCryptographicSuitesSupported().equals(that.getCryptographicSuitesSupported()) : that.getCryptographicSuitesSupported() != null)
|
|
||||||
return false;
|
|
||||||
if (getCredentialSigningAlgValuesSupported() != null ? !getCredentialSigningAlgValuesSupported().equals(that.getCredentialSigningAlgValuesSupported()) : that.getCredentialSigningAlgValuesSupported() != null)
|
|
||||||
return false;
|
|
||||||
return getDisplay() != null ? getDisplay().equals(that.getDisplay()) : that.getDisplay() == null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = getId() != null ? getId().hashCode() : 0;
|
return Objects.hash(id, format, scope, cryptographicBindingMethodsSupported, cryptographicSuitesSupported, credentialSigningAlgValuesSupported, display, vct, proofTypesSupported, claims);
|
||||||
result = 31 * result + (getFormat() != null ? getFormat().hashCode() : 0);
|
|
||||||
result = 31 * result + (getScope() != null ? getScope().hashCode() : 0);
|
|
||||||
result = 31 * result + (getCryptographicBindingMethodsSupported() != null ? getCryptographicBindingMethodsSupported().hashCode() : 0);
|
|
||||||
result = 31 * result + (getCryptographicSuitesSupported() != null ? getCryptographicSuitesSupported().hashCode() : 0);
|
|
||||||
result = 31 * result + (getCredentialSigningAlgValuesSupported() != null ? getCredentialSigningAlgValuesSupported().hashCode() : 0);
|
|
||||||
result = 31 * result + (getDisplay() != null ? getDisplay().hashCode() : 0);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.protocol.oid4vc;
|
package org.keycloak.protocol.oid4vc;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -23,6 +22,8 @@ import org.junit.runners.Parameterized;
|
||||||
import org.keycloak.protocol.oid4vc.model.DisplayObject;
|
import org.keycloak.protocol.oid4vc.model.DisplayObject;
|
||||||
import org.keycloak.protocol.oid4vc.model.Format;
|
import org.keycloak.protocol.oid4vc.model.Format;
|
||||||
import org.keycloak.protocol.oid4vc.model.OID4VCClient;
|
import org.keycloak.protocol.oid4vc.model.OID4VCClient;
|
||||||
|
import org.keycloak.protocol.oid4vc.model.ProofTypeJWT;
|
||||||
|
import org.keycloak.protocol.oid4vc.model.ProofTypesSupported;
|
||||||
import org.keycloak.protocol.oid4vc.model.SupportedCredentialConfiguration;
|
import org.keycloak.protocol.oid4vc.model.SupportedCredentialConfiguration;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -31,7 +32,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class OID4VCClientRegistrationProviderTest {
|
public class OID4VCClientRegistrationProviderTest {
|
||||||
|
@ -68,13 +68,12 @@ public class OID4VCClientRegistrationProviderTest {
|
||||||
Map.of(
|
Map.of(
|
||||||
"vc.credential-id.format", Format.JWT_VC.toString(),
|
"vc.credential-id.format", Format.JWT_VC.toString(),
|
||||||
"vc.credential-id.scope", "AnotherCredential",
|
"vc.credential-id.scope", "AnotherCredential",
|
||||||
"vc.credential-id.display.name", "Another",
|
"vc.credential-id.display.0", "{\"name\":\"Another\",\"locale\":\"en\"}"),
|
||||||
"vc.credential-id.display.locale", "en"),
|
|
||||||
new OID4VCClient(null, "did:web:test.org",
|
new OID4VCClient(null, "did:web:test.org",
|
||||||
List.of(new SupportedCredentialConfiguration()
|
List.of(new SupportedCredentialConfiguration()
|
||||||
.setId("credential-id")
|
.setId("credential-id")
|
||||||
.setFormat(Format.JWT_VC)
|
.setFormat(Format.JWT_VC)
|
||||||
.setDisplay(new DisplayObject().setLocale("en").setName("Another"))
|
.setDisplay(Arrays.asList(new DisplayObject().setLocale("en").setName("Another")))
|
||||||
.setScope("AnotherCredential")),
|
.setScope("AnotherCredential")),
|
||||||
null, null)
|
null, null)
|
||||||
},
|
},
|
||||||
|
@ -83,23 +82,23 @@ public class OID4VCClientRegistrationProviderTest {
|
||||||
Map.of(
|
Map.of(
|
||||||
"vc.first-id.format", Format.JWT_VC.toString(),
|
"vc.first-id.format", Format.JWT_VC.toString(),
|
||||||
"vc.first-id.scope", "AnotherCredential",
|
"vc.first-id.scope", "AnotherCredential",
|
||||||
"vc.first-id.display.name", "First",
|
"vc.first-id.display.0", "{\"name\":\"First\",\"locale\":\"en\"}",
|
||||||
"vc.first-id.display.locale", "en",
|
|
||||||
"vc.second-id.format", Format.SD_JWT_VC.toString(),
|
"vc.second-id.format", Format.SD_JWT_VC.toString(),
|
||||||
"vc.second-id.scope", "MyType",
|
"vc.second-id.scope", "MyType",
|
||||||
"vc.second-id.display.name", "Second Credential",
|
"vc.second-id.display.0", "{\"name\":\"Second Credential\",\"locale\":\"de\"}",
|
||||||
"vc.second-id.display.locale", "de"),
|
"vc.second-id.proof_types_supported","{\"jwt\":{\"proof_signing_alg_values_supported\":[\"ES256\"]}}"),
|
||||||
new OID4VCClient(null, "did:web:test.org",
|
new OID4VCClient(null, "did:web:test.org",
|
||||||
List.of(new SupportedCredentialConfiguration()
|
List.of(new SupportedCredentialConfiguration()
|
||||||
.setId("first-id")
|
.setId("first-id")
|
||||||
.setFormat(Format.JWT_VC)
|
.setFormat(Format.JWT_VC)
|
||||||
.setDisplay(new DisplayObject().setLocale("en").setName("First"))
|
.setDisplay(Arrays.asList(new DisplayObject().setLocale("en").setName("First")))
|
||||||
.setScope("AnotherCredential"),
|
.setScope("AnotherCredential"),
|
||||||
new SupportedCredentialConfiguration()
|
new SupportedCredentialConfiguration()
|
||||||
.setId("second-id")
|
.setId("second-id")
|
||||||
.setFormat(Format.SD_JWT_VC)
|
.setFormat(Format.SD_JWT_VC)
|
||||||
.setDisplay(new DisplayObject().setLocale("de").setName("Second Credential"))
|
.setDisplay(Arrays.asList(new DisplayObject().setLocale("de").setName("Second Credential")))
|
||||||
.setScope("MyType")),
|
.setScope("MyType")
|
||||||
|
.setProofTypesSupported(new ProofTypesSupported().setJwt(new ProofTypeJWT().setProofSigningAlgValuesSupported(Arrays.asList("ES256"))))),
|
||||||
null, null)
|
null, null)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -129,4 +128,4 @@ public class OID4VCClientRegistrationProviderTest {
|
||||||
OID4VCClientRegistrationProvider.fromClientAttributes("did:web:test.org", clientAttributes));
|
OID4VCClientRegistrationProvider.fromClientAttributes("did:web:test.org", clientAttributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.oid4vc.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
|
||||||
|
*/
|
||||||
|
public class ClaimsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toJsonString() throws JsonProcessingException {
|
||||||
|
Claims claims = new Claims();
|
||||||
|
claims.put("firstName", new Claim());
|
||||||
|
claims.put("lastName", new Claim());
|
||||||
|
claims.put("email", new Claim());
|
||||||
|
String jsonString = claims.toJsonString();
|
||||||
|
JsonNode jsonNode = JsonSerialization.mapper.readTree(jsonString);
|
||||||
|
assertNotNull(jsonNode.get("firstName"));
|
||||||
|
assertNotNull(jsonNode.get("lastName"));
|
||||||
|
assertNotNull(jsonNode.get("email"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromJsonString() {
|
||||||
|
final String serializeForm = "{ \"firstName\": {}, \"lastName\": {}, \"email\": {} }";
|
||||||
|
Claims claims = Claims.fromJsonString(serializeForm);
|
||||||
|
assertNotNull(claims);
|
||||||
|
assertNotNull(claims.get("firstName"));
|
||||||
|
assertNotNull(claims.get("lastName"));
|
||||||
|
assertNotNull(claims.get("email"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fromJsonStringDeepClaim() {
|
||||||
|
final String serializeForm = "{ \"firstName\": {\"mandatory\":false}, \"lastName\": {\"mandatory\":false}, \"email\": {\"mandatory\":true} }";
|
||||||
|
Claims claims = Claims.fromJsonString(serializeForm);
|
||||||
|
assertNotNull(claims);
|
||||||
|
assertNotNull(claims.get("firstName"));
|
||||||
|
assertFalse(claims.get("firstName").getMandatory());
|
||||||
|
assertNotNull(claims.get("lastName"));
|
||||||
|
assertFalse(claims.get("lastName").getMandatory());
|
||||||
|
assertNotNull(claims.get("email"));
|
||||||
|
assertTrue(claims.get("email").getMandatory());
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class OID4VCIssuerWellKnownProviderTest extends OID4VCTest {
|
public class OID4VCIssuerWellKnownProviderTest extends OID4VCTest {
|
||||||
|
@ -52,6 +54,16 @@ public class OID4VCIssuerWellKnownProviderTest extends OID4VCTest {
|
||||||
assertTrue("The test-credential should be supported.", credentialIssuer.getCredentialsSupported().containsKey("test-credential"));
|
assertTrue("The test-credential should be supported.", credentialIssuer.getCredentialsSupported().containsKey("test-credential"));
|
||||||
assertEquals("The test-credential should offer type VerifiableCredential", "VerifiableCredential", credentialIssuer.getCredentialsSupported().get("test-credential").getScope());
|
assertEquals("The test-credential should offer type VerifiableCredential", "VerifiableCredential", credentialIssuer.getCredentialsSupported().get("test-credential").getScope());
|
||||||
assertEquals("The test-credential should be offered in the jwt-vc format.", Format.JWT_VC, credentialIssuer.getCredentialsSupported().get("test-credential").getFormat());
|
assertEquals("The test-credential should be offered in the jwt-vc format.", Format.JWT_VC, credentialIssuer.getCredentialsSupported().get("test-credential").getFormat());
|
||||||
|
assertNotNull("The test-credential can optionally provide a claims claim.", credentialIssuer.getCredentialsSupported().get("test-credential").getClaims());
|
||||||
|
assertNotNull("The test-credential claim firstName is present.", credentialIssuer.getCredentialsSupported().get("test-credential").getClaims().get("firstName"));
|
||||||
|
assertFalse("The test-credential claim firstName is not mandatory.", credentialIssuer.getCredentialsSupported().get("test-credential").getClaims().get("firstName").getMandatory());
|
||||||
|
assertEquals("The test-credential claim firstName shall be displayed as First Name", "First Name", credentialIssuer.getCredentialsSupported().get("test-credential").getClaims().get("firstName").getDisplay().get(0).getName());
|
||||||
|
assertEquals("The test-credential should offer vct VerifiableCredential", "VerifiableCredential", credentialIssuer.getCredentialsSupported().get("test-credential").getVct());
|
||||||
|
assertTrue("The test-credential should contain a cryptographic binding method supported named jwk", credentialIssuer.getCredentialsSupported().get("test-credential").getCryptographicBindingMethodsSupported().contains("jwk"));
|
||||||
|
assertTrue("The test-credential should contain a credential signing algorithm named ES256", credentialIssuer.getCredentialsSupported().get("test-credential").getCredentialSigningAlgValuesSupported().contains("ES256"));
|
||||||
|
assertTrue("The test-credential should contain a credential signing algorithm named ES384", credentialIssuer.getCredentialsSupported().get("test-credential").getCredentialSigningAlgValuesSupported().contains("ES384"));
|
||||||
|
assertEquals("The test-credential should display as Test Credential", "Test Credential", credentialIssuer.getCredentialsSupported().get("test-credential").getDisplay().get(0).getName());
|
||||||
|
assertTrue("The test-credential should support a proof of type jwt with signing algorithm ES256", credentialIssuer.getCredentialsSupported().get("test-credential").getProofTypesSupported().getJwt().getProofSigningAlgValuesSupported().contains("ES256"));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,14 @@ public abstract class OID4VCTest extends AbstractTestRealmKeycloakTest {
|
||||||
clientRepresentation.setAttributes(Map.of(
|
clientRepresentation.setAttributes(Map.of(
|
||||||
"vc.test-credential.expiry_in_s", "100",
|
"vc.test-credential.expiry_in_s", "100",
|
||||||
"vc.test-credential.format", Format.JWT_VC.toString(),
|
"vc.test-credential.format", Format.JWT_VC.toString(),
|
||||||
"vc.test-credential.scope", "VerifiableCredential"));
|
"vc.test-credential.scope", "VerifiableCredential",
|
||||||
|
"vc.test-credential.claims", "{ \"firstName\": {\"mandatory\": false, \"display\": [{\"name\": \"First Name\", \"locale\": \"en-US\"}, {\"name\": \"名前\", \"locale\": \"ja-JP\"}]}, \"lastName\": {\"mandatory\": false}, \"email\": {\"mandatory\": false} }",
|
||||||
|
"vc.test-credential.vct", "VerifiableCredential",
|
||||||
|
"vc.test-credential.cryptographic_binding_methods_supported", "jwk",
|
||||||
|
"vc.test-credential.credential_signing_alg_values_supported", "ES256,ES384",
|
||||||
|
"vc.test-credential.display.0","{\n \"name\": \"Test Credential\"\n}",
|
||||||
|
"vc.test-credential.proof_types_supported","{\"jwt\":{\"proof_signing_alg_values_supported\":[\"ES256\"]}}"
|
||||||
|
));
|
||||||
clientRepresentation.setProtocolMappers(
|
clientRepresentation.setProtocolMappers(
|
||||||
List.of(
|
List.of(
|
||||||
getRoleMapper(clientId),
|
getRoleMapper(clientId),
|
||||||
|
@ -347,4 +354,4 @@ public abstract class OID4VCTest extends AbstractTestRealmKeycloakTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue