<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 11/07/2012 07:35 AM, Boleslaw
      Dawidowicz wrote:<br>
    </div>
    <blockquote
      cite="mid:5F7EEC45-6F54-4C08-8318-D5BE0502ADB2@redhat.com"
      type="cite">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div>Also +1. It looks really good.</div>
      <div><br>
      </div>
      <div>I assume the strategy to handle operations when two stores
        are configured is IdentityManager implementation area. I wonder
        if we should make this part also more flexible in some way. Not
        really thinking about IdentityStoreRepository kind of design I
        had in 1.x as it is probably a bit too much. However it should
        be at least easy to extend DefaultIdentityManager to add some
        customizations to how specific operations are handled. Or we
        should have something like GenericIdentityManager for such
        purpose.</div>
    </blockquote>
    <br>
    This feature (which I've been referring to as partitioning) is
    supported by requiring each configured IdentityStore to provide
    metadata as to which features are supported, via the getFeatureSet()
    method:<br>
    <br>
    Set&lt;Feature&gt; getFeatureSet();<br>
    <br>
    Feature is an enum defining all currently supported identity
    management operations:<br>
    <br>
        public enum Feature { createUser, readUser, updateUser,
    deleteUser, <br>
                              createGroup, readGroup, updateGroup,
    deleteGroup,<br>
                              createRole, readRole, updateRole,
    deleteRole,<br>
                              createMembership, readMembership,
    updateMembership, deleteMembership,<br>
                              validateCredential, updateCredential,<br>
                              all }<br>
    <br>
    When an IdentityManager method is invoked, the correct IdentityStore
    for the required operation is selected based on its supported
    feature set.  Here's an example of this, in the createUser() method:<br>
    <br>
    <br>
        @Override<br>
        public User createUser(String name) {<br>
            User user = new SimpleUser(name);<br>
            IdentityStore store =
    getStoreForFeature(Feature.createUser); <br>
            store.createUser(getContextFactory().getContext(store),
    user);<br>
            return user;<br>
        }<br>
    <br>
    The getStoreForFeature() method iterates through the configured
    stores and returns the one that supports the specified Feature, in
    this example Feature.createUser.  This way we can configure multiple
    stores with one of them providing user-related operations, one
    providing group and role operations, and so forth.<br>
    <br>
    <blockquote
      cite="mid:5F7EEC45-6F54-4C08-8318-D5BE0502ADB2@redhat.com"
      type="cite">
      <div><br>
      </div>
      <div>Looking forward to see your ideas around design of event
        handling part. I think it will be critical to truly pluggable
        and extendable.<br>
      </div>
    </blockquote>
    <br>
    This feature was quite simple.  I've opted to go with the "class as
    an event" model, where each event type is represented by a POJO
    containing the relevant event state.  For example, the following
    event is raised when a new user is created:<br>
    <br>
    public class UserCreatedEvent extends AbstractBaseEvent {<br>
        private User user;<br>
    <br>
        public UserCreatedEvent(User user) {<br>
            this.user = user;<br>
        }<br>
    <br>
        public User getUser() {<br>
            return user;<br>
        }<br>
    }<br>
    <br>
    In this example, the event class contains a reference to the User
    that was created.  In addition to this, each event class should
    extend AbstractBaseEvent which also provides an event context:<br>
    <br>
    public abstract class AbstractBaseEvent {<br>
        private EventContext context = new EventContext();<br>
    <br>
        public EventContext getContext() {<br>
            return context;<br>
        }<br>
    }<br>
    <br>
    The EventContext provides a general purpose mechanism for passing
    arbitrary state:<br>
    <br>
    public class EventContext {<br>
        private Map&lt;String,Object&gt; context;<br>
    <br>
        public Object getValue(String name) {<br>
            return context != null ? context.get(name) : null;<br>
        }<br>
    <br>
        public void setValue(String name, Object value) {<br>
            if (context == null) {<br>
                context = new HashMap&lt;String,Object&gt;();<br>
            }<br>
            context.put(name, value);<br>
        }<br>
    <br>
        public boolean contains(String name) {<br>
            return context != null &amp;&amp; context.containsKey(name);<br>
        }<br>
    <br>
        public boolean isEmpty() {<br>
            return context == null || context.isEmpty();<br>
        }<br>
    }<br>
    <br>
    It is via the EventContext that we can pass IdentityStore
    implementation-specific state (for example the actual entity bean
    instance that was persisted to the database in the case of a JPA
    backed IdentityStore) or any additional state that might be relevant
    to the event.<br>
    <br>
    As for bridging the event itself, the IdentityStoreInvocationContext
    provides access to the EventBridge via the getEventBridge() method:<br>
    <br>
    EventBridge getEventBridge();<br>
    <br>
    This is an extremely simple interface declaring just a single
    method:<br>
    <br>
    public interface EventBridge {<br>
        void raiseEvent(Object event);<br>
    }<br>
    <br>
    The idea here is that you can provide an EventBridge implementation
    tailored for the environment that you're running in.  In an EE6
    environment, this is a piece of cake as we just pass the event
    straight on through to the CDI event bus.<br>
    <br>
    That pretty much sums up event handling.<br>
    <br>
    <blockquote
      cite="mid:5F7EEC45-6F54-4C08-8318-D5BE0502ADB2@redhat.com"
      type="cite">
      <div><br>
        On Nov 6, 2012, at 5:35 PM, Jason Porter &lt;<a
          moz-do-not-send="true" href="mailto:lightguard.jp@gmail.com">lightguard.jp@gmail.com</a>&gt;
        wrote:<br>
        <br>
      </div>
      <blockquote type="cite">
        <div>+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.  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>
                     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'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'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'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.  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'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>
        </div>
      </blockquote>
      <blockquote type="cite">
        <div><span>_______________________________________________</span><br>
          <span>security-dev mailing list</span><br>
          <span><a moz-do-not-send="true"
              href="mailto:security-dev@lists.jboss.org">security-dev@lists.jboss.org</a></span><br>
          <span><a moz-do-not-send="true"
              href="https://lists.jboss.org/mailman/listinfo/security-dev">https://lists.jboss.org/mailman/listinfo/security-dev</a></span><br>
        </div>
      </blockquote>
    </blockquote>
    <br>
  </body>
</html>