Commit 08fd4578 authored by Clayton Donley's avatar Clayton Donley
Browse files

Fixs for ITS issue 2604

Added ability for  jdbc bridge to perform  ldap modify commands using the statement:
UPDATE ENTRY dn DO operation SET attribute=value WHERE condition
operation may be ADD REPLACE or DELETE
Added a IGNORE_TRANSACTION flag to the initialization parameters that allows transaction calls to be ignored
parent 8d57d891
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -26,6 +26,7 @@ import javax.naming.directory.*;
import com.octetstring.jdbcLdap.sql.statements.JdbcLdapInsert;
import com.octetstring.jdbcLdap.sql.*;
import java.sql.*;
import com.octetstring.jdbcLdap.util.*;
/**
*Inserts a new entry
*@author Marc Boorshtein, OctetString
......@@ -41,17 +42,26 @@ public class Insert {
SqlStore store = insert.getSqlStore();
String[] fields = store.getFields();
String[] vals = insert.getVals();
HashMap fieldsMap = store.getFieldsMap();
LinkedList fieldsMap = store.getFieldsMap();
Iterator it;
String field;
Pair p;
//take all attributes and add it to addition list
try {
it = fieldsMap.keySet().iterator();
it = fieldsMap.iterator();
while (it.hasNext()) {
field = (String) it.next();
atts.put(new BasicAttribute(field,fieldsMap.get(field)));
p = (Pair) it.next();
field = p.getName();
//System.out.println("adding " + field + "=" + p.getValue());
if (atts.get(field) == null ) {
atts.put(new BasicAttribute(field,p.getValue()));
}
else {
((BasicAttribute) atts.get(field)).add(p.getValue());
}
}
//System.out.println("in insert DN : " + insert.getDistinguishedName());
con.createSubcontext(insert.getDistinguishedName(),atts);
}
catch (NamingException ne) {
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -76,7 +76,12 @@ public class JndiLdapConnection implements java.sql.Connection {
public static final String JNDI_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
/** The JNDI DSML factory*/
public static final String JNDI_DSML_FACTORY = "com.sun.jndi.dsml.DsmlCtxFactory";
public static final String JNDI_DSML_FACTORY = "com.sun.jndi.dsmlv2.soap.DsmlSoapCtxFactory";
/** OPTIONAL - States if transaction calls should be ignored, default to false */
public static final String IGNORE_TRANSACTIONS = "IGNORE_TRANSACTIONS";
/** user property */
static final String USER = "user";
......@@ -90,6 +95,9 @@ public class JndiLdapConnection implements java.sql.Connection {
/** number of characters to eliminate 'jdbc:' from the url */
static final int ELIM_JDBC = 5;
/** number of characters to eliminate 'jdbc:dsml: from the url */
static final int ELIM_JDBC_DSML = 12;
/** Contains all cached statements */
HashMap statements;
......@@ -120,6 +128,12 @@ public class JndiLdapConnection implements java.sql.Connection {
/** temporary string buffer */
StringBuffer tmpBuff;
/** determines if the connection is dsmlv2 */
boolean isDsml;
/** determines if a transaction should be ignored */
boolean ignoreTransactions;
/*
*Public methods not part of java.sql.Connection
*/
......@@ -202,6 +216,8 @@ public class JndiLdapConnection implements java.sql.Connection {
this.concatAtts = false;
boolean authFound = false;
this.tmpBuff = new StringBuffer();
this.ignoreTransactions = false;
isDsml = url.startsWith(JdbcLdapDriver.DSML_URL_ID);
Enumeration en = props.propertyNames();
// System.out.println("JndiLdapConnection.<init>: url="+url);
......@@ -209,9 +225,14 @@ public class JndiLdapConnection implements java.sql.Connection {
// System.out.println("JndiLdapConnection.<init>: baseDN="+baseDN);
String prop;
String user=null, pass=null ;
env.put(Context.INITIAL_CONTEXT_FACTORY,JNDI_FACTORY);
env.put(Context.INITIAL_CONTEXT_FACTORY,isDsml ? JNDI_DSML_FACTORY : JNDI_FACTORY);
//env.put(Context.INITIAL_CONTEXT_FACTORY,JNDI_DSML_FACTORY);
env.put(Context.PROVIDER_URL,url.substring(ELIM_JDBC));
if (isDsml) {
env.put(Context.PROVIDER_URL,url.substring(ELIM_JDBC_DSML));
}
else {
env.put(Context.PROVIDER_URL,url.substring(ELIM_JDBC));
}
while (en.hasMoreElements()) {
prop = (String) en.nextElement();
......@@ -242,6 +263,8 @@ public class JndiLdapConnection implements java.sql.Connection {
if (props.getProperty(prop).equalsIgnoreCase("true")) {
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
} else if (prop.equalsIgnoreCase(IGNORE_TRANSACTIONS)) {
this.ignoreTransactions = props.getProperty(prop).equalsIgnoreCase("true");
}
else {
env.put(prop,props.getProperty(prop));
......@@ -286,7 +309,9 @@ public class JndiLdapConnection implements java.sql.Connection {
}
public void setTransactionIsolation(int param) throws java.sql.SQLException {
throw new SQLException("LDAP Does Not Support Transactions");
if (! this.ignoreTransactions) {
throw new SQLException("LDAP Does Not Support Transactions");
}
}
public boolean getAutoCommit() throws java.sql.SQLException {
......@@ -303,7 +328,9 @@ public class JndiLdapConnection implements java.sql.Connection {
}
public void commit() throws java.sql.SQLException {
throw new SQLException("LDAP Does Not Support Transactions");
if (! this.ignoreTransactions) {
throw new SQLException("LDAP Does Not Support Transactions");
}
}
public boolean isClosed() throws java.sql.SQLException {
......@@ -327,24 +354,28 @@ public class JndiLdapConnection implements java.sql.Connection {
public String ldapClean(String val) {
char c;
tmpBuff.setLength(0);
for (int i=0,m= val.length(); i<m; i++) {
c = val.charAt(i);
switch (c) {
case ',':
case '=':
case '+':
case '<':
case '>':
case '#':
case ';': this.tmpBuff.setLength(0);
case ',': tmpBuff.append("\\,"); break;
case '=': tmpBuff.append("\\="); break;
case '+': tmpBuff.append("\\+"); break;
case '<': tmpBuff.append("\\<"); break;
case '>': tmpBuff.append("\\>"); break;
case '#': tmpBuff.append("\\#"); break;
case ';': tmpBuff.append("\\;"); break; /*this.tmpBuff.setLength(0);
tmpBuff .append('"').append(val).append('"');
return tmpBuff.toString();
System.out.println("tmpbuf : " + tmpBuff.toString());
return tmpBuff.toString();*/
default : tmpBuff.append(c);
}
}
return val;
return tmpBuff.toString();
}
public void setCatalog(java.lang.String str) throws java.sql.SQLException {
......@@ -383,7 +414,9 @@ public class JndiLdapConnection implements java.sql.Connection {
}
public void setAutoCommit(boolean param) throws java.sql.SQLException {
throw new SQLException("LDAP Does Not Support Transactions");
if (! this.ignoreTransactions) {
throw new SQLException("LDAP Does Not Support Transactions");
}
}
public java.sql.CallableStatement prepareCall(java.lang.String str) throws java.sql.SQLException {
......@@ -471,7 +504,9 @@ public class JndiLdapConnection implements java.sql.Connection {
}
public void rollback(java.sql.Savepoint savepoint) throws java.sql.SQLException {
throw new SQLException("LDAP Does Not Support Transactions");
if (! this.ignoreTransactions) {
throw new SQLException("LDAP Does Not Support Transactions");
}
}
/**
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -96,7 +96,7 @@ public class RetrieveResults {
DirContext con = sql.getContext();
SearchControls ctls = new SearchControls();
int num;
//System.out.println("Search Scope : " + sql.getSearchScope());
ctls.setSearchScope(sql.getSearchScope());
num = sql.getTimeOut();
......@@ -104,7 +104,9 @@ public class RetrieveResults {
String filter = sql.getFilterWithParams();
// System.out.println("sql.getBaseContext() " + sql.getBaseContext());
// System.out.println("where : " + filter);
// System.out.println("scope : " + sql.getSearchScope());
return con.search(sql.getBaseContext(), filter ,ctls);
}
catch (NamingException e) {
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -23,6 +23,7 @@ package com.octetstring.jdbcLdap.jndi;
import java.sql.*;
import javax.naming.*;
/**
*Translates a JndiException to a SQLException
*@author Marc Boorshtein, OctetString
......@@ -106,4 +107,8 @@ public class SQLNamingException extends java.sql.SQLException {
}
public NamingException getNamingException() {
return this.e;
}
}
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -32,6 +32,17 @@ import java.sql.*;
*@author Marc Boorshtein, OctetString
*/
public class UnpackResults {
static final String HEX_COMMA="\\2C";
static final String HEX_PLUS="\\2B";
static final String HEX_DBL_QUOTE="\\22";
static final String HEX_BACK_SLASH="\\5C";
static final String HEX_LESS="\\3C";
static final String HEX_MORE="\\3E";
static final String HEX_SEMI_COLON="\\3B";
static final HashMap HEX_TO_STRING;
/** DN attribute name */
static final String DN_ATT = "DN";
......@@ -44,6 +55,18 @@ public class UnpackResults {
/** List of rows */
LinkedList rows;
static {
HEX_TO_STRING = new HashMap();
HEX_TO_STRING.put(HEX_COMMA,"\\,");
HEX_TO_STRING.put(HEX_PLUS,"\\+");
HEX_TO_STRING.put(HEX_DBL_QUOTE,"\\\"");
HEX_TO_STRING.put(HEX_BACK_SLASH,"\\\\");
HEX_TO_STRING.put(HEX_LESS,"\\<");
HEX_TO_STRING.put(HEX_MORE,"\\>");
HEX_TO_STRING.put(HEX_SEMI_COLON,"\\;");
}
/** Creates new UnpackResults */
public UnpackResults(JndiLdapConnection con) {
this.con = con;
......@@ -162,8 +185,16 @@ public class UnpackResults {
names.put(field.name, field);
}
buff.setLength(0);
buff.append(res.getName()).append(base);
if (buff.charAt(0) == ',')
//TODO, need to be able to handle unicode strings....
/*try {
System.out.println("in unpack dn : " + cleanDn(res.getName()));
}
catch (Exception e) {
e.printStackTrace();
}*/
buff.append(cleanDn(res.getName())).append(base);
if (buff.length() > 0 && buff.charAt(0) == ',')
buff.deleteCharAt(0);
// System.out.println("Unpack: dn="+buff);
......@@ -278,5 +309,23 @@ public class UnpackResults {
throw new SQLNamingException(e);
}
}
public String cleanDn(String dn) {
StringBuffer buf = new StringBuffer(dn);
int begin,end;
begin = buf.indexOf("\\");
String val;
while (begin != -1) {
val = (String) UnpackResults.HEX_TO_STRING.get(buf.substring(begin,begin+3));
if (val != null) {
buf.replace(begin,begin+3,val);
}
begin = begin = buf.indexOf("\\",begin + 1);
}
return buf.toString();
}
}
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -51,6 +51,7 @@ public class Update {
try {
NamingEnumeration enum = res.searchUpIns(update);
//System.out.println("enum.hasMore : " + enum.hasMore());
while (enum.hasMore()) {
seres = (SearchResult) enum.next();
buf.setLength(0);
......@@ -63,6 +64,8 @@ public class Update {
name = store.getDistinguishedName();
}
//System.out.println("name : " + name);
con.modifyAttributes(name,mods);
count++;
......
/* **************************************************************************
*
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
* TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
* AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
* IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
* OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
* PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM OCTET STRING, INC.,
* COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
******************************************************************************/
package com.octetstring.jdbcLdap.jndi;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
import java.sql.*;
import com.octetstring.jdbcLdap.sql.statements.*;
import com.octetstring.jdbcLdap.util.*;
/**
* @author mlb
*
* To change the template for this generated type comment go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
public class UpdateEntry {
RetrieveResults res = new RetrieveResults();
public int doUpdateEntry(JdbcLdapUpdateEntry stmt) throws SQLException {
int argPos = 0;
StringBuffer dn = new StringBuffer();
//first we need to construct the dn
/*String[] dnlist = stmt.getDnlist();
for (int i=0,m=dnlist.length;i<m;i++) {
dn.append(dnlist[i]);
//System.out.println("i,m :" + i + "," + m);
if (i < m-1) {
dn.append(stmt.getArgVals()[i]);
}
}*/
Iterator icmds = stmt.getCmds().iterator();
UpdateSet us;
LinkedList mods = new LinkedList();
int paramnum = 0;
while (icmds.hasNext()) {
us = (UpdateSet) icmds.next();
int modtype;
if (us.getCmd().equalsIgnoreCase(JdbcLdapUpdateEntry.ADD)) {
modtype = DirContext.ADD_ATTRIBUTE;
}
else if (us.getCmd().equalsIgnoreCase(JdbcLdapUpdateEntry.DELETE)) {
modtype = DirContext.REMOVE_ATTRIBUTE;
}
else {
modtype = DirContext.REPLACE_ATTRIBUTE;
}
//ModificationItem[] mods = new ModificationItem[stmt.getAttribs().size()];
Pair p;
String val,name;
Iterator it = us.getAttribs().iterator();
int i = 0;
ArrayList al = new ArrayList();
while (it.hasNext()) {
if (modtype == DirContext.ADD_ATTRIBUTE || modtype == DirContext.REPLACE_ATTRIBUTE) {
p = (Pair) it.next();
name = p.getName();
if (p.getValue().equals("?")) {
//System.out.println("paramnum : " + paramnum);
//System.out.println("val : " + stmt.getArgVals()[paramnum]);
val = stmt.getArgVals()[paramnum];
paramnum++;
//i++;
}
else {
val = p.getValue();
}
//System.out.println("moditem : " + modtype + ", " + name + "=" + val);
mods.add(new ModificationItem(modtype,new BasicAttribute(name,val)));
}
else {
Object o = it.next();
if (o instanceof String) {
name = (String) o;
//System.out.println("moditem : " + modtype + ", " + name);
mods.add(new ModificationItem(modtype,new BasicAttribute(name)));
} else {
p = (Pair) o;
name = p.getName();
if (p.getValue().equals("?")) {
//System.out.println("paramnum : " + paramnum);
//System.out.println("val : " + stmt.getArgVals()[paramnum]);
val = stmt.getArgVals()[paramnum];
paramnum++;
//i++;
}
else {
val = p.getValue();
}
//System.out.println("moditem : " + modtype + ", " + name + "=" + val);
mods.add(new ModificationItem(modtype,new BasicAttribute(name,val)));
}
}
i++;
}
}
Object[] toCopy = mods.toArray();
ModificationItem[] doMods = new ModificationItem[toCopy.length];
System.arraycopy(toCopy,0,doMods,0,doMods.length);
SearchResult seres;
StringBuffer buf = new StringBuffer();
String name;
try {
int count = 0;
if (stmt.getSearchScope() == SearchControls.OBJECT_SCOPE && stmt.getFilterWithParams().equalsIgnoreCase("(objectClass=*)")) {
stmt.getContext().modifyAttributes(stmt.getSqlStore().getDistinguishedName(),doMods);
count++;
} else {
NamingEnumeration enum = res.searchUpIns(stmt);
while (enum.hasMore()) {
seres = (SearchResult) enum.next();
buf.setLength(0);
String entryName = seres.getName();
if (seres.getName().trim().length() > 0) {
name = buf.append(entryName).append(',').append(stmt.getSqlStore().getDistinguishedName()).toString();
}
else {
name = stmt.getSqlStore().getDistinguishedName();
}
//System.out.println("name : " + name);
stmt.getContext().modifyAttributes(name,doMods);
count++;
//System.out.println("count : " + count);
}
enum.close();
}
//System.out.println("final count : " + count);
return count;
//stmt.getContext().modifyAttributes(dn.toString(),doMods);
} catch (NamingException ne) {
throw new SQLNamingException(ne);
}
}
}
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......
/* **************************************************************************
*
* Copyright (C) 2002 Octet String, Inc. All Rights Reserved.
* Copyright (C) 2002-2004 Octet String, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
......@@ -24,10 +24,12 @@ import junit.framework.*;
import com.octetstring.jdbcLdap.sql.statements.JdbcLdapSelect;
import com.octetstring.jdbcLdap.jndi.*;
import com.octetstring.jdbcLdap.sql.*;
import com.octetstring.jdbcLdap.util.*;
import com.octetstring.jdbcLdap.sql.statements.*;
import java.sql.*;
import javax.naming.directory.*;
/**
*Tests the parsing of a SELECT statement
*@author Marc Boorshtein, OctetString
......@@ -49,7 +51,7 @@ public class TestInsert extends junit.framework.TestCase {
protected void setUp() throws java.lang.Exception {
Class.forName("com.octetstring.jdbcLdap.sql.JdbcLdapDriver");
con = (JndiLdapConnection) DriverManager.getConnection(System.getProperty("ldapConnString") + "?SEARCH_SCOPE:=subTreeScope",System.getProperty("ldapUser"),System.getProperty("ldapPass"));
con = (JndiLdapConnection) DriverManager.getConnection(System.getProperty("ldapConnString") + "?CONCAT_ATTS:=true&SEARCH_SCOPE:=subTreeScope",System.getProperty("ldapUser"),System.getProperty("ldapPass"));
}