첫 번째 실행 파일이 제출되면 ExecutorService가 삽입 될 때 보안 주체가 해당 실행 파일에 대해 올바르게 설정됩니다. 이후에 제출 된 각 실행 파일에는 현재 실행 파일을 유지하는 대신 원래 사용자의 보안 사용자가 제공됩니다. 내 개발 컴퓨터에서 Wildfly 8.2가 실행 중입니다.ExecutorService가 Runnable의 보안 주체를 오버라이드하지 못하도록하는 방법
비동기 처리를위한보고 시스템을 만들고 있습니다. 어떤 사용자가 작업을 생성했는지 확인하고 해당 사용자 만 작업을 시작하거나 완료 할 수 있는지 확인하는 서비스를 만들었습니다. 서비스 코드는 다음과 같습니다. 다음은
@Stateless
public class ReportingService {
//EE injection security context
@Resource
SessionContext context;
//CDI security Principal
@Inject
Principal principal;
//this method handles getting the username for EE injection or CDI
private String getCurrentUser() {
if (context != null) {
return context.getCallerPrincipal().getName();
}
if (principal != null) {
return principal.getName();
}
return null;
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Transactional
public void registerTask(String taskId) {
//Create task
//set task.submittedBy = getCurrentUser()
//persist task
//code has been omitted since it is working
}
private void validateCurrentUserRegisteredJob(String taskId) {
String user = //get user that created task with id = id from DB
String currentUser = getCurrentUser();
if (!user.equals(currentUser)) {
throw new EJBAccesException("Current user "+currentUser+" did not register task");
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Transactional
public void startTask(String taskId) {
validateCurrentUserRegisteredJob(taskid);
//retrieve task entity, set start time to now, and merge
}
...
}
다음은 다음 과정
@Stateless
public ProjectService() {
@Inject
Instance<TaskRunner> taskRunner;
@Inject
ReportingService reportingService;
//ExecutorService that is create from Adam Bien's porcupine project
@Inject
@Dedicated
ExecutorService es;
//method that is called by rest enpoint to kick off
public void performAsynchAction(List<String> taskIds, ...rest of args...) {
taskIds.stream().forEach(t -> {
//registers task with user that made REST call
reportingService.registerTask(t);
TaskRunner runner = taskRunner.get();
runner.setTaskId(t);
log.debug("Created runner. Principal: "+runner.principal.getName());
es.submit(runner);
});
}
}
을 맞이할 수있는 REST 엔드 포인트에 의해 호출되는 비 저장 빈의 코드 내 Runnable를 코드
public TaskRunner() implements Runnable {
//CDI principal
@Inject
Principal principal;
@Inject
ReportingService rs;
private taskId;
public void setTaskId() {...}
public void run() {
log.debug("Inside Runner Current User: "+principal.getName());
rs.startTask(taskId);
....
}
}
입니다 통화 흐름 차트
REST -> ProjectService.performAsynchAction(...)
-> reportingService.registerTask(...)
-> create CDI injected Runnable
-> submit runner to executor service
-> ExecutorService calls Runner.run()
-> rs.startTask(taskId)
나는 Rest1을 처음으로 user1로 호출하고 작업을 등록합니다 : 1-2. 모두 예상대로 작동하며 로그에 다음과 같은 결과가 표시됩니다.
Created runner. Principal: user1
Created runner. Principal: user1
Inside Runner Current User: user1
Inside Runner Current User: user1
나도 같은 REST 호출로 사용자 2하고 난의 Runnable의 보안 사용자가 올바르게 처음 A를 설정되어 있는지 로그
Created runner. Principal: user2
Inside Runner Current User: user1
EJBAccessException Current user user1 did not register task
이 나타납니다에서 다음과 같은 출력을 얻을 다음에 Runnable가 ExecutorService에 제출됩니다. 그러나 ExecutorService에 제출 된 각 후속 Runneable에 대해 첫 번째 제출 된 실행 가능 개체의 보안 사용자를 사용합니다. 이것은 버그입니까, 의도 한 행동입니까? 누구든지 잠재적 인 해결 방법을 알고 있습니까?
편집 : 나는 ExecutorService를 생성하기 위해 사용했던 고슴 식물 프로젝트가 컨테이너에 의해 관리되지 않았다는 것을 알아 낸다. 일단 ManagedExecutorService로 전환하면 SessionContext가 제대로 전파되고 있습니다.
@Resource(lookup = "java:jboss/ee/concurrency/executor/customExecutor")
private ManagedExecutorService es;
현재 사용자의 정확한 위치를 알고 있습니까? 'SessionContext' 또는'Principal'? – flo
둘 다 주입되는 것으로 밝혀졌으며 둘 다 Runnable과 두 번째 호출 서비스에서 잘못된 값을 갖습니다. – Mike