Sunday, July 20, 2014

Monitor SVN commit using Perl script.

Usually it should be accomplished by configuring svn hooks, however in some cases when we do not have svn server access we are unable to notice if developers are committing as per SCM guideline.  Rather monitoring manually it’s better to automate the process which can check all commits in a day and notify the user/administrator if the commit in improper.

That is the purpose of the script. We use the same user ID and corresponding credential that is being used by Jenkins. To notify user or administrator the script will use SMTP. At the end the script will be scheduled as a user’s cron job at 22:30 PM every day.

Let’s have a look into the script…………

#!/usr/bin/perl

use strict;
use warnings;
use Net::SMTP;
use XML::Simple;
my $release = shift(@ARGV);
my $dt = `date +%Y-%m-%d`;
my $base = 'https://your.host.com/base/url';
chomp($dt);
my %hash;
my %nuhash;
my %users;
my $details;
my $xml = new XML::Simple;
my $contain = $xml->XMLin("/path/to/jenkins-home/hudson.scm.SubversionSCM.xml");
my $user = $contain->{credentials}->{'entry'}->[0]->{'hudson.scm.SubversionSCM_\
                                                      -DescriptorImpl_-PasswordCredential'}->{'userName'} . "\n";
my $auth = $contain->{credentials}->{'entry'}->[0]->{'hudson.scm.SubversionSCM_\
                                                      -DescriptorImpl_-PasswordCredential'}->{'password'};
my $encode = `echo $auth | python -m base64 -d`;
chomp($user);
chomp($encode);
if ($release =~ /REL_VER_/){
foreach my $repo ('app1', 'app2', 'app3') {
my $repo = "$repo" . "/branches/" . "$release";
my $URL = "$base" . "$repo\n";
my @to = ('your_mail_id@domain.com');
my $LOG = `svn --username=$user  --password=$encode log -r{$dt}:HEAD $URL`;

open LOG,'-|',"svn log -r{$dt}:HEAD $URL" or die $@;
my $i = 0;
while (&ltlog&gt) {
        next if /^----/;
        next if /^$/;
if (/^r/) {
  my($rev, $user) = split /\|/, $_;
                $hash{$rev} = '';
                $users{$rev} = $user;
                } else {
                my @keys = (keys %hash);
                my $key = $keys[$i];
                delete $hash{$key};
                $nuhash{$key} .= $_;
                }
        }

close(LOG);

foreach my $key (keys %hash) {
        if ($hash{$key} =~ /^$/){
        $nuhash{$key} .= '';
          }
        }

foreach my $tab (keys %nuhash) {
                if ($nuhash{$tab} =~ /^$/ || $nuhash{$tab} =~ /^\s+$/ ) {
                $details = `svn log -r$tab $URL`;
                &_send_mail('your_mail_id@domain.com',"$tab :" . "$users{$tab} \
                  => " . " NULL" , @to);
                        }
                }
$i++;
        }
}
#
# Check hash
#
#foreach my $k (keys %nuhash) {
#print "$k" . " => " . "$nuhash{$k}\n";
#}
#
# Send mail to the user
#
sub _send_mail {
my ($from, $sub, @to) = @_;

  my $smtp = Net::SMTP->new('YOUR.SMTP.SERVER');

  $smtp->mail($from);
  $smtp->to(@to);

  $smtp->data();
  $smtp->datasend("To: @to\n");
  $smtp->datasend("Subject: $sub\n");
  $smtp->datasend("\n");
  $smtp->datasend("$details\n");
  $smtp->dataend();

  $smtp->quit;
}

Saturday, January 4, 2014

Secure Tomcat manager for production use

Tomcat manager is very useful for production environment when multiple applications are deployed in a single server. It helps to manage applications without restarting the server.  However, accessing HTML interface of manager application remotely is not a wise decision.
Therefore preventing remote access of tomcat manager using web browser and allowing access of tool-friendly plain text interface instead would be the best choice. This article illustrates a simple solution that has been designed to secure tomcat server for production use.

Tomcat provides a number of Filters to secure the server itself or an individual application. Please check here for more details. Our goal is to prevent web browser to access the Manager application from outside of local host. At the same time we must allow commands as a part of the request URI to get responses in the form of simple text that can be easily parsed and processed. Therefore filter should have logic to allow access based on HTTP request header. A very simple logic could be filtering Remote Address and embedded request properties available in HTTP request header as below.

private String checkHeader = "MyComp";
.
.
.
if (headerValue != null) {
   /*
    * Either connect from 127.0.0.1 or use "tomcatmanager" command
    */
   if (headerValue.equals(checkHeader) || remoteIp.equals("127.0.0.1")) {
    denyStatus = true;
   }
  }

Second part of this solution is a java utility which performs two basic functions. First it encrypts plain text password available in properties file and then decrypt the same again to connect tool-friendly text URI.  Properties file contain plain text user and password as per tomcat-user.xml. Whenever tomcat credential gets change, properties file should get modified accordingly. Another function is to setRequestProperty to prepare URLConnection.

urlConnection.setRequestProperty("referer", "MyComp");

Users with the manager-gui role should not be granted the manager-script or manager-jmx roles. Therefore, to use this client utility, configure tomcat-users.xml accordingly.

Demonstration:
Consider two systems A and B. System A is your Tomcat server where manager application is deployed and system B is your Desktop client. If you try to access HTML interface of tomcat manager from your desktop, it will redirect you to an error page, however if you run the utility it will show you all details in readable text format as below.
  
How it works?
As a client, when you hit web browser to access GUI interface of tomcat manager, filter checks Remote Address and redirect your request. However the filter will allow access of GUI interface from system A as, in such a case, request goes from localhost.

When we run the utility from system B, filter checks and found hardcoded request properties, therefore filter refrain Remote Address checking and allow access of plain text URI.