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.shared.ldap.codec.bind;
021    
022    
023    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    
026    import org.apache.directory.shared.asn1.Asn1Object;
027    import org.apache.directory.shared.asn1.ber.tlv.TLV;
028    import org.apache.directory.shared.asn1.ber.tlv.Value;
029    import org.apache.directory.shared.asn1.codec.EncoderException;
030    import org.apache.directory.shared.i18n.I18n;
031    import org.apache.directory.shared.ldap.codec.LdapConstants;
032    import org.apache.directory.shared.ldap.util.StringTools;
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    
036    
037    /**
038     * A ldapObject which stores the SASL authentication of a BindRequest.
039     * 
040     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
041     * @version $Rev: 912399 $, $Date: 2010-02-21 21:52:31 +0100 (Sun, 21 Feb 2010) $, 
042     */
043    public class SaslCredentials extends LdapAuthentication
044    {
045        /** The logger */
046        private static Logger log = LoggerFactory.getLogger( SimpleAuthentication.class );
047    
048        /** Speedup for logs */
049        private static final boolean IS_DEBUG = log.isDebugEnabled();
050    
051        // ~ Instance fields
052        // ----------------------------------------------------------------------------
053    
054        /**
055         * Any mechanism defined in RFC 2222 : KERBEROS_V4, GSSAPI, SKEY, EXTERNAL
056         */
057        private String mechanism;
058        
059        /** The mechanism bytes */
060        private byte[] mechanismBytes;
061    
062        /** optional credentials of the user */
063        private byte[] credentials;
064    
065        /** The mechanism length */
066        private int mechanismLength;
067    
068        /** The credentials length */
069        private int credentialsLength;
070    
071    
072        /**
073         * @see Asn1Object#Asn1Object
074         */
075        public SaslCredentials()
076        {
077            super();
078        }
079    
080        // ~ Methods
081        // ------------------------------------------------------------------------------------
082    
083        /**
084         * Get the credentials
085         * 
086         * @return The credentials
087         */
088        public byte[] getCredentials()
089        {
090            if ( credentials == null )
091            {
092                return null;
093            }
094    
095            final byte[] copy = new byte[ credentials.length ];
096            System.arraycopy( credentials, 0, copy, 0, credentials.length );
097            return copy;
098        }
099    
100    
101        /**
102         * Set the credentials
103         * 
104         * @param credentials The credentials
105         */
106        public void setCredentials( byte[] credentials )
107        {
108            if ( credentials != null )
109            {
110                this.credentials = new byte[ credentials.length ];
111                System.arraycopy( credentials, 0, this.credentials, 0, credentials.length );
112            } else {
113                this.credentials = null;
114            }
115        }
116    
117    
118        /**
119         * Get the mechanism
120         * 
121         * @return The mechanism
122         */
123        public String getMechanism()
124        {
125    
126            return ( ( mechanism == null ) ? null : mechanism );
127        }
128    
129    
130        /**
131         * Set the mechanism
132         * 
133         * @param mechanism The mechanism
134         */
135        public void setMechanism( String mechanism )
136        {
137            this.mechanism = mechanism;
138        }
139    
140    
141        /**
142         * Compute the Sasl authentication length 
143         * 
144         * Sasl authentication :
145         * 
146         * 0xA3 L1 
147         *   0x04 L2 mechanism
148         *   [0x04 L3 credentials]
149         * 
150         * L2 = Length(mechanism)
151         * L3 = Length(credentials)
152         * L1 = L2 + L3
153         * 
154         * Length(Sasl authentication) = Length(0xA3) + Length(L1) + 
155         *                               Length(0x04) + Length(L2) + Length(mechanism)
156         *                               [+ Length(0x04) + Length(L3) + Length(credentials)]
157         */
158        public int computeLength()
159        {
160            mechanismBytes = StringTools.getBytesUtf8( mechanism );
161            mechanismLength = 1 + TLV.getNbBytes( mechanismBytes.length ) + mechanismBytes.length;
162            credentialsLength = 0;
163    
164            if ( credentials != null )
165            {
166                credentialsLength = 1 + TLV.getNbBytes( credentials.length ) + credentials.length;
167            }
168    
169            int saslLength = 1 + TLV.getNbBytes( mechanismLength + credentialsLength ) + mechanismLength
170                + credentialsLength;
171    
172            if ( IS_DEBUG )
173            {
174                log.debug( "SASL Authentication length : {}", Integer.valueOf( saslLength ) );
175            }
176    
177            return saslLength;
178        }
179    
180    
181        /**
182         * Encode the sasl authentication to a PDU. 
183         * 
184         * SimpleAuthentication : 
185         * 0xA3 L1 
186         *   0x04 L2 mechanism
187         *   [0x04 L3 credentials]
188         * 
189         * @param buffer The buffer where to put the PDU
190         * @return The PDU.
191         */
192        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
193        {
194            if ( buffer == null )
195            {
196                log.error( I18n.err( I18n.ERR_04023 ) );
197                throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
198            }
199    
200            try
201            {
202                // The saslAuthentication Tag
203                buffer.put( ( byte ) LdapConstants.BIND_REQUEST_SASL_TAG );
204    
205                buffer.put( TLV.getBytes( mechanismLength + credentialsLength ) );
206    
207                Value.encode( buffer, mechanism );
208    
209                if ( credentials != null )
210                {
211                    Value.encode( buffer, credentials );
212                }
213            }
214            catch ( BufferOverflowException boe )
215            {
216                log.error( I18n.err( I18n.ERR_04005 ) );
217                throw new EncoderException( I18n.err( I18n.ERR_04005)  );
218            }
219    
220            return buffer;
221        }
222    
223    
224        /**
225         * Get a String representation of a SaslCredential
226         * 
227         * @return A SaslCredential String
228         */
229        public String toString()
230        {
231            StringBuilder sb = new StringBuilder();
232    
233            sb.append( "        Sasl credentials\n" );
234            sb.append( "            Mechanism :'" ).append( mechanism ).append( '\'' );
235    
236            if ( credentials != null )
237            {
238                sb.append( "\n            Credentials :'" ).
239                    append( StringTools.dumpBytes(  credentials ) ).
240                    append( '\'' );
241            }
242    
243            return sb.toString();
244        }
245    }