You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ch...@apache.org on 2006/09/01 17:51:23 UTC

svn commit: r439357 - /incubator/activemq/site/weblogic-integration.html

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>