Skip to content

Commit ce4d30f

Browse files
committed
Fixes #539
1 parent 1b72119 commit ce4d30f

File tree

7 files changed

+146
-3
lines changed

7 files changed

+146
-3
lines changed

server/src/main/java/invite/api/InvitationController.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package invite.api;
22

3+
import invite.audit.UserRoleAuditService;
34
import invite.exception.InvitationEmailMatchingException;
45
import invite.exception.InvitationExpiredException;
56
import invite.exception.InvitationStatusException;
@@ -79,6 +80,7 @@ public class InvitationController implements InvitationResource {
7980
private final SecurityContextRepository securityContextRepository;
8081
private final SuperAdmin superAdmin;
8182
private final InvitationOperations invitationOperations;
83+
private final UserRoleAuditService userRoleAuditService;
8284

8385
public InvitationController(MailBox mailBox,
8486
Manage manage,
@@ -87,7 +89,7 @@ public InvitationController(MailBox mailBox,
8789
RoleRepository roleRepository,
8890
ProvisioningService provisioningService,
8991
SecurityContextRepository securityContextRepository,
90-
SuperAdmin superAdmin) {
92+
SuperAdmin superAdmin, UserRoleAuditService userRoleAuditService) {
9193
this.mailBox = mailBox;
9294
this.manage = manage;
9395
this.invitationRepository = invitationRepository;
@@ -97,6 +99,7 @@ public InvitationController(MailBox mailBox,
9799
this.securityContextRepository = securityContextRepository;
98100
this.superAdmin = superAdmin;
99101
this.invitationOperations = new InvitationOperations(this);
102+
this.userRoleAuditService = userRoleAuditService;
100103
}
101104

102105
@PostMapping("")
@@ -208,13 +211,19 @@ public ResponseEntity<Map<String, Object>> accept(@Validated @RequestBody Accept
208211
Authority currentAuthority = userRole.getAuthority();
209212
//Only act upon different authorities
210213
if (!currentAuthority.equals(intendedAuthority)) {
214+
boolean userRoleChanged = false;
211215
if (intendedAuthority.hasHigherRights(currentAuthority)) {
212216
userRole.setAuthority(intendedAuthority);
213217
userRole.setEndDate(invitation.getRoleExpiryDate());
218+
userRoleChanged = true;
214219
}
215220
if (currentAuthority.equals(Authority.GUEST) || intendedAuthority.equals(Authority.GUEST) ||
216221
invitation.isGuestRoleIncluded()) {
217222
userRole.setGuestRoleIncluded(true);
223+
userRoleChanged = true;
224+
}
225+
if (userRoleChanged) {
226+
userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.UPDATE);
218227
}
219228
}
220229
} else {
@@ -245,6 +254,7 @@ public ResponseEntity<Map<String, Object>> accept(@Validated @RequestBody Accept
245254
}
246255
userRepository.save(user);
247256
AccessLogger.user(LOG, Event.Created, user);
257+
newUserRoles.forEach(userRole -> userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.ADD));
248258

249259
//Only interact with the provisioning service if there is a guest role
250260
boolean isGuest = user.getUserRoles().stream()

server/src/main/java/invite/api/UserRoleController.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package invite.api;
22

3+
import invite.audit.UserRoleAuditService;
34
import invite.config.Config;
45
import invite.exception.NotAllowedException;
56
import invite.exception.NotFoundException;
@@ -58,17 +59,20 @@ public class UserRoleController implements UserRoleResource {
5859
private final ProvisioningService provisioningService;
5960
private final Config config;
6061
private final UserRoleOperations userRoleOperations;
62+
private final UserRoleAuditService userRoleAuditService;
6163

6264
public UserRoleController(UserRoleRepository userRoleRepository,
6365
RoleRepository roleRepository,
6466
UserRepository userRepository,
6567
ProvisioningService provisioningService,
68+
UserRoleAuditService userRoleAuditService,
6669
Config config) {
6770
this.userRoleRepository = userRoleRepository;
6871
this.roleRepository = roleRepository;
6972
this.userRepository = userRepository;
7073
this.provisioningService = provisioningService;
7174
this.config = config;
75+
this.userRoleAuditService = userRoleAuditService;
7276
this.userRoleOperations = new UserRoleOperations(this);
7377
}
7478

@@ -172,7 +176,8 @@ public ResponseEntity<User> userRoleProvisioning(@Validated @RequestBody UserRol
172176
: null)
173177
.filter(Objects::nonNull)
174178
.toList();
175-
179+
newUserRoles.stream().filter(userRole -> userRole.getId() == null)
180+
.forEach(userRole -> this.userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.ADD));
176181
userRepository.save(user);
177182
AccessLogger.user(LOG, Event.Created, user);
178183

@@ -194,6 +199,7 @@ public ResponseEntity<Map<String, Integer>> updateUserRoleExpirationDate(@Valida
194199
UserPermissions.assertValidInvitation(user, userRole.getAuthority(), List.of(userRole.getRole()));
195200
userRole.setEndDate(updateUserRole.getEndDate());
196201
userRoleRepository.save(userRole);
202+
userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.UPDATE);
197203
//If there is a EVA provisioning, then update the account
198204
provisioningService.updateUserRoleRequest(userRole);
199205
return Results.createResult();
@@ -215,11 +221,13 @@ public ResponseEntity<Void> deleteUserRole(@PathVariable("id") Long id,
215221
userRole.setAuthority(Authority.GUEST);
216222
}
217223
userRoleRepository.save(userRole);
224+
userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.UPDATE);
218225
AccessLogger.userRole(LOG, Event.Updated, user, userRole);
219226

220227
} else {
221228
provisioningService.updateGroupRequest(userRole, OperationType.Remove);
222229
provisioningService.deleteUserRoleRequest(userRole);
230+
userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.DELETE);
223231
userRoleRepository.deleteUserRoleById(id);
224232
AccessLogger.userRole(LOG, Event.Deleted, user, userRole);
225233
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package invite.audit;
2+
3+
import invite.model.UserRole;
4+
import invite.model.UserRoleAudit;
5+
import invite.repository.UserRoleAuditRepository;
6+
import org.springframework.security.core.Authentication;
7+
import org.springframework.security.core.context.SecurityContextHolder;
8+
import org.springframework.stereotype.Service;
9+
10+
@Service
11+
public class UserRoleAuditService {
12+
13+
private final UserRoleAuditRepository userRoleAuditRepository;
14+
15+
public UserRoleAuditService(UserRoleAuditRepository userRoleAuditRepository) {
16+
this.userRoleAuditRepository = userRoleAuditRepository;
17+
}
18+
19+
20+
public void logAction(UserRole userRole, UserRoleAudit.ActionType action) {
21+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
22+
String authority = authentication != null ? authentication.getName() : "system";
23+
24+
UserRoleAudit audit = new UserRoleAudit(action, userRole, authority);
25+
userRoleAuditRepository.save(audit);
26+
}
27+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package invite.model;
2+
3+
import jakarta.persistence.*;
4+
import jakarta.validation.constraints.NotNull;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
import lombok.Setter;
8+
9+
import java.time.Instant;
10+
11+
@Entity(name = "user_roles_audit")
12+
@NoArgsConstructor
13+
@Getter
14+
@Setter
15+
public class UserRoleAudit {
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
private Long id;
20+
21+
@Column(name = "user_id", nullable = false)
22+
private Long userId;
23+
24+
@Column(name = "user_email", nullable = false)
25+
private String userEmail;
26+
27+
@Column(name = "role_id", nullable = false)
28+
private Long roleId;
29+
30+
@Column(name = "role_name", nullable = false)
31+
private String roleName;
32+
33+
@Column(name = "end_date")
34+
private Instant endDate;
35+
36+
@Enumerated(EnumType.STRING)
37+
@Column(name = "action", nullable = false)
38+
private ActionType action;
39+
40+
@Enumerated(EnumType.STRING)
41+
@Column
42+
@NotNull
43+
private Authority authority;
44+
45+
@Column(name = "created_at")
46+
private Instant createdAt;
47+
48+
@Column(name = "created_by", nullable = false)
49+
private String createdBy;
50+
51+
public UserRoleAudit(ActionType action, UserRole userRole, String createdBy) {
52+
User user = userRole.getUser();
53+
Role role = userRole.getRole();
54+
this.userId = user.getId();
55+
this.userEmail = user.getEmail();
56+
this.roleId = role.getId();
57+
this.roleName = role.getName();
58+
this.endDate = userRole.getEndDate();
59+
this.action = action;
60+
this.authority = userRole.getAuthority();
61+
this.createdAt = Instant.now();
62+
this.createdBy = createdBy;
63+
}
64+
65+
public enum ActionType {
66+
ADD, DELETE, UPDATE
67+
}
68+
69+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package invite.repository;
2+
3+
import invite.model.UserRoleAudit;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface UserRoleAuditRepository extends JpaRepository<UserRoleAudit, Long> {
9+
10+
}

server/src/main/java/invite/teams/TeamsController.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package invite.teams;
22

33
import invite.api.Results;
4+
import invite.audit.UserRoleAuditService;
45
import invite.exception.InvalidInputException;
56
import invite.manage.Manage;
67
import invite.model.Role;
@@ -43,19 +44,21 @@ public class TeamsController {
4344
private final ApplicationRepository applicationRepository;
4445
private final Manage manage;
4546
private final ProvisioningService provisioningService;
47+
private final UserRoleAuditService userRoleAuditService;
4648

4749
public TeamsController(RoleRepository roleRepository,
4850
UserRepository userRepository,
4951
UserRoleRepository userRoleRepository,
5052
ApplicationRepository applicationRepository,
5153
Manage manage,
52-
ProvisioningService provisioningService) {
54+
ProvisioningService provisioningService, UserRoleAuditService userRoleAuditService) {
5355
this.roleRepository = roleRepository;
5456
this.userRepository = userRepository;
5557
this.userRoleRepository = userRoleRepository;
5658
this.applicationRepository = applicationRepository;
5759
this.manage = manage;
5860
this.provisioningService = provisioningService;
61+
this.userRoleAuditService = userRoleAuditService;
5962
}
6063

6164
@PutMapping("")
@@ -156,6 +159,7 @@ private void provision(Role role, Membership membership) {
156159
boolean guestRoleIncluded = teamsRole.equals(invite.teams.Role.ADMIN) || teamsRole.equals(invite.teams.Role.MANAGER);
157160
userRole.setGuestRoleIncluded(guestRoleIncluded);
158161
userRole = userRoleRepository.save(userRole);
162+
userRoleAuditService.logAction(userRole, UserRoleAudit.ActionType.ADD);
159163

160164
provisioningService.updateGroupRequest(userRole, OperationType.Add);
161165
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CREATE TABLE user_roles_audit
2+
(
3+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
4+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
5+
user_id BIGINT NOT NULL,
6+
user_email VARCHAR(255) NOT NULL,
7+
role_id BIGINT NOT NULL,
8+
role_name VARCHAR(255) NOT NULL,
9+
end_date DATETIME DEFAULT NULL,
10+
action VARCHAR(255) NOT NULL,
11+
authority VARCHAR(255) NOT NULL,
12+
created_by varchar(255) NOT NULL
13+
) ENGINE = InnoDB
14+
AUTO_INCREMENT = 1
15+
DEFAULT CHARSET = utf8mb4;

0 commit comments

Comments
 (0)