You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2013/10/02 20:27:07 UTC

svn commit: r1528587 [1/3] - in /karaf/trunk: ./ assemblies/features/framework/ assemblies/features/framework/src/main/filtered-resources/resources/bin/ assemblies/features/framework/src/main/filtered-resources/resources/etc/ assemblies/features/framew...

Author: jbonofre
Date: Wed Oct  2 18:27:05 2013
New Revision: 1528587

URL: http://svn.apache.org/r1528587
Log:
[KARAF-2435] Add role-based security for the JMX layer

Added:
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.cfg
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.java.lang.Memory.cfg
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.bundle.cfg
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.config.cfg
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.security.jmx.cfg
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.osgi.compendium.cm.cfg
    karaf/trunk/management/boot/
    karaf/trunk/management/boot/NOTICE
    karaf/trunk/management/boot/pom.xml
      - copied, changed from r1527610, karaf/trunk/management/server/pom.xml
    karaf/trunk/management/boot/src/
    karaf/trunk/management/boot/src/main/
    karaf/trunk/management/boot/src/main/java/
    karaf/trunk/management/boot/src/main/java/org/
    karaf/trunk/management/boot/src/main/java/org/apache/
    karaf/trunk/management/boot/src/main/java/org/apache/karaf/
    karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/
    karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/boot/
    karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/boot/KarafMBeanServerBuilder.java
    karaf/trunk/management/boot/src/main/resources/
    karaf/trunk/management/boot/src/main/resources/OSGI-INF/
    karaf/trunk/management/boot/src/main/resources/OSGI-INF/bundle.info
    karaf/trunk/management/boot/src/test/
    karaf/trunk/management/boot/src/test/java/
    karaf/trunk/management/boot/src/test/java/org/
    karaf/trunk/management/boot/src/test/java/org/apache/
    karaf/trunk/management/boot/src/test/java/org/apache/karaf/
    karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/
    karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/boot/
    karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/boot/KarafMBeanServerBuilderTest.java
    karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JMXSecurityMBean.java
    karaf/trunk/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
    karaf/trunk/management/server/src/main/java/org/apache/karaf/management/internal/
    karaf/trunk/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
    karaf/trunk/management/server/src/test/java/
    karaf/trunk/management/server/src/test/java/org/
    karaf/trunk/management/server/src/test/java/org/apache/
    karaf/trunk/management/server/src/test/java/org/apache/karaf/
    karaf/trunk/management/server/src/test/java/org/apache/karaf/management/
    karaf/trunk/management/server/src/test/java/org/apache/karaf/management/KarafMBeanServerGuardTest.java
    karaf/trunk/management/server/src/test/java/org/apache/karaf/management/TestRolePrincipal.java
    karaf/trunk/management/server/src/test/java/org/apache/karaf/management/internal/
    karaf/trunk/management/server/src/test/java/org/apache/karaf/management/internal/JMXSecurityMBeanImplTestCase.java
Modified:
    karaf/trunk/assemblies/features/framework/pom.xml
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance.bat
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf.bat
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat
    karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/etc/config.properties
    karaf/trunk/management/pom.xml
    karaf/trunk/management/server/pom.xml
    karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JaasAuthenticator.java
    karaf/trunk/management/server/src/main/resources/OSGI-INF/blueprint/karaf-management.xml
    karaf/trunk/manual/src/main/webapp/users-guide/jmx.conf
    karaf/trunk/pom.xml
    karaf/trunk/wrapper/core/src/main/resources/org/apache/karaf/wrapper/internal/unix/karaf-wrapper.conf
    karaf/trunk/wrapper/core/src/main/resources/org/apache/karaf/wrapper/internal/windows/karaf-wrapper.conf
    karaf/trunk/wrapper/core/src/main/resources/org/apache/karaf/wrapper/internal/windows64/karaf-wrapper.conf

Modified: karaf/trunk/assemblies/features/framework/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/pom.xml?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/pom.xml (original)
+++ karaf/trunk/assemblies/features/framework/pom.xml Wed Oct  2 18:27:05 2013
@@ -311,6 +311,12 @@
                                     <destFileName>karaf-jaas-boot.jar</destFileName>
                                 </artifactItem>
                                 <artifactItem>
+                                    <groupId>org.apache.karaf.management</groupId>
+                                    <artifactId>org.apache.karaf.management.boot</artifactId>
+                                    <outputDirectory>target/classes/resources/lib</outputDirectory>
+                                    <destFileName>karaf-jmx-boot.jar</destFileName>
+                                </artifactItem>
+                                <artifactItem>
                                     <groupId>org.apache.karaf</groupId>
                                     <artifactId>org.apache.karaf.exception</artifactId>
                                     <outputDirectory>target/classes/resources/lib/endorsed</outputDirectory>

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance Wed Oct  2 18:27:05 2013
@@ -323,7 +323,7 @@ run() {
         CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
     fi
 
-    exec "$JAVA" $JAVA_OPTS -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" $KARAF_OPTS $OPTS -classpath "$CLASSPATH" org.apache.karaf.instance.main.Execute "$@"
+    exec "$JAVA" $JAVA_OPTS -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" -Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder $KARAF_OPTS $OPTS -classpath "$CLASSPATH" org.apache.karaf.instance.main.Execute "$@"
 }
 
 main() {

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance.bat
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance.bat?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance.bat (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/instance.bat Wed Oct  2 18:27:05 2013
@@ -117,7 +117,7 @@ set CLASSPATH=%KARAF_HOME%\system\org\ap
     if "%SHIFT%" == "true" SET ARGS=%2 %3 %4 %5 %6 %7 %8
     if not "%SHIFT%" == "true" SET ARGS=%1 %2 %3 %4 %5 %6 %7 %8    
     rem Execute the Java Virtual Machine
-    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" %KARAF_OPTS% org.apache.karaf.instance.main.Execute %ARGS%
+    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" -Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder %KARAF_OPTS% org.apache.karaf.instance.main.Execute %ARGS%
 
 rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf Wed Oct  2 18:27:05 2013
@@ -389,7 +389,7 @@ run() {
         JAVA_EXT_DIRS=`cygpath --path --windows "$JAVA_EXT_DIRS"`
     fi
     cd "$KARAF_BASE"
-    exec "$JAVA" $JAVA_OPTS -Djava.endorsed.dirs="${JAVA_ENDORSED_DIRS}" -Djava.ext.dirs="${JAVA_EXT_DIRS}" -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Dkaraf.data="$KARAF_DATA" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" $KARAF_OPTS $OPTS -classpath "$CLASSPATH" $MAIN "$@"
+    exec "$JAVA" $JAVA_OPTS -Djava.endorsed.dirs="${JAVA_ENDORSED_DIRS}" -Djava.ext.dirs="${JAVA_EXT_DIRS}" -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Dkaraf.data="$KARAF_DATA" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" -Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder $KARAF_OPTS $OPTS -classpath "$CLASSPATH" $MAIN "$@"
 }
 
 main() {

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf.bat
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf.bat?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf.bat (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/karaf.bat Wed Oct  2 18:27:05 2013
@@ -306,7 +306,7 @@ if "%KARAF_PROFILER%" == "" goto :RUN
     SET ARGS=%1 %2 %3 %4 %5 %6 %7 %8
     rem Execute the Java Virtual Machine
     cd "%KARAF_BASE%"
-    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Djava.endorsed.dirs="%JAVA_HOME%\jre\lib\endorsed;%JAVA_HOME%\lib\endorsed;%KARAF_HOME%\lib\endorsed" -Djava.ext.dirs="%JAVA_HOME%\jre\lib\ext;%JAVA_HOME%\lib\ext;%KARAF_HOME%\lib\ext" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Dkaraf.data="%KARAF_DATA%" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" %KARAF_OPTS% %MAIN% %ARGS%
+    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Djava.endorsed.dirs="%JAVA_HOME%\jre\lib\endorsed;%JAVA_HOME%\lib\endorsed;%KARAF_HOME%\lib\endorsed" -Djava.ext.dirs="%JAVA_HOME%\jre\lib\ext;%JAVA_HOME%\lib\ext;%KARAF_HOME%\lib\ext" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Dkaraf.data="%KARAF_DATA%" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" -Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder %KARAF_OPTS% %MAIN% %ARGS%
 
 rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell Wed Oct  2 18:27:05 2013
@@ -317,7 +317,7 @@ run() {
         CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
     fi
 
-    exec "$JAVA" $JAVA_OPTS -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" $KARAF_OPTS $OPTS -classpath "$CLASSPATH" org.apache.karaf.shell.console.impl.Main --classpath="$KARAF_HOME/system" "$@"
+    exec "$JAVA" $JAVA_OPTS -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" -Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder $KARAF_OPTS $OPTS -classpath "$CLASSPATH" org.apache.karaf.shell.console.impl.Main --classpath="$KARAF_HOME/system" "$@"
 }
 
 main() {

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat Wed Oct  2 18:27:05 2013
@@ -119,7 +119,7 @@ set CLASSPATH=%CLASSPATH%;%KARAF_HOME%\s
     if "%SHIFT%" == "true" SET ARGS=%2 %3 %4 %5 %6 %7 %8
     if not "%SHIFT%" == "true" SET ARGS=%1 %2 %3 %4 %5 %6 %7 %8
     rem Execute the Java Virtual Machine
-    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" %KARAF_OPTS% org.apache.karaf.shell.console.impl.Main --classpath="%KARAF_HOME%\system" %ARGS%
+    "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" -Djavax.management.builder.initial=org.apache.karaf.management.boot.KarafMBeanServerBuilder %KARAF_OPTS% org.apache.karaf.shell.console.impl.Main --classpath="%KARAF_HOME%\system" %ARGS%
 
 rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 

Modified: karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/etc/config.properties
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/etc/config.properties?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/etc/config.properties (original)
+++ karaf/trunk/assemblies/features/framework/src/main/filtered-resources/resources/etc/config.properties Wed Oct  2 18:27:05 2013
@@ -73,6 +73,7 @@ org.osgi.framework.system.packages= \
  org.osgi.util.tracker;uses:="org.osgi.framework";version="1.5.1", \
  org.apache.karaf.jaas.boot;version="${karaf.osgi.version}", \
  org.apache.karaf.jaas.boot.principal;version="${karaf.osgi.version}", \
+ org.apache.karaf.management.boot;version="${karaf.osgi.version}", \
  org.apache.karaf.version;version="${karaf.osgi.version}", \
  ${jre-${java.specification.version}}
 
@@ -141,7 +142,7 @@ eecap-1.2= osgi.ee; osgi.ee="OSGi/Minimu
  osgi.ee; osgi.ee="JavaSE"; version:List<Version>="1.0,1.1,1.2"
 
 # javax.transaction is needed to avoid class loader constraint violation when using javax.sql  
-org.osgi.framework.bootdelegation=org.apache.karaf.jaas.boot,org.apache.karaf.jaas.boot.principal,sun.*,com.sun.*,javax.transaction,javax.transaction.*,org.apache.xerces.jaxp.datatype,org.apache.xerces.stax,org.apache.xerces.parsers,org.apache.xerces.jaxp,org.apache.xerces.jaxp.validation,org.apache.xerces.dom
+org.osgi.framework.bootdelegation=org.apache.karaf.jaas.boot,org.apache.karaf.jaas.boot.principal,org.apache.karaf.management.boot,sun.*,com.sun.*,javax.transaction,javax.transaction.*,org.apache.xerces.jaxp.datatype,org.apache.xerces.stax,org.apache.xerces.parsers,org.apache.xerces.jaxp,org.apache.xerces.jaxp.validation,org.apache.xerces.dom
 
 # OSGi Execution Environment
 org.osgi.framework.executionenvironment=J2SE-1.7,JavaSE-1.7,J2SE-1.6,JavaSE-1.6,J2SE-1.5,JavaSE-1.5,J2SE-1.4,JavaSE-1.4,J2SE-1.3,JavaSE-1.3,J2SE-1.2,,JavaSE-1.2,CDC-1.1/Foundation-1.1,CDC-1.0/Foundation-1.0,J2ME,OSGi/Minimum-1.1,OSGi/Minimum-1.0

Added: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.cfg
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.cfg?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.cfg (added)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.cfg Wed Oct  2 18:27:05 2013
@@ -0,0 +1,16 @@
+#
+# Generic JMX ACL
+# It defines the roles allowed to performed some MBean operations.
+#
+# The format is the following:
+#
+#  operation = roles
+# where:
+#  - operation is a regex to the operation name
+#  - roles is a list of role, separated by comma (',')
+#
+list* = viewer
+get* = viewer
+is* = viewer
+set* = admin
+* = admin
\ No newline at end of file

Added: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.java.lang.Memory.cfg
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.java.lang.Memory.cfg?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.java.lang.Memory.cfg (added)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.java.lang.Memory.cfg Wed Oct  2 18:27:05 2013
@@ -0,0 +1,4 @@
+#
+# JMX ACL specific to the java.lang.Memory MBean
+#
+gc = manager

Added: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.bundle.cfg
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.bundle.cfg?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.bundle.cfg (added)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.bundle.cfg Wed Oct  2 18:27:05 2013
@@ -0,0 +1,19 @@
+#
+# JMX ACL specific to the org.apache.karaf:type=bundle,name=* MBean
+#
+install = manager
+get* = viewer
+refresh = manager
+resolve = manager
+restart = manager
+setStartLevel(java.lang.String, int)[/([1-4])?[0-9]/,/.*/] = admin
+setStartLevel = manager
+start(java.lang.String)[/([1-4])?[0-9]/] = admin
+start = manager
+stop(java.lang.String)[/([1-4])?[0-9]/] = admin
+stop = manager
+uninstall(java.lang.String)["0"] = #this is a comment, no roles can perform this operation
+uninstall = admin
+update(java.lang.String)[/([1-4])?[0-9]/] = admin
+update(java.lang.String,java.lang.String)[/([1-4])?[0-9]/,/.*/] = admin
+update = manager
\ No newline at end of file

Added: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.config.cfg
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.config.cfg?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.config.cfg (added)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.config.cfg Wed Oct  2 18:27:05 2013
@@ -0,0 +1,18 @@
+#
+# JMX ACL specific to the org.apache.karaf:type=config,name=* MBean
+#
+# By default, only an admin can make changes to the JMX ACL rules, but managers can make
+# changes to other PIDs.
+#
+appendProperty(java.lang.String,java.lang.String,java.lang.String)[/^jmx[.]acl.*/,/.*/,/.*/] = admin
+appendProperty(java.lang.String,java.lang.String,java.lang.String) = manager
+create(java.lang.String)[/^jmx[.]acl.*/] = admin
+create(java.lang.String) = manager
+delete(java.lang.String)[/^jmx[.]acl.*/] = admin
+delete(java.lang.String) = manager
+deleteProperty(java.lang.String,java.lang.String)[/^jmx[.]acl.*/,/.*/] = admin
+deleteProperty(java.lang.String,java.lang.String) = manager
+setProperty(java.lang.String,java.lang.String,java.lang.String)[/^jmx[.]acl.*/,/.*/,/.*/] = admin
+setProperty(java.lang.String,java.lang.String,java.lang.String) = manager
+update(java.lang.String,java.util.Map)[/^jmx[.]acl.*/,/.*/] = admin
+update(java.lang.String,java.util.Map) = manager
\ No newline at end of file

Added: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.security.jmx.cfg
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.security.jmx.cfg?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.security.jmx.cfg (added)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.org.apache.karaf.security.jmx.cfg Wed Oct  2 18:27:05 2013
@@ -0,0 +1,4 @@
+#
+# JMX ACL specific
+#
+canInvoke = viewer
\ No newline at end of file

Added: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.osgi.compendium.cm.cfg
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.osgi.compendium.cm.cfg?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.osgi.compendium.cm.cfg (added)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/jmx.acl.osgi.compendium.cm.cfg Wed Oct  2 18:27:05 2013
@@ -0,0 +1,20 @@
+#
+# JMX ACL specific to osgi.compendium.cm MBean
+#
+# This configuration file configures the management of ConfigAdmin via the standard ConfigAdmin MBean
+# Such that only an admin can make changes to the JMX ACL rules, but managers can make
+# changes to other PIDs.
+#
+createFactoryConfiguration(java.lang.String)[/^jmx[.]acl.*/] = admin
+createFactoryConfiguration(java.lang.String) = manager
+createFactoryConfigurationForLocation(java.lang.String,java.lang.String)[/^jmx[.]acl.*/,/.*/] = admin
+createFactoryConfigurationForLocation(java.lang.String,java.lang.String) = manager
+delete(java.lang.String)[/^jmx[.]acl.*/] = admin
+delete(java.lang.String) = manager
+deleteConfigurations = admin
+deleteForLocation(java.lang.String,java.lang.String)[/^jmx[.]acl.*/,/.*/] = admin
+deleteForLocation(java.lang.String,java.lang.String) = manager
+update(java.lang.String,javax.management.openmbean.TabularData)[/^jmx[.]acl.*/,/.*/] = admin
+update(java.lang.String,javax.management.openmbean.TabularData) = manager
+updateForLocation(java.lang.String,java.lang.String,javax.management.openmbean.TabularData)[/^jmx[.]acl.*/,/.*/,/.*/] = admin
+updateForLocation(java.lang.String,java.lang.String,javax.management.openmbean.TabularData) = manager
\ No newline at end of file

Added: karaf/trunk/management/boot/NOTICE
URL: http://svn.apache.org/viewvc/karaf/trunk/management/boot/NOTICE?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/boot/NOTICE (added)
+++ karaf/trunk/management/boot/NOTICE Wed Oct  2 18:27:05 2013
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2013 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License

Copied: karaf/trunk/management/boot/pom.xml (from r1527610, karaf/trunk/management/server/pom.xml)
URL: http://svn.apache.org/viewvc/karaf/trunk/management/boot/pom.xml?p2=karaf/trunk/management/boot/pom.xml&p1=karaf/trunk/management/server/pom.xml&r1=1527610&r2=1528587&rev=1528587&view=diff
==============================================================================
--- karaf/trunk/management/server/pom.xml (original)
+++ karaf/trunk/management/boot/pom.xml Wed Oct  2 18:27:05 2013
@@ -28,50 +28,15 @@
         <relativePath>../pom.xml</relativePath>
     </parent>
 
-    <artifactId>org.apache.karaf.management.server</artifactId>
+    <artifactId>org.apache.karaf.management.boot</artifactId>
     <packaging>bundle</packaging>
-    <name>Apache Karaf :: Management</name>
-    <description>This bundle starts the Karaf embedded MBean server and RMI registry allowing users
-    to use JMX to manage Karaf.</description>
+    <name>Apache Karaf :: Management :: Boot</name>
+    <description>Provides the JMX classes loaded at boot of the process.</description>
 
     <properties>
-        <appendedResourcesDirectory>${basedir}/../etc/appended-resources</appendedResourcesDirectory>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
     </properties>
 
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.compendium</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.karaf.jaas</groupId>
-            <artifactId>org.apache.karaf.jaas.config</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.easymock</groupId>
-            <artifactId>easymock</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.easymock</groupId>
-            <artifactId>easymockclassextension</artifactId>
-            <version>${easymock.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
     <build>
         <resources>
             <resource>
@@ -94,15 +59,12 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Export-Package>org.apache.karaf.management;version=${project.version};-split-package:=merge-first</Export-Package>
-                        <Private-Package>
-                            org.apache.karaf.management
-                        </Private-Package>
+                        <Import-Package>*</Import-Package>
+                        <Private-Package>!*</Private-Package>
                     </instructions>
                 </configuration>
             </plugin>
-       </plugins>
+        </plugins>
     </build>
 
-
-</project>
+</project>
\ No newline at end of file

Added: karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/boot/KarafMBeanServerBuilder.java
URL: http://svn.apache.org/viewvc/karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/boot/KarafMBeanServerBuilder.java?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/boot/KarafMBeanServerBuilder.java (added)
+++ karaf/trunk/management/boot/src/main/java/org/apache/karaf/management/boot/KarafMBeanServerBuilder.java Wed Oct  2 18:27:05 2013
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.management.boot;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerBuilder;
+import javax.management.MBeanServerDelegate;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class KarafMBeanServerBuilder extends MBeanServerBuilder {
+
+    private static volatile InvocationHandler guard;
+
+    public static InvocationHandler getGuard() {
+        return guard;
+    }
+
+    public static void setGuard(InvocationHandler guardHandler) {
+        guard = guardHandler;
+    }
+
+    @Override
+    public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {
+        InvocationHandler handler = new MBeanInvocationHandler(super.newMBeanServer(defaultDomain, outer, delegate));
+        return (MBeanServer) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ MBeanServer.class }, handler);
+    }
+
+    private static final class MBeanInvocationHandler implements InvocationHandler {
+
+        private final MBeanServer wrapped;
+        private final List<String> guarded = Collections.unmodifiableList(Arrays.asList("invoke", "getAttribute", "getAttributes", "setAttribute", "setAttributes"));
+
+        MBeanInvocationHandler(MBeanServer mbeanServer) {
+            wrapped = mbeanServer;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (guarded.contains(method.getName())) {
+                if (KarafMBeanServerBuilder.guard == null) {
+                    throw new IllegalStateException("KarafMBeanServerBuilder not initialized");
+                }
+                guard.invoke(proxy, method, args);
+            }
+            return method.invoke(wrapped, args);
+        }
+
+    }
+
+}

Added: karaf/trunk/management/boot/src/main/resources/OSGI-INF/bundle.info
URL: http://svn.apache.org/viewvc/karaf/trunk/management/boot/src/main/resources/OSGI-INF/bundle.info?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/boot/src/main/resources/OSGI-INF/bundle.info (added)
+++ karaf/trunk/management/boot/src/main/resources/OSGI-INF/bundle.info Wed Oct  2 18:27:05 2013
@@ -0,0 +1,17 @@
+\u001B[1mSYNOPSIS\u001B[0m
+    ${project.name}
+
+    ${project.description}
+
+    Maven URL:
+        \u001B[33mmvn:${project.groupId}/${project.artifactId}/${project.version}\u001B[0m
+
+\u001B[1mDESCRIPTION\u001B[0m
+    This bundle provides JMX classes loaded during Karaf boot process.
+
+    In particular it provides the KarafMBeanServerBuilder.
+
+    The KarafMBeanServerBuilder builds a special MBeanServer that allows role-based authorization
+    for JMX access.
+    This class must be loadable from at startup by the JVM so this module is added to classpath, the
+    the boot delegation class path and made available via the system bundle.

Added: karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/boot/KarafMBeanServerBuilderTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/boot/KarafMBeanServerBuilderTest.java?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/boot/KarafMBeanServerBuilderTest.java (added)
+++ karaf/trunk/management/boot/src/test/java/org/apache/karaf/management/boot/KarafMBeanServerBuilderTest.java Wed Oct  2 18:27:05 2013
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.management.boot;
+
+import junit.framework.TestCase;
+import org.easymock.EasyMock;
+
+import javax.management.AttributeList;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class KarafMBeanServerBuilderTest extends TestCase {
+
+    public void testMBeanServerBuilderBlocking() throws Exception {
+        MBeanServer mbs = EasyMock.createMock(MBeanServer.class);
+        EasyMock.replay(mbs);
+
+        KarafMBeanServerBuilder mbsb = new KarafMBeanServerBuilder();
+        MBeanServer kmbs = mbsb.newMBeanServer("test", mbs, null);
+
+        final List<Object> handlerArgs = new ArrayList<Object>();
+        InvocationHandler guard = new InvocationHandler() {
+            @Override
+            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                handlerArgs.add(proxy);
+                handlerArgs.add(method);
+                handlerArgs.add(args);
+
+                throw new SecurityException("Access Denied");
+            }
+        };
+
+        KarafMBeanServerBuilder.setGuard(guard);
+
+        assertEquals("Precondition", 0, handlerArgs.size());
+
+        ObjectName on = ObjectName.getInstance("foo.bar:type=TestObject");
+
+        try {
+            kmbs.getAttribute(on, "myAttr");
+            fail("Should have access denied");
+        } catch (SecurityException se) {
+            // good
+            assertEquals(3, handlerArgs.size());
+            assertSame(kmbs, handlerArgs.get(0));
+            assertEquals("getAttribute", ((Method) handlerArgs.get(1)).getName());
+            Object[] args = (Object[]) handlerArgs.get(2);
+            assertEquals(2, args.length);
+            assertSame(on, args[0]);
+            assertEquals("myAttr", args[1]);
+        }
+
+        try {
+            kmbs.getAttributes(on, new String[]{"foo", "bar"});
+            fail("Should have access denied");
+        } catch (SecurityException se) {
+            // good
+        }
+
+        try {
+            kmbs.getAttributes(on, new String[]{ "goo", "far" });
+            fail("Should have access denied");
+        } catch (SecurityException se) {
+            // good
+        }
+
+        try {
+            kmbs.setAttributes(on, new AttributeList());
+            fail("Should have access denied");
+        } catch (SecurityException se) {
+            // good
+        }
+
+        try {
+            kmbs.setAttributes(on, new AttributeList());
+            fail("Should have access denied");
+        } catch (SecurityException se) {
+            // good
+        }
+
+        // try some MBeanServer operations that are not guarded
+        assertTrue(kmbs.getDomains().length > 0);
+        assertTrue(kmbs.getMBeanCount() > 0);
+        assertTrue(kmbs.getDefaultDomain().length() > 0);
+    }
+
+    public void testMBeanServerBuilderNonBlocking() throws Exception {
+        MBeanServer mbs = EasyMock.createMock(MBeanServer.class);
+        EasyMock.replay(mbs);
+
+        KarafMBeanServerBuilder mbsb = new KarafMBeanServerBuilder();
+        MBeanServer kmbs = mbsb.newMBeanServer("test", mbs, null);
+
+        final List<Object> handlerArgs = new ArrayList<Object>();
+        InvocationHandler guard = new InvocationHandler() {
+            @Override
+            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                handlerArgs.add(proxy);
+                handlerArgs.add(method);
+                handlerArgs.add(args);
+                return null;
+            }
+        };
+
+        KarafMBeanServerBuilder.setGuard(guard);
+
+        assertEquals("Precondition", 0, handlerArgs.size());
+
+        ObjectName on = ObjectName.getInstance("foo.bar:type=TestObject");
+
+        try {
+            kmbs.getAttribute(on, "myAttr");
+        } catch (Exception e) {
+            Throwable th = getInnermostException(e);
+            assertTrue("Expected exception as the object in question is not registered with the MBeanServer", th instanceof InstanceNotFoundException);
+            // good
+            assertEquals(3, handlerArgs.size());
+            assertSame(kmbs, handlerArgs.get(0));
+            assertEquals("getAttribute", ((Method) handlerArgs.get(1)).getName());
+            Object[] args = (Object[]) handlerArgs.get(2);
+            assertEquals(2, args.length);
+            assertSame(on, args[0]);
+            assertEquals("myAttr", args[1]);
+        }
+    }
+
+    private Throwable getInnermostException(Throwable th) {
+        if (th.getCause() != null) {
+            return getInnermostException(th.getCause());
+        } else {
+            return th;
+        }
+    }
+
+}

Modified: karaf/trunk/management/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/management/pom.xml?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/management/pom.xml (original)
+++ karaf/trunk/management/pom.xml Wed Oct  2 18:27:05 2013
@@ -34,6 +34,7 @@
     <name>Apache Karaf :: Management</name>
 
     <modules>
+        <module>boot</module>
         <module>server</module>
     </modules>
 

Modified: karaf/trunk/management/server/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/management/server/pom.xml?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/management/server/pom.xml (original)
+++ karaf/trunk/management/server/pom.xml Wed Oct  2 18:27:05 2013
@@ -51,10 +51,20 @@
         </dependency>
         <dependency>
             <groupId>org.apache.karaf.jaas</groupId>
+            <artifactId>org.apache.karaf.jaas.boot</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.jaas</groupId>
             <artifactId>org.apache.karaf.jaas.config</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.karaf.management</groupId>
+            <artifactId>org.apache.karaf.management.boot</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.servicemix.bundles</groupId>
             <artifactId>org.apache.servicemix.bundles.junit</artifactId>
             <scope>test</scope>
@@ -96,7 +106,8 @@
                     <instructions>
                         <Export-Package>org.apache.karaf.management;version=${project.version};-split-package:=merge-first</Export-Package>
                         <Private-Package>
-                            org.apache.karaf.management
+                            org.apache.karaf.management,
+                            org.apache.karaf.management.internal
                         </Private-Package>
                     </instructions>
                 </configuration>

Added: karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JMXSecurityMBean.java
URL: http://svn.apache.org/viewvc/karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JMXSecurityMBean.java?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JMXSecurityMBean.java (added)
+++ karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JMXSecurityMBean.java Wed Oct  2 18:27:05 2013
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.management;
+
+import javax.management.openmbean.*;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Security MBean. This MBean can be used to find out whether the currently logged user can access certain MBeans
+ * or invoke operations on these MBeans. It can be used when building client-facing consoles to ensure that only
+ * operations appropriate for the current user are presented.<p/>
+ * This MBean does not actually invoke any operations on the given objects, it only checks permissions.
+ */
+public interface JMXSecurityMBean {
+
+    /**
+     * The Tabular Type returned by the {@link #canInvoke(Map)} operation. The rows consist of
+     * {@link #CAN_INVOKE_RESULT_ROW_TYPE} entries.
+     * It has a composite key composed by the "ObjectName" and "Method" columns.
+     */
+    static final TabularType CAN_INVOKE_TABULAR_TYPE = SecurityMBeanOpenTypeInitializer.TABULAR_TYPE;
+
+    /**
+     * A row as returned by the {@link #CAN_INVOKE_TABULAR_TYPE}. The columns of the row are defined
+     * by {@link #CAN_INVOKE_RESULT_COLUMNS}
+     */
+    static final CompositeType CAN_INVOKE_RESULT_ROW_TYPE = SecurityMBeanOpenTypeInitializer.ROW_TYPE;
+
+    /**
+     * The columns contained in a {@link #CAN_INVOKE_RESULT_ROW_TYPE}. The data types for these columns are
+     * as follows:
+     * <ul>
+     *     <li>"ObjectName": {@link SimpleType#STRING}</li>
+     *     <li>"Method": {@link SimpleType#STRING}</li>
+     *     <li>"CanInvoke": {@link SimpleType#BOOLEAN}</li>
+     * </ul>
+     */
+    static final String[] CAN_INVOKE_RESULT_COLUMNS = SecurityMBeanOpenTypeInitializer.COLUMNS;
+
+    /**
+     * Checks whether the current user can invoke any methods on a JMX MBean.
+     *
+     * @param objectName the Object Name of the JMX MBean.
+     * @return {@code true} if there is at least one method on the MBean that the user can invoke, {@code false} else.
+     * @throws Exception
+     */
+    boolean canInvoke(String objectName) throws Exception;
+
+    /**
+     * Checks whether the current user can invoke overload of the given method.
+     *
+     * @param objectName the Object Name of the JMX MBean.
+     * @param methodName the name of the method to check.
+     * @return {@code true} if there is an overload of the specified method that the user can invoke, {@code false} else.
+     * @throws Exception
+     */
+    boolean canInvoke(String objectName, String methodName) throws Exception;
+
+    /**
+     * Checks whether the current user can invoke the given method.
+     *
+     * @param objectName the Object Name of the JMX MBean.
+     * @param methodName the name of the method to check.
+     * @param argumentTypes the argument types of the method.
+     * @return {@code true} if the user is allowed to invoke the method, or any of the methods with the given name if
+     * {@code null} is used for the arguments. There may still be certain values that the user does not have permissions
+     * to pass to the method.
+     * @throws Exception
+     */
+    boolean canInvoke(String objectName, String methodName, String[] argumentTypes) throws Exception;
+
+    /**
+     * Bulk operation to check whether the current user can access the requested MBeans or invoke the requested
+     * methods.
+     *
+     * @param bulkQuery a map of Object Name to requested operations. Operations can be specified with or without
+     *                  argument types. An operation without arguments matches any overloaded method with this
+     *                  name. If an empty list is provided for the operation names, a check is done whether the
+     *                  current user can invoke <em>any</em> operation on the MBean.<p/>
+     *                  Example:
+     *                  <pre>{@code
+     *                  Map<String, List<String>> query = new HashMap<>();
+     *                  String objectName = "org.acme:type=SomeMBean";
+     *                  query.put(objectName, Arrays.asList(
+     *                      "testMethod(long,java.lang.String)", // check this testMethod
+     *                      "otherMethod"));                     // check any overload of otherMethod
+     *                  query.put("org.acme:type=SomeOtherMBean",
+     *                      Collections.<String>emptyList());    // check any method of SomeOtherMBean
+     *                  TabularData result = mb.canInvoke(query);
+     *                  }</pre>
+     * @return A Tabular Data object with the result. This object conforms the structure as defined in {@link #CAN_INVOKE_TABULAR_TYPE}
+     * @throws Exception
+     */
+    TabularData canInvoke(Map<String, List<String>> bulkQuery) throws Exception;
+
+    // a member class is used to initialize final fields, as this needs to do some exception handling...
+    static class SecurityMBeanOpenTypeInitializer {
+
+        private static final String[] COLUMNS = new String[]{ "ObjectName", "Method", "CanInvoke" };
+        private static final CompositeType ROW_TYPE;
+
+        static {
+            try {
+                ROW_TYPE = new CompositeType("CanInvokeRowType",
+                        "The rows of a CanInvokeTabularType table.",
+                        COLUMNS,
+                        new String[]{
+                            "The ObjectName of the checked MBean.",
+                            "The Method to check. This can be either a bare method name which means 'any method with this name' "
+                                + "or any specific overload such as foo(java.lang.String). If an empty String is returned this means"
+                                + " 'any' method.",
+                            "true if the method or MBean can potentially be invoked by the current user."
+                        },
+                        new OpenType[] { SimpleType.STRING, SimpleType.STRING, SimpleType.BOOLEAN });
+            } catch (OpenDataException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private static final TabularType TABULAR_TYPE;
+        static {
+            try {
+                TABULAR_TYPE = new TabularType("CanInvokeTabularType", "Result of canInvoke() bulk operation", ROW_TYPE,
+                        new String[] { "ObjectName", "Method" });
+            } catch (OpenDataException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+    }
+
+}

Modified: karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JaasAuthenticator.java
URL: http://svn.apache.org/viewvc/karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JaasAuthenticator.java?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JaasAuthenticator.java (original)
+++ karaf/trunk/management/server/src/main/java/org/apache/karaf/management/JaasAuthenticator.java Wed Oct  2 18:27:05 2013
@@ -17,7 +17,6 @@
 package org.apache.karaf.management;
 
 import java.io.IOException;
-import java.security.Principal;
 
 import javax.management.remote.JMXAuthenticator;
 import javax.security.auth.Subject;
@@ -33,7 +32,6 @@ import javax.security.auth.login.LoginEx
 public class JaasAuthenticator implements JMXAuthenticator {
 
     private String realm;
-    private String role;
 
     public String getRealm() {
         return realm;
@@ -43,19 +41,12 @@ public class JaasAuthenticator implement
         this.realm = realm;
     }
 
-    public String getRole() {
-        return role;
-    }
-
-    public void setRole(String role) {
-        this.role = role;
-    }
-
     public Subject authenticate(Object credentials) throws SecurityException {
         if (!(credentials instanceof String[])) {
             throw new IllegalArgumentException("Expected String[2], got "
                             + (credentials != null ? credentials.getClass().getName() : null));
         }
+
         final String[] params = (String[]) credentials;
         if (params.length != 2) {
             throw new IllegalArgumentException("Expected String[2] but length was " + params.length);
@@ -76,26 +67,12 @@ public class JaasAuthenticator implement
                 }
             });
             loginContext.login();
-            if (role != null && role.length() > 0) {
-                String clazz = "org.apache.karaf.jaas.boot.principal.RolePrincipal";
-                String name = role;
-                int idx = role.indexOf(':');
-                if (idx > 0) {
-                    clazz = role.substring(0, idx);
-                    name = role.substring(idx + 1);
-                }
-                boolean found = false;
-                for (Principal p : subject.getPrincipals()) {
-                    if (p.getClass().getName().equals(clazz)
-                            && p.getName().equals(name)) {
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    throw new FailedLoginException("User does not have the required role " + role);
-                }
+
+            if (subject.getPrincipals().size() == 0) {
+                // there must be some Principals, but which ones required are tested later
+                throw new FailedLoginException("User does not have the required role");
             }
+
             return subject;
         } catch (LoginException e) {
             throw new SecurityException("Authentication failed", e);

Added: karaf/trunk/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java
URL: http://svn.apache.org/viewvc/karaf/trunk/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java (added)
+++ karaf/trunk/management/server/src/main/java/org/apache/karaf/management/KarafMBeanServerGuard.java Wed Oct  2 18:27:05 2013
@@ -0,0 +1,576 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.management;
+
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.management.boot.KarafMBeanServerBuilder;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import javax.management.*;
+import javax.security.auth.Subject;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
+import java.util.*;
+
+public class KarafMBeanServerGuard implements InvocationHandler {
+
+    private static final String JMX_ACL_PID_PREFIX = "jmx.acl";
+
+    private ConfigurationAdmin configAdmin;
+
+    public ConfigurationAdmin getConfigAdmin() {
+        return configAdmin;
+    }
+
+    public void setConfigAdmin(ConfigurationAdmin configAdmin) {
+        this.configAdmin = configAdmin;
+    }
+
+    public void init() {
+        KarafMBeanServerBuilder.setGuard(this);
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (method.getParameterTypes().length == 0)
+            return null;
+
+        if (!ObjectName.class.isAssignableFrom(method.getParameterTypes()[0]))
+            return null;
+
+        ObjectName objectName = (ObjectName) args[0];
+        if ("getAttribute".equals(method.getName())) {
+            handleGetAttribute((MBeanServer) proxy, objectName, (String) args[1]);
+        } else if ("getAttributes".equals(method.getName())) {
+            handleGetAttributes((MBeanServer) proxy, objectName, (String[]) args[1]);
+        } else if ("setAttribute".equals(method.getName())) {
+            handleSetAttribute((MBeanServer) proxy, objectName, (Attribute) args[1]);
+        } else if ("setAttributes".equals(method.getName())) {
+            handleSetAttributes((MBeanServer) proxy, objectName, (AttributeList) args[1]);
+        } else if ("invoke".equals(method.getName())) {
+            handleInvoke(objectName, (String) args[1], (Object[]) args[2], (String[]) args[3]);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns whether there is any method that the current user can invoke.
+     *
+     * @param mbeanServer the MBeanServer where the object is registered.
+     * @param objectName the ObjectName to check.
+     * @return {@code true} if there is a method on the object that can be invoked, {@code false} else.
+     * @throws JMException
+     * @throws IOException
+     */
+    public boolean canInvoke(MBeanServer mbeanServer, ObjectName objectName) throws JMException, IOException {
+        MBeanInfo info = mbeanServer.getMBeanInfo(objectName);
+
+        for (MBeanOperationInfo operation : info.getOperations()) {
+            List<String> sig = new ArrayList<String>();
+            for (MBeanParameterInfo param : operation.getSignature()) {
+                sig.add(param.getType());
+            }
+            if (canInvoke(objectName, operation.getName(), sig.toArray(new String[] {}))) {
+                return true;
+            }
+        }
+
+        for (MBeanAttributeInfo attr : info.getAttributes()) {
+            if (attr.isReadable()) {
+                if (canInvoke(objectName, attr.isIs() ? "is" : "get" + attr.getName(), new String[] {}))
+                    return true;
+            }
+            if (attr.isWritable()) {
+                if (canInvoke(objectName, "set" + attr.getName(), new String[]{attr.getType()}))
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns whether there is any overload of the specified method that can be invoked by the current user.
+     *
+     * @param mbeanServer the MBeanServer where the object is registered.
+     * @param objectName the MBean ObjectName.
+     * @param methodName the name of the method.
+     * @return {@code true} if there is an overload of the method that can be invoked by the current user.
+     * @throws JMException
+     * @throws IOException
+     */
+    public boolean canInvoke(MBeanServer mbeanServer, ObjectName objectName, String methodName) throws JMException, IOException {
+        methodName = methodName.trim();
+        MBeanInfo info = mbeanServer.getMBeanInfo(objectName);
+
+        for (MBeanOperationInfo op : info.getOperations()) {
+            if (!methodName.equals(op.getName())) {
+                continue;
+            }
+
+            List<String> sig = new ArrayList<String>();
+            for (MBeanParameterInfo param : op.getSignature()) {
+                sig.add(param.getType());
+            }
+            if (canInvoke(objectName, op.getName(), sig.toArray(new String[] {}))) {
+                return true;
+            }
+        }
+
+        for (MBeanAttributeInfo attr : info.getAttributes()) {
+            String attrName = attr.getName();
+            if (methodName.equals("is" + attrName) || methodName.equals("get" + attrName)) {
+                return canInvoke(objectName, methodName, new String[] {});
+            }
+            if (methodName.equals("set" + attrName)) {
+                return canInvoke(objectName, methodName, new String[] { attr.getType() });
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns true if the method on the MBean with the specified signature can be invoked.
+     *
+     * @param mbeanServer the MBeanServer where the object is registered.
+     * @param objectName the MBean ObjectName.
+     * @param methodName the name of the method.
+     * @param signature the signature of the method.
+     * @return {@code true} if the method can be invoked, {@code false} else. Note that if a method name or signature
+     *      is provided that does not exist on the MBean, the behaviour of this method is undefined. In other words,
+     *      if you ask whether a method that does not exist can be invoked, the method may return {@code true} but
+     *      actually invoking that method will obviously not work.
+     * @throws IOException
+     */
+    public boolean canInvoke(MBeanServer mbeanServer, ObjectName objectName, String methodName, String[] signature) throws IOException {
+        // no checking done on the MBeanServer of whether the method actually exists...
+        return canInvoke(objectName, methodName, signature);
+    }
+
+    private boolean canInvoke(ObjectName objectName, String methodName, String[] signature) throws IOException {
+        for (String role : getRequiredRoles(objectName, methodName, signature)) {
+            if (currentUserHasRole(role))
+                return true;
+        }
+
+        return false;
+    }
+
+    private void handleGetAttribute(MBeanServer proxy, ObjectName objectName, String attributeName) throws JMException, IOException {
+        MBeanInfo info = proxy.getMBeanInfo(objectName);
+        String prefix = null;
+        for (MBeanAttributeInfo attr : info.getAttributes()) {
+            if (attr.getName().equals(attributeName)) {
+                prefix = attr.isIs() ? "is" : "get";
+            }
+        }
+        if (prefix == null)
+            throw new IllegalStateException("Attribute " + attributeName + " can not be found");
+
+        handleInvoke(objectName, prefix + attributeName, new Object[]{}, new String[]{});
+    }
+
+    private void handleGetAttributes(MBeanServer proxy, ObjectName objectName, String[] attributeNames) throws JMException, IOException {
+        for (String attr : attributeNames) {
+            handleGetAttribute(proxy, objectName, attr);
+        }
+    }
+
+    private void handleSetAttribute(MBeanServer proxy, ObjectName objectName, Attribute attribute) throws JMException, IOException {
+        String dataType = null;
+        MBeanInfo info = proxy.getMBeanInfo(objectName);
+        for (MBeanAttributeInfo attr : info.getAttributes()) {
+            if (attr.getName().equals(attribute.getName())) {
+                dataType = attr.getType();
+                break;
+            }
+        }
+
+        if (dataType == null)
+            throw new IllegalStateException("Attribute data type can not be found");
+
+        handleInvoke(objectName, "set" + attribute.getName(), new Object[]{ attribute.getValue() }, new String[]{ dataType });
+    }
+
+    private void handleSetAttributes(MBeanServer proxy, ObjectName objectName, AttributeList attributes) throws JMException, IOException {
+        for (Attribute attr : attributes.asList()) {
+            handleSetAttribute(proxy, objectName, attr);
+        }
+    }
+
+    void handleInvoke(ObjectName objectName, String operationName, Object[] params, String[] signature) throws IOException {
+        for (String role : getRequiredRoles(objectName, operationName, params, signature)) {
+            if (currentUserHasRole(role))
+                return;
+        }
+        throw new SecurityException("Insufficient roles/credentials for operation");
+    }
+
+    List<String> getRequiredRoles(ObjectName objectName, String methodName, String[] signature) throws IOException {
+        return getRequiredRoles(objectName, methodName, null, signature);
+    }
+
+    List<String> getRequiredRoles(ObjectName objectName, String methodName, Object[] params, String[] signature) throws IOException {
+        List<String> roles = new ArrayList<String>();
+
+        List<String> allPids = new ArrayList<String>();
+        try {
+            for (Configuration config : configAdmin.listConfigurations("(service.pid=jmx.acl*)")) {
+                allPids.add(config.getPid());
+            }
+        } catch (InvalidSyntaxException ise) {
+            throw new RuntimeException(ise);
+        }
+
+        for (String pid : iterateDownPids(getNameSegments(objectName))) {
+            if (allPids.contains(pid)) {
+                Configuration config = configAdmin.getConfiguration(pid);
+                Dictionary<String, Object> properties = trimKeys(config.getProperties());
+
+                /*
+                1. get all direct string matches
+                2. get regex matches
+                3. get signature matches
+                4. without signature
+                5. method name wildcard
+
+                We return immediately when a definition is found, so if a specific definition is found, we do not
+                search for a more generic specification.
+                Regular expressions and exact matches are considered equally specific, so they are combined...
+                 */
+
+                boolean foundExactOrRegex = false;
+                if (params != null) {
+                    Object exactArgMatchRoles = properties.get(getExactArgSignature(methodName, signature, params));
+                    if (exactArgMatchRoles instanceof String) {
+                        roles.addAll(parseRoles((String) exactArgMatchRoles));
+                        foundExactOrRegex = true;
+                    }
+
+                    foundExactOrRegex |= getRegexRoles(properties, methodName, signature, params, roles);
+
+                    if (foundExactOrRegex) {
+                        // since we have the actual parameters we can match them and if they do, we won't look for any
+                        // more generic rules...
+                        return roles;
+                    }
+                } else {
+                    foundExactOrRegex = getExactArgOrRegexRoles(properties, methodName, signature, roles);
+                }
+
+                Object signatureRoles = properties.get(getSignature(methodName, signature));
+                if (signatureRoles instanceof String) {
+                    roles.addAll(parseRoles((String) signatureRoles));
+                    return roles;
+                }
+
+                if (foundExactOrRegex) {
+                    // we can get here if params == null and there were exact and/or regex rules but no signature rules
+                    return roles;
+                }
+
+                Object methodRoles = properties.get(methodName);
+                if (methodRoles instanceof String) {
+                    roles.addAll(parseRoles((String) methodRoles));
+                    return roles;
+                }
+
+                if (getMethodNameWildcardRoles(properties, methodName, roles))
+                    return roles;
+            }
+        }
+        return roles;
+    }
+
+    private Dictionary<String, Object> trimKeys(Dictionary<String, Object> properties) {
+        Dictionary<String, Object> d = new Hashtable<String, Object>();
+        for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+            String key = e.nextElement();
+            Object value = properties.get(key);
+
+            d.put(removeSpaces(key), value);
+        }
+        return d;
+    }
+
+    private String removeSpaces(String key) {
+        StringBuilder sb = new StringBuilder();
+        char quoteChar = 0;
+        for (int i = 0; i < key.length(); i++) {
+            char c = key.charAt(i);
+
+            if (quoteChar == 0 && c == ' ')
+                continue;
+
+            if (quoteChar == 0 && (c == '\"' || c == '/') && sb.length() > 0 &&
+                    (sb.charAt(sb.length() - 1) == '[' || sb.charAt(sb.length() - 1) == ',')) {
+                // we are in a quoted string
+                quoteChar = c;
+            } else if (quoteChar != 0 && c == quoteChar) {
+                // look ahead to see if the next non-space is the closing bracket or a comma, which ends the quoted string
+                for (int j = i + 1; j < key.length(); j++) {
+                    if (key.charAt(j) == ' ') {
+                        continue;
+                    }
+                    if (key.charAt(j) == ']' || key.charAt(j) == ',') {
+                        quoteChar = 0;
+                    }
+                    break;
+                }
+            }
+            sb.append(c);
+        }
+
+        return sb.toString();
+    }
+
+    private List<String> parseRoles(String roleString) {
+        int hashIndex = roleString.indexOf('#');
+        if (hashIndex >= 0) {
+            // you can put a comment at the end
+            roleString = roleString.substring(0, hashIndex);
+        }
+
+        List<String> roles = new ArrayList<String>();
+        for (String role : roleString.split("[,]")) {
+            String trimmed = role.trim();
+            if (trimmed.length() > 0)
+                roles.add(trimmed);
+        }
+
+        return roles;
+    }
+
+    private Object getExactArgSignature(String methodName, String[] signature, Object[] params) {
+        StringBuilder sb = new StringBuilder(getSignature(methodName, signature));
+        sb.append('[');
+        boolean first = true;
+        for (Object param : params) {
+            if (first)
+                first = false;
+            else
+                sb.append(',');
+
+            sb.append('"');
+            sb.append(param.toString().trim());
+            sb.append('"');
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+
+    private String getSignature(String methodName, String[] signature) {
+        StringBuilder sb = new StringBuilder(methodName);
+        sb.append('(');
+        boolean first = true;
+        for (String s : signature) {
+            if (first)
+                first = false;
+            else
+                sb.append(',');
+
+            sb.append(s);
+        }
+        sb.append(')');
+        return sb.toString();
+    }
+
+    private boolean getRegexRoles(Dictionary<String, Object> properties, String methodName, String[] signature, Object[] params, List<String> roles) {
+        boolean matchFound = false;
+        String methodSig = getSignature(methodName, signature);
+        String prefix = methodSig + "[/";
+        for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+            String key = e.nextElement().trim();
+            if (key.startsWith(prefix) && key.endsWith("/]")) {
+                List<String> regexArgs = getRegexDecl(key.substring(methodName.length()));
+                if (allParamsMatch(regexArgs, params)) {
+                    matchFound = true;
+                    Object roleString = properties.get(key);
+                    if (roleString instanceof String)
+                        roles.addAll(parseRoles((String) roleString));
+                }
+            }
+        }
+        return matchFound;
+    }
+
+    private boolean getExactArgOrRegexRoles(Dictionary<String, Object> properties, String methodName, String[] signature, List<String> roles) {
+        boolean matchFound = false;
+        String methodSig = getSignature(methodName, signature);
+        String prefix = methodSig + "[";
+        for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+            String key = e.nextElement().trim();
+            if (key.startsWith(prefix) && key.endsWith("]")) {
+                matchFound = true;
+                Object roleString = properties.get(key);
+                if (roleString instanceof String)
+                    roles.addAll(parseRoles((String) roleString));
+            }
+        }
+        return matchFound;
+    }
+
+    private boolean getMethodNameWildcardRoles(Dictionary<String, Object> properties, String methodName, List<String> roles) {
+        SortedMap<String, String> wildcardRules = new TreeMap<String, String>(new Comparator<String>() {
+            public int compare(String s1, String s2) {
+                // returns longer entries before shorter ones...
+                return s2.length() - s1.length();
+            }
+        });
+        for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+            String key = e.nextElement();
+            if (key.endsWith("*")) {
+                String prefix = key.substring(0, key.length() - 1);
+                if (methodName.startsWith(prefix)) {
+                    wildcardRules.put(prefix, properties.get(key).toString());
+                }
+            }
+        }
+
+        if (wildcardRules.size() != 0) {
+            roles.addAll(parseRoles(wildcardRules.values().iterator().next()));
+            return true;
+        } else
+            return false;
+    }
+
+    private boolean allParamsMatch(List<String> regexArgs, Object[] params) {
+        if (regexArgs.size() != params.length)
+            return false;
+
+        for (int i = 0; i < regexArgs.size(); i++) {
+            if (!params[i].toString().trim().matches(regexArgs.get(i)))
+                return false;
+        }
+
+        return true;
+    }
+
+    private List<String> getRegexDecl(String key) {
+        List<String> l = new ArrayList<String>();
+
+        boolean inRegex = false;
+        StringBuilder currentRegex = new StringBuilder();
+        for (int i = 0; i < key.length(); i++) {
+            if (!inRegex) {
+                if (key.length() > i+1) {
+                    String s = key.substring(i, i+2);
+
+                    if ("[/".equals(s) || ",/".equals(s)) {
+                        inRegex = true;
+                        i++;
+                        continue;
+                    }
+                }
+            } else {
+                String s = key.substring(i, i+2);
+                if ("/]".equals(s) || "/,".equals(s)) {
+                    l.add(currentRegex.toString());
+                    currentRegex = new StringBuilder();
+                    inRegex = false;
+                    continue;
+                }
+                currentRegex.append(key.charAt(i));
+            }
+        }
+        return l;
+    }
+
+    private List<String> getNameSegments(ObjectName objectName) {
+        List<String> segments = new ArrayList<String>();
+        segments.add(objectName.getDomain());
+
+        // TODO can an ObjectName property contain a comma as key or value ?
+        // TODO support quoting as described in http://docs.oracle.com/javaee/1.4/api/javax/management/ObjectName.html
+        for (String s : objectName.getKeyPropertyListString().split("[,]")) {
+            int index = s.indexOf('=');
+            if (index < 0)
+                continue;
+
+            segments.add(objectName.getKeyProperty(s.substring(0, index)));
+        }
+
+        return segments;
+    }
+
+    /**
+     * Given a list of segments, return a list of PIDs that are searched in this order.
+     * For example, given the following segments: org.foo, bar, test
+     * the following list of PIDs will be generated (in this order):
+     *      jmx.acl.org.foo.bar.test
+     *      jmx.acl.org.foo.bar
+     *      jmx.acl.org.foo
+     *      jmx.acl
+     * The order is used as a search order, in which the most specific PID is searched first.
+     *
+     * @param segments the ObjectName segments.
+     * @return the PIDs corresponding with the ObjectName in the above order.
+     */
+    private List<String> iterateDownPids(List<String> segments) {
+        List<String> res = new ArrayList<String>();
+        for (int i = segments.size(); i > 0; i--) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(JMX_ACL_PID_PREFIX);
+            for (int j = 0; j < i; j++) {
+                sb.append('.');
+                sb.append(segments.get(j));
+            }
+            res.add(sb.toString());
+        }
+        res.add(JMX_ACL_PID_PREFIX); // this is the top PID (aka jmx.acl)
+        return res;
+    }
+
+    static boolean currentUserHasRole(String requestedRole) {
+        String clazz;
+        String role;
+        int index = requestedRole.indexOf(':');
+        if (index > 0) {
+            clazz = requestedRole.substring(0, index);
+            role = requestedRole.substring(index + 1);
+        } else {
+            clazz = RolePrincipal.class.getName();
+            role = requestedRole;
+        }
+
+        AccessControlContext acc = AccessController.getContext();
+        if (acc == null) {
+            return false;
+        }
+        Subject subject = Subject.getSubject(acc);
+
+        if (subject == null) {
+            return false;
+        }
+
+        for (Principal p : subject.getPrincipals()) {
+            if (clazz.equals(p.getClass().getName()) && role.equals(p.getName())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}

Added: karaf/trunk/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java
URL: http://svn.apache.org/viewvc/karaf/trunk/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java?rev=1528587&view=auto
==============================================================================
--- karaf/trunk/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java (added)
+++ karaf/trunk/management/server/src/main/java/org/apache/karaf/management/internal/JMXSecurityMBeanImpl.java Wed Oct  2 18:27:05 2013
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.management.internal;
+
+import org.apache.karaf.management.JMXSecurityMBean;
+import org.apache.karaf.management.KarafMBeanServerGuard;
+import org.apache.karaf.management.boot.KarafMBeanServerBuilder;
+
+import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class JMXSecurityMBeanImpl extends StandardMBean implements JMXSecurityMBean {
+
+    private MBeanServer mbeanServer;
+
+    public JMXSecurityMBeanImpl() throws NotCompliantMBeanException {
+        super(JMXSecurityMBean.class);
+    }
+
+    public boolean canInvoke(String objectName) throws Exception {
+        KarafMBeanServerGuard guard = (KarafMBeanServerGuard) KarafMBeanServerBuilder.getGuard();
+        if (guard == null)
+            return true;
+
+        return guard.canInvoke(mbeanServer, new ObjectName(objectName));
+    }
+
+    public boolean canInvoke(String objectName, String methodName) throws Exception {
+        KarafMBeanServerGuard guard = (KarafMBeanServerGuard) KarafMBeanServerBuilder.getGuard();
+        if (guard == null)
+            return true;
+
+        return guard.canInvoke(mbeanServer, new ObjectName(objectName), methodName);
+    }
+
+    public boolean canInvoke(String objectName, String methodName, String[] argumentTypes) throws Exception {
+        ObjectName on = new ObjectName(objectName);
+
+        KarafMBeanServerGuard guard = (KarafMBeanServerGuard) KarafMBeanServerBuilder.getGuard();
+        if (guard == null)
+            return true;
+
+        return guard.canInvoke(mbeanServer, on, methodName, argumentTypes);
+    }
+
+    public TabularData canInvoke(Map<String, List<String>> bulkQuery) throws Exception {
+        TabularData table = new TabularDataSupport(CAN_INVOKE_TABULAR_TYPE);
+
+        for (Map.Entry<String, List<String>> entry : bulkQuery.entrySet()) {
+            String objectName = entry.getKey();
+            List<String> methods = entry.getValue();
+            if (methods.size() == 0) {
+                boolean res = canInvoke(objectName);
+                CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE, CAN_INVOKE_RESULT_COLUMNS, new Object[]{ objectName, "", res });
+                table.put(data);
+            } else {
+                for (String method : methods) {
+                    List<String> argTypes = new ArrayList<String>();
+                    String name = parseMethodName(method, argTypes);
+
+                    boolean res;
+                    if (name.equals(method)) {
+                        res = canInvoke(objectName, name);
+                    } else {
+                        res = canInvoke(objectName, name, argTypes.toArray(new String[]{}));
+                    }
+                    CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE, CAN_INVOKE_RESULT_COLUMNS, new Object[]{ objectName, method, res });
+                    table.put(data);
+                }
+            }
+        }
+
+        return table;
+    }
+
+    private String parseMethodName(String method, List<String> argTypes) {
+        method = method.trim();
+        int index = method.indexOf('(');
+        if (index < 0)
+            return method;
+
+        String args = method.substring(index + 1, method.length() - 1);
+        for (String arg : args.split(",")) {
+            argTypes.add(arg);
+        }
+
+        return method.substring(0, index);
+    }
+
+    public MBeanServer getMBeanServer() {
+        return this.mbeanServer;
+    }
+
+    public void setMBeanServer(MBeanServer mbeanServer) {
+        this.mbeanServer = mbeanServer;
+    }
+
+}

Modified: karaf/trunk/management/server/src/main/resources/OSGI-INF/blueprint/karaf-management.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/management/server/src/main/resources/OSGI-INF/blueprint/karaf-management.xml?rev=1528587&r1=1528586&r2=1528587&view=diff
==============================================================================
--- karaf/trunk/management/server/src/main/resources/OSGI-INF/blueprint/karaf-management.xml (original)
+++ karaf/trunk/management/server/src/main/resources/OSGI-INF/blueprint/karaf-management.xml Wed Oct  2 18:27:05 2013
@@ -37,7 +37,6 @@
             <cm:property name="rmiServerHost" value="0.0.0.0"/>
             <cm:property name="rmiServerPort" value="44444"/>
             <cm:property name="jmxRealm" value="karaf"/>
-            <cm:property name="jmxRole" value="$[karaf.admin.role]"/>
             <cm:property name="serviceUrl" value="service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-$[karaf.name]"/>
             <cm:property name="daemon" value="true"/>
             <cm:property name="threaded" value="true"/>
@@ -105,8 +104,26 @@
     <!-- JAAS authenticator -->
     <bean id="jaasAuthenticator" class="org.apache.karaf.management.JaasAuthenticator">
         <property name="realm" value="${jmxRealm}"/>
-        <property name="role" value="${jmxRole}"/>
     </bean>
 
+    <!-- Get a reference to the ConfigurationAdmin service -->
+    <reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
+
+    <!-- For role-based security on the JMX API -->
+    <bean id="karafMBeanServerGuard" class="org.apache.karaf.management.KarafMBeanServerGuard" init-method="init">
+        <property name="configAdmin" ref="configAdmin" />
+    </bean>
+
+    <!-- JMX Security MBean -->
+    <bean id="jmxSecurityMBean" class="org.apache.karaf.management.internal.JMXSecurityMBeanImpl">
+        <property name="mbeanServer" ref="mbeanServer"/>
+    </bean>
+
+    <service ref="jmxSecurityMBean" auto-export="interfaces">
+        <service-properties>
+            <entry key="jmx.objectname" value="org.apache.karaf:type=security,area=jmx,name=$[karaf.name]" />
+        </service-properties>
+    </service>
+
 </blueprint>