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 */ 020package org.apache.directory.server.kerberos.protocol; 021 022 023import java.net.InetAddress; 024import java.net.InetSocketAddress; 025 026import javax.security.auth.kerberos.KerberosPrincipal; 027 028import org.apache.directory.api.ldap.model.constants.Loggers; 029import org.apache.directory.server.i18n.I18n; 030import org.apache.directory.server.kerberos.kdc.KdcServer; 031import org.apache.directory.server.kerberos.kdc.authentication.AuthenticationContext; 032import org.apache.directory.server.kerberos.kdc.authentication.AuthenticationService; 033import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingContext; 034import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingService; 035import org.apache.directory.server.kerberos.shared.store.PrincipalStore; 036import org.apache.directory.shared.kerberos.KerberosMessageType; 037import org.apache.directory.shared.kerberos.KerberosTime; 038import org.apache.directory.shared.kerberos.components.KdcReq; 039import org.apache.directory.shared.kerberos.components.PrincipalName; 040import org.apache.directory.shared.kerberos.exceptions.ErrorType; 041import org.apache.directory.shared.kerberos.exceptions.KerberosException; 042import org.apache.directory.shared.kerberos.messages.KrbError; 043import org.apache.mina.core.service.IoHandlerAdapter; 044import org.apache.mina.core.session.IdleStatus; 045import org.apache.mina.core.session.IoSession; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049 050/** 051 * The Kerberos protocol handler for MINA which handles requests for the authentication 052 * service and the ticket granting service of the KDC. 053 * 054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 055 */ 056public class KerberosProtocolHandler extends IoHandlerAdapter 057{ 058 /** The loggers for this class */ 059 private static final Logger LOG = LoggerFactory.getLogger( KerberosProtocolHandler.class ); 060 private static final Logger LOG_KRB = LoggerFactory.getLogger( Loggers.KERBEROS_LOG.getName() ); 061 062 /** The KDC server */ 063 private KdcServer kdcServer; 064 065 /** The principal Name store */ 066 private PrincipalStore store; 067 068 private static final String CONTEXT_KEY = "context"; 069 070 071 /** 072 * Creates a new instance of KerberosProtocolHandler. 073 * 074 * @param kdcServer The KdcServer instance 075 * @param store The Principal store 076 */ 077 public KerberosProtocolHandler( KdcServer kdcServer, PrincipalStore store ) 078 { 079 this.kdcServer = kdcServer; 080 this.store = store; 081 } 082 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override 088 public void sessionCreated( IoSession session ) throws Exception 089 { 090 if ( LOG.isDebugEnabled() ) 091 { 092 LOG.debug( "{} CREATED: {}", session.getRemoteAddress(), session.getTransportMetadata() ); 093 } 094 095 if ( LOG_KRB.isDebugEnabled() ) 096 { 097 LOG_KRB.debug( "{} CREATED: {}", session.getRemoteAddress(), session.getTransportMetadata() ); 098 } 099 } 100 101 102 /** 103 * {@inheritDoc} 104 */ 105 @Override 106 public void sessionOpened( IoSession session ) 107 { 108 if ( LOG.isDebugEnabled() ) 109 { 110 LOG.debug( "{} OPENED", session.getRemoteAddress() ); 111 } 112 113 if ( LOG_KRB.isDebugEnabled() ) 114 { 115 LOG_KRB.debug( "{} OPENED", session.getRemoteAddress() ); 116 } 117 } 118 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override 124 public void sessionClosed( IoSession session ) 125 { 126 if ( LOG.isDebugEnabled() ) 127 { 128 LOG.debug( "{} CLOSED", session.getRemoteAddress() ); 129 } 130 131 if ( LOG_KRB.isDebugEnabled() ) 132 { 133 LOG_KRB.debug( "{} CLOSED", session.getRemoteAddress() ); 134 } 135 } 136 137 138 /** 139 * {@inheritDoc} 140 */ 141 @Override 142 public void sessionIdle( IoSession session, IdleStatus status ) 143 { 144 if ( LOG.isDebugEnabled() ) 145 { 146 LOG.debug( "{} IDLE ({})", session.getRemoteAddress(), status ); 147 } 148 149 if ( LOG_KRB.isDebugEnabled() ) 150 { 151 LOG_KRB.debug( "{} IDLE ({})", session.getRemoteAddress(), status ); 152 } 153 } 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public void exceptionCaught( IoSession session, Throwable cause ) 161 { 162 LOG.error( "{} EXCEPTION", session.getRemoteAddress(), cause ); 163 LOG_KRB.error( "{} EXCEPTION", session.getRemoteAddress(), cause ); 164 session.closeNow(); 165 } 166 167 168 /** 169 * {@inheritDoc} 170 */ 171 @Override 172 public void messageReceived( IoSession session, Object message ) 173 { 174 if ( LOG.isDebugEnabled() ) 175 { 176 LOG.debug( "{} RCVD: {}", session.getRemoteAddress(), message ); 177 } 178 179 if ( LOG_KRB.isDebugEnabled() ) 180 { 181 LOG_KRB.debug( "{} RCVD: {}", session.getRemoteAddress(), message ); 182 } 183 184 InetAddress clientAddress = ( ( InetSocketAddress ) session.getRemoteAddress() ).getAddress(); 185 186 if ( !( message instanceof KdcReq ) ) 187 { 188 LOG.error( I18n.err( I18n.ERR_152, ErrorType.KRB_AP_ERR_BADDIRECTION ) ); 189 LOG_KRB.error( I18n.err( I18n.ERR_152, ErrorType.KRB_AP_ERR_BADDIRECTION ) ); 190 191 session.write( getErrorMessage( kdcServer.getConfig().getServicePrincipal(), new KerberosException( 192 ErrorType.KRB_AP_ERR_BADDIRECTION ) ) ); 193 return; 194 } 195 196 KdcReq request = ( KdcReq ) message; 197 198 KerberosMessageType messageType = request.getMessageType(); 199 200 try 201 { 202 switch ( messageType ) 203 { 204 case AS_REQ: 205 AuthenticationContext authContext = new AuthenticationContext(); 206 authContext.setConfig( kdcServer.getConfig() ); 207 authContext.setStore( store ); 208 209 if ( request.getKdcReqBody().getAddresses() != null ) 210 { 211 authContext.setClientAddress( clientAddress ); 212 } 213 214 authContext.setRequest( request ); 215 session.setAttribute( CONTEXT_KEY, authContext ); 216 217 AuthenticationService.execute( authContext ); 218 219 LOG_KRB.debug( "AuthenticationContext for AS_REQ : \n{}", authContext ); 220 221 session.write( authContext.getReply() ); 222 break; 223 224 case TGS_REQ: 225 TicketGrantingContext tgsContext = new TicketGrantingContext(); 226 tgsContext.setConfig( kdcServer.getConfig() ); 227 tgsContext.setReplayCache( kdcServer.getReplayCache() ); 228 tgsContext.setStore( store ); 229 tgsContext.setClientAddress( clientAddress ); 230 tgsContext.setRequest( request ); 231 session.setAttribute( CONTEXT_KEY, tgsContext ); 232 233 TicketGrantingService.execute( tgsContext ); 234 235 LOG_KRB.debug( "TGSContext for TGS_REQ : \n {}", tgsContext ); 236 237 session.write( tgsContext.getReply() ); 238 break; 239 240 case AS_REP: 241 case TGS_REP: 242 throw new KerberosException( ErrorType.KRB_AP_ERR_BADDIRECTION ); 243 244 default: 245 throw new KerberosException( ErrorType.KRB_AP_ERR_MSG_TYPE ); 246 } 247 } 248 catch ( KerberosException ke ) 249 { 250 String messageText = ke.getLocalizedMessage() + " (" + ke.getErrorCode() + ")"; 251 252 LOG.warn( messageText ); 253 LOG_KRB.warn( messageText ); 254 255 KrbError error = getErrorMessage( kdcServer.getConfig().getServicePrincipal(), ke ); 256 257 logErrorMessage( error ); 258 259 session.write( error ); 260 } 261 catch ( Exception e ) 262 { 263 LOG.error( I18n.err( I18n.ERR_152, e.getLocalizedMessage() ), e ); 264 LOG_KRB.error( I18n.err( I18n.ERR_152, e.getLocalizedMessage() ), e ); 265 266 session.write( getErrorMessage( kdcServer.getConfig().getServicePrincipal(), new KerberosException( 267 ErrorType.KDC_ERR_SVC_UNAVAILABLE ) ) ); 268 } 269 } 270 271 272 /** 273 * {@inheritDoc} 274 */ 275 @Override 276 public void messageSent( IoSession session, Object message ) 277 { 278 if ( LOG.isDebugEnabled() ) 279 { 280 LOG.debug( "{} SENT: {}", session.getRemoteAddress(), message ); 281 } 282 283 if ( LOG_KRB.isDebugEnabled() ) 284 { 285 LOG_KRB.debug( "{} SENT: {}", session.getRemoteAddress(), message ); 286 } 287 } 288 289 290 /** 291 * Construct an error message given some conditions 292 * 293 * @param principal The Kerberos Principal 294 * @param exception The Exception we've got 295 * @return The resulting KrbError 296 */ 297 protected KrbError getErrorMessage( KerberosPrincipal principal, KerberosException exception ) 298 { 299 KrbError krbError = new KrbError(); 300 301 KerberosTime now = new KerberosTime(); 302 303 krbError.setErrorCode( ErrorType.getTypeByValue( exception.getErrorCode() ) ); 304 krbError.setEText( exception.getLocalizedMessage() ); 305 krbError.setSName( new PrincipalName( principal ) ); 306 krbError.setRealm( principal.getRealm() ); 307 krbError.setSTime( now ); 308 krbError.setSusec( 0 ); 309 krbError.setEData( exception.getExplanatoryData() ); 310 311 return krbError; 312 } 313 314 315 /** 316 * Creates an explicit error message 317 * The error we've get 318 * 319 * @param error The Kerberos error to log 320 */ 321 protected void logErrorMessage( KrbError error ) 322 { 323 try 324 { 325 StringBuilder sb = new StringBuilder(); 326 327 sb.append( "Responding to request with error:" ); 328 sb.append( "\n\t" + "explanatory text: " + error.getEText() ); 329 sb.append( "\n\t" + "error code: " + error.getErrorCode() ); 330 sb.append( "\n\t" + "clientPrincipal: " + error.getCName() ).append( "@" ).append( error.getCRealm() ); 331 sb.append( "\n\t" + "client time: " + error.getCTime() ); 332 sb.append( "\n\t" + "serverPrincipal: " + error.getSName() ).append( "@" ).append( error.getRealm() ); 333 sb.append( "\n\t" + "server time: " + error.getSTime() ); 334 335 String message = sb.toString(); 336 337 LOG.debug( message ); 338 LOG_KRB.debug( message ); 339 } 340 catch ( Exception e ) 341 { 342 // This is a monitor. No exceptions should bubble up. 343 LOG.error( I18n.err( I18n.ERR_155 ), e ); 344 LOG_KRB.error( I18n.err( I18n.ERR_155 ), e ); 345 } 346 } 347 348 349 @Override 350 public void inputClosed( IoSession session ) 351 { 352 session.closeNow(); 353 } 354}