1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.directory.server.changepw.protocol;
22
23
24 import java.io.UnsupportedEncodingException;
25 import java.net.InetAddress;
26 import java.net.InetSocketAddress;
27 import java.nio.ByteBuffer;
28
29 import javax.security.auth.kerberos.KerberosPrincipal;
30
31 import org.apache.directory.server.changepw.ChangePasswordServer;
32 import org.apache.directory.server.changepw.exceptions.ChangePasswordException;
33 import org.apache.directory.server.changepw.exceptions.ErrorType;
34 import org.apache.directory.server.changepw.messages.ChangePasswordErrorModifier;
35 import org.apache.directory.server.changepw.messages.ChangePasswordRequest;
36 import org.apache.directory.server.changepw.service.ChangePasswordContext;
37 import org.apache.directory.server.changepw.service.ChangePasswordService;
38 import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
39 import org.apache.directory.server.kerberos.shared.messages.ErrorMessage;
40 import org.apache.directory.server.kerberos.shared.messages.ErrorMessageModifier;
41 import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
42 import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
43 import org.apache.mina.common.IdleStatus;
44 import org.apache.mina.common.IoHandler;
45 import org.apache.mina.common.IoSession;
46 import org.apache.mina.common.TransportType;
47 import org.apache.mina.filter.codec.ProtocolCodecFilter;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51
52
53
54
55
56 public class ChangePasswordProtocolHandler implements IoHandler
57 {
58 private static final Logger log = LoggerFactory.getLogger( ChangePasswordProtocolHandler.class );
59
60 private ChangePasswordServer config;
61 private PrincipalStore store;
62 private String contextKey = "context";
63
64
65
66
67
68
69
70
71 public ChangePasswordProtocolHandler( ChangePasswordServer config, PrincipalStore store )
72 {
73 this.config = config;
74 this.store = store;
75 }
76
77
78 public void sessionCreated( IoSession session ) throws Exception
79 {
80 if ( log.isDebugEnabled() )
81 {
82 log.debug( "{} CREATED: {}", session.getRemoteAddress(), session.getTransportType() );
83 }
84
85 if ( session.getTransportType() == TransportType.DATAGRAM )
86 {
87 session.getFilterChain().addFirst( "codec",
88 new ProtocolCodecFilter( ChangePasswordUdpProtocolCodecFactory.getInstance() ) );
89 }
90 else
91 {
92 session.getFilterChain().addFirst( "codec",
93 new ProtocolCodecFilter( ChangePasswordTcpProtocolCodecFactory.getInstance() ) );
94 }
95 }
96
97
98 public void sessionOpened( IoSession session )
99 {
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();
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.getMessage(), ke );
148 }
149 else
150 {
151 log.warn( ke.getMessage() );
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( "Unexpected exception: " + e.getMessage(), 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.getMessage() );
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.getMessage().getBytes( "UTF-8" );
215 }
216 catch ( UnsupportedEncodingException uee )
217 {
218 log.error( uee.getMessage() );
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 }