[java-idp-oidc] 03/06: JOIDC-5 Initial version of a secret resolver based on Attribute Resolver.

Henri Mikkonen henri.mikkonen at iki.fi
Fri Jun 26 13:31:02 UTC 2020


This is an automated email from the git hooks/post-receive script.

hjmikkon pushed a commit to branch dev/JOIDC-5
in repository java-idp-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=a9ad6620575d038bc1cef59c7d2e24299bd2c3b7

commit a9ad6620575d038bc1cef59c7d2e24299bd2c3b7
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Jun 26 12:40:31 2020 +0300

    JOIDC-5 Initial version of a secret resolver based on Attribute Resolver.
    
    https://issues.shibboleth.net/jira/browse/JOIDC-5
    
    A new AttributeResolutionContext is constructed, and its populated with
    the client secret reference as principal and the related entity ID (RP
    client_id) as attribute recipient ID.
---
 .../ResolverServiceClientSecretValueResolver.java  | 160 ++++++++++++
 ...solverServiceClientSecretValueResolverTest.java | 283 +++++++++++++++++++++
 .../idpextension/oidc/metadata/impl/RdbmsData.sql  |   7 +
 .../idpextension/oidc/metadata/impl/RdbmsStore.sql |   5 +
 .../impl/attribute-resolver-clientsecrets.xml      |  53 ++++
 .../oidc/metadata/impl/ldapDataConnectorTest.ldif  |  26 ++
 .../idpextension/oidc/metadata/impl/service.xml    |  47 ++++
 7 files changed, 581 insertions(+)

diff --git a/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/metadata/impl/ResolverServiceClientSecretValueResolver.java b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/metadata/impl/ResolverServiceClientSecretValueResolver.java
new file mode 100644
index 00000000..fc136434
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/org/geant/idpextension/oidc/metadata/impl/ResolverServiceClientSecretValueResolver.java
@@ -0,0 +1,160 @@
+/*
+ * 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.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.geant.idpextension.oidc.criterion.ClientSecretReferenceCriterion;
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.resolver.AttributeResolver;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.collection.LazySet;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+import net.shibboleth.utilities.java.support.service.ReloadableService;
+
+/**
+ * A client secret value resolver that fetches the values from the given {@link AttributeResolver} service.
+ * 
+ * This class builds a new {@link AttributeResolutionContext} and sets the client secret reference key value to
+ * {@link AttributeResolutionContext#setPrincipal(String)} and its related entity ID to
+ * {@link AttributeResolutionContext#setAttributeRecipientID(String)}. The resolution context does not have any
+ * parent contexts.
+ */
+public class ResolverServiceClientSecretValueResolver extends AbstractClientSecretValueResolver {
+    
+    /** Class logger. */
+    private final Logger log = LoggerFactory.getLogger(ResolverServiceClientSecretValueResolver.class);
+   
+    /** The attribute resolver service used for the client secret value resolution. */
+    @NonnullAfterInit private ReloadableService<AttributeResolver> service;
+    
+    /** The list of attribute IDs that may contain the resolved client secret values. */
+    @Nonnull private List<String> attributeIds;
+    
+    /**
+     * Constructor.
+     */
+    public ResolverServiceClientSecretValueResolver() {
+        attributeIds = Collections.emptyList();
+    }
+    
+    /**
+     * Set the attribute resolver service used for the client secret value resolution.
+     * 
+     * @param resolver The attribute resolver service used for the client secret value resolution.
+     */
+    public void setAttributeResolver(@Nonnull final ReloadableService<AttributeResolver> resolver) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        service = Constraint.isNotNull(resolver, "Attribute resolver service can not be null");
+    }
+    
+    /**
+     * Get the attribute resolver service used for the client secret value resolution.
+     * 
+     * @return The attribute resolver service used for the client secret value resolution.
+     */
+    public @NonnullAfterInit ReloadableService<AttributeResolver> getAttributeResolver() {
+        return service;
+    }
+    
+    /**
+     * Set the list of attribute IDs that may contain the resolved client secret values.
+     * 
+     * @param ids The list of attribute IDs that may contain the resolved client secret values.
+     */
+    public void setAttributeIds(@Nonnull final List<String> ids) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        attributeIds = (List<String>) Constraint.isNotEmpty(ids, "The list of attribute ids cannot be empty");
+    }
+    
+    /**
+     * Get the list of attribute IDs that may contain the resolved client secret values.
+     * 
+     * @return The list of attribute IDs that may contain the resolved client secret values.
+     */
+    public @Nonnull List<String> getAttributeIds() {
+        return attributeIds;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public @Nonnull Iterable<String> resolve(@Nonnull final CriteriaSet criteria) throws ResolverException {
+        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        final ClientSecretReferenceCriterion referenceCriterion = criteria.get(ClientSecretReferenceCriterion.class);
+        Constraint.isNotNull(referenceCriterion,
+                "The client secret reference criterion must be included in the criteria.");
+
+        final AttributeResolutionContext resolutionContext = new AttributeResolutionContext();
+        resolutionContext.setPrincipal(referenceCriterion.getSecretReference());
+        if (criteria.contains(EntityIdCriterion.class)) {
+            resolutionContext.setAttributeRecipientID(criteria.get(EntityIdCriterion.class).getEntityId());
+        }
+        resolutionContext.resolveAttributes(service);
+        final Map<String, IdPAttribute> resolvedAttributes = resolutionContext.getResolvedIdPAttributes();
+        final LazySet<String> result = new LazySet<>();
+        for (final String attributeId : attributeIds) {
+            if (resolvedAttributes.containsKey(attributeId)) {
+                log.debug("Found a value for reference '{}' via attribute ID {}",
+                        referenceCriterion.getSecretReference(), attributeId);
+                result.add((String) resolvedAttributes.get(attributeId).getValues().get(0).getNativeValue());
+            }
+        }
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public @Nullable String resolveSingle(@Nonnull final CriteriaSet criteria) throws ResolverException {
+        final Iterator<String> iterator = resolve(criteria).iterator();
+        return iterator.hasNext() ? iterator.next() : null;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected void doDestroy() {
+        service = null;
+        attributeIds = null;
+        super.doDestroy();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (getAttributeResolver() == null) {
+            throw new ComponentInitializationException("Attribute resolver service can not be null");
+        }
+    }
+}
diff --git a/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/metadata/impl/ResolverServiceClientSecretValueResolverTest.java b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/metadata/impl/ResolverServiceClientSecretValueResolverTest.java
new file mode 100644
index 00000000..1bc18e78
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/org/geant/idpextension/oidc/metadata/impl/ResolverServiceClientSecretValueResolverTest.java
@@ -0,0 +1,283 @@
+/*
+ * 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.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.springframework.context.support.ConversionServiceFactoryBean;
+import org.springframework.context.support.GenericApplicationContext;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.listener.InMemoryListenerConfig;
+import com.unboundid.ldap.sdk.LDAPException;
+
+import net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor;
+import net.shibboleth.ext.spring.config.StringToDurationConverter;
+import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
+import net.shibboleth.idp.attribute.resolver.AttributeResolver;
+import net.shibboleth.idp.testing.DatabaseTestingSupport;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.UnmodifiableComponentException;
+import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+import net.shibboleth.utilities.java.support.service.ReloadableService;
+
+/**
+ * Unit tests for {@link ResolverServiceClientSecretValueResolver}.
+ * 
+ * Based on <pre>idp-attribute-resolver-spring</pre> / 
+ * <pre>net.shibboleth.idp.attribute.resolver.spring.AttributeResolverTest</pre>.
+ */
+public class ResolverServiceClientSecretValueResolverTest
+    extends BaseClientSecretValueResolverTest<ResolverServiceClientSecretValueResolver> {
+    
+    /** LDAP */
+    private InMemoryDirectoryServer directoryServer;
+
+    /** LDAP initialization. */
+    private static final String LDAP_INIT_FILE =
+            "src/test/resources/org/geant/idpextension/oidc/metadata/impl/ldapDataConnectorTest.ldif";
+
+    /** Database initialization. */
+    private static final String DB_INIT_FILE = "/org/geant/idpextension/oidc/metadata/impl/RdbmsStore.sql";
+
+    /** Database population. */
+    private static final String DB_DATA_FILE = "/org/geant/idpextension/oidc/metadata/impl/RdbmsData.sql";
+    
+    /** The resolver service configuration. */
+    private static final String SERVICE_CONF_FILE = "/org/geant/idpextension/oidc/metadata/impl/service.xml";
+
+    private GenericApplicationContext pendingTeardownContext = null;
+    
+    String entityId = "CLIENT_ID_ONE";
+    String entityId2 = "CLIENT_ID_TWO";
+    
+    String clientSecretKeyReferenceBoth = "keyReferenceOne";
+    String clientSecretKeyReferenceOnlyLdap = "keyReferenceTwo";
+    
+    String clientSecretValueRdbms = "thePlainTextSecretValue1234567890";
+    String clientSecretValueLdap = "thePlainTextSecretValue9876543210";
+
+    
+    @AfterMethod public void tearDownTestContext() {
+        if (null == pendingTeardownContext ) {
+            return;
+        }
+        pendingTeardownContext.close();
+        pendingTeardownContext = null;
+    }
+    
+    protected void setTestContext(final GenericApplicationContext context) {
+        tearDownTestContext();
+        pendingTeardownContext = context;
+    }
+
+    @BeforeTest public void setupDataConnectors() throws LDAPException {
+
+        System.setProperty("org.ldaptive.provider", "org.ldaptive.provider.unboundid.UnboundIDProvider");
+        
+        // LDAP
+        final InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=shibboleth,dc=net");
+        config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", 10391));
+        config.addAdditionalBindCredentials("cn=Directory Manager", "password");
+        directoryServer = new InMemoryDirectoryServer(config);
+        directoryServer.importFromLDIF(true, LDAP_INIT_FILE);
+        directoryServer.startListening();
+
+        // RDBMS
+        final DataSource datasource = DatabaseTestingSupport.GetMockDataSource(DB_INIT_FILE, "myTestDB");
+        DatabaseTestingSupport.InitializeDataSourceFromFile(DB_DATA_FILE, datasource);
+
+    }
+
+    /**
+     * Shutdown the in-memory directory server.
+     */
+    @AfterTest public void teardownDataConnectors() {
+        directoryServer.shutDown(true);
+        
+        System.clearProperty("org.ldaptive.provider");
+    }
+    
+    protected ReloadableService<AttributeResolver> getResolver() {
+        final GenericApplicationContext context = new GenericApplicationContext();
+        context.getBeanFactory().addBeanPostProcessor(new IdentifiableBeanPostProcessor());
+        setTestContext(context);
+        context.setDisplayName("ApplicationContext: " + ResolverServiceClientSecretValueResolverTest.class);
+
+        final ConversionServiceFactoryBean service = new ConversionServiceFactoryBean();
+        context.setDisplayName("ApplicationContext: ");
+        service.setConverters(new HashSet<>(Arrays.asList(new StringToDurationConverter())));
+        service.afterPropertiesSet();
+
+        context.getBeanFactory().setConversionService(service.getObject());
+        
+        final SchemaTypeAwareXMLBeanDefinitionReader beanDefinitionReader =
+                new SchemaTypeAwareXMLBeanDefinitionReader(context);
+
+        beanDefinitionReader.loadBeanDefinitions(SERVICE_CONF_FILE);
+        context.refresh();
+
+        return context.getBean(ReloadableService.class);
+    }
+        
+    @Test(expectedExceptions = ComponentInitializationException.class)
+    public void initialize_shouldThrowWhenAttributeResolverNotSet() throws ComponentInitializationException {
+        resolver = new ResolverServiceClientSecretValueResolver();
+        resolver.setId("mockId");
+        resolver.initialize();
+    }
+    
+    @Test(expectedExceptions = ConstraintViolationException.class)
+    public void setAttributeResolver_shouldThrowIfAttributeResolverIsNull() {
+        resolver = new ResolverServiceClientSecretValueResolver();
+        resolver.setAttributeResolver(null);
+    }
+    
+    @Test(expectedExceptions = UnmodifiableComponentException.class)
+    public void setAttributeResolver_shouldThrowAfterInit() throws ComponentInitializationException {
+        resolver = buildResolver(true);
+        resolver.setAttributeResolver(getResolver());
+    }
+
+    @Test(expectedExceptions = ConstraintViolationException.class)
+    public void setAttributeIds_shouldThrowIfAttributeIdsNull() throws ComponentInitializationException {
+        resolver = new ResolverServiceClientSecretValueResolver();
+        resolver.setAttributeIds(null);
+    }
+
+    @Test(expectedExceptions = ConstraintViolationException.class)
+    public void setAttributeIds_shouldThrowIfAttributeIdsEmpty() throws ComponentInitializationException {
+        resolver = new ResolverServiceClientSecretValueResolver();
+        resolver.setAttributeIds(Collections.emptyList());
+    }
+
+    @Test(expectedExceptions = UnmodifiableComponentException.class)
+    public void setAttributeIds_shouldThrowAfterInit() throws ComponentInitializationException {
+        resolver = buildResolver(true);
+        resolver.setAttributeIds(Arrays.asList("myDBClientSecret", "myLDAPClientSecret"));
+    }
+
+    @Test
+    public void resolveSingle_shouldReturnNullWhenValuesNotFound() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true);
+        Assert.assertNull(resolver.resolveSingle(buildCriteriaSet("not_found")));
+    }
+
+    @Test
+    public void resolveSingle_shouldReturnRdbmsValueWhenFound() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true, Arrays.asList("myDBClientSecret"));
+        Assert.assertEquals(resolver.resolveSingle(buildCriteriaSet(clientSecretKeyReferenceBoth, entityId)),
+                clientSecretValueRdbms);
+    }
+
+    @Test
+    public void resolveSingle_shouldReturnLdapValueWhenFound() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true, Arrays.asList("myLDAPClientSecret"));
+        Assert.assertEquals(resolver.resolveSingle(buildCriteriaSet(clientSecretKeyReferenceBoth, entityId)),
+                clientSecretValueLdap);
+    }
+
+    @Test
+    public void resolveSingle_shouldReturnLdapValueWhenOnlyFoundFromLdap() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true, Arrays.asList("myDBClientSecret", "myLDAPClientSecret"));
+        Assert.assertEquals(resolver.resolveSingle(buildCriteriaSet(clientSecretKeyReferenceOnlyLdap, entityId2)),
+                "thePlainTextSecretValue1111111111");
+    }
+
+    @Test
+    public void resolve_shouldReturnEmptyIteratorWhenValuesNotFound() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true);
+        final Iterable<String> iterable = resolver.resolve(buildCriteriaSet("not_found"));
+        Assert.assertNotNull(iterable);
+        Assert.assertFalse(iterable.iterator().hasNext());
+    }
+
+    @Test
+    public void resolve_shouldReturnOneValueIteratorWhenSingleValueFound() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true);
+        final Iterable<String> iterable 
+            = resolver.resolve(buildCriteriaSet(clientSecretKeyReferenceOnlyLdap, entityId2));
+        Assert.assertNotNull(iterable);
+        final Iterator<String> iterator = iterable.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), "thePlainTextSecretValue1111111111");
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void resolve_shouldReturnTwoValueIteratorWhenFoundFromBoth() throws ResolverException,
+        ComponentInitializationException {
+        resolver = buildResolver(true);
+        final Iterable<String> iterable = resolver.resolve(buildCriteriaSet(clientSecretKeyReferenceBoth, entityId));
+        Assert.assertNotNull(iterable);
+        final Iterator<String> iterator = iterable.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        final String firstValue = iterator.next();
+        Assert.assertTrue(firstValue.equals(clientSecretValueLdap) || firstValue.equals(clientSecretValueRdbms));
+        Assert.assertTrue(iterator.hasNext());
+        final String secondValue = iterator.next();
+        Assert.assertFalse(firstValue.equals(secondValue));
+        Assert.assertTrue(secondValue.equals(clientSecretValueLdap) || secondValue.equals(clientSecretValueRdbms));        
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Override
+    protected ResolverServiceClientSecretValueResolver buildResolver(boolean init)
+            throws ComponentInitializationException {
+        return buildResolver(init, Arrays.asList("myDBClientSecret", "myLDAPClientSecret"));
+    }
+    
+    protected ResolverServiceClientSecretValueResolver buildResolver(boolean init, List<String> attributeIds)
+            throws ComponentInitializationException {
+        ResolverServiceClientSecretValueResolver resolver = new ResolverServiceClientSecretValueResolver();
+        resolver.setAttributeResolver(getResolver());
+        resolver.setAttributeIds(attributeIds);
+        resolver.setId("resolver");
+        if (init) {
+            resolver.initialize();
+        }
+        return resolver;
+    }
+    
+    protected CriteriaSet buildCriteriaSet(final String secretReference, final String clientId) {
+        final CriteriaSet criteria = super.buildCriteriaSet(secretReference);
+        criteria.add(new EntityIdCriterion(clientId));
+        return criteria;
+    }
+
+}
diff --git a/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/RdbmsData.sql b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/RdbmsData.sql
new file mode 100644
index 00000000..483921be
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/RdbmsData.sql
@@ -0,0 +1,7 @@
+INSERT INTO clientSecrets
+        (entityId, clientSecretKeyReference, clientSecretValue)
+         values (
+         'CLIENT_ID_ONE',
+         'keyReferenceOne',
+         'thePlainTextSecretValue1234567890');
+
diff --git a/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/RdbmsStore.sql b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/RdbmsStore.sql
new file mode 100644
index 00000000..b4980e4b
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/RdbmsStore.sql
@@ -0,0 +1,5 @@
+CREATE TABLE clientSecrets (
+        entityId VARCHAR(250) NOT NULL,
+        clientSecretKeyReference VARCHAR(250) NOT NULL,
+        clientSecretValue VARCHAR(250) NOT NULL);
+
diff --git a/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/attribute-resolver-clientsecrets.xml b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/attribute-resolver-clientsecrets.xml
new file mode 100644
index 00000000..69e60d11
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/attribute-resolver-clientsecrets.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AttributeResolver xmlns="urn:mace:shibboleth:2.0:resolver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                   xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
+
+    <!-- ========================================== -->
+    <!--      Attribute Definitions                 -->
+    <!-- ========================================== -->
+
+    <AttributeDefinition xsi:type="Simple" id="myLDAPClientSecret">
+        <InputDataConnector ref="myLDAP" attributeNames="mobile"/>
+    </AttributeDefinition>
+
+    
+    <AttributeDefinition xsi:type="Simple" id="myDBClientSecret">
+        <InputDataConnector ref="myDB" attributeNames="CLIENTSECRETVALUE"/>
+    </AttributeDefinition>
+    
+    <!-- ========================================== -->
+    <!--      Data Connectors                       -->
+    <!-- ========================================== -->
+
+    <!-- Example Relational Database Connector -->
+
+    <DataConnector id="myDB" xsi:type="RelationalDatabase">
+        <SimpleManagedConnection
+	        jdbcDriver="org.hsqldb.jdbc.JDBCDriver"
+	        jdbcURL="jdbc:hsqldb:mem:myTestDB"
+	        jdbcUserName="SA"
+	        jdbcPassword="" />
+        <QueryTemplate>
+            <![CDATA[ 
+                SELECT * FROM clientSecrets WHERE clientSecretKeyReference = '$resolutionContext.principal' AND entityId = '$resolutionContext.attributeRecipientID'
+            ]]>
+        </QueryTemplate>
+    </DataConnector>
+     
+
+    <!-- Example LDAP Connector -->
+    <DataConnector id="myLDAP" xsi:type="LDAPDirectory"
+        ldapURL="ldap://localhost:10391" 
+        baseDN="dc=shibboleth,dc=net"
+        connectTimeout="PT6S"
+        responseTimeout="PT6S"
+        principal="cn=Directory Manager"
+        principalCredential="password">
+        <FilterTemplate>
+            <![CDATA[
+                (uid=$resolutionContext.principal)
+            ]]>
+        </FilterTemplate>
+    </DataConnector>
+
+</AttributeResolver>
diff --git a/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/ldapDataConnectorTest.ldif b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/ldapDataConnectorTest.ldif
new file mode 100644
index 00000000..30e88e48
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/ldapDataConnectorTest.ldif
@@ -0,0 +1,26 @@
+dn: dc=shibboleth,dc=net
+dc: shibboleth
+objectClass: dcObject
+objectClass: organization
+o: Shibboleth, Inc.
+
+dn: ou=clientsecrets,dc=shibboleth,dc=net
+ou: clientsecrets
+description: Client secrets
+objectclass: organizationalunit
+
+dn: cn=CLIENT_ID_ONE,ou=clientsecrets,dc=shibboleth,dc=net
+objectclass: inetOrgPerson
+cn: CLIENT_ID_ONE
+sn: Ignored
+uid: keyReferenceOne
+mobile: thePlainTextSecretValue9876543210
+description: test principal
+
+dn: cn=CLIENT_ID_TWO,ou=clientsecrets,dc=shibboleth,dc=net
+objectclass: inetOrgPerson
+cn: CLIENT_ID_TWO
+sn: Ignored
+uid: keyReferenceTwo
+mobile: thePlainTextSecretValue1111111111
+description: test principal
diff --git a/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/service.xml b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/service.xml
new file mode 100644
index 00000000..34d6966b
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/resources/org/geant/idpextension/oidc/metadata/impl/service.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xmlns:util="http://www.springframework.org/schema/util"
+        xmlns:p="http://www.springframework.org/schema/p"
+        xmlns:c="http://www.springframework.org/schema/c"
+        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+        default-init-method="initialize"
+        default-destroy-method="destroy">
+                            
+    <!-- This BeanPostProcessor auto-sets identifiable beans with the bean name (if not already set). -->
+    <bean id="shibboleth.IdentifiableBeanPostProcessor"
+        class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />     
+                            
+    <bean id="shibboleth.VelocityEngine" class="net.shibboleth.ext.spring.velocity.VelocityEngineFactoryBean">
+        <property name="velocityProperties">
+            <props>
+                <prop key="resource.loader">classpath, string</prop>
+                <prop key="classpath.resource.loader.class">
+                    org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
+                </prop>
+                <prop key="string.resource.loader.class">
+                    org.apache.velocity.runtime.resource.loader.StringResourceLoader
+                </prop>
+            </props>
+        </property>
+    </bean>
+    
+    <bean id="shibboleth.ClientSecretValueResolverService" class="net.shibboleth.ext.spring.service.ReloadableSpringService"
+        depends-on="shibboleth.VelocityEngine"
+        p:beanPostProcessors-ref="shibboleth.IdentifiableBeanPostProcessor"
+        p:failFast="false" p:reloadCheckDelay="0">
+        
+        <constructor-arg name="claz"
+            value="net.shibboleth.idp.attribute.resolver.AttributeResolver" />
+        <constructor-arg name="strategy">
+            <bean
+                class="net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverServiceStrategy"
+                p:id="Shibboleth.Resolver" />
+        </constructor-arg>
+        <property name="serviceConfigurations">
+            <util:list>
+                <value>org/geant/idpextension/oidc/metadata/impl/attribute-resolver-clientsecrets.xml</value>
+            </util:list>
+        </property>
+    </bean>
+</beans>
\ 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