February 10, 2015

CSRF and Character Encoding Filter in Tomcat 7

In Tomcat 7 there are several interesting filter, which are ready to be used:

There are more out-of-the-box Filter, see FilterBase.

Also check out the Combined Realm org.apache.catalina.realm.LockOutRealm, which can be used to mitigate user password brute force attacks.

February 9, 2015

Enable JMX Remote in Tomcat 7

Introduction

Remote monitoring is essential in a IT infrastructure. Sadly is the standard Java JMX based on port range. Here I will show you to overcome that in Tomcat 7.

Installation

Download catalina-jmx-remote.jar to $CATALINA_HOME/lib

Configuration

$ vi $CATALINA_HOME/conf/server.xml

<Server port="8005" shutdown="SHUTDOWN">
...
  <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
          rmiRegistryPortPlatform="10001" rmiServerPortPlatform="10002" />
...
</Server>
# vi $CATALINA_HOME/bin/setenv.sh

export JAVA_OPTS="-Dcom.sun.management.jmxremote=true \
                  -Dcom.sun.management.jmxremote.ssl=false \
                  -Dcom.sun.management.jmxremote.authenticate=false"

Test

Start jvisualvm and connect.

Reference

http://tomcat.apache.org/tomcat-7.0-doc/config/listeners.html

http://blog.markshead.com/1129/connecting-visual-vm-to-tomcat-7/

https://www.zabbix.com/documentation/2.0/manual/config/items/itemtypes/jmx_monitoring

http://docs.oracle.com/javase/1.5.0/docs/guide/management/agent.html

Use Log4J in Tomcat 7

Introduction

Tomcat uses default Java SDK Logging, which is in mine opinion, generates default log files that are hard to read and it is also quite silly to reinvent the wheel, because there is already a de-facto standard logging framework - log4j.

So lets replace the default logging framework with log4j in Tomcat.

Configuration

  1. Create and configure Log4J in $CATALINA_HOME/lib/log4j.properties.
  2. Download Log4J 1.2 to $CATALINA_HOME/lib.
  3. Download tomcat-juli-adapters.jar to $CATALINA_HOME/lib.
  4. Download tomcat-juli.jar and RELPACE existing $CATALINA_HOME/bin/tomcat-juli.jar.
  5. Delete $CATALINA_HOME/conf/logging.properties.

$CATALINA_HOME/lib/log4j.properties

I do not find having separate Tomcat log convenient so I let all loggers write to the same file.

log4j.rootLogger = INFO, CATALINA

# Define all the appenders
log4j.appender.CATALINA = org.apache.log4j.DailyRollingFileAppender
log4j.appender.CATALINA.File = ${catalina.base}/logs/catalina.out
log4j.appender.CATALINA.Append = true
log4j.appender.CATALINA.Encoding = UTF-8
log4j.appender.CATALINA.DatePattern = '.'yyyy-MM-dd
log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c:%L - %m%n

log4j.appender.LOCALHOST = org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOCALHOST.File = ${catalina.base}/logs/catalina.out
log4j.appender.LOCALHOST.Append = true
log4j.appender.LOCALHOST.Encoding = UTF-8
log4j.appender.LOCALHOST.DatePattern = '.'yyyy-MM-dd
log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout
log4j.appender.LOCALHOST.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c:%L - %m%n

log4j.appender.MANAGER = org.apache.log4j.DailyRollingFileAppender
log4j.appender.MANAGER.File = ${catalina.base}/logs/catalina.out
log4j.appender.MANAGER.Append = true
log4j.appender.MANAGER.Encoding = UTF-8
log4j.appender.MANAGER.DatePattern = '.'yyyy-MM-dd
log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.MANAGER.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c:%L - %m%n

log4j.appender.HOST-MANAGER = org.apache.log4j.DailyRollingFileAppender
log4j.appender.HOST-MANAGER.File = ${catalina.base}/logs/catalina.out
log4j.appender.HOST-MANAGER.Append = true
log4j.appender.HOST-MANAGER.Encoding = UTF-8
log4j.appender.HOST-MANAGER.DatePattern = '.'yyyy-MM-dd
log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c:%L - %m%n

log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Encoding = UTF-8
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c:%L - %m%n

# Configure which loggers log to which appenders
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost] = INFO, LOCALHOST
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager] = INFO, MANAGER
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager] = INFO, HOST-MANAGER

log4j.logger.org.apache.catalina.realm = TRACE

LDAP Authentication in Tomcat 7

Introduction Tomcat Configuration

Before starting we need to understand the Tomcat configuration (Context) hierarchy. Tomcat configuration can be placed in three places.

    - In $CATALINA_BASE/conf/server.xml.

    - In application /META-INF/context.xml.
    
    - In $CATALINA_BASE/conf/[enginename]/[hostname]/[appname].xml. The default 
    enginename is Catalina. The default hostname is localhost. Which resolves 
    above path to $CATALINA_BASE/conf/Catalina/localhost/[appname].xml.

    [http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Defining_a_context]

The recommended alternative is the last, externally the application, but not intrusive the Tomcat server.

This seperation makes also automated configuration more easily:

  1. One package with standardised Tomcat configuration.
  2. And another package for each application and their seperated configuration.

Next step is to do the actual Authentication configuration which is done by a Realm component.

    "A Catalina container (Engine, Host, or Context) may contain no more than ONE Realm element" 

    [http://tomcat.apache.org/tomcat-7.0-doc/config/realm.html#Introduction]

So a Realm is kind of like a singletone, but it also have scoope, depending where we place it.

    - Inside an <Engine> element - This Realm will be shared across ALL web 
    applications on ALL virtual hosts, UNLESS it is overridden by a Realm element 
    nested inside a subordinate <Host> or <Context> element.
    
    - Inside a <Host> element - This Realm will be shared across ALL web 
    applications for THIS virtual host, UNLESS it is overridden by a Realm element 
    nested inside a subordinate <Context> element.
    
    - Inside a <Context> element - This Realm will be used ONLY for THIS web application.

    [http://tomcat.apache.org/tomcat-7.0-doc/realm-howto.html#Configuring_a_Realm]

Configuration

Tomcat comes with several authentication modules (Realm) out of the boxes. Here we will use the LDAP authentication module org.apache.catalina.realm.JNDIRealm.

JNDI Directory Realm - org.apache.catalina.realm.JNDIRealm

JNDIRealm

$ vi $CATALINA_BASE/conf/Catalina/localhost/example-ldap.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Realm className="org.apache.catalina.realm.JNDIRealm" 
        connectionURL="ldap://ldap.magnuskkarlsson.com:389"
        userPattern="uid={0},ou=People,dc=magnuskkarlsson,dc=com" 
        roleBase="ou=Group,dc=magnuskkarlsson,dc=com"
        roleName="cn" roleSearch="(memberUid={1})" />
</Context>

users.ldif

dn: uid=magkar,ou=People,dc=magnuskkarlsson,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
objectClass: top
uid: magkar
givenName: Magnus
initials: K
sn: Karlsson
cn: Magnus K Karlsson
mail: magnus.k.karlsson@msc.se
uidNumber: 500
gidNumber: 500
homeDirectory: /home/student
userPassword: {crypt}$6$TgMwYtfv6Z0C8Peo$H7p8XjUYuBIspHgTmbo2KKSusssqFuBJFi58uRIcFVsObQJr72RHmBEq9Qz8JcBuA0tCbKvmDawxbQzz112/y0
shadowLastChange: 16467
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash

dn: cn=magkar,ou=Group,dc=magnuskkarlsson,dc=com
objectClass: top
objectClass: posixGroup
cn: magkar
userPassword: {crypt}x
gidNumber: 500

dn: cn=tomcat,ou=Group,dc=magnuskkarlsson,dc=com
objectClass: top
objectClass: posixGroup
cn: tomcat
userPassword: {crypt}x
gidNumber: 501
memberUid: magkar

Test

To test this we create a simple web application.

example-ldap.war/index.jsp

<html>
<body>
<p>Remote User : <%= request.getRemoteUser()  %></p>
</body>
</html>

example-ldap.war/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0" metadata-complete="true">

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>tomcat</role-name>
        </auth-constraint>
    </security-constraint>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Example LDAP Authentication</realm-name>
    </login-config>

    <security-role>
        <role-name>tomcat</role-name>
    </security-role>
</web-app>

February 8, 2015

Using LDAP as Address Book in Thunderbird

In my previous blog I described how to setup OpenLDAP. In this blog I will describe how to use it as address book in thunderbird.

  1. Open Preferences by clicking on menu Edit -> Preferences.
  2. Select Composition and Addressing. Click on Edit Directories...
  3. From the LDAP Directory Servers window click Add and enter you LDAP.
  4. Click OK on all open windows. From main thunderbird window click on tool button Address Book.
  5. Select you LDAP server and search in the quick search tool bar textfield and press Enter.

Understanding LDAP and LDAP Authentication

Introduction

If you let an IT administrator pick a persistence storage technique, he would probably choose a LDAP directory. But if you asked a system developer, then he would probably choose a RDBMS (Relational Database Management System). Why is that? I would guess because of history.

So is the two different technique so much different? They both stores data. Right. But they also have some key differences.

  • LDAP stores data in a tree (hierarchical database) and RDBMS stores data in tables with relationship between them via primary keys and foreign keys.
  • LDAP uses path (Distinguished Name, DN) to make entries unique. RDBMS uses primary keys in tables.
  • In a RDBMS you design your tables and columns. In LDAP you pick from predefined object class (RDBMS table), with predefined attributes (RDBMS column).
  • In RDBMS you define the column data types, but in LDAP everything are strings.

So by that said lets start to discover LDAP, with OpenLDAP.

Installation

openldap A package containing the libraries necessary to run the OpenLDAP server and client applications.

openldap-clients A package containing the command-line utilities for viewing and modifying directories on an LDAP server.

openldap-servers A package containing both the services and utilities to configure and run an LDAP server. This includes the Standalone LDAP Daemon, slapd.

compat-openldap A package containing the OpenLDAP compatibility libraries.

Choosing a Suffix

The LDAP suffix is the global LDAP name space or the toop root of you LDAP tree.

There are two standard approaches:

  1. The X.500 naming model, which is geographically and organizationally based.
    Example: o=Magnus K Karlsson,l=Stockholm,s=Stockholm,c=SE
  2. The Internet domain naming model, i.e. the organizations's DNS domain.
    Example: dc=magnuskkarlsson,dc=com

Abbreviation:
dc, Domain Component
dn, Distinguished Name
cn, Common Name
sn, Surname (family name/last name)
uid, User ID
o, Organization
ou, Organization Unit
l, Location
s, State
c, Country
RDN, Relative Distinuished Name
OID, Object Identifier
DIT, Directory Information Tree
LDIF, LDAP Data Interchange Format

The preferred method is the organizations's DNS domain.

Password Storing Policy

Storing password securily is importand. The default way in OpenLDAP is SSHA-1, in RHEL 6 it is SSHA-512 with 8-bit salt, see crypt(3).

NOTES
   Glibc Notes
       The glibc2 version of this function supports additional encryption 
       algorithms.

       If salt is a character string starting with the characters "$id$" 
       followed by a string terminated by "$":

              $id$salt$encrypted

       then instead of using the DES machine, id identifies the encryption 
       method used and this then determines how the rest of the password string 
       is interpreted.  The following values of id are supported:

              ID  | Method
              ---------------------------------------------------------
              1   | MD5
              2a  | Blowfish (not in mainline glibc; added in some
                  | Linux distributions)
              5   | SHA-256 (since glibc 2.7)
              6   | SHA-512 (since glibc 2.7)

       So $5$salt$encrypted is an SHA-256 encoded password and $6$salt$encrypted 
       is an SHA-512 encoded one.

       "salt" stands for the up to 16 characters following "$id$" in the salt. 
       The encrypted part of the password string is the actual computed password.  
       The size of this string is fixed:

       MD5     | 22 characters
       SHA-256 | 43 characters
       SHA-512 | 86 characters

       The characters in "salt" and "encrypted" are drawn from the set 
       [a–zA–Z0–9./]. In the MD5 and SHA implementations the entire key is 
       significant (instead of only the first 8 bytes in DES).

The slappasswd tool can be given options to use crypt(3), see slappasswd(8).

       -c crypt-salt-format
              Specify the format of the salt passed to crypt(3) when generating 
              {CRYPT} passwords.  This string needs to be in sprintf(3) format 
              and may include one (and only one) %s conversion. This  conversion
              will be substituted with a string of random characters from 
              [A-Za-z0-9./]. For example, ’%.2s’ provides a two character salt 
              and ’$1$%.8s’ tells some versions of crypt(3) to use an MD5 
              algorithm and provides 8 random characters of salt. The default is 
              ’%s’, which provides 31 characters of salt.

The recommended way is to use the strongest option, i.e. SSHA-512 with 16 bit salt.

$ slappasswd -c '$6$%.16s'
New password: 
Re-enter new password: 
{CRYPT}$6$/rq5GLnmg5yVZ8XB$CKypmnBEwy1g09R/8k7w8ZCdyelz04DPagKwBS7MakGNqnKSOcftiqW48pg.LBdI0cxAT6yfb1C8sWeD/qeP01

Configuration

The configuration in newer OpenLDAP versions has been moved from a single configuration file (/etc/openldap/slapd.conf) to a configuration directory (/etc/openldap/slapd.d/), containing several configuration files.

For more novice users is the single configuration file more easier to understand and easier to get an overview of all configuration. Here we will use the single configuration file.

$ rm -rf /etc/openldap/slapd.d
$ cp /usr/share/openldap-servers/slapd.conf.obsolete /etc/openldap/slapd.conf

Now we are ready to configure LDAP suffix and username and password for LDAP root user.

$ vi /etc/openldap/slapd.conf
...
suffix          "dc=magnuskkarlsson,dc=com"
rootdn          "cn=admin,dc=magnuskkarlsson,dc=com"
rootpw          "{CRYPT}$6$/rq5GLnmg5yVZ8XB$CKypmnBEwy1g09R/8k7w8ZCdyelz04DPagKwBS7MakGNqnKSOcftiqW48pg.LBdI0cxAT6yfb1C8sWeD/qeP01"
...

Start

$ service slapd start

Test

To test we can run a simple search.

$ ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
...
dn:
namingContexts: dc=magnuskkarlsson,dc=com
...

Another test can be to print all configuration.

$ ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config
...
olcRootDN: cn=admin,dc=magnuskkarlsson,dc=com
olcRootPW: {SSHA}nZElz+cA+HvrxmNVKn3tONJhRWphVLTN
...

GUI Administration Tools

Apache Directory Studio Eclipse-based LDAP tools

For Bug on RHEL 6 and CentOS 6:

See resolution https://issues.apache.org/jira/browse/DIRSTUDIO-999

Designing the Name Space

Designing your LDAP tree or Directory Information Tree (DIT) is an important thing.

Flat Name Space

Example:
uid=john,dc=magnuskkarlsson,dc=com
uid=jim,dc=magnuskkarlsson,dc=com

Advantages:

  • Names do not need to change when job roles change or the organization changes.
  • Simple design avoids need to object categoratization by directory administrators.

Disadvanteges:

  • Hard to partition the directory later if needed.
  • May be hard to maintain unique DNs.

Deeper Name Space

Example:
uid=peter,ou=Development,ou=People,l=Europe,dc=magnuskkarlsson,dc=com
uid=maria,ou=Sales,ou=People,l=Asia,dc=magnuskkarlsson,dc=com

Advantages:

  • Easier to delegate control to organizational units.
  • May simplify later partitioning of directory service among several servers.

Disadvanteges:

  • Names to tend to change more often: job transfer, organizational changes, etc.
  • May require more work to correctly categorize entries, keep up to date.

Compromise Name Space

Example:
ou=People,dc=magnuskkarlsson,dc=com
ou=Group,dc=magnuskkarlsson,dc=com

base.ldif

dn: dc=magnuskkarlsson,dc=com
dc: magnuskkarlsson
objectClass: domain
objectClass: top

dn: ou=People,dc=magnuskkarlsson,dc=com
ou: People
objectClass: organizationalUnit
objectClass: top

dn: ou=Group,dc=magnuskkarlsson,dc=com
ou: Group
objectClass: organizationalUnit
objectClass: top

OpenLDAP Tool

The openldap-clients packages installes a number of tools, the most common used are:

  • ldapsearch, tool to search the directory.
  • ldapadd and ldapmodify, tool that use LDIF (LDAP Data Interchange Format) files to update the directory.
  • ldapdelete, tool to delete entry.

Common options for these tools are:

  • -H host
  • -x Use simple, not SASL binds (login method)
  • -D dn Bind using dn (username)
  • -W prompt for simple bind password

Example:

$ ldapadd -x -D "cn=admin,dc=magnuskkarlsson,dc=com" -W -f base.ldif

Common options for ldapsearch:

  • -b dn Base DN in tree to start search from.

Example:

$ ldapsearch -x -b 'dc=magnuskkarlsson,dc=com' '(objectclass=*)'

User Class

User Structural Class

After we have designed and created our LDAP tree structure, it's time to create the actual user entry. But before that we need to decide which base class we want to use for our user entry.

Note that an entry must have one and only one structural object class. Each object class have a defined set of attributes, some mandatory and other optional. You can extend or add one or more addition auxiliary object classes.

The two most frequently used structural classes are:

  • account Is useful if you are only using LDAP as a NIS (Network Information Service) replacement.
  • inetOrgPerson Is best if you are also using LDAP to provide contact information.

User Auxiliary Classes

If you are planning to use the LDAP directory for RHEL authentication, you need to add the following auxiliary classes.

posixAccount represents a line from /etc/passwd.

shadowAccount represents a line from /etc/shadow.

Group Structural Class

To complete a UNIX user/authentication you also needs groups.

posixGroup represents a line from /etc/group.

student.ldif

dn: uid=student,ou=People,dc=magnuskkarlsson,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
objectClass: top
cn: student
sn: student
uid: student
uidNumber: 500
gidNumber: 500
homeDirectory: /home/student
userPassword: {crypt}$6$TgMwYtfv6Z0C8Peo$H7p8XjUYuBIspHgTmbo2KKSusssqFuBJFi58uRIcFVsObQJr72RHmBEq9Qz8JcBuA0tCbKvmDawxbQzz112/y0
shadowLastChange: 16467
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash

dn: cn=student,ou=Group,dc=magnuskkarlsson,dc=com
objectClass: top
objectClass: posixGroup
cn: student
userPassword: {crypt}x
gidNumber: 500

Access Control Instructions, ACI

Writing ACI is out of the scoop of this blog, so comment out every ACI in /etc/openldap/slapd.conf, which will give everyone read, but restricts updates to rootdn.

Installation Apache Web Server (httpd) and LDAP authentication

Lets test our new LDAP directory, by configure LDAP authentication against httpd manual pages.

$ sudo yum install httpd httpd-manual

The httpd ldap module is alreaddy by default installed.

$ grep authnz /etc/httpd/conf/httpd.conf 
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so

Lets configure httpd-manual authentication.

$ vi /etc/httpd/conf.d/manual.conf

<Directory "/var/www/manual">
    AuthType Basic
    AuthName "Restricted Resource"
    AuthBasicProvider ldap
    AuthLDAPURL "ldap://ldap.magnuskkarlsson.com:389/ou=People,dc=magnuskkarlsson,dc=com?uid"
    Require valid-user
    Order deny,allow
    Deny from all
    Allow from all
</Directory>

Restart httpd and test.

$ service httpd restart

RHEL 6 LDAP Authentication Migrations Tools

$ sudo yum install migrationtools

Create LDIF export of local user and its password.

$ /usr/share/migrationtools/migrate_passwd.pl /etc/passwd

Create LDIF export of local groups.

$ /usr/share/migrationtools/migrate_group.pl /etc/group

To export and import everything.

$ /usr/share/migrationtools/migrate_all_online.sh
Enter the X.500 naming context you wish to import into: [dc=padl,dc=com] dc=magnuskkarlsson,dc=com
Enter the hostname of your LDAP server [ldap]: ldap.magnuskkarlsson.com
Enter the manager DN: [cn=manager,dc=magnuskkarlsson,dc=com]: cn=admin,dc=magnuskkarlsson,dc=com
Enter the credentials to bind with: 
Do you wish to generate a DUAConfigProfile [yes|no]? no

References

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Directory_Servers.html

https://help.ubuntu.com/lts/serverguide/openldap-server.html

http://wiki.openiam.com/pages/viewpage.action?pageId=7635198

LDAP Schemas

Default installed LDAP schemas.

$ cat /etc/openldap/slapd.conf
...
include  /etc/openldap/schema/corba.schema
include  /etc/openldap/schema/core.schema
include  /etc/openldap/schema/cosine.schema
include  /etc/openldap/schema/duaconf.schema
include  /etc/openldap/schema/dyngroup.schema
include  /etc/openldap/schema/inetorgperson.schema
include  /etc/openldap/schema/java.schema
include  /etc/openldap/schema/misc.schema
include  /etc/openldap/schema/nis.schema
include  /etc/openldap/schema/openldap.schema
include  /etc/openldap/schema/ppolicy.schema
include  /etc/openldap/schema/collective.schema
...

/etc/openldap/schema/cosine.schema

objectclass ( 0.9.2342.19200300.100.4.5 NAME 'account'
        SUP top STRUCTURAL
        MUST userid
        MAY ( description $ seeAlso $ localityName $
                organizationName $ organizationalUnitName $ host )
        )

/etc/openldap/schema/nis.schema

objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
        DESC 'Abstraction of an account with POSIX attributes'
        SUP top AUXILIARY
        MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
        MAY ( userPassword $ loginShell $ gecos $ description ) )

objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount'
        DESC 'Additional attributes for shadow passwords'
        SUP top AUXILIARY
        MUST uid
        MAY ( userPassword $ shadowLastChange $ shadowMin $
              shadowMax $ shadowWarning $ shadowInactive $
              shadowExpire $ shadowFlag $ description ) )

objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup'
        DESC 'Abstraction of a group of accounts'
        SUP top STRUCTURAL
        MUST ( cn $ gidNumber )
        MAY ( userPassword $ memberUid $ description ) )

/etc/openldap/schema/core.schema

objectclass ( 2.5.6.6 NAME 'person'
        DESC 'RFC2256: a person'
        SUP top STRUCTURAL
        MUST ( sn $ cn )
        MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )

objectclass ( 2.5.6.7 NAME 'organizationalPerson'
        DESC 'RFC2256: an organizational person'
        SUP person STRUCTURAL
        MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
                preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
                telephoneNumber $ internationaliSDNNumber $ 
                facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
                postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )

/etc/openldap/schema/inetorgperson.schema

objectclass     ( 2.16.840.1.113730.3.2.2
    NAME 'inetOrgPerson'
        DESC 'RFC2798: Internet Organizational Person'
    SUP organizationalPerson
    STRUCTURAL
        MAY (
                audio $ businessCategory $ carLicense $ departmentNumber $
                displayName $ employeeNumber $ employeeType $ givenName $
                homePhone $ homePostalAddress $ initials $ jpegPhoto $
                labeledURI $ mail $ manager $ mobile $ o $ pager $
                photo $ roomNumber $ secretary $ uid $ userCertificate $
                x500uniqueIdentifier $ preferredLanguage $
                userSMIMECertificate $ userPKCS12 )
        )

January 9, 2015

The Java EE 6 Interceptors

Introduction

The AOP Interceptor was in EE 6 introduced and was before only supported with additional libraries such as aspectj and jboss-aop.

Before using Interceptor one should first really consider if this is the right tool for solving ones problem. Because using AOP Interceptor is not a holy grail, BUT for certain problem it is. Those are:

  • Logging
  • Caching
  • Security
  • And similiar

The above examples are so called cross cutting concern, that are well suited to be solved with AOP Interceptor.

Java EE 6 Interceptors

To create a Java EE Interceptor you create a POJO with:

  • A public, no-argument constructor.
  • One around-invoke interceptor method with syntax @javax.interceptor.AroundInvoke visibility Object method-name(javax.interceptor.InvocationContext) throws Exception { ... }

Example

public class AuditInterceptor {

    private java.util.logging.Logger log = java.util.logging.Logger
            .getLogger(AuditInterceptor.class.getName());

    @javax.interceptor.AroundInvoke
    protected Object invoke(javax.interceptor.InvocationContext ctx)
            throws Exception {

        StringBuilder sb = new StringBuilder("[");
        for (Object obj : ctx.getParameters()) {
            sb.append(obj.toString());
            sb.append(", ");
        }
        sb.append("]");
        log.log(java.util.logging.Level.INFO,
                "user {0} invoced {1} with method {2} and parameters: {3}",
                new Object[] { ctx.getTarget().toString(), 
                        ctx.getMethod().getName(), sb.toString() });
        return ctx.proceed();
    }
}

To use it, add @javax.interceptor.Interceptors(AuditInterceptor.class) to any bean that supports injection, e.g. Servlet, JSF ManagedBean, EJB.

Example

@javax.interceptor.Interceptors(AuditInterceptor.class)
@javax.ejb.Stateless
public class FooSLSB {

    public void save(Object obj) {
        // do something
    }
}

NOTE: You can either annotate the class (Interceptor will be called whenever every public method is called) or a specific method.

The final piece to make it work is to add the beans.xml in:

  • META-INF/ for ejb jar.
  • WEB-INF/ for web war.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

</beans>

Reference

Oracle EE 6 Tutorial Chapter 50: Using Java EE Interceptors