<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">Shane - the configuration API is
      important. Go ahead.<br>
      <br>
      On 11/06/2012 10:34 AM, Jason Porter wrote:<br>
    </div>
    <blockquote
cite="mid:CAF9TksNcbOV=RmEEbDsdtyGtfMf0Y5i_N1QqLNY9YC49M6LpRg@mail.gmail.com"
      type="cite">+1 at all sounds good to me.
      <div class="gmail_extra"><br>
        <br>
        <div class="gmail_quote">On Tue, Nov 6, 2012 at 3:08 AM, Shane
          Bryzak <span dir="ltr">&lt;<a moz-do-not-send="true"
              href="mailto:sbryzak@redhat.com" target="_blank">sbryzak@redhat.com</a>&gt;</span>
          wrote:<br>
          <blockquote class="gmail_quote" style="margin:0 0 0
            .8ex;border-left:1px #ccc solid;padding-left:1ex">Hey guys,<br>
            <br>
            For the past few days I've been wracking my brain trying to
            come up with<br>
            a design for the IDM configuration API that doesn't suck,
            and allows<br>
            easy configuration in both Java SE and EE environments while
            maintaining<br>
            separation between the API and implementation. &nbsp;I think I've
            come up<br>
            with something that's quite flexible and extensible, so I'd
            like to run<br>
            it past everyone for some feedback.<br>
            <br>
            The starting point for configuring the Identity Management
            API is a<br>
            concrete class called IdentityConfiguration:<br>
            <br>
            public class IdentityConfiguration {<br>
            &nbsp; &nbsp; &nbsp;private List&lt;IdentityStoreConfiguration&gt;
            configuredStores = new<br>
            ArrayList&lt;IdentityStoreConfiguration&gt;();<br>
            &nbsp; &nbsp; &nbsp;public List&lt;IdentityStoreConfiguration&gt;
            getConfiguredStores() {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return configuredStores;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void
            addStoreConfiguration(IdentityStoreConfiguration config) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;configuredStores.add(config);<br>
            &nbsp; &nbsp; &nbsp;}<br>
            }<br>
            <br>
            This class simply provides a holder for one or more<br>
            IdentityStoreConfiguration(s), an abstract class that
            provides the<br>
            basics for configuring an IdentityStore:<br>
            <br>
            public abstract class IdentityStoreConfiguration {<br>
            &nbsp; &nbsp; &nbsp;private final Map&lt;String,String&gt; properties = new<br>
            HashMap&lt;String,String&gt;();<br>
            &nbsp; &nbsp; &nbsp;private final Set&lt;Feature&gt; supportedFeatures =
            new HashSet&lt;Feature&gt;();<br>
            &nbsp; &nbsp; &nbsp;public Set&lt;Feature&gt; getSupportedFeatures() {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return supportedFeatures;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void addSupportedFeature(Feature feature) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;supportedFeatures.add(feature);<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void removeSupportedFeature(Feature feature) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;supportedFeatures.remove(feature);<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void setProperty(String name, String value) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;properties.put(name, value);<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public String getPropertyValue(String name) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return properties.get(name);<br>
            &nbsp; &nbsp; &nbsp;}<br>
            }<br>
            <br>
            Each IdentityStore implementation (such as JPAIdentityStore,<br>
            LDAPIdentityStore, etc) should have a corresponding<br>
            IdentityStoreConfiguration implementation that provides an
            API for<br>
            setting specific property values for its IdentityStore. &nbsp;For
            example,<br>
            this is the one for JPAIdentityStore which allows a number
            of entity<br>
            classes to be set:<br>
            <br>
            public class JPAIdentityStoreConfiguration extends<br>
            IdentityStoreConfiguration {<br>
            &nbsp; &nbsp; &nbsp;private Class&lt;?&gt; identityClass;<br>
            &nbsp; &nbsp; &nbsp;private Class&lt;?&gt; membershipClass;<br>
            &nbsp; &nbsp; &nbsp;private Class&lt;?&gt; credentialClass;<br>
            &nbsp; &nbsp; &nbsp;private Class&lt;?&gt; attributeClass;<br>
            &nbsp; &nbsp; &nbsp;public Class&lt;?&gt; getIdentityClass() {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return identityClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void setIdentityClass(Class&lt;?&gt;
            identityClass) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.identityClass = identityClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public Class&lt;?&gt; getCredentialClass() {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return credentialClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void setCredentialClass(Class&lt;?&gt;
            credentialClass) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.credentialClass = credentialClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public Class&lt;?&gt; getMembershipClass() {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return membershipClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void setMembershipClass(Class&lt;?&gt;
            membershipClass) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.membershipClass = membershipClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public Class&lt;?&gt; getAttributeClass() {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return attributeClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            &nbsp; &nbsp; &nbsp;public void setAttributeClass(Class&lt;?&gt;
            attributeClass) {<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.attributeClass = attributeClass;<br>
            &nbsp; &nbsp; &nbsp;}<br>
            }<br>
            <br>
            The IdentityStore-specific configurations are intended to be
            part of the<br>
            API, so they should be placed in the API module within the<br>
            org.picketlink.idm.config package.<br>
            <br>
            After creating an IdentityConfiguration, you can create an<br>
            IdentityManager and provide the configuration via the
            bootstrap() method:<br>
            <br>
            IdentityConfiguration identityConfig = new
            IdentityConfiguration();<br>
            JPAIdentityStoreConfiguration storeConfig = new<br>
            JPAIdentityStoreConfiguration();<br>
            // snip storeConfig configuration<br>
            <br>
            identityConfig.addStoreConfiguration(storeConfig);<br>
            <br>
            IdentityManager identityManager = new
            DefaultIdentityManager();<br>
            identityManager.bootstrap(identityConfig, new<br>
            DefaultIdentityStoreInvocationContextFactory(null));<br>
            <br>
            The reason we use bootstrap() instead of performing
            configuration in the<br>
            constructor is so the developer has a chance to override the<br>
            IdentityStoreFactory. &nbsp;This is an SPI interface that defines
            a couple of<br>
            methods which are used to control which
            IdentityStoreConfigurations<br>
            correspond to which IdentityStore.<br>
            <br>
            public interface IdentityStoreFactory {<br>
            &nbsp; &nbsp; &nbsp;/**<br>
            &nbsp; &nbsp; &nbsp; * Creates an instance of an IdentityStore using the
            provided<br>
            configuration<br>
            &nbsp; &nbsp; &nbsp; *<br>
            &nbsp; &nbsp; &nbsp; * @param config<br>
            &nbsp; &nbsp; &nbsp; * @return<br>
            &nbsp; &nbsp; &nbsp; */<br>
            &nbsp; &nbsp; &nbsp;IdentityStore
            createIdentityStore(IdentityStoreConfiguration config);<br>
            <br>
            &nbsp; &nbsp; &nbsp;/**<br>
            &nbsp; &nbsp; &nbsp; * Maps specific implementations of
            IdentityStoreConfiguration to a<br>
            corresponding<br>
            &nbsp; &nbsp; &nbsp; * IdentityStore implementation.<br>
            &nbsp; &nbsp; &nbsp; *<br>
            &nbsp; &nbsp; &nbsp; * @param configClass<br>
            &nbsp; &nbsp; &nbsp; * @param storeClass<br>
            &nbsp; &nbsp; &nbsp; */<br>
            &nbsp; &nbsp; &nbsp;void mapConfiguration(Class&lt;? extends
            IdentityStoreConfiguration&gt;<br>
            configClass,<br>
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Class&lt;? extends IdentityStore&gt;
            storeClass);<br>
            }<br>
            <br>
            By default, the DefaultIdentityManager will create and use
            an instance<br>
            of DefaultIdentityStoreFactory - this factory knows about
            all the<br>
            built-in IdentityStore implementations and can create
            IdentityStore<br>
            instances based on their corresponding
            IdentityStoreConfiguration. &nbsp;If a<br>
            developer wished to provide their own IdentityStore though
            (or override<br>
            the behaviour of one of the built-in ones) then we need to
            provide a<br>
            hook to allow them to override the default factory with
            their own. &nbsp;This<br>
            is provided by the IdentityManager.setIdentityStoreFactory()
            method - by<br>
            invoking this method with a new IdentityStoreFactory the
            developer can<br>
            provide an alternative factory for creating IdentityStore
            instances<br>
            based on non built-in configurations before bootstrap() is
            called.<br>
            <br>
            Here's an example where the built-in identity stores are
            supplemented<br>
            with support for a native Hibernate-based identity store:<br>
            <br>
            IdentityManager identityManager = new
            DefaultIdentityManager();<br>
            <br>
            DefaultIdentityStoreFactory factory = new
            DefaultIdentityStoreFactory();<br>
factory.mapConfiguration(HibernateIdentityStoreConfiguration.class,<br>
            HibernateIdentityStore.class);<br>
            identityManager.setIdentityStoreFactory(factory);<br>
            <br>
            identityManager.bootstrap(identityConfig, new<br>
            DefaultIdentityStoreInvocationContextFactory(null));<br>
            <br>
            The last piece of the puzzle is the second parameter to the
            bootstrap()<br>
            method. &nbsp;This parameter should be an instance of<br>
            IdentityStoreInvocationContextFactory (I know, it's a
            mouthful), an SPI<br>
            interface that declares a single method:<br>
            <br>
            public interface IdentityStoreInvocationContextFactory {<br>
            &nbsp; &nbsp; &nbsp;IdentityStoreInvocationContext getContext(IdentityStore
            store);<br>
            }<br>
            <br>
            The implementation of this interface is responsible for
            creating<br>
            IdentityStoreInvocationContext instances, which are passed
            as a<br>
            parameter value to pretty much all of the IdentityStore
            methods and<br>
            allow the IdentityStore implementation to be shared between
            multiple<br>
            threads (i.e. a stateless design). &nbsp;The
            IdentityStoreInvocationContext<br>
            is responsible for providing the IdentityStore with any
            state (besides<br>
            the IdentityStore configuration) required to execute its
            requested<br>
            operation. &nbsp;It also provides a gateway to the event bridge,
            which allows<br>
            events to be raised during an IdentityStore operation and
            propagated to<br>
            any environment, such as the CDI event bus. &nbsp;The<br>
            IdentityStoreInvocationContext implementation/s are
            currently still a<br>
            work in progress, however the basic API should not change.<br>
            <br>
            This essentially wraps up the description of the
            configuration API. What<br>
            I haven't touched upon yet are the builders (classes that
            parse a<br>
            configuration source such as a file to create an<br>
            IdentityStoreConfiguration) however I'm hoping Anil that you
            might want<br>
            to have a go at this.<br>
            <br>
            With these changes comes a small TO-DO list:<br>
            <br>
            1) IdentityStoreConfiguration implementations should be
            created in the<br>
            API module within the org.picketlink.idm.config package for
            each of the<br>
            IdentityStore implementations (we already have one for LDAP,
            but it<br>
            needs to be moved and possibly renamed to
            LDAPIdentityStoreConfiguration<br>
            for consistency).<br>
            <br>
            2) During the course of the refactor I had to provide
            workarounds for<br>
            many of the tests, and I also managed to totally break quite
            a few<br>
            others. &nbsp;The test suite needs a quick review to see why the
            tests are<br>
            broken, and once configurations are provided for the other
            identity<br>
            stores the workarounds can be removed.<br>
            <br>
            3) The getFeatureSet() method should be correctly
            implemented for all<br>
            IdentityStores. &nbsp;With the change to the configuration API we
            now have<br>
            proper support for partitioning, and it's important that
            this method<br>
            accurately reflect the underlying capabilities of the
            IdentityStore<br>
            implementation for this feature to work correctly.<br>
            <br>
            Thanks for listening, and I'm looking forward to getting
            some feedback<br>
            on this!<br>
            <br>
            Shane<br>
            _______________________________________________<br>
            security-dev mailing list<br>
            <a moz-do-not-send="true"
              href="mailto:security-dev@lists.jboss.org">security-dev@lists.jboss.org</a><br>
            <a moz-do-not-send="true"
              href="https://lists.jboss.org/mailman/listinfo/security-dev"
              target="_blank">https://lists.jboss.org/mailman/listinfo/security-dev</a><br>
          </blockquote>
        </div>
        <br>
        <br clear="all">
        <div><br>
        </div>
        -- <br>
        Jason Porter<br>
        <a moz-do-not-send="true"
          href="http://lightguard-jp.blogspot.com" target="_blank">http://lightguard-jp.blogspot.com</a><br>
        <a moz-do-not-send="true" href="http://twitter.com/lightguardjp"
          target="_blank">http://twitter.com/lightguardjp</a><br>
        <br>
        Software Engineer<br>
        Open Source Advocate<br>
        <br>
        PGP key id: 926CCFF5<br>
        PGP key available at: <a moz-do-not-send="true"
          href="http://keyserver.net" target="_blank">keyserver.net</a>,
        <a moz-do-not-send="true" href="http://pgp.mit.edu"
          target="_blank">pgp.mit.edu</a><br>
      </div>
      <br>
    </blockquote>
    &nbsp;
  </body>
</html>