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;
21  
22  
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.concurrent.ConcurrentHashMap;
27  
28  import org.apache.directory.server.core.CoreSession;
29  import org.apache.directory.shared.ldap.message.AbandonableRequest;
30  import org.apache.directory.shared.ldap.message.BindStatus;
31  import org.apache.mina.common.IoSession;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  
36  /**
37   * An object representing an LdapSession.  Any connection established with the
38   * LDAP server forms a session.
39   *
40   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
41   * @version $Rev$, $Date$
42   */
43  public class LdapSession
44  {
45      /** The logger */
46      private static final Logger LOG = LoggerFactory.getLogger( LdapSession.class );
47      
48      /** A speedup for logs */
49      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
50  
51      
52      private static final AbandonableRequest[] EMPTY_ABANDONABLES = new AbandonableRequest[0]; 
53      
54      private final String outstandingLock;
55      
56      /**
57       * The associated IoSession. Usually, a LdapSession is established
58       * at the user request, which means we have a IoSession.
59       */
60      private final IoSession ioSession;
61      
62      /** The CoreSession */
63      private CoreSession coreSession;
64      
65      /** A reference on the LdapService instance */
66      private LdapService ldapService;
67      
68      
69      private Map<Integer, AbandonableRequest> outstandingRequests;
70      
71      
72      /** The current Bind status */
73      private BindStatus bindStatus;
74      
75      /** The current mechanism used to authenticate the user */
76      private String currentMechanism;
77      
78      
79      /**
80       * A Map containing Objects used during the SASL negotiation
81       */
82      private Map<String, Object> saslProperties;
83      
84   
85      /**
86       * Creates a new instance of LdapSession associated with the underlying
87       * connection (MINA IoSession) to the server.
88       *
89       * @param ioSession the MINA session associated this LdapSession
90       */
91      public LdapSession( IoSession ioSession )
92      {
93          this.ioSession = ioSession;
94          outstandingLock = "OutstandingRequestLock: " + ioSession.toString();
95          outstandingRequests = new ConcurrentHashMap<Integer, AbandonableRequest>();
96          bindStatus = BindStatus.ANONYMOUS;
97          saslProperties = new HashMap<String, Object>();
98      }
99      
100     
101     /**
102      * Check if the session is authenticated. There are two conditions for
103      * a session to be authenticated :<br>
104      * - the coreSession must not be null<br>
105      * - and the state should be Authenticated.
106      * 
107      * @return <code>true</code> if the session is not anonymous
108      */
109     public boolean isAuthenticated()
110     {
111         return ( coreSession != null ) && bindStatus == BindStatus.AUTHENTICATED;
112     }
113     
114     
115     /**
116      * Check if the session is authenticated. There are two conditions for
117      * a session to be authenticated :<br>
118      * - it has to exist<br>
119      * - and the session should not be anonymous.
120      * 
121      * @return <code>true</code> if the session is not anonymous
122      */
123     public boolean isAnonymous()
124     {
125         return bindStatus == BindStatus.ANONYMOUS;
126     }
127     
128     
129     /**
130      * Check if the session is in the middle of a SASL negotiation.
131      * 
132      * @return <code>true</code> if the session is in AuthPending state
133      */
134     public boolean isAuthPending()
135     {
136         return bindStatus == BindStatus.AUTH_PENDING;
137     }
138     
139     
140     /**
141      * Gets the MINA IoSession associated with this LdapSession.
142      *
143      * @return the MINA IoSession 
144      */
145     public IoSession getIoSession()
146     {
147         return ioSession;
148     }
149     
150     
151     /**
152      * Gets the logical core DirectoryService session associated with this 
153      * LdapSession.
154      *
155      * @return the logical core DirectoryService session
156      */
157     public CoreSession getCoreSession()
158     {
159         return coreSession;
160     }
161     
162     
163     /**
164      * Sets the logical core DirectoryService session. 
165      * 
166      * @param coreSession the logical core DirectoryService session
167      */
168     public void setCoreSession( CoreSession coreSession )
169     {
170         this.coreSession = coreSession;
171     }
172     
173     
174     /**
175      * Abandons all outstanding requests associated with this session.
176      */
177     public void abandonAllOutstandingRequests()
178     {
179         synchronized ( outstandingLock )
180         {
181             AbandonableRequest[] abandonables = outstandingRequests.values().toArray( EMPTY_ABANDONABLES );
182             
183             for ( AbandonableRequest abandonable : abandonables )
184             {
185                 abandonOutstandingRequest( abandonable.getMessageId() );
186             }
187         }
188     }
189     
190 
191     /**
192      * Abandons a specific request by messageId.
193      */
194     public AbandonableRequest abandonOutstandingRequest( Integer messageId )
195     {
196         AbandonableRequest request = null;
197         
198         synchronized ( outstandingLock )
199         {
200             request = outstandingRequests.remove( messageId );
201         }
202 
203         if ( request == null )
204         {
205             LOG.warn( "AbandonableRequest with messageId {} not found in outstandingRequests.", messageId );
206             return null;
207         }
208         
209         if ( request.isAbandoned() )
210         {
211             LOG.warn( "AbandonableRequest with messageId {} has already been abandoned", messageId );
212             return request;
213         }
214 
215         request.abandon();
216         
217         if ( IS_DEBUG )
218         {
219             LOG.debug( "AbandonRequest on AbandonableRequest wth messageId {} was successful.", messageId );
220         }
221         
222         return request;
223     }
224 
225     
226     /**
227      * Registers an outstanding request which can be abandoned later.
228      *
229      * @param request an outstanding request that can be abandoned
230      */
231     public void registerOutstandingRequest( AbandonableRequest request )
232     {
233         synchronized( outstandingLock )
234         {
235             outstandingRequests.put( request.getMessageId(), request );
236         }
237     }
238 
239     
240     /**
241      * Unregisters an outstanding request.
242      *
243      * @param request the request to unregister
244      */
245     public void unregisterOutstandingRequest( AbandonableRequest request )
246     {
247         synchronized( outstandingLock )
248         {
249             outstandingRequests.remove( request.getMessageId() );
250         }
251     }
252     
253     
254     public Map<Integer, AbandonableRequest> getOutstandingRequests()
255     {
256         synchronized( outstandingLock )
257         {
258             return Collections.unmodifiableMap( outstandingRequests );
259         }
260     }
261 
262 
263     /**
264      * @return the current bind status for this session
265      */
266     public BindStatus getBindStatus()
267     {
268         return bindStatus;
269     }
270     
271     
272     /**
273      * Set the current BindStatus to authentication pending
274      */
275     public void setAuthPending()
276     {
277         bindStatus = BindStatus.AUTH_PENDING;
278     }
279 
280 
281     /**
282      * Set the current BindStatus to Anonymous
283      */
284     public void setAnonymous()
285     {
286         bindStatus = BindStatus.ANONYMOUS;
287     }
288     
289 
290     /**
291      * Set the current BindStatus to authenticated
292      */
293     public void setAuthenticated()
294     {
295         bindStatus = BindStatus.AUTHENTICATED;
296     }
297     
298     
299     /**
300      * Get the mechanism selected by a user during a SASL Bind negotiation.
301      * 
302      * @return The used mechanism, if any
303      */
304     public String getCurrentMechanism()
305     {
306         return currentMechanism;
307     }
308 
309 
310     /**
311      * Add a Sasl property and value
312      * 
313      * @param property the property to add
314      * @param value the value for this property
315      */
316     public void putSaslProperty( String property, Object value )
317     {
318         saslProperties.put( property, value );
319     }
320     
321     
322     /**
323      * Get a Sasl property's value
324      * 
325      * @param property the property to get
326      * @return the associated value, or null if we don't have such a property
327      */
328     public Object getSaslProperty( String property )
329     {
330         return saslProperties.get( property );
331     }
332     
333     
334     /**
335      * Clear all the Sasl values stored into the Map
336      */
337     public void clearSaslProperties()
338     {
339         saslProperties.clear();
340     }
341     
342     
343     /**
344      * Remove a property from the SaslProperty map
345      *
346      * @param property the property to remove
347      */
348     public void removeSaslProperty( String property )
349     {
350         saslProperties.remove( property );
351     }
352 
353 
354     /**
355      *  @return The LdapService reference
356      */
357     public LdapService getLdapServer()
358     {
359         return ldapService;
360     }
361 
362 
363     /**
364      * Store a reference on the LdapService intance
365      *
366      * @param ldapService the LdapService instance
367      */
368     public void setLdapServer( LdapService ldapService )
369     {
370         this.ldapService = ldapService;
371     }
372 }