package com.demo.apacheDS;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;

import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.directory.shared.asn1.EncoderException;
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
import org.apache.directory.shared.kerberos.components.EncryptionKey;
import org.apache.directory.shared.ldap.model.entry.Attribute;
import org.apache.directory.shared.ldap.model.entry.DefaultAttribute;
import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
import org.apache.directory.shared.ldap.model.entry.Entry;
import org.apache.directory.shared.ldap.model.exception.LdapException;
import org.apache.directory.shared.ldap.model.schema.SchemaManager;
import org.apache.directory.shared.ldap.model.schema.registries.DefaultSchema;
import org.apache.directory.shared.ldap.model.schema.registries.Schema;
import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;

public class HeimdalLDAPEntry {
	public static String loginDN = "cn=Manager,dc=example,dc=com";
	public static String loginDNPwd = "apple123$";// "people";
	private static final Map<EncryptionType, String> DEFAULT_CIPHERS;

	public static Map<EncryptionType, String> getDefaultCiphers() {
		return DEFAULT_CIPHERS;
	}
	
	static {
		Map map = new HashMap();
		map.put(EncryptionType.DES_CBC_MD5, "DES");
		map.put(EncryptionType.DES3_CBC_SHA1_KD, "DESede");
		map.put(EncryptionType.RC4_HMAC, "ArcFourHmac");
		map.put(EncryptionType.AES128_CTS_HMAC_SHA1_96, "AES128");
		map.put(EncryptionType.AES256_CTS_HMAC_SHA1_96, "AES256");	
		DEFAULT_CIPHERS = Collections.unmodifiableMap(map);
	}
	
	public static void main(String[] args) throws IOException, LdapException {
		createPrincipalForHeimdalDSCode();
	}

	public static void createPrincipalForHeimdalDSCode () throws LdapException, IOException{
		String USERS_DN = "ou=KerberosPrincipals,dc=example,dc=com";
		String principalName = "sample@HELLO.COM";
		String rdn ="krb5PrincipalName="+principalName;
		String userPassword ="apple";
		String loginDN = "cn=Manager,dc=example,dc=com";// ou=people,dc=example,dc=com";
		String loginDNPwd = "apple123$";// "people";
		String uid = principalName.split("@")[0];
		LdapConnection connection = null;
		try {
			System.out.println("Started the process");
			connection = new LdapNetworkConnection("localhost", 389);
			connection.bind(loginDN, loginDNPwd);

			SchemaManager schemaManager = new DefaultSchemaManager();
			Schema schema = new DefaultSchema("hdb");
			schemaManager.getLoader().addSchema(schema);
			System.out.println("Schema Process Done");

			Map keys = getKerberosKeys(principalName, userPassword, DEFAULT_CIPHERS.keySet());
			Attribute attribute = getKeyAttribute(schemaManager, keys);

			Entry entry = new DefaultEntry(schemaManager);
			entry.setDn( rdn + "," + USERS_DN );
			entry.add( "objectClass", "top", "account","krb5Principal","krb5KDCEntry");
			entry.add("krb5PrincipalName",principalName);
			entry.add("krb5KeyVersionNumber","1");
			entry.add("uid",uid);
			entry.add("krb5MaxLife","86400");
			entry.add("krb5MaxRenew","604800");
			entry.add(new Attribute[] { attribute });

			System.out.println("entry" +entry);
			connection.add( entry );
			System.out.println("Entry has been created");
			System.out.println(connection);

			connection.unBind();
		}catch (Exception e) {
			e.printStackTrace();
		}
		finally{
			connection.close();
		}

	}

	private static Attribute getKeyAttribute(SchemaManager schemaManager,
			Map<EncryptionType, EncryptionKey> keys) throws LdapException {
		Attribute keyAttribute = new DefaultAttribute("krb5Key",schemaManager.lookupAttributeTypeRegistry("krb5Key"));
		for (EncryptionKey encryptionKey : keys.values()) {
			try {
				ByteBuffer buffer = ByteBuffer.allocate(encryptionKey.computeLength());
				encryptionKey.encode(buffer);
				keyAttribute.add(new byte[][] { buffer.array() });
			} catch (EncoderException ioe) {
				ioe.printStackTrace();
			}
		}
		return keyAttribute;
	}

	public static Map<EncryptionType, EncryptionKey> getKerberosKeys(String principalName, String passPhrase, Set<EncryptionType> ciphers) {
		KerberosPrincipal principal = new KerberosPrincipal(principalName);
		Map kerberosKeys = new HashMap();

		Iterator it = ciphers.iterator();
		while (it.hasNext()) {
			EncryptionType encryptionType = (EncryptionType) it.next();
			String algorithm = (String) DEFAULT_CIPHERS.get(encryptionType);
			try {
				KerberosKey kerberosKey = new KerberosKey(principal,passPhrase.toCharArray(), algorithm);
				EncryptionKey encryptionKey = new EncryptionKey(encryptionType,kerberosKey.getEncoded(),kerberosKey.getVersionNumber());
				kerberosKeys.put(encryptionType, encryptionKey);
			} catch (IllegalArgumentException iae) {
				iae.printStackTrace();
			}
		}
		return kerberosKeys;
	}
}
