Dne 26.11.2010 08:41, Martin Kuba napsal(a):
Spring Security jsem nepoužíval, jenom Spring LDAP, ale podle toho popisu 
soudím,
že je třeba si vytvořit vlastní implementaci AbstractContextSource, viz
http://static.springsource.org/spring-ldap/docs/1.3.x/apidocs/index.html?org/springframework/ldap/core/support/AbstractContextSource.html
která se k připojí k LDAP serveru a použije přitom SSL certifikát.

V něm je třeba se správně autentizovat, popis je na
http://download.oracle.com/javase/jndi/tutorial/ldap/security/ssl.html
v části "Using Custom Sockets". Je třeba si vytvořit SslSocketFactory, která
dokáže předložit klientský SSL certifikát. To se dělá zhruba takto:

Tak jsem si to zkusil, a je to tak. V konfiguraci Springu se musí
org.springframework.ldap.core.support.LdapContextSource
nahradit za vlastní implementaci, která musí vypadat nějak takto:

package cz.makub;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.core.support.AbstractContextSource;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.InitialLdapContext;
import javax.net.SocketFactory;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.util.Hashtable;

/**
 * Alternative to LdapContextSource allowing client SSL certificates.
 *
 * @author Martin Kuba [email protected]
 * @version $Id:$
 * @see org.springframework.ldap.core.support.LdapContextSource
 */
public class MyContextSource extends AbstractContextSource {

    final static Logger log = LoggerFactory.getLogger(MyContextSource.class);

    private String keyStoreFile;
    private String keyStorePassword;

    public void setKeyStoreFile(String keyStoreFile) {
        this.keyStoreFile = keyStoreFile;
    }

    public void setKeyStorePassword(String keyStorePassword) {
        this.keyStorePassword = keyStorePassword;
    }

    @SuppressWarnings({"unchecked"})
    @Override
    protected DirContext getDirContextInstance(Hashtable env) throws 
NamingException {
        String url = (String) env.get(Context.PROVIDER_URL);
        try {
            if (new URI(url).getScheme().equalsIgnoreCase("ldaps")) {
                env.put("java.naming.ldap.factory.socket", 
"cz.makub.MyContextSource$MySSLFactory");
                MySSLFactory.setManagers(getKeyManagers(), null);
            }
        } catch (URISyntaxException e) {
            log.error("LDAP URL " + url + " is wrong", e);
        }
        return new InitialLdapContext(env, null);
    }

    private KeyManager[] getKeyManagers() {
        return getKeyManagers(loadKeyStoreFromFile(keyStoreFile, 
keyStorePassword), keyStorePassword);
    }

    private static KeyManager[] getKeyManagers(KeyStore keyStore, String 
storePassword) {
        try {
            KeyManagerFactory keyManagerFactory = 
KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore, storePassword != null ? 
storePassword.toCharArray() : null);
            return keyManagerFactory.getKeyManagers();
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

    private static KeyStore loadKeyStoreFromFile(String ksfile, String 
password) {
        String kstype;
        if (ksfile.endsWith(".jks")) {
            kstype = "JKS";
        } else if (ksfile.endsWith(".p12")) {
            kstype = "PKCS12";
        } else {
            throw new RuntimeException("keystore file name " + ksfile + " must end 
with .ks (JKS) or .p12 (PKCS12)");
        }
        try {
            KeyStore store = KeyStore.getInstance(kstype);
            store.load(new FileInputStream(ksfile), password != null ? 
password.toCharArray() : null);
            return store;
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

    /**
     * SSL SocketFactory enabling client certificates and customs server checks.
     */
    @SuppressWarnings({"UnusedDeclaration"})
    public static class MySSLFactory extends SocketFactory {

        final static MySSLFactory thisFactory = new MySSLFactory();

        static SSLSocketFactory factory = (SSLSocketFactory) 
SSLSocketFactory.getDefault();

        public static void setManagers(KeyManager[] keyManagers, TrustManager[] 
trustManagers) {
            try {
                SSLContext sctx = SSLContext.getInstance("TLS");
                sctx.init(keyManagers, trustManagers, null);
                factory = sctx.getSocketFactory();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        public static SocketFactory getDefault() {
            return thisFactory;
        }

        @Override
        public Socket createSocket() throws IOException {
            return factory.createSocket();
        }

        public Socket createSocket(String s, int i) throws IOException {
            return factory.createSocket(s, i);
        }

        public Socket createSocket(String s, int i, InetAddress inetAddress, 
int i1) throws IOException {
            return factory.createSocket(s, i, inetAddress, i1);
        }

        public Socket createSocket(InetAddress inetAddress, int i) throws 
IOException {
            return factory.createSocket(inetAddress, i);
        }

        public Socket createSocket(InetAddress inetAddress, int i, InetAddress 
inetAddress1, int i1) throws IOException {
            return factory.createSocket(inetAddress, i, inetAddress1, i1);
        }
    }
}


Klientský certifikát pak musí být ve formátu JKS nebo PKCS12 v souboru
odkazovaném property keyStoreFile a v property keyStorePassword
musí být heslo k soouboru i ke klíči, to u PKCS12 bývá totožné.

Tož tak.

Makub
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Supercomputing Center Brno             Martin Kuba
Institute of Computer Science    email: [email protected]
Masaryk University             http://www.ics.muni.cz/~makub/
Botanicka 68a, 60200 Brno, CZ     mobil: +420-603-533775
--------------------------------------------------------------

Odpovedet emailem