Author: chirino
Date: Fri Sep  1 08:51:22 2006
New Revision: 439357

URL: http://svn.apache.org/viewvc?rev=439357&view=rev
Log:
Latest export from confluence

Modified:
    incubator/activemq/site/weblogic-integration.html

Modified: incubator/activemq/site/weblogic-integration.html
URL: 
http://svn.apache.org/viewvc/incubator/activemq/site/weblogic-integration.html?rev=439357&r1=439356&r2=439357&view=diff
==============================================================================
--- incubator/activemq/site/weblogic-integration.html (original)
+++ incubator/activemq/site/weblogic-integration.html Fri Sep  1 08:51:22 2006
@@ -475,13 +475,202 @@
 
 <P>Of these, Derby could be omitted if ActiveMQ was configured to not use a 
database for persistence or to use a separate database for persistence.  The 
WebLogic JAR is needed only at build time (it&apos;s provided by the server at 
runtime).  Spring could be omitted if a different strategy was used to start 
and stop ActiveMQ when the web app was started or stopped (a little custom code 
could replace this dependency).  The rest are probably unavoidable, unless 
ActiveMQ changes its dependencies in a future version.</P>
 
-<H5><A name="WebLogicIntegration-CodeandConfigurationFiles"></A>Code and 
Configuration Files</H5>
+<H5><A name="WebLogicIntegration-WebLogicIntegrationCode"></A>WebLogic 
Integration Code</H5>
 
-<P><B>TODO:</B> show and discuss code for:</P>
+<P>There are several custom classes used for this example.  We&apos;ll show in 
a minute how to configure ActiveMQ to use these.  Note that these are all 
optional &ndash; if you don&apos;t want to leverage WebLogic&apos;s MBeanServer 
or security realm, you can skip these.</P>
+
+<P>The first lets ActiveMQ installed its JMX MBeans into the WebLogic runtime 
MBeanServer:</P>
+
+<P><B>ActiveMQToWebLogicManagement.java</B></P>
+
+<P>This class overrides the ActiveMQ default MBeanServer lookup behavior (in 
the ActiveMQ class <TT>ManagementContext</TT> to prefer the WebLogic runtime 
MBeanServer.</P>
+
+<DIV class="code"><DIV class="codeContent">
+<PRE class="code-java">/**
+ * Makes ActiveMQ favor the WebLogic runtime MBeanServer
+ */
+<SPAN class="code-keyword">public</SPAN> class ActiveMQToWebLogicManagement 
<SPAN class="code-keyword">extends</SPAN> ManagementContext {
+    <SPAN class="code-keyword">protected</SPAN> <SPAN 
class="code-keyword">synchronized</SPAN> MBeanServer findMBeanServer() {
+        <SPAN class="code-keyword">try</SPAN> {
+            Context ctx = <SPAN class="code-keyword">new</SPAN> 
InitialContext();
+            MBeanServer server = (MBeanServer) ctx.lookup(<SPAN 
class="code-quote">&quot;java:comp/env/jmx/runtime&quot;</SPAN>);
+            <SPAN class="code-keyword">if</SPAN>(server != <SPAN 
class="code-keyword">null</SPAN>) {
+                <SPAN class="code-object">System</SPAN>.out.println(<SPAN 
class="code-quote">&quot;ACTIVEMQ Found WebLogic MBeanServer&quot;</SPAN>);
+                <SPAN class="code-keyword">return</SPAN> server;
+            }
+        } <SPAN class="code-keyword">catch</SPAN> (NamingException e) {
+            e.printStackTrace();
+        }
+        <SPAN class="code-object">System</SPAN>.out.println(<SPAN 
class="code-quote">&quot;ACTIVEMQ Did not find WebLogic 
MBeanServer&quot;</SPAN>);
+        <SPAN class="code-keyword">return</SPAN> <SPAN 
class="code-keyword">super</SPAN>.findMBeanServer();
+    }
+}</PRE>
+</DIV></DIV>
+
+<P>The next class makes ActiveMQ use the WebLogic security realm for 
authentication, and lets you specify a single WebLogic group to use for 
authorization (only members of that group can access ActiveMQ, though group 
members have full access to ActiveMQ).</P>
+
+<P><B>ActiveMQToWebLogicSecurity.java</B></P>
+
+<P>This class is an ActiveMQ &quot;plugin&quot;, which installs two filters 
(authorization and authentication) which will be invoked on every request.  
This is similar to the default behavior provided by ActiveMQ&apos;s 
<TT>JaasAuthenticationPlugin</TT> and <TT>AuthorizationPlugin</TT>.</P>
+
+<DIV class="code"><DIV class="codeContent">
+<PRE class="code-java">/**
+ * An ActiveMQ security plugin that installs two security filters
+ * (authentication and authorization) that use WebLogic security realms to
+ * handle the login and provide user and group principals.
+ */
+<SPAN class="code-keyword">public</SPAN> class ActiveMQToWebLogicSecurity 
<SPAN class="code-keyword">implements</SPAN> BrokerPlugin {
+    <SPAN class="code-keyword">private</SPAN> <SPAN 
class="code-object">String</SPAN> authorizedGroup;
+
+    <SPAN class="code-keyword">public</SPAN> Broker installPlugin(Broker 
broker) {
+        <SPAN class="code-comment">// Install the first filter <SPAN 
class="code-keyword">for</SPAN> authentication
+</SPAN>        Broker first = <SPAN class="code-keyword">new</SPAN> 
ActiveMQWebLogicAuthenticationFilter(broker);
+        <SPAN class="code-comment">// Configure and install the second filter 
<SPAN class="code-keyword">for</SPAN> authorization
+</SPAN>        AuthorizationEntry entry = <SPAN 
class="code-keyword">new</SPAN> AuthorizationEntry();
+        Set acls = <SPAN class="code-keyword">new</SPAN> HashSet();
+        acls.add(<SPAN class="code-keyword">new</SPAN> 
WLSGroupImpl(authorizedGroup));
+        entry.setAdminACLs(acls);
+        entry.setReadACLs(acls);
+        entry.setWriteACLs(acls);
+        DefaultAuthorizationMap map = <SPAN class="code-keyword">new</SPAN> 
DefaultAuthorizationMap();
+        map.setDefaultEntry(entry);
+        <SPAN class="code-comment">//todo: <SPAN 
class="code-keyword">if</SPAN> finer-grained access is required, add more 
entries to the authorization map
+</SPAN>        Broker second = <SPAN class="code-keyword">new</SPAN> 
AuthorizationBroker(first, map);
+        <SPAN class="code-keyword">return</SPAN> second;
+    }
+
+    <SPAN class="code-keyword">public</SPAN> <SPAN 
class="code-object">String</SPAN> getAuthorizedGroup() {
+        <SPAN class="code-keyword">return</SPAN> authorizedGroup;
+    }
+
+    /**
+     * Called by XBean at configuration time to set the authorized group from a
+     * property in the main ActiveMQ configuration file.
+     */
+    <SPAN class="code-keyword">public</SPAN> void setAuthorizedGroup(<SPAN 
class="code-object">String</SPAN> authorizedGroup) {
+        <SPAN class="code-keyword">this</SPAN>.authorizedGroup = 
authorizedGroup;
+    }
+}</PRE>
+</DIV></DIV>
+
+<P>Finally, the last class is the authentication filter used by the class 
above to authenticate all logins against the WebLogic default security 
realm.</P>
+
+<P><B>ActiveMQWebLogicAuthenticationFilter.java</B></P>
+
+<DIV class="code"><DIV class="codeContent">
+<PRE class="code-java">/**
+ * A broker filter that authenticates callers against WebLogic security.
+ * This is similar to the ActiveMQ JaasAuthenticationBroker except <SPAN 
class="code-keyword">for</SPAN> two
+ * things:
+ * &lt;ul&gt;
+ *   &lt;li&gt;Instead of reading a JAAS configuration file, it hardcodes the 
JAAS
+ *     configuration to require authentication against WebLogic&lt;/li&gt;
+ *
+ *   &lt;li&gt;The SecurityContext implementation overrides the method used to
+ *     compare actual and eligible principals in order to handle the fact
+ *     that WebLogic principals (WLSGroupImpl in particular) <SPAN 
class="code-keyword">do</SPAN> not seem
+ *     to match according to equals and hashCode even <SPAN 
class="code-keyword">if</SPAN> the principal class
+ *     and principal name are the same (perhaps having to <SPAN 
class="code-keyword">do</SPAN> with the
+ *     signature data on the WLSAbstractPrincipal).&lt;/li&gt;
+ * &lt;/ul&gt;
+ */
+<SPAN class="code-keyword">public</SPAN> class 
ActiveMQWebLogicAuthenticationFilter <SPAN class="code-keyword">extends</SPAN> 
BrokerFilter {
+    <SPAN class="code-keyword">private</SPAN> <SPAN 
class="code-keyword">final</SPAN> <SPAN class="code-keyword">static</SPAN> 
Configuration WEBLOGIC_JAAS_CONFIGURATION = <SPAN 
class="code-keyword">new</SPAN> Configuration() {
+        <SPAN class="code-keyword">public</SPAN> AppConfigurationEntry[] 
getAppConfigurationEntry(<SPAN class="code-object">String</SPAN> name) {
+            <SPAN class="code-keyword">return</SPAN> <SPAN 
class="code-keyword">new</SPAN> AppConfigurationEntry[]{
+                    <SPAN class="code-keyword">new</SPAN> 
AppConfigurationEntry(<SPAN 
class="code-quote">&quot;weblogic.security.auth.login.UsernamePasswordLoginModule&quot;</SPAN>,
+                            
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, Collections.EMPTY_MAP)
+            };
+        }
+
+        <SPAN class="code-keyword">public</SPAN> void refresh() {
+        }
+    };
+    <SPAN class="code-keyword">private</SPAN> <SPAN 
class="code-keyword">final</SPAN> CopyOnWriteArrayList securityContexts = <SPAN 
class="code-keyword">new</SPAN> CopyOnWriteArrayList();
+
+    <SPAN class="code-keyword">public</SPAN> 
ActiveMQWebLogicAuthenticationFilter(Broker next) {
+        <SPAN class="code-keyword">super</SPAN>(next);
+    }
+
+    <SPAN class="code-keyword">static</SPAN> class JaasSecurityContext <SPAN 
class="code-keyword">extends</SPAN> SecurityContext {
+
+        <SPAN class="code-keyword">private</SPAN> <SPAN 
class="code-keyword">final</SPAN> Subject subject;
+
+        <SPAN class="code-keyword">public</SPAN> JaasSecurityContext(<SPAN 
class="code-object">String</SPAN> userName, Subject subject) {
+            <SPAN class="code-keyword">super</SPAN>(userName);
+            <SPAN class="code-keyword">this</SPAN>.subject = subject;
+        }
+
+        <SPAN class="code-keyword">public</SPAN> Set getPrincipals() {
+            <SPAN class="code-keyword">return</SPAN> subject.getPrincipals();
+        }
+
+        /**
+         * This is necessary because WebLogic uses extra logic when comparing 
principals,
+         * probably to check whether they are cryptographically signed (which 
WebLogic
+         * supports).  We skip that test because ActiveMQ does not sign the 
principals
+         * it deals with.
+         */
+        <SPAN class="code-keyword">public</SPAN> <SPAN 
class="code-object">boolean</SPAN> isInOneOf(Set eligiblePrincipals) {
+            <SPAN class="code-keyword">for</SPAN> (Iterator it = 
getPrincipals().iterator(); it.hasNext();) {
+                Principal test = (Principal) it.next();
+                <SPAN class="code-keyword">for</SPAN> (Iterator el = 
eligiblePrincipals.iterator(); el.hasNext();) {
+                    Principal eligible = (Principal) el.next();
+                    <SPAN 
class="code-keyword">if</SPAN>(test.getName().equals(eligible.getName()) 
&amp;&amp;
+                            
test.getClass().getName().equals(eligible.getClass().getName())) {
+                        <SPAN class="code-keyword">return</SPAN> <SPAN 
class="code-keyword">true</SPAN>;
+                    }
+                }
+            }
+            <SPAN class="code-keyword">return</SPAN> <SPAN 
class="code-keyword">false</SPAN>;
+        }
+    }
+
+    <SPAN class="code-keyword">public</SPAN> void 
addConnection(ConnectionContext context, ConnectionInfo info) <SPAN 
class="code-keyword">throws</SPAN> Exception {
+        <SPAN class="code-keyword">if</SPAN>( 
context.getSecurityContext()==<SPAN class="code-keyword">null</SPAN> ) {
+            <SPAN class="code-comment">// Do the login.
+</SPAN>            <SPAN class="code-keyword">try</SPAN> {
+                LoginContext lc = <SPAN class="code-keyword">new</SPAN> 
LoginContext(<SPAN class="code-quote">&quot;ActiveMQ&quot;</SPAN>, <SPAN 
class="code-keyword">new</SPAN> Subject(),
+                        <SPAN class="code-keyword">new</SPAN> 
URLCallbackHandler(info.getUserName(), info.getPassword()),
+                        WEBLOGIC_JAAS_CONFIGURATION);
+                lc.login();
+                Subject subject = lc.getSubject();
+
+                SecurityContext s = <SPAN class="code-keyword">new</SPAN> 
JaasSecurityContext(info.getUserName(), subject);
+                context.setSecurityContext(s);
+                securityContexts.add(s);
+            } <SPAN class="code-keyword">catch</SPAN> (Exception e) {
+                <SPAN class="code-keyword">throw</SPAN> 
(SecurityException)<SPAN class="code-keyword">new</SPAN> 
SecurityException(<SPAN class="code-quote">&quot;User name or password is 
invalid.&quot;</SPAN>).initCause(e);
+            }
+        }
+        <SPAN class="code-keyword">super</SPAN>.addConnection(context, info);
+    }
+
+    <SPAN class="code-keyword">public</SPAN> void 
removeConnection(ConnectionContext context, ConnectionInfo info, Throwable 
error) <SPAN class="code-keyword">throws</SPAN> Exception {
+        <SPAN class="code-keyword">super</SPAN>.removeConnection(context, 
info, error);
+        <SPAN class="code-keyword">if</SPAN>( 
securityContexts.remove(context.getSecurityContext()) ) {
+            context.setSecurityContext(<SPAN class="code-keyword">null</SPAN>);
+        }
+    }
+
+    /**
+     * Previously logged in users may no longer have the same access anymore.  
Refresh
+     * all the logged into users.
+     */
+    <SPAN class="code-keyword">public</SPAN> void refresh() {
+        <SPAN class="code-keyword">for</SPAN> (Iterator iter = 
securityContexts.iterator(); iter.hasNext();) {
+            SecurityContext sc = (SecurityContext) iter.next();
+            sc.getAuthorizedReadDests().clear();
+            sc.getAuthorizedWriteDests().clear();
+        }
+    }
+}</PRE>
+</DIV></DIV>
+
+<H5><A name="WebLogicIntegration-SampleActiveMQConfigurationFiles"></A>Sample 
ActiveMQ Configuration Files</H5>
+
+<P><B>TODO:</B> show and discuss:</P>
 <UL>
-       <LI>ActiveMQ Management plugin for WebLogic</LI>
-       <LI>ActiveMQ Security plugin for WebLogic</LI>
-       <LI>ActiveMQ authentication filter for WebLogic</LI>
        <LI>ActiveMQ config file for one broker or a network of brokers, with 
the plugins above</LI>
 </UL>
 
@@ -561,7 +750,7 @@
     <DIV id="site-footer">
           Added by     <A 
href="http://goopen.org/confluence/users/viewuserprofile.action?username=ammulder";>Aaron
 Mulder</A>,
     last edited by     <A 
href="http://goopen.org/confluence/users/viewuserprofile.action?username=ammulder";>Aaron
 Mulder</A> on Sep 01, 2006
-                  &nbsp;(<A 
href="http://goopen.org/confluence/pages/diffpages.action?pageId=13349&originalId=13363";>view
 change</A>)
+                  &nbsp;(<A 
href="http://goopen.org/confluence/pages/diffpages.action?pageId=13349&originalId=13364";>view
 change</A>)
               
       (<A 
href="http://goopen.org/confluence/pages/editpage.action?pageId=13349";>edit 
page</A>)
     </DIV>


Reply via email to