How to update LOGININFO table in Confluence 4.0 in custom Confluence authenticator?

In the Confluence Shibboleth Authenticator, we had functionality used by some customers to record the last and previous login dates of a user (see source). In SHBL-50 we've been asked to update the Logininfo table that is now in Confluence 4.0. Is that a table used by embedded Crowd and/or Confluence 4.0? Or is it something else? Is there a way that we could update that database table via a Confluence and/or embedded Crowd API from our authenticator? Thanks!

7 answers

1 accepted

1 vote
Accepted answer

I found out that calling the super.login(request, response, username, password, cookie) method on ConfluenceAuthenticator is what was logging to LOGININFO. However, that requires a password that you don't have when authenticating via some (or most?) SSOs. Joseph Clark provided something I think can be a workaround in this snippet: https://answers.atlassian.com/questions/24227/invoke-embedded-crowd-login?page=1#25210

I'm using that at the moment and waiting on the customer to test and respond.

This is what debugging tells about updating the table:

2011-11-30 13:35:07,460 DEBUG [TP-Processor3] [atlassian.seraph.filter.PasswordB
asedLoginFilter] runAuthentication runAuthentication : 'admin' was successfully
authenticated
2011-11-30 13:35:07,461 DEBUG [TP-Processor3] [net.sf.hibernate.SQL] log select userlogini0_.id as id, userlogini0_.CURFAILED as CURFAILED, userlogini0_.TOTALFAILED as TOTALFAI3_, userlogini0_.SUCCESSDATE as SUCCESSD4_, userlogini0_.PREVSUCCESSDATE as PREVSUCC5_, userlogini0_.FAILEDDATE as FAILEDDATE, userlogini0_.USERNAME as USERNAME from logininfo userlogini0_ where (userlogini0_.USERNAME=? )
2011-11-30 13:35:07,464 DEBUG [TP-Processor3] [net.sf.hibernate.SQL] log update logininfo set CURFAILED=?, TOTALFAILED=?, SUCCESSDATE=?, PREVSUCCESSDATE=?, FAILEDDATE=?, USERNAME=? where id=?
2011-11-30 13:35:07,467 DEBUG [TP-Processor3] [atlassian.seraph.filter.BaseLoginFilter] doFilter doFilter : Login completed for 'admin' - os_authstatus = 'success'

Erkki,

Unfortunately, it isn't clear to me what code we need in the custom Confluence authenticator (Confluence Shibboleth Authenticator) to get the authenticator to ensure that the LOGININFO table is updated. We need to get it to work via the proper Atlassian API using Atlassian-supported methods rather than updating the table directly/via Hibernate, because as Confluence changes, we need to be forward and backward compatible without a lot of work on the authenticator side.

Thanks for the info, though. You might want to also paste that as a comment to the Jira ticket, SHBL-50.

I'll also follow-up with you in that ticket, as I think at this point we need to open a ticket with Atlassian, since there has been no answer to this; it may be a bug with use of custom authenticators w/Confluence 4.0, or it could be a configuration issue.

Thanks,

Gary

Created CONF-24033, so please watch there for additional comments by Atlassian.

To be more precise, the log above tells something about updating logininfo for a local user and there logininfo is indeed updated correctly. For a user autheticating via Shibboleth the log shows this:

2011-11-30 13:41:35,162 DEBUG [TP-Processor11] [atlassian.seraph.filter.PasswordBasedLoginFilter] login login : No user name or password was returned. No authentication attempt will be made. User may still be found via a SecurityFilter later.
2011-11-30 13:41:35,162 DEBUG [TP-Processor11] [atlassian.seraph.filter.BaseLoginFilter] doFilter doFilter : Login completed for 'aalto@helsinki.fi' - os_authstatus = 'null'

I am fairly sure the answer to this is to use an Atlassian login filter somehow as a workaround, but it would be nice if someone from Atlassian who helps with authenticators could assist with some sample code.

I have just received this answer:

How Confluence itself updates the LOGININFO table is via the:

HibernateuserLoginInfoDao.java class. (Line 42)

This is mainly used by the DefeaultLoginManager.java (which handles the logging of user's)

Here is snippet of the source

1
2
3
4
5
6
7
8
9
10
11
12
public void onFailedLoginAttempt(String userName, HttpServletRequest servletRequest)
{
recordLoginFailure(userName, servletRequest);
User user = userAccessor.getUser(userName);
// User exists: Store the number of failed login attempts against this user
if (null != user)
{
UserLoginInfo userLoginInfo = loginInfoDao.findOrCreateUserLoginInfoForUser(user);
userLoginInfo.failedLogin(clock.getCurrentDate());
loginInfoDao.saveOrUpdate(userLoginInfo);
}

Erkki, this doesn't help, unfortunately. The authenticator should not be concerned with the implementation details of the Confluence, Atlassian User, and Embedded Crowd APIs, but rather should be calling higher-level methods that will help to avoid issues caused by upgrades, differences between environments, etc.

Should we then be calling this:

onSuccessfulLoginAttempt

public void onSuccessfulLoginAttempt(String userName,
                                     javax.servlet.http.HttpServletRequest servletRequest)
<dl><dd>This is called after a successful login attempt has been made. It allows the LoginManager to update information about a users login history.

</dd><dd><dl><dt>Specified by:</dt><dd>onSuccessfulLoginAttempt in interface LoginManager</dd></dl></dd><dd><dl><dt>Parameters:</dt><dd>userName - the name of the user in play. This MUST not be null.</dd><dd>servletRequest - the request pertaining to a login attempt.</dd></dl></dd></dl>

To continue, the source says:

public void onSuccessfulLoginAttempt(String userName, HttpServletRequest servletRequest)
{
log.debug("Successful login attempt for user '{}'", userName);
User user = userAccessor.getUser(userName);
if (null != user) // should not be null if the login was successful
{
/**
* This keeps track of the most recent and most recent but one login date and times for the user who has just logged in.
*/
UserLoginInfo userLoginInfo = loginInfoDao.findOrCreateUserLoginInfoForUser(user);
userLoginInfo.successfulLogin(clock.getCurrentDate());
loginInfoDao.saveOrUpdate(userLoginInfo);
}
else
{
log.error("Can not retrieve the user '{}' to set the successful login information (last login date).", userName);
}
}

Suggest an answer

Log in or Sign up to answer
Community showcase
Published Friday in Agile

Are you a Jira Service Desk agent? We want to talk to you!

Are you a whiz at handling tickets and looking at how you can further optimize your workflow with automation? Do you tackle detailed customer support questions while simultaneously getting flooded wi...

59 views 0 2
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you