/** * Crete a new Resource env instance. * * @param obj The reference object describing the DataSource */ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof ResourceEnvRef) { Reference ref = (Reference) obj; ObjectFactory factory = null; RefAddr factoryRefAddr = ref.get(Constants.FACTORY); if (factoryRefAddr != null) { // Using the specified factory String factoryClassName = factoryRefAddr.getContent().toString(); // Loading factory ClassLoader tcl = Thread.currentThread().getContextClassLoader(); Class factoryClass = null; if (tcl != null) { try { factoryClass = tcl.loadClass(factoryClassName); } catch (ClassNotFoundException e) { NamingException ex = new NamingException("Could not load resource factory class"); ex.initCause(e); throw ex; } } else { try { factoryClass = Class.forName(factoryClassName); } catch (ClassNotFoundException e) { NamingException ex = new NamingException("Could not load resource factory class"); ex.initCause(e); throw ex; } } if (factoryClass != null) { try { factory = (ObjectFactory) factoryClass.newInstance(); } catch (Throwable t) { if (t instanceof NamingException) throw (NamingException) t; NamingException ex = new NamingException("Could not create resource factory instance"); ex.initCause(t); throw ex; } } } // Note: No defaults here if (factory != null) { return factory.getObjectInstance(obj, name, nameCtx, environment); } else { throw new NamingException("Cannot create resource instance"); } } return null; }
@Override public Object getObjectInstance( Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { // What kind of resource should we create? JndiResourceDescriptor resource = (JndiResourceDescriptor) obj; // Get class loader, we'll need it to load the factory class Class<?> factoryClass = null; ObjectFactory factory = null; try { factoryClass = clResourceClasses.loadClass(resource.getFactoryClassName()); } catch (ClassNotFoundException e) { NamingException ex = new NamingException("Could not find resource or resource factory class in the classpath"); ex.initCause(e); throw ex; } catch (Exception e) { NamingException ex = new NamingException( "Could not load resource or resource factory class for an unknown reason"); ex.initCause(e); throw ex; } try { factory = (ObjectFactory) factoryClass.newInstance(); } catch (Exception e) { NamingException ex = new NamingException("Could not create resource factory instance"); ex.initCause(e); throw ex; } Object result = null; try { result = factory.getObjectInstance(obj, name, nameCtx, environment); } catch (Exception e) { NamingException ex = new NamingException( "Could not create object resource from resource factory. JNDI definition & parameters may be incorrect."); ex.initCause(e); throw ex; } return result; }
/** * This is just a commodity method used to try to get an InitialLdapContext. * * @param t the Thread to be used to create the InitialLdapContext. * @param pair an Object[] array that contains the InitialLdapContext and the Throwable if any * occurred. * @param timeout the timeout in milliseconds. If we do not get to create the connection before * the timeout a CommunicationException will be thrown. * @return the created InitialLdapContext * @throws NamingException if something goes wrong during the creation. */ private static InitialLdapContext getInitialLdapContext(Thread t, Object[] pair, int timeout) throws NamingException { try { if (timeout > 0) { t.start(); t.join(timeout); } else { t.run(); } } catch (InterruptedException x) { // This might happen for problems in sockets // so it does not necessarily imply a bug } boolean throwException = false; if ((timeout > 0) && t.isAlive()) { t.interrupt(); try { t.join(2000); } catch (InterruptedException x) { // This might happen for problems in sockets // so it does not necessarily imply a bug } throwException = true; } if ((pair[0] == null) && (pair[1] == null)) { throwException = true; } if (throwException) { NamingException xx; ConnectException x = new ConnectException("Connection timed out"); xx = new CommunicationException("Connection timed out"); xx.initCause(x); throw xx; } if (pair[1] != null) { if (pair[1] instanceof NamingException) { throw (NamingException) pair[1]; } else if (pair[1] instanceof RuntimeException) { throw (RuntimeException) pair[1]; } else if (pair[1] instanceof Throwable) { throw new IllegalStateException("Unexpected throwable occurred", (Throwable) pair[1]); } } return (InitialLdapContext) pair[0]; }
/** * Binds a name to an object, along with associated attributes, overwriting any existing binding. * If attrs is null and obj is a DirContext, the attributes from obj are used. If attrs is null * and obj is not a DirContext, any existing attributes associated with the object already bound * in the directory remain unchanged. If attrs is non-null, any existing attributes associated * with the object already bound in the directory are removed and attrs is associated with the * named object. If obj is a DirContext and attrs is non-null, the attributes of obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some "mandatory" attributes of * the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj, Attributes attrs) throws NamingException { // Note: No custom attributes allowed // Check obj type File file = new File(base, name); InputStream is = null; if (obj instanceof Resource) { try { is = ((Resource) obj).streamContent(); } catch (IOException e) { // Ignore } } else if (obj instanceof InputStream) { is = (InputStream) obj; } else if (obj instanceof DirContext) { if (file.exists()) { if (!file.delete()) throw new NamingException(sm.getString("resources.bindFailed", name)); } if (!file.mkdir()) throw new NamingException(sm.getString("resources.bindFailed", name)); } if (is == null) throw new NamingException(sm.getString("resources.bindFailed", name)); // Open os try { FileOutputStream os = null; byte buffer[] = new byte[BUFFER_SIZE]; int len = -1; try { os = new FileOutputStream(file); while (true) { len = is.read(buffer); if (len == -1) break; os.write(buffer, 0, len); } } finally { if (os != null) os.close(); is.close(); } } catch (IOException e) { NamingException ne = new NamingException(sm.getString("resources.bindFailed", e)); ne.initCause(e); throw ne; } }
/** * Use DNS and obtains the LDAP servers that we should try. * * @param preferredServers If non-null, these servers are reported instead of doing the * discovery. In previous versions, this was simply added on top of the auto-discovered * list, but this option is useful when you have many domain controllers (because a single * mistyped password can cause an authentication attempt with every listed server, which can * lock the user out!) This also puts this feature in alignment with {@link * #DOMAIN_CONTROLLERS}, which seems to indicate that there are users who prefer this * behaviour. * @return A list with at least one item. */ public List<SocketInfo> obtainLDAPServer( DirContext ictx, String domainName, String site, String preferredServers) throws NamingException { List<SocketInfo> result = new ArrayList<SocketInfo>(); if (preferredServers == null) preferredServers = DOMAIN_CONTROLLERS; if (preferredServers != null) { for (String token : preferredServers.split(",")) { result.add(new SocketInfo(token.trim())); } return result; } String ldapServer = null; Attribute a = null; NamingException failure = null; // try global catalog if it exists first, then the particular domain for (String candidate : CANDIDATES) { ldapServer = candidate + (site != null ? site + "._sites." : "") + domainName; LOGGER.fine("Attempting to resolve " + ldapServer + " to SRV record"); try { Attributes attributes = ictx.getAttributes(ldapServer, new String[] {"SRV"}); a = attributes.get("SRV"); if (a != null) break; } catch (NamingException e) { // failed retrieval. try next option. failure = e; } } if (a != null) { // discover servers class PrioritizedSocketInfo implements Comparable<PrioritizedSocketInfo> { SocketInfo socket; int priority; PrioritizedSocketInfo(SocketInfo socket, int priority) { this.socket = socket; this.priority = priority; } public int compareTo(PrioritizedSocketInfo that) { return that.priority - this.priority; // sort them so that bigger priority comes first } } List<PrioritizedSocketInfo> plist = new ArrayList<PrioritizedSocketInfo>(); for (NamingEnumeration ne = a.getAll(); ne.hasMoreElements(); ) { String record = ne.next().toString(); LOGGER.fine("SRV record found: " + record); String[] fields = record.split(" "); // fields[1]: weight // fields[2]: port // fields[3]: target host name String hostName = fields[3]; // cut off trailing ".". JENKINS-2647 if (hostName.endsWith(".")) hostName = hostName.substring(0, hostName.length() - 1); int port = Integer.parseInt(fields[2]); if (FORCE_LDAPS) { // map to LDAPS ports. I don't think there's any SRV records specifically for LDAPS. // I think Microsoft considers LDAP+TLS the way to go, or else there should have been // separate SRV entries. if (port == 389) port = 686; if (port == 3268) port = 3269; } int p = Integer.parseInt(fields[0]); plist.add(new PrioritizedSocketInfo(new SocketInfo(hostName, port), p)); } Collections.sort(plist); for (PrioritizedSocketInfo psi : plist) result.add(psi.socket); } if (result.isEmpty()) { NamingException x = new NamingException("No SRV record found for " + ldapServer); if (failure != null) x.initCause(failure); throw x; } LOGGER.fine(ldapServer + " resolved to " + result); return result; }
/** * Return a general naming exception with a root cause. * * @param message the message * @param cause the exception cause, or {@code null} for none * @return the exception */ public static NamingException namingException(final String message, final Throwable cause) { final NamingException exception = new NamingException(message); if (cause != null) exception.initCause(cause); return exception; }