In my case, I have Java 1.6 and want to connect to a remote server which only supports TLS1.2. Server URL is: https://blagajne-test.fu.gov.si:9002 and certificate public key is here: http://datoteke.durs.gov.si/dpr/files/test-tls.cer
I have no possibility to upgrade Java because is a part of Oracle Database 11g (11.4).
I tried to write a simple program in Java which uses BouncyCastel libraries but got error: Exception in thread "main"
org.bouncycastle.crypto.tls.TlsFatalAlertReceived: handshake_failure(40)
at org.bouncycastle.crypto.tls.TlsProtocol.handleAlertMessage(Unknown Source)
The step I have followed was:
1.) have downloaded test-tls.cer and imported the key into jssacerts and cacerts.
2.) In Java have done this example:
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.security.MessageDigest;
import java.security.Security;
import java.security.Signature;
import javax.net.ssl.HttpsURLConnection;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.TlsAuthentication;
import org.bouncycastle.crypto.tls.TlsClientProtocol;
import org.bouncycastle.crypto.tls.TlsCredentials;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class Test3 {
public static Signature podpis = null;
public static MessageDigest md = null;
static {
try {
Security.addProvider(new BouncyCastleProvider());
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
String httpsURL = "https://blagajne-test.fu.gov.si:9002";
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection )myurl.openConnection();
con.setSSLSocketFactory(new TLSSocketConnectionFactory());
InputStream ins = con.getInputStream();
}
}
and
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.security.cert.X509Certificate;
import org.apache.commons.logging.Log;
import org.bouncycastle.crypto.tls.Certificate;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.ExtensionType;
import org.bouncycastle.crypto.tls.TlsAuthentication;
import org.bouncycastle.crypto.tls.TlsClientProtocol;
import org.bouncycastle.crypto.tls.TlsCredentials;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class TLSSocketConnectionFactory extends SSLSocketFactory {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adding Custom BouncyCastleProvider
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SECURE RANDOM
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
private SecureRandom _secureRandom = new SecureRandom();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adding Custom BouncyCastleProvider
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
#Override
public Socket createSocket(Socket socket, final String host, int port, boolean arg3)
throws IOException {
if (socket == null) {
socket = new Socket();
}
if (!socket.isConnected()) {
socket.connect(new InetSocketAddress(host, port));
}
final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), _secureRandom);
return _createSSLSocket(host, tlsClientProtocol);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SOCKET FACTORY METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#Override
public String[] getDefaultCipherSuites() {
return null;
}
#Override
public String[] getSupportedCipherSuites() {
return null;
}
#Override
public Socket createSocket(String host,
int port) throws IOException, UnknownHostException {
return null;
}
#Override
public Socket createSocket(InetAddress host,
int port) throws IOException {
return null;
}
#Override
public Socket createSocket(String host,
int port,
InetAddress localHost,
int localPort) throws IOException, UnknownHostException {
return null;
}
#Override
public Socket createSocket(InetAddress address,
int port,
InetAddress localAddress,
int localPort) throws IOException {
return null;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SOCKET CREATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private SSLSocket _createSSLSocket(final String host, final TlsClientProtocol tlsClientProtocol) {
return new SSLSocket() {
private java.security.cert.Certificate[] peertCerts;
#Override
public InputStream getInputStream() throws IOException {
return tlsClientProtocol.getInputStream();
}
#Override
public OutputStream getOutputStream() throws IOException {
return tlsClientProtocol.getOutputStream();
}
#Override
public synchronized void close() throws IOException {
tlsClientProtocol.close();
}
#Override
public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) {
}
#Override
public boolean getEnableSessionCreation() {
return false;
}
#Override
public String[] getEnabledCipherSuites() {
return null;
}
#Override
public String[] getEnabledProtocols() {
return null;
}
#Override
public boolean getNeedClientAuth() {
return false;
}
#Override
public SSLSession getSession() {
return new SSLSession() {
#Override
public int getApplicationBufferSize() {
return 0;
}
#Override
public String getCipherSuite() {
throw new UnsupportedOperationException();
}
#Override
public long getCreationTime() {
throw new UnsupportedOperationException();
}
#Override
public byte[] getId() {
throw new UnsupportedOperationException();
}
#Override
public long getLastAccessedTime() {
throw new UnsupportedOperationException();
}
#Override
public java.security.cert.Certificate[] getLocalCertificates() {
throw new UnsupportedOperationException();
}
#Override
public Principal getLocalPrincipal() {
throw new UnsupportedOperationException();
}
#Override
public int getPacketBufferSize() {
throw new UnsupportedOperationException();
}
#Override
public X509Certificate[] getPeerCertificateChain()
throws SSLPeerUnverifiedException {
return null;
}
#Override
public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
return peertCerts;
}
#Override
public String getPeerHost() {
throw new UnsupportedOperationException();
}
#Override
public int getPeerPort() {
return 0;
}
#Override
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
return null;
//throw new UnsupportedOperationException();
}
#Override
public String getProtocol() {
throw new UnsupportedOperationException();
}
#Override
public SSLSessionContext getSessionContext() {
throw new UnsupportedOperationException();
}
#Override
public Object getValue(String arg0) {
throw new UnsupportedOperationException();
}
#Override
public String[] getValueNames() {
throw new UnsupportedOperationException();
}
#Override
public void invalidate() {
throw new UnsupportedOperationException();
}
#Override
public boolean isValid() {
throw new UnsupportedOperationException();
}
#Override
public void putValue(String arg0, Object arg1) {
throw new UnsupportedOperationException();
}
#Override
public void removeValue(String arg0) {
throw new UnsupportedOperationException();
}
};
}
#Override
public String[] getSupportedProtocols() {
return null;
}
#Override
public boolean getUseClientMode() {
return false;
}
#Override
public boolean getWantClientAuth() {
return false;
}
#Override
public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) {
}
#Override
public void setEnableSessionCreation(boolean arg0) {
}
#Override
public void setEnabledCipherSuites(String[] arg0) {
}
#Override
public void setEnabledProtocols(String[] arg0) {
}
#Override
public void setNeedClientAuth(boolean arg0) {
}
#Override
public void setUseClientMode(boolean arg0) {
}
#Override
public void setWantClientAuth(boolean arg0) {
}
#Override
public String[] getSupportedCipherSuites() {
return null;
}
#Override
public void startHandshake() throws IOException {
tlsClientProtocol.connect(new DefaultTlsClient() {
#SuppressWarnings("unchecked")
#Override
public Hashtable<Integer, byte[]> getClientExtensions() throws IOException {
Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions();
if (clientExtensions == null) {
clientExtensions = new Hashtable<Integer, byte[]>();
}
//Add host_name
byte[] host_name = host.getBytes();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final DataOutputStream dos = new DataOutputStream(baos);
dos.writeShort(host_name.length + 3);
dos.writeByte(0); //
dos.writeShort(host_name.length);
dos.write(host_name);
dos.close();
clientExtensions.put(ExtensionType.server_name, baos.toByteArray());
return clientExtensions;
}
#Override
public TlsAuthentication getAuthentication()
throws IOException {
return new TlsAuthentication() {
#Override
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
try {
KeyStore ks = _loadKeyStore();
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
boolean trustedCertificate = false;
for (org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) {
java.security.cert.Certificate cert = cf.generateCertificate(new ByteArrayInputStream(c.getEncoded()));
certs.add(cert);
String alias = ks.getCertificateAlias(cert);
if (alias != null) {
if (cert instanceof java.security.cert.X509Certificate) {
try {
((java.security.cert.X509Certificate) cert).checkValidity();
trustedCertificate = true;
} catch (CertificateExpiredException cee) {
cee.printStackTrace();
}
}
} else {
System.out.println("-->");
}
}
if (!trustedCertificate) {
throw new CertificateException("Unknown cert " + serverCertificate);
}
peertCerts = certs.toArray(new java.security.cert.Certificate[0]);
} catch (Exception ex) {
ex.printStackTrace();
throw new IOException(ex);
}
}
#Override
public TlsCredentials getClientCredentials(CertificateRequest arg0)
throws IOException {
return null;
}
/**
* Private method to load keyStore with system or
* default properties.
*
* #return
* #throws Exception
*/
private KeyStore _loadKeyStore() throws Exception {
FileInputStream trustStoreFis = null;
try {
String sysTrustStore = null;
File trustStoreFile = null;
KeyStore localKeyStore = null;
sysTrustStore = System.getProperty("javax.net.ssl.trustStore");
String javaHome;
if (!"NONE".equals(sysTrustStore)) {
if (sysTrustStore != null) {
trustStoreFile = new File(sysTrustStore);
trustStoreFis = _getFileInputStream(trustStoreFile);
} else {
javaHome = System.getProperty("java.home");
trustStoreFile = new File(javaHome + File.separator + "lib" + File.separator + "security" + File.separator + "jssecacerts");
if ((trustStoreFis = _getFileInputStream(trustStoreFile)) == null) {
trustStoreFile = new File(javaHome + File.separator + "lib" + File.separator + "security" + File.separator + "cacerts");
trustStoreFis = _getFileInputStream(trustStoreFile);
}
}
if (trustStoreFis != null) {
sysTrustStore = trustStoreFile.getPath();
} else {
sysTrustStore = "No File Available, using empty keystore.";
}
}
System.out.println("sysTrustStore: " +sysTrustStore);
String trustStoreType = System.getProperty("javax.net.ssl.trustStoreType") != null ? System.getProperty("javax.net.ssl.trustStoreType") : KeyStore.getDefaultType();
String trustStoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider") != null ? System.getProperty("javax.net.ssl.trustStoreProvider") : "";
if (trustStoreType.length() != 0) {
if (trustStoreProvider.length() == 0) {
localKeyStore = KeyStore.getInstance(trustStoreType);
} else {
localKeyStore = KeyStore.getInstance(trustStoreType, trustStoreProvider);
}
char[] keyStorePass = null;
String str5 = System.getProperty("javax.net.ssl.trustStorePassword") != null ? System.getProperty("javax.net.ssl.trustStorePassword") : "";
if (str5.length() != 0) {
keyStorePass = str5.toCharArray();
}
localKeyStore.load(trustStoreFis, (char[]) keyStorePass);
if (keyStorePass != null) {
for (int i = 0; i < keyStorePass.length; i++) {
keyStorePass[i] = 0;
}
}
}
return (KeyStore) localKeyStore;
} finally {
if (trustStoreFis != null) {
trustStoreFis.close();
}
}
}
private FileInputStream _getFileInputStream(File paramFile) throws Exception {
if (paramFile.exists()) {
return new FileInputStream(paramFile);
}
return null;
}
};
}
});
}
};//Socket
}
}
When I execute the main program I got:
What I'm doing wrong or why I get back that exception?
Download jce_policy-6.zip from oracle website
unzip the jce_policy-6.zip you will have two jars local_policy.jar and US_export_policy.jar.
Install the jars based on the README file provided in the zip - two jars should be copied to %JAVA_HOME%/lib/security
Edit the file %JAVA_HOME%/jre/lib/security/java.security and locate the security-provider list add this line -
security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider
Use the following code to get the SSLContext.
Provider provider = new BouncyCastleJsseProvider();
Security.addProvider(provider);
SSLContext ctx = SSLContext.getInstance("TLS",provider.getName());
Please switch to Version 1.55 this will fix the issue...
Related
i have a requirement in my project. i want to change the value of sended data through postman, like as if there is three parameter like as id, name, salary.now i am sending the data through postman
}
"id":1,
"name":"dhiraj",
"salary":787878
}
now when send the data,it should be save as actual data in database .but if i am sending like as that
}
"id":2,
"name":"",
"salary":787878
}
then name column should be null instead of empty in database.i am using following code for that, but not getting exact output,please help me .
'package com.httpmodify.test.HttpModify.filter;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Locale;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.LocaleResolver;
import com.httpmodify.test.HttpModify.model.Student;
#Component
public class RequestModify implements Filter{
private static Logger log=LoggerFactory.getLogger(Student.class);
private static final String ACCEPT_LANGUAGE = "Accept-Language";
#Autowired
LocaleResolver localeResolver;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// Need to add code if something is required to be initialized.
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
StringBuilder requestJson = new StringBuilder();
String responseJson = "";
BufferedReader bufferedReader = request.getReader();
String line = null;
if (bufferedReader != null) {
while (null != (line = bufferedReader.readLine())) {
requestJson.append(line);
}
}
if (request.getMethod().equals("POST")) {
RestAPIRequestWrapper requestWrapper = new RestAPIRequestWrapper(request,
requestJson.toString().getBytes());
RestAPIResponseWrapper responseWrapper = new RestAPIResponseWrapper(response);
chain.doFilter(requestWrapper, responseWrapper);
response.setContentType("text/plain");
responseJson = responseWrapper.getCaptureAsString();
response.getWriter().write(responseWrapper.getCaptureAsString());
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
// Need to write some code if some resource needs to be destroyed.
}
/**
* #param locale
* #return String
*/
private String getAcceptLanguage(String locale) {
return locale != null ? locale : "en";
}
}
'
package com.httpmodify.test.HttpModify.filter;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* #author Ashwini Upadhyay
* #Version 1.0
* #date 2019-Apr-02 12:57:38 PM
*/
public class RestAPIRequestWrapper extends HttpServletRequestWrapper {
private final ByteArrayInputStream decryptedDataBAIS;
private HttpServletRequest wrapped;
private Map<String, String[]> parameterMap;
private Map<String, String> headerMap = new HashMap<>();
public RestAPIRequestWrapper(HttpServletRequest wrapped, byte[] decryptedData) {
super(wrapped);
this.wrapped = wrapped;
decryptedDataBAIS = new ByteArrayInputStream(decryptedData);
}
public RestAPIRequestWrapper(HttpServletRequest wrapped, byte[] decryptedData, Map<String, String> headerMap) {
super(wrapped);
this.wrapped = wrapped;
decryptedDataBAIS = new ByteArrayInputStream(decryptedData);
this.headerMap = headerMap;
}
public RestAPIRequestWrapper(HttpServletRequest wrapped) {
super(wrapped);
this.wrapped = wrapped;
decryptedDataBAIS = new ByteArrayInputStream("".getBytes());
}
public RestAPIRequestWrapper(HttpServletRequest wrapped, String paramstr) {
super(wrapped);
this.wrapped = wrapped;
decryptedDataBAIS = null;
String[] paramsArr = paramstr.split("&");
for (int i = 0; i < paramsArr.length; i++) {
String[] paramArr = paramsArr[i].split("=");
addParameter(paramArr[0], paramArr[1]);
}
}
#Override
public String getContentType() {
return super.getContentType();
}
#Override
public BufferedReader getReader() throws UnsupportedEncodingException {
return new BufferedReader(new InputStreamReader(decryptedDataBAIS, "UTF_8"));
}
#Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStream() {
#Override
public int read() {
return decryptedDataBAIS.read();
}
#Override
public boolean isFinished() {
return decryptedDataBAIS.available() == 0;
}
#Override
public boolean isReady() {
return true;
}
#Override
public void setReadListener(ReadListener arg0) {
throw new RuntimeException("Not implemented");
}
};
}
#Override
public Enumeration<String> getParameterNames() {
if (parameterMap == null) {
return wrapped.getParameterNames();
}
return Collections.enumeration(parameterMap.keySet());
}
#Override
public String[] getParameterValues(String name) {
if (parameterMap == null) {
return wrapped.getParameterValues(name);
}
return parameterMap.get(name);
}
#Override
public String getParameter(String name) {
if (parameterMap == null) {
return wrapped.getParameter(name);
}
String[] strings = parameterMap.get(name);
if (strings != null) {
return strings[0];
}
return null;
}
public void addParameter(String name, String value) {
if (parameterMap == null) {
parameterMap = new HashMap<>();
parameterMap.putAll(wrapped.getParameterMap());
}
String[] values = parameterMap.get(name);
if (values == null) {
values = new String[0];
}
List<String> list = new ArrayList<>(values.length + 1);
list.addAll(Arrays.asList(values));
list.add(value);
parameterMap.put(name, list.toArray(new String[0]));
}
#Override
public Map<String, String[]> getParameterMap() {
if (parameterMap == null) {
return wrapped.getParameterMap();
}
return Collections.unmodifiableMap(parameterMap);
}
#Override
public String getHeader(String headerName) {
String headerValue = null;
if (headerMap.containsKey(headerName)) {
headerValue = headerMap.get(headerName);
} else {
headerValue = super.getHeader(headerName);
}
return headerValue;
}
#Override
public Enumeration<String> getHeaders(String name) {
Set<String> values = new HashSet<>();
if (headerMap.containsKey(name) || name.equalsIgnoreCase("Authorization")) {
if (headerMap.get(name) != null)
values.add(headerMap.get(name));
} else {
for (Enumeration<String> e = super.getHeaders(name); e.hasMoreElements();) {
String headerValue = e.nextElement();
values.add(headerValue);
}
}
return Collections.enumeration(values);
}
#Override
public Enumeration<String> getHeaderNames() {
Set<String> names = new HashSet<>();
for (String name : headerMap.keySet()) {
names.add(name);
}
for (Enumeration<String> e = super.getHeaderNames(); e.hasMoreElements();) {
String headerName = e.nextElement();
if (!headerName.equalsIgnoreCase("Authorization"))
names.add(headerName);
}
return Collections.enumeration(names);
}
public void addHeader(String name, String value) {
headerMap.put(name, value);
}
}
package com.httpmodify.test.HttpModify.filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* #author Ashwini Upadhyay
* #Version 1.0
* #date 2019-Apr-02 12:57:17 PM
*/
public class RestAPIResponseWrapper extends HttpServletResponseWrapper {
private final ByteArrayOutputStream capture;
private ServletOutputStream output;
private PrintWriter writer;
public RestAPIResponseWrapper(HttpServletResponse response) {
super(response);
capture = new ByteArrayOutputStream(response.getBufferSize());
}
#Override
public ServletOutputStream getOutputStream() throws IOException {
if (writer != null) {
throw new IllegalStateException("getWriter() has already been called on this response.");
}
if (output == null) {
output = new ServletOutputStream() {
#Override
public void write(int b) throws IOException {
capture.write(b);
}
#Override
public void flush() throws IOException {
capture.flush();
}
#Override
public void close() throws IOException {
capture.close();
}
#Override
public boolean isReady() {
return false;
}
#Override
public void setWriteListener(WriteListener arg0) {
}
};
}
return output;
}
#Override
public PrintWriter getWriter() throws IOException {
if (output != null) {
throw new IllegalStateException("getOutputStream() has already been called on this response.");
}
if (writer == null) {
writer = new PrintWriter(new OutputStreamWriter(capture, getCharacterEncoding()));
}
return writer;
}
#Override
public void flushBuffer() throws IOException {
super.flushBuffer();
if (writer != null) {
writer.flush();
} else if (output != null) {
output.flush();
}
}
public byte[] getCaptureAsBytes() throws IOException {
if (writer != null) {
writer.close();
} else if (output != null) {
output.close();
}
return capture.toByteArray();
}
public String getCaptureAsString() throws IOException {
return new String(getCaptureAsBytes(), getCharacterEncoding());
}
}
After getting the request in the controller, you can validate the input value. If the input for the name is empty then make it null, and perform the same operation for other input values. After performing these operations save the object to the database.
I'm pulling my hair out as I cannot get the samples to work - hopefully someone can help..
I would like to DETECT if a docx and a doc file is password protected/encrypted. I have seen this posted in a few places but I cannot get it work - it doesnt throw an exception. Can someone see what I am doing wrong. Note I only need to detect the password..i dont want to open the document.
String fileLocation = "C:/myfile.docx";
File file = new File(fileLocation);
FileInputStream fis = new FileInputStream(file.getAbsolutePath());
POIFSFileSystem pfis = new POIFSFileSystem(fis);
try{
EncryptionInfo info = new EncryptionInfo(pfis);
EncryptionMode mode = info.getEncryptionMode();
Decryptor d = Decryptor.getInstance(info);
//Try and open it
if(!d.verifyPassword(Decryptor.DEFAULT_PASSWORD))
{
//file is encrypted
}
}
catch(GeneralSecurityException gse)
{
//file is encrypted
}
catch(EncryptedDocumentException edc)
{
//file is encrypted
}
I haven't elaborated much to get the code smaller, but I've simply taken one of the factory classes - like SlideShowFactory - and modified it for H/XWPF. As H/XWPF hasn't got a common interface on the document level (as of now), the quick&dirty approach is to return an Object.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
public class EncDetect {
public static void main(String[] args) {
String dir = "/home/kiwiwings/project/poi/poi/test-data";
String[] files = {
"document/bug53475-password-is-solrcell.docx",
"document/password_tika_binaryrc4.doc",
"document/58067.docx",
"document/58804.doc"
};
for (String f : files) {
try {
DocumentFactory.create(new File(dir, f));
System.out.println(f + " not encrypted");
} catch (EncryptedDocumentException e) {
System.out.println(f + " is encrypted");
} catch (Exception e) {
System.out.println(f + " " +e.getMessage());
}
}
}
static class DocumentFactory {
public static Object create(NPOIFSFileSystem fs) throws IOException {
return create(fs, null);
}
public static Object create(final NPOIFSFileSystem fs, String password) throws IOException {
DirectoryNode root = fs.getRoot();
// Encrypted OOXML files go inside OLE2 containers, is this one?
if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
InputStream stream = null;
try {
stream = DocumentFactoryHelper.getDecryptedStream(fs, password);
return createXWPFDocument(stream);
} finally {
IOUtils.closeQuietly(stream);
}
}
// If we get here, it isn't an encrypted XWPF file
// So, treat it as a regular HWPF one
boolean passwordSet = false;
if (password != null) {
Biff8EncryptionKey.setCurrentUserPassword(password);
passwordSet = true;
}
try {
return createHWPFDocument(fs);
} finally {
if (passwordSet) {
Biff8EncryptionKey.setCurrentUserPassword(null);
}
}
}
public static Object create(InputStream inp) throws IOException, EncryptedDocumentException {
return create(inp, null);
}
public static Object create(InputStream inp, String password) throws IOException, EncryptedDocumentException {
// If clearly doesn't do mark/reset, wrap up
if (! inp.markSupported()) {
inp = new PushbackInputStream(inp, 8);
}
// Ensure that there is at least some data there
byte[] header8 = IOUtils.peekFirst8Bytes(inp);
// Try to create
if (NPOIFSFileSystem.hasPOIFSHeader(header8)) {
NPOIFSFileSystem fs = new NPOIFSFileSystem(inp);
return create(fs, password);
}
if (DocumentFactoryHelper.hasOOXMLHeader(inp)) {
return createXWPFDocument(inp);
}
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
}
public static Object create(File file) throws IOException, EncryptedDocumentException {
return create(file, null);
}
public static Object create(File file, String password) throws IOException, EncryptedDocumentException {
return create(file, password, false);
}
public static Object create(File file, String password, boolean readOnly) throws IOException, EncryptedDocumentException {
if (!file.exists()) {
throw new FileNotFoundException(file.toString());
}
NPOIFSFileSystem fs = null;
try {
fs = new NPOIFSFileSystem(file, readOnly);
return create(fs, password);
} catch(OfficeXmlFileException e) {
IOUtils.closeQuietly(fs);
return createXWPFDocument(file, readOnly);
} catch(RuntimeException e) {
IOUtils.closeQuietly(fs);
throw e;
}
}
protected static Object createHWPFDocument(NPOIFSFileSystem fs) throws IOException, EncryptedDocumentException {
return new HWPFDocument(fs.getRoot());
}
protected static Object createXWPFDocument(InputStream stream) throws IOException, EncryptedDocumentException {
return new XWPFDocument(stream);
}
protected static Object createXWPFDocument(File file, boolean readOnly) throws IOException, EncryptedDocumentException {
try {
OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE);
return new XWPFDocument(pkg);
} catch (InvalidFormatException e) {
throw new IOException(e);
}
}
}
}
I am working on a socket server for a MMORPG I am creating, and I am unsure how to organize commands and handlers for readability.
I will be getting the command from data[0], such as ban, kick, identify, etc. I have read that you can use a HashMap and have an Interface Command, and create a new class for each handler/command that implements Command. You'd then create a HashMap and go from there. I have also read that you can reflection. I want to do what an experienced programmer would do.
Client Class:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client implements Runnable {
private Socket socket;
private Server server;
private boolean isConnected;
private BufferedReader in;
private PrintWriter out;
public Client(Socket socket, Server server) {
this.socket = socket;
this.server = server;
this.isConnected = true;
this.in = null;
this.out = null;
}
#Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (isConnected) {
String recv = in.readLine().trim();
if (recv != null) {
String[] data = recv.split("%");
}
}
} catch (IOException e) {}
}
public synchronized void send(String data) {
out.println(data);
}
}
What you want is to use the Command Pattern.
Here is how I would use the Command Pattern for handling commands from a client.
/* Command Exception. */
public class ClientCommandException extends Exception {
public ClientCommandException(String msg) {
super(msg);
}
}
/* The ClientCommand interface */
public interface ClientCommand {
void execute(Client client, String[] params) throws ClientCommandException;
}
import java.util.HashMap;
import java.util.Arrays;
/* Container for commands */
public class Commands implements ClientCommand {
private HashMap<String, ClientCommand> cmds;
public Commands() {
cmds = new HashMap<String, ClientCommand>();
}
public void addCommand(ClientCommand cmd, String name) {
cmds.put(name, cmd);
}
public void execute(Client client, String[] params) throws ClientCommandException {
ClientCommand cmd = cmds.get(params[0]);
if(cmd != null) {
cmd.execute(client, Arrays.copyOfRange(params, 1, params.length));
} else {
throw new ClientCommandException("Unknown Command: " + params[0]);
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class Client implements Runnable {
private boolean isConnected;
private Commands cmds;
private BufferedReader in;
private PrintWriter out;
private class EchoCommand implements ClientCommand {
public void execute(Client client, String[] params) throws ClientCommandException {
StringBuilder b = new StringBuilder("Echo back:");
int len = params.length;
for(int i = 0; i < len; i++) {
b.append(' ');
b.append(params[i]);
}
client.send(b.toString());
}
}
private class DisconnectCommand implements ClientCommand {
public void execute(Client client, String[] params) throws ClientCommandException {
client.close();
}
}
public Client() {
cmds = new Commands();
cmds.addCommand(new EchoCommand(), "echo");
cmds.addCommand(new DisconnectCommand(), "disconnect");
/* sub-commands */
Commands server = new Commands();
server.addCommand(new EchoCommand(), "print");
cmds.addCommand(server, "server");
isConnected = true;
}
public void addCommand(ClientCommand cmd, String name) {
cmds.addCommand(cmd, name);
}
public void close() {
isConnected = false;
}
#Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(System.in));
out = new PrintWriter(System.out, true);
while (isConnected) {
String recv = in.readLine().trim();
if (recv != null) {
String[] data = recv.split("%");
try {
cmds.execute(this, data);
} catch(ClientCommandException e) {
/* Return some error back to the client. */
out.println(e.toString());
}
}
}
} catch (IOException e) {}
}
public synchronized void send(String data) {
out.println(data);
}
public static void main(String[] args){
Client client = new Client();
System.out.println("Start Client.");
client.run();
}
}
I've got the following code for a file upload with Apache's HTTP-Client (org.apache.http.client):
public static void main(String[] args) throws Exception
{
String fileName = "test.avi";
File file = new File(fileName);
String serverResponse = null;
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient client = new DefaultHttpClient(params);
HttpPut put = new HttpPut("http://localhost:8080/" + fileName);
FileEntity fileEntity = new FileEntity(file, "binary/octet-stream");
put.setEntity(fileEntity);
HttpResponse response = client.execute(put);
HttpEntity entity = response.getEntity();
if (entity != null)
{
serverResponse = EntityUtils.toString(entity);
System.out.println(serverResponse);
}
}
It work's quite well but now I want to have a progress bar which shows the progress of the file upload. How can this be made? I found a code snippet at File Upload with Java (with progress bar) but it is designed for Apache HTTP Client 3 (org.apache.commons.httpclient) and the RequestEntity class does not exist in Apache HTTP Client 4. ;(
Maybe someone of you has an approach?
Many greetings
Benny
I introduced a derived FileEntity that just counts the written bytes.
It uses OutputStreamProgress that does the actual counting (kind of a decorator to the actual OutputStream).
The advantage of this (and decoration in general) is that I do not need to copy the actual implementation, like the the actual copying from the file stream to the output stream. I can also change to use a different (newer) implementation, like the NFileEntity.
Enjoy...
FileEntity.java
public class FileEntity extends org.apache.http.entity.FileEntity {
private OutputStreamProgress outstream;
public FileEntity(File file, String contentType) {
super(file, contentType);
}
#Override
public void writeTo(OutputStream outstream) throws IOException {
this.outstream = new OutputStreamProgress(outstream);
super.writeTo(this.outstream);
}
/**
* Progress: 0-100
*/
public int getProgress() {
if (outstream == null) {
return 0;
}
long contentLength = getContentLength();
if (contentLength <= 0) { // Prevent division by zero and negative values
return 0;
}
long writtenLength = outstream.getWrittenLength();
return (int) (100*writtenLength/contentLength);
}
}
OutputStreamProgress.java
public class OutputStreamProgress extends OutputStream {
private final OutputStream outstream;
private volatile long bytesWritten=0;
public OutputStreamProgress(OutputStream outstream) {
this.outstream = outstream;
}
#Override
public void write(int b) throws IOException {
outstream.write(b);
bytesWritten++;
}
#Override
public void write(byte[] b) throws IOException {
outstream.write(b);
bytesWritten += b.length;
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
outstream.write(b, off, len);
bytesWritten += len;
}
#Override
public void flush() throws IOException {
outstream.flush();
}
#Override
public void close() throws IOException {
outstream.close();
}
public long getWrittenLength() {
return bytesWritten;
}
}
A new version using the package org.apache.commons.io.output from commons-io (2.4) and its class CountingOutputStream.
I changed the initial code to reflect my project needs to use a multipart form as input and the post method (this dues to the requirements imposed by the server side).
Consider that the delta of large file correspond in my tests to 4096 bytes. This means that the listener method counterChanged() is called every 4096 bytes of transfered data, what is acceptable for my use case.
The method looks like:
public void post(String url, File sendFile) {
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient client = new DefaultHttpClient(params);
HttpPost post = new HttpPost(url + "/" + sendFile.getName());
MultipartEntity multiEntity = new MultipartEntity();
MyFileBody fileBody = new MyFileBody(sendFile);
fileBody.setListener(new IStreamListener(){
#Override
public void counterChanged(int delta) {
// do something
System.out.println(delta);
}});
multiEntity.addPart("file", fileBody);
StringBody stringBody = new StringBody(sendFile.getName());
multiEntity.addPart("fileName", stringBody);
post.setEntity(multiEntity);
HttpResponse response = client.execute(post);
}
The class MyFileBody becomes:
public class MyFileBody extends FileBody {
private IStreamListener listener;
public MyFileBody(File file) {
super(file);
}
#Override
public void writeTo(OutputStream out) throws IOException {
CountingOutputStream output = new CountingOutputStream(out) {
#Override
protected void beforeWrite(int n) {
if (listener != null && n != 0)
listener.counterChanged(n);
super.beforeWrite(n);
}
};
super.writeTo(output);
}
public void setListener(IStreamListener listener) {
this.listener = listener;
}
public IStreamListener getListener() {
return listener;
}
}
Finally, the listener interface looks like:
public interface IStreamListener {
void counterChanged(int delta);
}
This answer extends kilaka's answer by adding a simple listener to the OutputStreamProgress.java class instead of having the public getProgress() method (I'm honestly not sure how you are suppose to call the getProgress() method since the thread will be executing inside of httpclient's code the entire time you might want to call getProgress()!).
Please note you'll need to extend the entity class for each entity type you want to use, and when you write your HttpClient code, you'll need to create the entity of that new type.
I wrote a very basic write listener that implements the WriteListener interface. This is where you'll add your logic to do something with the write reports from the OutputStreamProgress, something like updating a progress bar :)
Big thanks to kilaka for using the decorator idea to sneak in a counting outstream.
WriteLisener.java
public interface WriteListener {
void registerWrite(long amountOfBytesWritten);
}
OutputStreamProgress.java
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamProgress extends OutputStream {
private final OutputStream outstream;
private long bytesWritten=0;
private final WriteListener writeListener;
public OutputStreamProgress(OutputStream outstream, WriteListener writeListener) {
this.outstream = outstream;
this.writeListener = writeListener;
}
#Override
public void write(int b) throws IOException {
outstream.write(b);
bytesWritten++;
writeListener.registerWrite(bytesWritten);
}
#Override
public void write(byte[] b) throws IOException {
outstream.write(b);
bytesWritten += b.length;
writeListener.registerWrite(bytesWritten);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
outstream.write(b, off, len);
bytesWritten += len;
writeListener.registerWrite(bytesWritten);
}
#Override
public void flush() throws IOException {
outstream.flush();
}
#Override
public void close() throws IOException {
outstream.close();
}
}
BasicWriteListener
public class BasicWriteListener implements WriteListener {
public BasicWriteListener() {
// TODO Auto-generated constructor stub
}
public void registerWrite(long amountOfBytesWritten) {
System.out.println(amountOfBytesWritten);
}
}
MultipartEntityWithProgressBar
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
public class MultipartEntityWithProgressBar extends MultipartEntity {
private OutputStreamProgress outstream;
private WriteListener writeListener;
#Override
public void writeTo(OutputStream outstream) throws IOException {
this.outstream = new OutputStreamProgress(outstream, writeListener);
super.writeTo(this.outstream);
}
public MultipartEntityWithProgressBar(WriteListener writeListener)
{
super();
this.writeListener = writeListener;
}
public MultipartEntityWithProgressBar(HttpMultipartMode mode, WriteListener writeListener)
{
super(mode);
this.writeListener = writeListener;
}
public MultipartEntityWithProgressBar(HttpMultipartMode mode, String boundary, Charset charset, WriteListener writeListener)
{
super(mode, boundary, charset);
this.writeListener = writeListener;
}
// Left in for clarity to show where I took from kilaka's answer
// /**
// * Progress: 0-100
// */
// public int getProgress() {
// if (outstream == null) {
// return 0;
// }
// long contentLength = getContentLength();
// if (contentLength <= 0) { // Prevent division by zero and negative values
// return 0;
// }
// long writtenLength = outstream.getWrittenLength();
// return (int) (100*writtenLength/contentLength);
// }
}
Hello guys!
I solved the problem myself and made a simple example to it.
If there are any questions, feel free to ask.
Here we go!
ApplicationView.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
public class ApplicationView implements ActionListener
{
File file = new File("C:/Temp/my-upload.avi");
JProgressBar progressBar = null;
public ApplicationView()
{
super();
}
public void createView()
{
JFrame frame = new JFrame("File Upload with progress bar - Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 200);
frame.setVisible(true);
progressBar = new JProgressBar(0, 100);
progressBar.setBounds(20, 20, 200, 30);
progressBar.setStringPainted(true);
progressBar.setVisible(true);
JButton button = new JButton("upload");
button.setBounds(progressBar.getX(),
progressBar.getY() + progressBar.getHeight() + 20,
100,
40);
button.addActionListener(this);
JPanel panel = (JPanel) frame.getContentPane();
panel.setLayout(null);
panel.add(progressBar);
panel.add(button);
panel.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
try
{
sendFile(this.file, this.progressBar);
}
catch (Exception ex)
{
System.out.println(ex.getLocalizedMessage());
}
}
private void sendFile(File file, JProgressBar progressBar) throws Exception
{
String serverResponse = null;
HttpParams params = new BasicHttpParams();
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpClient client = new DefaultHttpClient(params);
HttpPut put = new HttpPut("http://localhost:8080/" + file.getName());
ProgressBarListener listener = new ProgressBarListener(progressBar);
FileEntityWithProgressBar fileEntity = new FileEntityWithProgressBar(file, "binary/octet-stream", listener);
put.setEntity(fileEntity);
HttpResponse response = client.execute(put);
HttpEntity entity = response.getEntity();
if (entity != null)
{
serverResponse = EntityUtils.toString(entity);
System.out.println(serverResponse);
}
}
}
FileEntityWithProgressBar.java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.http.entity.AbstractHttpEntity;
/**
* File entity which supports a progress bar.<br/>
* Based on "org.apache.http.entity.FileEntity".
* #author Benny Neugebauer (www.bennyn.de)
*/
public class FileEntityWithProgressBar extends AbstractHttpEntity implements Cloneable
{
protected final File file;
private final ProgressBarListener listener;
private long transferredBytes;
public FileEntityWithProgressBar(final File file, final String contentType, ProgressBarListener listener)
{
super();
if (file == null)
{
throw new IllegalArgumentException("File may not be null");
}
this.file = file;
this.listener = listener;
this.transferredBytes = 0;
setContentType(contentType);
}
public boolean isRepeatable()
{
return true;
}
public long getContentLength()
{
return this.file.length();
}
public InputStream getContent() throws IOException
{
return new FileInputStream(this.file);
}
public void writeTo(final OutputStream outstream) throws IOException
{
if (outstream == null)
{
throw new IllegalArgumentException("Output stream may not be null");
}
InputStream instream = new FileInputStream(this.file);
try
{
byte[] tmp = new byte[4096];
int l;
while ((l = instream.read(tmp)) != -1)
{
outstream.write(tmp, 0, l);
this.transferredBytes += l;
this.listener.updateTransferred(this.transferredBytes);
}
outstream.flush();
}
finally
{
instream.close();
}
}
public boolean isStreaming()
{
return false;
}
#Override
public Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
ProgressBarListener.java
import javax.swing.JProgressBar;
public class ProgressBarListener
{
private int transferedMegaBytes = 0;
private JProgressBar progressBar = null;
public ProgressBarListener()
{
super();
}
public ProgressBarListener(JProgressBar progressBar)
{
this();
this.progressBar = progressBar;
}
public void updateTransferred(long transferedBytes)
{
transferedMegaBytes = (int) (transferedBytes / 1048576);
this.progressBar.setValue(transferedMegaBytes);
this.progressBar.paint(progressBar.getGraphics());
System.out.println("Transferred: " + transferedMegaBytes + " Megabytes.");
}
}
Happy Coding!
I have a good connection to AD. I can authenticate and check error messages from failed auths.
The issue I'm having comes from trying to change the password. I have an LDAPContext established at this point (yes it is an SSL connection). The issue comes from not knowing what value to use in the "username" parameter. I've tried all variations I can think of and end up getting one of three errors:
A) NO_OBJECT - I'm assuming this means it is connecting to AD properly but can't find what I'm looking for.
B) DIR_ERROR - I'm assuming this means it can get into AD properly but doesn't know wtf I want it to do after that.
C) Some type of ref error that only happens when I don't qualify the DC, so I think that's pretty much a given.
Here is the code I am using:
public void changePassword(String username, String password) {
ModificationItem[] mods = new ModificationItem[1];
String newQuotedPassword = "\"" + password + "\"";
byte[] newUnicodePassword = newQuotedPassword.getBytes();
try {
newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword));
try {
ldapContext.modifyAttributes(username, mods);
} catch (NamingException e) {
System.out.println("Error changing password for '" + username + "': " + e.getMessage());
e.printStackTrace();
}
}
Spring has an LDAP module that works very nicely. I'll bet it will do what you need.
Here is a working example:
Main.java:
package io.fouad.ldap;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import java.io.UnsupportedEncodingException;
import java.util.Hashtable;
public class Main
{
public static void main(String[] args)
{
final String LDAP_SERVERS = "ldap://AD_SERVER:636 ldap://AD_SERVER2:636"; // separated by single spaces
final String LDAP_CONNECT_TIMEOUT_MS = "10000"; // 10 seconds
final String LDAP_READ_TIMEOUT_MS = "10000"; // 10 seconds
final String AUTHENTICATION_DOMAIN = "domain.com";
final String USERNAME = "username";
final String OLD_PASSWORD = "123";
final String NEW_PASSWORD = "456";
final String TARGET_BASE_DN = "dc=domain,dc=com";
Hashtable<String, String> ldapEnv = new Hashtable<>();
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.PROVIDER_URL, LDAP_SERVERS);
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put("java.naming.ldap.version", "3");
ldapEnv.put(Context.SECURITY_PRINCIPAL, USERNAME + "#" + AUTHENTICATION_DOMAIN);
ldapEnv.put(Context.SECURITY_CREDENTIALS, OLD_PASSWORD);
ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
ldapEnv.put("java.naming.ldap.factory.socket", "io.fouad.ldap.MySSLSocketFactory");
//ldapEnv.put("com.sun.jndi.ldap.connect.timeout", LDAP_CONNECT_TIMEOUT_MS);
//ldapEnv.put("com.sun.jndi.ldap.read.timeout", LDAP_READ_TIMEOUT_MS);
DirContext ldapContext = null;
try
{
ldapContext = new InitialDirContext(ldapEnv);
}
catch(AuthenticationException e)
{
System.out.println("Wrong username/password!");
e.printStackTrace();
}
catch(NamingException e)
{
e.printStackTrace();
}
if(ldapContext == null) return;
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration objects = null;
try
{
objects = ldapContext.search(TARGET_BASE_DN, String.format("(&(objectClass=user)(sAMAccountName=%s))", USERNAME), searchControls);
}
catch(NamingException e)
{
e.printStackTrace();
}
if(objects == null) return;
try
{
if(objects.hasMore())
{
SearchResult entry = (SearchResult) objects.next();
ModificationItem[] mods = new ModificationItem[2];
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("unicodePwd", getPasswordByteArray(OLD_PASSWORD)));
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("unicodePwd", getPasswordByteArray(NEW_PASSWORD)));
ldapContext.modifyAttributes(entry.getName() + "," + TARGET_BASE_DN, mods);
System.out.println("Successfully changed the password!");
}
else
{
System.out.println("User (" + USERNAME + ") was not found!");
}
}
catch(NamingException e)
{
e.printStackTrace();
}
System.out.println("DONE!");
}
private static byte[] getPasswordByteArray(String password)
{
String quotedPassword = "\"" + password + "\"";
try
{
return quotedPassword.getBytes("UTF-16LE");
}
catch(UnsupportedEncodingException e)
{
e.printStackTrace();
return null;
}
}
}
MySSLSocketFactory.java: (Use it at your own risk)
package io.fouad.ldap;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class MySSLSocketFactory extends SSLSocketFactory
{
private SSLSocketFactory socketFactory;
public MySSLSocketFactory()
{
try
{
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] {new X509TrustManager()
{
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s){}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s){}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
}}, new SecureRandom());
socketFactory = ctx.getSocketFactory();
}
catch(Exception ex)
{
ex.printStackTrace(System.err);
}
}
public static SocketFactory getDefault()
{
return new MySSLSocketFactory();
}
#Override
public String[] getDefaultCipherSuites()
{
return socketFactory.getDefaultCipherSuites();
}
#Override
public String[] getSupportedCipherSuites()
{
return socketFactory.getSupportedCipherSuites();
}
#Override
public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException
{
return socketFactory.createSocket(socket, string, i, bln);
}
#Override
public Socket createSocket(String string, int i) throws IOException
{
return socketFactory.createSocket(string, i);
}
#Override
public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException
{
return socketFactory.createSocket(string, i, ia, i1);
}
#Override
public Socket createSocket(InetAddress ia, int i) throws IOException
{
return socketFactory.createSocket(ia, i);
}
#Override
public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException
{
return socketFactory.createSocket(ia, i, ia1, i1);
}
}
We have a reference for Java fro JNDI here http://ldapwiki.willeke.com/wiki/Set%20Active%20Directory%20Password%20From%20Java
You cannot change the password of a user by just modifying the property that stores it. Instead, you need to use a special LDAP operation SetPassword. I couldn't find a Java reference, but a C# one, and a Perl one.