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 021 package org.apache.directory.server.changepw.protocol; 022 023 024 import java.io.UnsupportedEncodingException; 025 import java.net.InetAddress; 026 import java.net.InetSocketAddress; 027 import java.nio.ByteBuffer; 028 029 import javax.security.auth.kerberos.KerberosPrincipal; 030 031 import org.apache.directory.server.changepw.ChangePasswordServer; 032 import org.apache.directory.server.changepw.exceptions.ChangePasswordException; 033 import org.apache.directory.server.changepw.exceptions.ErrorType; 034 import org.apache.directory.server.changepw.messages.ChangePasswordErrorModifier; 035 import org.apache.directory.server.changepw.messages.ChangePasswordRequest; 036 import org.apache.directory.server.changepw.service.ChangePasswordContext; 037 import org.apache.directory.server.changepw.service.ChangePasswordService; 038 import org.apache.directory.server.i18n.I18n; 039 import org.apache.directory.server.kerberos.shared.exceptions.KerberosException; 040 import org.apache.directory.server.kerberos.shared.messages.ErrorMessage; 041 import org.apache.directory.server.kerberos.shared.messages.ErrorMessageModifier; 042 import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime; 043 import org.apache.directory.server.kerberos.shared.store.PrincipalStore; 044 import org.apache.mina.core.service.IoHandler; 045 import org.apache.mina.core.session.IdleStatus; 046 import org.apache.mina.core.session.IoSession; 047 import org.apache.mina.filter.codec.ProtocolCodecFilter; 048 import org.slf4j.Logger; 049 import org.slf4j.LoggerFactory; 050 051 052 /** 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 * @version $Rev: 901657 $, $Date: 2010-01-21 12:27:15 +0100 (Thu, 21 Jan 2010) $ 055 */ 056 public class ChangePasswordProtocolHandler implements IoHandler 057 { 058 private static final Logger log = LoggerFactory.getLogger( ChangePasswordProtocolHandler.class ); 059 060 private ChangePasswordServer config; 061 private PrincipalStore store; 062 private String contextKey = "context"; 063 064 065 /** 066 * Creates a new instance of ChangePasswordProtocolHandler. 067 * 068 * @param config 069 * @param store 070 */ 071 public ChangePasswordProtocolHandler( ChangePasswordServer config, PrincipalStore store ) 072 { 073 this.config = config; 074 this.store = store; 075 } 076 077 078 public void sessionCreated( IoSession session ) throws Exception 079 { 080 if ( log.isDebugEnabled() ) 081 { 082 log.debug( "{} CREATED: {}", session.getRemoteAddress(), session.getTransportMetadata() ); 083 } 084 085 if ( session.getTransportMetadata().isConnectionless() ) 086 { 087 session.getFilterChain().addFirst( "codec", 088 new ProtocolCodecFilter( ChangePasswordUdpProtocolCodecFactory.getInstance() ) ); 089 } 090 else 091 { 092 session.getFilterChain().addFirst( "codec", 093 new ProtocolCodecFilter( ChangePasswordTcpProtocolCodecFactory.getInstance() ) ); 094 } 095 } 096 097 098 public void sessionOpened( IoSession session ) 099 { 100 log.debug( "{} OPENED", session.getRemoteAddress() ); 101 } 102 103 104 public void sessionClosed( IoSession session ) 105 { 106 log.debug( "{} CLOSED", session.getRemoteAddress() ); 107 } 108 109 110 public void sessionIdle( IoSession session, IdleStatus status ) 111 { 112 log.debug( "{} IDLE ({})", session.getRemoteAddress(), status ); 113 } 114 115 116 public void exceptionCaught( IoSession session, Throwable cause ) 117 { 118 log.debug( session.getRemoteAddress() + " EXCEPTION", cause ); 119 session.close( true ); 120 } 121 122 123 public void messageReceived( IoSession session, Object message ) 124 { 125 log.debug( "{} RCVD: {}", session.getRemoteAddress(), message ); 126 127 InetAddress clientAddress = ( ( InetSocketAddress ) session.getRemoteAddress() ).getAddress(); 128 ChangePasswordRequest request = ( ChangePasswordRequest ) message; 129 130 try 131 { 132 ChangePasswordContext changepwContext = new ChangePasswordContext(); 133 changepwContext.setConfig( config ); 134 changepwContext.setStore( store ); 135 changepwContext.setClientAddress( clientAddress ); 136 changepwContext.setRequest( request ); 137 session.setAttribute( getContextKey(), changepwContext ); 138 139 ChangePasswordService.execute( session, changepwContext ); 140 141 session.write( changepwContext.getReply() ); 142 } 143 catch ( KerberosException ke ) 144 { 145 if ( log.isDebugEnabled() ) 146 { 147 log.warn( ke.getLocalizedMessage(), ke ); 148 } 149 else 150 { 151 log.warn( ke.getLocalizedMessage() ); 152 } 153 154 ErrorMessage errorMessage = getErrorMessage( config.getServicePrincipal(), ke ); 155 156 ChangePasswordErrorModifier modifier = new ChangePasswordErrorModifier(); 157 modifier.setErrorMessage( errorMessage ); 158 159 session.write( modifier.getChangePasswordError() ); 160 } 161 catch ( Exception e ) 162 { 163 log.error( I18n.err( I18n.ERR_152, e.getLocalizedMessage() ), e ); 164 165 session.write( getErrorMessage( config.getServicePrincipal(), new ChangePasswordException( 166 ErrorType.KRB5_KPASSWD_UNKNOWN_ERROR ) ) ); 167 } 168 } 169 170 171 public void messageSent( IoSession session, Object message ) 172 { 173 if ( log.isDebugEnabled() ) 174 { 175 log.debug( "{} SENT: {}", session.getRemoteAddress(), message ); 176 } 177 } 178 179 180 protected String getContextKey() 181 { 182 return ( this.contextKey ); 183 } 184 185 186 private ErrorMessage getErrorMessage( KerberosPrincipal principal, KerberosException exception ) 187 { 188 ErrorMessageModifier modifier = new ErrorMessageModifier(); 189 190 KerberosTime now = new KerberosTime(); 191 192 modifier.setErrorCode( exception.getErrorCode() ); 193 modifier.setExplanatoryText( exception.getLocalizedMessage() ); 194 modifier.setServerPrincipal( principal ); 195 modifier.setServerTime( now ); 196 modifier.setServerMicroSecond( 0 ); 197 modifier.setExplanatoryData( buildExplanatoryData( exception ) ); 198 199 return modifier.getErrorMessage(); 200 } 201 202 203 private byte[] buildExplanatoryData( KerberosException exception ) 204 { 205 short resultCode = ( short ) exception.getErrorCode(); 206 207 byte[] resultString = 208 { ( byte ) 0x00 }; 209 210 if ( exception.getExplanatoryData() == null || exception.getExplanatoryData().length == 0 ) 211 { 212 try 213 { 214 resultString = exception.getLocalizedMessage().getBytes( "UTF-8" ); 215 } 216 catch ( UnsupportedEncodingException uee ) 217 { 218 log.error( uee.getLocalizedMessage() ); 219 } 220 } 221 else 222 { 223 resultString = exception.getExplanatoryData(); 224 } 225 226 ByteBuffer byteBuffer = ByteBuffer.allocate( 256 ); 227 byteBuffer.putShort( resultCode ); 228 byteBuffer.put( resultString ); 229 230 byteBuffer.flip(); 231 byte[] explanatoryData = new byte[byteBuffer.remaining()]; 232 byteBuffer.get( explanatoryData, 0, explanatoryData.length ); 233 234 return explanatoryData; 235 } 236 }