How to apply IP based rate-limiting in spring boot - java

I want to apply rate-limit on the basis of IP for each (/get)service for my project for e.g each IP can access each service for a particular no. of time i.e 5 times /10 second. I have used bucket4j rate-limiting but it's not working. Does anyone have any idea about it??
this is my application.properties
spring.cache.jcache.config=classpath:ehcache.xml
logging.level.org.ehcache=info
bucket4j.enabled=true
bucket4j.filters[0].cache-name=buckets
bucket4j.filters[0].filter-method=servlet
bucket4j.filters[0].url=.*
bucket4j.filters[0].rate-limits[0].bandwidths[0].capacity=5
bucket4j.filters[0].rate-limits[0].bandwidths[0].time=10
bucket4j.filters[0].rate-limits[0].bandwidths[0].unit=seconds
bucket4j.filters[0].rate-limits[0].expression="getRemoteAddress()"
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval=0
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval-unit=seconds
this is encache.xml
<config xmlns='http://www.ehcache.org/v3'
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<cache alias="buckets">
<expiry><ttl unit="seconds">6</ttl></expiry>
<heap unit="entries">2000</heap>
<jsr107:mbeans enable-statistics="true"/>
</cache>
</config>
pom.xml
<dependency>
<groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
<artifactId>bucket4j-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<scope>runtime</scope>
</dependency>
server Initializer
#EnableCaching
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(EwseparationApplication.class);
}
}

I was having the same issue. It looks like there was an issue opened with the bucket4j spring boot starter github project about this (link).
I converted my application.properties to application.yml as the individual reported in the issue and my rate limit started working. I'm not sure what the actual issue is (why application.yml works and application.properties does not). I kindof prefer the properties format over yml.

you can use .yaml as .properties is still having some issue in recognizing the tags

Related

timetoliveseconds ehcache spring boot config is not working

Below is my ehcache Config file
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<cache name="trans"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="0"
timeToLiveSeconds="6"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
</ehcache>
All Spring annotation and configurations are working correctly
#Component
#CacheConfig(cacheNames = {"trans" })
public class MyTransService {
private List<Trans> list;
#Autowired
private EhCacheCacheManager manage;
#PostConstruct
public void setup() {
list = new ArrayList<>();
}
#CachePut
public void addTransaction(Trans trans) {
this.list.add(trans);
}
#CacheEvict(allEntries = true)
public void deleteAll() {
this.list.clear();
}
}
But the cache is not getting clear after timetoliveseconds.
Can someone help me whats wrong in my config.
Below page says that it's bug , but not sure how to fix this ?
I am using spring-boot-starter-cache-2.0.3 version
https://github.com/ehcache/ehcache-jcache/issues/26
there are some similar questions but not providing any solutions
Was able to resolve this using ehcache-JSR-107 wrapper. Below is java config
#Component
public class CachingSetup implements JCacheManagerCustomizer {
#Override
public void customize(CacheManager cacheManager)
{
cacheManager.createCache("trans", new MutableConfiguration<>()
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(SECONDS, 10)))
.setStoreByValue(false)
.setStatisticsEnabled(true));
}
}
Pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId> <!--Starter for using Spring Framework's caching support-->
</dependency>
<dependency>
<groupId>javax.cache</groupId> <!-- JSR-107 API-->
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
If you are expecting the cache content to disappear without interaction, that is indeed not happening. Ehcache does not have a background check for expired items that removes them eagerly.
Instead removal of expired items happens inline, whenever you try to access them or if during a write to the cache, eviction kicks in because the cache is full.

Spring boot AOP Aspect not being invoked

I'm trying to intercept rest service calls with an aspect in the following manner
package mypackage.services.Service;
#Component
public class Service {
#Override
public Response helloService() {
return handleResult("Hello test " + new Date());
}
}
#Component
#Aspect
public class AuditLog {
#Before("execution(* mypackage.services.Service.*(..))")
public void beforeServcie(JoinPoint jp){
log.info("Before ",jp.getSignature().getName());
}
}
I'm using the following maven dependencies
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
This maven plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.0</version>
</plugin>
And my configuration xml contains
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="mypackage"/>
<aop:aspectj-autoproxy proxy-target-class="true" />
also in the Application class I've added the following annotation
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class Configuration{
...
}
On startup, by logging beans in the ApplicationContext, I can see that the aspect class "AuditLog" is being created.
I've set 2 breakpoints, but the debugger does not stop at the "beforeServcie" method but it does stop at the "helloService".
What am I missing?
Try this
execution(* mypackage.services.Service.*.*(..))
instead of
execution(* mypackage.services.Service.*(..))
If you are using spring-boot then instead of automatically adding dependency jars you can do
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
If you're using XML config <aop:aspectj-autoproxy ... /> then no need to have #EnableAspectJAutoProxy. It probably doesn't matter since AFAIK XML config wins over annotation config but better to avoid duplication
I am not quite sure why do you need aspectj-maven-plugin since Spring implements AOP by proxy and AFAIK this plugin is only needed for compile-time, post compile-time or load time weaving which are different concepts, see Spring AOP vs AspectJ
Now all the above mentioned points may not resolve your issue but the following might
execution(* mypackage.services.Service.Service.*(..))
And, don't set proxyTargetClass=true, let it be default false.
Explanation
The format is execution(<return type> <package name>.<class name>.<method name>(..)
The package name here is mypackage.services.Service and the class name is Service.

Java Security Policy Preventing Access to Maven Resource Files

I'm currently working on a Maven based project in Eclipse which I want to connect to a database using Hibernate + JPA. I have created a persistence.xml file and placed it in the directory <project>/src/main/resources/META-INF. When I run the application it will throw the very known exception No Persistence provider for EntityManager named
The contents of my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="NetworkMonDB">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
How I'm initializing this in my application:
public void initializeDatabase(){
final HashMap<String, String> dbConfig = new HashMap<String, String>();
dbConfig.put("javax.persistence.jdbc.url", this.properties.getProperty("database.uri"));
dbConfig.put("javax.persistence.jdbc.user", this.properties.getProperty("database.usr"));
dbConfig.put("javax.persistence.jdbc.password", this.properties.getProperty("database.psw"));
final EntityManagerFactory factory = Persistence.createEntityManagerFactory("NetworkMonDB", dbConfig); //exception thrown at this point.
this.entityManager = factory.createEntityManager();
}
And here are my Maven Dependencies:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version>
</dependency>
I conducted some further tests (see edits for previous comments on identifying the problem) and it seems the problem comes from my currently used security policy. While I have a security policy file to use when the application is built and packaged in a jar file, I do not have one that will work inside the Eclipse IDE. As soon as I figure out what the best way to configure the security policy I will post it as an answer, unless someone else has an answer.
The problem as described above was caused by a handling of the security policy and security manager. Since this application will eventually read from the hard drive, and work with RMI I need to use a security manager and security policy. However, when working inside the IDE you don't actually need to set a codebase value in the security policy file.
My current solution is to have this as my development area security policy:
grant {
permission java.security.AllPermission;
}
And then the security policy in use when I deploy my application would look like this:
grant codeBase "file:./MyApplication.jar" {
permission java.security.AllPermission;
}
I know that eventually I will need to provide a better more specific security policy for deployment that grants specific permissions to specific file locations and network values, but this should get me going until then.

Combining Spring project and Jersey

I've built a project with Spring JPA, and now I want to use it in my Jersey project.
I've added my SJPA project as a dependency in my pom.xml
I would like to use my service classes from my SJPA when I use GET/POST/PUT/DELETE methods.
Is there an easy way to do this with annotations? Or do I have to get AnnotationConfigApplicationContext in each class? Feels kind of waste.
#Path("/users")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public final class UserResource
{
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
private PodcastService service;
#GET
public Response getAllPodcasts() {
context.scan("org.villy.spring.service");
context.refresh();
service= context.getBean(PodcastService.class);
return Response.ok(service.findAll()).build();
}
}
NOTE: The linked example projects below are from the Jersey master branch, which is currently a snapshot of Jersey 3, which is not yet released. Jersey 3 will be using Spring 4, so you may notice a dependency jersey-spring4. This dependency does not exist yet, as Jersey 3 is not yet released (probably not for a while). So the dependency to use is jersey-spring3. All the example should still work the same, just changing that one dependency. If you want to use Spring 4, see the dependencies listed in the example pom below in this answer
You don't need to create the ApplicationContext where you need the service. You should be able to configure a global one. Jersey has a module for this that integrates the two frameworks. This allows you to simply #Autowired all your Spring services into your Jersey resource classes.
Instead of trying to produce any example, I will just link to the official examples. They are straight from the projects, so the links should be good for some time. Take special not of the Maven dependencies. You will need to make sure to have them for the example to work.
Jersey 2.x with Spring XML config
Jersey 2.x with Spring Java config [1]
Jersey 1.x with Spring XML config
Jersey 2.x with Spring Boot
Note: The ${spring3.version} version in the examples is 3.2.3.RELEASE. It's possible to use Spring 4 with the examples, but you will need to make sure to exclude all the Spring transitive dependencies from the jersey-spring3 dependency.
[1] - One thing to note about the Java config example is that it uses a standalone app. To use Java config in a webapp requires a bit of trickery. This is a known bug where Jersey looks for an param contextConfigLocation with the location of the applicationContext.xml file and will throw an exception when it doesn't find one.
I've found a few ways around this.
An example of this was mentioned by the person who raised the issue. You can create a Spring web initializer where you configure the spring context and override the param property. (See full example here).
#Order(1)
public class SpringWebContainerInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
// Set the Jersey used property to it won't load a ContextLoaderListener
servletContext.setInitParameter("contextConfigLocation", "");
}
private void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext webContext;
webContext = createWebAplicationContext(SpringAnnotationConfig.class);
servletContext.addListener(new ContextLoaderListener(webContext));
}
public WebApplicationContext createWebAplicationContext(Class... configClasses) {
AnnotationConfigWebApplicationContext context;
context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
}
}
You could simply add the applicationContext.xml to the classpath and just register the spring Java configuration class as a bean
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="config" class="com.your.pkg.SpringAnnotationConfig"/>
</beans>
There's another way I can think of, but I've save that for a time I can actually test it out.
UPDATE
"Failed to read candidate component class ... ASM ClassReader failed to parse class file - probably due to a new Java class file version that isn't supported yet"
Seems to be related to this, using Spring 3 with Java 8. Like I said, if you want to use Spring 4, you will need to exclude the Spring transitive dependencies from jersey-spring3 and just change the version of your explicitly declared Spring dependencies. Here is an example, that I tested and works.
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.1</version>
</dependency>

Spring Boot, #Autowire into an unmanaged class using #Configurable and load time weaving

I have a collection of unmanaged classes that I are instantiated outside of Spring. I've been attempting to use Spring AOP with load time weaving to #Autowire a bean into these classes but have so far not had any luck.
I've been testing using Tomcat 8 and Spring Boot 1.2.0.
My #Configuration where I attempt to set up class looks like this:
#Configuration
#PropertySource("classpath:application.properties")
#EnableSpringConfigured
#EnableLoadTimeWeaving
public class Config
Inside Config I define the bean I want to #Auotwire into my unmanaged classes:
#Bean
public StateProvider stateProvider() {
//setup bean
return new DynamoStateProviderImpl( );
}
The unmanaged bean looks like this:
#Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true, preConstruction = true)
public class StateOutput implements UnifiedOutput {
#Autowired
private StateProvider stateProvider;
And I have the following deps inside my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-agent</artifactId>
<version>2.5.6.SEC03</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
So far, I have not been able to see anything injected into stateProvider or been able to pull any info from the logs. I've also attempted setter style injection using
#Autowired
public void setStateProvider(StateProvider stateProvider){
this.stateProvider = stateProvider;
}
Thanks
In order to instrument LTW you'll need to either use the javaagent or place spring-tomcat-weaver.jar in the \lib folder and set up TomcatInstrumentableClassLoader in context.xml.
javaagent example:
-javaagent:"${settings.localRepository}/org/springframework/spring-agent/2.5.6.SEC03/spring-agent-2.5.6.SEC03".jar
ClassLoader example:
<Context>
<Loader loaderClass="org.springframework.instrument.classl oading.tomcat.TomcatInstrumentableClassLoader" />
</Context>

Categories

Resources