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 */
020package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
021
022
023import org.apache.directory.api.asn1.DecoderException;
024import org.apache.directory.api.asn1.util.Asn1Buffer;
025import org.apache.directory.api.i18n.I18n;
026import org.apache.directory.api.ldap.codec.api.AbstractExtendedOperationFactory;
027import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
028import org.apache.directory.api.ldap.codec.api.LdapApiService;
029import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequest;
030import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequestImpl;
031import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponse;
032import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponseImpl;
033import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
034import org.apache.directory.api.ldap.model.message.ExtendedResponse;
035import org.apache.directory.api.ldap.model.name.Dn;
036import org.apache.directory.api.util.Strings;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * An {@link ExtendedOperationFactory} for creating WhoAmI extended request response 
043 * pairs.
044 *
045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
046 */
047public class WhoAmIFactory extends AbstractExtendedOperationFactory
048{
049    /** logger */
050    private static final Logger LOG = LoggerFactory.getLogger( WhoAmIFactory.class );
051    
052    /**
053     * Creates a new instance of WhoAmIFactory.
054     *
055     * @param codec The codec for this factory.
056     */
057    public WhoAmIFactory( LdapApiService codec )
058    {
059        super( codec, WhoAmIRequest.EXTENSION_OID );
060    }
061
062
063    /**
064     * {@inheritDoc}
065     */
066    @Override
067    public WhoAmIRequest newRequest()
068    {
069        return new WhoAmIRequestImpl();
070    }
071
072
073    /**
074     * {@inheritDoc}
075     */
076    @Override
077    public WhoAmIRequest newRequest( byte[] value ) throws DecoderException
078    {
079        WhoAmIRequest whoAmIRequest = new WhoAmIRequestImpl();
080
081        if ( value != null )
082        {
083            decodeValue( whoAmIRequest, value );
084        }
085
086        return whoAmIRequest;
087    }
088
089
090    /**
091     * {@inheritDoc}
092     */
093    @Override
094    public WhoAmIResponse newResponse() throws DecoderException
095    {
096        return new WhoAmIResponseImpl();
097    }
098
099
100    /**
101     * {@inheritDoc}
102     */
103    @Override
104    public WhoAmIResponse newResponse( byte[] value ) throws DecoderException
105    {
106        WhoAmIResponse whoAmIResponse = new WhoAmIResponseImpl();
107
108        if ( value != null )
109        {
110            decodeValue( whoAmIResponse, value );
111        }
112
113        return whoAmIResponse;
114    }
115
116
117    /**
118     * {@inheritDoc}
119     */
120    @Override
121    public void encodeValue( Asn1Buffer buffer, ExtendedResponse extendedResponse )
122    {
123        if ( extendedResponse == null )
124        {
125            return;
126        }
127
128        // Reset the responseName, it should always be null for a WhoAMI extended operation
129        extendedResponse.setResponseName( null );
130        
131        // The authzID as a opaque byte array
132        byte[] authzid =  ( ( WhoAmIResponse ) extendedResponse ).getAuthzId();
133        
134        if ( !Strings.isEmpty( authzid ) )
135        {
136            buffer.put( authzid );
137        }
138    }
139    
140    
141    /**
142     * Decode a PDU which must contain a WhoAmIResponse extended operation.
143     * Note that the stream of bytes much contain a full PDU, not a partial one.
144     * 
145     * @param whoAmIResponse The WhoAmI extended response that will be feed
146     * @param data The bytes to be decoded
147     * @return a WhoAmIRequest object
148     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
149     */
150    public static WhoAmIResponse decode( WhoAmIResponse whoAmIResponse, byte[] data ) throws DecoderException
151    {
152        if ( Strings.isEmpty( data ) )
153        {
154            ( ( WhoAmIResponseImpl ) whoAmIResponse ).setAuthzId( null );
155        }
156        else
157        {
158            switch ( data.length )
159            {
160                case 0:
161                    // Error
162                case 1:
163                    // Error
164                    String msg = I18n.err( I18n.ERR_08226_AUTHZID_TOO_SHORT_MISSING_U_OR_DN );
165                    LOG.error( msg );
166                    throw new DecoderException( msg );
167
168                case 2 :
169                    if ( ( data[0] == 'u' ) && ( data[1] == ':' ) )
170                    {
171                        ( ( WhoAmIResponseImpl ) whoAmIResponse ).setAuthzId( data );
172                        ( ( WhoAmIResponseImpl ) whoAmIResponse ).setUserId( Strings.utf8ToString( data, 2, data.length - 2 ) );
173                    }
174                    else
175                    {
176                        msg = I18n.err( I18n.ERR_08227_AUTHZID_MUST_START_WITH_U_OR_DN, Strings.utf8ToString( data ) );
177                        LOG.error( msg );
178                        throw new DecoderException( msg );
179                    }
180                    
181                    break;
182                    
183                default :
184                    switch ( data[0] )
185                    {
186                        case 'u' :
187                            if ( data[1] == ':' )
188                            {
189                                ( ( WhoAmIResponseImpl ) whoAmIResponse ).setAuthzId( data );
190                                ( ( WhoAmIResponseImpl ) whoAmIResponse ).setUserId( Strings.utf8ToString( data, 2, data.length - 2 ) );
191                            }
192                            else
193                            {
194                                msg = I18n.err( I18n.ERR_08227_AUTHZID_MUST_START_WITH_U_OR_DN, Strings.utf8ToString( data ) );
195                                LOG.error( msg );
196                                throw new DecoderException( msg );
197                            }
198                            
199                            break;
200                            
201                        case 'd' :
202                            if ( ( data[1] == 'n' ) && ( data[2] == ':' ) )
203                            {
204                                // Check that the remaining bytes are a valid DN
205                                if ( Dn.isValid( Strings.utf8ToString( data, 3, data.length - 3 ) ) )
206                                {
207                                    ( ( WhoAmIResponseImpl ) whoAmIResponse ).setAuthzId( data );
208                                    
209                                    try
210                                    {
211                                        ( ( WhoAmIResponseImpl ) whoAmIResponse ).setDn( new Dn( Strings.utf8ToString( data, 3, data.length - 3 ) ) );
212                                    }
213                                    catch ( LdapInvalidDnException e )
214                                    {
215                                        // Should never happen
216                                    }
217                                }
218                                else
219                                {
220                                    msg = I18n.err( I18n.ERR_08227_AUTHZID_MUST_START_WITH_U_OR_DN, Strings.utf8ToString( data ) );
221                                    LOG.error( msg );
222                                    throw new DecoderException( msg );
223                                }
224                            }
225                            else
226                            {
227                                msg = I18n.err( I18n.ERR_08227_AUTHZID_MUST_START_WITH_U_OR_DN, Strings.utf8ToString( data ) );
228                                LOG.error( msg );
229                                throw new DecoderException( msg );
230                            }
231                            
232                            break;
233
234                        default :
235                            msg = I18n.err( I18n.ERR_08227_AUTHZID_MUST_START_WITH_U_OR_DN, Strings.utf8ToString( data ) );
236                            LOG.error( msg );
237                            throw new DecoderException( msg );
238                    }
239                    
240                    break;
241            }
242        }
243
244        return whoAmIResponse;
245    }
246
247    
248    /**
249     * {@inheritDoc}
250     */
251    @Override
252    public void decodeValue( ExtendedResponse extendedResponse, byte[] responseValue ) throws DecoderException
253    {
254        decode( ( WhoAmIResponse ) extendedResponse, responseValue );
255    }
256}