2016-10-12 1 views
2

첫 번째 실행 파일이 제출되면 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; 
+1

현재 사용자의 정확한 위치를 알고 있습니까? 'SessionContext' 또는'Principal'? – flo

+0

둘 다 주입되는 것으로 밝혀졌으며 둘 다 Runnable과 두 번째 호출 서비스에서 잘못된 값을 갖습니다. – Mike

답변

1

:

당신은 당신의 ProjectService@RequestScoped 콩으로 캡슐화하여 새 ExecutorService를를 만드는 "강제"할 수있다. 나는 고슴도치 코드를 조사해 보았고 ExecutorService가 컨테이너에 의해 관리되지 않는다는 것을 알아 냈습니다. ManagerExecutorService를 만들었고 SessionContext가 올바르게 전파되었습니다.

@Resource(lookup = "java:jboss/ee/concurrency/executor/customExecutor") 
private ManagedExecutorService es_; 
0

당신 @Inject@Dependent@Stateless 콩에 ExecutorService를 범위 것을, 문제라고 생각합니다.
@Stateless 빈은 풀링되고 재사용 될 수 있지만 @Dependent CDI 빈은 참조로 저장되므로 @Stateless 빈이 재사용 될 때 재 작성되지 않습니다.

ExecutorService의 구현을 모르는 상태에서 처음 실행하는 동안 상황에 맞는 스레드를 만들고 두 번째 실행에서 상황을 조정하지 않고 다시 사용했다고 생각합니다. 내가 문제를 파악

@RequestScoped 
public class ESHolder { 
    @Inject 
    @Dedicated 
    ExecutorService eS; 

    public ExecutorService getES() { 
     return eS; 
    } 
} 


@Stateless 
public ProjectService() { 
    // ... 

    @Inject   
    ESHolder esHolder; 

    public void performAsynchAction(List<String> taskIds, ...rest of args...) { 
     taskIds.stream().forEach(t -> { 
      // ... 

      esHolder.getES().submit(runner); 
     }); 
    } 
} 
+0

나는 이것을 시도했다. 나는 아직도 주입 된 SessionContext와 Principal 모두에서 잘못된 주체를 얻고있다. – Mike

관련 문제