Lightweight Directory Access Protocol (LDAP)
Service Provisioning via Docker
Deploying an OpenLDAP server alongside a phpLDAPadmin interface can be achieved using Docker Compose.
version: '3.8'
services:
directory-server:
image: osixia/openldap:latest
container_name: openldap-host
environment:
- TZ=UTC
- LDAP_ORGANISATION=myorg
- LDAP_DOMAIN=myorg.io
- LDAP_ADMIN_PASSWORD=SuperSecretAdmin123
ports:
- 389:389
- 636:636
networks:
- directory-net
admin-ui:
image: osixia/phpldapadmin:latest
container_name: ldap-admin-console
privileged: true
environment:
- TZ=UTC
- PHPLDAPADMIN_HTTPS=false
- PHPLDAPADMIN_LDAP_HOSTS=directory-server
ports:
- 8081:80
depends_on:
- directory-server
networks:
- directory-net
networks:
directory-net:
driver: bridge
Spring Boot Integration
Add the required dependency to your project configuration:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
Implement a configuration manager to handle connections and directory operations dynamically:
import lombok.extern.slf4j.Slf4j;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.query.LdapQueryBuilder;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class DirectoryManager {
private volatile LdapTemplate ldapOperations;
private void initializeTemplate() {
try {
Map<String, String> configProps = fetchConfigFromStore();
LdapContextSource contextSrc = new LdapContextSource();
contextSrc.setUrl(configProps.get("url"));
contextSrc.setBase(configProps.get("baseDn"));
contextSrc.setUserDn(configProps.get("adminDn"));
contextSrc.setPassword(configProps.get("adminPass"));
contextSrc.setPooled(true);
Map<String, Object> envProps = new HashMap<>();
envProps.put("java.naming.ldap.attributes.binary", "objectGUID");
contextSrc.setBaseEnvironmentProperties(envProps);
contextSrc.afterPropertiesSet();
this.ldapOperations = new LdapTemplate(contextSrc);
this.ldapOperations.setIgnorePartialResultException(true);
} catch (Exception ex) {
log.error("Failed to establish LDAP connection", ex);
throw new IllegalStateException("Directory connection error");
}
}
public boolean authenticateUser(String uid, String pwd) {
EqualsFilter filter = new EqualsFilter("uid", uid);
try {
return getTemplate().authenticate("", filter.toString(), pwd);
} catch (Exception ex) {
log.error("Authentication check failed", ex);
throw new IllegalStateException("Directory auth error");
}
}
public List<Map<String, Object>> searchEntries(String uid) {
try {
return getTemplate().search(
LdapQueryBuilder.query().where("uid").is(uid),
(AttributesMapper<Map<String, Object>>) attrs -> {
Map<String, Object> entryMap = new HashMap<>();
NamingEnumeration<? extends Attribute> attrEnum = attrs.getAll();
while (attrEnum.hasMore()) {
Attribute attr = attrEnum.next();
entryMap.put(attr.getID(), attr.get());
}
return entryMap;
}
);
} catch (Exception ex) {
log.error("Entry search failed", ex);
throw new IllegalStateException("Directory search error");
}
}
private LdapTemplate getTemplate() {
if (ldapOperations == null) {
synchronized (this) {
if (ldapOperations == null) {
initializeTemplate();
}
}
}
return ldapOperations;
}
private Map<String, String> fetchConfigFromStore() {
// Retrieve configuration from database or properties
return Map.of(
"url", "ldap://127.0.0.1:389",
"baseDn", "dc=myorg,dc=io",
"adminDn", "cn=admin,dc=myorg,dc=io",
"adminPass", "SuperSecretAdmin123"
);
}
}
Secure File Transfer Protocol (SFTP)
Container Deployment
Deploy an SFTP server using Docker Compose:
version: '3.8'
services:
sftp-host:
image: atmoz/sftp
volumes:
- ./sftp-data/:/home/transfer_user/
ports:
- "2221:22"
privileged: true
command: transfer_user:S3cureP@ss:1002
The mapped root directory acts as a chroot jail and must lack write permissions for the user. Assign 755 to the root mount, then create a sub-directory with 777 permissions for actual file uploads:
mkdir ./sftp-data/upload_dir
chmod 777 ./sftp-data/upload_dir
Spring Boot Integration
Include the JSch library and Commons IO:
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
Create a utility class for SFTP operations:
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Vector;
@Slf4j
public class SftpClient {
public static ChannelSftp createConnection(String host, String user, String pass, int port) throws IOException {
JSch jsch = new JSch();
int maxRetries = 3;
int timeoutMs = 10000;
for (int attempt = 0; attempt < maxRetries; attempt++) {
try {
Session session = jsch.getSession(user, host, port);
session.setPassword(pass);
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
session.setConfig(sshConfig);
session.connect(timeoutMs);
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
return sftpChannel;
} catch (Exception ex) {
log.warn("SFTP connection attempt {} failed. Retrying...", attempt + 1, ex);
try { Thread.sleep(3000); } catch (InterruptedException ignored) {}
}
}
throw new IOException("Unable to establish SFTP connection after retries.");
}
public static void transferFile(ChannelSftp channel, String destPath, InputStream dataStream) {
try {
channel.put(dataStream, destPath);
} catch (SftpException ex) {
log.error("File upload failed to path {}", destPath, ex);
} finally {
try { dataStream.close(); } catch (IOException ignored) {}
}
}
public static void retrieveFile(ChannelSftp channel, String remotePath, OutputStream outStream) {
try {
channel.get(remotePath, outStream);
} catch (SftpException ex) {
log.error("File download failed for path {}", remotePath, ex);
}
}
public static void ensureDirectoryExists(ChannelSftp channel, String path) throws SftpException {
String[] dirs = path.split("/");
for (String dir : dirs) {
if (StringUtils.isBlank(dir)) continue;
try {
channel.cd(dir);
} catch (SftpException e) {
channel.mkdir(dir);
channel.cd(dir);
}
}
}
public static void disconnect(ChannelSftp channel) {
if (channel != null && channel.isConnected()) {
try {
Session s = channel.getSession();
if (s.isConnected()) s.disconnect();
} catch (JSchException ignored) {}
channel.disconnect();
}
}
public static boolean deleteRemoteFile(ChannelSftp channel, String filePath) {
try {
channel.rm(filePath);
return true;
} catch (SftpException e) {
return false;
}
}
public static boolean removeRemoteDirectory(ChannelSftp channel, String dirPath) {
try {
Vector<ChannelSftp.LsEntry> entries = channel.ls(dirPath);
if (entries != null) {
for (ChannelSftp.LsEntry entry : entries) {
if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) {
String fullPath = dirPath + "/" + entry.getFilename();
if (entry.getAttrs().isDir()) {
removeRemoteDirectory(channel, fullPath);
} else {
channel.rm(fullPath);
}
}
}
}
channel.rmdir(dirPath);
return true;
} catch (SftpException e) {
return false;
}
}
}
Simple Network Management Protocol (SNMP)
Service Installation and Configuration
Install the net-snmp utilities on a Linux host:
yum install net-snmp net-snmp-utils
systemctl enable snmpd
systemctl start snmpd
Update the SNMP daemon configuration to support v3 users:
# /etc/snmp/snmpd.conf
rwuser snmp_admin
Configure the trap daemon:
# /etc/snmp/snmptrapd.conf
authCommunity log,execute,net public
createUser -e 0x8000137001C0A842D64CE2B7CF snmp_admin MD5 "P@ssw0rd12" DES "P@ssw0rd12"
authUser log,execute,net snmp_admin
Launch the trap listener:
snmptrapd -df -C -c /etc/snmp/snmptrapd.conf -Lo
Spring Boot Integration
Include the SNMP4J dependency:
<dependency>
<groupId>org.snmp4j</groupId>
<artifactId>snmp4j</artifactId>
<version>2.7.0</version>
</dependency>
Define the configuration DTO and service interface:
import lombok.Data;
@Data
public class SnmpProfile {
private String targetIp;
private String targetPort;
private String communityStr = "public";
private int retryCount = 0;
private long timeoutMs = 1000;
private String protocolVersion = "v2c";
private String secName;
private String authMethod = "MD5";
private String authPass;
private String privacyMethod = "DES";
private String privacyPass;
}
import org.snmp4j.PDU;
import org.snmp4j.Target;
import org.snmp4j.smi.VariableBinding;
import java.util.List;
public interface SnmpManager {
Target buildTarget(SnmpProfile profile);
PDU buildPDU(List<VariableBinding> bindings, int pduType);
void dispatchTrap(List<VariableBinding> bindings, SnmpProfile profile) throws Exception;
void dispatchInform(List<VariableBinding> bindings, SnmpProfile profile) throws Exception;
}
Implement the base service:
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public abstract class AbstractSnmpHandler implements SnmpManager {
public static final String TRAP_OID_PREFIX = "1.3.6.1.4.1.9955.11.2.1.1.2.";
public static final Map<String, Integer> TRAP_FIELD_MAP = new HashMap<>();
static {
TRAP_FIELD_MAP.put("seqId", 11);
TRAP_FIELD_MAP.put("objId", 12);
TRAP_FIELD_MAP.put("domainName", 13);
TRAP_FIELD_MAP.put("alarmId", 14);
TRAP_FIELD_MAP.put("raisedTime", 15);
}
protected static Snmp snmpSession = null;
protected static Snmp initSession() throws Exception {
if (snmpSession != null) return snmpSession;
try {
TransportMapping<?> transport = new DefaultUdpTransportMapping();
snmpSession = new Snmp(transport);
snmpSession.listen();
return snmpSession;
} catch (Exception ex) {
log.error("SNMP session initialization failed", ex);
throw new Exception("SNMP init error");
}
}
@Override
public PDU buildPDU(List<VariableBinding> bindings, int pduType) {
PDU pdu = new PDU();
pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID("1.3.6.1.4.1")));
bindings.forEach(pdu::add);
pdu.setType(pduType);
return pdu;
}
public VariableBinding createBinding(String key, String val) {
Integer idx = TRAP_FIELD_MAP.get(key);
if (idx == null) return null;
return new VariableBinding(new OID(TRAP_OID_PREFIX + idx), new OctetString(val));
}
}
Implement V2C handler logic:
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import java.util.List;
@Slf4j
public class SnmpV2cHandler extends AbstractSnmpHandler {
static {
try { initSession(); } catch (Exception e) { log.error("Init failed", e); }
}
@Override
public Target buildTarget(SnmpProfile profile) {
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString(profile.getCommunityStr()));
target.setAddress(new UdpAddress(profile.getTargetIp() + "/" + profile.getTargetPort()));
target.setRetries(profile.getRetryCount());
target.setTimeout(profile.getTimeoutMs());
target.setVersion(SnmpConstants.version2c);
return target;
}
@Override
public void dispatchTrap(List<VariableBinding> bindings, SnmpProfile profile) throws Exception {
Target target = buildTarget(profile);
PDU pdu = buildPDU(bindings, PDU.TRAP);
try {
snmpSession.send(pdu, target);
} catch (Exception ex) {
throw new Exception("Trap dispatch failed", ex);
}
}
@Override
public void dispatchInform(List<VariableBinding> bindings, SnmpProfile profile) throws Exception {
Target target = buildTarget(profile);
PDU pdu = buildPDU(bindings, PDU.INFORM);
try {
ResponseEvent response = snmpSession.inform(pdu, target);
if (response == null || response.getResponse() == null || response.getResponse().getErrorStatus() != PDU.noError) {
throw new Exception("Inform acknowledgment failed");
}
} catch (Exception ex) {
throw new Exception("Inform dispatch failed", ex);
}
}
}
CLI Validation
snmptrap -v 3 -e 0x8000137001C0A842D64CE2B7CF00000000 -u snmp_admin -l authPriv -a MD5 -A P@ssw0rd12 -x DES -X P@ssw0rd12 127.0.0.1 0 linkUp.0
JSON Web Signature (JWS) RFC 7515 Validation
Verifying JWS structures according to RFC 7515 can be implemented as follows:
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTSignerUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.util.Base64;
public class JwsRfc7515Validator {
public static void main(String[] args) {
String headerB64 = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9";
String payloadB64 = "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ";
// Decoding Base64URL components
byte[] headerBytes = Base64.getUrlDecoder().decode(headerB64);
byte[] payloadBytes = Base64.getUrlDecoder().decode(payloadB64);
System.out.println("Header: " + new String(headerBytes));
System.out.println("Payload: " + new String(payloadBytes));
String signingKeyB64 = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow";
byte[] keyBytes = Base64.getUrlDecoder().decode(signingKeyB64);
// Verifying an existing token
String existingToken = headerB64 + "." + payloadB64 + ".dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
boolean isVerified = JWT.of(existingToken).setKey(keyBytes).verify();
System.out.println("Token Valid: " + isVerified);
// Generating a new HS256 token
String hs256Token = JWT.create()
.setKey(keyBytes)
.setHeader("typ", "JWT")
.setHeader("alg", "HS256")
.setPayload("iss", "joe")
.setPayload("exp", 1300819380)
.sign();
System.out.println("HS256 Token: " + hs256Token);
// Generating ES256 signature
String algId = "ES256";
KeyPair ecKeyPair = KeyUtil.generateKeyPair("EC");
PrivateKey ecPrivateKey = ecKeyPair.getPrivate();
System.out.println("EC Private Key: " + ecPrivateKey.toString());
String es256Signature = JWTSignerUtil.createSigner(algId, ecKeyPair).sign(headerB64, payloadB64);
System.out.println("ES256 Signature: " + es256Signature);
}
}