Apache Sentry API for Policy Management - apache-sentry

I am looking for way to define policy for Role pragmatically. Is there any API available for Sentry ? Either REST/JAVA ?
Any documentation or link will be great help?

Sentry exposes apache thrift client interface, here you can find thrift api definition sentry_policy_service.thrift. You can use it for client source code generating.
Additionally, Cloudera releases compiled client libraries compatible to Sentry Service, distributed as a part of CDH i.e.:
<dependency>
<groupId>org.apache.sentry</groupId>
<artifactId>sentry-provider-db</artifactId>
<version>1.5.1-cdh5.5.1</version>
</dependency>
available in Cloudera's maven repository:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>
</project>

Here is a sample program using "sentry-provider-db" to get the permission details of a given hive database, (this program may not be defining policy for Role, but this program might give you an idea, to use other methods to achieve that)
public class ConnectSentry {
public static void main(String[] args) throws IOException, SentryUserException, LoginException {
String userName=args[0];
String databaseName=args[1];
Configuration conf = new Configuration();
conf.set(ClientConfig.SERVER_RPC_ADDRESS, "servernamexx.domain");
conf.set(ClientConfig.SERVER_RPC_PORT, "8038"); //default port is 8038, verify this setting in configuration of Sentry
System.setProperty("javax.security.auth.login.name", "userName");
System.setProperty("java.security.auth.login.config", "login.conf");
System.setProperty("java.security.krb5.conf", "krb5.conf");
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
System.setProperty("sun.security.krb5.debug", "false");
conf.set(ServerConfig.PRINCIPAL, "sentry/<sentry-server-principal>");
SentryPolicyServiceClientDefaultImpl sentryPolicyServiceClientDefaultImpl = new SentryPolicyServiceClientDefaultImpl(
conf);
sentryPolicyServiceClientDefaultImpl.listUserRoles(userName).
forEach(rolesentry -> {//System.out.println(rolesentry.getRoleName());
try {
sentryPolicyServiceClientDefaultImpl.listAllPrivilegesByRoleName(userName, rolesentry.getRoleName()).forEach(
allpriv ->{
String db = allpriv.getDbName();
String permission=allpriv.getAction();
if (db.equals(args[1]))
{
System.out.println("found database and permission is "+permission);
}
}
);
} catch (SentryUserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
}
}
Refer the below program to get idea about the available methods
https://github.com/apache/incubator-sentry/blob/master/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClientDefaultImpl.java
Below methods and class might be useful for you:
public class SentryPolicyServiceClientDefaultImpl implements SentryPolicyServiceClient
public synchronized void importPolicy(Map>> policyFileMappingData,
String requestorUserName, boolean isOverwriteRole)
Post a comment, if you need sample krb5.conf, login.conf and pom.xml

Related

Unable to perform JNDI lookup using IBM WebSphere Application Server Liberty

I am using IBM WebSphere Application Server Liberty to perform JNDI lookup.I am pretty sure about giving right about the location of resources in the project. However, when i run this I am getting a name not found error.
Here is the code performing the lookup:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
PrintWriter out = response.getWriter();
response.setContentType("text/html");
try {
FlightService flightService = (FlightService)new InitialContext().lookup("java:comp/Web1/FlightService!com.airline.FlightService");
}
catch(Exception ex){
ex.printStackTrace();
}
if(flightService !=null){
out.println(flightService.getAirplaneModel());
out.println(flightService.getFrom());
out.println(flightService.getTo());
}
}
Here is the server.xml:
<server description="new server">
<!-- Enable features -->
<featureManager>
<feature>webProfile-7.0</feature>
<feature>localConnector-1.0</feature>
</featureManager>
<!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
<httpEndpoint httpPort="9090" httpsPort="9443" id="defaultHttpEndpoint"/>
<!-- Automatically expand WAR files and EAR files -->
<applicationManager autoExpand="true"/>
<applicationMonitor updateTrigger="mbean"/>
<webApplication id="Web1" location="Web1-0.0.1-SNAPSHOT.war" name="Web1"/>
</server>
I am not sure , If i have to set any configuration related properties. Any help would be appreciated.
Looking at the server xml. I don't see JNDI entry being defined.
Based on the code, it should be trying to access a JNDI entry from a servlet. In this case, where do you define you JNDI entry in the first place?
I think you need the following to define the JNDI entry in the server xml
https://www.ibm.com/support/knowledgecenter/en/SSEQTP_8.5.5/com.ibm.websphere.wlp.doc/ae/twlp_dep_jndi_refentry.html
Please give it a try

How to configure the Neo4j repository with Spring Data Neo4j 3.4.0?

I tried to upgrade from the 3.3.2 to the 3.4.0 version of spring data neo4j on search.maven.org but the build now gives the following exception:
AnnotationFormatError: Invalid default: public abstract java.lang.Class org.springframework.data.neo4j.config.EnableNeo4jRepositories.repositoryBaseClass()
The application works just fine in 3.3.2.
Here is the configuration class:
#Configuration
#EnableNeo4jRepositories(basePackages = { "it.data.neo4j.repository" })
#EnableTransactionManagement
#ComponentScan(basePackages = { "it.data.neo4j.service" })
public class Neo4JRepositoryConfiguration extends Neo4jConfiguration {
private static Logger logger = LoggerFactory.getLogger(Neo4JRepositoryConfiguration.class);
public static final String URL = "http://localhost:7474/db/data/";
public static final String LOGIN = "neo4j";
public static final String PASSWORD = "xxxx";
Neo4JRepositoryConfiguration() {
setBasePackage("it.data.neo4j.domain");
}
#Bean
GraphDatabaseService graphDatabaseService() {
return new SpringCypherRestGraphDatabase(URL, LOGIN, PASSWORD);
}
#Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory;
#Override
public PlatformTransactionManager neo4jTransactionManager(
GraphDatabaseService graphDatabaseService) {
return new ChainedTransactionManager(
new JpaTransactionManager(entityManagerFactory.getObject()),
new JtaTransactionManagerFactoryBean(graphDatabaseService).getObject());
}
}
The dependencies are:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>3.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-rest</artifactId>
<version>3.4.0.RELEASE</version>
</dependency>
Most likely a conflicting class path dependencies with spring-data-commons.jar
Make sure all jars on the class path are using the same version of spring-data-commons.
In my case I had 2 jars referencing both spring-data-commons.jar 1.10 and 1.11 which caused the issue.
Does your package it.data.neo4j.repository contain both JPA and Neo4j repositories? If so you may need to segregate them into separate packages.
Additionally, Spring Data Neo4j version 4 is a major shift from the previous versions and a bit of code migration is involved, it is possible your actual application code needs to be adjusted to be compatible with SDN4:
http://docs.spring.io/spring-data/neo4j/docs/4.0.0.RELEASE/reference/html/#migration

Spring boot Security Disable security

When I use security.basic.enabled=false to disable security on a Spring Boot project that has the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
I see the following Exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration$ManagementWebSecurityConfigurerAdapter': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.setObjectPostProcessor(org.springframework.security.config.annotation.ObjectPostProcessor); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.config.annotation.ObjectPostProcessor] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
In order to fix this exception I had to add the property - management.security.enabled=false . My understanding is that when the actuator is in the classpath, both security.basic.enabled=false and management.security.enabled=false should be set to disable the security.
Could someone please let me know if my understanding is wrong?
In case you have spring-boot-actuator in your package, you should add the following
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration.class})
With older Spring-boot, the class was called ManagementSecurityAutoConfiguration.
In newer versions this has changed to
#SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration.class}
)
UPDATE
If for reactive application you are having the same issue, you can exclude the following classes
#SpringBootApplication(exclude = {ReactiveSecurityAutoConfiguration.class, ReactiveManagementWebSecurityAutoConfiguration.class })
What also seems to work fine is creating a file application-dev.properties that contains:
security.basic.enabled=false
management.security.enabled=false
If you then start your Spring Boot app with the dev profile, you don't need to log on.
For Spring Boot 2 following properties are deprecated in application.yml configuration
security.basic.enabled: false
management.security.enabled: false
To disable security for Sprint Boot 2 Basic + Actuator Security following properties can be used in application.yml file instead of annotation based exclusion
(#EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class}))
spring:
autoconfigure:
exclude[0]: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
exclude[1]: org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
For application.properties syntax would be like
spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
If you need security as a dependency but don't want Spring Boot to configure it for you, you can use this exclusion:
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class
})
For the spring boot 2 users it has to be
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
Step 1: Comment annotation #EnableWebSecurity in your security config
//#EnableWebSecurity
Step 2: Add this to your application.properties file.
security.ignored=/**
spring.security.enabled=false
management.security.enabled=false
security.basic.enabled=false
For more details look here: http://codelocation.com/how-to-turn-on-and-off-spring-security-in-spring-boot-application/
Add following class into your code
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* #author vaquar khan
*/
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll().anyRequest().authenticated().and().csrf().disable();
}
}
And insie of application.properties add
security.ignored=/**
security.basic.enabled=false
management.security.enabled=false
Answer is to allow all requests in WebSecurityConfigurerAdapter as below.
you can do this in existing class or in new class.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
}
Please note : If ther is existing GlobalMethodSecurityConfiguration class, you must disable it.
If you are using #WebMvcTest annotation in your test class
#EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class })
#TestPropertySource(properties = {"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration"})
doesn't help you.
You can disable security here
#WebMvcTest(secure = false)
The easiest way for Spring Boot 2 without dependencies or code changes is just:
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
Permit access to everything using antMatchers("/")
protected void configure(HttpSecurity http) throws Exception {
System.out.println("configure");
http.csrf().disable();
http.authorizeRequests().antMatchers("/").permitAll();
}
I simply added security.ignored=/**in the application.properties,and that did the charm.
The only thing that worked for me:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().permitAll();
}
and
security.ignored=/**
Could be that the properties part is redundant or can be done in code, but had no time to experiment. Anyway is temporary.
You need to add this entry to application.properties to bypass Springboot Default Security
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
Then there won't be any authentication box.
otrws, credentials are:-
user and 99b962fa-1848-4201-ae67-580bdeae87e9 (password randomly generated)
Note: my springBootVersion = '1.5.14.RELEASE'
You can configure to toggle spring security in your project by following below 2 steps:
STEP 1:
Add a #ConditionalOnProperty annotation on top of your SecurityConfig class. Refer below:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity (prePostEnabled = true)
#ConditionalOnProperty (name = "myproject.security.enabled", havingValue = "true", matchIfMissing = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// your security config
}
STEP 2:
Add following config to your application.properties or application.yml file.
application.properties
security.ignored=/**
myproject.security.enabled=false
OR
application.yml
security:
ignored: /**
myproject:
security:
enabled: false
In order to avoid security you can use annotations.
Use this annotation on top of configure class:
#EnableWebSecurity
For example:
#EnableWebSecurity
#Configuration
public class AuthFilter{
// configured method
}
As previously multiple solutions mentioned to disable security through commenting of
#EnableWebSecurity
annotation and other is through properties in application.properties or yml. But those properties are showing as deprecated in latest spring boot version.
So, I would like to share another approach to configure default username and password in your application-dev.properties or application-dev.yml and use them to login into swagger and etc in development environment.
spring.security.user.name=admin
spring.security.user.password=admin
So, this approach will also provides you some kind of security as well and you can share this information with your development team. You can also configure user roles as well, but its not required in development level.
Latest spring 2.7.x, create two class, set DISABLE_KEYCLOAK_AUDIT_PROPERTY = 'your key' in application profile for enable/disable security:
public static final String DISABLE_KEYCLOAK_AUDIT_PROPERTY = "enable_security";
#EnableAutoConfiguration(exclude =
{org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration.class
})
#Configuration
#ConditionalOnProperty(name = DISABLE_KEYCLOAK_AUDIT_PROPERTY, havingValue = "true")
static
class DisableSecurityConfig {
}
#Configuration
#ConditionalOnProperty(name = DISABLE_KEYCLOAK_AUDIT_PROPERTY, havingValue = "false")
#Import({KeycloakSecurityConfig.class, KeycloakConfig.class})
static
class EnableSecurityConfig {
}
for example use in application.yml:
enable_security: true
Add the below lines to your main app.
Remove org.activiti.spring.boot.SecurityAutoConfiguration.class if you're not using activiti.
Similarly, remove the one for actuator if you're not using spring-boot-actuator.
#EnableAutoConfiguration(exclude = {
org.activiti.spring.boot.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration.class,
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class })
With Gradle and Spring boot v2.4.4, you can exclude spring security completely by adding this config in your build.gradle
configurations.all {
exclude group:"org.springframework.boot", module: "spring-boot-starter-security"
}
As of Spring Boot 2.7.3 using #EnableAutoConfiguration(exclude = {}) generated an error, suggesting the exclude property be used in the #SpringBootApplication annotation.
Here is what worked for me when disabling Spring Security completely.
#SpringBootApplication(
exclude = {
SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class
})
public class GeoServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GeoServiceApplication.class, args);
}
}
I tried excluding only SecurityAutoConfiguration.class, but I got an error for no HttpSecurity bean defined for ManagementWebSecurityAutoConfiguration.class.
With Spring 2.6.0 this helped in my case:
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.SecurityDataConfiguration.class
})
And additional I had to remove the dependency in the pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
In Spring Security 5.7.0-M2 WebSecurityConfigurerAdapter was deprecated. Spring Security team encourages users to move towards a component-based security configuration.
package com.may.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll(); // config to permit all requests
return http.build();
}
#Bean
public AuthenticationManager authenticationManager() { // to delete default username and password that is printed in the log every time, you can provide here any auth manager (InMemoryAuthenticationManager, etc) as you need
return authentication -> {
throw new UnsupportedOperationException();
};
}
}
More examples here:
https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
I added below settings in application.yml and worked fine.
security:
route-patterns-to-be-skipped:
- /**/*
this can be converted as security.route-paterns-to-be-skipped=/**/* for application.properties

Injecting Stateless Local EJB (3.1) into #WebComponent in WebLogic 12c not working

I have a Java EE 6 War project containing the following:
An EJB declared as so (it's also a JAX-RS Service):
#Path("/booksList")
#Produces("application/json")
#Stateless
#LocalBean
#Local(BooksListEJB.class)
public class BooksListEJBImpl implements BooksListEJB
A WebComponent declared as so:
#WebServlet(urlPatterns="/initDbData")
public class DataInitListener extends HttpServlet {
#EJB
private BooksListEJB booksListEJB;
An empty beans.xml file in the WEB-INF folder
When I deploy it in WebLogic 12c, I get the following error:
<Warning> <weblogic.jaxrs.onwls.deploy.ejb.provider.EJBComponentProviderFactory> <BEA-000000> <An instance of EJB class com.shivandragon.jee6TestService.ejb.impl.BooksListEJBImpl could not be looked up using simple form name. Attempting to look up using the fully-qualified form name.
javax.naming.NameNotFoundException: While trying to look up comp/env/BooksListEJBImpl in /app/webapp/jee6Test-service-0.1-SNAPSHOT.war/2039754748.; remaining na
me 'comp/env/BooksListEJBImpl'
at weblogic.jndi.internal.BasicNamingNode.newNameNotFoundException(BasicNamingNode.java:1180)
at weblogic.jndi.internal.ApplicationNamingNode.lookup(ApplicationNamingNode.java:146)
at weblogic.jndi.internal.WLEventContextImpl.lookup(WLEventContextImpl.java:253)
at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:426)
at weblogic.jndi.factories.java.ReadOnlyContextWrapper.lookup(ReadOnlyContextWrapper.java:45)
Truncated. see log file for complete stacktrace
I've looked similar questions, and found the suggestion to add #ManagedBean to the servlet. Tried that but had the same error.
My question is:
Shouldn't this work, am I misusing some Java EE 6 directive/standard?
In EJB 3.1 have been added new Bean view - LocaBean. You can develop a bean without need implement any inerfaces. That beans view is "no-interface view", annotated with #LocalBean and injected by classname. There are beans that implemented some local interfaces and has "local view" and should be injected via local interface. In your code you mixed no-interface view bean and local view bean. You should delete the #LocalBean annotation as #Sam answered.
Updated
I test it on WebLogic Server 12.1.1.0.
Create a simple interface with one method:
package ejbrest;
public interface SessionEJBLocal {
public String hello();
}
Then create a EJB with the RESTful annotations:
package ejbrest;
// ... imports
#Path("/booksList")
#Produces("application/json")
#Stateless
#Local(SessionEJBLocal.class)
public class SessionEJBBean implements SessionEJBLocal {
public SessionEJBBean() {
}
#Override
#GET
public String hello() {
return "Hello, world";
}
}
The deployment descriptor, web.xml (you can see it does not have any servlet definitions):
<?xml version = '1.0' encoding = 'UTF-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
</web-app>
You can create a servlet for the local bean injection demo:
package ejbrest;
// ... imports
#WebServlet(name = "DemoServlet", urlPatterns = { "/demoservlet" })
public class DemoServlet extends HttpServlet {
private static final String CONTENT_TYPE = "text/html; charset=UTF-8";
#EJB
private SessionEJBLocal ejb;
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>DemoServlet</title></head>");
out.println("<body>");
out.println("<p>The servlet has received a GET. This is the reply: " +
ejb.hello() + "</p>");
out.println("</body></html>");
out.close();
}
}
After deployment you can try call your RESTful service by url:
http://[host]:[port]/[appcontext]/resources/booksList
Response:
Hello, world
Also, your demo servlet will be accessable by url:
http://[host]:[port]/[appcontext]/demoservlet
Response:
The servlet has received a GET. This is the reply:Hello, world
By default Oracle WebLogic Server use resources as link on Jersey servlet. Please read the official documentation for informs about all supported deployments variants.

How to mock Grails Services in Camel Production Route unit tests

I need to write Unit tests for production routes in Grails which use Services referenced by Camel bean component. My requirement is neither to change nor to copy existing routes in test.
Problem is to somehow mock Service bean and add it to Camel registry.
I was able to do this using 'bind' method on 'context.registry.registry' object. Is there any functionality to do that in more safe way? Camel version is 2.10, Grails 2.1
Route is:
from('direct:validate').to('bean:camelService?method=echo')
CamelService is just simple class:
package com
class CamelService {
def echo(text) {
println "text=$text"
text
}
}
Test is following (route copied only to make question simpler):
package com
import grails.test.mixin.*
import org.apache.camel.builder.RouteBuilder
import org.apache.camel.test.junit4.CamelTestSupport
#TestFor(CamelService)
class RouteTests extends CamelTestSupport {
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from('direct:validate').to('bean:camelService?method=echo')
}
};
}
void testMockBean() throws Exception {
context.registry.registry.bind 'camelService', service
def result = template.requestBody('direct:validate', 'message')
assert result != null
assert result == 'message'
}
}
Camel allows you to plugin any custom registry you want, and out of the box it uses a Jndi based registry, which is why you can bind a service to it with the code example. An alternative is to use a SimpleRegistry which is just a Map, so you can put a service into the registry using the put method from the Map. You would then need to override createCamelContext method from the CamelTestSupport class and
pass in the SimpleRegistry to the constructor of DefaultCamelContext.
Anyway your code is safe as long you use the non-Spring CamelTestSupport class, as its using the JNDI based registrry out of the box. If you use CamelSpringTestSupport, then its a spring based registry, and you would need to use the spring app context to add your bean to it.
You can inject your components using CamelSpringtestSupport rather than CamelTestSupport as your base class.
Reading the documentation on Spring Test will help you for sure, and you might find interesting to use mock in your tests.
Anyway, you can build a custom context for your test, containing your bean's declaration and load it in the test.
public class RouteTests extends CamelSpringTestSupport {
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("route-test-context.xml");
}
#Test
public void testMockBean(){
//...
}
}
route-test-context.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/cxf" xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="service" ref="com.CamelService"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>com</package>
</camelContext>
</beans>

Resources