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 org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; 026import org.apache.directory.api.ldap.model.name.Dn; 027import org.apache.directory.server.kerberos.KerberosConfig; 028import org.apache.directory.server.kerberos.changepwd.ChangePasswordServer; 029import org.apache.directory.server.kerberos.protocol.KerberosProtocolHandler; 030import org.apache.directory.server.kerberos.protocol.codec.KerberosProtocolCodecFactory; 031import org.apache.directory.server.kerberos.shared.replay.ReplayCache; 032import org.apache.directory.server.kerberos.shared.replay.ReplayCacheImpl; 033import org.apache.directory.server.kerberos.shared.store.PrincipalStore; 034import org.apache.directory.server.protocol.shared.DirectoryBackedService; 035import org.apache.directory.server.protocol.shared.transport.TcpTransport; 036import org.apache.directory.server.protocol.shared.transport.Transport; 037import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; 038import org.apache.mina.core.filterchain.IoFilterChainBuilder; 039import org.apache.mina.core.service.IoAcceptor; 040import org.apache.mina.filter.codec.ProtocolCodecFilter; 041import org.apache.mina.transport.socket.AbstractDatagramSessionConfig; 042import org.apache.mina.transport.socket.AbstractSocketSessionConfig; 043//import org.apache.mina.transport.socket.AbstractSocketSessionConfig; 044import org.apache.mina.transport.socket.nio.NioSocketAcceptor; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048 049/** 050 * Contains the configuration parameters for the Kerberos protocol provider. 051 * 052 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 053 */ 054public class KdcServer extends DirectoryBackedService 055{ 056 private static final long serialVersionUID = 522567370475574165L; 057 058 /** logger for this class */ 059 private static final Logger LOG = LoggerFactory.getLogger( KdcServer.class ); 060 061 /** The default kdc service name */ 062 private static final String SERVICE_NAME = "Keydap Kerberos Service"; 063 064 /** the cache used for storing AS and TGS requests */ 065 private ReplayCache replayCache; 066 067 private KerberosConfig config; 068 069 private ChangePasswordServer changePwdServer; 070 071 072 /** 073 * Creates a new instance of KdcServer with the default configuration. 074 */ 075 public KdcServer() 076 { 077 this( new KerberosConfig() ); 078 } 079 080 081 /** 082 * 083 * Creates a new instance of KdcServer with the given config. 084 * 085 * @param config the kerberos server configuration 086 */ 087 public KdcServer( KerberosConfig config ) 088 { 089 this.config = config; 090 super.setServiceName( SERVICE_NAME ); 091 super.setSearchBaseDn( config.getSearchBaseDn() ); 092 } 093 094 095 /** 096 * @return the replayCache 097 */ 098 public ReplayCache getReplayCache() 099 { 100 return replayCache; 101 } 102 103 104 /** 105 * @throws IOException if we cannot bind to the sockets 106 */ 107 public void start() throws IOException, LdapInvalidDnException 108 { 109 PrincipalStore store; 110 111 store = new DirectoryPrincipalStore( getDirectoryService(), new Dn( this.getSearchBaseDn() ) ); 112 113 LOG.debug( "initializing the kerberos replay cache" ); 114 115 replayCache = new ReplayCacheImpl( 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 // Set the buffer size to 32Kb, instead of 1Kb by default 139 ( ( AbstractSocketSessionConfig ) acceptor.getSessionConfig() ).setReadBufferSize( 32 * 1024 ); 140 ( ( AbstractSocketSessionConfig ) acceptor.getSessionConfig() ).setSendBufferSize( 32 * 1024 ); 141 } 142 else 143 { 144 // Set the buffer size to 32Kb, instead of 1Kb by default 145 ( ( AbstractDatagramSessionConfig ) acceptor.getSessionConfig() ).setReadBufferSize( 32 * 1024 ); 146 ( ( AbstractDatagramSessionConfig ) acceptor.getSessionConfig() ).setSendBufferSize( 32 * 1024 ); 147 } 148 149 // Inject the codec 150 ( ( DefaultIoFilterChainBuilder ) chainBuilder ).addFirst( "codec", 151 new ProtocolCodecFilter( 152 KerberosProtocolCodecFactory.getInstance() ) ); 153 154 acceptor.setFilterChainBuilder( chainBuilder ); 155 156 // Inject the protocol handler 157 acceptor.setHandler( new KerberosProtocolHandler( this, store ) ); 158 159 160 // Bind to the configured address 161 acceptor.bind(); 162 } 163 164 LOG.info( "Kerberos service started." ); 165 166 if ( changePwdServer != null ) 167 { 168 changePwdServer.setSearchBaseDn( this.getSearchBaseDn() ); 169 changePwdServer.start(); 170 } 171 } 172 173 174 public void stop() 175 { 176 for ( Transport transport : getTransports() ) 177 { 178 IoAcceptor acceptor = transport.getAcceptor(); 179 180 if ( acceptor != null ) 181 { 182 acceptor.dispose(); 183 } 184 } 185 186 if ( replayCache != null ) 187 { 188 replayCache.clear(); 189 } 190 191 LOG.info( "Kerberos service stopped." ); 192 193 if ( changePwdServer != null ) 194 { 195 changePwdServer.stop(); 196 } 197 } 198 199 200 /** 201 * gets the port number on which TCP transport is running 202 * @return the port number if TCP transport is enabled, -1 otherwise 203 */ 204 public int getTcpPort() 205 { 206 for ( Transport t : transports ) 207 { 208 if ( t instanceof TcpTransport ) 209 { 210 return t.getPort(); 211 } 212 } 213 214 return -1; 215 } 216 217 218 /** 219 * @return the KDC server configuration 220 */ 221 public KerberosConfig getConfig() 222 { 223 return config; 224 } 225 226 227 public ChangePasswordServer getChangePwdServer() 228 { 229 return changePwdServer; 230 } 231 232 233 public void setChangePwdServer( ChangePasswordServer changePwdServer ) 234 { 235 this.changePwdServer = changePwdServer; 236 } 237 238 239 /** 240 * @see Object#toString() 241 */ 242 public String toString() 243 { 244 StringBuilder sb = new StringBuilder(); 245 246 sb.append( "KDCServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' ); 247 248 if ( getTransports() != null ) 249 { 250 for ( Transport transport : getTransports() ) 251 { 252 sb.append( " " ).append( transport ).append( '\n' ); 253 } 254 } 255 256 return sb.toString(); 257 } 258}