001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.kerberos.kdc; 021 022 023import java.io.IOException; 024 025import net.sf.ehcache.Cache; 026 027import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 028import org.apache.directory.api.ldap.model.name.Dn; 029import org.apache.directory.server.kerberos.KerberosConfig; 030import org.apache.directory.server.kerberos.changepwd.ChangePasswordServer; 031import org.apache.directory.server.kerberos.protocol.KerberosProtocolHandler; 032import org.apache.directory.server.kerberos.protocol.codec.KerberosProtocolCodecFactory; 033import org.apache.directory.server.kerberos.shared.replay.ReplayCache; 034import org.apache.directory.server.kerberos.shared.replay.ReplayCacheImpl; 035import org.apache.directory.server.kerberos.shared.store.PrincipalStore; 036import org.apache.directory.server.protocol.shared.DirectoryBackedService; 037import org.apache.directory.server.protocol.shared.transport.TcpTransport; 038import org.apache.directory.server.protocol.shared.transport.Transport; 039import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; 040import org.apache.mina.core.filterchain.IoFilterChainBuilder; 041import org.apache.mina.core.service.IoAcceptor; 042import org.apache.mina.filter.codec.ProtocolCodecFilter; 043import org.apache.mina.transport.socket.nio.NioSocketAcceptor; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047 048/** 049 * Contains the configuration parameters for the Kerberos protocol provider. 050 * 051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 052 */ 053public class KdcServer extends DirectoryBackedService 054{ 055 private static final long serialVersionUID = 522567370475574165L; 056 057 /** logger for this class */ 058 private static final Logger LOG = LoggerFactory.getLogger( KdcServer.class ); 059 060 /** The default kdc service name */ 061 private static final String SERVICE_NAME = "Keydap Kerberos Service"; 062 063 /** the cache used for storing AS and TGS requests */ 064 private ReplayCache replayCache; 065 066 private KerberosConfig config; 067 068 private ChangePasswordServer changePwdServer; 069 070 071 /** 072 * Creates a new instance of KdcServer with the default configuration. 073 */ 074 public KdcServer() 075 { 076 this( new KerberosConfig() ); 077 } 078 079 080 /** 081 * 082 * Creates a new instance of KdcServer with the given config. 083 * 084 * @param config the kerberos server configuration 085 */ 086 public KdcServer( KerberosConfig config ) 087 { 088 this.config = config; 089 super.setServiceName( SERVICE_NAME ); 090 super.setSearchBaseDn( config.getSearchBaseDn() ); 091 } 092 093 094 /** 095 * @return the replayCache 096 */ 097 public ReplayCache getReplayCache() 098 { 099 return replayCache; 100 } 101 102 103 /** 104 * @throws IOException if we cannot bind to the sockets 105 */ 106 public void start() throws IOException, LdapInvalidDnException 107 { 108 PrincipalStore store; 109 110 store = new DirectoryPrincipalStore( getDirectoryService(), new Dn( this.getSearchBaseDn() ) ); 111 112 LOG.debug( "initializing the kerberos replay cache" ); 113 114 Cache cache = getDirectoryService().getCacheService().getCache( "kdcReplayCache" ); 115 replayCache = new ReplayCacheImpl( cache, config.getAllowableClockSkew() ); 116 117 // Kerberos can use UDP or TCP 118 for ( Transport transport : transports ) 119 { 120 IoAcceptor acceptor = transport.getAcceptor(); 121 122 // Now, configure the acceptor 123 // Inject the chain 124 IoFilterChainBuilder chainBuilder = new DefaultIoFilterChainBuilder(); 125 126 if ( transport instanceof TcpTransport ) 127 { 128 // Now, configure the acceptor 129 // Disable the disconnection of the clients on unbind 130 acceptor.setCloseOnDeactivation( false ); 131 132 // No Nagle's algorithm 133 ( ( NioSocketAcceptor ) acceptor ).getSessionConfig().setTcpNoDelay( true ); 134 135 // Allow the port to be reused even if the socket is in TIME_WAIT state 136 ( ( NioSocketAcceptor ) acceptor ).setReuseAddress( true ); 137 } 138 139 // Inject the codec 140 ( ( DefaultIoFilterChainBuilder ) chainBuilder ).addFirst( "codec", 141 new ProtocolCodecFilter( 142 KerberosProtocolCodecFactory.getInstance() ) ); 143 144 acceptor.setFilterChainBuilder( chainBuilder ); 145 146 // Inject the protocol handler 147 acceptor.setHandler( new KerberosProtocolHandler( this, store ) ); 148 149 // Bind to the configured address 150 acceptor.bind(); 151 } 152 153 LOG.info( "Kerberos service started." ); 154 155 if ( changePwdServer != null ) 156 { 157 changePwdServer.setSearchBaseDn( this.getSearchBaseDn() ); 158 changePwdServer.start(); 159 } 160 } 161 162 163 public void stop() 164 { 165 for ( Transport transport : getTransports() ) 166 { 167 IoAcceptor acceptor = transport.getAcceptor(); 168 169 if ( acceptor != null ) 170 { 171 acceptor.dispose(); 172 } 173 } 174 175 if ( replayCache != null ) 176 { 177 replayCache.clear(); 178 } 179 180 LOG.info( "Kerberos service stopped." ); 181 182 if ( changePwdServer != null ) 183 { 184 changePwdServer.stop(); 185 } 186 } 187 188 189 /** 190 * gets the port number on which TCP transport is running 191 * @return the port number if TCP transport is enabled, -1 otherwise 192 */ 193 public int getTcpPort() 194 { 195 for ( Transport t : transports ) 196 { 197 if ( t instanceof TcpTransport ) 198 { 199 return t.getPort(); 200 } 201 } 202 203 return -1; 204 } 205 206 207 /** 208 * @return the KDC server configuration 209 */ 210 public KerberosConfig getConfig() 211 { 212 return config; 213 } 214 215 216 public ChangePasswordServer getChangePwdServer() 217 { 218 return changePwdServer; 219 } 220 221 222 public void setChangePwdServer( ChangePasswordServer changePwdServer ) 223 { 224 this.changePwdServer = changePwdServer; 225 } 226 227 228 /** 229 * @see Object#toString() 230 */ 231 public String toString() 232 { 233 StringBuilder sb = new StringBuilder(); 234 235 sb.append( "KDCServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' ); 236 237 if ( getTransports() != null ) 238 { 239 for ( Transport transport : getTransports() ) 240 { 241 sb.append( " " ).append( transport ).append( '\n' ); 242 } 243 } 244 245 return sb.toString(); 246 } 247}