View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
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   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
54   * @version $Rev: 590961 $, $Date: 2007-11-01 11:41:51 +0100 (Do, 01 Nov 2007) $
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       * Creates a new instance of ChangePasswordProtocolHandler.
67       *
68       * @param config
69       * @param store
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 }