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>