Support enabling and disabling shiro based AAA 53/27053/6
authorRyan Goulding <ryandgoulding@gmail.com>
Tue, 15 Sep 2015 14:49:30 +0000 (10:49 -0400)
committerRyan Goulding <ryandgoulding@gmail.com>
Wed, 16 Sep 2015 19:18:17 +0000 (15:18 -0400)
This change supports enabling and disabling shiro AAA through the use of a
ServiceProxy.  This support was added in order to support workflows such as
those included in the odl-restconf-noauth feature.  This change also adds a
significant amount of documentation to help users extend and debug the shiro
functionality.

Change-Id: I213a200c18d48fd1bf59da1ec171b0814a283fce
Signed-off-by: Ryan Goulding <ryandgoulding@gmail.com>
19 files changed:
aaa-shiro-act/pom.xml [new file with mode: 0644]
aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java [new file with mode: 0644]
aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java [new file with mode: 0644]
aaa-shiro/pom.xml
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/Activator.java
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java [new file with mode: 0644]
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/accounting/Accounter.java
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/filters/AAAFilter.java
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealm.java
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/RadiusRealm.java
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/realm/TACACSRealm.java
aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironment.java
aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java [new file with mode: 0644]
aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/realm/ODLJndiLdapRealmTest.java
aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/web/env/KarafIniWebEnvironmentTest.java
features/authn/pom.xml
features/shiro/pom.xml
features/shiro/src/main/features/features.xml
pom.xml

diff --git a/aaa-shiro-act/pom.xml b/aaa-shiro-act/pom.xml
new file mode 100644 (file)
index 0000000..116dce7
--- /dev/null
@@ -0,0 +1,84 @@
+<!-- Copyright (c) 2015 Brocade Communications Systems, Inc. and others.
+  All rights reserved. This program and the accompanying materials are made
+  available under the terms of the Eclipse Public License v1.0 which accompanies
+  this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <relativePath>../parent</relativePath>
+  </parent>
+
+  <artifactId>aaa-shiro-act</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.aaa</groupId>
+      <artifactId>aaa-shiro</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-beanutils</groupId>
+      <artifactId>commons-beanutils</artifactId>
+      <version>1.8.3</version>
+    </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>${bundle.plugin.version}</version>
+          <extensions>true</extensions>
+          <configuration>
+            <instructions>
+              <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+            </instructions>
+            <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Activator>org.opendaylight.aaa.shiroact.Activator</Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java b/aaa-shiro-act/src/main/java/org/opendaylight/aaa/shiroact/Activator.java
new file mode 100644 (file)
index 0000000..4e476e7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiroact;
+
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.opendaylight.aaa.shiro.ServiceProxy;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responsible for activating the aaa-shiro-act bundle. This bundle is primarily
+ * responsible for enabling AuthN and AuthZ. If this bundle is not installed,
+ * then AuthN and AuthZ will not take effect.
+ *
+ * To ensure that the AAA is enabled for your feature, make sure to include the
+ * <code>odl-aaa-shiro</code> feature in your feature definition.
+ *
+ * Offers contextual <code>DEBUG</code> level clues concerning the activation of
+ * the <code>aaa-shiro-act</code> bundle. To enable the enhanced debugging issue
+ * the following line in the karaf shell:
+ * <code>log:set debug org.opendaylight.aaa.shiroact.Activator</code>
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class Activator extends DependencyActivatorBase {
+
+    private static Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    @Override
+    public void destroy(BundleContext bc, DependencyManager dm)
+            throws Exception {
+        final String DEBUG_MESSAGE = "Destroying the aaa-shiro-act bundle";
+        LOG.debug(DEBUG_MESSAGE);
+    }
+
+    @Override
+    public void init(BundleContext bc, DependencyManager dm) throws Exception {
+        final String DEBUG_MESSAGE = "Initializing the aaa-shiro-act bundle";
+        LOG.debug(DEBUG_MESSAGE);
+        ServiceProxy.getInstance().setEnabled(true);
+    }
+
+}
diff --git a/aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java b/aaa-shiro-act/src/test/java/org/opendaylight/aaa/shiroact/ActivatorTest.java
new file mode 100644 (file)
index 0000000..3909545
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.aaa.shiroact;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.opendaylight.aaa.shiro.ServiceProxy;
+
+public class ActivatorTest {
+
+    @Test
+    public void testActivatorEnablesServiceProxy() throws Exception {
+        // should toggle the ServiceProxy enable status to true
+        new Activator().init(null, null);;
+        assertTrue(ServiceProxy.getInstance().getEnabled(null));
+    }
+
+}
index 933f115c5b998677299d93b0f565434f54be80b7..25af61045e716c223155323d3e686f20a1a1ad84 100644 (file)
-<!--
-     Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
-     This program and the accompanying materials are made available under the
-     terms of the Eclipse Public License v1.0 which accompanies this distribution,
-     and is available at http://www.eclipse.org/legal/epl-v10.html
--->
+<!-- Copyright (c) 2015 Brocade Communications Systems, Inc. and others.
+  All rights reserved. This program and the accompanying materials are made
+  available under the terms of the Eclipse Public License v1.0 which accompanies
+  this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-       <modelVersion>4.0.0</modelVersion>
-       <parent>
-               <groupId>org.opendaylight.aaa</groupId>
-               <artifactId>aaa-parent</artifactId>
-               <version>0.3.0-SNAPSHOT</version>
-               <relativePath>../parent</relativePath>
-       </parent>
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.aaa</groupId>
+    <artifactId>aaa-parent</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+    <relativePath>../parent</relativePath>
+  </parent>
 
-       <artifactId>aaa-shiro</artifactId>
-       <packaging>bundle</packaging>
+  <artifactId>aaa-shiro</artifactId>
+  <packaging>bundle</packaging>
 
-       <dependencies>
-               <dependency>
-                       <groupId>org.apache.felix</groupId>
-                       <artifactId>org.apache.felix.dependencymanager</artifactId>
-               </dependency>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+    </dependency>
 
-               <dependency>
-                       <groupId>org.apache.shiro</groupId>
-                       <artifactId>shiro-core</artifactId>
-                       <version>1.2.3</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.apache.shiro</groupId>
-                       <artifactId>shiro-web</artifactId>
-                       <version>1.2.3</version>
-               </dependency>
-               <dependency>
-                       <groupId>org.slf4j</groupId>
-                       <artifactId>slf4j-api</artifactId>
-               </dependency>
-               <dependency>
-                       <groupId>commons-beanutils</groupId>
-                       <artifactId>commons-beanutils</artifactId>
-                       <version>1.8.3</version>
-               </dependency>
-               <dependency>
-                       <groupId>javax.servlet</groupId>
-                       <artifactId>servlet-api</artifactId>
-               </dependency>
+    <dependency>
+      <groupId>org.apache.shiro</groupId>
+      <artifactId>shiro-core</artifactId>
+      <version>1.2.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.shiro</groupId>
+      <artifactId>shiro-web</artifactId>
+      <version>1.2.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-beanutils</groupId>
+      <artifactId>commons-beanutils</artifactId>
+      <version>1.8.3</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+    </dependency>
 
-               <!-- Testing Dependencies -->
-               <dependency>
-                       <groupId>junit</groupId>
-                       <artifactId>junit</artifactId>
-                       <scope>test</scope>
-               </dependency>
-               <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
-            <scope>test</scope>
-        </dependency>
-       </dependencies>
-       <build>
-               <pluginManagement>
-                       <plugins>
-                               <plugin>
-                                       <groupId>org.apache.felix</groupId>
-                                       <artifactId>maven-bundle-plugin</artifactId>
-                                       <version>${bundle.plugin.version}</version>
-                                       <extensions>true</extensions>
-                                       <configuration>
-                                               <instructions>
-                                                       <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
-                                               </instructions>
-                                               <manifestLocation>${project.basedir}/META-INF</manifestLocation>
-                                       </configuration>
-                               </plugin>
-                       </plugins>
-               </pluginManagement>
-               <plugins>
-                       <plugin>
-                               <groupId>org.apache.felix</groupId>
-                               <artifactId>maven-bundle-plugin</artifactId>
-                               <extensions>true</extensions>
-                               <configuration>
-                                       <instructions>
-                                               <Bundle-Activator>org.opendaylight.aaa.shiro.Activator</Bundle-Activator>
-                                       </instructions>
-                               </configuration>
-                       </plugin>
-                       <plugin>
-                               <groupId>org.apache.maven.plugins</groupId>
-                               <artifactId>maven-jar-plugin</artifactId>
-                       </plugin>
-                       <plugin>
-                               <groupId>org.codehaus.mojo</groupId>
-                               <artifactId>build-helper-maven-plugin</artifactId>
-                               <executions>
-                                       <execution>
-                                               <id>attach-artifacts</id>
-                                               <phase>package</phase>
-                                               <goals>
-                                                       <goal>attach-artifact</goal>
-                                               </goals>
-                                               <configuration>
-                                                       <artifacts>
-                                                               <artifact>
-                                                                       <file>${project.build.directory}/classes/shiro.ini</file>
-                                                                       <type>ini</type>
-                                                                       <classifier>config</classifier>
-                                                               </artifact>
-                                                       </artifacts>
-                                               </configuration>
-                                       </execution>
-                               </executions>
-                       </plugin>
-               </plugins>
-       </build>
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <version>${bundle.plugin.version}</version>
+          <extensions>true</extensions>
+          <configuration>
+            <instructions>
+              <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+            </instructions>
+            <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Activator>org.opendaylight.aaa.shiro.Activator</Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <phase>package</phase>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/shiro.ini</file>
+                  <type>cfg</type>
+                  <classifier>configuration</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 </project>
index 9e3735146870872b08bab66f48b14dc8bf74d4e5..e25c57f3ea974cd43e8f415edccc6ce6837d6367 100644 (file)
@@ -15,26 +15,32 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Offers contextual <code>DEBUG</code> level clues concerning the activation
- * of the <code>aaa-shiro</code> bundle.
+ * This scaffolding allows the use of AAA Filters without AuthN or AuthZ
+ * enabled. This is done to support workflows such as those included in the
+ * <code>odl-restconf-noauth</code> feature.
+ *
+ * This class is also responsible for offering contextual <code>DEBUG</code>
+ * level clues concerning the activation of the <code>aaa-shiro</code> bundle.
+ * To enable these debug messages, issue the following command in the karaf
+ * shell: <code>log:set debug org.opendaylight.aaa.shiro.Activator</code>
  *
  * @author Ryan Goulding (ryandgoulding@gmail.com)
  */
 public class Activator extends DependencyActivatorBase {
 
-  private static Logger LOG = LoggerFactory.getLogger(Activator.class);
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
 
-  @Override
-  public void destroy(BundleContext bc, DependencyManager dm)
-      throws Exception {
-    final String DEBUG_MESSAGE = "Destroying the aaa-shiro bundle";
-    LOG.debug(DEBUG_MESSAGE);
-  }
+    @Override
+    public void destroy(BundleContext bc, DependencyManager dm)
+            throws Exception {
+        final String DEBUG_MESSAGE = "Destroying the aaa-shiro bundle";
+        LOG.debug(DEBUG_MESSAGE);
+    }
 
-  @Override
-  public void init(BundleContext bc, DependencyManager dm) throws Exception {
-    final String DEBUG_MESSAGE = "Initializing the aaa-shiro bundle";
-    LOG.debug(DEBUG_MESSAGE);
-  }
+    @Override
+    public void init(BundleContext bc, DependencyManager dm) throws Exception {
+        final String DEBUG_MESSAGE = "Initializing the aaa-shiro bundle";
+        LOG.debug(DEBUG_MESSAGE);
+    }
 
 }
diff --git a/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java b/aaa-shiro/src/main/java/org/opendaylight/aaa/shiro/ServiceProxy.java
new file mode 100644 (file)
index 0000000..80475ea
--- /dev/null
@@ -0,0 +1,88 @@
+package org.opendaylight.aaa.shiro;
+
+import org.opendaylight.aaa.shiro.filters.AAAFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Responsible for enabling and disabling the AAA service. By default, the
+ * service is disabled; the AAAFilter will not require AuthN or AuthZ. The
+ * service is enabled through calling
+ * <code>ServiceProxy.getInstance().setEnabled(true)</code>. AuthN and AuthZ are
+ * disabled by default in order to support workflows such as the feature
+ * <code>odl-restconf-noauth</code>.
+ *
+ * The AAA service is enabled through installing the <code>odl-aaa-shiro</code>
+ * feature. The <code>org.opendaylight.aaa.shiroact.Activator()</code>
+ * constructor calls enables AAA through the ServiceProxy, which in turn enables
+ * the AAAFilter.
+ *
+ * ServiceProxy is a singleton; access to the ServiceProxy is granted through
+ * the <code>getInstance()</code> function.
+ *
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ * @link
+ *       https://github.com/opendaylight/netconf/blob/master/opendaylight/restconf
+ *       /sal-rest-connector/src/main/resources/WEB-INF/web.xml
+ * @see <code>org.opendaylight.aaa.shiro.Activator</code>
+ * @see <code>org.opendaylight.aaa.shiro.filters.AAAFilter</code>
+ */
+public class ServiceProxy {
+    private static final Logger LOG = LoggerFactory
+            .getLogger(ServiceProxy.class);
+
+    /**
+     * AuthN and AuthZ are disabled by default to support workflows included in
+     * features such as <code>odl-restconf-noauth</code>
+     */
+    public static final boolean DEFAULT_AA_ENABLE_STATUS = false;
+
+    private static ServiceProxy instance = new ServiceProxy();
+    private volatile boolean enabled = false;
+    private AAAFilter filter;
+
+    /**
+     * private for singleton pattern
+     */
+    private ServiceProxy() {
+        final String INFO_MESSAGE = "Creating the ServiceProxy";
+        LOG.info(INFO_MESSAGE);
+    }
+
+    /**
+     * @return ServiceProxy, a feature level singleton
+     */
+    public static ServiceProxy getInstance() {
+        return instance;
+    }
+
+    /**
+     * Enables/disables the feature, cascading the state information to the
+     * AAAFilter.
+     *
+     * @param enabled
+     */
+    public synchronized void setEnabled(final boolean enabled) {
+        this.enabled = enabled;
+        final String SERVICE_ENABLED_INFO_MESSAGE = "Setting ServiceProxy enabled to "
+                + enabled;
+        LOG.info(SERVICE_ENABLED_INFO_MESSAGE);
+        // check for null because of non-determinism in bundle load
+        if (filter != null) {
+            filter.setEnabled(enabled);
+        }
+    }
+
+    /**
+     * Extract whether the service is enabled.
+     *
+     * @param filter
+     *            register an optional Filter for callback if enable state
+     *            changes
+     * @return
+     */
+    public synchronized boolean getEnabled(final AAAFilter filter) {
+        this.filter = filter;
+        return enabled;
+    }
+}
index 0556927ae58f80e4233ece318057e3dc25f775f2..2d4f9072c780901d093890d5fa2797176d69ca82 100644 (file)
@@ -11,28 +11,28 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Accounter is a common place to output AAA messages.  Use this class through
+ * Accounter is a common place to output AAA messages. Use this class through
  * invoking <code>Logger.output("message")</code>.
  *
  * @author Ryan Goulding (ryandgoulding@gmail.com)
  */
 public class Accounter {
 
-  private static Logger LOG = LoggerFactory.getLogger(Accounter.class);
+    private static final Logger LOG = LoggerFactory.getLogger(Accounter.class);
 
-  /*
-   * Essentially makes Accounter a singleton, avoiding the verbosity
-   * of <code>Accounter.getInstance().output("message")</code>.
-   */
-  private Accounter() {
-  }
+    /*
+     * Essentially makes Accounter a singleton, avoiding the verbosity of
+     * <code>Accounter.getInstance().output("message")</code>.
+     */
+    private Accounter() {
+    }
 
-  /**
-   * Account for a particular <code>message</code>
-   *
-   * @param message
-   */
-  public static void output(final String message) {
-    LOG.debug(message);
-  }
+    /**
+     * Account for a particular <code>message</code>
+     *
+     * @param message
+     */
+    public static void output(final String message) {
+        LOG.debug(message);
+    }
 }
index bc731e753a108bb0f15e7dacd4c8db3d450ae4a9..032c70c11cc100b9a6e91a7fb2ff7ddbbc6fec1b 100644 (file)
@@ -9,11 +9,16 @@
 package org.opendaylight.aaa.shiro.filters;
 
 import org.apache.shiro.web.servlet.ShiroFilter;
+import org.opendaylight.aaa.shiro.ServiceProxy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The default AAA JAX-RS 1.X Web Filter.
+ * The default AAA JAX-RS 1.X Web Filter. This class is also responsible for
+ * delivering debug information; to enable these debug statements, please issue
+ * the following in the karaf shell:
+ *
+ * <code>log:set debug org.opendaylight.aaa.shiro.filters.AAAFilter</code>
  *
  * @author Ryan Goulding (ryandgoulding@gmail.com)
  * @see <code>javax.servlet.Filter</code>
@@ -21,18 +26,47 @@ import org.slf4j.LoggerFactory;
  */
 public class AAAFilter extends ShiroFilter {
 
-  private static Logger LOG = LoggerFactory.getLogger(AAAFilter.class);
+    private static Logger LOG = LoggerFactory.getLogger(AAAFilter.class);
+
+    public AAAFilter() {
+        super();
+        final String DEBUG_MESSAGE = "Creating the AAAFilter";
+        LOG.debug(DEBUG_MESSAGE);
+    }
 
-  public AAAFilter() {
-    super();
-    final String DEBUG_MESSAGE = "Creating the AAAFilter";
-    LOG.debug(DEBUG_MESSAGE);
-  }
+    /*
+     * (non-Javadoc)
+     * 
+     * Adds context clues that aid in debugging. Also initializes the enable
+     * status to correspond with
+     * <code>ServiceProxy.getInstance.getEnabled()</code>.
+     * 
+     * @see org.apache.shiro.web.servlet.ShiroFilter#init()
+     */
+    @Override
+    public void init() throws Exception {
+        super.init();
+        final String DEBUG_MESSAGE = "Initializing the AAAFilter";
+        LOG.debug(DEBUG_MESSAGE);
+        // sets the filter to the startup value. Because of non-determinism in
+        // bundle loading, this passes an instance of itself along so that if
+        // the
+        // enable status changes, then AAAFilter enable status is changed.
+        setEnabled(ServiceProxy.getInstance().getEnabled(this));
+    }
 
-  @Override
-  public void init() throws Exception {
-    super.init();
-    final String DEBUG_MESSAGE = "Initializing the AAAFilter";
-    LOG.debug(DEBUG_MESSAGE);
-  }
+    /*
+     * (non-Javadoc)
+     * 
+     * Adds context clues to aid in debugging whether the filter is enabled.
+     * 
+     * @see
+     * org.apache.shiro.web.servlet.OncePerRequestFilter#setEnabled(boolean)
+     */
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        final String DEBUG_MESSAGE = "Setting AAAFilter enabled to " + enabled;
+        LOG.debug(DEBUG_MESSAGE);
+    }
 }
index edb5b2a6221cc462a882dc4e96bc89590c48153a..a81dda402739d741bfb5da79a0ce30af607d9bcd 100644 (file)
@@ -40,187 +40,196 @@ import org.slf4j.LoggerFactory;
  *
  * @author Ryan Goulding (ryandgoulding@gmail.com)
  * @see <code>org.apache.shiro.realm.ldap.JndiLdapRealm</code>
- * {@link https://shiro.apache.org/static/1.2.3/apidocs/org/apache/shiro/realm/ldap/JndiLdapRealm.html}
+ * @link {https
+ *      ://shiro.apache.org/static/1.2.3/apidocs/org/apache/shiro/realm/ldap/
+ *      JndiLdapRealm.html}
  */
 public class ODLJndiLdapRealm extends JndiLdapRealm {
-  private static final Logger LOG = LoggerFactory
-      .getLogger(ODLJndiLdapRealm.class);
-
-  private static final String LDAP_CONNECTION_MESSAGE = "AAA LDAP connection from ";
-
-  /*
-   * Adds debugging information surrounding creation of ODLJndiLdapRealm
-   */
-  public ODLJndiLdapRealm() {
-    super();
-    final String DEBUG_MESSAGE = "Creating ODLJndiLdapRealm";
-    LOG.debug(DEBUG_MESSAGE);
-  }
-
-  /*
-   * (non-Javadoc) Overridden to expose important audit trail information
-   * for accounting.
-   *
-   * @see org.apache.shiro.realm.ldap.JndiLdapRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
-   */
-  @Override
-  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
-      throws AuthenticationException {
-
-    try {
-      final String username = getUsername(token);
-      logIncomingConnection(username);
-      return super.doGetAuthenticationInfo(token);
-    } catch (ClassCastException e) {
-      final String ERROR_MESSAGE = "Couldn't service the LDAP connection";
-      LOG.info(ERROR_MESSAGE, e);
+    private static final Logger LOG = LoggerFactory
+            .getLogger(ODLJndiLdapRealm.class);
+
+    private static final String LDAP_CONNECTION_MESSAGE = "AAA LDAP connection from ";
+
+    /*
+     * Adds debugging information surrounding creation of ODLJndiLdapRealm
+     */
+    public ODLJndiLdapRealm() {
+        super();
+        final String DEBUG_MESSAGE = "Creating ODLJndiLdapRealm";
+        LOG.debug(DEBUG_MESSAGE);
     }
-    return null;
-  }
-
-  /**
-   * Logs an incoming LDAP connection
-   *
-   * @param username the requesting user
-   */
-  protected void logIncomingConnection(final String username) {
-    final String message = LDAP_CONNECTION_MESSAGE + username;
-    LOG.info(message);
-    Accounter.output(message);
-  }
-
-  /**
-   * Extracts the username from <code>token</code>
-   *
-   * @param token
-   * @return
-   * @throws ClassCastException The incoming token is not username/password
-   * (i.e., X.509 certificate)
-   */
-  public static String getUsername(AuthenticationToken token) throws ClassCastException {
-    if (null == token) {
-      return null;
+
+    /*
+     * (non-Javadoc) Overridden to expose important audit trail information for
+     * accounting.
+     *
+     * @see
+     * org.apache.shiro.realm.ldap.JndiLdapRealm#doGetAuthenticationInfo(org
+     * .apache.shiro.authc.AuthenticationToken)
+     */
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(
+            AuthenticationToken token) throws AuthenticationException {
+
+        try {
+            final String username = getUsername(token);
+            logIncomingConnection(username);
+            return super.doGetAuthenticationInfo(token);
+        } catch (ClassCastException e) {
+            final String ERROR_MESSAGE = "Couldn't service the LDAP connection";
+            LOG.info(ERROR_MESSAGE, e);
+        }
+        return null;
     }
-    return (String) token.getPrincipal();
-  }
-
-  @Override
-  protected AuthorizationInfo doGetAuthorizationInfo(
-      PrincipalCollection principals) {
-
-     AuthorizationInfo ai = null;
-     try {
-       ai = this.queryForAuthorizationInfo(principals,
-           getContextFactory());
-     }
-     catch (NamingException e) {
-       e.printStackTrace();
-     }
-     return ai;
-  }
-
-  /**
-   * extracts a username from <code>principals</code>
-   *
-   * @param principals
-   * @return
-   * @throws ClassCastException the PrincipalCollection contains an element
-   * that is not in username/password form (i.e., X.509 certificate)
-   */
-  protected String getUsername(final PrincipalCollection principals)
-      throws ClassCastException {
-
-    if (null == principals) {
-      return null;
+
+    /**
+     * Logs an incoming LDAP connection
+     *
+     * @param username
+     *            the requesting user
+     */
+    protected void logIncomingConnection(final String username) {
+        final String message = LDAP_CONNECTION_MESSAGE + username;
+        LOG.info(message);
+        Accounter.output(message);
     }
-    return (String) getAvailablePrincipal(principals);
-  }
-
-  @Override
-  protected AuthorizationInfo queryForAuthorizationInfo(
-      PrincipalCollection principals, LdapContextFactory ldapContextFactory)
-      throws NamingException {
-
-    AuthorizationInfo authorizationInfo = null;
-    try {
-      final String username = getUsername(principals);
-      LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
-      Set<String> roleNames;
-
-      try {
-        roleNames = getRoleNamesForUser(username, ldapContext);
-        authorizationInfo = buildAuthorizationInfo(roleNames);
-      } finally {
-        LdapUtils.closeContext(ldapContext);
-      }
-    } catch(ClassCastException e) {
-      final String ERROR_MESSAGE = "Unable to extract a valid user";
-      LOG.error(ERROR_MESSAGE, e);
+
+    /**
+     * Extracts the username from <code>token</code>
+     *
+     * @param token
+     * @return
+     * @throws ClassCastException
+     *             The incoming token is not username/password (i.e., X.509
+     *             certificate)
+     */
+    public static String getUsername(AuthenticationToken token)
+            throws ClassCastException {
+        if (null == token) {
+            return null;
+        }
+        return (String) token.getPrincipal();
     }
-    return authorizationInfo;
-  }
 
-  public static AuthorizationInfo buildAuthorizationInfo(final Set<String> roleNames) {
-    if(null == roleNames) {
-      return null;
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(
+            PrincipalCollection principals) {
+
+        AuthorizationInfo ai = null;
+        try {
+            ai = this
+                    .queryForAuthorizationInfo(principals, getContextFactory());
+        } catch (NamingException e) {
+            LOG.error("Unable to query for AuthZ info: ", e);
+        }
+        return ai;
     }
-    return new SimpleAuthorizationInfo(roleNames);
-  }
-
-  /**
-   * extracts the Set of roles associated with a user based on the username and
-   * ldap context (server).
-   *
-   * @param username
-   * @param ldapContext
-   * @return
-   * @throws NamingException
-   */
-  protected Set<String> getRoleNamesForUser(String username,
-      LdapContext ldapContext) throws NamingException {
-
-    Set<String> roleNames = new LinkedHashSet<String>();
-    SearchControls searchControls = createSearchControls();
-    // set CN=username
-    String SEARCH_FILTER = "(&(objectClass=*)(CN={0}))";
-    Object[] SEARCH_ARGS = new Object[] { username };
-    String searchBase = super.getUserDnSuffix();
-    LOG.debug("searchBase=" + searchBase);
-    NamingEnumeration<SearchResult> answer =
-        ldapContext.search(searchBase, SEARCH_FILTER, SEARCH_ARGS,
-            searchControls);
-
-    String MEMBER_OF = "memberOf";
-    while (answer.hasMoreElements()) {
-      SearchResult searchResult = answer.next();
-      Attributes attrs = searchResult.getAttributes();
-      if (attrs != null) {
-        NamingEnumeration<? extends Attribute> ae = attrs.getAll();
-        while (ae.hasMore()) {
-          Attribute attr = ae.next();
-          if (attr.getID().equals(MEMBER_OF)) {
-            Collection<String> groupNames = LdapUtils.getAllAttributeValues(attr);
-            Collection<String> rolesForGroups = groupNames;
-            roleNames.addAll(rolesForGroups);
-          }
+
+    /**
+     * extracts a username from <code>principals</code>
+     *
+     * @param principals
+     * @return
+     * @throws ClassCastException
+     *             the PrincipalCollection contains an element that is not in
+     *             username/password form (i.e., X.509 certificate)
+     */
+    protected String getUsername(final PrincipalCollection principals)
+            throws ClassCastException {
+
+        if (null == principals) {
+            return null;
+        }
+        return (String) getAvailablePrincipal(principals);
+    }
+
+    @Override
+    protected AuthorizationInfo queryForAuthorizationInfo(
+            PrincipalCollection principals,
+            LdapContextFactory ldapContextFactory) throws NamingException {
+
+        AuthorizationInfo authorizationInfo = null;
+        try {
+            final String username = getUsername(principals);
+            LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
+            Set<String> roleNames;
+
+            try {
+                roleNames = getRoleNamesForUser(username, ldapContext);
+                authorizationInfo = buildAuthorizationInfo(roleNames);
+            } finally {
+                LdapUtils.closeContext(ldapContext);
+            }
+        } catch (ClassCastException e) {
+            final String ERROR_MESSAGE = "Unable to extract a valid user";
+            LOG.error(ERROR_MESSAGE, e);
         }
-      }
+        return authorizationInfo;
+    }
+
+    public static AuthorizationInfo buildAuthorizationInfo(
+            final Set<String> roleNames) {
+        if (null == roleNames) {
+            return null;
+        }
+        return new SimpleAuthorizationInfo(roleNames);
+    }
+
+    /**
+     * extracts the Set of roles associated with a user based on the username
+     * and ldap context (server).
+     *
+     * @param username
+     * @param ldapContext
+     * @return
+     * @throws NamingException
+     */
+    protected Set<String> getRoleNamesForUser(String username,
+            LdapContext ldapContext) throws NamingException {
+
+        Set<String> roleNames = new LinkedHashSet<String>();
+        SearchControls searchControls = createSearchControls();
+        // set CN=username
+        String SEARCH_FILTER = "(&(objectClass=*)(CN={0}))";
+        Object[] SEARCH_ARGS = new Object[] { username };
+        String searchBase = super.getUserDnSuffix();
+        final String DEBUG_MESSAGE = searchBase=" + searchBase";
+        LOG.debug(DEBUG_MESSAGE);
+        NamingEnumeration<SearchResult> answer = ldapContext.search(searchBase,
+                SEARCH_FILTER, SEARCH_ARGS, searchControls);
+
+        String MEMBER_OF = "memberOf";
+        while (answer.hasMoreElements()) {
+            SearchResult searchResult = answer.next();
+            Attributes attrs = searchResult.getAttributes();
+            if (attrs != null) {
+                NamingEnumeration<? extends Attribute> ae = attrs.getAll();
+                while (ae.hasMore()) {
+                    Attribute attr = ae.next();
+                    if (attr.getID().equals(MEMBER_OF)) {
+                        Collection<String> groupNames = LdapUtils
+                                .getAllAttributeValues(attr);
+                        Collection<String> rolesForGroups = groupNames;
+                        roleNames.addAll(rolesForGroups);
+                    }
+                }
+            }
+        }
+        return roleNames;
+    }
+
+    /**
+     * A utility method to help create the search controls for the LDAP lookup
+     *
+     * @return
+     */
+    protected static SearchControls createSearchControls() {
+        SearchControls searchControls = new SearchControls();
+        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+        return searchControls;
+    }
+
+    public String getUserDnSuffix() {
+        return super.getUserDnSuffix();
     }
-    return roleNames;
-  }
-
-  /**
-   * A utility method to help create the search controls for the LDAP lookup
-   *
-   * @return
-   */
-  protected static SearchControls createSearchControls() {
-    SearchControls searchControls = new SearchControls();
-    searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-    return searchControls;
-  }
-
-  public String getUserDnSuffix() {
-    return super.getUserDnSuffix();
-  }
 }
index c6d908c96d45c1a74f7325885f963f500b3dca02..4bd97de3023ac10006adbe15a90c3cf5bff837aa 100644 (file)
@@ -17,22 +17,21 @@ import org.apache.shiro.subject.PrincipalCollection;
 /**
  * Implementation of a Radius AuthorizingRealm.
  *
- *
  * @author Ryan Goulding (ryandgoulding@gmail.com)
  */
 public class RadiusRealm extends AuthorizingRealm {
 
-  @Override
-  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
-    // TODO use JRadius to extract Authorization Info
-    return null;
-  }
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
+        // TODO use JRadius to extract Authorization Info
+        return null;
+    }
 
-  @Override
-  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0)
-      throws AuthenticationException {
-    // TODO use JRadius to extract Authentication Info
-    return null;
-  }
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(
+            AuthenticationToken arg0) throws AuthenticationException {
+        // TODO use JRadius to extract Authentication Info
+        return null;
+    }
 
 }
index 96c714861fdcf11112eb5ecf53d0eaaee6940255..30ee152cb3006a3abcd4882b6f927c144b3cf455 100644 (file)
@@ -22,17 +22,17 @@ import org.apache.shiro.subject.PrincipalCollection;
  */
 public class TACACSRealm extends AuthorizingRealm {
 
-  @Override
-  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
-    // TODO Extract AuthorizationInfo using JNetLib
-    return null;
-  }
+    @Override
+    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
+        // TODO Extract AuthorizationInfo using JNetLib
+        return null;
+    }
 
-  @Override
-  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0)
-      throws AuthenticationException {
-    // TODO Extract AuthenticationInfo using JNetLib
-    return null;
-  }
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(
+            AuthenticationToken arg0) throws AuthenticationException {
+        // TODO Extract AuthenticationInfo using JNetLib
+        return null;
+    }
 
 }
index 0a7e124d7bad288e5dbace0a9a5a47bb8a7752b0..61001503f3dfe433619a94d19ff0575574247f7c 100644 (file)
@@ -25,60 +25,65 @@ import org.slf4j.LoggerFactory;
  */
 public class KarafIniWebEnvironment extends IniWebEnvironment {
 
-  private static Logger LOG = LoggerFactory.getLogger(KarafIniWebEnvironment.class);
-  public static final String DEFAULT_SHIRO_INI_FILE = "etc/shiro.ini";
-  public static final String SHIRO_FILE_PREFIX = "file:/";
+    private static final Logger LOG = LoggerFactory
+            .getLogger(KarafIniWebEnvironment.class);
+    public static final String DEFAULT_SHIRO_INI_FILE = "etc/shiro.ini";
+    public static final String SHIRO_FILE_PREFIX = "file:/";
 
-  public KarafIniWebEnvironment() {
-  }
+    public KarafIniWebEnvironment() {
+    }
 
-  @Override
-  public void init() {
-    // Initialize the Shiro environment from etc/shiro.ini then delegate to the
-    // parent class
-    Ini ini;
-    try {
-      ini = createDefaultShiroIni();
-      setIni(ini);
-    } catch (FileNotFoundException e) {
-      final String ERROR_MESSAGE = "Could not find etc/shiro.ini";
-      LOG.error(ERROR_MESSAGE, e);
+    @Override
+    public void init() {
+        // Initialize the Shiro environment from etc/shiro.ini then delegate to
+        // the
+        // parent class
+        Ini ini;
+        try {
+            ini = createDefaultShiroIni();
+            setIni(ini);
+        } catch (FileNotFoundException e) {
+            final String ERROR_MESSAGE = "Could not find etc/shiro.ini";
+            LOG.error(ERROR_MESSAGE, e);
+        }
+        super.init();
     }
-    super.init();
-  }
 
-  /**
-   *
-   * @return Ini associated with <code>$KARAF_HOME/etc/shiro.ini</code>
-   * @throws FileNotFoundException
-   */
-  static Ini createDefaultShiroIni() throws FileNotFoundException {
-    return createShiroIni(DEFAULT_SHIRO_INI_FILE);
-  }
+    /**
+     *
+     * @return Ini associated with <code>$KARAF_HOME/etc/shiro.ini</code>
+     * @throws FileNotFoundException
+     */
+    static Ini createDefaultShiroIni() throws FileNotFoundException {
+        return createShiroIni(DEFAULT_SHIRO_INI_FILE);
+    }
 
-  /**
-   *
-   * @param path the file path, which is either absolute or relative to
-   * <code>$KARAF_HOME</code>
-   * @return Ini loaded from <code>path</code>
-   */
-  static Ini createShiroIni(final String path) throws FileNotFoundException {
-    File f = new File(path);
-    Ini ini = new Ini();
-    final String fileBasedIniPath = createFileBasedIniPath(f.getAbsolutePath());
-    ini.loadFromPath(fileBasedIniPath);
-    return ini;
-  }
+    /**
+     *
+     * @param path
+     *            the file path, which is either absolute or relative to
+     *            <code>$KARAF_HOME</code>
+     * @return Ini loaded from <code>path</code>
+     */
+    static Ini createShiroIni(final String path) throws FileNotFoundException {
+        File f = new File(path);
+        Ini ini = new Ini();
+        final String fileBasedIniPath = createFileBasedIniPath(f
+                .getAbsolutePath());
+        ini.loadFromPath(fileBasedIniPath);
+        return ini;
+    }
 
-  /**
-   *
-   * @param path the file path, which is either absolute or relative to
-   * <code>$KARAF_HOME</code>
-   * @return <code>file:/$KARAF_HOME/etc/shiro.ini</code>
-   */
-  static String createFileBasedIniPath(final String path) {
-    String fileBasedIniPath = SHIRO_FILE_PREFIX + path;
-    LOG.debug(fileBasedIniPath);
-    return fileBasedIniPath;
-  }
+    /**
+     *
+     * @param path
+     *            the file path, which is either absolute or relative to
+     *            <code>$KARAF_HOME</code>
+     * @return <code>file:/$KARAF_HOME/etc/shiro.ini</code>
+     */
+    static String createFileBasedIniPath(final String path) {
+        String fileBasedIniPath = SHIRO_FILE_PREFIX + path;
+        LOG.debug(fileBasedIniPath);
+        return fileBasedIniPath;
+    }
 }
diff --git a/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java b/aaa-shiro/src/test/java/org/opendaylight/aaa/shiro/ServiceProxyTest.java
new file mode 100644 (file)
index 0000000..91b620e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.aaa.shiro;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.opendaylight.aaa.shiro.filters.AAAFilter;
+
+/**
+ * @author Ryan Goulding (ryandgoulding@gmail.com)
+ */
+public class ServiceProxyTest {
+
+    @Test
+    public void testGetInstance() {
+        // ensures that singleton pattern is working
+        assertNotNull(ServiceProxy.getInstance());
+    }
+
+    @Test
+    public void testGetSetEnabled() {
+        // combines set and get tests. These are important in this instance,
+        // because getEnabled allows an optional callback Filter.
+        ServiceProxy.getInstance().setEnabled(true);
+        assertTrue(ServiceProxy.getInstance().getEnabled(null));
+
+        AAAFilter testFilter = new AAAFilter();
+        // register the filter
+        ServiceProxy.getInstance().getEnabled(testFilter);
+        assertTrue(testFilter.isEnabled());
+
+        ServiceProxy.getInstance().setEnabled(false);
+        assertFalse(ServiceProxy.getInstance().getEnabled(testFilter));
+        assertFalse(testFilter.isEnabled());
+    }
+}
index 9e7640238d798dd27903dab720bc7a454a98066b..49855b096d8c169377de4e665d297340988fce90 100644 (file)
@@ -8,8 +8,8 @@
 
 package org.opendaylight.aaa.shiro.realm;
 
-import static org.mockito.Mockito.*;
 import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -37,211 +37,212 @@ import org.junit.Test;
  */
 public class ODLJndiLdapRealmTest {
 
-  /**
-   * throw-away anonymous test class
-   */
-  class TestNamingEnumeration implements NamingEnumeration<SearchResult> {
-
-    /**
-     * state variable
-     */
-    boolean first = true;
-
-    /**
-     * returned the first time <code>next()</code> or
-     * <code>nextElement()</code> is called.
-     */
-    SearchResult searchResult = new SearchResult("testuser",
-        null, new BasicAttributes("memberOf", "engineering"));
-
     /**
-     * returns true the first time, then false for subsequent calls
+     * throw-away anonymous test class
      */
-    @Override
-    public boolean hasMoreElements() {
-      return first;
-    }
-
-    /**
-     * returns <code>searchResult</code> then null for subsequent calls
-     */
-    @Override
-    public SearchResult nextElement() {
-      if(first) {
-        first = false;
-        return searchResult;
-      }
-      return null;
-    }
-
-    /**
-     * does nothing because close() doesn't require any special
-     * behavior
-     */
-    @Override
-    public void close() throws NamingException {
-    }
+    class TestNamingEnumeration implements NamingEnumeration<SearchResult> {
+
+        /**
+         * state variable
+         */
+        boolean first = true;
+
+        /**
+         * returned the first time <code>next()</code> or
+         * <code>nextElement()</code> is called.
+         */
+        SearchResult searchResult = new SearchResult("testuser", null,
+                new BasicAttributes("memberOf", "engineering"));
+
+        /**
+         * returns true the first time, then false for subsequent calls
+         */
+        @Override
+        public boolean hasMoreElements() {
+            return first;
+        }
+
+        /**
+         * returns <code>searchResult</code> then null for subsequent calls
+         */
+        @Override
+        public SearchResult nextElement() {
+            if (first) {
+                first = false;
+                return searchResult;
+            }
+            return null;
+        }
+
+        /**
+         * does nothing because close() doesn't require any special behavior
+         */
+        @Override
+        public void close() throws NamingException {
+        }
+
+        /**
+         * returns true the first time, then false for subsequent calls
+         */
+        @Override
+        public boolean hasMore() throws NamingException {
+            return first;
+        }
+
+        /**
+         * returns <code>searchResult</code> then null for subsequent calls
+         */
+        @Override
+        public SearchResult next() throws NamingException {
+            if (first) {
+                first = false;
+                return searchResult;
+            }
+            return null;
+        }
+    };
 
     /**
-     * returns true the first time, then false for subsequent calls
-     */
-    @Override
-    public boolean hasMore() throws NamingException {
-      return first;
-    }
-
-    /**
-     * returns <code>searchResult</code> then null for subsequent calls
+     * throw away test class
+     *
+     * @author ryan
      */
-    @Override
-    public SearchResult next() throws NamingException {
-      if(first) {
-        first = false;
-        return searchResult;
-      }
-      return null;
-    }
-  };
-
-  /**
-   * throw away test class
-   *
-   * @author ryan
-   */
-  class TestPrincipalCollection implements PrincipalCollection {
-    /**
+    class TestPrincipalCollection implements PrincipalCollection {
+        /**
      *
      */
-    private static final long serialVersionUID = -1236759619455574475L;
-
-    Vector<String> collection =
-        new Vector<String>();
-
-    public TestPrincipalCollection(String element) {
-      collection.add(element);
-    }
-
-    @Override
-    public Iterator<String> iterator() {
-      return collection.iterator();
-    }
-
-    @Override
-    public List<String> asList() {
-      return collection;
-    }
-
-    @Override
-    public Set<String> asSet() {
-      HashSet<String> set = new HashSet<String>();
-      set.addAll(collection);
-      return set;
-    }
-
-    @Override
-    public <T> Collection<T> byType(Class<T> arg0) {
-      return null;
+        private static final long serialVersionUID = -1236759619455574475L;
+
+        Vector<String> collection = new Vector<String>();
+
+        public TestPrincipalCollection(String element) {
+            collection.add(element);
+        }
+
+        @Override
+        public Iterator<String> iterator() {
+            return collection.iterator();
+        }
+
+        @Override
+        public List<String> asList() {
+            return collection;
+        }
+
+        @Override
+        public Set<String> asSet() {
+            HashSet<String> set = new HashSet<String>();
+            set.addAll(collection);
+            return set;
+        }
+
+        @Override
+        public <T> Collection<T> byType(Class<T> arg0) {
+            return null;
+        }
+
+        @Override
+        public Collection<String> fromRealm(String arg0) {
+            return collection;
+        }
+
+        @Override
+        public Object getPrimaryPrincipal() {
+            return collection.firstElement();
+        }
+
+        @Override
+        public Set<String> getRealmNames() {
+            return null;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return collection.isEmpty();
+        }
+
+        @Override
+        public <T> T oneByType(Class<T> arg0) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+    };
+
+    @Test
+    public void testGetUsernameAuthenticationToken() {
+        AuthenticationToken authenticationToken = null;
+        assertNull(ODLJndiLdapRealm.getUsername(authenticationToken));
+        AuthenticationToken validAuthenticationToken = new UsernamePasswordToken(
+                "test", "testpassword");
+        assertEquals("test",
+                ODLJndiLdapRealm.getUsername(validAuthenticationToken));
     }
 
-    @Override
-    public Collection<String> fromRealm(String arg0) {
-      return collection;
+    @Test
+    public void testGetUsernamePrincipalCollection() {
+        PrincipalCollection pc = null;
+        assertNull(new ODLJndiLdapRealm().getUsername(pc));
+        TestPrincipalCollection tpc = new TestPrincipalCollection("testuser");
+        String username = new ODLJndiLdapRealm().getUsername(tpc);
+        assertEquals("testuser", username);
     }
 
-    @Override
-    public Object getPrimaryPrincipal() {
-      return collection.firstElement();
+    @Test
+    public void testQueryForAuthorizationInfoPrincipalCollectionLdapContextFactory()
+            throws NamingException {
+        LdapContext ldapContext = mock(LdapContext.class);
+        // emulates an ldap search and returns the mocked up test class
+        when(
+                ldapContext.search((String) any(), (String) any(),
+                        (Object[]) any(), (SearchControls) any())).thenReturn(
+                new TestNamingEnumeration());
+        LdapContextFactory ldapContextFactory = mock(LdapContextFactory.class);
+        when(ldapContextFactory.getSystemLdapContext()).thenReturn(ldapContext);
+        AuthorizationInfo authorizationInfo = new ODLJndiLdapRealm()
+                .queryForAuthorizationInfo(new TestPrincipalCollection(
+                        "testuser"), ldapContextFactory);
+        assertNotNull(authorizationInfo);
+        assertFalse(authorizationInfo.getRoles().isEmpty());
+        assertTrue(authorizationInfo.getRoles().contains("engineering"));
     }
 
-    @Override
-    public Set<String> getRealmNames() {
-      return null;
+    @Test
+    public void testBuildAuthorizationInfo() {
+        assertNull(ODLJndiLdapRealm.buildAuthorizationInfo(null));
+        Set<String> roleNames = new HashSet<String>();
+        roleNames.add("engineering");
+        AuthorizationInfo authorizationInfo = ODLJndiLdapRealm
+                .buildAuthorizationInfo(roleNames);
+        assertNotNull(authorizationInfo);
+        assertFalse(authorizationInfo.getRoles().isEmpty());
+        assertTrue(authorizationInfo.getRoles().contains("engineering"));
     }
 
-    @Override
-    public boolean isEmpty() {
-      return collection.isEmpty();
+    @Test
+    public void testGetRoleNamesForUser() throws NamingException {
+        ODLJndiLdapRealm ldapRealm = new ODLJndiLdapRealm();
+        LdapContext ldapContext = mock(LdapContext.class);
+
+        // emulates an ldap search and returns the mocked up test class
+        when(
+                ldapContext.search((String) any(), (String) any(),
+                        (Object[]) any(), (SearchControls) any())).thenReturn(
+                new TestNamingEnumeration());
+
+        // extracts the roles for "testuser" and ensures engineering is returned
+        Set<String> roles = ldapRealm.getRoleNamesForUser("testuser",
+                ldapContext);
+        assertFalse(roles.isEmpty());
+        assertTrue(roles.iterator().next().equals("engineering"));
     }
 
-    @Override
-    public <T> T oneByType(Class<T> arg0) {
-      // TODO Auto-generated method stub
-      return null;
+    @Test
+    public void testCreateSearchControls() {
+        SearchControls searchControls = ODLJndiLdapRealm.createSearchControls();
+        assertNotNull(searchControls);
+        int expectedSearchScope = SearchControls.SUBTREE_SCOPE;
+        int actualSearchScope = searchControls.getSearchScope();
+        assertEquals(expectedSearchScope, actualSearchScope);
     }
-  };
-
-  @Test
-  public void testGetUsernameAuthenticationToken() {
-    AuthenticationToken authenticationToken = null;
-    assertNull(ODLJndiLdapRealm.getUsername(authenticationToken));
-    AuthenticationToken validAuthenticationToken =
-        new UsernamePasswordToken("test", "testpassword");
-    assertEquals("test",
-        ODLJndiLdapRealm.getUsername(validAuthenticationToken));
-  }
-
-  @Test
-  public void testGetUsernamePrincipalCollection() {
-    PrincipalCollection pc = null;
-    assertNull(new ODLJndiLdapRealm().getUsername(pc));
-    TestPrincipalCollection tpc = new TestPrincipalCollection("testuser");
-    String username = new ODLJndiLdapRealm().getUsername(tpc);
-    assertEquals("testuser", username);
-  }
-
-  @Test
-  public void testQueryForAuthorizationInfoPrincipalCollectionLdapContextFactory() throws NamingException {
-    LdapContext ldapContext = mock(LdapContext.class);
-    // emulates an ldap search and returns the mocked up test class
-    when(ldapContext.search((String) any(),
-        (String) any(), (Object[]) any(),
-        (SearchControls) any()))
-        .thenReturn(new TestNamingEnumeration());
-    LdapContextFactory ldapContextFactory = mock(LdapContextFactory.class);
-    when(ldapContextFactory.getSystemLdapContext()).thenReturn(ldapContext);
-    AuthorizationInfo authorizationInfo = new ODLJndiLdapRealm().queryForAuthorizationInfo(new TestPrincipalCollection("testuser"), ldapContextFactory);
-    assertNotNull(authorizationInfo);
-    assertFalse(authorizationInfo.getRoles().isEmpty());
-    assertTrue(authorizationInfo.getRoles().contains("engineering"));
-  }
-
-  @Test
-  public void testBuildAuthorizationInfo() {
-    assertNull(ODLJndiLdapRealm.buildAuthorizationInfo(null));
-    Set<String> roleNames = new HashSet<String>();
-    roleNames.add("engineering");
-    AuthorizationInfo authorizationInfo =
-        ODLJndiLdapRealm.buildAuthorizationInfo(roleNames);
-    assertNotNull(authorizationInfo);
-    assertFalse(authorizationInfo.getRoles().isEmpty());
-    assertTrue(authorizationInfo.getRoles().contains("engineering"));
-  }
-
-  @Test
-  public void testGetRoleNamesForUser() throws NamingException {
-    ODLJndiLdapRealm ldapRealm = new ODLJndiLdapRealm();
-    LdapContext ldapContext = mock(LdapContext.class);
-
-    // emulates an ldap search and returns the mocked up test class
-    when(ldapContext.search((String) any(),
-        (String) any(), (Object[]) any(),
-        (SearchControls) any()))
-        .thenReturn(new TestNamingEnumeration());
-
-    // extracts the roles for "testuser" and ensures engineering is returned
-    Set<String> roles =
-        ldapRealm.getRoleNamesForUser("testuser", ldapContext);
-    assertFalse(roles.isEmpty());
-    assertTrue(roles.iterator().next().equals("engineering"));
-  }
-
-  @Test
-  public void testCreateSearchControls() {
-    SearchControls searchControls = ODLJndiLdapRealm.createSearchControls();
-    assertNotNull(searchControls);
-    int expectedSearchScope = SearchControls.SUBTREE_SCOPE;
-    int actualSearchScope = searchControls.getSearchScope();
-    assertEquals(expectedSearchScope, actualSearchScope);
-  }
 
 }
index a1447e52c09c070579ff881e8f1a3dbbfae05d3e..1c7253b928823eb6fda1c4d57b71cebb6dd652fc 100644 (file)
@@ -24,58 +24,55 @@ import org.junit.Test;
  * @author Ryan Goulding (ryandgoulding@gmail.com)
  */
 public class KarafIniWebEnvironmentTest {
-  private static File iniFile;
+    private static File iniFile;
 
-  @BeforeClass
-  public static void setup() throws IOException {
-    iniFile = createShiroIniFile();
-    assertTrue(iniFile.exists());
-  }
+    @BeforeClass
+    public static void setup() throws IOException {
+        iniFile = createShiroIniFile();
+        assertTrue(iniFile.exists());
+    }
 
-  @AfterClass
-  public static void teardown() {
-    iniFile.delete();
-  }
+    @AfterClass
+    public static void teardown() {
+        iniFile.delete();
+    }
 
-  private static String createFakeShiroIniContents() {
-    return "[users]\n"
-        + "admin=admin, ROLE_ADMIN \n"
-        + "[roles]\n"
-        + "ROLE_ADMIN = *\n"
-        + "[urls]\n"
-        + "/** = authcBasic";
-  }
+    private static String createFakeShiroIniContents() {
+        return "[users]\n" + "admin=admin, ROLE_ADMIN \n" + "[roles]\n"
+                + "ROLE_ADMIN = *\n" + "[urls]\n" + "/** = authcBasic";
+    }
 
-  private static File createShiroIniFile() throws IOException {
-    File shiroIni = File.createTempFile("shiro", "ini");
-    FileWriter writer = new FileWriter(shiroIni);
-    writer.write(createFakeShiroIniContents());
-    writer.flush();
-    writer.close();
-    return shiroIni;
-  }
+    private static File createShiroIniFile() throws IOException {
+        File shiroIni = File.createTempFile("shiro", "ini");
+        FileWriter writer = new FileWriter(shiroIni);
+        writer.write(createFakeShiroIniContents());
+        writer.flush();
+        writer.close();
+        return shiroIni;
+    }
 
-  @Test
-  public void testCreateShiroIni() throws IOException {
-    Ini ini = KarafIniWebEnvironment.createShiroIni(iniFile.getAbsolutePath());
-    assertNotNull(ini);
-    assertNotNull(ini.getSection("users"));
-    assertNotNull(ini.getSection("roles"));
-    assertNotNull(ini.getSection("urls"));
-    Section usersSection = ini.getSection("users");
-    assertTrue(usersSection.containsKey("admin"));
-    assertTrue(usersSection.get("admin").contains("admin"));
-    assertTrue(usersSection.get("admin").contains("ROLE_ADMIN"));
-  }
+    @Test
+    public void testCreateShiroIni() throws IOException {
+        Ini ini = KarafIniWebEnvironment.createShiroIni(iniFile
+                .getAbsolutePath());
+        assertNotNull(ini);
+        assertNotNull(ini.getSection("users"));
+        assertNotNull(ini.getSection("roles"));
+        assertNotNull(ini.getSection("urls"));
+        Section usersSection = ini.getSection("users");
+        assertTrue(usersSection.containsKey("admin"));
+        assertTrue(usersSection.get("admin").contains("admin"));
+        assertTrue(usersSection.get("admin").contains("ROLE_ADMIN"));
+    }
 
-  @Test
-  public void testCreateFileBasedIniPath() {
-    String testPath = "/shiro.ini";
-    String expectedFileBasedIniPath =
-        KarafIniWebEnvironment.SHIRO_FILE_PREFIX + testPath;
-    String actualFileBasedIniPath =
-        KarafIniWebEnvironment.createFileBasedIniPath(testPath);
-    assertEquals(expectedFileBasedIniPath, actualFileBasedIniPath);
-  }
+    @Test
+    public void testCreateFileBasedIniPath() {
+        String testPath = "/shiro.ini";
+        String expectedFileBasedIniPath = KarafIniWebEnvironment.SHIRO_FILE_PREFIX
+                + testPath;
+        String actualFileBasedIniPath = KarafIniWebEnvironment
+                .createFileBasedIniPath(testPath);
+        assertEquals(expectedFileBasedIniPath, actualFileBasedIniPath);
+    }
 
 }
index a92da292a40cc4d3e6d11fdf588fc3e32606d91a..3d3f4b82f5afacd9de60c20edde2cb998cf29907 100644 (file)
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>features-mdsal</artifactId>
-            <version>${mdsal.version}</version>
             <classifier>features</classifier>
             <type>xml</type>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>features-mdsal</artifactId>
-            <version>${mdsal.model.version}</version>
             <classifier>features</classifier>
             <type>xml</type>
         </dependency>
index 445c8caebaab2806b5b207dab42aac599d4bebf8..4d7d5c2dffd75cea5d2581357729d37914de812a 100644 (file)
     <dependencies>
         <dependency>
             <groupId>org.opendaylight.aaa</groupId>
-            <artifactId>features-aaa-api</artifactId>
-            <classifier>features</classifier>
-            <type>xml</type>
+            <artifactId>aaa-shiro-act</artifactId>
+            <version>0.3.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.aaa</groupId>
             <artifactId>aaa-shiro</artifactId>
             <version>0.3.0-SNAPSHOT</version>
+            <type>cfg</type>
+            <classifier>configuration</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-shiro</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.felix</groupId>
index fc16cec096fb3767f1a298f236d437fa2f07eb50..93a7f2a9901e84d0b5090952e811921b65a7864e 100644 (file)
@@ -6,10 +6,10 @@
 <features name="odl-aaa-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
-    <repository>mvn:org.opendaylight.aaa/features-aaa-api/${project.version}/xml/features</repository>
 
+    <!-- odl-aaa-shiro feature which combines all aspects of AAA into one feature -->
     <feature name='odl-aaa-shiro' description='OpenDaylight :: AAA :: Shiro'
-             version='${project.version}'>
+             version='0.3.0-SNAPSHOT'>
         <!-- OSGI -->
         <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/{{VERSION}}</bundle>
         <bundle>mvn:org.apache.felix/org.apache.felix.metatype/{{VERSION}}</bundle>
         <!-- Apache Shiro & Dependencies -->
         <bundle>mvn:org.apache.shiro/shiro-core/1.2.3</bundle>
         <bundle>mvn:org.apache.shiro/shiro-web/1.2.3</bundle>
-        <bundle>wrap:mvn:javax.servlet/javax.servlet-api/3.1.0</bundle>
+        <bundle>wrap:mvn:javax.servlet/servlet-api/2.5</bundle>
 
+        <!-- AAA bundles relating to stand-alone shiro feature -->
+        <configfile finalname="/etc/shiro.ini">mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}/cfg/configuration</configfile>
         <bundle>mvn:org.opendaylight.aaa/aaa-shiro/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.aaa/aaa-shiro-act/{{VERSION}}</bundle>
     </feature>
 
 </features>
diff --git a/pom.xml b/pom.xml
index 59251f7252b8864ac706d33f6508b2cfbc4b87ba..d1381416d52d1b829e2a53f9b81dc39fd3b2992a 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
     <module>distribution-karaf</module>
     <module>parent</module>
     <module>aaa-shiro</module>
+    <module>aaa-shiro-act</module>
   </modules>
 
   <scm>