io.milton.ldap.LdapResponseHandler Maven / Gradle / Ivy
/*
* 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 - 2025 Weber Informatics LLC | Privacy Policy