Skip to content

Instantly share code, notes, and snippets.

@jrichardsz
Last active February 6, 2023 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jrichardsz/b2efb318381caebf0acbe57c5c58c403 to your computer and use it in GitHub Desktop.
Save jrichardsz/b2efb318381caebf0acbe57c5c58c403 to your computer and use it in GitHub Desktop.
ad ldap snippets
https://knowledge.broadcom.com/external/article/207245/ldap-errors-explanations-from-smpslog-of.html
At first glance, those errors are returned by the LDAP Server and they're no specific code from SiteMinder.
80090308: LdapErr: DSID-0C09044E, comment AcceptSecurityContext error, data 52e, v2580
This error means the username is valid, but the password is not valid (1).
[6915/140245661083392][Mon Jan 04 2021 22:27:43][SmDsLdapProvider.cpp:1888][ERROR][sm-Ldap-00650] CSmDsLdapProvider::Search(): Wrong syntax of LDAP search filter (samAccountName=) 
It means as there's no value passed to samAccountName, then the filter cannot be applied:
CSmDsLdapProvider::Search(): Wrong syntax of LDAP search filter: (samAccountName=)
[2738/140170544277248][Mon Jan 04 2021 21:09:30][SmDsLdapConnMgr.cpp:1201][ERROR][sm-Ldap-02230] Error# '32' during search: 'error: No such object extended error: 0000208D: NameErr: DSID-03100238, problem 2001 (NO_OBJECT), data 0, best match of: 'cn=jsmith,dc=training,dc=com' matched dn: cn=jsmith,dc=training,dc=com' Search Query = 'objectclass=*' for server '10.0.0.1:636'
It means the defined DN doesn't exist (2).
[10840/20][Mon Jan 04 2021 21:01:54][SmDsLdapFunctionImpl.cpp:1367][ERROR][sm-Ldap-00880] (SetUserProp) DN: 'cn=jsmith,dc=training,dc=com', PropName: 'myProp', PropValue: 'myUser [NDSEnc-J]dfasdfsfsdfsdfSDDFSaDsdASdASDas1241421313dadsd'. Status: Error 50 . Insufficient access
The admin user that connects to the LDAP Store hasn't sufficient rights to set the property "myProp" with value "myUser:[NDSEnc-J]dfasdfsfsdfsdfSDDFSaDsdASdASDas1241421313dadsd" for user "cn=jsmith,dc=training,dc=com";
[793/140026520262400][Mon Jan 04 2021 17:07:50][plugin_AD.cpp:821][ERROR][sm-Ldap-02070] Failed to read Active Directory user attribute userAccountControl for user: cn=jsmith,dc=training,dc=com
The admin user that connects to the LDAP Store cannot read the attribute "userAccountControl" value for user "cn=jsmith,dc=training,dc=com";
Maybe for rights or the value is corrupted or the value isn't in the proper format or there's no value;
[13528/140711800305408][Mon Jan 04 2021 16:27:49][SmDsLdapConnMgr.cpp:1201][ERROR][sm-Ldap-02230] Error# '87' during search: 'error: Bad search filter' Search Query = 'all' for server '10.0.0.1:636'
The search filter has been set to 'all' probably in 1 Policy:
In the User Tab, User directories are displayed and when clicking on "Add Entry" of the LDAP directory then the browser goes to the "User Directory Search Expression Editor" screen. When setting something wrong there then this error will show.
Error 87 is about filter problem (3).
Common Active Directory Bind Errors
| Code | hex | DEC | Short Description | More Information | Comments |
|------+-----+------+---------------------+------------------------------------+-------------------------|
| 49 | 52e | 1326 | ERROR_LOGON_FAILURE | Returns when username is valid but | Will prevent most other |
| | | | | password/credential is invalid. | errors from being |
| | | | | | displayed as noted. |
(2)
LDAP Error Code 32
| Data Code | Description |
|-----------+---------------------------|
| 0 | Defined DN does not exist |
package test;
import java.net.*;
import java.io.*;
public class ServerSideSocket {
public void run() {
try {
int serverPort = 33389;
ServerSocket serverSocket = new ServerSocket(serverPort);
while(true) {
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket socket = serverSocket.accept();
System.out.println("Jus connected to " + socket.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
PrintWriter toClient =
new PrintWriter(socket.getOutputStream(),true);
System.out.println("Server received: " + in.readInt());
toClient.println("Thank you");
}
}
catch(UnknownHostException ex) {
ex.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
ServerSideSocket srv = new ServerSideSocket();
srv.run();
}
}
package test;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.xml.bind.DatatypeConverter;
/*
* https://www.bogotobogo.com/Java/tutorials/tcp_socket_server_client.php
* */
public class LdapServerMock implements Runnable {
private static final int BIND_OR_CLOSE = 809042433;
private static final int SEARCH = 812581377;
private static final int UPDATE = 812974593;
private ServerSocket serverSocket = null;
public void stop() throws IOException {
serverSocket.close();
}
public void run() {
try {
int serverPort = 33389;
serverSocket = new ServerSocket(serverPort);
while (true) {
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
int operation = in.readInt();
System.out.println("operation: " + operation);
switch (operation) {
case BIND_OR_CLOSE:
System.out.println("BIND_OR_CLOSE");
sendByteMessage(out, "300c02010161070a010004000400");
break;
case SEARCH:
System.out.println("SEARCH");
sendByteMessage(out, "300c02010265070a010004000400");
break;
case UPDATE:
System.out.println("UPDATE");
sendByteMessage(out, "300c02010267070a010004000400");
break;
default:
System.out.println("operation not supported");
}
}
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendByteMessage(DataOutputStream out, String hexaAsString) throws IOException {
byte[] message = DatatypeConverter.parseHexBinary(hexaAsString);
out.writeInt(message.length);
out.write(message);
System.out.println("message was sent");
}
public static void main(String[] args) {
LdapServerMock srv = new LdapServerMock();
srv.run();
}
}

Java way

start in-memory ldap

InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=example,dc=org");
config.addAdditionalBindCredentials("uid=admin,ou=people,dc=example,dc=org", "changeme");
config.setListenerConfigs(
    new InMemoryListenerConfig("myListener", null, 33389, null, null, null));

String baseLocation = Paths.get(".").toAbsolutePath().normalize().toString();
Path pathLdifFile =
    (Path) Paths.get(baseLocation, "src", "test", "resources", "ldap-test-data.ldif");
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
ds.importFromLDIF(true, pathLdifFile.toFile().getAbsolutePath());
ds.startListening();

configuration

Hashtable<String, String> environment = new Hashtable<String, String>();

environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL,
    String.format("%s://%s:%s", ldapProtocol, ldapHost, Integer.parseInt(ldapPort)));
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=people,dc=example,dc=org");
environment.put(Context.SECURITY_CREDENTIALS, "changeme");
environment.put("java.naming.ldap.attributes.binary", "objectSid ObjectGUID");
if (ldapProtocol.contentEquals("ldaps")) {
  environment.put(Context.SECURITY_PROTOCOL, "SSL");
}

InitialDirContext context = new InitialDirContext(environment);
context.close();
logger.info("Validate: connected successfully");

LDIF file way

ldap-test-data.ldif

dn: dc=example,dc=org
objectclass: domain
objectclass: top
dc: example

dn: ou=groups,dc=example,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=people,dc=example,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

# admin user
dn: uid=admin,ou=people,dc=example,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Rod Johnson
sn: admin
uid: admin
userPassword: changeme

start in-memory ldap

InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=example,dc=org");
config.setListenerConfigs(
    new InMemoryListenerConfig("myListener", null, 33389, null, null, null));

String baseLocation = Paths.get(".").toAbsolutePath().normalize().toString();
Path pathLdifFile =
    (Path) Paths.get(baseLocation, "src", "test", "resources", "ldap-test-data.ldif");
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
ds.importFromLDIF(true, pathLdifFile.toFile().getAbsolutePath());
ds.startListening();

configuration

Hashtable<String, String> environment = new Hashtable<String, String>();

environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL,
    String.format("%s://%s:%s", ldapProtocol, ldapHost, Integer.parseInt(ldapPort)));
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=people,dc=example,dc=org");
environment.put(Context.SECURITY_CREDENTIALS, "changeme");
environment.put("java.naming.ldap.attributes.binary", "objectSid ObjectGUID");
if (ldapProtocol.contentEquals("ldaps")) {
  environment.put(Context.SECURITY_PROTOCOL, "SSL");
}

InitialDirContext context = new InitialDirContext(environment);
context.close();
logger.info("Validate: connected successfully");

ldap protocols

nodejs mock

const net = require('net');
const server = net.createServer();
server.on('connection', handleConnection);
server.listen(33389);

function handleConnection(socket) {
  socket.on('data', (chunk) => {
    console.log('Received chunk:');
    console.log(chunk.toString())
    var operationInteger = chunk.readUInt32BE();
    switch(operationInteger){
      case 809042433:
        console.log("bind or close")
        socket.write(Buffer.from('300c02010161070a010004000400', 'hex'));
        break;
      case 812581377:
        console.log("search")
        socket.write(Buffer.from('300c02010265070a010004000400', 'hex'));
        break; 
        case 812974593:
          console.log("update")
          socket.write(Buffer.from('300c02010267070a010004000400', 'hex'));
          break;                 
      default:
        console.log(`operation int not supported: ${operationInteger} \n`+chunk.toString());  
    }
  });
}
https://ldap.com/ldapv3-wire-protocol-reference-bind/
/*
* Copyright 2007-2022 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2007-2022 Ping Identity Corporation
*
* Licensed 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.
*/
/*
* Copyright (C) 2007-2022 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
package com.unboundid.ldap.sdk;
import java.util.ArrayList;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.asn1.ASN1StreamReader;
import com.unboundid.asn1.ASN1StreamReaderSequence;
import com.unboundid.util.Debug;
import com.unboundid.util.Extensible;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import static com.unboundid.ldap.sdk.LDAPMessages.*;
/**
* This class provides a data structure for holding information about the result
* of processing a bind operation. It provides generic bind response elements
* as described in the {@link LDAPResult} class, but may be overridden to
* provide more detailed information for specific types of bind requests.
*/
@Extensible()
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public class BindResult
extends LDAPResult
{
/**
* The BER type for the server SASL credentials element in the bind result.
*/
private static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87;
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 2211625049303605730L;
// The server SASL credentials from the response, if available.
@Nullable private final ASN1OctetString serverSASLCredentials;
/**
* Creates a new bind result with the provided information.
*
* @param messageID The message ID for the LDAP message that is
* associated with this bind result.
* @param resultCode The result code from the response.
* @param diagnosticMessage The diagnostic message from the response, if
* available.
* @param matchedDN The matched DN from the response, if available.
* @param referralURLs The set of referral URLs from the response, if
* available.
* @param responseControls The set of controls from the response, if
* available.
*/
public BindResult(final int messageID, @NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final String[] referralURLs,
@Nullable final Control[] responseControls)
{
this(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
responseControls, null);
}
/**
* Creates a new bind result with the provided information.
*
* @param messageID The message ID for the LDAP message that is
* associated with this bind result.
* @param resultCode The result code from the response.
* @param diagnosticMessage The diagnostic message from the response, if
* available.
* @param matchedDN The matched DN from the response, if
* available.
* @param referralURLs The set of referral URLs from the response,
* if available.
* @param responseControls The set of controls from the response, if
* available.
* @param serverSASLCredentials The server SASL credentials from the
* response, if available.
*/
public BindResult(final int messageID, @NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final String[] referralURLs,
@Nullable final Control[] responseControls,
@Nullable final ASN1OctetString serverSASLCredentials)
{
super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
responseControls);
this.serverSASLCredentials = serverSASLCredentials;
}
/**
* Creates a new bind result from the provided generic LDAP result.
*
* @param ldapResult The LDAP result to use to create this bind result.
*/
public BindResult(@NotNull final LDAPResult ldapResult)
{
super(ldapResult);
serverSASLCredentials = null;
}
/**
* Creates a new bind result from the provided {@code LDAPException}.
*
* @param exception The {@code LDAPException} to use to create this bind
* result.
*/
public BindResult(@NotNull final LDAPException exception)
{
super(exception.toLDAPResult());
if (exception instanceof LDAPBindException)
{
serverSASLCredentials =
((LDAPBindException) exception).getServerSASLCredentials();
}
else
{
serverSASLCredentials = null;
}
}
/**
* Creates a new bind result from the provided bind result. This constructor
* may be used in creating custom subclasses.
*
* @param bindResult The bind result to use to create this bind result.
*/
protected BindResult(@NotNull final BindResult bindResult)
{
super(bindResult);
serverSASLCredentials = bindResult.serverSASLCredentials;
}
/**
* Creates a new bind result object with the provided message ID and with the
* protocol op and controls read from the given ASN.1 stream reader.
*
* @param messageID The LDAP message ID for the LDAP message that is
* associated with this bind result.
* @param messageSequence The ASN.1 stream reader sequence used in the
* course of reading the LDAP message elements.
* @param reader The ASN.1 stream reader from which to read the
* protocol op and controls.
*
* @return The decoded bind result.
*
* @throws LDAPException If a problem occurs while reading or decoding data
* from the ASN.1 stream reader.
*/
@NotNull()
static BindResult readBindResultFrom(final int messageID,
@NotNull final ASN1StreamReaderSequence messageSequence,
@NotNull final ASN1StreamReader reader)
throws LDAPException
{
try
{
final ASN1StreamReaderSequence protocolOpSequence =
reader.beginSequence();
final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
String matchedDN = reader.readString();
if (matchedDN.isEmpty())
{
matchedDN = null;
}
String diagnosticMessage = reader.readString();
if (diagnosticMessage.isEmpty())
{
diagnosticMessage = null;
}
String[] referralURLs = null;
ASN1OctetString serverSASLCredentials = null;
while (protocolOpSequence.hasMoreElements())
{
final byte type = (byte) reader.peek();
switch (type)
{
case TYPE_REFERRAL_URLS:
final ArrayList<String> refList = new ArrayList<>(1);
final ASN1StreamReaderSequence refSequence = reader.beginSequence();
while (refSequence.hasMoreElements())
{
refList.add(reader.readString());
}
referralURLs = new String[refList.size()];
refList.toArray(referralURLs);
break;
case TYPE_SERVER_SASL_CREDENTIALS:
serverSASLCredentials =
new ASN1OctetString(type, reader.readBytes());
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_BIND_RESULT_INVALID_ELEMENT.get(StaticUtils.toHex(type)));
}
}
Control[] controls = NO_CONTROLS;
if (messageSequence.hasMoreElements())
{
final ArrayList<Control> controlList = new ArrayList<>(1);
final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
while (controlSequence.hasMoreElements())
{
controlList.add(Control.readFrom(reader));
}
controls = new Control[controlList.size()];
controlList.toArray(controls);
}
return new BindResult(messageID, resultCode, diagnosticMessage, matchedDN,
referralURLs, controls, serverSASLCredentials);
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw le;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_BIND_RESULT_CANNOT_DECODE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Retrieves the server SASL credentials from the bind result, if available.
*
* @return The server SASL credentials from the bind response, or
* {@code null} if none were provided.
*/
@Nullable()
public ASN1OctetString getServerSASLCredentials()
{
return serverSASLCredentials;
}
/**
* {@inheritDoc}
*/
@Override()
public void toString(@NotNull final StringBuilder buffer)
{
buffer.append("BindResult(resultCode=");
buffer.append(getResultCode());
final int messageID = getMessageID();
if (messageID >= 0)
{
buffer.append(", messageID=");
buffer.append(messageID);
}
final String diagnosticMessage = getDiagnosticMessage();
if (diagnosticMessage != null)
{
buffer.append(", diagnosticMessage='");
buffer.append(diagnosticMessage);
buffer.append('\'');
}
final String matchedDN = getMatchedDN();
if (matchedDN != null)
{
buffer.append(", matchedDN='");
buffer.append(matchedDN);
buffer.append('\'');
}
final String[] referralURLs = getReferralURLs();
if (referralURLs.length > 0)
{
buffer.append(", referralURLs={");
for (int i=0; i < referralURLs.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append('\'');
buffer.append(referralURLs[i]);
buffer.append('\'');
}
buffer.append('}');
}
buffer.append(", hasServerSASLCredentials=");
buffer.append(serverSASLCredentials != null);
final Control[] responseControls = getResponseControls();
if (responseControls.length > 0)
{
buffer.append(", responseControls={");
for (int i=0; i < responseControls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(responseControls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
}
/*
* Copyright 2007-2022 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2007-2022 Ping Identity Corporation
*
* Licensed 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.
*/
/*
* Copyright (C) 2007-2022 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
package com.unboundid.ldap.sdk;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.unboundid.asn1.ASN1Exception;
import com.unboundid.asn1.ASN1StreamReader;
import com.unboundid.asn1.ASN1StreamReaderSequence;
import com.unboundid.ldap.protocol.LDAPMessage;
import com.unboundid.ldap.protocol.LDAPResponse;
import com.unboundid.util.Debug;
import com.unboundid.util.Extensible;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import static com.unboundid.ldap.sdk.LDAPMessages.*;
/**
* This class provides a data structure for holding the elements that are common
* to most types of LDAP responses. The elements contained in an LDAP result
* include:
* <UL>
* <LI>Result Code -- An integer value that provides information about the
* status of the operation. See the {@link ResultCode} class for
* information about a number of result codes defined in LDAP.</LI>
* <LI>Diagnostic Message -- An optional string that may provide additional
* information about the operation. For example, if the operation failed,
* it may include information about the reason for the failure. It will
* often (but not always) be absent in the result for successful
* operations, and it may be absent in the result for failed
* operations.</LI>
* <LI>Matched DN -- An optional DN which specifies the entry that most
* closely matched the DN of a non-existent entry in the server. For
* example, if an operation failed because the target entry did not exist,
* then the matched DN field may specify the DN of the closest ancestor
* to that entry that does exist in the server.</LI>
* <LI>Referral URLs -- An optional set of LDAP URLs which refer to other
* directories and/or locations within the DIT in which the operation may
* be attempted. If multiple referral URLs are provided, then they should
* all be considered equivalent for the purpose of attempting the
* operation (e.g., the different URLs may simply refer to different
* servers in which the operation could be processed).</LI>
* <LI>Response Controls -- An optional set of controls included in the
* response from the server. If any controls are included, then they may
* provide additional information about the processing that was performed
* by the server.</LI>
* </UL>
* <BR><BR>
* Note that even though this class is marked with the @Extensible annotation
* type, it should not be directly subclassed by third-party code. Only the
* {@link BindResult} and {@link ExtendedResult} subclasses are actually
* intended to be extended by third-party code.
*/
@Extensible()
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public class LDAPResult
implements Serializable, LDAPResponse
{
/**
* The BER type for the set of referral URLs.
*/
static final byte TYPE_REFERRAL_URLS = (byte) 0xA3;
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 2215819095653175991L;
// The protocol op type for this result, if available.
@Nullable private final Byte protocolOpType;
// The set of controls from the response.
@NotNull private final Control[] responseControls;
// The message ID for the LDAP message that is associated with this LDAP
// result.
private final int messageID;
// The result code from the response.
@NotNull private final ResultCode resultCode;
// The diagnostic message from the response, if available.
@Nullable private final String diagnosticMessage;
// The matched DN from the response, if available.
@Nullable private final String matchedDN;
// The set of referral URLs from the response, if available.
@NotNull private final String[] referralURLs;
/**
* Creates a new LDAP result object based on the provided result.
*
* @param result The LDAP result object to use to initialize this result.
*/
protected LDAPResult(@NotNull final LDAPResult result)
{
protocolOpType = result.protocolOpType;
messageID = result.messageID;
resultCode = result.resultCode;
diagnosticMessage = result.diagnosticMessage;
matchedDN = result.matchedDN;
referralURLs = result.referralURLs;
responseControls = result.responseControls;
}
/**
* Creates a new LDAP result object with the provided message ID and result
* code, and no other information.
*
* @param messageID The message ID for the LDAP message that is associated
* with this LDAP result.
* @param resultCode The result code from the response.
*/
public LDAPResult(final int messageID, @NotNull final ResultCode resultCode)
{
this(null, messageID, resultCode, null, null, StaticUtils.NO_STRINGS,
NO_CONTROLS);
}
/**
* Creates a new LDAP result object with the provided information.
*
* @param messageID The message ID for the LDAP message that is
* associated with this LDAP result.
* @param resultCode The result code from the response.
* @param diagnosticMessage The diagnostic message from the response, if
* available.
* @param matchedDN The matched DN from the response, if available.
* @param referralURLs The set of referral URLs from the response, if
* available.
* @param responseControls The set of controls from the response, if
* available.
*/
public LDAPResult(final int messageID, @NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final String[] referralURLs,
@Nullable final Control[] responseControls)
{
this(null, messageID, resultCode, diagnosticMessage, matchedDN,
referralURLs, responseControls);
}
/**
* Creates a new LDAP result object with the provided information.
*
* @param messageID The message ID for the LDAP message that is
* associated with this LDAP result.
* @param resultCode The result code from the response.
* @param diagnosticMessage The diagnostic message from the response, if
* available.
* @param matchedDN The matched DN from the response, if available.
* @param referralURLs The set of referral URLs from the response, if
* available.
* @param responseControls The set of controls from the response, if
* available.
*/
public LDAPResult(final int messageID, @NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final List<String> referralURLs,
@Nullable final List<Control> responseControls)
{
this(null, messageID, resultCode, diagnosticMessage, matchedDN,
referralURLs, responseControls);
}
/**
* Creates a new LDAP result object with the provided information.
*
* @param protocolOpType The protocol op type for this result, if
* available.
* @param messageID The message ID for the LDAP message that is
* associated with this LDAP result.
* @param resultCode The result code from the response.
* @param diagnosticMessage The diagnostic message from the response, if
* available.
* @param matchedDN The matched DN from the response, if available.
* @param referralURLs The set of referral URLs from the response, if
* available.
* @param responseControls The set of controls from the response, if
* available.
*/
private LDAPResult(@Nullable final Byte protocolOpType, final int messageID,
@NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final String[] referralURLs,
@Nullable final Control[] responseControls)
{
this.protocolOpType = protocolOpType;
this.messageID = messageID;
this.resultCode = resultCode;
this.diagnosticMessage = diagnosticMessage;
this.matchedDN = matchedDN;
if (referralURLs == null)
{
this.referralURLs = StaticUtils.NO_STRINGS;
}
else
{
this.referralURLs = referralURLs;
}
if (responseControls == null)
{
this.responseControls = NO_CONTROLS;
}
else
{
this.responseControls = responseControls;
}
}
/**
* Creates a new LDAP result object with the provided information.
*
* @param protocolOpType The protocol op type for this result, if
* available.
* @param messageID The message ID for the LDAP message that is
* associated with this LDAP result.
* @param resultCode The result code from the response.
* @param diagnosticMessage The diagnostic message from the response, if
* available.
* @param matchedDN The matched DN from the response, if available.
* @param referralURLs The set of referral URLs from the response, if
* available.
* @param responseControls The set of controls from the response, if
* available.
*/
private LDAPResult(@Nullable final Byte protocolOpType, final int messageID,
@NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final List<String> referralURLs,
@Nullable final List<Control> responseControls)
{
this.protocolOpType = protocolOpType;
this.messageID = messageID;
this.resultCode = resultCode;
this.diagnosticMessage = diagnosticMessage;
this.matchedDN = matchedDN;
if ((referralURLs == null) || referralURLs.isEmpty())
{
this.referralURLs = StaticUtils.NO_STRINGS;
}
else
{
this.referralURLs = new String[referralURLs.size()];
referralURLs.toArray(this.referralURLs);
}
if ((responseControls == null) || responseControls.isEmpty())
{
this.responseControls = NO_CONTROLS;
}
else
{
this.responseControls = new Control[responseControls.size()];
responseControls.toArray(this.responseControls);
}
}
/**
* Creates a new LDAP result object with the provided message ID and with the
* protocol op and controls read from the given ASN.1 stream reader.
*
* @param messageID The LDAP message ID for the LDAP message that is
* associated with this LDAP result.
* @param messageSequence The ASN.1 stream reader sequence used in the
* course of reading the LDAP message elements.
* @param reader The ASN.1 stream reader from which to read the
* protocol op and controls.
*
* @return The decoded LDAP result.
*
* @throws LDAPException If a problem occurs while reading or decoding data
* from the ASN.1 stream reader.
*/
@NotNull()
static LDAPResult readLDAPResultFrom(final int messageID,
@NotNull final ASN1StreamReaderSequence messageSequence,
@NotNull final ASN1StreamReader reader)
throws LDAPException
{
try
{
final ASN1StreamReaderSequence protocolOpSequence =
reader.beginSequence();
final byte protocolOpType = protocolOpSequence.getType();
final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated());
String matchedDN = reader.readString();
if (matchedDN.isEmpty())
{
matchedDN = null;
}
String diagnosticMessage = reader.readString();
if (diagnosticMessage.isEmpty())
{
diagnosticMessage = null;
}
String[] referralURLs = StaticUtils.NO_STRINGS;
if (protocolOpSequence.hasMoreElements())
{
final ArrayList<String> refList = new ArrayList<>(1);
final ASN1StreamReaderSequence refSequence = reader.beginSequence();
while (refSequence.hasMoreElements())
{
refList.add(reader.readString());
}
referralURLs = new String[refList.size()];
refList.toArray(referralURLs);
}
Control[] responseControls = NO_CONTROLS;
if (messageSequence.hasMoreElements())
{
final ArrayList<Control> controlList = new ArrayList<>(1);
final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
while (controlSequence.hasMoreElements())
{
controlList.add(Control.readFrom(reader));
}
responseControls = new Control[controlList.size()];
controlList.toArray(responseControls);
}
return new LDAPResult(protocolOpType, messageID, resultCode,
diagnosticMessage, matchedDN, referralURLs, responseControls);
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw le;
}
catch (final ASN1Exception ae)
{
Debug.debugException(ae);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_RESULT_CANNOT_DECODE.get(ae.getMessage()), ae);
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_RESULT_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)), e);
}
}
/**
* Retrieves the message ID for the LDAP message with which this LDAP result
* is associated.
*
* @return The message ID for the LDAP message with which this LDAP result
* is associated.
*/
@Override()
public final int getMessageID()
{
return messageID;
}
/**
* Retrieves the type of operation that triggered this result, if available.
*
* @return The type of operation that triggered this result, or {@code null}
* if the operation type is not available.
*
* Retrieves the BER type for the LDAP protocol op from which this
*/
@Nullable()
public final OperationType getOperationType()
{
if (protocolOpType != null)
{
switch (protocolOpType)
{
case LDAPMessage.PROTOCOL_OP_TYPE_ADD_RESPONSE:
return OperationType.ADD;
case LDAPMessage.PROTOCOL_OP_TYPE_BIND_RESPONSE:
return OperationType.BIND;
case LDAPMessage.PROTOCOL_OP_TYPE_COMPARE_RESPONSE:
return OperationType.COMPARE;
case LDAPMessage.PROTOCOL_OP_TYPE_DELETE_RESPONSE:
return OperationType.DELETE;
case LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_RESPONSE:
return OperationType.EXTENDED;
case LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_RESPONSE:
return OperationType.MODIFY;
case LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE:
return OperationType.MODIFY_DN;
case LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE:
return OperationType.SEARCH;
}
}
return null;
}
/**
* Retrieves the result code from the response.
*
* @return The result code from the response.
*/
@NotNull()
public final ResultCode getResultCode()
{
return resultCode;
}
/**
* Retrieves the diagnostic message from the response, if available.
*
* @return The diagnostic message from the response, or {@code null} if none
* was provided.
*/
@Nullable()
public final String getDiagnosticMessage()
{
return diagnosticMessage;
}
/**
* Retrieves the matched DN from the response, if available.
*
* @return The matched DN from the response, or {@code null} if none was
* provided.
*/
@Nullable()
public final String getMatchedDN()
{
return matchedDN;
}
/**
* Retrieves the set of referral URLs from the response, if available.
*
* @return The set of referral URLs from the response. The array returned
* may be empty if the response did not include any referral URLs.
*/
@NotNull()
public final String[] getReferralURLs()
{
return referralURLs;
}
/**
* Retrieves the set of controls from the response, if available. Individual
* response controls of a specific type may be retrieved and decoded using the
* {@code get} method in the response control class.
*
* @return The set of controls from the response. The array returned may be
* empty if the response did not include any controls.
*/
@NotNull()
public final Control[] getResponseControls()
{
return responseControls;
}
/**
* Indicates whether this result contains at least one control.
*
* @return {@code true} if this result contains at least one control, or
* {@code false} if not.
*/
public final boolean hasResponseControl()
{
return (responseControls.length > 0);
}
/**
* Indicates whether this result contains at least one control with the
* specified OID.
*
* @param oid The object identifier for which to make the determination. It
* must not be {@code null}.
*
* @return {@code true} if this result contains at least one control with
* the specified OID, or {@code false} if not.
*/
public final boolean hasResponseControl(@NotNull final String oid)
{
for (final Control c : responseControls)
{
if (c.getOID().equals(oid))
{
return true;
}
}
return false;
}
/**
* Retrieves the response control with the specified OID. If there is more
* than one response control with the specified OID, then the first will be
* returned.
*
* @param oid The OID for the response control to retrieve.
*
* @return The requested response control, or {@code null} if there is no
* such response control.
*/
@Nullable()
public final Control getResponseControl(@NotNull final String oid)
{
for (final Control c : responseControls)
{
if (c.getOID().equals(oid))
{
return c;
}
}
return null;
}
/**
* Retrieves a string representation of this LDAP result, consisting of
* the result code, diagnostic message (if present), matched DN (if present),
* and referral URLs (if present).
*
* @return A string representation of this LDAP result.
*/
@NotNull()
public String getResultString()
{
final StringBuilder buffer = new StringBuilder();
buffer.append("result code='");
buffer.append(resultCode);
buffer.append('\'');
if ((diagnosticMessage != null) && (! diagnosticMessage.isEmpty()))
{
buffer.append(" diagnostic message='");
buffer.append(diagnosticMessage);
buffer.append('\'');
}
if ((matchedDN != null) && (! matchedDN.isEmpty()))
{
buffer.append(" matched DN='");
buffer.append(matchedDN);
buffer.append('\'');
}
if ((referralURLs != null) && (referralURLs.length > 0))
{
buffer.append(" referral URLs={");
for (int i=0; i < referralURLs.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append('\'');
buffer.append(referralURLs[i]);
buffer.append('\'');
}
buffer.append('}');
}
return buffer.toString();
}
/**
* Retrieves a string representation of this LDAP result.
*
* @return A string representation of this LDAP result.
*/
@Override()
@NotNull()
public String toString()
{
final StringBuilder buffer = new StringBuilder();
toString(buffer);
return buffer.toString();
}
/**
* Appends a string representation of this LDAP result to the provided buffer.
*
* @param buffer The buffer to which to append a string representation of
* this LDAP result.
*/
@Override()
public void toString(@NotNull final StringBuilder buffer)
{
buffer.append("LDAPResult(resultCode=");
buffer.append(resultCode);
if (messageID >= 0)
{
buffer.append(", messageID=");
buffer.append(messageID);
}
if (protocolOpType != null)
{
switch (protocolOpType)
{
case LDAPMessage.PROTOCOL_OP_TYPE_ADD_RESPONSE:
buffer.append(", opType='add'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_BIND_RESPONSE:
buffer.append(", opType='bind'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_COMPARE_RESPONSE:
buffer.append(", opType='compare'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_DELETE_RESPONSE:
buffer.append(", opType='delete'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_RESPONSE:
buffer.append(", opType='extended'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_RESPONSE:
buffer.append(", opType='modify'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_DN_RESPONSE:
buffer.append(", opType='modify DN'");
break;
case LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_DONE:
buffer.append(", opType='search'");
break;
}
}
if (diagnosticMessage != null)
{
buffer.append(", diagnosticMessage='");
buffer.append(diagnosticMessage);
buffer.append('\'');
}
if (matchedDN != null)
{
buffer.append(", matchedDN='");
buffer.append(matchedDN);
buffer.append('\'');
}
if (referralURLs.length > 0)
{
buffer.append(", referralURLs={");
for (int i=0; i < referralURLs.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append('\'');
buffer.append(referralURLs[i]);
buffer.append('\'');
}
buffer.append('}');
}
if (responseControls.length > 0)
{
buffer.append(", responseControls={");
for (int i=0; i < responseControls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(responseControls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
}

package edu.usil.ldap.certificate;

import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Objects;

public class CertficateImporterTest { public static void main(String[] argv) throws Exception { addX509CertificateToTrustStore("/fo/bar/file.pem", "jojo", "/baz/openjdk/jre/lib/security/cacerts_test_1", "changeit", KeyStore.getDefaultType()); }

public static void addX509CertificateToTrustStore(String certPath, String certAlias, String storePath, String storePassword, String storeType) throws Exception {

char[] storePasswordCharArr = Objects.requireNonNull(storePassword, "").toCharArray();

KeyStore keystore;
try (FileInputStream storeInputStream = new FileInputStream(storePath);) {
  keystore = KeyStore.getInstance(storeType);
  keystore.load(storeInputStream, storePasswordCharArr);

  String certificateContent =
      new String(Files.readAllBytes(Paths.get(certPath)), StandardCharsets.UTF_8);

  Certificate certificate = convertStringToX509Cert(certificateContent);

  keystore.setCertificateEntry(certAlias, certificate);
} finally {
}

try (FileOutputStream storeOutputStream = new FileOutputStream(storePath)) {
  keystore.store(storeOutputStream, storePasswordCharArr);
} finally {
}

}

private static X509Certificate convertStringToX509Cert(String certificate) throws Exception { InputStream targetStream = new ByteArrayInputStream(certificate.getBytes()); return (X509Certificate) CertificateFactory.getInstance("X509") .generateCertificate(targetStream); } }

package edu.usil.ldap.certificate;

import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Base64; import java.util.Enumeration;

public class P12Certificate2Success {

public static void main(String[] args) throws Exception { importP12B64Certificate("/foo/bar/base64.txt", "changeme", "/baz/openjdk/jre/lib/security/cacerts_test_2", "changeit"); }

public static void importP12B64Certificate(String filePathBase64P12, String passwordP12, String filePathJks, String passwordJKS) throws Exception {

// String base64CertP12 = // new String(Files.readAllBytes(Paths.get(filePathBase64P12)), StandardCharsets.UTF_8);

String base64CertP12 = System.getenv("BASE64_P12_CERT");

byte[] decodedCertificate = Base64.getMimeDecoder().decode(base64CertP12);
InputStream decodedCertificateStream = new ByteArrayInputStream(decodedCertificate);


KeyStore p12Store =
    loadKeystoreFromInputStream(decodedCertificateStream, passwordP12, "pkcs12");

KeyStore jksStore = loadKeystore(filePathJks, passwordJKS, "jks");

Enumeration aliases = p12Store.aliases();

while (aliases.hasMoreElements()) {

  String alias = (String) aliases.nextElement();

  if (p12Store.isKeyEntry(alias)) {
    System.out.println("Adding key for alias " + alias);
    Key key = p12Store.getKey(alias, passwordP12.toCharArray());

    Certificate[] chain = p12Store.getCertificateChain(alias);

    jksStore.setKeyEntry(alias, key, passwordJKS.toCharArray(), chain);
  }
}

storeKeystore(jksStore, filePathJks, passwordJKS);

}

public static void importP12Certificate(String filePathP12, String passwordP12, String filePathJks, String passwordJKS) throws Exception {

KeyStore p12Store = loadKeystore(filePathP12, passwordP12, "pkcs12");

KeyStore jksStore = loadKeystore(filePathJks, passwordJKS, "jks");

Enumeration aliases = p12Store.aliases();

while (aliases.hasMoreElements()) {

  String alias = (String) aliases.nextElement();

  if (p12Store.isKeyEntry(alias)) {
    System.out.println("Adding key for alias " + alias);
    Key key = p12Store.getKey(alias, passwordP12.toCharArray());

    Certificate[] chain = p12Store.getCertificateChain(alias);

    jksStore.setKeyEntry(alias, key, passwordJKS.toCharArray(), chain);
  }
}

storeKeystore(jksStore, filePathJks, passwordJKS);

}

private static KeyStore loadKeystoreFromInputStream(InputStream loadedP12Cert, String keystorePassword, String keystoreType) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {

KeyStore keystore = null;

if (keystore == null) {
  keystore = KeyStore.getInstance(KeyStore.getDefaultType());
} else {
  keystore = KeyStore.getInstance(keystoreType);
}

keystore.load(loadedP12Cert, keystorePassword.toCharArray());

return keystore;

}

private static KeyStore loadKeystore(String keyStoreFile, String keystorePassword, String keystoreType) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {

File file = new File(keyStoreFile);
InputStream inputStream = new FileInputStream(file);

KeyStore keystore = null;

if (keystore == null) {
  keystore = KeyStore.getInstance(KeyStore.getDefaultType());
} else {
  keystore = KeyStore.getInstance(keystoreType);
}

keystore.load(inputStream, keystorePassword.toCharArray());

return keystore;

}

private static void storeKeystore(KeyStore keystore, String keyStoreFile, String keystorePassword) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {

File file = new File(keyStoreFile);
FileOutputStream out = new FileOutputStream(file);
keystore.store(out, keystorePassword.toCharArray());
out.close();

}

}

package edu.usil.ldap.certificate;

import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Enumeration;

public class P12CertificateSuccess {

public static void main(String[] args) throws Exception { importP12Certificate("/foo/bar/new2.pfx", "changeme", "/baz/openjdk/jre/lib/security/cacerts_test_1", "changeit"); }

public static void importP12Certificate(String filePathP12, String passwordP12, String filePathJks, String passwordJKS) throws Exception {

KeyStore p12Store = loadKeystore(filePathP12, passwordP12, "pkcs12");

KeyStore jksStore = loadKeystore(filePathJks, passwordJKS, "jks");

Enumeration aliases = p12Store.aliases();

while (aliases.hasMoreElements()) {

  String alias = (String) aliases.nextElement();

  if (p12Store.isKeyEntry(alias)) {
    System.out.println("Adding key for alias " + alias);
    Key key = p12Store.getKey(alias, passwordP12.toCharArray());

    Certificate[] chain = p12Store.getCertificateChain(alias);

    jksStore.setKeyEntry(alias, key, passwordJKS.toCharArray(), chain);
  }
}

storeKeystore(jksStore, filePathJks, passwordJKS);

}

private static KeyStore loadKeystore(String keyStoreFile, String keystorePassword, String keystoreType) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {

File file = new File(keyStoreFile);
InputStream inputStream = new FileInputStream(file);

KeyStore keystore = null;

if (keystore == null) {
  keystore = KeyStore.getInstance(KeyStore.getDefaultType());
} else {
  keystore = KeyStore.getInstance(keystoreType);
}

keystore.load(inputStream, keystorePassword.toCharArray());

return keystore;

}

private static void storeKeystore(KeyStore keystore, String keyStoreFile, String keystorePassword) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {

File file = new File(keyStoreFile);
FileOutputStream out = new FileOutputStream(file);
keystore.store(out, keystorePassword.toCharArray());
out.close();

}

}

const net = require('net');
const server = net.createServer();
server.on('connection', handleConnection);
server.listen(33389);
function handleConnection(socket) {
socket.on('data', (chunk) => {
console.log('Received chunk:\n', chunk.toString());
socket.write(Buffer.from('300c02010161070a010004000400', 'hex'));
});
//socket.write('HTTP/1.1 200 OK\r\nServer: my-web-server\r\nContent-Length: 0\r\n\r\n');
//socket.write(Buffer.from('300c02010161070a010004000400', 'hex'));
//socket.write(Buffer.from([0x61]));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment