Package org.wso2.carbon.apacheds.impl

Source Code of org.wso2.carbon.apacheds.impl.ApacheKDCServer

/*
*  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. licenses this file to you 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.
*/
package org.wso2.carbon.apacheds.impl;

import org.apache.directory.server.core.DirectoryService;
import org.apache.directory.server.core.jndi.CoreContextFactory;
import org.apache.directory.server.kerberos.kdc.KdcServer;
import org.apache.directory.server.kerberos.shared.store.KerberosAttribute;
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
import org.apache.directory.server.protocol.shared.transport.Transport;
import org.apache.directory.server.protocol.shared.transport.UdpTransport;
import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
import org.apache.mina.util.AvailablePortFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.apacheds.KDCServer;
import org.wso2.carbon.apacheds.KdcConfiguration;
import org.wso2.carbon.apacheds.LDAPServer;
import org.wso2.carbon.apacheds.PartitionInfo;
import org.wso2.carbon.apacheds.exception.DirectoryServerException;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.io.IOException;
import java.util.Hashtable;

/**
* An implementation of the KDC server. This uses KDC server which comes with ApacheDS.
*/
public class ApacheKDCServer implements KDCServer {
       
    private static final Logger logger = LoggerFactory.getLogger(ApacheKDCServer.class);

    private static final int START_PORT = 6088;

    private KdcServer kdcServer;

    /** the context root for the schema */
    protected LdapContext schemaRoot;

    public ApacheKDCServer () {
        this.kdcServer = new KdcServer();
    }

    public void init(final KdcConfiguration configuration, LDAPServer ldapServer)
        throws DirectoryServerException {

        if (configuration == null) {
            throw new DirectoryServerException("Could not initialize KDC server. " +
                                               "KDC configurations are null");
        }

        if (ldapServer == null) {
            throw new DirectoryServerException("Could not initialize KDC server. " +
                                               "Directory service is null.");
        }

        if (!(ldapServer instanceof ApacheLDAPServer)) {
            throw new DirectoryServerException("Apache KDC server is only compatible with " +
                                               "ApacheLDAPServer");
        }

        ApacheLDAPServer apacheLDAP = (ApacheLDAPServer)ldapServer;

        this.kdcServer.setServiceName(configuration.getKdcName());
        this.kdcServer.setKdcPrincipal(configuration.getKdcPrinciple());
        this.kdcServer.setPrimaryRealm(configuration.getPrimaryRealm());
        this.kdcServer.setMaximumTicketLifetime(configuration.getMaxTicketLifeTime());
        this.kdcServer.setMaximumRenewableLifetime(configuration.getMaxRenewableLifeTime());
        this.kdcServer.setSearchBaseDn(configuration.getSearchBaseDomainName());
        this.kdcServer.setPaEncTimestampRequired(
                configuration.isPreAuthenticateTimeStampRequired());
       
        configureTransportHandlers(configuration);

        DirectoryService directoryService = apacheLDAP.getService();

        if (directoryService == null) {
            throw new DirectoryServerException("LDAP service is null. " +
                                               "Could not configure Kerberos.");
        }

        this.kdcServer.setDirectoryService(directoryService);

        setSchemaContext(configuration, directoryService, ldapServer.getConnectionDomainName());

        enableKerberoseSchema();

    }

    private void enableKerberoseSchema() throws DirectoryServerException {
        // check if krb5kdc is disabled
        Attributes krb5kdcAttrs;
        try {
            krb5kdcAttrs = schemaRoot.getAttributes("cn=Krb5kdc");

            boolean isKrb5KdcDisabled = false;
            if (krb5kdcAttrs.get("m-disabled") != null) {
                isKrb5KdcDisabled = (
                        (String)krb5kdcAttrs.get("m-disabled").get()).equalsIgnoreCase("TRUE");
            }

            // if krb5kdc is disabled then enable it
            if (isKrb5KdcDisabled) {
                Attribute disabled = new BasicAttribute("m-disabled");
                ModificationItem[] mods =
                    new ModificationItem[]{new ModificationItem(
                            DirContext.REMOVE_ATTRIBUTE, disabled)};
                schemaRoot.modifyAttributes("cn=Krb5kdc", mods);
            }
        } catch (NamingException e) {
            String msg = "An error occurred while enabling Kerberos schema.";
            logger.error(msg, e);
            throw new DirectoryServerException(msg, e);
        }
    }

    public void kerberizePartition(final PartitionInfo partitionInfo, final LDAPServer ldapServer)
        throws DirectoryServerException {

        DirContext ctx = null;

        try {

            if (!(ldapServer instanceof ApacheLDAPServer)) {
                throw new DirectoryServerException("Apache KDC server is only compatible with " +
                                                   "ApacheLDAPServer");
            }

            ApacheLDAPServer apacheLDAP = (ApacheLDAPServer)ldapServer;

            // Get a context, create the ou=users subcontext, then create the 3 principals.
            Hashtable<String, Object> env = new Hashtable<String, Object>();
            env.put(DirectoryService.JNDI_KEY, apacheLDAP.getService());
            env.put(Context.INITIAL_CONTEXT_FACTORY,
                    ConfigurationConstants.LDAP_INITIAL_CONTEXT_FACTORY);
            env.put(Context.PROVIDER_URL, ConfigurationConstants.USER_SUB_CONTEXT + "," +
                                          partitionInfo.getRootDN());
            env.put(Context.SECURITY_PRINCIPAL, partitionInfo.getAdminDomainName());
            env.put(Context.SECURITY_CREDENTIALS,
                    partitionInfo.getPartitionAdministrator().getAdminPassword());
            env.put(Context.SECURITY_AUTHENTICATION, ConfigurationConstants.SIMPLE_AUTHENTICATION);

            ctx = new InitialDirContext(env);


            // Set KDC principle for this partition
            Attributes attrs = getPrincipalAttributes(ConfigurationConstants.SERVER_PRINCIPLE,
                                           ConfigurationConstants.KDC_SERVER_COMMON_NAME,
                                           ConfigurationConstants.KDC_SERVER_UID,
                                           partitionInfo.getPartitionKdcPassword(),
                                           getKDCPrincipleName(partitionInfo));

            ctx.createSubcontext("uid=" + ConfigurationConstants.KDC_SERVER_UID, attrs);

            // Set LDAP principle for this partition
            attrs = getPrincipalAttributes(ConfigurationConstants.SERVER_PRINCIPLE,
                                           ConfigurationConstants.LDAP_SERVER_COMMON_NAME,
                                           ConfigurationConstants.LDAP_SERVER_UID,
                                           partitionInfo.getLdapServerPrinciplePassword(),
                                           getLDAPPrincipleName(partitionInfo));

            ctx.createSubcontext("uid=" + ConfigurationConstants.LDAP_SERVER_UID, attrs);

        } catch (NamingException e) {
            String msg = "Unable to add server principles for KDC and LDAP. " +
                         "Incorrect domain names.";
            logger.error(msg, e);
            throw new DirectoryServerException(msg, e);
        } finally {

            if (ctx != null) {
                try {
                    ctx.close();
                } catch (NamingException e) {
                    logger.error("Error closing LDAP context.", e);
                }
            }
        }

    }

    private String getKDCPrincipleName(final PartitionInfo partitionInfo) {

        return ConfigurationConstants.KDC_SERVER_UID + "/" + partitionInfo.getRealm() + "@" +
               partitionInfo.getRealm();
    }

    private String getLDAPPrincipleName(PartitionInfo partitionInfo) {
        // TODO find a way to get host name
        return ConfigurationConstants.LDAP_SERVER_UID + "/" + "localhost" + "@" +
               partitionInfo.getRealm();
    }

    /**
     * Convenience method for creating principals.
     *
     * @param cn           the commonName of the person
     * @param principal    the kerberos principal name for the person
     * @param sn           the surName of the person
     * @param uid          the unique identifier for the person
     * @param userPassword the credentials of the person
     * @return the attributes of the person principal
     */
    protected Attributes getPrincipalAttributes( String sn, String cn, String uid,
                                                 String userPassword, String principal )
    {
        Attributes attributes = new BasicAttributes( true );
        Attribute basicAttribute = new BasicAttribute( "objectClass" );
        basicAttribute.add( "top" );
        basicAttribute.add( "person" ); // sn $ cn
        basicAttribute.add( "inetOrgPerson" ); // uid
        basicAttribute.add( "krb5principal" );
        basicAttribute.add( "krb5kdcentry" );
        attributes.put( basicAttribute );
        attributes.put( "cn", cn );
        attributes.put( "sn", sn );
        attributes.put( "uid", uid );
        attributes.put( SchemaConstants.USER_PASSWORD_AT, userPassword );
        attributes.put( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT, principal );
        attributes.put( KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT, "0" );

        return attributes;
    }

    private void setSchemaContext(KdcConfiguration configuration, DirectoryService service,
                                  String connectionUser)
        throws DirectoryServerException {
        Hashtable<String, Object> env = new Hashtable<String, Object>();
        env.put(DirectoryService.JNDI_KEY, service);
        env.put(Context.SECURITY_PRINCIPAL, connectionUser);
        env.put(Context.SECURITY_CREDENTIALS, configuration.getSystemAdminPassword());
        env.put(Context.SECURITY_AUTHENTICATION, ConfigurationConstants.SIMPLE_AUTHENTICATION);
        env.put(Context.INITIAL_CONTEXT_FACTORY, CoreContextFactory.class.getName());

        env.put(Context.PROVIDER_URL, SchemaConstants.OU_SCHEMA);

        try {
            schemaRoot = new InitialLdapContext(env, null);
        } catch (NamingException e) {
            throw new DirectoryServerException(
                "Unable to create Schema context with user " + connectionUser);
        }

    }



    public void start()
        throws DirectoryServerException {
        try {
            this.kdcServer.start();
            logger.info("KDC server started ...");
        } catch (IOException e) {

            String msg = "Could not start KDC server due to an IOException";
            logger.error(msg, e);
            throw new DirectoryServerException(msg, e);

        } catch (LdapInvalidDnException e) {
            String msg = "Could not start KDC server due to an error in a domain name.";
            logger.error(msg, e);
            throw new DirectoryServerException(msg, e);
        }
    }

    public boolean isKDCServerStarted() {
        return this.kdcServer.isStarted();
    }

    public void stop()
        throws DirectoryServerException {

        this.kdcServer.stop();
        logger.info("KDC server stopped ...");

    }

    private void configureTransportHandlers(KdcConfiguration configuration) {

        int port = getServerPort(configuration);
        if (configuration.getKdcCommunicationProtocol() ==
            KdcConfiguration.ProtocolType.UDP_PROTOCOL) {

            logger.info("Starting KDC on UDP mode at port - " + port + " at host - " +
                configuration.getKdcHostAddress());

            UdpTransport defaultTransport = new UdpTransport(port);
            this.kdcServer.addTransports(defaultTransport);

        } else {

            logger.info("Starting KDC on a TCP port " + port + " at host " +
                        configuration.getKdcHostAddress());
            Transport tcp =
                new TcpTransport(configuration.getKdcHostAddress(), port,
                                 configuration.getNumberOfThreads(),
                                 configuration.getBackLogCount());
            this.kdcServer.addTransports(tcp);

        }
    }

    private int getServerPort(KdcConfiguration configuration) {
        int port = configuration.getKdcCommunicationPort();

        if (port == -1) {
            port = AvailablePortFinder.getNextAvailable(START_PORT);
        }

        return port;
    }

}
TOP

Related Classes of org.wso2.carbon.apacheds.impl.ApacheKDCServer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.