It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

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
Answer accepted

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
Posted in Jira

We want to hear from you! How do you use Slack and Atlassian together?

Hi Everyone! My name is Mina and I am on Atlassian’s Ecosystems Marketing team. Our team is focused on our technology partnerships and marketplace apps. One of Atlassian’s partners is Slack, who ...

108 views 1 6
Join discussion

Community Events

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

Find an event

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

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you