Add #PreAuthorize role for spring schedule job - java

In my Backend, I have added #PreAuthorize("hasRole('ROLE_ADMIN') to allow user to access the functions in service layer. And now I would like to use my schedule job (springframework scheduling) to access these service but obviously it can not. My question is how can I add ROLE_ADMIN role or generate a user principal for the schedule job?
#PreAuthorize("hasRole('ROLE_ADMIN')")
JsonNode loadSMS(String additionalPath) {
.....
}

Either have another method not annotated with the #PreAuthorize which your scheduler calls. Move the implementation into this new method, and change the existing loadSMS to use this new method to reduce code duplication. Otherwise you could add a role at runtime, but I don't think that is such a great idea.

You can try below code
#Service
class SchedulerService {
#Autowired
private YourService service;
#Scheduled(fixedRate = 600000L, initialDelay = 60000L)
public void executeTask() throws IOException {
RunAs.runAsAdmin(() -> {
service.loadSMS(String additionalPath) {
});
}
}
public class RunAs {
#FunctionalInterface
public interface RunAsMethod {
default void run() {
try {
runWithException();
} catch (Exception e) {
}
}
void runWithException() throws Exception;
}
public static void runAsAdmin(final RunAsMethod func) {
final AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("adminUser", "adminPassword",
ImmutableList.of(new SimpleGrantedAuthority("ROLE_ADMIN")));
final Authentication originalAuthentication = SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder.getContext().setAuthentication(token);
func.run();
SecurityContextHolder.getContext().setAuthentication(originalAuthentication);
}
}

Related

Run a process asynchronously after completion of initial process in Spring boot

I have a requirement. I have 2 processes
Contact creation and
Associating contact to the Department
Currently I have a spring boot API which has a REST POST call to perform both in one thread. Since process 2 is taking more time I wanted to run that in the
background immediately after finishing the step 1.
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
try {
response = myService.processPayload(payload);
} catch (Exception e) {
logger.error("Exception in the controller");
}
return response;
}
I want to return the response to the user as soon as step 1 is done and performing step 2 at the background. How do I achieve that
Thanks in advance
In your main class, or a #Configuration class, use #EnableAsync to bootstrap a thread pool:
#EnableAsync
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
You can optionally set Thread Pool properties under spring.task.execution.pool property. Example:
spring:
task:
execution:
pool:
core-size: 8
max-size 16
Here's a stack post detailing what each property means: Core pool size vs maximum pool size in ThreadPoolExecutor
Inside your controller:
#RestController
public class TestController {
private final ContactService contactService;
private final DepartmentService departmentService;
// Constructor Injection
public TestController(ContactService contactService, DepartmentService departmentService) {
this.contactService = contactService;
this.departmentService = departmentService;
}
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
List<Contact> contacts = contactService.processPayload(payload);
departmentService.associateContacts(contacts); // This is an asynchronous call
return ResponseEntity.ok(new PayloadResponse(contacts));
}
}
I've removed the try/catch from the controller method since error handling is a cross cutting concern and is handled by AOP. More on that here: Baeldung
And finally in your DepartmentService, you use the #Async annotation to turn it into an asynchronous method:
#Service
public class DepartmentService {
#Async
public void associateContacts(List<Contact> contacts) {
// method
}
}
I see other answers are basically saying the same thing and are correct, but not complete so I felt the need to put everything together for you.
Spring framework provides support for asynchronous processing out of the box. Spring can create & manage threads for us by providing support for various TaskExecutor abstraction.
We can create a method in a new class that will do the second process (associate contact to the Department) and annotate that method with #Aysnc. The annotation ensures the spring executes this method as a Runnable/Future depending on return type.
Sample Implementation (We have to add #EnableAsync in any of our configuration class)
#Component
class ContactManager {
#Async
public void associateContactToDepartment(){
//method implementation goes here
}
}
class MyService {
#Autowired
private ContactManager contactManager;
public PayloadResponse processPayload(String payload){
payloadResponse payloadResponse = createContact();//first process
contactManager.associateContactToDepartment() // this call will be executed asynchronously.
return payloadResponse;
}
}
Refer this for quick intro to async methods.
Follow the below steps:
Add #EnableAsync annotation and Add TaskExecutor Bean to main spring boot application class
#SpringBootApplication
#EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(SpringBootApplication.class);
#Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootApplication.class,args);
}
Add the contact to department method as below:
#Service
public class DepartmentProcess {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
#Async("processExecutor")
#Override
public void processDepartment() {
logger.info("Received request to process in DepartmentProcess.processDepartment()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
Call the method from the controller as below:
#PostMapping(value = "/processDeptContact", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PayloadResponse> processDeptContact(#RequestBody String payload) {
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
try {
response = myService.processPayload(payload);
myService.processDepartment();//async method
} catch (Exception e) {
logger.error("Exception in the controller");
}
return response;
}
Points 1 and 2 are not here but it doesn't matter, let's call them foo1() and foo2().
In myService.processPayload() you want to do:
ResponseEntity result = foo1();
Runnable runnable = () -> {
foo2()
};
Thread thread = new Thread(runnable);
thread.start(); // the logic in foo2 will happen in a background thread so it will not block on this line, consider using a thread pool instead
return result;
BTW, this sounds like premature optimization and you should think about race conditions with parallel threads but this is not what the question was asking.
One more thing, move this to the catch because it's a waste of instantiations if the try will succeed, which should happen most of the time.
ResponseEntity response = new ResponseEntity(new ErrorResponse("Exception"),
new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);

Spring-retry #Recover method works only in interface definition

I'm using spring-retry to provide retry policy for my business logic. I have Interface and the service that implements it
public interface MyInterface {
#Retryable(maxAttempts = 5, backoff = #Backoff(value = 0L))
void doSth() throws Exception;
#Recover
void recoverIfFailed(Exception e);
}
#Service
public class MyService implements MyInterface {
public void doSth() throws Exception {
throw new Exception();
}
public void recoverIfFailed(Exception e) {
System.out.println("Recovered!");
}
}
and in this configuration everything working fine. However I cannot understand why I mustn't move #Recovery annotation to the interface implementation like this:
#Service
public class MyService implements MyInterface {
#Retryable(maxAttempts = 5, backoff = #Backoff(value = 0L)) // -- this is working
public void doSth() throws Exception {
throw new Exception();
}
#Recover // -- this is not working!
public void recoverIfFailed(Exception e) {
System.out.println("Recovered!");
}
}
I really would like to not expose my recovery method in the interface (as it seems to be my internal logic) but I cannot due to this issue. Can anyone advise what can be an issue?
I submitted an open pull request to fix this.
As a work-around, use #EnableRetry(proxyTargetClass = true).

Spring Boot REST - requests are not executing with ThreadPoolTaskExecutor configuration

I am trying to develop a spring boot app. I have written all core implementations in core java without spring framework. I am using that jar in this spring boot app. I would like to manage the concurrency of my rest controller. So, configured ThreadPoolTaskExecutor accordingly in the main class. Ideally, I want only 2 concurrent requests to get into the execute() method, which I annotated Async. I was testing for 2 concurrent requests at a time but I see in the log that my requests are entering execute() all at once. All the tasks are memory intensive. So those are failing with heap memory issues. I am trying to figure out the ideal concurrency number. I would like to know if my configuration is correct or am I missing something? Thank you.
Here's my main class:
#SpringBootApplication
#EnableAsync
public class RestapiApplication implements AsyncConfigurer {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(RestapiApplication.class, args);
System.out.println("Rightdata Middleware ready to accept requests:");
}
#Bean(name = "executor1")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(2);
taskExecutor.setCorePoolSize(2);
taskExecutor.setThreadNamePrefix("LULExecutor-");
taskExecutor.setQueueCapacity(100);
taskExecutor.initialize();
return taskExecutor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
And here's my REST controller:
#RestController
#RequestMapping("/end2end")
public class End2EndRestController {
/**
* The log.
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
#RequestMapping(method = RequestMethod.POST)
public JSONObjectPOJO process(#RequestBody String end2EndScenarioString) throws InterruptedException, ExecutionException {
final JSONObjectPOJO jsonObjectPOJO = convertToJavaObject(end2EndScenarioString);
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
try {
execute(jsonObjectPOJO);
} catch (Exception e) {
e.getMessage();
}
}});
executor.shutdown();
return jsonObjectPOJO;
}
#Async("executor1")
private void execute(JSONObjectPOJO jsonObjectPOJO) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<?> futureTarget;
Future<?> futureSource;
futureSource = processSource(executorService);
futureTarget = processTarget(executorService);
manageSourceProcessingResults(futureSource);
manageTargetProcessingResults(futureTarget);
executorService.shutdown();
//Do rest of the tasks.
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processSource(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureSource = executorService.submit(coreActionClass);
return futureSource;
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processTarget(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureTarget = executorService.submit(coreActionClass); //callable method in core.
return futureTarget;
}
private void manageSourceProcessingResults(Future<?> futureSource) {
try{
futureSource.get();
} catch(Exception e){
e.printStackTrace();
}
}
private void manageTargetProcessingResults(Future<?> futureTarget) {
try{
futureTarget.get();
} catch(Exception e){
e.printStackTrace();
}
}
}
UPDATE- 1:
I have now changed the code to following:
#RestController
#RequestMapping("/end2end")
public class End2EndRestController {
/**
* The log.
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
#RequestMapping(method = RequestMethod.POST)
public JSONObjectPOJO process(#RequestBody String end2EndScenarioString) throws InterruptedException, ExecutionException {
final JSONObjectPOJO jsonObjectPOJO = convertToJavaObject(end2EndScenarioString);
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
try {
execute(jsonObjectPOJO);
} catch (Exception e) {
e.getMessage();
}
}});
executor.shutdown();
return jsonObjectPOJO;
}
}
And AsyncService class:
public class AsyncService {
#Async("executor1")
public void execute(JSONObjectPOJO jsonObjectPOJO) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<?> futureTarget;
Future<?> futureSource;
futureSource = processSource(executorService);
futureTarget = processTarget(executorService);
manageSourceProcessingResults(futureSource);
manageTargetProcessingResults(futureTarget);
executorService.shutdown();
//Do rest of the tasks.
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processSource(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureSource = executorService.submit(coreActionClass);
return futureSource;
}
#SuppressWarnings({"unchecked", "rawtypes"})
protected Future<?> processTarget(executorService){
//Get appropriate class instance with call() - coreActionClass.
Future<?> futureTarget = executorService.submit(coreActionClass); //callable method in core.
return futureTarget;
}
private void manageSourceProcessingResults(Future<?> futureSource) {
try{
futureSource.get();
} catch(Exception e){
e.printStackTrace();
}
}
private void manageTargetProcessingResults(Future<?> futureTarget) {
try{
futureTarget.get();
} catch(Exception e){
e.printStackTrace();
}
}
}
My understanding is that when I configure maxpoolsize(2) no more
than 2 requests would be in the execute() method at one time. For a
new request to enter, one of the earlier requests has to complete
its execution. Is my understanding correct? Would the async apply
to the inner executor service?
I am of the view that at one time only 2 requests are handled and
each of those requests can spawn 2 different threads and complete
its task. Please clarify.
I see two problems.
1) In your process method you are creating a new ExecutorService. This is not needed. Instead just call the execute method after the jsonObjectPOJO is retrieved.
2) You cannot use #Async int he same class that it is implemented. You'll need to create a new class, lets called MyAsyncService to contain the #Async method. This is because of the aspect orientated programming that is going on under the covers.
Check out this link for more info. Below is a quote from the link.
First – let’s go over the rules – #Async has two limitations:
it must be applied to public methods only
self-invocation – calling the async method from within the same class – won’t work
The reasons are simple – the method needs to be public so that it can be proxied. And self-invocation doesn’t work because it bypasses the proxy and calls the underlying method directly.
EDIT 1:
#RestController
#RequestMapping("/end2end")
public class End2EndRestController {
#AutoWired
AsyncService asyncService;
private final Logger log = LoggerFactory.getLogger(this.getClass());
#RequestMapping(method = RequestMethod.POST)
public JSONObjectPOJO process(#RequestBody String end2EndScenarioString) throws InterruptedException, ExecutionException {
final JSONObjectPOJO jsonObjectPOJO = convertToJavaObject(end2EndScenarioString);
asyncService.execute(jsonObjectPOJO);
return jsonObjectPOJO;
}
public class AsyncService {
#Async("executor1")
public void execute(JSONObjectPOJO jsonObjectPOJO) throws Exception {
//No Futures, no ExecutorServices, just process that request.
}
}
By creating and configuring the ThreadPoolTaskExecutor to use only 2 threads, you have accomplished your goal.
EDIT2: Spring #Async limit number of threads

What Jersey security annotation can be used to permit anonymous only access to an endpoint?

I have a registration endpoint that I only want anonymous users to be able to access. In other words, I only want non-authenticated users to be able to POST to the endpoint. What is the best way to go about doing this?
#Path("/accounts")
public class AccountResource {
#Inject
private AccountService accountService;
#DenyAll
#POST
public void register(CreateAccountJson account) {
try {
accountService.registerUserAndCreateAccount(account.getEmail(),
account.getPassword());
} catch (RegistrationException e) {
throw new BadRequestException(e.getMessage());
}
}
}
There's no such annotation. This use case doesn't really fit into the semantics of authorization. One work around you can use is to inject the SecurityContext. Just check if there is a Principal. If not, then there is no authenticated user. If there is, then you could just send a 404
#POST
public void register(#Context SecurityContext context, CreateAccountJson account) {
if (context.getUserPrincipal() != null) {
throw new NotFoundException();
}
...
}
UPDATE
If you have a lot of resource methods like this, it might be better to use a filter that is name bound. For example
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface NonAuthenticated {}
#NonAuthenticated
// Perform before normal authorization filter
#Priority(Priorities.AUTHORIZATION - 1)
public class NonAuthenticatedCheckFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext request) {
final SerurityContext context = request.getSecurityContext();
if (context.getUserPrincipal() != null) {
throw new ForbiddenException();
}
}
}
#POST
#NonAuthenticated
public void register(CreateAccountJson account) { }
// register the Dw
environment.jersey().register(NonAuthenticatedCheckFilter.class);
For more information on Jersey filters see Filter and Interceptors from Jersey docs.

Query tables across multiple tenants (same table name)

I have a system where there is an unknown number of tenants (different database instances on same database server). I have working code where a user logs in and the correct tenant is selected, and I can read the configuration table for that tenant.
I want the application at start time to loop through all tenants, read the configuration and act upon it. Prior to moving to Spring Data JPA (backed by hibernate) this was easy as I was connecting to each database instance separately.
I don't think I can use Spring's #Transactional as it only sets up a single connection.
I hope to use the same repository interface with the same bean, as this works when i only need to hit one tenant at a time.
I do have a class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl that will give me a dataSource for a given tenant, but I'm not sure how to use that in a #Service class's method?
I'm not sure if I should remove my previous answer, edit it or what. So if a MOD can let me know proper procedure I'll be happy to comply.
Turns out I was right about the use of #Transactional not going to work. I ended up using an custom implementation of and AbstractRoutingDataSource to replace my MultiTenantConnectionProviderImpl and CurrentTenantResolverImpl. I use this new data source instead of setting the hibernate.multiTenancy hibernate.multi_tenant_connection_provider and hibernate.tenant_identifier_resolver
My temporary override class looks like this:
public class MultitenancyTemporaryOverride implements AutoCloseable
{
static final ThreadLocal<String> tenantOverride = new NamedThreadLocal<>("temporaryTenantOverride");
public void setCurrentTenant(String tenantId)
{
tenantOverride.set(tenantId);
}
public String getCurrentTenant()
{
return tenantOverride.get();
}
#Override
public void close() throws Exception
{
tenantOverride.remove();
}
}
My TenantRoutingDataSource looks like this:
#Component
public class TenantRoutingDataSource extends AbstractDataSource implements InitializingBean
{
#Override
public Connection getConnection() throws SQLException
{
return determineTargetDataSource().getConnection();
}
#Override
public Connection getConnection(String username, String password) throws SQLException
{
return determineTargetDataSource().getConnection(username, password);
}
#Override
public void afterPropertiesSet() throws Exception
{
}
protected String determineCurrentLookupKey()
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String database = "shared";
if (authentication != null && authentication.getPrincipal() instanceof MyUser)
{
MyUser user = (MyUser) authentication.getPrincipal();
database = user.getTenantId();
}
String temporaryOverride = MultitenancyTemporaryOverride.tenantOverride.get();
if (temporaryOverride != null)
{
database = temporaryOverride;
}
return database;
}
protected DataSource determineTargetDataSource()
{
return selectDataSource(determineCurrentLookupKey());
}
public DataSource selectDataSource(String tenantIdentifier)
{
//I use C3P0 for my connection pool
PooledDataSource pds = C3P0Registry.pooledDataSourceByName(tenantIdentifier);
if (pds == null)
pds = getComboPooledDataSource(tenantIdentifier);
return pds;
}
private ComboPooledDataSource getComboPooledDataSource(String tenantIdentifier)
{
ComboPooledDataSource cpds = new ComboPooledDataSource(tenantIdentifier);
cpds.setJdbcUrl("A JDBC STRING HERE");
cpds.setUser("MyDbUsername");
cpds.setPassword("MyDbPassword");
cpds.setInitialPoolSize(10);
cpds.setMaxConnectionAge(10000);
try
{
cpds.setDriverClass("com.informix.jdbc.IfxDriver");
}
catch (PropertyVetoException e)
{
throw new RuntimeException("Weird error when setting the driver class", e);
}
return cpds;
}
}
Then i just provide my custom data source to my Entity Manager factory bean when creating it.
#Service
public class TestService
{
public void doSomeGets()
{
List<String> tenants = getListSomehow();
try(MultitenancyTemporaryOverride tempOverride = new MultitenancyTemporaryOverride())
{
for(String tenant : tenants)
{
tempOverride.setCurrentTenant(tenant);
//do some work here, which only applies to the tenant
}
}
catch (Exception e)
{
logger.error(e);
}
}
}
I think I'm close to one solution, but I'm not too entirely happy with it. I would love for a better answer to come up.
EDITED: turns out this doesn't quite work, as Spring or Hibernate appears to only call the current tenant identifier resolver once, not for each time a #Transactional method is called
It involves changing the CurrentTenantIdentifierResolver implementation to not only look at the current user (if it is set) to get their current tenant id (up to implementor to figure out how to set that)...it also needs to look at a thread local variable to see if an override has been set.
Using this approach, I can temporarily set the tenantID...call a service method with my multi tenancy transaction manager specified and then get the data.
My Test Service:
#Service
public class TestService
{
#Transactional(transactionManager = "sharedTxMgr")
public void doSomeGets()
{
List<String> tenants = getListSomehow();
try(MultitenancyTemporaryOverride tempOverride = new MultitenancyTemporaryOverride())
{
for(String tenant : tenants)
{
tempOverride.setCurrentTenant(tenant);
doTenantSpecificWork();
}
}
catch (Exception e)
{
logger.error(e);
}
}
#Transactional(transactionManager = "tenantSpecificTxMgr")
public void doTenantSpecificWork()
{
//do some work here, which only applies to the tenant
}
}
My class that wraps setting ThreadLocal, implementing AutoCloseable to help make sure variable is cleaned up
public class MultitenancyTemporaryOverride implements AutoCloseable
{
static final ThreadLocal<String> tenantOverride = new ThreadLocal<>();
public void setCurrentTenant(String tenantId)
{
tenantOverride.set(tenantId);
}
public String getCurrentTenant()
{
return tenantOverride.get();
}
#Override
public void close() throws Exception
{
tenantOverride.remove();
}
}
My tenant resolver implementation that uses the thread local
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver
{
#Override
public String resolveCurrentTenantIdentifier()
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
logger.debug(ToStringBuilder.reflectionToString(authentication));
String database = "shared";
if (authentication != null && authentication.getPrincipal() instanceof MyUser)
{
MyUser user = (MyUser) authentication.getPrincipal();
database = user.getTenantId();
}
String temporaryOverride = MultitenancyTemporaryOverride.tenantOverride.get();
if(temporaryOverride != null)
{
database = temporaryOverride;
}
return database;
}

Categories

Resources