[Developer] #617 apply DDS MCP end-user authorization
This commit is contained in:
@@ -23,12 +23,14 @@ public class SecurityConfig {
|
||||
}
|
||||
|
||||
return http
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers("/mcp/messages", "/mcp/*/messages"))
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers(
|
||||
"/mcp/messages", "/mcp/*/messages", "/dds/mcp/messages"))
|
||||
.headers(headers -> headers.httpStrictTransportSecurity(hsts -> hsts
|
||||
.includeSubDomains(true)
|
||||
.maxAgeInSeconds(31_536_000)))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/css/**", "/js/**", "/webjars/**").permitAll()
|
||||
.requestMatchers("/css/**", "/js/**", "/webjars/**", "/dds/mcp/sse", "/dds/mcp/messages")
|
||||
.permitAll()
|
||||
.anyRequest().authenticated())
|
||||
.httpBasic(basic -> {
|
||||
})
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.cloudhandson.vpdbackoffice.service;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Keeps the shared user/role/permission services independent from the DDS app.
|
||||
* The normal VPD application has no synchronizer. The DDS application provides
|
||||
* one and receives the change before the management request returns.
|
||||
*/
|
||||
@Service
|
||||
public class DdsAuthorizationChangeNotifier {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DdsAuthorizationChangeNotifier.class);
|
||||
private final ObjectProvider<DdsAuthorizationSynchronizer> synchronizer;
|
||||
|
||||
public DdsAuthorizationChangeNotifier(ObjectProvider<DdsAuthorizationSynchronizer> synchronizer) {
|
||||
this.synchronizer = synchronizer;
|
||||
}
|
||||
|
||||
private DdsAuthorizationChangeNotifier() {
|
||||
this.synchronizer = null;
|
||||
}
|
||||
|
||||
public static DdsAuthorizationChangeNotifier noop() {
|
||||
return new DdsAuthorizationChangeNotifier();
|
||||
}
|
||||
|
||||
public void changed(String reason) {
|
||||
if (synchronizer != null) {
|
||||
log.info("DDS authorization change published: {}", reason);
|
||||
synchronizer.ifAvailable(target -> target.synchronize(reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.cloudhandson.vpdbackoffice.service;
|
||||
|
||||
/** Optional bridge implemented only by the dedicated DDS application. */
|
||||
public interface DdsAuthorizationSynchronizer {
|
||||
|
||||
void synchronize(String reason);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.cloudhandson.vpdbackoffice.domain.group.GroupRoleView;
|
||||
import com.cloudhandson.vpdbackoffice.domain.group.GroupUserView;
|
||||
import com.cloudhandson.vpdbackoffice.mapper.GroupMapper;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -15,10 +16,21 @@ public class GroupService {
|
||||
|
||||
private final GroupMapper groupMapper;
|
||||
private final AuditService auditService;
|
||||
private final DdsAuthorizationChangeNotifier ddsAuthorizationChangeNotifier;
|
||||
|
||||
public GroupService(GroupMapper groupMapper, AuditService auditService) {
|
||||
@Autowired
|
||||
public GroupService(
|
||||
GroupMapper groupMapper,
|
||||
AuditService auditService,
|
||||
DdsAuthorizationChangeNotifier ddsAuthorizationChangeNotifier
|
||||
) {
|
||||
this.groupMapper = groupMapper;
|
||||
this.auditService = auditService;
|
||||
this.ddsAuthorizationChangeNotifier = ddsAuthorizationChangeNotifier;
|
||||
}
|
||||
|
||||
public GroupService(GroupMapper groupMapper, AuditService auditService) {
|
||||
this(groupMapper, auditService, DdsAuthorizationChangeNotifier.noop());
|
||||
}
|
||||
|
||||
public List<AppGroup> findAll() {
|
||||
@@ -38,6 +50,7 @@ public class GroupService {
|
||||
long groupId = groupMapper.nextGroupId();
|
||||
groupMapper.insertGroup(groupId, command);
|
||||
auditService.record(new AuditEvent("GROUP_CREATED", null, null, "SUCCESS", null, null, command.groupCode()));
|
||||
ddsAuthorizationChangeNotifier.changed("GROUP_CREATED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -56,6 +69,7 @@ public class GroupService {
|
||||
}
|
||||
auditService.record(new AuditEvent("GROUP_ACTIVE_CHANGED", null, null, "SUCCESS", null, null,
|
||||
"groupId=" + groupId + ",active=" + active));
|
||||
ddsAuthorizationChangeNotifier.changed("GROUP_ACTIVE_CHANGED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -63,6 +77,7 @@ public class GroupService {
|
||||
groupMapper.insertGroupUser(groupId, userId);
|
||||
auditService.record(new AuditEvent("GROUP_USER_ADDED", null, null, "SUCCESS", null, null,
|
||||
"groupId=" + groupId + ",userId=" + userId));
|
||||
ddsAuthorizationChangeNotifier.changed("GROUP_USER_ADDED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -81,6 +96,7 @@ public class GroupService {
|
||||
}
|
||||
auditService.record(new AuditEvent("GROUP_USER_REMOVED", null, null, "SUCCESS", null, null,
|
||||
"groupId=" + groupId + ",userId=" + userId));
|
||||
ddsAuthorizationChangeNotifier.changed("GROUP_USER_REMOVED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -88,6 +104,7 @@ public class GroupService {
|
||||
groupMapper.insertGroupRole(groupId, roleId);
|
||||
auditService.record(new AuditEvent("GROUP_ROLE_ADDED", null, null, "SUCCESS", null, null,
|
||||
"groupId=" + groupId + ",roleId=" + roleId));
|
||||
ddsAuthorizationChangeNotifier.changed("GROUP_ROLE_ADDED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -106,5 +123,6 @@ public class GroupService {
|
||||
}
|
||||
auditService.record(new AuditEvent("GROUP_ROLE_REMOVED", null, null, "SUCCESS", null, null,
|
||||
"groupId=" + groupId + ",roleId=" + roleId));
|
||||
ddsAuthorizationChangeNotifier.changed("GROUP_ROLE_REMOVED");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -32,15 +33,27 @@ public class PermissionService {
|
||||
private final PermissionMapper permissionMapper;
|
||||
private final ProtectedObjectService protectedObjectService;
|
||||
private final AuditService auditService;
|
||||
private final DdsAuthorizationChangeNotifier ddsAuthorizationChangeNotifier;
|
||||
|
||||
@Autowired
|
||||
public PermissionService(
|
||||
PermissionMapper permissionMapper,
|
||||
ProtectedObjectService protectedObjectService,
|
||||
AuditService auditService,
|
||||
DdsAuthorizationChangeNotifier ddsAuthorizationChangeNotifier
|
||||
) {
|
||||
this.permissionMapper = permissionMapper;
|
||||
this.protectedObjectService = protectedObjectService;
|
||||
this.auditService = auditService;
|
||||
this.ddsAuthorizationChangeNotifier = ddsAuthorizationChangeNotifier;
|
||||
}
|
||||
|
||||
public PermissionService(
|
||||
PermissionMapper permissionMapper,
|
||||
ProtectedObjectService protectedObjectService,
|
||||
AuditService auditService
|
||||
) {
|
||||
this.permissionMapper = permissionMapper;
|
||||
this.protectedObjectService = protectedObjectService;
|
||||
this.auditService = auditService;
|
||||
this(permissionMapper, protectedObjectService, auditService, DdsAuthorizationChangeNotifier.noop());
|
||||
}
|
||||
|
||||
public List<AppRole> findRoles() {
|
||||
@@ -64,6 +77,7 @@ public class PermissionService {
|
||||
long roleId = permissionMapper.nextRoleId();
|
||||
permissionMapper.insertRole(roleId, roleName.trim(), description, normalizeSensitivityLevel(maxSensitivityLevel));
|
||||
auditService.record(new AuditEvent("ROLE_CREATED", null, null, "SUCCESS", null, null, roleName));
|
||||
ddsAuthorizationChangeNotifier.changed("ROLE_CREATED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -75,6 +89,7 @@ public class PermissionService {
|
||||
}
|
||||
auditService.record(new AuditEvent("ROLE_MAX_SENSITIVITY_UPDATED", null, null, "SUCCESS", null, null,
|
||||
"roleId=" + roleId + ", max=" + normalized));
|
||||
ddsAuthorizationChangeNotifier.changed("ROLE_MAX_SENSITIVITY_UPDATED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -100,6 +115,7 @@ public class PermissionService {
|
||||
throw new AppException("삭제할 역할을 찾을 수 없습니다.");
|
||||
}
|
||||
auditService.record(new AuditEvent("ROLE_DELETED", null, null, "SUCCESS", null, null, "roleId=" + roleId));
|
||||
ddsAuthorizationChangeNotifier.changed("ROLE_DELETED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -148,6 +164,7 @@ public class PermissionService {
|
||||
"PERMISSION_SAVED", null, command.objectId(), "SUCCESS", null, null,
|
||||
"roleId=" + command.roleId()
|
||||
));
|
||||
ddsAuthorizationChangeNotifier.changed("PERMISSION_SAVED");
|
||||
return new PermissionSet(permissionId, command.roleId(), command.objectId(), "SELECT", permissionEffect, List.of(), List.of());
|
||||
}
|
||||
|
||||
@@ -173,6 +190,7 @@ public class PermissionService {
|
||||
}
|
||||
auditService.record(new AuditEvent("PERMISSION_DELETED", null, null, "SUCCESS", null, null,
|
||||
"permissionId=" + permissionId));
|
||||
ddsAuthorizationChangeNotifier.changed("PERMISSION_DELETED");
|
||||
}
|
||||
|
||||
public int countPermissionsByObjectId(long objectId) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.cloudhandson.vpdbackoffice.domain.user.UserCreateCommand;
|
||||
import com.cloudhandson.vpdbackoffice.domain.user.UserRoleView;
|
||||
import com.cloudhandson.vpdbackoffice.mapper.UserMapper;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -14,10 +15,21 @@ public class UserService {
|
||||
|
||||
private final UserMapper userMapper;
|
||||
private final AuditService auditService;
|
||||
private final DdsAuthorizationChangeNotifier ddsAuthorizationChangeNotifier;
|
||||
|
||||
public UserService(UserMapper userMapper, AuditService auditService) {
|
||||
@Autowired
|
||||
public UserService(
|
||||
UserMapper userMapper,
|
||||
AuditService auditService,
|
||||
DdsAuthorizationChangeNotifier ddsAuthorizationChangeNotifier
|
||||
) {
|
||||
this.userMapper = userMapper;
|
||||
this.auditService = auditService;
|
||||
this.ddsAuthorizationChangeNotifier = ddsAuthorizationChangeNotifier;
|
||||
}
|
||||
|
||||
public UserService(UserMapper userMapper, AuditService auditService) {
|
||||
this(userMapper, auditService, DdsAuthorizationChangeNotifier.noop());
|
||||
}
|
||||
|
||||
public List<AppUser> findAll() {
|
||||
@@ -33,6 +45,7 @@ public class UserService {
|
||||
long userId = userMapper.nextUserId();
|
||||
userMapper.insertUser(userId, command);
|
||||
auditService.record(new AuditEvent("USER_CREATED", null, null, "SUCCESS", null, null, command.username()));
|
||||
ddsAuthorizationChangeNotifier.changed("USER_CREATED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -43,6 +56,7 @@ public class UserService {
|
||||
}
|
||||
auditService.record(new AuditEvent("USER_ACTIVE_CHANGED", null, null, "SUCCESS", null, null,
|
||||
"userId=" + userId + ",active=" + active));
|
||||
ddsAuthorizationChangeNotifier.changed("USER_ACTIVE_CHANGED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -50,6 +64,7 @@ public class UserService {
|
||||
userMapper.insertUserRole(userId, roleId);
|
||||
auditService.record(new AuditEvent("USER_ROLE_GRANTED", null, null, "SUCCESS", null, null,
|
||||
"userId=" + userId + ",roleId=" + roleId));
|
||||
ddsAuthorizationChangeNotifier.changed("USER_ROLE_GRANTED");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -60,5 +75,6 @@ public class UserService {
|
||||
}
|
||||
auditService.record(new AuditEvent("USER_ROLE_REVOKED", null, null, "SUCCESS", null, null,
|
||||
"userId=" + userId + ",roleId=" + roleId));
|
||||
ddsAuthorizationChangeNotifier.changed("USER_ROLE_REVOKED");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user