blob: 8f6f1bd6f6500d9a506b3edc365659a804eedb06 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.kerby.kerberos.kerb.keytab;
import org.apache.kerby.kerberos.kerb.type.KerberosTime;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class KeytabEntry {
private PrincipalName principal;
private KerberosTime timestamp;
private int kvno;
private EncryptionKey key;
public KeytabEntry(PrincipalName principal, KerberosTime timestamp,
int kvno, EncryptionKey key) {
this.principal = principal;
this.timestamp = timestamp;
this.kvno = kvno;
this.key = key;
}
public KeytabEntry() {
}
void load(KeytabInputStream kis, int version, int entrySize) throws IOException {
int bytesLeft = kis.available();
this.principal = kis.readPrincipal(version);
this.timestamp = kis.readTime();
this.kvno = kis.readByte();
this.key = kis.readKey();
int entryBytesRead = bytesLeft - kis.available();
// Some implementations of Kerberos recognize a 32-bit key version at the end of an entry, if record length is
// at least 4 bytes longer than the entry and the value of those 32 bits is not 0. If present, this key version
// supersedes the 8-bit key version.
if (entryBytesRead + 4 <= entrySize) {
int tmp = kis.readInt();
if (tmp != 0) {
this.kvno = tmp;
}
} else if (entryBytesRead != entrySize) {
throw new IOException(
String.format("Bad input stream with less data read [%d] than expected [%d] for keytab entry.",
entryBytesRead, entrySize));
}
}
void store(KeytabOutputStream kos) throws IOException {
byte[] body = null;
// compute entry body content first so that to get and write the size
ByteArrayOutputStream baos = new ByteArrayOutputStream();
KeytabOutputStream subKos = new KeytabOutputStream(baos);
writeBody(subKos, 0); // todo: consider the version
subKos.flush();
body = baos.toByteArray();
kos.writeInt(body.length);
kos.write(body);
}
public EncryptionKey getKey() {
return key;
}
public int getKvno() {
return kvno;
}
public PrincipalName getPrincipal() {
return principal;
}
public KerberosTime getTimestamp() {
return timestamp;
}
void writeBody(KeytabOutputStream kos, int version) throws IOException {
kos.writePrincipal(principal, version);
kos.writeTime(timestamp);
kos.writeByte(kvno);
kos.writeKey(key, version);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
KeytabEntry that = (KeytabEntry) o;
if (kvno != that.kvno) {
return false;
}
if (!key.equals(that.key)) {
return false;
}
if (!principal.equals(that.principal)) {
return false;
}
if (!timestamp.equals(that.timestamp)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = principal.hashCode();
result = 31 * result + timestamp.hashCode();
result = 31 * result + kvno;
result = 31 * result + key.hashCode();
return result;
}
}