View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.kerberos.credentials.cache;
21  
22  
23  import java.io.DataOutputStream;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  import java.util.List;
27  
28  import org.apache.directory.api.util.Strings;
29  import org.apache.directory.shared.kerberos.KerberosTime;
30  import org.apache.directory.shared.kerberos.codec.KerberosEncoder;
31  import org.apache.directory.shared.kerberos.components.AuthorizationData;
32  import org.apache.directory.shared.kerberos.components.AuthorizationDataEntry;
33  import org.apache.directory.shared.kerberos.components.EncryptionKey;
34  import org.apache.directory.shared.kerberos.components.HostAddress;
35  import org.apache.directory.shared.kerberos.components.HostAddresses;
36  import org.apache.directory.shared.kerberos.components.PrincipalName;
37  import org.apache.directory.shared.kerberos.messages.Ticket;
38  
39  
40  /**
41   * Writing credentials cache according to FCC format by reference the following
42   * https://www.gnu.org/software/shishi/manual/html_node/The-Credential-Cache-Binary-File-Format.html
43   * 
44   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
45   */
46  public class CacheOutputStream extends DataOutputStream
47  {
48  
49      public CacheOutputStream( OutputStream out )
50      {
51          super( out );
52      }
53  
54  
55      public void write( CredentialsCache credCache ) throws IOException
56      {
57          /**
58           * Currently we always write using this version to limit the test effort.
59           * This version seems to be the easiest to be compatible with MIT tools.
60           * In future we might allow to specify the format version to write if necessary. 
61           */
62          int writeVersion = CredentialsCacheConstants.FCC_FVNO_3;
63  
64          writeVersion( writeVersion );
65  
66          if ( writeVersion == CredentialsCacheConstants.FCC_FVNO_4 )
67          {
68              writeTags( credCache.getTags() );
69          }
70  
71          writePrincipal( credCache.getPrimaryPrincipalName(), writeVersion );
72  
73          List<Credentials> credentialsList = credCache.getCredsList();
74          if ( credentialsList != null )
75          {
76              for ( Credentials cred : credentialsList )
77              {
78                  writeCredentials( cred, writeVersion );
79              }
80          }
81      }
82  
83  
84      private void writeVersion( int version ) throws IOException
85      {
86          writeShort( version );
87      }
88  
89  
90      private void writeTags( List<Tag> tags ) throws IOException
91      {
92          int length = 0;
93          if ( tags != null )
94          {
95              for ( Tag tag : tags )
96              {
97                  if ( tag.tag != CredentialsCacheConstants.FCC_TAG_DELTATIME )
98                  {
99                      continue;
100                 }
101                 length += tag.length;
102             }
103         }
104 
105         writeShort( length );
106 
107         if ( tags != null )
108         {
109             for ( Tag tag : tags )
110             {
111                 if ( tag.tag != CredentialsCacheConstants.FCC_TAG_DELTATIME )
112                 {
113                     continue;
114                 }
115                 writeTag( tag );
116             }
117         }
118     }
119 
120 
121     private void writeTag( Tag tag ) throws IOException
122     {
123         writeShort( tag.tag );
124         writeShort( tag.length );
125         writeInt( tag.time );
126         writeInt( tag.usec );
127     }
128 
129 
130     private void writePrincipal( PrincipalName pname, int version ) throws IOException
131     {
132         int num = pname.getNames().size();
133 
134         if ( version != CredentialsCacheConstants.FCC_FVNO_1 )
135         {
136             writeInt( pname.getNameType().getValue() );
137         }
138         else
139         {
140             num++;
141         }
142 
143         writeInt( num );
144 
145         if ( pname.getRealm() != null )
146         {
147             byte[] realmBytes = null;
148             realmBytes = Strings.getBytesUtf8( pname.getRealm() );
149             writeInt( realmBytes.length );
150             write( realmBytes );
151         }
152         else
153         {
154             writeInt( 0 );
155         }
156 
157         byte[] bytes = null;
158         for ( int i = 0; i < pname.getNames().size(); i++ )
159         {
160             bytes = Strings.getBytesUtf8( pname.getNames().get( i ) );
161             writeInt( bytes.length );
162             write( bytes );
163         }
164     }
165 
166 
167     private void writeCredentials( Credentials creds, int version ) throws IOException
168     {
169         writePrincipal( creds.getClientName(), version );
170         writePrincipal( creds.getServerName(), version );
171         writeKey( creds.getKey(), version );
172 
173         writeKerberosTime( creds.getAuthTime() );
174         writeKerberosTime( creds.getStartTime() );
175         writeKerberosTime( creds.getEndTime() );
176         writeKerberosTime( creds.getRenewTill() );
177 
178         writeByte( creds.isEncInSKey() ? 1 : 0 );
179 
180         writeInt( creds.getFlags().getIntValue() );
181 
182         writeAddrs( creds.getClientAddresses() );
183         writeAuth( creds.getAuthzData() );
184 
185         writeTicket( creds.getTicket() );
186         writeTicket( creds.getSecondTicket() );
187     }
188 
189 
190     private void writeKerberosTime( KerberosTime ktime ) throws IOException
191     {
192         int time = 0;
193         if ( ktime != null )
194         {
195             time = ( int ) ( ktime.getTime() / 1000 );
196         }
197         writeInt( time );
198     }
199 
200 
201     private void writeKey( EncryptionKey key, int version ) throws IOException
202     {
203         writeShort( key.getKeyType().getValue() );
204         if ( version == CredentialsCacheConstants.FCC_FVNO_3 )
205         {
206             writeShort( key.getKeyType().getValue() );
207         }
208         // It's not correct with "uint16_t keylen", instead "uint32_t keylen" in keyblock    	
209         writeInt( key.getKeyValue().length );
210         write( key.getKeyValue() );
211     }
212 
213 
214     private void writeAddrs( HostAddresses addresses ) throws IOException
215     {
216         if ( addresses == null )
217         {
218             writeInt( 0 );
219         }
220         else
221         {
222             HostAddress[] addrs = addresses.getAddresses();
223             write( addrs.length );
224             for ( int i = 0; i < addrs.length; i++ )
225             {
226                 write( addrs[i].getAddrType().getValue() );
227                 write( addrs[i].getAddress().length );
228                 write( addrs[i].getAddress(), 0,
229                     addrs[i].getAddress().length );
230             }
231         }
232     }
233 
234 
235     private void writeAuth( AuthorizationData authData ) throws IOException
236     {
237         if ( authData == null )
238         {
239             writeInt( 0 );
240         }
241         else
242         {
243             for ( AuthorizationDataEntry ade : authData.getAuthorizationData() )
244             {
245                 write( ade.getAdType().getValue() );
246                 write( ade.getAdData().length );
247                 write( ade.getAdData() );
248             }
249         }
250     }
251 
252 
253     private void writeTicket( Ticket t ) throws IOException
254     {
255         if ( t == null )
256         {
257             writeInt( 0 );
258         }
259         else
260         {
261             byte[] bytes = KerberosEncoder.encode( t, false ).array();
262             writeInt( bytes.length );
263             write( bytes );
264         }
265     }
266 }