2016-10-12 4 views
2

Когда первая запущенная информация представляет собой инъекцию ExecutorService, Принцип безопасности правильно установлен для этой runnable. Каждому впоследствии представленному runnable предоставляется руководитель безопасности оригинального пользователя, а не текущий текущий runnable. Моя машина разработки работает 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 
    } 
    ... 
} 

Ниже мой 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); 
     .... 
    } 
} 

Ниже приведен код из Stateless Bean, который вызывается с помощью REST конечной точки, которая стартует процесс

@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 -> ProjectService.performAsynchAction(...) 
     -> reportingService.registerTask(...) 
     -> create CDI injected Runnable 
     -> submit runner to executor service 
      -> ExecutorService calls Runner.run() 
       -> rs.startTask(taskId) 

Я вызываю конечную точку Rest как user1 в первый раз и регистрирую задачи: 1-2. Все они работают так, как ожидалось, и я получаю следующий вывод в своем журнале.

Created runner. Principal: user1 
Created runner. Principal: user1 
Inside Runner Current User: user1 
Inside Runner Current User: user1 

В следующий раз, когда я сделать то же самое REST вызов, как user2 и я получаю следующий результат в журнале

Created runner. Principal: user2 
Inside Runner Current User: user1 
EJBAccessException Current user user1 did not register task 

Представляется, что Принципал Безопасность Runnable правильно установить в первый раз Runnable передается в ExecutorService. Но для каждого последующего Runneable, представленного в ExecutorService, используется Принцип безопасности первой представленной runnable. Это ошибка или предполагаемое поведение? Кто-нибудь знает о потенциальной работе?

EDIT: Я понимаю, что проект дикобраза, который я использовал для создания ExecutorService, не управлялся контейнером. Когда я переключился на ManagedExecutorService, SessionContext был правильно размножен.

@Resource(lookup = "java:jboss/ee/concurrency/executor/customExecutor") 
private ManagedExecutorService es; 
+1

Вы знаете, откуда уходит ваш currentUser? 'SessionContext' или' Principal'? – flo

+0

Оказывается, что оба они вводятся, и оба они имеют неправильное значение как в Runnable, так и в сервисе для второго вызова. – Mike

ответ

1

Я понял вопрос. Я заглянул в код дикобраза и узнал, что Контейнер не управляет ExecutorService. Я создал диспетчер ManagerExecutorService, а SessionContext был правильно проповедён.

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

Я думаю, что проблема в том, что вы @Inject@Dependent область действия ExecutorService в @Stateless боба.
@Stateless бобы могут быть объединены и повторно использованы, в то время как @Dependent CDI-бобы хранятся по ссылке и поэтому не воссоздаются, когда используется фасоль @Stateless.

Не зная о реализации вашего ExecutorService, я предполагаю, что он создает контекстные потоки во время первого запуска и повторно использует их во втором прогоне без корректировки контекста.

Вы можете «заставить» ваше ProjectService создать новый ExecutorService инкапсулируя его в @RequestScoped боба:

@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, так и в Принципале – Mike

Смежные вопросы