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 */ 020 package org.apache.directory.server.changepw; 021 022 023 import java.io.IOException; 024 import java.util.ArrayList; 025 import java.util.List; 026 027 import javax.security.auth.kerberos.KerberosPrincipal; 028 029 import org.apache.directory.server.changepw.protocol.ChangePasswordProtocolHandler; 030 import org.apache.directory.server.constants.ServerDNConstants; 031 import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType; 032 import org.apache.directory.server.kerberos.shared.store.DirectoryPrincipalStore; 033 import org.apache.directory.server.kerberos.shared.store.PrincipalStore; 034 import org.apache.directory.server.protocol.shared.DirectoryBackedService; 035 import org.apache.directory.server.protocol.shared.transport.TcpTransport; 036 import org.apache.directory.server.protocol.shared.transport.Transport; 037 import org.apache.directory.server.protocol.shared.transport.UdpTransport; 038 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 039 import org.apache.directory.shared.ldap.name.DN; 040 import org.apache.mina.core.service.IoAcceptor; 041 import org.apache.mina.transport.socket.DatagramAcceptor; 042 import org.apache.mina.transport.socket.DatagramSessionConfig; 043 import org.apache.mina.transport.socket.SocketAcceptor; 044 import org.slf4j.Logger; 045 import org.slf4j.LoggerFactory; 046 047 048 /** 049 * Contains the configuration parameters for the Change Password protocol provider. 050 * 051 * @org.apache.xbean.XBean 052 * 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 * @version $Rev: 923757 $, $Date: 2010-03-16 15:33:59 +0100 (Tue, 16 Mar 2010) $ 055 */ 056 public class ChangePasswordServer extends DirectoryBackedService 057 { 058 private static final long serialVersionUID = 3509208713288140629L; 059 060 /** logger for this class */ 061 private static final Logger LOG = LoggerFactory.getLogger( ChangePasswordServer.class.getName() ); 062 063 /** The default change password principal name. */ 064 private static final String SERVICE_PRINCIPAL_DEFAULT = "kadmin/changepw@EXAMPLE.COM"; 065 066 /** The default change password realm. */ 067 private static final String REALM_DEFAULT = "EXAMPLE.COM"; 068 069 /** The default change password port. */ 070 private static final int DEFAULT_IP_PORT = 464; 071 072 /** The default encryption types. */ 073 public static final String[] ENCRYPTION_TYPES_DEFAULT = new String[] 074 { "des-cbc-md5" }; 075 076 /** The default changepw buffer size. */ 077 private static final long DEFAULT_ALLOWABLE_CLOCKSKEW = 5 * 60000; 078 079 /** The default empty addresses. */ 080 private static final boolean DEFAULT_EMPTY_ADDRESSES_ALLOWED = true; 081 082 /** The default change password password policy for password length. */ 083 public static final int DEFAULT_PASSWORD_LENGTH = 6; 084 085 /** The default change password password policy for category count. */ 086 public static final int DEFAULT_CATEGORY_COUNT = 3; 087 088 /** The default change password password policy for token size. */ 089 public static final int DEFAULT_TOKEN_SIZE = 3; 090 091 /** The default service PID. */ 092 private static final String SERVICE_PID_DEFAULT = "org.apache.directory.server.changepw"; 093 094 /** The default service name. */ 095 private static final String SERVICE_NAME_DEFAULT = "ApacheDS Change Password Service"; 096 097 /** The encryption types. */ 098 private EncryptionType[] encryptionTypes; 099 100 /** The primary realm. */ 101 private String primaryRealm = REALM_DEFAULT; 102 103 /** The service principal name. */ 104 private String servicePrincipal = SERVICE_PRINCIPAL_DEFAULT; 105 106 /** The allowable clock skew. */ 107 private long allowableClockSkew = DEFAULT_ALLOWABLE_CLOCKSKEW; 108 109 /** Whether empty addresses are allowed. */ 110 private boolean isEmptyAddressesAllowed = DEFAULT_EMPTY_ADDRESSES_ALLOWED; 111 112 /** The policy for password length. */ 113 private int policyPasswordLength; 114 115 /** The policy for category count. */ 116 private int policyCategoryCount; 117 118 /** The policy for token size. */ 119 private int policyTokenSize; 120 121 122 /** 123 * Creates a new instance of ChangePasswordConfiguration. 124 */ 125 public ChangePasswordServer() 126 { 127 super.setServiceName( SERVICE_NAME_DEFAULT ); 128 super.setServiceId( SERVICE_PID_DEFAULT ); 129 super.setSearchBaseDn( ServerDNConstants.USER_EXAMPLE_COM_DN ); 130 setTransports( new TcpTransport( DEFAULT_IP_PORT ), new UdpTransport( DEFAULT_IP_PORT ) ); 131 132 prepareEncryptionTypes(); 133 } 134 135 136 /** 137 * Returns the primary realm. 138 * 139 * @return The primary realm. 140 */ 141 public String getPrimaryRealm() 142 { 143 return primaryRealm; 144 } 145 146 147 /** 148 * @param primaryRealm The primaryRealm to set. 149 */ 150 public void setPrimaryRealm( String primaryRealm ) 151 { 152 this.primaryRealm = primaryRealm; 153 } 154 155 156 /** 157 * Returns the encryption types. 158 * 159 * @return The encryption types. 160 */ 161 public EncryptionType[] getEncryptionTypes() 162 { 163 return encryptionTypes; 164 } 165 166 167 /** 168 * @param encryptionTypes The encryptionTypes to set. 169 */ 170 public void setEncryptionTypes( EncryptionType[] encryptionTypes ) 171 { 172 this.encryptionTypes = encryptionTypes; 173 } 174 175 176 /** 177 * Returns the allowable clock skew. 178 * 179 * @return The allowable clock skew. 180 */ 181 public long getAllowableClockSkew() 182 { 183 return allowableClockSkew; 184 } 185 186 187 /** 188 * @param allowableClockSkew The allowableClockSkew to set. 189 */ 190 public void setAllowableClockSkew( long allowableClockSkew ) 191 { 192 this.allowableClockSkew = allowableClockSkew; 193 } 194 195 196 /** 197 * Returns the Change Password service principal. 198 * 199 * @return The Change Password service principal. 200 */ 201 public KerberosPrincipal getServicePrincipal() 202 { 203 return new KerberosPrincipal( servicePrincipal ); 204 } 205 206 207 /** 208 * @param servicePrincipal The Change Password service principal to set. 209 */ 210 public void setServicePrincipal( String servicePrincipal ) 211 { 212 this.servicePrincipal = servicePrincipal; 213 } 214 215 216 /** 217 * Returns whether empty addresses are allowed. 218 * 219 * @return Whether empty addresses are allowed. 220 */ 221 public boolean isEmptyAddressesAllowed() 222 { 223 return isEmptyAddressesAllowed; 224 } 225 226 227 /** 228 * @param isEmptyAddressesAllowed The isEmptyAddressesAllowed to set. 229 */ 230 public void setEmptyAddressesAllowed( boolean isEmptyAddressesAllowed ) 231 { 232 this.isEmptyAddressesAllowed = isEmptyAddressesAllowed; 233 } 234 235 236 /** 237 * Returns the password length. 238 * 239 * @return The password length. 240 */ 241 public int getPasswordLengthPolicy() 242 { 243 return policyPasswordLength; 244 } 245 246 247 /** 248 * Returns the category count. 249 * 250 * @return The category count. 251 */ 252 public int getCategoryCountPolicy() 253 { 254 return policyCategoryCount; 255 } 256 257 258 /** 259 * Returns the token size. 260 * 261 * @return The token size. 262 */ 263 public int getTokenSizePolicy() 264 { 265 return policyTokenSize; 266 } 267 268 269 /** 270 * @throws IOException if we cannot bind to the specified ports 271 */ 272 public void start() throws IOException, LdapInvalidDnException 273 { 274 PrincipalStore store = new DirectoryPrincipalStore( getDirectoryService(), new DN(this.getSearchBaseDn()) ); 275 276 if ( ( transports == null ) || ( transports.size() == 0 ) ) 277 { 278 // Default to UDP with port 464 279 // We have to create a DatagramAcceptor 280 UdpTransport transport = new UdpTransport( DEFAULT_IP_PORT ); 281 setTransports( transport ); 282 283 DatagramAcceptor acceptor = (DatagramAcceptor)transport.getAcceptor(); 284 285 // Set the handler 286 acceptor.setHandler( new ChangePasswordProtocolHandler( this, store ) ); 287 288 // Allow the port to be reused even if the socket is in TIME_WAIT state 289 ((DatagramSessionConfig)acceptor.getSessionConfig()).setReuseAddress( true ); 290 291 // Start the listener 292 acceptor.bind(); 293 } 294 else 295 { 296 for ( Transport transport:transports ) 297 { 298 IoAcceptor acceptor = transport.getAcceptor(); 299 300 // Disable the disconnection of the clients on unbind 301 acceptor.setCloseOnDeactivation( false ); 302 303 if ( transport instanceof UdpTransport ) 304 { 305 // Allow the port to be reused even if the socket is in TIME_WAIT state 306 ((DatagramSessionConfig)acceptor.getSessionConfig()).setReuseAddress( true ); 307 } 308 else 309 { 310 // Allow the port to be reused even if the socket is in TIME_WAIT state 311 ((SocketAcceptor)acceptor).setReuseAddress( true ); 312 313 // No Nagle's algorithm 314 ((SocketAcceptor)acceptor).getSessionConfig().setTcpNoDelay( true ); 315 } 316 317 // Set the handler 318 acceptor.setHandler( new ChangePasswordProtocolHandler( this, store ) ); 319 320 // Bind 321 acceptor.bind(); 322 } 323 } 324 325 LOG.info( "ChangePassword service started." ); 326 System.out.println( "ChangePassword service started." ); 327 } 328 329 330 public void stop() 331 { 332 for ( Transport transport :getTransports() ) 333 { 334 IoAcceptor acceptor = transport.getAcceptor(); 335 336 if ( acceptor != null ) 337 { 338 acceptor.dispose(); 339 } 340 } 341 342 LOG.info( "ChangePassword service stopped." ); 343 System.out.println( "ChangePassword service stopped." ); 344 } 345 346 347 private void prepareEncryptionTypes() 348 { 349 String[] encryptionTypeStrings = ENCRYPTION_TYPES_DEFAULT; 350 List<EncryptionType> encTypes = new ArrayList<EncryptionType>(); 351 352 for ( String enc : encryptionTypeStrings ) 353 { 354 for ( EncryptionType type : EncryptionType.getEncryptionTypes() ) 355 { 356 if ( type.toString().equalsIgnoreCase( enc ) ) 357 { 358 encTypes.add( type ); 359 } 360 } 361 } 362 363 encryptionTypes = encTypes.toArray( new EncryptionType[encTypes.size()] ); 364 } 365 366 367 /** 368 * Sets the policy's minimum?? password length. 369 * 370 * @param policyPasswordLength the minimum password length requirement 371 */ 372 public void setPolicyPasswordLength( int policyPasswordLength ) 373 { 374 this.policyPasswordLength = policyPasswordLength; 375 } 376 377 378 /** 379 * Sets the policy category count - what's this? 380 * 381 * @param policyCategoryCount the policy category count 382 */ 383 public void setPolicyCategoryCount( int policyCategoryCount ) 384 { 385 this.policyCategoryCount = policyCategoryCount; 386 } 387 388 389 /** 390 * Sets the policy token size - what's this? 391 * 392 * @param policyTokenSize the policy token size 393 */ 394 public void setPolicyTokenSize( int policyTokenSize ) 395 { 396 this.policyTokenSize = policyTokenSize; 397 } 398 399 400 /** 401 * @see Object#toString() 402 */ 403 public String toString() 404 { 405 StringBuilder sb = new StringBuilder(); 406 407 sb.append( "ChangePasswordServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' ); 408 409 if ( getTransports() != null ) 410 { 411 for ( Transport transport:getTransports() ) 412 { 413 sb.append( " " ).append( transport ).append( '\n' ); 414 } 415 } 416 417 return sb.toString(); 418 } 419 }