1 package org.collectionspace.authentication;
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
8 import javax.security.auth.login.AccountException;
9 import javax.security.auth.login.AccountNotFoundException;
11 import org.collectionspace.authentication.realm.db.CSpaceDbRealm;
12 import org.postgresql.util.PSQLState;
13 import org.springframework.context.ApplicationListener;
14 import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
15 import org.springframework.security.core.Authentication;
16 import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken;
17 import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
19 public class CSpaceAuthenticationSuccessEvent implements ApplicationListener<AuthenticationSuccessEvent> {
21 private static final String UPDATE_USER_SQL =
22 "UPDATE users SET lastlogin = now() WHERE username = ?";
24 private static final String DELETE_EXPIRED_AUTHORIZATIONS_SQL =
25 "DELETE FROM oauth2_authorization WHERE access_token_expires_at < now()";
28 public void onApplicationEvent(AuthenticationSuccessEvent event) {
29 Object eventSource = event.getSource();
32 eventSource instanceof Authentication
33 // Ignore authentication via JWT token, since this indicates a continuing session -- not what a user would consider a "log in"
34 && !(eventSource instanceof JwtAuthenticationToken)
35 // Ignore authorization code requests
36 && !(eventSource instanceof OAuth2AuthorizationCodeRequestAuthenticationToken)
38 Authentication authentication = (Authentication) eventSource;
40 if (authentication.getPrincipal() instanceof CSpaceUser) {
41 CSpaceDbRealm cspaceDbRealm = new CSpaceDbRealm();
42 CSpaceUser cspaceUser = (CSpaceUser) authentication.getPrincipal();
43 String username = cspaceUser.getUsername();
46 setLastLogin(cspaceDbRealm, username);
47 } catch (Exception e) {
52 deleteExpiredAuthorizations(cspaceDbRealm);
53 } catch (Exception e) {
60 private void setLastLogin(CSpaceDbRealm cspaceDbRealm, String username) throws AccountException {
61 Connection conn = null;
62 PreparedStatement ps = null;
66 conn = cspaceDbRealm.getConnection();
67 ps = conn.prepareStatement(UPDATE_USER_SQL);
68 ps.setString(1, username);
69 int affected = ps.executeUpdate();
71 String errMsg = String.format("No matching username '%s' found.", username);
72 throw new AccountException(errMsg);
74 } catch (SQLException ex) {
75 // Assuming PostgreSQL
76 if (PSQLState.UNDEFINED_COLUMN.getState().equals(ex.getSQLState())) {
77 System.err.println("'users' table is missing 'lastlogin' column.");
79 AccountException ae = new AccountException("Authentication query failed: " + ex.getLocalizedMessage());
83 } catch (AccountNotFoundException ex) {
85 } catch (Exception ex) {
86 AccountException ae = new AccountException("Unknown Exception");
93 } catch (SQLException e) {
99 } catch (SQLException e) {
105 } catch (SQLException ex) {
111 private void deleteExpiredAuthorizations(CSpaceDbRealm cspaceDbRealm) throws AccountException {
112 Connection conn = null;
113 PreparedStatement ps = null;
117 conn = cspaceDbRealm.getConnection();
118 ps = conn.prepareStatement(DELETE_EXPIRED_AUTHORIZATIONS_SQL);
120 } catch (Exception ex) {
121 AccountException ae = new AccountException("Unknown Exception");
128 } catch (SQLException e) {
134 } catch (SQLException e) {
140 } catch (SQLException ex) {