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  package org.apache.directory.server.ldap.handlers;
21  
22  
23  import org.apache.directory.server.core.CoreSession;
24  import org.apache.directory.server.ldap.LdapService;
25  import org.apache.directory.server.ldap.LdapSession;
26  import org.apache.directory.server.ldap.handlers.extended.StartTlsHandler;
27  import org.apache.directory.shared.ldap.message.AbandonRequest;
28  import org.apache.directory.shared.ldap.message.BindRequest;
29  import org.apache.directory.shared.ldap.message.ExtendedRequest;
30  import org.apache.directory.shared.ldap.message.LdapResult;
31  import org.apache.directory.shared.ldap.message.Request;
32  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
33  import org.apache.directory.shared.ldap.message.ResultResponse;
34  import org.apache.directory.shared.ldap.message.ResultResponseRequest;
35  import org.apache.mina.common.IoFilterChain;
36  import org.apache.mina.common.IoSession;
37  import org.apache.mina.handler.demux.MessageHandler;
38  
39  
40  /**
41   * A base class for all LDAP request handlers.
42   *
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   * @version $Rev: 541827 $
45   */
46  public abstract class LdapRequestHandler<T extends Request> implements MessageHandler<T>
47  {
48  	/** The reference on the Ldap server instance */
49      protected LdapService ldapService;
50  
51  
52      /**
53       * @return The associated ldap server instance
54       */
55      public final LdapService getLdapServer()
56      {
57          return ldapService;
58      }
59  
60  
61      /**
62       * Associates a Ldap server instance to the message handler
63       * @param ldapService the associated ldap server instance
64       */
65      public final void setLdapServer( LdapService ldapService )
66      {
67          this.ldapService = ldapService;
68      }
69      
70      
71      /**
72       * Checks to see if confidentiality requirements are met.  If the 
73       * LdapService requires confidentiality and the SSLFilter is engaged
74       * this will return true.  If confidentiality is not required this 
75       * will return true.  If confidentially is required and the SSLFilter
76       * is not engaged in the IoFilterChain this will return false.
77       * 
78       * This method is used by handlers to determine whether to send back
79       * {@link ResultCodeEnum#CONFIDENTIALITY_REQUIRED} error responses back
80       * to clients.
81       * 
82       * @param session the MINA IoSession to check for TLS security
83       * @return true if confidentiality requirement is met, false otherwise
84       */
85      public final boolean isConfidentialityRequirementSatisfied( IoSession session )
86      {
87         
88         if ( ! ldapService.isConfidentialityRequired() )
89         {
90             return true;
91         }
92         
93          IoFilterChain chain = session.getFilterChain();
94          return chain.contains( "sslFilter" );
95      }
96  
97      
98      public void rejectWithoutConfidentiality( IoSession session, ResultResponse resp ) 
99      {
100         LdapResult result = resp.getLdapResult();
101         result.setResultCode( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
102         result.setErrorMessage( "Confidentiality (TLS secured connection) is required." );
103         session.write( resp );
104         return;
105     }
106 
107 
108     /**
109      * Handle a LDAP message received during a session.
110      * 
111      * @param session the user session created when the user first connected
112      * to the server
113      * @param message the LDAP message received. Can be any of the LDAP Request
114      * @throws Exception the thrown exception if something went wrong during 
115      * the message processing
116      */
117     public final void messageReceived( IoSession session, T message ) throws Exception
118     {
119         LdapSession ldapSession = ldapService.getLdapSessionManager().getLdapSession( session );
120         
121         // TODO - session you get from LdapService should have the ldapService 
122         // member already set no?  Should remove these lines where ever they
123         // may be if that's the case.
124         ldapSession.setLdapServer( ldapService );
125         
126         // protect against insecure conns when confidentiality is required 
127         if ( ! isConfidentialityRequirementSatisfied( session ) )
128         {
129             if ( message instanceof ExtendedRequest )
130             {
131                 // Reject all extended operations except StartTls  
132                 ExtendedRequest req = ( ExtendedRequest ) message;
133                 if ( ! req.getID().equals( StartTlsHandler.EXTENSION_OID ) )
134                 {
135                     rejectWithoutConfidentiality( session, req.getResultResponse() );
136                     return;
137                 }
138                 
139                 // Allow StartTls extended operations to go through
140             }
141             else if ( message instanceof ResultResponseRequest )
142             {
143                 // Reject all other operations that have a result response  
144                 rejectWithoutConfidentiality( session, ( ( ResultResponseRequest ) message ).getResultResponse() );
145                 return;
146             }
147             else // Just return from unbind, and abandon immediately
148             {
149                 return;
150             }
151         }
152 
153         // We should check that the server allows anonymous requests
154         // only if it's not a BindRequest
155         if ( message instanceof BindRequest )
156         {
157         	handle( ldapSession, message );
158         }
159         else
160         {
161             CoreSession coreSession = null;
162             
163             /*
164              * All requests except bind automatically presume the authentication 
165              * is anonymous if the session has not been authenticated.  Hence a
166              * default bind is presumed as the anonymous identity.
167              */
168             if ( ldapSession.isAuthenticated() )
169             {
170                 coreSession = ldapSession.getCoreSession();
171                 handle( ldapSession, message );
172                 return;
173             }
174             
175             coreSession = getLdapServer().getDirectoryService().getSession();
176             ldapSession.setCoreSession( coreSession );
177 
178             if ( message instanceof AbandonRequest )
179             {
180                 return;
181             }
182             
183             handle( ldapSession, message );
184             return;
185         }
186     }
187 
188     
189     /**
190      * Handle a Ldap message associated with a session
191      * 
192      * @param session The associated session
193      * @param message The message we have to handle
194      * @throws Exception If there is an error during the processing of this message
195      */
196     public abstract void handle( LdapSession session, T message ) throws Exception;
197 }