自己收藏-JNDI应用实例
一、JNDI在Java EE中的应用 JNDI技术是Java EE规范中的一个重要“幕后”角色,它为Java EE容器、组件提供者和应用程序之间提供了桥梁作用:Java EE容器同时扮演JNDI提供者角色,组件提供者将某个服务的具体实现部署到容器上,应用程序通过标准的JNDI接口就可以从容器上发现并使用服务,而不用关心服务的具体实现是什么,它的具体位置在哪里。 下面以一个常见的J2EE应用场景来看四种角色(组件接口、容器、组件提供者、应用程序)是如何围绕JNDI来发挥作用的:组件接口数据源DataSource是一种很常见的服务。我们通常将组件接口绑定到容器的Context上供客户调用。 Java EE容器 Tomcat是一种常见的Java EE容器,其他的还有JBoss,WebLogic,它们同时也实现了JNDI提供者规范。容器通常提供一个JNDI注入场所供加入组件的具体实现,比如Tomcat中的Server.xml配置文件。 组件提供者众多数据库厂商提供了DataSource的实现,比如OracleDataSource,MySQLDataSource,XXXDataSource等。我们将该实现的部署到容器中:将一系列jar加入classpath中,在Server.xml中配置DataSource实现,如:
<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" ..../>
应用程序
一个JSP/Servlet应用程序。通过JNDI接口使用DataSource服务,如:
Context initContext = new InitialContext(); Context envContext = (Context)initContext.lookup("java:/comp/env"); DataSource ds = (DataSource)envContext.lookup("jdbc/MyDB");
二、JNDI实例演练:在Java SE中使用JNDI
要在Java EE中环境中提供一个独立的实例不太容易。下面以一个独立的Java SE应用来演练JNDI的使用过程。在该应用中,我们使用JNDI来使用两种假想的服务:数据库服务DBService和日志服务LogService。
1、指定JNDI提供者
要使用JNDI,首先要配置JNDI提供者。在我们的Java SE应用中,没有Java EE容器充当JNDI提供者,因此我们要指定其他的JNDI提供者。在我们的例子里,我们使用SUN的文件系统服务提供者File System Service Provider。由于SUN的文件系统服务提供者并没有包含在JDK中,我们需要从SUN网站上下载:http://java.sun.com/products/jndi/downloads/index.html。它包含两个jar文件:fscontext.jar和providerutil.jar。我们将这两个文件加入项目的类路径中。
2、定义服务接口
首先,我们在服务接口package(xyz.service)中定义服务接口:DBService和LogService,分别表示数据库服务和日志服务。
♦数据库服务接口 DBService.java
package xyz.service; public interface DBService { String getLocation(); //获取数据库位置 String getState(); //获取数据库状态 void accessDB(); //访问数据库 void setProperty(int index,String property); //设置数据库信息 }
日志服务接口 LogService.java
package xyz.service; public interface LogService { void log(String message); //记录日志 }
3、组件提供者实现服务接口
接下来,我们在组件提供者package(xyz.serviceprovider)中提供DBService和LogService的实现:SimpleDBService和SimpleLogService。为了让服务能够在JNDI环境中使用,根据JNDI规范,我们同时定义两个对象工厂类SimpleDBServiceFactory和SimpleLogServiceFactory,分别用来创建服务实例。
♦数据库服务接口实现 SimpleDBService.java
package xyz.serviceprovider; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.StringRefAddr; import xyz.service.DBService; //为了将数据库服务实例加入JNDI的Context中,我们需要实现Referenceable接口,并实现RetReference方法。 //关于Reference和Referenceable,请参考上一篇:Java技术回顾之JNDI:JNDI API public class SimpleDBService implements Referenceable, DBService { private String location="mydb//local:8421/defaultdb";//数据库服务属性之一:数据库位置 private String state="start"; //数据库服务属性之二:数据库状态 public Reference getReference() throws NamingException { //Reference是对象的引用,Context中存放的是Reference,为了从Reference中还原出对象实例, //我们需要添加RefAddr,它们是创建对象实例的线索。在我们的SimpleDBService中,location和state是这样两个线索。 Reference ref=new Reference(getClass().getName(),SimpleDBServiceFactory.class.getName(),null); ref.add(new StringRefAddr("location",location)); ref.add(new StringRefAddr("state",state)); return ref; } public void accessDB() { if(state.equals("start")) System.out.println("we are accessing DB."); else System.out.println("DB is not start."); } public String getLocation() { return location; } public String getState() { return state; } public void setProperty(int index,String property){ if(index==0) location=property; else state=property; } }
♦数据库服务对象工厂类 SimpleDBServiceFactory.java
package xyz.serviceprovider; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; //数据库服务对象工厂类被JNDI提供者调用来创建数据库服务实例,对使用JNDI的客户不可见。 public class SimpleDBServiceFactory implements ObjectFactory { //根据Reference中存储的信息创建出SimpleDBService实例 public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> env) throws Exception { if(obj instanceof Reference){ Reference ref=(Reference)obj; String location=(String)ref.get("location").getContent(); String state=(String)ref.get("state").getContent(); SimpleDBService db= new SimpleDBService(); db.setProperty(0, location); db.setProperty(1, state); return db; } return null; } }
♦日志服务接口实现 SimpleLogService.java
package xyz.serviceprovider; import java.text.SimpleDateFormat; import java.util.Date; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.Referenceable; import xyz.service.LogService; public class SimpleLogService implements Referenceable, LogService { private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //SimpleLogService没有任何属性,通过SimpleLogService类名创建出来的SimpleLogService实例都是一样的, //因此这里无需添加RefAddr了。 public Reference getReference() throws NamingException { return new Reference(getClass().getName(),SimpleLogServiceFactory.class.getName(),null); } public void log(String message) { String date=sdf.format(new Date()); System.out.println(date+":"+message); } }
♦日志服务对象工厂类 SimpleLogServiceFactory.java
package xyz.serviceprovider; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; public class SimpleLogServiceFactory implements ObjectFactory { public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable<?, ?> env) throws Exception { if(obj instanceof Reference){ return new SimpleLogService(); } return null; } }
4、JNDI容器和JNDI客户端
最后,我们在JNDI应用package(xyz.jndi)中实现一个JNDI容器JNDIContainer和一个JNDI客户端应用JNDIClient。
JNDIContainer在内部使用文件系统服务提供者fscontext来提供命名和目录服务,配置文件JNDIContainer.properties是服务注入场所,供配置DBService和LogService实现。
♦JNDI容器类 JNDIContainer.java
package xyz.jndi; import java.io.InputStream; import java.util.Hashtable; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import xyz.service.DBService; import xyz.service.LogService; public class JNDIContainer { private Context ctx=null; public void init() throws Exception{ //初始化JNDI提供者。 Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put(Context.PROVIDER_URL, "file:/c:/sample"); //fscontext的初始目录,我们需要在c:\下创建sample目录。 ctx=new InitialContext(env); loadServices(); } //从配置文件JNDIContainer.properties中读取DBService和LogService实现,绑定到Context中。 private void loadServices() throws Exception{ InputStream in=getClass().getResourceAsStream("JNDIContainer.properties"); Properties props=new Properties(); props.load(in); //inject dbservice String s=props.getProperty("DBServiceClass"); Object obj=Class.forName(s).newInstance(); if(obj instanceof DBService){ DBService db=(DBService)obj; String[] ss=props.getProperty("DBServiceProperty").split(";"); for(int i=0;i<ss.length;i++) db.setProperty(i, ss[i]); ctx.rebind(props.getProperty("DBServiceName"), db); } //inject logservice s=props.getProperty("LogServiceClass"); obj=Class.forName(s).newInstance(); if(obj instanceof LogService){ LogService log=(LogService)obj; ctx.rebind(props.getProperty("LogServiceName"), log); } } public void close() throws NamingException{ ctx.close(); } public Context getContext(){ return ctx; } }
♦JNDI容器配置文件 JNDIContainer.properties
//和JNDIContainer.java文件位于同一目录 DBServiceName=DBService DBServiceClass=xyz.serviceprovider.SimpleDBService DBServiceProperty=mydb//192.168.1.2:8421/testdb;start LogServiceName=LogService LogServiceClass=xyz.serviceprovider.SimpleLogService
♦JNDI客户端 JNDIClient.java
package xyz.jndi; import javax.naming.Context; import xyz.service.DBService; import xyz.service.LogService; public class JNDIClient { public static void main(String[] args){ try{ JNDIContainer container=new JNDIContainer(); container.init(); //JNDI客户端使用标准JNDI接口访问命名服务。 Context ctx=container.getContext(); DBService db=(DBService)ctx.lookup("DBService"); System.out.println("db location is:"+db.getLocation()+",state is:"+db.getState()); db.accessDB(); LogService ls=(LogService)ctx.lookup("LogService"); ls.log("this is a log message."); container.close(); } catch(Exception e){ e.printStackTrace(); } } }
至此,我们的整个Java SE应用已经完成。
文章出处:飞诺网(www.firnow.com):http://dev.firnow.com/course/3_program/java/javajs/2008114/96341_2.html
相关推荐
自用CVE-2018-3191 weblogic反序列化exp。
java asm jndi_JNDI-Injection-Exploit,用于log4j2漏洞验证 可执行程序为jar包,在命令行中运行以下命令: $ java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar [-C] [command] [-A] [address] 其中: -C ...
Simple-JNDI旨在解决的第二个问题是从应用程序中的任何位置轻松访问应用程序配置。 如果您唯一的目的是测试或使用依赖于Tomcat之外的Tomcat JNDI环境的类,或者仅需要基于JNDI的数据源,请 (不要与Simple-JNDI...
这个压缩包中的主要文件"apacheds-server-jndi-1.0.1.jar"是ApacheDS Server JNDI的实现库,包含了必要的类和资源,使得开发者能够在Java应用程序中使用JNDI API与ApacheDS通信。这个版本号1.0.1表明这是一个特定的...
整合rmi和ldap服务器+恶意类,使用方法: $ java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar [-C] [command] [-A] [address] where: -C - command executed in the remote classfile. (optional , ...
攻击者通过构造恶意的JNDI引用,使得应用程序在解析这些引用时,会远程加载并执行攻击者控制的代码。这种攻击通常发生在程序对用户输入未进行充分验证和过滤的情况下,一旦成功,攻击者可以执行任意系统命令,获取...
在Java应用服务器中,Tomcat是一个广泛使用的轻量级服务器,而JNDI(Java Naming and Directory Interface)则是Java平台中的一个核心API,用于提供命名和目录服务。本篇文章将深入探讨Tomcat与JNDI的结合使用,帮助...
JNDI全名为Java Naming and Directory Interface.JNDI主要提供应用程序所需要资源上命名与目录服务。在Java EE环境中,JNDI扮演了一个很重要的角色,它提供了一个接口让用户在不知道资源所在位置的情形下,取得该...
附件为springboot+jndi+tomcat的事例代码, 工程中的jndi.txt有详细说明
开发者应该使用参数化查询,而不是字符串拼接,同时限制应用程序的JNDI查找范围,只允许访问特定的服务或资源。此外,更新和打补丁也非常重要,因为许多已知的JNDI注入漏洞已经被修复。 总的来说,JNDI注入是一个...
JNDI注入攻击通常发生在应用程序不当处理JNDI查找时,攻击者可以通过构造恶意的JNDI引用来执行任意代码。例如,Fastjson是一个流行的Java库,用于快速转换Java对象到JSON格式和反之。在某些版本的Fastjson中,存在...
NULL 博文链接:https://zzy603.iteye.com/blog/1039826
在Tomcat服务器中,JNDI的应用主要体现在其内置的JNDI实现——Tomcat JNDI,它允许开发者在应用中通过名称查找和使用资源,如数据源、环境变量等。本文将深入解析Tomcat 5.0中JNDI的工作原理,特别是`ContextBinding...
通过JNDI,开发者可以方便地在分布式环境中查找和使用资源,如EJB组件、数据库连接、消息队列等,而无需关注这些资源的实际位置或类型。这种抽象和标准化极大地提高了开发效率和系统的可移植性。同时,JNDI还允许...
然后,本地服务器使用包含有效载荷之一的恶意条目进行响应,这对于实现远程代码执行很有用。 动机 除了已知的JNDI攻击方法(通过引用中的远程类加载)之外,此工具还利用的功能带来了新的攻击媒介。 支持的有效载荷...
JNDI的核心理念是将应用程序与特定的命名或目录服务解耦,使得开发者能够灵活地在不同环境中部署应用,无需更改代码。 标题中的"jndi-1_2_1.zip_jndi_jndi-1.2.1.jar"表明这是一个关于JNDI的版本1.2.1的开源软件包...
例如使用`InMemoryDirectoryServer`类来创建一个内存中的LDAP服务器实例,以及通过`InMemoryDirectoryServerConfig`和`InMemoryListenerConfig`类来配置服务器的基本参数和监听器的行为。 ### 安全性考虑 在搭建...
本文档旨在指导读者如何在 Eclipse 中配置 GlassFish 3.1.1,实现连接池配置和 JNDI 配置。同时,也会解决在部署过程中可能出现的异常。 一、GlassFish 3.1.1 简介 GlassFish 是一个开源的 Java EE 应用服务器,由 ...