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.shared.ldap.extras.controls.ppolicy;
021
022
023import java.nio.ByteBuffer;
024
025import org.apache.directory.shared.asn1.Asn1Object;
026import org.apache.directory.shared.asn1.DecoderException;
027import org.apache.directory.shared.asn1.EncoderException;
028import org.apache.directory.shared.asn1.ber.Asn1Decoder;
029import org.apache.directory.shared.asn1.ber.tlv.TLV;
030import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
031import org.apache.directory.shared.asn1.ber.tlv.Value;
032import org.apache.directory.shared.i18n.I18n;
033import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
034import org.apache.directory.shared.ldap.codec.api.LdapApiService;
035
036
037/**
038 * PasswordPolicy decorator.
039 *
040 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
041 */
042public class PasswordPolicyDecorator extends ControlDecorator<PasswordPolicy> implements PasswordPolicy
043{
044    /** An instance of this decoder */
045    private static final Asn1Decoder decoder = new Asn1Decoder();
046    
047    // Storage for computed lengths
048    private int valueLength = 0;
049    private int ppolicySeqLength = 0;
050    private int warningLength = 0;
051    private int timeBeforeExpirationTagLength;
052    private int graceAuthNsRemainingTagLength;
053    
054    
055    public PasswordPolicyDecorator( LdapApiService codec )
056    {
057        super( codec, new PasswordPolicyImpl() );
058    }
059    
060    
061    public PasswordPolicyDecorator( LdapApiService codec, boolean hasResponse )
062    {
063        super( codec, new PasswordPolicyImpl( hasResponse ) );
064    }
065
066
067    public PasswordPolicyDecorator( LdapApiService codec, PasswordPolicy policy )
068    {
069        super( codec, policy );
070    }
071    
072
073    /**
074     * {@inheritDoc}
075     */
076    @Override
077    public void setValue( byte[] value )
078    {
079        if ( value == null || value.length == 0 )
080        {
081            setResponse( null );
082        }
083        
084        if ( value != null && ! hasResponse() )
085        {
086            setResponse( true );
087        }
088        
089        super.setValue( value );
090    }
091
092
093    @Override
094    public int computeLength()
095    {
096        // reset the length values
097        valueLength = 0;
098        ppolicySeqLength = 0;
099        warningLength = 0;
100        timeBeforeExpirationTagLength = 0;
101        graceAuthNsRemainingTagLength = 0;
102
103        if ( ! hasResponse() )
104        {
105            return 0;
106        }
107        
108        if ( getResponse().getTimeBeforeExpiration() >= 0 )
109        {
110            timeBeforeExpirationTagLength = TLV.getNbBytes( getResponse().getTimeBeforeExpiration() );
111            warningLength = 1 + TLV.getNbBytes( timeBeforeExpirationTagLength ) + timeBeforeExpirationTagLength;
112        }
113        else if ( getResponse().getGraceAuthNsRemaining() >= 0 )
114        {
115            graceAuthNsRemainingTagLength = TLV.getNbBytes( getResponse().getGraceAuthNsRemaining() );
116            warningLength = 1 + TLV.getNbBytes( graceAuthNsRemainingTagLength ) + graceAuthNsRemainingTagLength;
117        }
118
119        if ( warningLength != 0 )
120        {
121            ppolicySeqLength = 1 + TLV.getNbBytes( warningLength ) + warningLength;
122        }
123
124        if ( getResponse().getPasswordPolicyError() != null )
125        {
126            ppolicySeqLength += 1 + 1 + 1;
127        }
128        
129        if ( ppolicySeqLength > 0 )
130        {
131            valueLength = 1 + TLV.getNbBytes( ppolicySeqLength ) + ppolicySeqLength;
132        }
133
134        return valueLength;
135    }
136
137
138    @Override
139    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
140    {
141        if ( ! hasResponse() )
142        {
143            return buffer;
144        }
145        
146        if ( buffer == null )
147        {
148            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
149        }
150
151        if ( ( getResponse().getTimeBeforeExpiration() < 0 ) && ( getResponse().getGraceAuthNsRemaining() < 0 ) && ( 
152            getResponse().getPasswordPolicyError() == null ) )
153        {
154            return buffer;
155        }
156        else
157        {
158            // Encode the Sequence tag
159            buffer.put( UniversalTag.SEQUENCE.getValue() );
160            buffer.put( TLV.getBytes( ppolicySeqLength ) );
161
162            if ( warningLength > 0 )
163            {
164                // Encode the Warning tag
165                buffer.put( ( byte )PasswordPolicyTags.PPOLICY_WARNING_TAG.getValue() );
166                buffer.put( TLV.getBytes( warningLength ) );
167
168                if ( getResponse().getTimeBeforeExpiration() >= 0 )
169                {
170                    buffer.put( ( byte ) PasswordPolicyTags.TIME_BEFORE_EXPIRATION_TAG.getValue() );
171                    buffer.put( TLV.getBytes( timeBeforeExpirationTagLength ) );
172                    buffer.put( Value.getBytes( getResponse().getTimeBeforeExpiration() ) );
173                }
174                else if ( getResponse().getGraceAuthNsRemaining() >= 0 )
175                {
176                    buffer.put( ( byte ) PasswordPolicyTags.GRACE_AUTHNS_REMAINING_TAG.getValue() );
177                    buffer.put( TLV.getBytes( graceAuthNsRemainingTagLength ) );
178                    buffer.put( Value.getBytes( getResponse().getGraceAuthNsRemaining() ) );
179                }
180            }
181    
182            if ( getResponse().getPasswordPolicyError() != null )
183            {
184                buffer.put( (byte)PasswordPolicyTags.PPOLICY_ERROR_TAG.getValue() );
185                buffer.put( ( byte ) 0x01 );
186                buffer.put( Value.getBytes( getResponse().getPasswordPolicyError().getValue() ) );
187            }
188        }
189
190        return buffer;
191    }
192
193    
194    @Override
195    public String toString()
196    {
197        StringBuilder sb = new StringBuilder();
198
199        sb.append( "  PasswordPolicyResponse control :\n" );
200        sb.append( "   oid          : '" ).append( getOid() ).append( '\n' );
201        
202        if ( hasResponse() && getResponse().getTimeBeforeExpiration() >= 0 )
203        {
204            sb.append( "   timeBeforeExpiration          : '" ).append( getResponse().getTimeBeforeExpiration() ).append( '\n' );
205        }
206        else if ( hasResponse() && getResponse().getGraceAuthNsRemaining() >= 0 )
207        {
208            sb.append( "   graceAuthNsRemaining          : '" ).append( getResponse().getGraceAuthNsRemaining() ).append( '\n' );
209        }
210
211        if ( hasResponse() && getResponse().getPasswordPolicyError() != null )
212        {
213            sb.append( "   ppolicyError          : '" ).append( getResponse().getPasswordPolicyError().toString() ).append( '\n' );
214        }
215
216        return sb.toString();
217    }
218
219
220    /**
221     * {@inheritDoc}
222     */
223    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
224    {
225        if ( ! hasResponse() )
226        {
227            return this;
228        }
229        
230        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
231        PasswordPolicyContainer container = new PasswordPolicyContainer( getCodecService(), this );
232        decoder.decode( bb, container );
233        return this;
234    }
235
236
237    /**
238     * 
239     * {@inheritDoc}
240     */
241    public boolean hasResponse()
242    {
243        return getDecorated().hasResponse();
244    }
245    
246    
247    /**
248     * 
249     * {@inheritDoc}
250     */
251    public void setResponse( PasswordPolicyResponse response )
252    {
253        getDecorated().setResponse( response );
254    }
255
256    
257    /**
258     * 
259     * {@inheritDoc}
260     */
261    public PasswordPolicyResponse setResponse( boolean hasResponse )
262    {
263        return getDecorated().setResponse( hasResponse );
264    }
265    
266
267    /**
268     * 
269     * {@inheritDoc}
270     */
271    public PasswordPolicyResponse getResponse()
272    {
273        return getDecorated().getResponse();
274    }
275}