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 }