[java-idp-oidc] 03/44: JOIDC-5 Initial versions of the node processor + related files. WIP.
Henri Mikkonen
henri.mikkonen at iki.fi
Thu Oct 22 13:08:15 UTC 2020
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=7b922743f2faa675fccce01b26ad7d7e18a288c6
commit 7b922743f2faa675fccce01b26ad7d7e18a288c6
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Apr 15 16:16:14 2020 +0300
JOIDC-5 Initial versions of the node processor + related files. WIP.
https://issues.shibboleth.net/jira/browse/JOIDC-5
---
.../oidc/filter/impl/ClientInformationParser.java | 56 +++
.../oidc/impl/MetadataNamespaceHandler.java | 39 +++
.../impl/ClientInformationNodeProcessor.java | 382 +++++++++++++++++++++
.../src/main/resources/META-INF/spring.handlers | 1 +
.../src/main/resources/META-INF/spring.schemas | 3 +-
.../schema/idp-oidc-extension-metadata-ext.xsd | 20 ++
.../impl/ClientInformationNodeProcessorTest.java | 104 ++++++
.../impl/EntitiesDescriptor-with-oidcmd.xml | 85 +++++
8 files changed, 689 insertions(+), 1 deletion(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/oidc/filter/impl/ClientInformationParser.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/oidc/filter/impl/ClientInformationParser.java
new file mode 100644
index 00000000..6150f0eb
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/oidc/filter/impl/ClientInformationParser.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 - 2020, GÉANT
+ *
+ * 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 net.shibboleth.idp.profile.spring.relyingparty.metadata.oidc.filter.impl;
+
+import javax.annotation.Nonnull;
+import javax.xml.namespace.QName;
+
+import org.geant.idpextension.oidc.metadata.impl.ClientInformationNodeProcessor;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+
+import net.shibboleth.idp.profile.spring.relyingparty.metadata.oidc.impl.MetadataNamespaceHandler;
+
+/**
+ * Parser for a <ClientInformation> node processor.
+ */
+public class ClientInformationParser extends AbstractSingleBeanDefinitionParser {
+
+ /** Element name. */
+ @Nonnull public static final QName TYPE_NAME =
+ new QName(MetadataNamespaceHandler.NAMESPACE, "ClientInformation");
+
+ /** {@inheritDoc} */
+ @Override protected Class<?> getBeanClass(final Element element) {
+ return ClientInformationNodeProcessor.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doParse(final Element element, final ParserContext parserContext,
+ final BeanDefinitionBuilder builder) {
+
+ }
+
+ /** {@inheritDoc} */
+ @Override protected boolean shouldGenerateId() {
+ return true;
+ }
+
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/oidc/impl/MetadataNamespaceHandler.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/oidc/impl/MetadataNamespaceHandler.java
new file mode 100644
index 00000000..caa9b0d7
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/profile/spring/relyingparty/metadata/oidc/impl/MetadataNamespaceHandler.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 - 2020, GÉANT
+ *
+ * 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 net.shibboleth.idp.profile.spring.relyingparty.metadata.oidc.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.ext.spring.util.BaseSpringNamespaceHandler;
+import net.shibboleth.idp.profile.spring.relyingparty.metadata.oidc.filter.impl.ClientInformationParser;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/** Namespace handler for <code>urn:mace:shibboleth:2.0:metadata:oidc</code>. */
+public class MetadataNamespaceHandler extends BaseSpringNamespaceHandler {
+
+ /** Namespace for this handler. */
+ @Nonnull
+ @NotEmpty
+ public static final String NAMESPACE = "urn:mace:shibboleth:2.0:metadata:oidc";
+
+ /** {@inheritDoc} */
+ @Override
+ public void init() {
+ registerBeanDefinitionParser(ClientInformationParser.TYPE_NAME, new ClientInformationParser());
+ }
+
+}
diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/metadata/impl/ClientInformationNodeProcessor.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/metadata/impl/ClientInformationNodeProcessor.java
new file mode 100644
index 00000000..1816ab02
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/metadata/impl/ClientInformationNodeProcessor.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2017 - 2020, GÉANT
+ *
+ * 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.geant.idpextension.oidc.metadata.impl;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.geant.idpextension.oidc.security.impl.CredentialConversionUtil;
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.saml.criterion.RoleDescriptorCriterion;
+import org.opensaml.saml.metadata.resolver.RoleDescriptorResolver;
+import org.opensaml.saml.metadata.resolver.filter.FilterException;
+import org.opensaml.saml.metadata.resolver.filter.MetadataNodeProcessor;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml.security.impl.MetadataCredentialResolver;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver;
+import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver;
+import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider;
+import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider;
+import org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider;
+import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.Curve;
+import com.nimbusds.jose.jwk.ECKey;
+import com.nimbusds.jose.jwk.JWK;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.oauth2.sdk.GrantType;
+import com.nimbusds.oauth2.sdk.ResponseType;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.oauth2.sdk.id.SoftwareID;
+import com.nimbusds.oauth2.sdk.id.SoftwareVersion;
+import com.nimbusds.openid.connect.sdk.SubjectType;
+import com.nimbusds.openid.connect.sdk.claims.ACR;
+import com.nimbusds.openid.connect.sdk.rp.ApplicationType;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+
+import net.shibboleth.idp.saml.oidc.xmlobject.DefaultAcrValue;
+import net.shibboleth.idp.saml.oidc.xmlobject.MetadataValueSAMLObject;
+import net.shibboleth.idp.saml.oidc.xmlobject.OAuthRPRoleDescriptorType;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * An implementation of {@link MetadataNodeProcessor} which supports adding an instance of
+ * {@link OIDCClientInformation} to the object metadata of {@link OAuthRPRoleDescriptorType}.
+ */
+public class ClientInformationNodeProcessor implements MetadataNodeProcessor {
+
+ /** Class logger. */
+ private final Logger log = LoggerFactory.getLogger(ClientInformationNodeProcessor.class);
+
+ private KeyInfoCredentialResolver keyInfoCredentialResolver;
+
+ public ClientInformationNodeProcessor() {
+ final List<KeyInfoProvider> keyInfoProviders = new ArrayList<>();
+ keyInfoProviders.add(new DSAKeyValueProvider());
+ keyInfoProviders.add(new RSAKeyValueProvider());
+ keyInfoProviders.add(new InlineX509DataProvider());
+ keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver(keyInfoProviders);
+
+ }
+
+ protected Iterable<Credential> resolveCredentials(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final MetadataCredentialResolver credentialResolver = new MetadataCredentialResolver();
+ credentialResolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver);
+ credentialResolver.setRoleDescriptorResolver(new RoleDescriptorResolver() {
+
+ @Override
+ public Iterable<RoleDescriptor> resolve(CriteriaSet criteria) throws ResolverException {
+ final ArrayList<RoleDescriptor> result = new ArrayList<>();
+ result.add(resolveSingle(criteria));
+ return result;
+ }
+
+ @Override
+ public RoleDescriptor resolveSingle(CriteriaSet criteria) throws ResolverException {
+ return roleDescriptor;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequireValidMetadata() {
+ return false;
+ }
+
+ @Override
+ public void setRequireValidMetadata(boolean requireValidMetadata) {
+ // no op
+ }
+
+ });
+ try {
+ credentialResolver.initialize();
+ } catch (ComponentInitializationException e) {
+ log.error("Could not initialize the metdadata credential resolver", e);
+ return null;
+ }
+ final CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add(new RoleDescriptorCriterion(roleDescriptor));
+
+ try {
+ return credentialResolver.resolve(criteriaSet);
+ } catch (ResolverException e) {
+ log.error("Could not resolve credentials", e);
+ return null;
+ }
+ }
+
+ @Override
+ public void process(XMLObject metadataNode) throws FilterException {
+ if (metadataNode instanceof OAuthRPRoleDescriptorType) {
+ final OAuthRPRoleDescriptorType roleDescriptor = (OAuthRPRoleDescriptorType) metadataNode;
+ log.info("Keys: {}", roleDescriptor.getKeyDescriptors());
+ final ClientID clientId = parseClientID(roleDescriptor);
+ if (clientId == null) {
+ log.error("Could not find a value for client_id, nothing to do");
+ return;
+ }
+ final OIDCClientMetadata metadata = populateMetadata(roleDescriptor);
+ final OIDCClientInformation clientInformation = new OIDCClientInformation(clientId, null, metadata, null);
+ metadataNode.getObjectMetadata().put(clientInformation);
+
+ final Iterable<Credential> credentials = resolveCredentials(roleDescriptor);
+ if (credentials != null) {
+ for (final Credential credential : credentials) {
+ log.debug("JWK {}", credentialToKey(credential).toJSONString());
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Resolved KeyUse parameter from credential.
+ *
+ * @param credential credential to resolve KeyUse of
+ * @return KeyUse of credential
+ */
+ private KeyUse resolveKeyUse(Credential credential) {
+ if (credential.getUsageType().equals(UsageType.SIGNING)) {
+ return KeyUse.SIGNATURE;
+ }
+ if (credential.getUsageType().equals(UsageType.ENCRYPTION)) {
+ return KeyUse.ENCRYPTION;
+ }
+ return null;
+ }
+
+ /**
+ * Convert credential to JWK. Only RSA and EC keys supported.
+ *
+ * @param credential to convert.
+ * @return credential as JWK.
+ */
+ private JWK credentialToKey(Credential credential) {
+ JWK key = null;
+ switch (credential.getPublicKey().getAlgorithm()) {
+ case "RSA":
+ key = new RSAKey.Builder((RSAPublicKey) credential.getPublicKey()).keyUse(resolveKeyUse(credential))
+ .keyID(CredentialConversionUtil.resolveKid(credential)).build();
+ break;
+
+ case "EC":
+ key = new ECKey.Builder(Curve.forECParameterSpec(((ECPublicKey) credential.getPublicKey()).getParams()),
+ (ECPublicKey) credential.getPublicKey()).keyUse(resolveKeyUse(credential))
+ .keyID(CredentialConversionUtil.resolveKid(credential)).build();
+ default:
+ break;
+ }
+ return key;
+ }
+
+ protected ClientID parseClientID(final OAuthRPRoleDescriptorType roleDescriptor) {
+ if (!roleDescriptor.hasParent() || !(roleDescriptor.getParent() instanceof EntityDescriptor)) {
+ log.warn("Unexpected structure, EntityDescriptor not as a parent for OAuthRPRoleDescriptor");
+ return null;
+ }
+ final EntityDescriptor entityDescriptor = (EntityDescriptor) roleDescriptor.getParent();
+ return new ClientID(entityDescriptor.getEntityID());
+ }
+
+ protected OIDCClientMetadata populateMetadata(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final OIDCClientMetadata metadata = new OIDCClientMetadata();
+ metadata.setApplicationType(parseApplicationType(roleDescriptor));
+ metadata.setURI(getSingleURIValue(roleDescriptor.getClientUri()));
+ metadata.setDefaultACRs(parseDefaultAcrValues(roleDescriptor));
+ metadata.setGrantTypes(parseGrantTypes(roleDescriptor));
+ metadata.setIDTokenJWEAlg(parseJweAlgorithm(roleDescriptor.getIdTokenEncryptionResponseAlg()));
+ metadata.setIDTokenJWEEnc(parseEncryptionMethod(roleDescriptor.getIdTokenEncryptionResponseEnc()));
+ metadata.setIDTokenJWSAlg(parseJwsAlgorithm(roleDescriptor.getIdTokenSignedResponseAlg()));
+ metadata.setInitiateLoginURI(getSingleURIValue(roleDescriptor.getInitiateLoginUri()));
+ metadata.setJWKSetURI(getSingleURIValue(roleDescriptor.getJwksUri()));
+ metadata.setPostLogoutRedirectionURIs(parseUris(roleDescriptor.getPostLogoutRedirectUris()));
+ metadata.setRedirectionURIs(parseUris(roleDescriptor.getRedirectUris()));
+ metadata.setRequestObjectJWEAlg(parseJweAlgorithm(roleDescriptor.getRequestObjectEncryptionResponseAlg()));
+ metadata.setRequestObjectJWEEnc(parseEncryptionMethod(roleDescriptor.getRequestObjectEncryptionResponseEnc()));
+ metadata.setRequestObjectJWSAlg(parseJwsAlgorithm(roleDescriptor.getRequestObjectSignedResponseAlg()));
+ metadata.setRequestObjectURIs(parseUris(roleDescriptor.getRequestUris()));
+ metadata.setResponseTypes(parseResponseTypes(roleDescriptor));
+ metadata.setScope(parseScope(roleDescriptor));
+ metadata.setSectorIDURI(getSingleURIValue(roleDescriptor.getSectorIdentifierUri()));
+ final String softwareId = getSingleValue(roleDescriptor.getSoftwareId());
+ if (softwareId != null) {
+ metadata.setSoftwareID(new SoftwareID(softwareId));
+ }
+ final String softwareVersion = getSingleValue(roleDescriptor.getSoftwareVersion());
+ if (softwareVersion != null) {
+ metadata.setSoftwareVersion(new SoftwareVersion(softwareVersion));
+ }
+ metadata.setSubjectType(parseSubjectType(roleDescriptor));
+ metadata.setTokenEndpointAuthMethod(parseClientAuthenticationMethod(roleDescriptor));
+ metadata.setTokenEndpointAuthJWSAlg(parseJwsAlgorithm(roleDescriptor.getTokenEndpointAuthSigningAlg()));
+ metadata.setUserInfoJWEAlg(parseJweAlgorithm(roleDescriptor.getUserInfoEncryptionResponseAlg()));
+ metadata.setUserInfoJWEEnc(parseEncryptionMethod(roleDescriptor.getUserInfoEncryptionResponseEnc()));
+ metadata.setUserInfoJWSAlg(parseJwsAlgorithm(roleDescriptor.getUserInfoSignedResponseAlg()));
+ return metadata;
+ }
+
+ protected ClientAuthenticationMethod parseClientAuthenticationMethod(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final String metadataValue = getSingleValue(roleDescriptor.getTokenEndpointAuthMethod());
+ if (metadataValue == null) {
+ return null;
+ }
+ return ClientAuthenticationMethod.parse(metadataValue);
+ }
+
+ protected ApplicationType parseApplicationType(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final String metadataValue = getSingleValue(roleDescriptor.getApplicationType());
+ if (ApplicationType.NATIVE.toString().equalsIgnoreCase(metadataValue)) {
+ return ApplicationType.NATIVE;
+ }
+ return ApplicationType.WEB;
+ }
+
+ protected SubjectType parseSubjectType(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final String metadataValue = getSingleValue(roleDescriptor.getSubjectType());
+ if (SubjectType.PAIRWISE.toString().equalsIgnoreCase(metadataValue)) {
+ return SubjectType.PAIRWISE;
+ }
+ return SubjectType.PUBLIC;
+ }
+
+ protected List<ACR> parseDefaultAcrValues(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final List<ACR> acrs = new ArrayList<>();
+ for (final DefaultAcrValue acr : roleDescriptor.getDefaultAcrValues()) {
+ final String value = getSingleValue(acr);
+ if (value != null) {
+ acrs.add(new ACR(value));
+ }
+ }
+ return acrs;
+ }
+
+ protected Set<GrantType> parseGrantTypes(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final Set<GrantType> grantTypes = new HashSet<>();
+ for (final net.shibboleth.idp.saml.oidc.xmlobject.GrantType grantType : roleDescriptor.getGrantTypes()) {
+ final String value = getSingleValue(grantType);
+ if (value != null) {
+ grantTypes.add(new GrantType(value));
+ }
+ }
+ return grantTypes;
+ }
+
+ protected Set<ResponseType> parseResponseTypes(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final Set<ResponseType> responseTypes = new HashSet<>();
+ for (final net.shibboleth.idp.saml.oidc.xmlobject.ResponseType responseType : roleDescriptor.getResponseTypes()) {
+ final String value = getSingleValue(responseType);
+ if (value != null) {
+ responseTypes.add(new ResponseType(value));
+ }
+ }
+ return responseTypes;
+ }
+
+ protected Scope parseScope(final OAuthRPRoleDescriptorType roleDescriptor) {
+ final Scope scope = new Scope();
+ for (final net.shibboleth.idp.saml.oidc.xmlobject.Scope singleScope : roleDescriptor.getScopes()) {
+ final String value = getSingleValue(singleScope);
+ if (value != null) {
+ scope.add(value);
+ }
+ }
+ if (!scope.contains("openid")) {
+ scope.add("openid");
+ }
+ return scope;
+ }
+
+ protected JWEAlgorithm parseJweAlgorithm(final MetadataValueSAMLObject metadataValue) {
+ final String value = getSingleValue(metadataValue);
+ if (value != null) {
+ return new JWEAlgorithm(value);
+ }
+ return null;
+ }
+
+ protected JWSAlgorithm parseJwsAlgorithm(final MetadataValueSAMLObject metadataValue) {
+ final String value = getSingleValue(metadataValue);
+ if (value != null) {
+ return new JWSAlgorithm(value);
+ }
+ return null;
+ }
+
+ protected EncryptionMethod parseEncryptionMethod(final MetadataValueSAMLObject metadataValue) {
+ final String value = getSingleValue(metadataValue);
+ if (value != null) {
+ return new EncryptionMethod(value);
+ }
+ return null;
+ }
+
+ protected Set<URI> parseUris(final List<? extends MetadataValueSAMLObject> listOfValues) {
+ final Set<URI> uris = new HashSet<>();
+ for (final MetadataValueSAMLObject value : listOfValues) {
+ final URI uri = getSingleURIValue(value);
+ if (uri != null) {
+ uris.add(uri);
+ }
+ }
+ return uris;
+ }
+
+ protected String getSingleValue(final MetadataValueSAMLObject metadataValue) {
+ if (metadataValue != null) {
+ return StringSupport.trimOrNull(metadataValue.getValue());
+ }
+ return null;
+ }
+
+ protected URI getSingleURIValue(final MetadataValueSAMLObject metadataValue) {
+ final String value = getSingleValue(metadataValue);
+ if (value != null) {
+ try {
+ return new URI(value);
+ } catch (URISyntaxException e) {
+ log.warn("Could not parse {} into an URI", value, e);
+ }
+ }
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/spring.handlers b/idp-oidc-extension-impl/src/main/resources/META-INF/spring.handlers
index 56325217..94d1859f 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/spring.handlers
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/spring.handlers
@@ -1,2 +1,3 @@
org.geant.idpextension.oidc.attribute.encoder = org.geant.idpextension.oidc.attribute.resolver.spring.enc.impl.AttributeEncoderNamespaceHandler
org.geant.idpextension.oidc.attribute.filter = org.geant.idpextension.oidc.attribute.filter.spring.impl.AttributeFilterNamespaceHandler
+urn\:mace\:shibboleth\:2.0\:metadata\:oidc = net.shibboleth.idp.profile.spring.relyingparty.metadata.oidc.impl.MetadataNamespaceHandler
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/spring.schemas b/idp-oidc-extension-impl/src/main/resources/META-INF/spring.schemas
index da0faa73..0bda88dc 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/spring.schemas
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/spring.schemas
@@ -1,2 +1,3 @@
classpath\:/schema/idp-oidc-extension-afp.xsd = schema/idp-oidc-extension-afp.xsd
-classpath\:/schema/idp-oidc-extension-attribute-encoder.xsd = schema/idp-oidc-extension-attribute-encoder.xsd
\ No newline at end of file
+classpath\:/schema/idp-oidc-extension-attribute-encoder.xsd = schema/idp-oidc-extension-attribute-encoder.xsd
+classpath\:/schema/idp-oidc-extension-metadata-ext.xsd = schema/idp-oidc-extension-metadata-ext.xsd
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-metadata-ext.xsd b/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-metadata-ext.xsd
new file mode 100644
index 00000000..5ed3ce0b
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/resources/schema/idp-oidc-extension-metadata-ext.xsd
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:shibmd="urn:mace:shibboleth:2.0:metadata"
+ targetNamespace="urn:mace:shibboleth:2.0:metadata:oidc" elementFormDefault="qualified">
+
+ <import namespace="urn:mace:shibboleth:2.0:metadata"
+ schemaLocation="http://shibboleth.net/schema/idp/shibboleth-metadata.xsd" />
+
+ <complexType name="ClientInformation">
+ <annotation>
+ <documentation>
+ A node processor that processes OAuthRP and attaches the parsed client
+ information via object metadata.
+ </documentation>
+ </annotation>
+ <complexContent>
+ <extension base="shibmd:MetadataNodeProcessorType"/>
+ </complexContent>
+ </complexType>
+
+</schema>
diff --git a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/metadata/impl/ClientInformationNodeProcessorTest.java b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/metadata/impl/ClientInformationNodeProcessorTest.java
new file mode 100644
index 00000000..5dfbfc8c
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/metadata/impl/ClientInformationNodeProcessorTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017 - 2020, GÉANT
+ *
+ * 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.geant.idpextension.oidc.metadata.impl;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.core.xml.XMLObjectBaseTestCase;
+import org.opensaml.saml.criterion.EntityRoleCriterion;
+import org.opensaml.saml.criterion.ProtocolCriterion;
+import org.opensaml.saml.metadata.resolver.filter.MetadataNodeProcessor;
+import org.opensaml.saml.metadata.resolver.filter.impl.NodeProcessingMetadataFilter;
+import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver;
+import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
+import net.shibboleth.idp.saml.oidc.xmlobject.OAuthRPRoleDescriptorType;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+public class ClientInformationNodeProcessorTest extends XMLObjectBaseTestCase {
+
+ private String mdFileName;
+
+ private FilesystemMetadataResolver mdProvider;
+
+ private PredicateRoleDescriptorResolver roleResolver;
+
+ @BeforeMethod
+ protected void setUp() throws Exception {
+ mdFileName = "/org/geant/idpextension/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd.xml";
+
+ URL mdURL = ClientInformationNodeProcessorTest.class.getResource(mdFileName);
+ File mdFile = new File(mdURL.toURI());
+
+ mdProvider = new FilesystemMetadataResolver(mdFile);
+ mdProvider.setParserPool(parserPool);
+ mdProvider.setId("test");
+ NodeProcessingMetadataFilter filter = new NodeProcessingMetadataFilter();
+ List<MetadataNodeProcessor> processors = new ArrayList<>();
+ processors.add(new ClientInformationNodeProcessor());
+ filter.setNodeProcessors(processors);
+ filter.initialize();
+ mdProvider.setMetadataFilter(filter);
+ mdProvider.initialize();
+
+ roleResolver = new PredicateRoleDescriptorResolver(mdProvider);
+ roleResolver.initialize();
+
+ }
+
+ // Success cases
+
+ /**
+ * Test valid index.
+ * @throws ResolverException
+ */
+ @Test
+ public void testWithValidIndex() throws ResolverException {
+ RoleDescriptor role = roleResolver.resolveSingle(new CriteriaSet(
+ new EntityIdCriterion("mockSamlClientId"),
+ new EntityRoleCriterion(OAuthRPRoleDescriptorType.DEFAULT_ELEMENT_NAME),
+ new ProtocolCriterion("http://openid.net/specs/openid-connect-core-1_0.html")));
+ Assert.assertNotNull(role);
+
+ System.out.println(role.getClass());
+ final OAuthRPRoleDescriptorType rp = (OAuthRPRoleDescriptorType) role;
+ System.out.println(rp.getRedirectUris().get(0).getValue());
+ System.out.println(rp.getRedirectUris().get(1).getValue());
+ System.out.println(rp.getResponseTypes().get(0).getValue());
+ System.out.println(rp.getGrantTypes().get(0).getValue());
+ System.out.println(rp.getApplicationType().getValue());
+ System.out.println(rp.getDefaultMaxAge());
+ System.out.println(rp.isRequireAuthTime());
+
+ final List<OIDCClientInformation> clientInformations = rp.getObjectMetadata().get(OIDCClientInformation.class);
+ if (clientInformations != null && clientInformations.size() > 0) {
+ System.out.println("Katsos: " + clientInformations.get(0).getID());
+ }
+ }
+
+}
diff --git a/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd.xml b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd.xml
new file mode 100644
index 00000000..c3304734
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/EntitiesDescriptor-with-oidcmd.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" Name="RP test">
+
+ <md:EntityDescriptor entityID="mockSamlClientId">
+
+ <md:RoleDescriptor xmlns:oidcmd="urn:mace:shibboleth:metadata:oidc:1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:type="oidcmd:OAuthRPRoleDescriptorType"
+ protocolSupportEnumeration="http://openid.net/specs/openid-connect-core-1_0.html"
+ defaultMaxAge="123"
+ requireAuthTime="true">
+ <md:KeyDescriptor use="signing">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:X509Data>
+ <ds:X509Certificate>
+MIIEQDCCAqigAwIBAgIVAIarXvdvyS47KJR7U40FlTufyD8vMA0GCSqGSIb3DQEB
+CwUAMCAxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2NhbGRvbWFpbjAeFw0xOTA2MTcx
+MTI5MTJaFw0zOTA2MTcxMTI5MTJaMCAxHjAcBgNVBAMMFWxvY2FsaG9zdC5sb2Nh
+bGRvbWFpbjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALXysGFnoBFh
+oasd5uMecp9OTBjvztntPUVmHfm4R3AcItEMEZEN/pETcX/wgKdo4qCBq4PrZITa
+T8Salgl0XL6qF1Wia3JNA7Hh/OaoQEUsbsHgsjLMKt6MJh8vIaE1o8loL7Ay4WmZ
+Cr3wc8ZS6CpMsv+qbxkyfl1h7MTydETnQhg/X83bj+BjJSh7QeFU0d0SWK1dN2/D
+nFoGOfuTfVqeDRIwMxKlR5G//8N202sLaG28NljaHhLn3jHXeiGpCQ+Q2X90dkFb
+EKb6sQ6SlDUAzm9MwLYjglDyOhXpUqOnvD67nggLb4Gn/4k+g5wtdfr7unOJYcHK
+w7JGnI8Gd0lJMd6B3SpkhUOWgKv/D6HIBArhqSEmXuTyy8FewyYuo1XkIw/Lu3bB
+9qoBojM1tygoGlKi7R7e719J+DSkhyGbMyQ59leoN97iGGgqjUWS5mew8zSNviyz
+4uGqvxmLWU9UTH1YhlARsBF1bMiMnwLz7dF74AaAkC4pN3BYzDMyHQIDAQABo3Ew
+bzAdBgNVHQ4EFgQUwKUd9D1Qymu2oBEVTscrAhP+sIUwTgYDVR0RBEcwRYIVbG9j
+YWxob3N0LmxvY2FsZG9tYWluhixodHRwczovL2xvY2FsaG9zdC5sb2NhbGRvbWFp
+bi9pZHAvc2hpYmJvbGV0aDANBgkqhkiG9w0BAQsFAAOCAYEAEYqh54a+j5OuR1UB
+/AT9k2xXVwHiqQXAC/2un8O5BWAOeOq9+0gLJO5yaJp5c9GjPXRJmnDfGP9HFF6R
+CjngtRCm1gV/fpj97IRQS5oroaeTWPQ9ZD5+ogs5DNt6UZeJ2GqpfA5mOytNg3cM
+OP1B5QnA1apOaG4FHTegJR7WOIXkkAjEJUy6R+5Q6At7DdK/SRrP5onVPFv2HgGF
+E9v9iX/uQepDizS5F2oi6LZCl1/b38gxA8BFL7VZu53JQguaA7SrnP+dBOErT/yh
+Qcx3e9wE2ms8H1qISIdl3e7gvLi5jEyDWC9Agde6EjjvVVJAF7jR0puQ39mBfoxP
+moVdHJQmCt3V7Ew9tYZUpG3rjp4YNXOiM+QhtwhHWT94q9uJKUQ6JvbxgLNDs5KM
+3PENx2C60TPFne9nRRIMVDavU4wwY7GdCgeo8PiZ5zxI0ZCkxh38ODePtKQrxJ7i
+E0J1BE2LIxa1T7KY0XKpsH0iI2dNfZfNpNp4v/HiDb4svYgq
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+ <md:KeyDescriptor use="signing">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:X509Data>
+ <ds:X509Certificate>
+MIIBKDCBzgIJAOYlspXlaqguMAoGCCqGSM49BAMCMBwxCzAJBgNVBAYTAkZJMQ0w
+CwYDVQQDDAR0ZXN0MB4XDTE5MTEwMTA4Mjg0OVoXDTIwMTAzMTA4Mjg0OVowHDEL
+MAkGA1UEBhMCRkkxDTALBgNVBAMMBHRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAARCUOlFMtRj3MIbdCzXmoGz4giDwjzPoX4AxMehhlXmPOodQhLDdvDqx3KE
+hqadzIIsKHRQPDycscpHWpPbaQ2VMAoGCCqGSM49BAMCA0kAMEYCIQCVykSuUjlX
+j4lxI6YqgYVuuhL2rG4hIrXw/pCey7eF2gIhAOSSaS025lQWy09W4NlnO28OkHoI
++Hbap7+DQlhbbr2d
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+ <md:KeyDescriptor use="encryption">
+ <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+ <ds:X509Data>
+ <ds:X509Certificate>
+MIIBKDCBzgIJAOYlspXlaqguMAoGCCqGSM49BAMCMBwxCzAJBgNVBAYTAkZJMQ0w
+CwYDVQQDDAR0ZXN0MB4XDTE5MTEwMTA4Mjg0OVoXDTIwMTAzMTA4Mjg0OVowHDEL
+MAkGA1UEBhMCRkkxDTALBgNVBAMMBHRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAARCUOlFMtRj3MIbdCzXmoGz4giDwjzPoX4AxMehhlXmPOodQhLDdvDqx3KE
+hqadzIIsKHRQPDycscpHWpPbaQ2VMAoGCCqGSM49BAMCA0kAMEYCIQCVykSuUjlX
+j4lxI6YqgYVuuhL2rG4hIrXw/pCey7eF2gIhAOSSaS025lQWy09W4NlnO28OkHoI
++Hbap7+DQlhbbr2d
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+ <oidcmd:RedirectUri>https://example.org/cb</oidcmd:RedirectUri>
+ <oidcmd:RedirectUri>https://example.org/cb2</oidcmd:RedirectUri>
+ <oidcmd:GrantType>authorization_code</oidcmd:GrantType>
+ <oidcmd:ResponseType>code</oidcmd:ResponseType>
+ <oidcmd:ApplicationType>web</oidcmd:ApplicationType>
+ <oidcmd:TokenEndpointAuthMethod>client_secret_basic</oidcmd:TokenEndpointAuthMethod>
+ <oidcmd:Scope>openid</oidcmd:Scope>
+ <oidcmd:Scope>profile</oidcmd:Scope>
+ </md:RoleDescriptor>
+
+ </md:EntityDescriptor>
+
+</md:EntitiesDescriptor>
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list