| jmx4perl documentation | Contained in the jmx4perl distribution. |
JMX::Jmx4Perl::Agent::Jolokia::WebXmlHandler - Handler for web.xml transformation
This module is repsonsible for various manipulations on a web.xml descriptor as found in JEE WAR archives. It uses XML::LibXML for the dirty work, and XML::Tidy to clean up after the manipulation. The later module is optional, but recommended.
Creates a new handler. The following arguments can be used:
"logger" Logger to use
Add a security constraint to the given web.xml. This triggers on the realm "Jolokia" on the loging-config and the URL-Pattern "/*" for the security mapping. Any previous sections are removed and replaced.
$role is the role to insert.
This method returns the updated web.xml as a string.
Remove login-config with Realm "Jolokia" and security constraint to "/*" along with the associated role definit. Return the updated web.xml as string.
Adds a JSR-160 proxy declaration which is contained as init-param of the servlet definition ("dispatcherClasses"). If the init-param is missing, a new is created otherwise an existing is updated. Does nothing, if the init-param "dispatcherClasses" already contains the JSR 160 dispacher.
Returns the updated web.xml as string.
Removes a JSR-160 proxy declaration which is contained as init-param of the servlet definition ("dispatcherClasses"). Does nothing, if the init-param "dispatcherClasses" already doese not contain the JSR 160 dispacher.
Returns the updated web.xml as string.
Find a single element with a given XQuery query. Croaks if more than one
element is found. Returns either undef (nothing found) or the matched
node's text content.
Checks, whether authentication is switched on.
Checks, whether a JSR-160 proxy is configured.
This file is part of jmx4perl. Jmx4perl is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by The Free Software Foundation, either version 2 of the License, or (at your option) any later version.
jmx4perl is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with jmx4perl. If not, see <http://www.gnu.org/licenses/>.
A commercial license is available as well. Please contact roland@cpan.org for further details.
roland@cpan.org
| jmx4perl documentation | Contained in the jmx4perl distribution. |
#!/usr/bin/perl package JMX::Jmx4Perl::Agent::Jolokia::WebXmlHandler;
use Data::Dumper; use vars qw($HAS_LIBXML $HAS_XML_TIDY); use strict; # Trigger for <login-config> my $REALM = "Jolokia"; # Class used as proxy dispatcher my $JSR_160_PROXY_CLASS = "org.jolokia.jsr160.Jsr160RequestDispatcher"; BEGIN { $HAS_LIBXML = eval "require XML::LibXML; use XML::LibXML::XPathContext; 1"; $HAS_XML_TIDY = eval "require XML::Tidy; 1"; }
sub new { my $class = shift; my %args = @_; my $self = {logger => $args{logger}}; bless $self,(ref($class) || $class); $self->_fatal("No XML::LibXML found. Please install it to allow changes and queries on web.xml") unless $HAS_LIBXML; return $self; }
sub add_security { my $self = shift; my $webxml = shift; my $args = shift; my $doc = XML::LibXML->load_xml(string => $webxml); my $parent = $doc->getDocumentElement; $self->_remove_security_elements($doc); $self->_create_login_config($doc,$parent); $self->_create_security_constraint($doc,$parent,$args->{role}); $self->_create_security_role($doc,$parent,$args->{role}); $self->_info("Added security mapping for role ","[em]",$args->{role},"[/em]"); return $self->_cleanup_doc($doc); }
sub remove_security { my $self = shift; my $webxml = shift; my $doc = XML::LibXML->load_xml(string => $webxml); $self->_remove_security_elements($doc); $self->_info("Removed security mapping"); return $self->_cleanup_doc($doc); }
sub add_jsr160_proxy { my $self = shift; my $webxml = shift; my $doc = XML::LibXML->load_xml(string => $webxml); my @init_params = $self->_init_params($doc,"dispatcherClasses"); if (!@init_params) { $self->_add_jsr160_proxy($doc); $self->_info("Added JSR-160 proxy"); } elsif (@init_params == 1) { my $param = $init_params[0]; my ($value,$classes) = $self->_extract_dispatcher_classes($init_params[0]); unless (grep { $_ eq $JSR_160_PROXY_CLASS } @$classes) { $self->_update_text($value,join(",",@$classes,$JSR_160_PROXY_CLASS)); $self->_info("Added JSR-160 proxy"); } else { $self->_info("JSR-160 proxy already active"); return undef; } } else { # Error $self->_fatal("More than one init-param 'dispatcherClasses' found"); } return $self->_cleanup_doc($doc); }
sub remove_jsr160_proxy { my $self = shift; my $webxml = shift; my $doc = XML::LibXML->load_xml(string => $webxml); my @init_params = $self->_init_params($doc,"dispatcherClasses"); if (!@init_params) { $self->info("No JSR-160 proxy active"); return undef; } elsif (@init_params == 1) { my ($value,$classes) = $self->_extract_dispatcher_classes($init_params[0]); if (grep { $_ eq $JSR_160_PROXY_CLASS } @$classes) { $self->_update_text($value,join(",",grep { $_ ne $JSR_160_PROXY_CLASS } @$classes)); $self->_info("Removed JSR-160 proxy"); } else { $self->_info("No JSR-160 proxy active"); return undef; } } else { $self->_fatal("More than one init-param 'dispatcherClasses' found"); } return $self->_cleanup_doc($doc); }
sub find { my $self = shift; my $webxml = shift; my $query = shift; my $doc = XML::LibXML->load_xml(string => $webxml); my @nodes = $self->_find_nodes($doc,$query); $self->_fatal("More than one element found matching $query") if @nodes > 1; return @nodes == 0 ? undef : $nodes[0]->textContent; }
sub has_authentication { my $self = shift; my $webxml = shift; $self->find ($webxml, "//j2ee:security-constraint[j2ee:web-resource-collection/j2ee:url-pattern='/*']/j2ee:auth-constraint/j2ee:role-name"); }
sub has_jsr160_proxy { my $self = shift; my $webxml = shift; my $doc = XML::LibXML->load_xml(string => $webxml); my @init_params = $self->_init_params($doc,"dispatcherClasses"); if (@init_params > 1) { $self->_fatal("More than one dispatcherClasses init-param found"); } elsif (@init_params == 1) { my $param = $init_params[0]; my ($value,$classes) = $self->_extract_dispatcher_classes($init_params[0]); return grep { $_ eq $JSR_160_PROXY_CLASS } @$classes; } else { return 0; } } # =============================================================================== sub _remove_security_elements { my $self = shift; my $doc = shift; my $role = shift; $self->_remove_login_config($doc); my $role = $self->_remove_security_constraint($doc); $self->_remove_security_role($doc,$role); } sub _create_login_config { my $self = shift; my $doc = shift; my $parent = shift; my $l = _e($doc,$parent,"login-config"); _e($doc,$l,"auth-method","BASIC"); _e($doc,$l,"realm-name",$REALM); } sub _create_security_constraint { my $self = shift; my $doc = shift; my $parent = shift; my $role = shift; my $s = _e($doc,$parent,"security-constraint"); my $w = _e($doc,$s,"web-resource-collection"); _e($doc,$w,"web-resource-name","Jolokia-Agent Access"); _e($doc,$w,"url-pattern","/*"); my $a = _e($doc,$s,"auth-constraint"); _e($doc,$a,"role-name",$role); } sub _create_security_role { my $self = shift; my $doc = shift; my $parent = shift; my $role = shift; my $s = _e($doc,$parent,"security-role"); _e($doc,$s,"role-name",$role); } sub _remove_security_constraint { my $self = shift; my $doc = shift; my @s = $doc->getElementsByTagName("security-constraint"); for my $s (@s) { my @r = $s->getElementsByTagName("role-name"); my $role; for my $r (@r) { $role = $r->textContent; } my @u = $s->getElementsByTagName("url-pattern"); for my $u (@u) { if ($u->textContent eq "/*") { $s->parentNode->removeChild($s); return $role; } } } } sub _remove_login_config { my $self = shift; my $doc = shift; my @l = $doc->getElementsByTagName("realm-name"); for my $l (@l) { if ($l->textContent eq $REALM) { my $toRemove = $l->parentNode; $toRemove->parentNode->removeChild($toRemove); return; } } } sub _remove_security_role { my $self = shift; my $doc = shift; my $role = shift; my @s = $doc->getElementsByTagName("security-role"); for my $s (@s) { my @r = $s->getElementsByTagName("role-name"); for my $r (@r) { if ($r->textContent eq $role) { $s->parentNode->removeChild($s); return; } } } } sub _init_params { my $self = shift; my $doc = shift; my $param_name = shift; return $self->_find_nodes ($doc, "/j2ee:web-app/j2ee:servlet[j2ee:servlet-name='jolokia-agent']/j2ee:init-param[j2ee:param-name='$param_name']"); } sub _extract_dispatcher_classes { my $self = shift; my $param = shift; my @values = $self->_find_nodes($param,"j2ee:param-value"); $self->_fatal("No or more than one param-value found") if (!@values || @values > 1); my $value = $values[0]; my $content = $value->textContent(); my @classes = split /\s*,\s*/,$content; return ($value,\@classes); } sub _update_text { my $self = shift; my $el = shift; my $value = shift; my $parent = $el->parentNode; $parent->removeChild($el); $parent->appendTextChild($el->nodeName,$value); } sub _add_jsr160_proxy { my $self = shift; my $doc = shift; my @init_params = $self->_find_nodes ($doc, "/j2ee:web-app/j2ee:servlet[j2ee:servlet-name='jolokia-agent']/j2ee:init-param"); my $first = $init_params[0] || $self->_fatal("No init-params found"); my $new_init = $doc->createElement("init-param"); _e($doc,$new_init,"param-name","dispatcherClasses"); _e($doc,$new_init,"param-value",$JSR_160_PROXY_CLASS); $first->parentNode->insertBefore($new_init,$first); } sub _find_nodes { my $self = shift; my $doc = shift; my $query = shift; my $xpc = XML::LibXML::XPathContext->new; $xpc->registerNs('j2ee', 'http://java.sun.com/xml/ns/j2ee'); return $xpc->findnodes($query,$doc); } sub _e { my $doc = shift; my $parent = shift; my $e = $doc->createElement(shift); my $c = shift; if ($c) { $e->appendChild($doc->createTextNode($c)); } $parent->appendChild($e); return $e; } sub _cleanup_doc { my $self = shift; my $doc = shift; if ($HAS_XML_TIDY) { my $ret = new XML::Tidy(xml => $doc->toString())->tidy->toString(); #print $ret; return $ret; } else { return $doc->toString(1); } } sub _fatal { my $self = shift; $self->{logger}->error(@_); die "\n"; } sub _info { my $self = shift; $self->{logger}->info(@_); }
1;