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.kerberos.protocol;
021    
022    
023    import java.net.InetAddress;
024    import java.net.InetSocketAddress;
025    
026    import javax.security.auth.kerberos.KerberosPrincipal;
027    
028    import org.apache.directory.server.i18n.I18n;
029    import org.apache.directory.server.kerberos.kdc.KdcServer;
030    import org.apache.directory.server.kerberos.kdc.authentication.AuthenticationContext;
031    import org.apache.directory.server.kerberos.kdc.authentication.AuthenticationService;
032    import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingContext;
033    import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingService;
034    import org.apache.directory.server.kerberos.shared.KerberosMessageType;
035    import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
036    import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
037    import org.apache.directory.server.kerberos.shared.messages.ErrorMessage;
038    import org.apache.directory.server.kerberos.shared.messages.ErrorMessageModifier;
039    import org.apache.directory.server.kerberos.shared.messages.KdcRequest;
040    import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
041    import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
042    import org.apache.mina.core.service.IoHandler;
043    import org.apache.mina.core.session.IdleStatus;
044    import org.apache.mina.core.session.IoSession;
045    import org.slf4j.Logger;
046    import org.slf4j.LoggerFactory;
047    
048    
049    /**
050     * The Kerberos protocol handler for MINA which handles requests for the authentication
051     * service and the ticket granting service of the KDC.
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 KerberosProtocolHandler implements IoHandler
057    {
058        private static final Logger log = LoggerFactory.getLogger( KerberosProtocolHandler.class );
059    
060        private KdcServer config;
061        private PrincipalStore store;
062        private static final String CONTEXT_KEY = "context";
063        
064    
065        /**
066         * Creates a new instance of KerberosProtocolHandler.
067         *
068         * @param config
069         * @param store
070         */
071        public KerberosProtocolHandler( KdcServer 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    
086    
087        public void sessionOpened( IoSession session )
088        {
089            if ( log.isDebugEnabled() )
090            {
091                log.debug( "{} OPENED", session.getRemoteAddress() );
092            }
093        }
094    
095    
096        public void sessionClosed( IoSession session )
097        {
098            if ( log.isDebugEnabled() )
099            {
100                log.debug( "{} CLOSED", session.getRemoteAddress() );
101            }
102        }
103    
104    
105        public void sessionIdle( IoSession session, IdleStatus status )
106        {
107            if ( log.isDebugEnabled() )
108            {
109                log.debug( "{} IDLE ({})", session.getRemoteAddress(), status );
110            }
111        }
112    
113    
114        public void exceptionCaught( IoSession session, Throwable cause )
115        {
116            log.error( session.getRemoteAddress() + " EXCEPTION", cause );
117            session.close( true );
118        }
119    
120    
121        public void messageReceived( IoSession session, Object message )
122        {
123            if ( log.isDebugEnabled() )
124            {
125                log.debug( "{} RCVD:  {}", session.getRemoteAddress(), message );
126            }
127    
128            InetAddress clientAddress = ( ( InetSocketAddress ) session.getRemoteAddress() ).getAddress();
129            KdcRequest request = ( KdcRequest ) message;
130    
131            KerberosMessageType messageType = request.getMessageType();
132    
133            try
134            {
135                switch ( messageType )
136                {
137                    case AS_REQ :
138                        AuthenticationContext authContext = new AuthenticationContext();
139                        authContext.setConfig( config );
140                        authContext.setStore( store );
141                        authContext.setClientAddress( clientAddress );
142                        authContext.setRequest( request );
143                        session.setAttribute( CONTEXT_KEY, authContext );
144    
145                        AuthenticationService.execute( authContext );
146    
147                        session.write( authContext.getReply() );
148                        break;
149    
150                    case TGS_REQ:
151                        TicketGrantingContext tgsContext = new TicketGrantingContext();
152                        tgsContext.setConfig( config );
153                        tgsContext.setStore( store );
154                        tgsContext.setClientAddress( clientAddress );
155                        tgsContext.setRequest( request );
156                        session.setAttribute( CONTEXT_KEY, tgsContext );
157    
158                        TicketGrantingService.execute( tgsContext );
159    
160                        session.write( tgsContext.getReply() );
161                        break;
162    
163                    case AS_REP:
164                    case TGS_REP:
165                        throw new KerberosException( ErrorType.KRB_AP_ERR_BADDIRECTION );
166    
167                    default:
168                        throw new KerberosException( ErrorType.KRB_AP_ERR_MSG_TYPE );
169                }
170            }
171            catch ( KerberosException ke )
172            {
173                String messageText = ke.getLocalizedMessage() + " (" + ke.getErrorCode() + ")";
174    
175                if ( log.isDebugEnabled() )
176                {
177                    log.warn( messageText, ke );
178                }
179                else
180                {
181                    log.warn( messageText );
182                }
183    
184                ErrorMessage error = getErrorMessage( config.getServicePrincipal(), ke );
185    
186                if ( log.isDebugEnabled() )
187                {
188                    logErrorMessage( error );
189                }
190    
191                session.write( error );
192            }
193            catch ( Exception e )
194            {
195            e.printStackTrace();
196                log.error( I18n.err( I18n.ERR_152, e.getLocalizedMessage() ), e );
197    
198                session.write( getErrorMessage( config.getServicePrincipal(), new KerberosException(
199                    ErrorType.KDC_ERR_SVC_UNAVAILABLE ) ) );
200            }
201        }
202    
203    
204        public void messageSent( IoSession session, Object message )
205        {
206            if ( log.isDebugEnabled() )
207            {
208                log.debug( "{} SENT:  {}", session.getRemoteAddress(), message );
209            }
210        }
211    
212    
213        protected ErrorMessage getErrorMessage( KerberosPrincipal principal, KerberosException exception )
214        {
215            ErrorMessageModifier modifier = new ErrorMessageModifier();
216    
217            KerberosTime now = new KerberosTime();
218    
219            modifier.setErrorCode( exception.getErrorCode() );
220            modifier.setExplanatoryText( exception.getLocalizedMessage() );
221            modifier.setServerPrincipal( principal );
222            modifier.setServerTime( now );
223            modifier.setServerMicroSecond( 0 );
224            modifier.setExplanatoryData( exception.getExplanatoryData() );
225    
226            return modifier.getErrorMessage();
227        }
228    
229    
230        protected void logErrorMessage( ErrorMessage error )
231        {
232            try
233            {
234                StringBuffer sb = new StringBuffer();
235    
236                sb.append( "Responding to request with error:" );
237                sb.append( "\n\t" + "explanatory text:      " + error.getExplanatoryText() );
238                sb.append( "\n\t" + "error code:            " + error.getErrorCode() );
239                sb.append( "\n\t" + "clientPrincipal:       " + error.getClientPrincipal() );
240                sb.append( "\n\t" + "client time:           " + error.getClientTime() );
241                sb.append( "\n\t" + "serverPrincipal:       " + error.getServerPrincipal() );
242                sb.append( "\n\t" + "server time:           " + error.getServerTime() );
243    
244                log.debug( sb.toString() );
245            }
246            catch ( Exception e )
247            {
248                // This is a monitor.  No exceptions should bubble up.
249                log.error( I18n.err( I18n.ERR_155 ), e );
250            }
251        }
252    }