Security in JSR-160 remoting is an all-or-nothing option. Either all or none of your MBeans are accessible (except when your application server uses a SecurityManager, but that is not often the case). Jolokia, on the other hand, allows for fine grained security defined in an XML security policy file. It allows for access restrictions on MBean names (or patterns), attributes, operations, source IP address (or a subnet) and type of Jolokia operation.
Access to MBean and to the Jolokia agents in general can be restricted with an XML policy file. This policy can be configured for various parameters and is divided into several sections.
Overall access can be granted based on the IP address of an
HTTP client. These restrictions are
specified within a <remote>
section,
which contains one or more <host>
elements. The source can be given either as an IP address,
a host name, or a netmask given in
CIDR format
(e.g. "10.0.0.0/16" for all clients coming from the 10.0
network). The following allows access from localhost and all
clients whose IP addresses start with "10.0". For all other
IP addresses access is denied.
<remote> <host>localhost</host> <host>10.0.0.0/16</host> </remote>
This section specifies the Jolokia commands for which access
is generally granted. For each command in the list, access can
be further restricted within the
<deny>
part and each command
missing in the list, which is forbidden globally, can be
selectively enabled for certain MBeans in the
<allow>
section. If the
<commands>
section is missing
completely, access to all commands is allowed.
All Jolokia commands described in Chapter 6, Jolokia Protocol can be used in this section:
In the following example, access is granted to the
read
, list
,
search
and version
command, but
not to write
and exec
operations.
<commands> <command>read</command> <command>list</command> <command>version</command> <command>search</command> </commands>
Within an <allow>
section, access
to MBeans can be granted regardless of the
operations specified in the
<commands>
section. The reverse is
true for the <deny>
section: It
rejects access to the MBeans specified here. Both sections
contain one or more <mbean>
elements which have a format like:
<mbean> <name>java.lang:type=Memory</name> <attribute>*Memory*</attribute> <attribute mode="read">Verbose</attribute> <operation>gc</operation> </mbean>
Within the <name>
section the name
of the MBean is specified. This can bei either a complete
ObjectName or a MBean pattern containing wildcards. The
value given here must conform to the JMX specification for a
valid ObjectName
. On this MBean (or
MBeans if name
is a pattern),
attributes are specified within one or more
<attribute>
elements and operations
within one or more <operation>
elements. The content can also be a pattern, which uses a wildcard
*
. e.g. <attribute>*</attribute>
specifies all attributes on the given MBean. If for an
<attribute>
element the XML
attribute mode="read"
is given, then this
attribute can be accessed only read-only.
Finally, access can be restricted based on the HTTP method
with which an Jolokia request was received with the
<http>
element. Method allowed
(post
or get
) are
specified with an <method>
inner
element. The following example restricts the access to POST
requests only:
<http> <method>post</method> </http>
It the <http>
section is missing
completely, any HTTP method can be used.
Jolokia (since version 1.0.3) supports the W3C specification for Cross-Origin Resource Sharing (also known as "CORS") which allows browser to access resources which are located on a different server than the calling script is loaded from. This specification provides a controlled way to come around the same origin policy. Most contemporary browsers support CORS.
By default Jolokia allows cross origin access from any
host. This can be limited to certain hosts by using
<allow-origin>
sections within a
<cors>
sections. This tags can
contain the origin URL provided by browsers with the
Origin:
header literally or a
wildcard specification with *
.
<cors> <!-- Allow cross origin access from www.jolokia.org ... --> <allow-origin>http://www.jolokia.org</allow-origin> <!-- ... and all servers from jmx4perl.org with any protocol -> <allow-origin>*://*.jmx4perl.org</allow-origin> </cors>
The following complete example applies various access restrictions:
read
and
list
requests are allowed.
exec
request is allowed for
triggering garbage collection.
<?xml version="1.0" encoding="utf-8"?> <restrict> <remote> <host>127.0.0.1</host> </remote> <http> <method>post</method> </http> <commands> <command>read</command> <command>list</command> </commands> <allow> <mbean> <name>java.lang:type=Memory</name> <operation>gc</operation> </mbean> </allow> <deny> <mbean> <name>com.mchange.v2.c3p0:type=PooledDataSource,*</name> <attribute>properties</attribute> </mbean> </deny> </restrict>
But how do the agents lookup the policy file ? By default,
the agents will lookup for a policy file top-level in the
classpath under the name
jolokia-access.html
. Hence for the war
agent, the policy file must be packaged within the war at
WEB-INF/classes/jolokia-access.xml
, for
all other agents at
/jolokia-access.xml
. The location can
be overwritten with the configuration parameter
policyLocation
, which has to be set
differently depending on the agent type. Please refer to
Chapter 3, Agents for more details. The value of this
init parameter can be any URL which can loaded by the JVM. A
special case is an URL with the scheme
classpath:
which results in a lookup of
the policy file within the classpath. As stated above, the
default value of this parameter is
classpath:/jolokia-access.xml
. If a
non-classpath URL is provided with this parameter, and the
target policy file could not be found then access is
completely denied. If a classpath lookup fails then access
is globally granted and a warning is given on standard
output.
In order to provide fine grained security, Jolokia using the
abstract concept of an Restrictor. It is
represented by the Java interface
org.jolokia.restrictor.Restrictor
and
comes with several implementations. The most prominent one is
the PolicyRestrictor
which is described
in Section 4.1, “Policy based security”. This is also the
restrictor which is active by default. For special needs, it is
possible to provide a custom implementation of this
interface for the WAR and OSGi agents. It is recommended to
subclass either
org.jolokia.restrictor.AllowAllRestrictor
or
org.jolokia.restrictor.DenyAllRestrictor
.
For the WAR agent (Section 3.1, “JEE Agent (WAR)”), a subclass
of org.jolokia.http.AgentServlet
should
be created which overrides the
createRestrictor()
public class RestrictedAgentServlet extends AgentServlet { @Override protected Restrictor createRestrictor(String policyLocation) { return new MyOwnRestrictor(); } }
policyLocation
is a URL pointing to the
policy file, which is either the default value
classpath:/jolokia-access.xml
or the
value specified with the init parameter
policyLocation
. This servlet can then be
easily configured in a custom web.xml
the same way as the Jolokia agent.
For programmatic usage there is an even simpler way:
AgentServlet
provides an constructor
which takes an restrictor as argument, so no sublcassing is
required in this case.
For an OSGi agent (Section 3.2, “OSGi Agents”),
org.jolokia.osgi.servlet.JolokiaServlet
is the proper extension point. It can be subclassed the same
way as shown above and allows a restrictor implementation as
constructor parameter, too. In contrast to
AgentServlet
this class is also OSGi
exported and can be referenced from other
bundles. Additionally, the OSGi agent can also pick up a
restrictor as an OSGi service. See Section 3.2, “OSGi Agents” for details.