001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS. 026 */ 027 028package org.forgerock.opendj.examples; 029 030import static org.forgerock.opendj.ldap.LDAPConnectionFactory.AUTHN_BIND_REQUEST; 031import static org.forgerock.opendj.ldap.LDAPConnectionFactory.HEARTBEAT_ENABLED; 032import static org.forgerock.opendj.ldap.LDAPListener.*; 033import static org.forgerock.opendj.ldap.requests.Requests.newSimpleBindRequest; 034 035import java.io.IOException; 036import java.util.LinkedList; 037import java.util.List; 038 039import org.forgerock.opendj.ldap.ConnectionFactory; 040import org.forgerock.opendj.ldap.Connections; 041import org.forgerock.opendj.ldap.LdapException; 042import org.forgerock.opendj.ldap.LDAPClientContext; 043import org.forgerock.opendj.ldap.LDAPConnectionFactory; 044import org.forgerock.opendj.ldap.LDAPListener; 045import org.forgerock.opendj.ldap.RequestContext; 046import org.forgerock.opendj.ldap.RequestHandlerFactory; 047import org.forgerock.opendj.ldap.ServerConnectionFactory; 048import org.forgerock.opendj.ldap.requests.BindRequest; 049import org.forgerock.util.Options; 050 051/** 052 * An LDAP load balancing proxy which forwards requests to one or more remote 053 * Directory Servers. This is implementation is very simple and is only intended 054 * as an example: 055 * <ul> 056 * <li>It does not support SSL connections 057 * <li>It does not support StartTLS 058 * <li>It does not support Abandon or Cancel requests 059 * <li>Very basic authentication and authorization support. 060 * </ul> 061 * This example takes the following command line parameters: 062 * 063 * <pre> 064 * {@code <listenAddress> <listenPort> <proxyDN> <proxyPassword> <remoteAddress1> <remotePort1> 065 * [<remoteAddress2> <remotePort2> ...]} 066 * </pre> 067 */ 068public final class Proxy { 069 /** 070 * Main method. 071 * 072 * @param args 073 * The command line arguments: listen address, listen port, 074 * remote address1, remote port1, remote address2, remote port2, 075 * ... 076 */ 077 public static void main(final String[] args) { 078 if (args.length < 6 || args.length % 2 != 0) { 079 System.err.println("Usage: listenAddress listenPort " 080 + "proxyDN proxyPassword remoteAddress1 remotePort1 " 081 + "remoteAddress2 remotePort2 ..."); 082 System.exit(1); 083 } 084 085 // Parse command line arguments. 086 final String localAddress = args[0]; 087 final int localPort = Integer.parseInt(args[1]); 088 089 final String proxyDN = args[2]; 090 final String proxyPassword = args[3]; 091 092 // Create load balancer. 093 // --- JCite pools --- 094 final List<ConnectionFactory> factories = new LinkedList<>(); 095 final BindRequest bindRequest = newSimpleBindRequest(proxyDN, proxyPassword.toCharArray()); 096 final Options factoryOptions = Options.defaultOptions() 097 .set(HEARTBEAT_ENABLED, true) 098 .set(AUTHN_BIND_REQUEST, bindRequest); 099 100 final List<ConnectionFactory> bindFactories = new LinkedList<>(); 101 final Options bindFactoryOptions = Options.defaultOptions().set(HEARTBEAT_ENABLED, true); 102 103 for (int i = 4; i < args.length; i += 2) { 104 final String remoteAddress = args[i]; 105 final int remotePort = Integer.parseInt(args[i + 1]); 106 107 factories.add(Connections.newCachedConnectionPool(new LDAPConnectionFactory(remoteAddress, 108 remotePort, 109 factoryOptions))); 110 111 bindFactories.add(Connections.newCachedConnectionPool(new LDAPConnectionFactory(remoteAddress, 112 remotePort, 113 bindFactoryOptions))); 114 } 115 // --- JCite pools --- 116 117 // --- JCite load balancer --- 118 final ConnectionFactory factory = Connections.newRoundRobinLoadBalancer(factories, factoryOptions); 119 final ConnectionFactory bindFactory = Connections.newRoundRobinLoadBalancer(bindFactories, bindFactoryOptions); 120 // --- JCite load balancer --- 121 122 // --- JCite backend --- 123 /* 124 * Create a server connection adapter which will create a new proxy 125 * backend for each inbound client connection. This is required because 126 * we need to maintain authorization state between client requests. 127 */ 128 final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory = 129 new RequestHandlerFactory<LDAPClientContext, RequestContext>() { 130 @Override 131 public ProxyBackend handleAccept(LDAPClientContext clientContext) 132 throws LdapException { 133 return new ProxyBackend(factory, bindFactory); 134 } 135 }; 136 final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = 137 Connections.newServerConnectionFactory(proxyFactory); 138 // --- JCite backend --- 139 140 // --- JCite listener --- 141 // Create listener. 142 final Options options = Options.defaultOptions().set(CONNECT_MAX_BACKLOG, 4096); 143 LDAPListener listener = null; 144 try { 145 listener = new LDAPListener(localAddress, localPort, connectionHandler, options); 146 System.out.println("Press any key to stop the server..."); 147 System.in.read(); 148 } catch (final IOException e) { 149 System.out.println("Error listening on " + localAddress + ":" + localPort); 150 e.printStackTrace(); 151 } finally { 152 if (listener != null) { 153 listener.close(); 154 } 155 } 156 // --- JCite listener --- 157 } 158 159 private Proxy() { 160 // Not used. 161 } 162}