All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.milton.ldap.LdapResponseHandler Maven / Gradle / Ivy

Go to download

Milton Community Edition: Supports DAV level 1 and is available on Apache2 license

There is a newer version: 4.0.3.2215
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package io.milton.ldap;

import com.sun.jndi.ldap.Ber;
import com.sun.jndi.ldap.BerEncoder;
import io.milton.common.LogUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author brad
 */
public class LdapResponseHandler {

	private static final Logger log = LoggerFactory.getLogger(LdapResponseHandler.class);
	/**
	 * reusable BER encoder
	 */
	final BerEncoder responseBer = new BerEncoder();
	
	private final Socket client;
	private final OutputStream os;
	/**
	 * Current LDAP version (used for String encoding)
	 */
	int ldapVersion = Ldap.LDAP_VERSION3;
	
	private String currentHostName;

	public LdapResponseHandler(Socket client, OutputStream os) {
		this.client = client;
		this.os = os;
	}
	
	

	public boolean isLdapV3() {
		return ldapVersion == Ldap.LDAP_VERSION3;
	}

	/**
	 * Send Root DSE
	 *
	 * @param currentMessageId current message id
	 * @throws IOException on error
	 */
	public void sendRootDSE(int currentMessageId) throws IOException {
		log.debug("LOG_LDAP_SEND_ROOT_DSE");

		Map attributes = new HashMap<>();
		attributes.put("objectClass", "top");
		attributes.put("namingContexts", Ldap.NAMING_CONTEXTS);
		//attributes.put("supportedsaslmechanisms", "PLAIN");

		sendEntry(currentMessageId, "Root DSE", attributes);
	}

	public void sendEntry(int currentMessageId, String dn, Map attributes) throws IOException {
		LogUtils.trace(log, "sendEntry", currentMessageId, dn, attributes.size());
		// synchronize on responseBer
		synchronized (responseBer) {
			responseBer.reset();
			responseBer.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
			responseBer.encodeInt(currentMessageId);
			responseBer.beginSeq(Ldap.LDAP_REP_SEARCH);
			responseBer.encodeString(dn, isLdapV3());
			responseBer.beginSeq(Ldap.LBER_SEQUENCE);
			for (Map.Entry entry : attributes.entrySet()) {
				responseBer.beginSeq(Ldap.LBER_SEQUENCE);
				responseBer.encodeString(entry.getKey(), isLdapV3());
				responseBer.beginSeq(Ldap.LBER_SET);
				Object values = entry.getValue();
				if (values instanceof String) {
					responseBer.encodeString((String) values, isLdapV3());
				} else if (values instanceof List) {
					for (Object value : (List) values) {
						responseBer.encodeString((String) value, isLdapV3());
					}
				} else {
					throw new RuntimeException("EXCEPTION_UNSUPPORTED_VALUE: " + values);
				}
				responseBer.endSeq();
				responseBer.endSeq();
			}
			responseBer.endSeq();
			responseBer.endSeq();
			responseBer.endSeq();
			sendResponse();
		}
	}

	public void sendErr(int currentMessageId, int responseOperation, Exception e) throws IOException {
		String message = e.getMessage();
		if (message == null) {
			message = e.toString();
		}
		sendClient(currentMessageId, responseOperation, Ldap.LDAP_OTHER, message);
	}

	public void sendClient(int currentMessageId, int responseOperation, int status, String message) throws IOException {
		responseBer.reset();

		responseBer.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
		responseBer.encodeInt(currentMessageId);
		responseBer.beginSeq(responseOperation);
		responseBer.encodeInt(status, Ldap.LBER_ENUMERATED);
		// dn
		responseBer.encodeString("", isLdapV3());
		// error message
		responseBer.encodeString(message, isLdapV3());
		responseBer.endSeq();
		responseBer.endSeq();
		sendResponse();
	}

	public void sendResponse() throws IOException {
		//Ber.dumpBER(System.out, ">\n", responseBer.getBuf(), 0, responseBer.getDataLen());
		os.write(responseBer.getBuf(), 0, responseBer.getDataLen());
		os.flush();
	}

	void setVersion(int v) {
		ldapVersion = v;
	}

	/**
	 * Send Base Context
	 *
	 * @param currentMessageId current message id
	 * @throws IOException on error
	 */
	public void sendBaseContext(int currentMessageId) throws IOException {
		List objectClasses = new ArrayList<>();
		objectClasses.add("top");
		objectClasses.add("organizationalUnit");
		Map attributes = new HashMap<>();
		attributes.put("objectClass", objectClasses);
		attributes.put("description", "Milton LDAP Gateway");
		sendEntry(currentMessageId, Ldap.BASE_CONTEXT, attributes);
	}

	/**
	 * Send ComputerContext
	 *
	 * @param currentMessageId current message id
	 * @param returningAttributes attributes to return
	 * @throws IOException on error
	 */
	public void sendComputerContext(int currentMessageId, Set returningAttributes) throws IOException {
		List objectClasses = new ArrayList<>();
		objectClasses.add("top");
		objectClasses.add("apple-computer");
		Map attributes = new HashMap<>();
		addIf(attributes, returningAttributes, "objectClass", objectClasses);
		addIf(attributes, returningAttributes, "apple-generateduid", Ldap.COMPUTER_GUID);
		addIf(attributes, returningAttributes, "apple-serviceinfo", getServiceInfo());
		// TODO: remove ?
		addIf(attributes, returningAttributes, "apple-xmlplist", getServiceInfo());
		addIf(attributes, returningAttributes, "apple-serviceslocator", "::anyService");
		addIf(attributes, returningAttributes, "cn", getCurrentHostName());

		String dn = "cn=" + getCurrentHostName() + ", " + Ldap.COMPUTER_CONTEXT;
		LogUtils.debug(log, "LOG_LDAP_SEND_COMPUTER_CONTEXT", dn, attributes);

		sendEntry(currentMessageId, dn, attributes);
	}

	protected String getServiceInfo() {
		StringBuilder buffer = new StringBuilder();
		buffer.append(""
				+ ""
				+ ""
				+ ""
				+ "com.apple.macosxserver.host"
				+ ""
				+ "localhost" + // NOTE: Will be replaced by real hostname
				""
				+ "com.apple.macosxserver.virtualhosts"
				+ ""
				+ "" + Ldap.VIRTUALHOST_GUID + ""
				+ ""
				+ "hostDetails"
				+ ""
				+ "http"
				+ ""
				+ "enabled"
				+ ""
				+ ""
				+ "https"
				+ ""
				+ "disabled"
				+ ""
				+ "port"
				+ "0"
				+ ""
				+ ""
				+ "hostname"
				+ "");
		try {
			buffer.append(getCurrentHostName());
		} catch (UnknownHostException ex) {
			buffer.append("Unknown host");
		}
		buffer.append(""
				+ "serviceInfo"
				+ ""
				+ "calendar"
				+ ""
				+ "enabled"
				+ ""
				+ "templates"
				+ ""
				+ "calendarUserAddresses"
				+ ""
				+ "%(principaluri)s"
				+ "mailto:%(email)s"
				+ "urn:uuid:%(guid)s"
				+ ""
				+ "principalPath"
				+ "/principals/__uuids__/%(guid)s/"
				+ ""
				+ ""
				+ ""
				+ "serviceType"
				+ ""
				+ "calendar"
				+ ""
				+ ""
				+ ""
				+ ""
				+ "");

		return buffer.toString();
	}
	

	protected String getCurrentHostName() throws UnknownHostException {
		if (currentHostName == null) {
			if (client.getInetAddress().isLoopbackAddress()) {
				// local address, probably using localhost in iCal URL
				currentHostName = "localhost";
			} else {
				// remote address, send fully qualified domain name
				currentHostName = InetAddress.getLocalHost().getCanonicalHostName();
			}
		}
		return currentHostName;
	}	
	

	public void dumpBer(byte[] inbuf, int offset) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		Ber.dumpBER(baos, "LDAP request buffer\n", inbuf, 0, offset);
		try {
			log.debug(new String(baos.toByteArray(), "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// should not happen
			log.error("", e);
		}
	}
	

	protected void addIf(Map attributes, Set returningAttributes, String name, Object value) {
		if ((returningAttributes.isEmpty()) || returningAttributes.contains(name)) {
			attributes.put(name, value);
		}
	}	

	public void sendBindResponse(int currentMessageId, int status, byte[] serverResponse) throws IOException {
		responseBer.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
		responseBer.encodeInt(currentMessageId);
		responseBer.beginSeq(Ldap.LDAP_REP_BIND);
		responseBer.encodeInt(status, Ldap.LBER_ENUMERATED);
		// server credentials	
		responseBer.encodeString("", isLdapV3());
		responseBer.encodeString("", isLdapV3());
		// challenge or response
		if (serverResponse != null) {
			responseBer.encodeOctetString(serverResponse, 0x87);
		}
		responseBer.endSeq();
		responseBer.endSeq();
		sendResponse();
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy