+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 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&#39;ve been wracking my brain trying to come up with<br>
a design for the IDM configuration API that doesn&#39;t suck, and allows<br>
easy configuration in both Java SE and EE environments while maintaining<br>
separation between the API and implementation.  I think I&#39;ve come up<br>
with something that&#39;s quite flexible and extensible, so I&#39;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>
     private List&lt;IdentityStoreConfiguration&gt; configuredStores = new<br>
ArrayList&lt;IdentityStoreConfiguration&gt;();<br>
     public List&lt;IdentityStoreConfiguration&gt; getConfiguredStores() {<br>
         return configuredStores;<br>
     }<br>
     public void addStoreConfiguration(IdentityStoreConfiguration config) {<br>
         configuredStores.add(config);<br>
     }<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>
     private final Map&lt;String,String&gt; properties = new<br>
HashMap&lt;String,String&gt;();<br>
     private final Set&lt;Feature&gt; supportedFeatures = new HashSet&lt;Feature&gt;();<br>
     public Set&lt;Feature&gt; getSupportedFeatures() {<br>
         return supportedFeatures;<br>
     }<br>
     public void addSupportedFeature(Feature feature) {<br>
         supportedFeatures.add(feature);<br>
     }<br>
     public void removeSupportedFeature(Feature feature) {<br>
         supportedFeatures.remove(feature);<br>
     }<br>
     public void setProperty(String name, String value) {<br>
         properties.put(name, value);<br>
     }<br>
     public String getPropertyValue(String name) {<br>
         return properties.get(name);<br>
     }<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.  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>
     private Class&lt;?&gt; identityClass;<br>
     private Class&lt;?&gt; membershipClass;<br>
     private Class&lt;?&gt; credentialClass;<br>
     private Class&lt;?&gt; attributeClass;<br>
     public Class&lt;?&gt; getIdentityClass() {<br>
         return identityClass;<br>
     }<br>
     public void setIdentityClass(Class&lt;?&gt; identityClass) {<br>
         this.identityClass = identityClass;<br>
     }<br>
     public Class&lt;?&gt; getCredentialClass() {<br>
         return credentialClass;<br>
     }<br>
     public void setCredentialClass(Class&lt;?&gt; credentialClass) {<br>
         this.credentialClass = credentialClass;<br>
     }<br>
     public Class&lt;?&gt; getMembershipClass() {<br>
         return membershipClass;<br>
     }<br>
     public void setMembershipClass(Class&lt;?&gt; membershipClass) {<br>
         this.membershipClass = membershipClass;<br>
     }<br>
     public Class&lt;?&gt; getAttributeClass() {<br>
         return attributeClass;<br>
     }<br>
     public void setAttributeClass(Class&lt;?&gt; attributeClass) {<br>
         this.attributeClass = attributeClass;<br>
     }<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.  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>
     /**<br>
      * Creates an instance of an IdentityStore using the provided<br>
configuration<br>
      *<br>
      * @param config<br>
      * @return<br>
      */<br>
     IdentityStore createIdentityStore(IdentityStoreConfiguration config);<br>
<br>
     /**<br>
      * Maps specific implementations of IdentityStoreConfiguration to a<br>
corresponding<br>
      * IdentityStore implementation.<br>
      *<br>
      * @param configClass<br>
      * @param storeClass<br>
      */<br>
     void mapConfiguration(Class&lt;? extends IdentityStoreConfiguration&gt;<br>
configClass,<br>
             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.  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.  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&#39;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.  This parameter should be an instance of<br>
IdentityStoreInvocationContextFactory (I know, it&#39;s a mouthful), an SPI<br>
interface that declares a single method:<br>
<br>
public interface IdentityStoreInvocationContextFactory {<br>
     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).  The IdentityStoreInvocationContext<br>
is responsible for providing the IdentityStore with any state (besides<br>
the IdentityStore configuration) required to execute its requested<br>
operation.  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.  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&#39;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&#39;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.  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.  With the change to the configuration API we now have<br>
proper support for partitioning, and it&#39;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&#39;m looking forward to getting some feedback<br>
on this!<br>
<br>
Shane<br>
_______________________________________________<br>
security-dev mailing list<br>
<a href="mailto:security-dev@lists.jboss.org">security-dev@lists.jboss.org</a><br>
<a 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 href="http://lightguard-jp.blogspot.com" target="_blank">http://lightguard-jp.blogspot.com</a><br><a 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 href="http://keyserver.net" target="_blank">keyserver.net</a>, <a href="http://pgp.mit.edu" target="_blank">pgp.mit.edu</a><br>


</div>