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.server.kerberos.changepwd.messages;
021
022
023import java.nio.ByteBuffer;
024
025import org.apache.directory.api.asn1.DecoderException;
026import org.apache.directory.api.asn1.EncoderException;
027import org.apache.directory.api.asn1.ber.Asn1Decoder;
028import org.apache.directory.api.util.Strings;
029import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
030import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
031import org.apache.directory.shared.kerberos.codec.krbError.KrbErrorContainer;
032import org.apache.directory.shared.kerberos.messages.KrbError;
033
034
035/**
036 * 
037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038 */
039public class ChangePasswordError extends AbstractPasswordMessage
040{
041    private KrbError krbError;
042
043    private short krbErrorLen;
044    private short messageLength;
045
046    public ChangePasswordError( KrbError krbError )
047    {
048        this( PVNO, krbError );
049    }
050    
051    /**
052     * Creates a new instance of ChangePasswordError.
053     *
054     * @param versionNumber The version number 
055     * @param krbError The KRB-ERROR
056     */
057    public ChangePasswordError( short versionNumber, KrbError krbError )
058    {
059        super( versionNumber );
060
061        this.krbError = krbError;
062    }
063
064
065    /**
066     * Returns the {@link KrbError}.
067     *
068     * @return The {@link KrbError}.
069     */
070    public KrbError getKrbError()
071    {
072        return krbError;
073    }
074
075
076    @Override
077    public short computeLength()
078    {
079        krbErrorLen = ( short ) krbError.computeLength();
080        messageLength = ( short ) ( HEADER_LENGTH + krbErrorLen );
081        
082        return messageLength;
083    }
084
085    @Override
086    public ByteBuffer encode( ByteBuffer buf ) throws EncoderException
087    {
088        buf.putShort( messageLength );
089
090        buf.putShort( getVersionNumber() );
091
092        buf.putShort( ( short )0 ); // zero means, what follows is an error
093
094        krbError.encode( buf );
095        
096        return buf;
097    }
098
099    /**
100     * Decodes a {@link ByteBuffer} into a {@link ChangePasswordError}.
101     *
102     * @param buf The buffer containing the ChangePasswordError to decode
103     * @return The {@link ChangePasswordError}.
104     * @throws ChangePasswordException If the decoding failed
105     */
106    public static ChangePasswordError decode( ByteBuffer buf ) throws ChangePasswordException
107    {
108        short messageLength = buf.getShort();
109
110        short pvno = buf.getShort();
111
112        // AP_REQ length will be 0 for error messages
113        buf.getShort(); // authHeader length
114
115        int errorLength = messageLength - HEADER_LENGTH;
116
117        byte[] errorBytes = new byte[errorLength];
118
119        buf.get( errorBytes );
120        ByteBuffer errorBuffer = ByteBuffer.wrap( errorBytes );
121
122        KrbErrorContainer container = new KrbErrorContainer( errorBuffer );
123
124        try
125        {
126            Asn1Decoder.decode( errorBuffer, container );
127        }
128        catch( DecoderException e )
129        {
130            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_MALFORMED, e );
131        }
132        
133        KrbError errorMessage = container.getKrbError();
134
135        return new ChangePasswordError( pvno, errorMessage );
136    }
137
138    public ChangePasswdErrorType getResultCode()
139    {
140        ByteBuffer buf = ByteBuffer.wrap( krbError.getEData() );
141        
142        return ChangePasswdErrorType.getTypeByValue( buf.getShort() );
143    }
144    
145    public String getResultString()
146    {
147        byte[] edata = krbError.getEData();
148
149        // first two bytes contain the result code
150        return Strings.utf8ToString( edata, 2, edata.length - 2 );
151    }
152}