Page 1 of 1

Authentication/User logging

PostPosted: Fri Oct 28, 2016 2:47 pm
by Development@SIB
Some applications need detailed information about successful or failed user logins. If you have such requirement, you could create a custom security manager to solve the problem. The security manager will be used for user authentication, so it's the right place to start.

We use the database security manager as base class:
Syntax: [ Download ] [ Hide ]
package com.sibvisions.apps.vaadin.web;

public class LoggingSecurityManager extends DBSecurityManager
{
    private PreparedStatement psLockedUsers;

    @Override
    protected boolean isPasswordValid(ISession pSession, String pPassword) throws Exception
    {
        // additional check: locked user

        ResultSet resultSet = null;

        try
        {
            psLockedUsers.clearParameters();
            psLockedUsers.setString(1, pSession.getUserName());
            psLockedUsers.execute();

            resultSet = psLockedUsers.getResultSet();

            if (resultSet.next())
            {
                throw new SilentAbortException();
            }
        }
        finally
        {
            CommonUtil.close(resultSet);
        }

        return super.isPasswordValid(pSession, pPassword);
    }

    @Override
    public synchronized void validateAuthentication(ISession pSession) throws Exception
    {
        String result = null;

        Throwable error = null;

        try
        {
            super.validateAuthentication(pSession);

            result = Constants.RESULT_OK;
        }
        catch (SilentAbortException sae)
        {
            result = Constants.RESULT_IGNORE;
            error = sae;

            throw sae;
        }
        catch (SecurityException se)
        {
            result = Constants.RESULT_DENIED;
            error = se;

            throw se;
        }
        catch (Exception ex)
        {
            result = Constants.RESULT_ERROR;
            error = ex;

            error(ex);

            throw ex;
        }
        finally
        {
            try
            {
                pSession.callAction("dbLog", Constants.TYPE_LOGIN, error, result);
            }
            catch (Throwable thr)
            {
                error(thr);
            }
        }
    }

    @Override
    public synchronized void logout(ISession pSession)
    {
        String result = null;
        Throwable error = null;

        try
        {
            super.logout(pSession);

            if (Boolean.parseBoolean((String)pSession.getProperty("userlogout")))
            {
                result = Constants.RESULT_OK;
            }
            else
            {
                result = Constants.RESULT_EXPIRED;
            }
        }
        catch (Exception ex)
        {
            result = Constants.RESULT_ERROR;
            error = ex;

            error(ex);
        }
        finally
        {
            try
            {
                pSession.callAction("dbLog", Constants.TYPE_LOGOUT, error, result);
            }
            catch (Throwable eLog)
            {
                error(eLog);
            }
        }
    }

    @Override
    protected void initStatements(Connection pConnection) throws Exception
    {
        super.initStatements(pConnection);

        psLockedUsers = prepareStatement(pConnection, "select * from LOCKS where USERNAME = ?");
    }

}     // LoggingSecurityManager

The clue is that the log method dbLog was implemented in the session LCO of our application because we re-use the business logic in our security manager. Here's the missing method:

Syntax: [ Download ] [ Hide ]
public void dbLog(int pAction, Throwable pError, String pStatus)
{
    ILogger log = LoggerFactory.getInstance(getClass());

    log.info("Log action ", pAction, pError, pStatus);
   
    try
    {
        getDBAccess().executeProcedure("log",
                                       pAction,
                                       SessionContext.getCurrentSession().getUserName(),
                                       new Timestamp(System.currentTimeMillis()));
    }
    catch (Exception ex)
    {
        log.error(ex);
    }
}