Log4J & Email

written by Marco Ferretti on November 17, 2011, at 09:10 AM

Among other appenders, Log4J comes with an SMTP appender that is dramatically useful when you need to alert someone of an event; here's two examples :

  • Using unsecured connection
  • Using secure connection, such as SSL or TLS.

Using unsecured connection

In order to use a simple and unsecured smpt server, all you have to do is configure log4j.properties so that it includes something like this

log4j.appender.SENDMAIL = org.apache.log4j.net.SMTPAppender
log4j.appender.SENDMAIL.To = A_USER@SOMEWHERE.SOMETHING
log4j.appender.SENDMAIL.From = system.alert@fermasoft.com
log4j.appender.SENDMAIL.SMTPHost = some.unsecured.smtp
#some servers do not use the default port : change this as you need
log4j.appender.SENDMAIL.SMTPPort = 25
log4j.appender.SENDMAIL.SMTPDebug = true
log4j.appender.SENDMAIL.SMTPPassword=XXXXXXXX
log4j.appender.SENDMAIL.SMTPUsername=XXXXXXXX
# the maximum number of logging events to collect in a cyclic buffer
log4j.appender.SENDMAIL.BufferSize = 1
log4j.appender.SENDMAIL.LocationInfo = true
log4j.appender.SENDMAIL.Subject = "System Error"
log4j.appender.SENDMAIL.layout = org.apache.log4j.PatternLayout
log4j.appender.SENDMAIL.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n

and the job is done

Using Secure Connection

The problem comes when your mailserver uses secure connection as TLS or SSL, then you need to add the following javax.mail.Session properties:

System.setProperty("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
System.setProperty("mail.smtp.socketFactory.port", "465");
System.setProperty("mail.smtp.socketFactory.fallback", "false");

so that the following configuration snippet can actually work :

log4j.appender.SMTP.layout=org.apache.log4j.SimpleLayout
log4j.appender.SMTP=org.apache.log4j.net.SMTPAppender
# the maximum number of logging events to collect in a cyclic buffer
log4j.appender.SMTP.BufferSize=1
log4j.appender.SMTP.From=system.alert@fermasoft.com
log4j.appender.SMTP.LocationInfo=true
log4j.appender.SMTP.SMTPDebug=true
log4j.appender.SMTP.SMTPHost=smtp.gmail.com
log4j.appender.SMTP.SMTPPassword=PASSWORD
log4j.appender.SMTP.SMTPUsername=USER@gmail.com
log4j.appender.SMTP.Subject=System Error
log4j.appender.SMTP.To=A_USER@SOMEWHERE.SOMETHING

Happy logging !

Liferay 5.2.3 javascript injection vulnerability

written by Marco Ferretti on September 27, 2011, at 02:43 PM

According to liferay's Jira LPS-5545 is still open and affects liferay 5.2.3 .

I tested the above vulnerability onto Liferay 6 and it looks like this problem was fixed. I looked at the code and what it does ... and it came out that everything you need to prevent this issue is already there in L5 too.

The short path

simply use unix patch to apply this patch ( Attach:LanguageImpl.java.patch ), recompile and generate portal-impl.jar and live happy.

What it does

The patch checks the language id parameter against a white list of languages (namely _localesMap and _charEncodings ) that are already there; we slightly modify the constructor in order to make sure the maps are filled :

        private LanguageImpl() {
                String[] localesArray = PropsValues.LOCALES;

                _locales = new Locale[localesArray.length];
                _localesSet = new HashSet<Locale>(localesArray.length);
                _localesMap = new HashMap<String, Locale>(localesArray.length);
                _charEncodings = new HashMap<String, String>();

                for (int i = 0; i < localesArray.length; i++) {
                        String languageId = localesArray[i];

                        int pos = languageId.indexOf(StringPool.UNDERLINE);

                        String language = languageId.substring(0, pos);
                        //String country = languageId.substring(pos + 1);

                        Locale locale = LocaleUtil.fromLanguageId(languageId);

                        _charEncodings.put(locale.toString(), StringPool.UTF8);                 // backport of white list of language ids

                        _locales[i] = locale;
                        if (!_localesMap.containsKey(language)) {//backport of white list of language ids
                                _localesMap.put(language, locale);
                        }
                        _localesSet.add(locale);
                        //_localesMap.put(language, locale);//backport of white list of language ids
                        _charEncodings.put(locale.toString(), StringPool.UTF8);

                }
        }

and add the check

if (_localesMap.containsKey(languageId) || _charEncodings.containsKey(languageId)) {// backport of white list of language ids

in

public String getLanguageId(HttpServletRequest request)

just before returning the language id :

        public String getLanguageId(HttpServletRequest request) {
                String languageId = ParamUtil.getString(request, "languageId");

                if (Validator.isNotNull(languageId)) {
                        if (_localesMap.containsKey(languageId) || _charEncodings.containsKey(languageId)) {// backport of white list of language ids
                                return languageId;
                        }
                }

                Locale locale = PortalUtil.getLocale(request);

                return getLanguageId(locale);
        }

Happy patching folks !

Dynamic java.library.path HowTo

(:blogit-skin author pre_text='written by ' post_text=' ':)Marco Ferretti

on August 09, 2011, at 09:00 AM

Sometimes you need to use native libraries in order to accomplish some tasks ( e.g. : statistics ) that, if written in Java, take more time than they should. The "classic" way of loading a native library is to use one of the following Java call

 Runtime.getRuntime().loadLibrary(String s);
 Runtime.getRuntime().load(String s);

 that are exactly equivalent to 

 System.loadLibrary(String s);
 System.load(String s);

The main difference between the two calls is that load(String s) needs an absolute path, while loadLibrary the "core name" of the library that is then resolved by the underlying operating system into a library file. For example, if we wanted to use the library "TestJni" the call

 Runtime.getRuntime().load("TestJni");

would be resolved into looking for the library file

 Windows:
 TestJni.dll
 Unix:
 libTestJni.so

and that file would be looked up in the directories specified in the system variable java.library.path

I prefer loading a library calling the core name because doing so I can create and compile the same native library for as many O.S. as I need to run my software on and load those libraries always in the same way regardless of the platform the software is running onto. The caveats of this method, though, are that of actually finding and loading the library.

There are, in the Java language, three strategies that can be used to achieve this task :

  1. copy the native library into the default O.S. system paths
  2. setting the java.library.path variable at JVM startup
  3. copy the native library in a predefined path within the software and use the System.load call

The main problem with solution 1 is that you can't always suppose that the person installing your software will have the privileges to write in the system library directories; solution 2 consists of firing the Java Vitual Machine with the parameter

 -Djava.library.path=path_to_the_directory_where_your_library_is_sitting

doable, but ugly ( IMHO ) especially if you think that modern S.O. can run a jar file ( if it contains a main(String[] args) method by double clicking it.

Solution number 3 implies that java.library.path is modified before you try to load the native library; apart form that, it permits to install/copy all the necessary libraries and jars your application depends on in, my personal flavor, ./lib without having to care where that directory will actually be copied by the installer .

In order to modify java.library.path you need to resolve the absolute path of the "./lib" directory :

 public String getRunningPath() {
     Logger.getLogger(getClass()).debug("determining running path");
     URL url = Utils.class.getProtectionDomain().getCodeSource().getLocation();
     File file;
     try {
         file = new File(url.toURI().getPath());
     } catch (URISyntaxException e) {
         file = new File(url.getPath());
     }
     Logger.getLogger(Utils.class).debug("resolved running path : " + file.getAbsolutePath());
     if (file.isDirectory()) {
         return file.getAbsolutePath();
     } else {
         return getPath(file);
     }
 }

 public String getPath(File file) {
     Logger.getLogger(Utils.class).debug("resolving path for " + file.getName());
     if (file.isDirectory()) {
         Logger.getLogger(Utils.class).debug(file.getName() + " is a directory so the running path is "+ file.getAbsolutePath() + File.separator);
         return file.getAbsolutePath() + File.separator;
     }
     String path = file.getAbsolutePath();
     path = path.substring(0, path.lastIndexOf(file.getName()));
     Logger.getLogger(Utils.class).debug(
     file.getName() + " is a file so the running path is " + path);
     return path;
 }
 

The method getRunningPath returns the path where the Java Virtual Machine was fired from. If we kept the example nomenclature, out library directory will be

 String libraryPath = getRunningPath() + File.separator + "lib";

The method that changes the system variable java.library.path is

        public void addDir(String s) throws IOException {
                try {
                        // This enables the java.library.path to be modified at runtime
                        // From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176
                        //
                        Field field = ClassLoader.class.getDeclaredField("usr_paths");
                        field.setAccessible(true);
                        String[] paths = (String[])field.get(null);
                        for (int i = 0; i < paths.length; i++) {
                                if (s.equals(paths[i])) {
                                        return;
                                }
                        }
                        String[] tmp = new String[paths.length+1];
                        System.arraycopy(paths,0,tmp,0,paths.length);
                        tmp[paths.length] = s;
                        field.set(null,tmp);
                        System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s);
                } catch (IllegalAccessException e) {
                        throw new IOException("Failed to get permissions to set library path");
                } catch (NoSuchFieldException e) {
                        throw new IOException("Failed to get field handle to set library path");
                }
        }
 

Thus the main call :

 addDir(getRunningPath() + File.separator + "lib") ;

this way the call

 System.loadLibrary(LIBRARY_CORE_NAME);

will look up your library in ./lib too

Struts2 Convention plugin : e' quasi magia

written by marco ferretti on August 05, 2011, at 02:48 PM

Oggi mi era una giornata fiacca. Mi sono detto : " Guardiamo un po' di cose che mi ero lasciato da fare" e l'occhio mi e' cascato su Struts2. Intendiamoci, non che non abbia mai visto come funziona questo framwork ( chiunque lavori con Java in ambito Web prima o poi ha a che fare con Struts ), semplicemente non ero mai andato + che tanto a fondo nella versione 2 di Struts.

Ho cominciato a guardare un po' di documentazione ( l'indice ) e l'occhio mi e' caduto su Convention plugin ... e ne sono entusiasta !

Ecco un piccolo diario delle mie prove ...

Per prima cosa, mi sono creato un progetto web dinamico con Eclipse. Poi ho preso tutte le librerie dall'applicazione di esempio "struts2-rest-showcase" ... tanto per non sbagliare o avere dipendenze non risolte ( prima o poi dovro' passare a Maven, ma che ci volete fare ... sono affezionato ad Ant ! ) . Ho quindi velocemente letto la prima parte della pagina linkata prima ( Convention plugin ) e poi ho cominciato a smanettare un po' con i files delle risorse e ... senza una riga di configurazione ( apparte il caricamento del filtro per struts ) mi sono ritrovato per le mani una pagina jsp che ha associato un bean e un file di risorse che risponde in maniera dinamica !!!

Ecco il gioco spiegato in due parole : Per default Convention cerca le pagine in WEB-INF/content, quindi se create una pagina pippo.jsp qui' dentro viene automaticamente creata una azione pippo che risponde sulla root della vostra applicazione ; inoltre, il plugin cerca tutto quello che implementa com.opensymphony.xwork2.Action e lo trasforma in una azione ... o quasi . Tutto quello che si trova all'interno di <un nome package>.action o <un nome package>.actions o <un nome package>.struts diventa un azione e viene mappato a partire dal piu' "anziano" parente. Facciamo un esempio :

com.pippo.action.PippoAction viene mappato in / com.pippo.action.pippo.Paperino ( che implementa com.opensymphony.xwork2.Action ) viene mappato in /pippo/ com.pippo.struts.pippo.paperino.QuackQuackAction viene mappato in /pippo/paperino

e viene fatto senza bisogno che scriviate una riga di configurazione o mappatura !

In piu' il nome dell'azione viene interpretato secondo il camel case e la classe rispondera' a com.pippo.action.PippoAction == /pippo com.pippo.action.pippo.Paperino == /pippo/paperino com.pippo.struts.pippo.paperino.QuackQuackAction == /pippo/paperino/quack-quack

La cosa ancora piu' intrigante e' che, sempre gratis, se create le relative pagine jsp in /WEB-INF/content queste vengono associate alla view dell'azione e automaticamente bindati ai relativi JavaBean !!! E quindi :

com.pippo.action.PippoAction == /pippo == /WEB-INF/content/pippo.jsp com.pippo.action.pippo.Paperino == /pippo/paperino == /WEB-INF/content/pippo/paperino.jsp com.pippo.struts.pippo.paperino.QuackQuackAction == /pippo/paperino/quack-quack == /WEB-INF/content/pippo/paperino/quack-quack.jsp

Ed eccoci all'esempio :

HelloAction.java

 package com.fermasoft.prove.convention.action;

 import java.text.SimpleDateFormat;
 import java.util.Date;

 import com.opensymphony.xwork2.ActionSupport;

 public class HelloAction extends ActionSupport {

 	public String execute(){
 		return SUCCESS;
 	}

 	public String getName(){
 		return "Goofy";
 	}

 	public String getTime(){
 		SimpleDateFormat formatter = new SimpleDateFormat("HH.mm");
 		return formatter.format(new Date(System.currentTimeMillis()));
 	}
 } 

HelloAction.properties

greeting=Hello ${name} ! It's ${time} o' clock !
testing.param=  ${name} you passed me {0}
value=I am string coming from the class resources

package.properties

package.value=I am a string coming from the package wide resources
value=I am another string coming from the package wide resources

hello.jsp

 <%@ taglib prefix="s" uri="/struts-tags"%>
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>hello convention !</title>
 </head>
 <body>
 <p>Testing the Convention plugin</p>

here's a greeting that takes parameters from a bean I didn't explicitly declare in this page :


 <div style="font-style: italic;">
 <s:text name="greeting"/>
 <br />
 </div>

here's a parametrized text that comes from a resource bundle I didn't declare either ; the first part in the result of a call the the same bean as above, the second part is a parameter I directly passed from the page :


 <div style="font-style: italic;">
 <s:text name="testing.param">
 	<s:param value="'aValue'" />
 </s:text>
 <br />
 </div>

here's a text that comes from a package wide bundle :

 <div style="font-style: italic;"><s:property value="getText('package.value')" /></div> <br />
 here's a text that comes from a Class bundle that overrides the package bundle :  
 <div style="font-style: italic;"><s:property value="getText('value')" /> </div><br />


 </body>
 </html>

web.xml

 <?xml version="1.0" encoding="UTF-8"?>
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
 	<display-name>sanity</display-name>
 	<filter>
 		<filter-name>struts2</filter-name>
 		<filter-class>
 			org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
 		<init-param>
 			<param-name>struts.devMode</param-name>
 			<param-value>true</param-value>
 		</init-param>

 	</filter>
 	<filter-mapping>
 		<filter-name>struts2</filter-name>
 		<url-pattern>/*</url-pattern>
 	</filter-mapping>

 	<welcome-file-list>
 		<welcome-file>index.jsp</welcome-file>
 	</welcome-file-list>
 </web-app>