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.core.interceptor.context;
021     
022    
023    import java.util.Collection;
024    import java.util.Collections;
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.apache.commons.lang.NotImplementedException;
030    import org.apache.directory.server.core.CoreSession;
031    import org.apache.directory.server.core.LdapPrincipal;
032    import org.apache.directory.server.core.ReferralHandlingMode;
033    import org.apache.directory.server.core.entry.ClonedServerEntry;
034    import org.apache.directory.server.i18n.I18n;
035    import org.apache.directory.shared.ldap.codec.MessageTypeEnum;
036    import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
037    import org.apache.directory.shared.ldap.entry.Modification;
038    import org.apache.directory.shared.ldap.entry.ServerEntry;
039    import org.apache.directory.shared.ldap.message.control.Control;
040    import org.apache.directory.shared.ldap.name.DN;
041    import org.apache.directory.shared.ldap.util.StringTools;
042    
043    
044    /**
045     * A Bind context used for Interceptors. It contains all the informations
046     * needed for the bind operation, and used by all the interceptors
047     *
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev$, $Date$
050     */
051    public class BindOperationContext implements OperationContext
052    {
053        /** The password */
054        private byte[] credentials;
055    
056        /** The SASL mechanism */
057        private String saslMechanism;
058        
059        /** The SASL identifier */
060        private String saslAuthId;
061        
062        private static final Control[] EMPTY_CONTROLS = new Control[0];
063    
064        /** The DN associated with the context */
065        private DN dn;
066        
067        /** The associated request's controls */
068        private Map<String, Control> requestControls = new HashMap<String, Control>(4);
069    
070        /** The associated response's controls */
071        private Map<String, Control> responseControls = new HashMap<String, Control>(4);
072    
073        /** A flag to tell that this is a collateral operation */
074        private boolean collateralOperation;
075        
076        /** the Interceptors bypassed by this operation */
077        private Collection<String> bypassed;
078        
079        private CoreSession session;
080        
081        private LdapPrincipal authorizedPrincipal;
082        
083        private OperationContext next;
084        
085        private OperationContext previous;
086    
087        private ReferralHandlingMode referralHandlingMode;
088    
089        private ClonedServerEntry entry;
090    
091        
092        /**
093         * Creates a new instance of BindOperationContext.
094         */
095        public BindOperationContext( CoreSession session )
096        {
097            this.session = session;
098        }
099    
100        
101        /**
102         * @return The authentication level. One of :
103         * <li>ANONYMOUS</li>
104         * <li>SIMPLE</li>
105         * <li>STRONG (sasl)</li>
106         * <li>UNAUTHENT</li>
107         * <li>INVALID</li>
108         */
109        public AuthenticationLevel getAuthenticationLevel()
110        {
111            if ( ( saslMechanism == null ) )
112            {
113                if ( dn.isEmpty() )
114                {
115                    if ( StringTools.isEmpty( credentials ) )
116                    {
117                        // Dn and Credentials are empty, this is an anonymous authent
118                        return AuthenticationLevel.NONE;
119                    }
120                    else
121                    {
122                        // If we have a password but no DN, this is invalid 
123                        return AuthenticationLevel.INVALID;
124                    }
125                }
126                else if ( StringTools.isEmpty( credentials ) )
127                {
128                    return AuthenticationLevel.UNAUTHENT;
129                }
130                else
131                {
132                    return AuthenticationLevel.SIMPLE;
133                }
134            }
135            else
136            {
137                return AuthenticationLevel.STRONG;
138            }
139        }
140        
141        
142        /**
143         * @return the SASL mechanisms
144         */
145        public String getSaslMechanism()
146        {
147            return saslMechanism;
148        }
149    
150        
151        public void setSaslMechanism( String saslMechanism )
152        {
153            this.saslMechanism = saslMechanism;
154        }
155    
156        
157        /**
158         * @return The principal password
159         */
160        public byte[] getCredentials()
161        {
162            return credentials;
163        }
164    
165        
166        public void setCredentials( byte[] credentials )
167        {
168            this.credentials = credentials;
169        }
170    
171        
172        /**
173         * @return The SASL authentication ID
174         */
175        public String getSaslAuthId()
176        {
177            return saslAuthId;
178        }
179    
180    
181        public void setSaslAuthId( String saslAuthId )
182        {
183            this.saslAuthId = saslAuthId;
184        }
185        
186        
187        public boolean isSaslBind()
188        {
189            return saslMechanism != null;
190        }
191        
192        
193        /**
194         * @return the operation name
195         */
196        public String getName()
197        {
198            return MessageTypeEnum.BIND_REQUEST.name();
199        }
200    
201    
202        /**
203         * @see Object#toString()
204         */
205        public String toString()
206        {
207            return "BindContext for DN '" + getDn().getName() + "', credentials <" +
208                ( credentials != null ? StringTools.dumpBytes( credentials ) : "" ) + ">" +
209                ( saslMechanism != null ? ", saslMechanism : <" + saslMechanism + ">" : "" ) +
210                ( saslAuthId != null ? ", saslAuthId <" + saslAuthId + ">" : "" );
211        }
212    
213    
214        public CoreSession getSession()
215        {
216            return session;
217        }
218        
219        
220        public void setSession( CoreSession session )
221        {
222            this.session = session;
223        }
224    
225    
226        /**
227         * Tells if the current operation is considered a side effect of the
228         * current context
229         */
230        public boolean isCollateralOperation()
231        {
232            return collateralOperation;
233        }
234    
235    
236        public void setCollateralOperation( boolean collateralOperation )
237        {
238            this.collateralOperation = collateralOperation;
239        }
240    
241    
242        /**
243         * @return The associated DN
244         */
245        public DN getDn()
246        {
247            return dn;
248        }
249    
250        
251        /**
252         * Set the context DN
253         *
254         * @param dn The DN to set
255         */
256        public void setDn( DN dn )
257        {
258            this.dn = dn;
259        }
260    
261        
262        public void addRequestControl( Control requestControl )
263        {
264            requestControls.put( requestControl.getOid(), requestControl );
265        }
266    
267        
268        public Control getRequestControl( String numericOid )
269        {
270            return requestControls.get( numericOid );
271        }
272    
273        
274        public boolean hasRequestControl( String numericOid )
275        {
276            return requestControls.containsKey( numericOid );
277        }
278    
279        
280        public boolean hasRequestControls()
281        {
282            return ! requestControls.isEmpty();
283        }
284    
285    
286        public void addResponseControl( Control responseControl )
287        {
288            responseControls.put( responseControl.getOid(), responseControl );
289        }
290    
291    
292        public Control getResponseControl( String numericOid )
293        {
294            return responseControls.get( numericOid );
295        }
296    
297    
298        public boolean hasResponseControl( String numericOid )
299        {
300            return responseControls.containsKey( numericOid );
301        }
302    
303    
304        public Control[] getResponseControls()
305        {
306            if ( responseControls.isEmpty() )
307            {
308                return EMPTY_CONTROLS;
309            }
310            
311            return responseControls.values().toArray( EMPTY_CONTROLS );
312        }
313    
314    
315        public boolean hasResponseControls()
316        {
317            return ! responseControls.isEmpty();
318        }
319    
320    
321        public int getResponseControlCount()
322        {
323            return responseControls.size();
324        }
325    
326    
327        public void addRequestControls( Control[] requestControls )
328        {
329            for ( Control c : requestControls )
330            {
331                this.requestControls.put( c.getOid(), c );
332            }
333        }
334    
335    
336        /**
337         * Gets the set of bypassed Interceptors.
338         *
339         * @return the set of bypassed Interceptors
340         */
341        public Collection<String> getByPassed()
342        {
343            if ( bypassed == null )
344            {
345                return Collections.emptyList();
346            }
347            
348            return Collections.unmodifiableCollection( bypassed );
349        }
350        
351        
352        /**
353         * Sets the set of bypassed Interceptors.
354         * 
355         * @param byPassed the set of bypassed Interceptors
356         */
357        public void setByPassed( Collection<String> byPassed )
358        {
359            this.bypassed = byPassed;
360        }
361    
362        
363        /**
364         * Checks to see if an Interceptor is bypassed for this operation.
365         *
366         * @param interceptorName the interceptorName of the Interceptor to check for bypass
367         * @return true if the Interceptor should be bypassed, false otherwise
368         */
369        public boolean isBypassed( String interceptorName )
370        {
371            return bypassed != null && bypassed.contains( interceptorName );
372        }
373    
374    
375        /**
376         * Checks to see if any Interceptors are bypassed by this operation.
377         *
378         * @return true if at least one bypass exists
379         */
380        public boolean hasBypass()
381        {
382            return bypassed != null && !bypassed.isEmpty();
383        }
384        
385        
386        public LookupOperationContext newLookupContext( DN dn )
387        {
388            return new LookupOperationContext( session, dn );
389        }
390    
391    
392        public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
393        {
394            return session.getDirectoryService().getOperationManager().lookup( opContext );
395        }
396    
397    
398        public ClonedServerEntry lookup( DN dn, Collection<String> byPassed ) throws Exception
399        {
400            LookupOperationContext opContext = newLookupContext( dn );
401            opContext.setByPassed( byPassed );
402            return session.getDirectoryService().getOperationManager().lookup( opContext );
403        }
404    
405    
406        public LdapPrincipal getEffectivePrincipal()
407        {
408            if ( authorizedPrincipal != null )
409            {
410                return authorizedPrincipal;
411            }
412            
413            return session.getEffectivePrincipal();
414        }
415        
416        
417        // -----------------------------------------------------------------------
418        // OperationContext Linked List Methods
419        // -----------------------------------------------------------------------
420        
421        
422        public boolean isFirstOperation()
423        {
424            return previous == null;
425        }
426        
427        
428        public OperationContext getFirstOperation()
429        {
430            if ( previous == null )
431            {
432                return this;
433            }
434            
435            return previous.getFirstOperation();
436        }
437        
438        
439        public OperationContext getLastOperation()
440        {
441            if ( next == null )
442            {
443                return this;
444            }
445            
446            return next.getLastOperation();
447        }
448        
449        
450        public OperationContext getNextOperation()
451        {
452            return next;
453        }
454        
455        
456        public OperationContext getPreviousOperation()
457        {
458            return previous;
459        }
460    
461    
462        public void add( ServerEntry entry, Collection<String> bypass ) throws Exception
463        {
464            throw new NotImplementedException();
465        }
466    
467    
468        public void delete( DN dn, Collection<String> bypass ) throws Exception
469        {
470            throw new NotImplementedException();
471        }
472    
473    
474        public void modify( DN dn, List<Modification> mods, Collection<String> bypass ) throws Exception
475        {
476            throw new NotImplementedException();
477        }
478    
479    
480        private void setup( AbstractOperationContext opContext )
481        {
482            opContext.setPreviousOperation( this );
483            next = opContext;
484            opContext.setByPassed( opContext.getByPassed() );
485            opContext.setAuthorizedPrincipal( authorizedPrincipal );
486        }
487        
488        
489        public boolean hasEntry( DN dn, Collection<String> byPassed ) throws Exception
490        {
491            EntryOperationContext opContext = new EntryOperationContext( session, dn );
492            setup( opContext );
493            opContext.setByPassed( byPassed );
494            return session.getDirectoryService().getOperationManager().hasEntry( opContext );
495        }
496    
497    
498        public ReferralHandlingMode getReferralHandlingMode()
499        {
500            return referralHandlingMode;
501        }
502    
503    
504        public void setReferralHandlingMode( ReferralHandlingMode referralHandlingMode )
505        {
506            this.referralHandlingMode = referralHandlingMode;
507        }
508    
509    
510        public ClonedServerEntry getEntry()
511        {
512            return entry;
513        }
514    
515    
516        public void setEntry( ClonedServerEntry entry )
517        {
518            this.entry = entry;
519        }
520    
521    
522        /**
523         * {@inheritDoc}
524         */
525        public void throwReferral()
526        {
527            throw new NotImplementedException( I18n.err( I18n.ERR_320 ) );
528        }
529        
530        
531        /**
532         * {@inheritDoc}
533         */
534        public boolean isReferralThrown()
535        {
536            throw new NotImplementedException( I18n.err( I18n.ERR_321 ) );
537        }
538    
539    
540        /**
541         * {@inheritDoc}
542         */
543        public void ignoreReferral()
544        {
545            throw new NotImplementedException( I18n.err( I18n.ERR_322 ) );
546        }
547    
548    
549        /**
550         * {@inheritDoc}
551         */
552        public boolean isReferralIgnored()
553        {
554            throw new NotImplementedException( I18n.err( I18n.ERR_323 ) );
555        }
556    }