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 }