From 84b546ba021ad81072637cde49600959d60f65fd Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Mon, 4 Sep 2023 15:33:18 +0300 Subject: [PATCH 1/6] add new fields to db --- .../flyway/oskari/V2_13_0__add_created_field_to_user_table.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql diff --git a/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql b/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql new file mode 100644 index 000000000..99a6ee6e2 --- /dev/null +++ b/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql @@ -0,0 +1,2 @@ +ALTER TABLE oskari_users ADD COLUMN created TIMESTAMP WITH TIME ZONE DEFAULT NOW(); +ALTER TABLE oskari_users ADD COLUMN last_login TIMESTAMP WITH TIME ZONE DEFAULT null; \ No newline at end of file From 145d60cbab39aceac56ade119225d7d1d8acf0d4 Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Wed, 6 Sep 2023 09:47:18 +0300 Subject: [PATCH 2/6] fetch timestamps with user info and update last_login when logging in --- .../main/java/fi/nls/oskari/domain/User.java | 19 +++++++++++++++ .../nls/oskari/user/DatabaseUserService.java | 23 +++++++++++++++++-- .../java/fi/nls/oskari/user/UsersMapper.java | 17 ++++++++------ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/service-base/src/main/java/fi/nls/oskari/domain/User.java b/service-base/src/main/java/fi/nls/oskari/domain/User.java index d47b7d155..6ed5745de 100755 --- a/service-base/src/main/java/fi/nls/oskari/domain/User.java +++ b/service-base/src/main/java/fi/nls/oskari/domain/User.java @@ -8,6 +8,7 @@ import org.json.JSONObject; import java.io.Serializable; +import java.time.OffsetDateTime; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; @@ -34,6 +35,8 @@ public class User implements Serializable { private String screenname = ""; private String email = ""; private JSONObject attributes = new JSONObject(); + private OffsetDateTime created; + private OffsetDateTime lastLogin; private String uuid = ""; private Set roles = new LinkedHashSet<>(); @@ -210,6 +213,22 @@ public String getFirstname() { return firstname; } + public OffsetDateTime getCreated() { + return created; + } + + public void setCreated(OffsetDateTime created) { + this.created = created; + } + + public OffsetDateTime getLastLogin() { + return lastLogin; + } + + public void setLastLogin(OffsetDateTime lastLogin) { + this.lastLogin = lastLogin; + } + public JSONObject toJSON() { try { JSONObject userData = new JSONObject(); diff --git a/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java b/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java index 08f67bc86..e7db827b7 100755 --- a/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java +++ b/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java @@ -11,7 +11,17 @@ import org.apache.commons.codec.digest.DigestUtils; import org.springframework.security.crypto.bcrypt.BCrypt; -import java.util.*; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + public class DatabaseUserService extends UserService { @@ -57,7 +67,16 @@ public User login(final String user, final String pass) throws ServiceException return null; } - return getUser(username); + User fetchedUser = getUser(username); + OffsetDateTime previousLastLogin = fetchedUser.getLastLogin(); + OffsetDateTime now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toOffsetDateTime(); + fetchedUser.setLastLogin(now); + userService.updateUser(fetchedUser); + + // return the previous login to front + fetchedUser.setLastLogin(previousLastLogin); + return fetchedUser; + } catch (Exception ex) { throw new ServiceException("Unable to handle login", ex); } diff --git a/service-users/src/main/java/fi/nls/oskari/user/UsersMapper.java b/service-users/src/main/java/fi/nls/oskari/user/UsersMapper.java index 628e7ce03..d14659f7a 100644 --- a/service-users/src/main/java/fi/nls/oskari/user/UsersMapper.java +++ b/service-users/src/main/java/fi/nls/oskari/user/UsersMapper.java @@ -13,22 +13,24 @@ public interface UsersMapper { @Result(property="email", column="email"), @Result(property="uuid", column="uuid"), @Result(property="screenname", column="user_name"), - @Result(property="attributes", column="attributes") + @Result(property="attributes", column="attributes"), + @Result(property="created", column="created"), + @Result(property="lastLogin", column="last_login") }) - @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes" + + @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes, created, last_login" + " FROM oskari_users" + " ORDER BY user_name") List findAll(); @ResultMap("UsersResult") - @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes" + + @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes, created, last_login" + " FROM oskari_users" + " ORDER BY user_name" + " LIMIT #{limit} OFFSET #{offset}") List findAllPaginated(@Param("limit") int limit, @Param("offset") int offset); @ResultMap("UsersResult") - @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes" + + @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes, created, last_login" + " FROM oskari_users" + " WHERE " + " user_name ilike '%' || #{query} || '%'" + @@ -74,12 +76,13 @@ public interface UsersMapper { " last_name = #{lastname}, " + " user_name = #{screenname}, " + " email = #{email}, " + - " attributes = #{attributes} " + + " attributes = #{attributes}, " + + " last_login = #{lastLogin} " + " WHERE id = #{id}") void updateUser(User user); @ResultMap("UsersResult") - @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes" + + @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes, created, last_login" + " FROM oskari_users" + " WHERE id = #{id}") User find(long id); @@ -95,7 +98,7 @@ public interface UsersMapper { String getPassword(final String username); @ResultMap("UsersResult") - @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes" + + @Select("SELECT id, first_name, last_name, user_name, email, uuid, attributes, created, last_login" + " FROM oskari_users" + " WHERE user_name = #{username}") User findByUserName(String username); From 65296bea13eda6dfb79aeb5b4c7342c3dc4d021a Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Wed, 6 Sep 2023 14:02:01 +0300 Subject: [PATCH 3/6] add not null to created - field --- .../flyway/oskari/V2_13_0__add_created_field_to_user_table.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql b/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql index 99a6ee6e2..1c978efbb 100644 --- a/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql +++ b/content-resources/src/main/resources/flyway/oskari/V2_13_0__add_created_field_to_user_table.sql @@ -1,2 +1,2 @@ -ALTER TABLE oskari_users ADD COLUMN created TIMESTAMP WITH TIME ZONE DEFAULT NOW(); +ALTER TABLE oskari_users ADD COLUMN created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(); ALTER TABLE oskari_users ADD COLUMN last_login TIMESTAMP WITH TIME ZONE DEFAULT null; \ No newline at end of file From 24fd134f1e8c58df407c1ec7d2547ef5e304ae07 Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Wed, 6 Sep 2023 14:03:11 +0300 Subject: [PATCH 4/6] use UTC for last login --- .../src/main/java/fi/nls/oskari/user/DatabaseUserService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java b/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java index e7db827b7..c17bacc91 100755 --- a/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java +++ b/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; import java.time.OffsetDateTime; -import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -69,7 +69,7 @@ public User login(final String user, final String pass) throws ServiceException User fetchedUser = getUser(username); OffsetDateTime previousLastLogin = fetchedUser.getLastLogin(); - OffsetDateTime now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toOffsetDateTime(); + OffsetDateTime now = LocalDateTime.now().atOffset(ZoneOffset.UTC); fetchedUser.setLastLogin(now); userService.updateUser(fetchedUser); From 2376396fe076a0a035d8c3ab985f06c0d2ff9f9c Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Wed, 6 Sep 2023 14:04:12 +0300 Subject: [PATCH 5/6] deliver created and last login to frontend --- service-base/src/main/java/fi/nls/oskari/domain/User.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/service-base/src/main/java/fi/nls/oskari/domain/User.java b/service-base/src/main/java/fi/nls/oskari/domain/User.java index 6ed5745de..b59bea275 100755 --- a/service-base/src/main/java/fi/nls/oskari/domain/User.java +++ b/service-base/src/main/java/fi/nls/oskari/domain/User.java @@ -28,6 +28,8 @@ public class User implements Serializable { private static final String KEY_USERID = "userID"; private final static String KEY_ROLES = "roles"; private final static String KEY_ADMIN = "admin"; + private final static String KEY_CREATED = "created"; + private final static String KEY_LAST_LOGIN = "lastLogin"; private long id = -1; private String lastname = ""; @@ -238,6 +240,8 @@ public JSONObject toJSON() { userData.put(KEY_NICKNAME, getScreenname()); userData.put(KEY_USERUUID, getUuid()); userData.put(KEY_USERID, getId()); + userData.put(KEY_CREATED, getCreated()); + userData.put(KEY_LAST_LOGIN, getLastLogin()); if (isAdmin()){ userData.put(KEY_ADMIN, true); } From c3f18988148c95c327db9f592cf1930591c1048b Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Wed, 6 Sep 2023 16:00:45 +0300 Subject: [PATCH 6/6] move updating the last login after the user has been updated to session --- .../fi/nls/oskari/user/DatabaseUserService.java | 14 +------------- .../oskari/spring/security/OskariUserHelper.java | 8 ++++++++ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java b/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java index c17bacc91..1bcbf2a84 100755 --- a/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java +++ b/service-users/src/main/java/fi/nls/oskari/user/DatabaseUserService.java @@ -11,9 +11,6 @@ import org.apache.commons.codec.digest.DigestUtils; import org.springframework.security.crypto.bcrypt.BCrypt; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -67,16 +64,7 @@ public User login(final String user, final String pass) throws ServiceException return null; } - User fetchedUser = getUser(username); - OffsetDateTime previousLastLogin = fetchedUser.getLastLogin(); - OffsetDateTime now = LocalDateTime.now().atOffset(ZoneOffset.UTC); - fetchedUser.setLastLogin(now); - userService.updateUser(fetchedUser); - - // return the previous login to front - fetchedUser.setLastLogin(previousLastLogin); - return fetchedUser; - + return getUser(username); } catch (Exception ex) { throw new ServiceException("Unable to handle login", ex); } diff --git a/servlet-map/src/main/java/fi/nls/oskari/spring/security/OskariUserHelper.java b/servlet-map/src/main/java/fi/nls/oskari/spring/security/OskariUserHelper.java index 1155ad21e..84d2b068d 100755 --- a/servlet-map/src/main/java/fi/nls/oskari/spring/security/OskariUserHelper.java +++ b/servlet-map/src/main/java/fi/nls/oskari/spring/security/OskariUserHelper.java @@ -6,6 +6,7 @@ import fi.nls.oskari.log.LogFactory; import fi.nls.oskari.log.Logger; import fi.nls.oskari.service.UserService; +import fi.nls.oskari.user.MybatisUserService; import org.oskari.log.AuditLog; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -15,6 +16,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -25,6 +27,7 @@ public class OskariUserHelper { private static Logger log = LogFactory.getLogger(OskariUserHelper.class); + private MybatisUserService userService = new MybatisUserService(); /** * Common code done for SAML and DB authentication on successful login @@ -77,6 +80,11 @@ private void setupSession(final HttpServletRequest httpRequest, final String use AuditLog.user(ActionParameters.getClientIp(httpRequest), loadedUser) .withMsg("Login") .updated(AuditLog.ResourceType.USER); + + // update last login + User userToUpdate = UserService.getInstance().getUser(username); + userToUpdate.setLastLogin(OffsetDateTime.now()); + userService.updateUser(userToUpdate); } else { log.error("Login user check failed! Got user from principal, but can't find it in Oskari db:", username);