Spring Jobrunr: No qualifying bean of type DelegatingSecurityContextRunnable available

241 Views Asked by At

I have an AuthorizationComponent that allows me to check my user's roles. I use it in the methods of my various services.

Now, I try to create a job (using Jobrunr) that @Autowired one of these services, but it crashes because the SecurityContextHolder.getContext() is null.

So I'm trying to apply the answer I got here. Only, when I use DelegatingSecurityContextRunnable and my job is run, I get the following stacktrace:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.concurrent.DelegatingSecurityContextRunnable' available
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) ~[spring-beans-5.3.23.jar:5.3.23]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) ~[spring-beans-5.3.23.jar:5.3.23]
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172) ~[spring-context-5.3.23.jar:5.3.23]
        at org.jobrunr.server.runner.BackgroundJobWithIocRunner.supports(BackgroundJobWithIocRunner.java:21) ~[jobrunr-6.1.4.jar:6.1.4]
        at org.jobrunr.server.BackgroundJobServer.lambda$getBackgroundJobRunner$0(BackgroundJobServer.java:224) ~[jobrunr-6.1.4.jar:6.1.4]
        at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:176) ~[?:?]
        at java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:958) ~[?:?]
        at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127) ~[?:?]
        at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502) ~[?:?]
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488) ~[?:?]
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[?:?]
        at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) ~[?:?]
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
        at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543) ~[?:?]
        at org.jobrunr.server.BackgroundJobServer.getBackgroundJobRunner(BackgroundJobServer.java:225) ~[jobrunr-6.1.4.jar:6.1.4]
        at org.jobrunr.server.BackgroundJobPerformer.runActualJob(BackgroundJobPerformer.java:88) ~[jobrunr-6.1.4.jar:6.1.4]
        at org.jobrunr.server.BackgroundJobPerformer.performJob(BackgroundJobPerformer.java:64) ~[jobrunr-6.1.4.jar:6.1.4]
        at org.jobrunr.server.BackgroundJobPerformer.run(BackgroundJobPerformer.java:42) ~[jobrunr-6.1.4.jar:6.1.4]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
        at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
        at java.lang.Thread.run(Thread.java:829)

Here's some code to give you some context:


Authorization component:

@Component
public class AuthorizationComponent {
    public SecurityContext getSecurityContext() {
        return SecurityContextHolder.getContext();
    }

    public Authentication getAuthentication() {
        return this.getSecurityContext().getAuthentication();
    }

    public CustomUserDetails getUser() {
        return (CustomUserDetails) this.getAuthentication().getPrincipal();
    }

    public boolean hasAnyRole(ERole...roles) {
        return this.getAuthentication().getAuthorities().stream()
            .anyMatch(grantedAuthority -> Arrays.stream(roles)
                .map(Enum::toString)
                .collect(Collectors.toList())
                .contains(grantedAuthority.getAuthority())
            );
    }

    public boolean hasSuperAdminRights() {
        return this.hasAnyRole(ERole.ROLE_ADMIN);
    }

    public boolean hasAdminRights() {
        return this.hasAnyRole(ERole.ROLE_ADMIN, ERole.ROLE_HR);
    }
}

Jobrunr job :

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class InactiveUsersEmail implements JobRequest {
    private Integer userId;

    @Override
    public Class<InactiveUsersEmailHandler> getJobRequestHandler() {
        return InactiveUsersEmailHandler.class;
    }
}

Define the recurring job:

@Service
@Transactional
@RequiredArgsConstructor
public class RecurringJobService {
    private final AuthorizationComponent authorizationComponent;

    @Recurring(id = "inactive-users-email", cron = "0 5 * * *")
    @Job(name = "Sends email to inactive users")
    public void sendInactiveUsersEmail() {
        // for this example, only send user id 1
        Runnable task = () -> new InactiveUsersEmail(1);
        DelegatingSecurityContextRunnable securedTask = new DelegatingSecurityContextRunnable(task, this.authorizationComponent.getSecurityContext());
        BackgroundJob.enqueue(securedTask::run);
    }
0

There are 0 best solutions below