You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by dr...@apache.org on 2015/01/22 22:47:45 UTC
[06/45] directory-kerberos git commit: DIRKRB-149 New layout
structure with the new name "Apache Kerby"
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/replay/SimpleCacheService.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/replay/SimpleCacheService.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/replay/SimpleCacheService.java
new file mode 100644
index 0000000..96d95c1
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/replay/SimpleCacheService.java
@@ -0,0 +1,46 @@
+/**
+ * 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.server.replay;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class SimpleCacheService implements CacheService {
+ private Set<RequestRecord> requests;
+
+ public SimpleCacheService() {
+ requests = new HashSet<RequestRecord>();
+ }
+
+ @Override
+ public boolean checkAndCache(RequestRecord request) {
+ if (requests.contains(request)) {
+ return true;
+ } else {
+ requests.add(request);
+ }
+ return false;
+ }
+
+ @Override
+ public void clear() {
+ requests.clear();
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
new file mode 100644
index 0000000..5cc6375
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
@@ -0,0 +1,91 @@
+/**
+ * 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.server.request;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.server.KdcContext;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.*;
+import org.apache.kerby.kerberos.kerb.spec.kdc.*;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlag;
+
+public class AsRequest extends KdcRequest {
+
+ public AsRequest(AsReq asReq, KdcContext kdcContext) {
+ super(asReq, kdcContext);
+ }
+
+ @Override
+ protected void makeReply() throws KrbException {
+ Ticket ticket = getTicket();
+
+ AsRep reply = new AsRep();
+
+ reply.setCname(getClientEntry().getPrincipal());
+ reply.setCrealm(kdcContext.getServerRealm());
+ reply.setTicket(ticket);
+
+ EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();
+ reply.setEncPart(encKdcRepPart);
+
+ EncryptionKey clientKey = getClientKey();
+ EncryptedData encryptedData = EncryptionUtil.seal(encKdcRepPart,
+ clientKey, KeyUsage.AS_REP_ENCPART);
+ reply.setEncryptedEncPart(encryptedData);
+
+ setReply(reply);
+ }
+
+ protected EncKdcRepPart makeEncKdcRepPart() {
+ KdcReq request = getKdcReq();
+ Ticket ticket = getTicket();
+
+ EncKdcRepPart encKdcRepPart = new EncAsRepPart();
+
+ //session key
+ encKdcRepPart.setKey(ticket.getEncPart().getKey());
+
+ LastReq lastReq = new LastReq();
+ LastReqEntry entry = new LastReqEntry();
+ entry.setLrType(LastReqType.THE_LAST_INITIAL);
+ entry.setLrValue(new KerberosTime());
+ lastReq.add(entry);
+ encKdcRepPart.setLastReq(lastReq);
+
+ encKdcRepPart.setNonce(request.getReqBody().getNonce());
+
+ encKdcRepPart.setFlags(ticket.getEncPart().getFlags());
+ encKdcRepPart.setAuthTime(ticket.getEncPart().getAuthTime());
+ encKdcRepPart.setStartTime(ticket.getEncPart().getStartTime());
+ encKdcRepPart.setEndTime(ticket.getEncPart().getEndTime());
+
+ if (ticket.getEncPart().getFlags().isFlagSet(TicketFlag.RENEWABLE)) {
+ encKdcRepPart.setRenewTill(ticket.getEncPart().getRenewtill());
+ }
+
+ encKdcRepPart.setSname(ticket.getSname());
+ encKdcRepPart.setSrealm(ticket.getRealm());
+ encKdcRepPart.setCaddr(ticket.getEncPart().getClientAddresses());
+
+ return encKdcRepPart;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
new file mode 100644
index 0000000..de3048c
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
@@ -0,0 +1,521 @@
+/**
+ * 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.server.request;
+
+import org.apache.kerby.kerberos.kerb.KrbErrorCode;
+import org.apache.kerby.kerberos.kerb.codec.KrbCodec;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcContext;
+import org.apache.kerby.kerberos.kerb.server.preauth.FastContext;
+import org.apache.kerby.kerberos.kerb.server.preauth.PreauthContext;
+import org.apache.kerby.kerberos.kerb.server.preauth.PreauthHandler;
+import org.apache.kerby.kerberos.kerb.KrbConstant;
+import org.apache.kerby.kerberos.kerb.KrbErrorException;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.*;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOption;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOptions;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcRep;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcReq;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaDataType;
+import org.apache.kerby.kerberos.kerb.spec.ticket.EncTicketPart;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlag;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.List;
+
+public abstract class KdcRequest {
+
+ protected KdcContext kdcContext;
+
+ private Ticket ticket;
+ private boolean isPreAuthenticated;
+ private KdcReq kdcReq;
+ private KdcRep reply;
+ private InetAddress clientAddress;
+ private boolean isTcp;
+ private EncryptionType encryptionType;
+ private EncryptionKey clientKey;
+ private KrbIdentity clientEntry;
+ private KrbIdentity serverEntry;
+ private EncryptionKey serverKey;
+ private KrbIdentity tgsEntry;
+ private PreauthContext preauthContext;
+ private FastContext fastContext;
+ private PrincipalName serverPrincipal;
+
+ public KdcRequest(KdcReq kdcReq, KdcContext kdcContext) {
+ this.kdcReq = kdcReq;
+ this.kdcContext = kdcContext;
+ this.preauthContext = kdcContext.getPreauthHandler()
+ .preparePreauthContext(this);
+ this.fastContext = new FastContext();
+ }
+
+ public KdcContext getKdcContext() {
+ return kdcContext;
+ }
+
+ public PreauthContext getPreauthContext() {
+ return preauthContext;
+ }
+
+ public void process() throws KrbException {
+ checkVersion();
+ checkClient();
+ checkServer();
+ preauth();
+ authenticate();
+ issueTicket();
+ makeReply();
+ }
+
+ public KdcReq getKdcReq() {
+ return kdcReq;
+ }
+
+ public KrbIdentity getTgsEntry() {
+ return tgsEntry;
+ }
+
+ public void setTgsEntry(KrbIdentity tgsEntry) {
+ this.tgsEntry = tgsEntry;
+ }
+
+ public boolean isTcp() {
+ return isTcp;
+ }
+
+ public void isTcp(boolean isTcp) {
+ this.isTcp = isTcp;
+ }
+
+ public KrbMessage getReply() {
+ return reply;
+ }
+
+ public void setReply(KdcRep reply) {
+ this.reply = reply;
+ }
+
+ public InetAddress getClientAddress() {
+ return clientAddress;
+ }
+
+ public void setClientAddress(InetAddress clientAddress) {
+ this.clientAddress = clientAddress;
+ }
+
+ public EncryptionType getEncryptionType() {
+ return encryptionType;
+ }
+
+ public void setEncryptionType(EncryptionType encryptionType) {
+ this.encryptionType = encryptionType;
+ }
+
+ public Ticket getTicket() {
+ return ticket;
+ }
+
+ public void setTicket(Ticket ticket) {
+ this.ticket = ticket;
+ }
+
+ public boolean isPreAuthenticated() {
+ return isPreAuthenticated;
+ }
+
+ public void setPreAuthenticated(boolean isPreAuthenticated) {
+ this.isPreAuthenticated = isPreAuthenticated;
+ }
+
+ public KrbIdentity getServerEntry() {
+ return serverEntry;
+ }
+
+ public void setServerEntry(KrbIdentity serverEntry) {
+ this.serverEntry = serverEntry;
+ }
+
+ public KrbIdentity getClientEntry() {
+ return clientEntry;
+ }
+
+ public void setClientEntry(KrbIdentity clientEntry) {
+ this.clientEntry = clientEntry;
+ }
+
+ public EncryptionKey getClientKey(EncryptionType encType) throws KrbException {
+ return getClientEntry().getKey(encType);
+ }
+
+ public EncryptionKey getClientKey() {
+ return clientKey;
+ }
+
+ public void setClientKey(EncryptionKey clientKey) {
+ this.clientKey = clientKey;
+ }
+
+ public EncryptionKey getServerKey() {
+ return serverKey;
+ }
+
+ public void setServerKey(EncryptionKey serverKey) {
+ this.serverKey = serverKey;
+ }
+
+ public PrincipalName getTgsPrincipal() {
+ PrincipalName result = new PrincipalName(kdcContext.getConfig().getTgsPrincipal());
+ result.setRealm(kdcContext.getKdcRealm());
+ return result;
+ }
+
+ protected abstract void makeReply() throws KrbException;
+
+ protected void checkVersion() throws KrbException {
+ KdcReq request = getKdcReq();
+
+ int kerberosVersion = request.getPvno();
+ if (kerberosVersion != KrbConstant.KRB_V5) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_BAD_PVNO);
+ }
+ }
+
+ protected void checkPolicy() throws KrbException {
+ KrbIdentity entry = getClientEntry();
+
+ if (entry.isDisabled()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
+ }
+
+ if (entry.isLocked()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
+ }
+
+ if (entry.getExpireTime().lessThan(new Date().getTime())) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_REVOKED);
+ }
+ }
+
+ protected void checkClient() throws KrbException {
+ KdcReq request = getKdcReq();
+
+ PrincipalName clientPrincipal = request.getReqBody().getCname();
+ String clientRealm = request.getReqBody().getRealm();
+ if (clientRealm == null || clientRealm.isEmpty()) {
+ clientRealm = kdcContext.getServerRealm();
+ }
+ clientPrincipal.setRealm(clientRealm);
+
+ KrbIdentity clientEntry = getEntry(clientPrincipal.getName());
+ setClientEntry(clientEntry);
+
+ EncryptionType encType = request.getReqBody().getEtypes().listIterator().next();
+ EncryptionKey clientKey = clientEntry.getKeys().get(encType);
+ setClientKey(clientKey);
+ }
+
+ protected void preauth() throws KrbException {
+ KdcReq request = getKdcReq();
+
+ PaData preAuthData = request.getPaData();
+
+ if (preauthContext.isPreauthRequired()) {
+ if (preAuthData == null || preAuthData.isEmpty()) {
+ KrbError krbError = makePreAuthenticationError(kdcContext);
+ throw new KrbErrorException(krbError);
+ } else {
+ getPreauthHandler().verify(this, preAuthData);
+ }
+ }
+
+ setPreAuthenticated(true);
+ }
+
+ protected void setPreauthRequired(boolean preauthRequired) {
+ preauthContext.setPreauthRequired(preauthRequired);
+ }
+
+ protected boolean isPreauthRequired() {
+ return preauthContext.isPreauthRequired();
+ }
+
+ protected PreauthHandler getPreauthHandler() {
+ return kdcContext.getPreauthHandler();
+ }
+
+ protected void checkEncryptionType() throws KrbException {
+ List<EncryptionType> requestedTypes = getKdcReq().getReqBody().getEtypes();
+
+ EncryptionType bestType = EncryptionUtil.getBestEncryptionType(requestedTypes,
+ kdcContext.getConfig().getEncryptionTypes());
+
+ if (bestType == null) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_ETYPE_NOSUPP);
+ }
+
+ setEncryptionType(bestType);
+ }
+
+ protected void authenticate() throws KrbException {
+ checkEncryptionType();
+ checkPolicy();
+ }
+
+ protected void issueTicket() throws KrbException {
+ KdcReq request = getKdcReq();
+
+ EncryptionType encryptionType = getEncryptionType();
+ EncryptionKey serverKey = getServerEntry().getKeys().get(encryptionType);
+
+ PrincipalName ticketPrincipal = request.getReqBody().getSname();
+
+ EncTicketPart encTicketPart = new EncTicketPart();
+ KdcConfig config = kdcContext.getConfig();
+
+ TicketFlags ticketFlags = new TicketFlags();
+ encTicketPart.setFlags(ticketFlags);
+ ticketFlags.setFlag(TicketFlag.INITIAL);
+
+ if (isPreAuthenticated()) {
+ ticketFlags.setFlag(TicketFlag.PRE_AUTH);
+ }
+
+ if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.FORWARDABLE)) {
+ if (!config.isForwardableAllowed()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+ }
+
+ ticketFlags.setFlag(TicketFlag.FORWARDABLE);
+ }
+
+ if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.PROXIABLE)) {
+ if (!config.isProxiableAllowed()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+ }
+
+ ticketFlags.setFlag(TicketFlag.PROXIABLE);
+ }
+
+ if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.ALLOW_POSTDATE)) {
+ if (!config.isPostdatedAllowed()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+ }
+
+ ticketFlags.setFlag(TicketFlag.MAY_POSTDATE);
+ }
+
+ KdcOptions kdcOptions = request.getReqBody().getKdcOptions();
+
+ EncryptionKey sessionKey = EncryptionHandler.random2Key(getEncryptionType());
+ encTicketPart.setKey(sessionKey);
+
+ encTicketPart.setCname(request.getReqBody().getCname());
+ encTicketPart.setCrealm(request.getReqBody().getRealm());
+
+ TransitedEncoding transEnc = new TransitedEncoding();
+ encTicketPart.setTransited(transEnc);
+ String serverRealm = request.getReqBody().getRealm();
+
+ KerberosTime now = KerberosTime.now();
+ encTicketPart.setAuthTime(now);
+
+ KerberosTime krbStartTime = request.getReqBody().getFrom();
+ if (krbStartTime == null || krbStartTime.lessThan(now) ||
+ krbStartTime.isInClockSkew(config.getAllowableClockSkew())) {
+ krbStartTime = now;
+ }
+ if (krbStartTime.greaterThan(now)
+ && !krbStartTime.isInClockSkew(config.getAllowableClockSkew())
+ && !kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_CANNOT_POSTDATE);
+ }
+
+ if (kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
+ if (!config.isPostdatedAllowed()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+ }
+
+ ticketFlags.setFlag(TicketFlag.POSTDATED);
+ encTicketPart.setStartTime(krbStartTime);
+ }
+
+ KerberosTime krbEndTime = request.getReqBody().getTill();
+ if (krbEndTime == null) {
+ krbEndTime = krbStartTime.extend(config.getMaximumTicketLifetime() * 1000);
+ } else if (krbStartTime.greaterThan(krbEndTime)) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
+ }
+ encTicketPart.setEndTime(krbEndTime);
+
+ long ticketLifeTime = Math.abs(krbEndTime.diff(krbStartTime));
+ if (ticketLifeTime < config.getMinimumTicketLifetime()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
+ }
+
+ KerberosTime krbRtime = request.getReqBody().getRtime();
+ if (kdcOptions.isFlagSet(KdcOption.RENEWABLE_OK)) {
+ kdcOptions.setFlag(KdcOption.RENEWABLE);
+ }
+ if (kdcOptions.isFlagSet(KdcOption.RENEWABLE)) {
+ if (!config.isRenewableAllowed()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+ }
+
+ ticketFlags.setFlag(TicketFlag.RENEWABLE);
+
+ if (krbRtime == null) {
+ krbRtime = KerberosTime.NEVER;
+ }
+ KerberosTime allowedMaximumRenewableTime = krbStartTime;
+ allowedMaximumRenewableTime.extend(config.getMaximumRenewableLifetime() * 1000);
+ if (krbRtime.greaterThan(allowedMaximumRenewableTime)) {
+ krbRtime = allowedMaximumRenewableTime;
+ }
+ encTicketPart.setRenewtill(krbRtime);
+ }
+
+ HostAddresses hostAddresses = request.getReqBody().getAddresses();
+ if (hostAddresses == null || hostAddresses.isEmpty()) {
+ if (!config.isEmptyAddressesAllowed()) {
+ throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+ }
+ } else {
+ encTicketPart.setClientAddresses(hostAddresses);
+ }
+
+ EncryptedData encryptedData = EncryptionUtil.seal(encTicketPart,
+ serverKey, KeyUsage.KDC_REP_TICKET);
+
+ Ticket newTicket = new Ticket();
+ newTicket.setSname(ticketPrincipal);
+ newTicket.setEncryptedEncPart(encryptedData);
+ newTicket.setRealm(serverRealm);
+ newTicket.setEncPart(encTicketPart);
+
+ setTicket(newTicket);
+ }
+
+ private void checkServer() throws KrbException {
+ KdcReq request = getKdcReq();
+
+ KrbIdentity tgsEntry = getEntry(getTgsPrincipal().getName());
+ setTgsEntry(tgsEntry);
+
+ PrincipalName principal = request.getReqBody().getSname();
+ String serverRealm = request.getReqBody().getRealm();
+ if (serverRealm == null || serverRealm.isEmpty()) {
+ serverRealm = kdcContext.getServerRealm();
+ }
+ principal.setRealm(serverRealm);
+
+ KrbIdentity serverEntry = getEntry(principal.getName());
+ setServerEntry(serverEntry);
+
+ EncryptionType encType = request.getReqBody().getEtypes().listIterator().next();
+ EncryptionKey serverKey = serverEntry.getKeys().get(encType);
+ setServerKey(serverKey);
+ }
+
+ protected KrbError makePreAuthenticationError(KdcContext kdcContext) throws KrbException {
+ EncryptionType requestedType = getEncryptionType();
+ List<EncryptionType> encryptionTypes = kdcContext.getConfig().getEncryptionTypes();
+ boolean isNewEtype = true;
+
+ EtypeInfo2 eTypeInfo2 = new EtypeInfo2();
+
+ EtypeInfo eTypeInfo = new EtypeInfo();
+
+ for (EncryptionType encryptionType : encryptionTypes) {
+ if (!isNewEtype) {
+ EtypeInfoEntry etypeInfoEntry = new EtypeInfoEntry();
+ etypeInfoEntry.setEtype(encryptionType);
+ etypeInfoEntry.setSalt(null);
+ eTypeInfo.add(etypeInfoEntry);
+ }
+
+ EtypeInfo2Entry etypeInfo2Entry = new EtypeInfo2Entry();
+ etypeInfo2Entry.setEtype(encryptionType);
+ eTypeInfo2.add(etypeInfo2Entry);
+ }
+
+ byte[] encTypeInfo = null;
+ byte[] encTypeInfo2 = null;
+ if (!isNewEtype) {
+ encTypeInfo = KrbCodec.encode(eTypeInfo);
+ }
+ encTypeInfo2 = KrbCodec.encode(eTypeInfo2);
+
+ MethodData methodData = new MethodData();
+ methodData.add(new PaDataEntry(PaDataType.ENC_TIMESTAMP, null));
+ if (!isNewEtype) {
+ methodData.add(new PaDataEntry(PaDataType.ETYPE_INFO, encTypeInfo));
+ }
+ methodData.add(new PaDataEntry(PaDataType.ETYPE_INFO2, encTypeInfo2));
+
+ KrbError krbError = new KrbError();
+ krbError.setErrorCode(KrbErrorCode.KDC_ERR_PREAUTH_REQUIRED);
+ byte[] encodedData = KrbCodec.encode(methodData);
+ krbError.setEdata(encodedData);
+
+ return krbError;
+ }
+
+ protected KrbIdentity getEntry(String principal) throws KrbException {
+ KrbIdentity entry = null;
+ KrbErrorCode krbErrorCode = KrbErrorCode.KDC_ERR_C_PRINCIPAL_UNKNOWN;
+
+ try {
+ entry = kdcContext.getIdentityService().getIdentity(principal);
+ } catch (Exception e) {
+ throw new KrbException(krbErrorCode, e);
+ }
+
+ if (entry == null) {
+ throw new KrbException(krbErrorCode);
+ }
+
+ return entry;
+ }
+
+ public ByteBuffer getRequestBody() throws KrbException {
+ return null;
+ }
+
+ public EncryptionKey getArmorKey() throws KrbException {
+ return fastContext.armorKey;
+ }
+
+ public PrincipalName getServerPrincipal() {
+ return serverPrincipal;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
new file mode 100644
index 0000000..f60c63d
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
@@ -0,0 +1,196 @@
+/**
+ * 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.server.request;
+
+import org.apache.kerby.kerberos.kerb.KrbErrorCode;
+import org.apache.kerby.kerberos.kerb.codec.KrbCodec;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.server.KdcContext;
+import org.apache.kerby.kerberos.kerb.KrbConstant;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.ap.ApOption;
+import org.apache.kerby.kerberos.kerb.spec.ap.ApReq;
+import org.apache.kerby.kerberos.kerb.spec.ap.Authenticator;
+import org.apache.kerby.kerberos.kerb.spec.common.*;
+import org.apache.kerby.kerberos.kerb.spec.kdc.*;
+import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
+import org.apache.kerby.kerberos.kerb.spec.ticket.EncTicketPart;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlag;
+
+import java.nio.ByteBuffer;
+
+public class TgsRequest extends KdcRequest {
+
+ private EncryptionKey tgtSessionKey;
+
+ public TgsRequest(TgsReq tgsReq, KdcContext kdcContext) {
+ super(tgsReq, kdcContext);
+
+ setPreauthRequired(true);
+ }
+
+ public EncryptionKey getTgtSessionKey() {
+ return tgtSessionKey;
+ }
+
+ public void setTgtSessionKey(EncryptionKey tgtSessionKey) {
+ this.tgtSessionKey = tgtSessionKey;
+ }
+
+ public void verifyAuthenticator(PaDataEntry paDataEntry) throws KrbException {
+ ApReq apReq = KrbCodec.decode(paDataEntry.getPaDataValue(), ApReq.class);
+
+ if (apReq.getPvno() != KrbConstant.KRB_V5) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADVERSION);
+ }
+
+ if (apReq.getMsgType() != KrbMessageType.AP_REQ) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_MSG_TYPE);
+ }
+
+ EncryptionType encType = getKdcReq().getReqBody().getEtypes().listIterator().next();
+ EncryptionKey tgsKey = getTgsEntry().getKeys().get(encType);
+
+ Ticket ticket = apReq.getTicket();
+ if (ticket.getTktvno() != KrbConstant.KRB_V5) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADVERSION);
+ }
+
+ EncTicketPart encPart = EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
+ tgsKey, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
+ ticket.setEncPart(encPart);
+
+ EncryptionKey encKey = null;
+ //if (apReq.getApOptions().isFlagSet(ApOptions.USE_SESSION_KEY)) {
+ encKey = ticket.getEncPart().getKey();
+
+ if (encKey == null) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_NOKEY);
+ }
+ Authenticator authenticator = EncryptionUtil.unseal(apReq.getEncryptedAuthenticator(),
+ encKey, KeyUsage.TGS_REQ_AUTH, Authenticator.class);
+
+ if (!authenticator.getCname().equals(ticket.getEncPart().getCname())) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADMATCH);
+ }
+
+ HostAddresses hostAddresses = ticket.getEncPart().getClientAddresses();
+ if (hostAddresses == null || hostAddresses.isEmpty()) {
+ if (!kdcContext.getConfig().isEmptyAddressesAllowed()) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADADDR);
+ }
+ } else if (!hostAddresses.contains(getClientAddress())) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADADDR);
+ }
+
+ PrincipalName serverPrincipal = ticket.getSname();
+ serverPrincipal.setRealm(ticket.getRealm());
+ PrincipalName clientPrincipal = authenticator.getCname();
+ clientPrincipal.setRealm(authenticator.getCrealm());
+
+ if (!authenticator.getCtime().isInClockSkew(
+ kdcContext.getConfig().getAllowableClockSkew() * 1000)) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_SKEW);
+ }
+
+ KerberosTime now = KerberosTime.now();
+ KerberosTime startTime = ticket.getEncPart().getStartTime();
+ if (startTime == null) {
+ startTime = ticket.getEncPart().getAuthTime();
+ }
+ if (! startTime.lessThan(now)) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_NYV);
+ }
+
+ KerberosTime endTime = ticket.getEncPart().getEndTime();
+ if (! endTime.greaterThan(now)) {
+ throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_EXPIRED);
+ }
+
+ apReq.getApOptions().setFlag(ApOption.MUTUAL_REQUIRED);
+
+ setTgtSessionKey(ticket.getEncPart().getKey());
+ }
+
+ @Override
+ protected void makeReply() throws KrbException {
+ Ticket ticket = getTicket();
+
+ TgsRep reply = new TgsRep();
+
+ reply.setCname(getClientEntry().getPrincipal());
+ reply.setCrealm(kdcContext.getServerRealm());
+ reply.setTicket(ticket);
+
+ EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();
+ reply.setEncPart(encKdcRepPart);
+
+ EncryptionKey sessionKey = getTgtSessionKey();
+ EncryptedData encryptedData = EncryptionUtil.seal(encKdcRepPart,
+ sessionKey, KeyUsage.TGS_REP_ENCPART_SESSKEY);
+ reply.setEncryptedEncPart(encryptedData);
+
+ setReply(reply);
+ }
+
+ private EncKdcRepPart makeEncKdcRepPart() {
+ KdcReq request = getKdcReq();
+ Ticket ticket = getTicket();
+
+ EncKdcRepPart encKdcRepPart = new EncTgsRepPart();
+
+ //session key
+ encKdcRepPart.setKey(ticket.getEncPart().getKey());
+
+ LastReq lastReq = new LastReq();
+ LastReqEntry entry = new LastReqEntry();
+ entry.setLrType(LastReqType.THE_LAST_INITIAL);
+ entry.setLrValue(new KerberosTime());
+ lastReq.add(entry);
+ encKdcRepPart.setLastReq(lastReq);
+
+ encKdcRepPart.setNonce(request.getReqBody().getNonce());
+
+ encKdcRepPart.setFlags(ticket.getEncPart().getFlags());
+ encKdcRepPart.setAuthTime(ticket.getEncPart().getAuthTime());
+ encKdcRepPart.setStartTime(ticket.getEncPart().getStartTime());
+ encKdcRepPart.setEndTime(ticket.getEncPart().getEndTime());
+
+ if (ticket.getEncPart().getFlags().isFlagSet(TicketFlag.RENEWABLE)) {
+ encKdcRepPart.setRenewTill(ticket.getEncPart().getRenewtill());
+ }
+
+ encKdcRepPart.setSname(ticket.getSname());
+ encKdcRepPart.setSrealm(ticket.getRealm());
+ encKdcRepPart.setCaddr(ticket.getEncPart().getClientAddresses());
+
+ return encKdcRepPart;
+ }
+
+ public ByteBuffer getRequestBody() throws KrbException {
+ return null;
+ }
+
+ public EncryptionKey getArmorKey() throws KrbException {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/main/resources/kdc.conf
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/resources/kdc.conf b/kerby-kerb/kerb-server/src/main/resources/kdc.conf
new file mode 100644
index 0000000..8f286a1
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/resources/kdc.conf
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+[logging]
+ default = FILE:/var/log/krb5libs.log
+ kdc = FILE:/var/log/krb5kdc.log
+ admin_server = FILE:/var/log/kadmind.log
+
+[kdcdefaults]
+ kdc_udp_port = 88
+ kdc_tcp_port = 8014
+ restrict_anonymous_to_tgt = true
+ kdc_max_dgram_reply_size = 4096
+
+[realms]
+# ATHENA.MIT.EDU = {
+# kadmind_port = 749
+# max_life = 12h 0m 0s
+# max_renewable_life = 7d 0h 0m 0s
+# master_key_type = des3-hmac-sha1
+# supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal des-cbc-crc:v4
+# database_module = openldap_ldapconf
+# }
+
+[dbdefaults]
+ ldap_kerberos_container_dn = cn=krbcontainer dc=mit dc=edu
+
+[dbmodules]
+# openldap_ldapconf = {
+# db_library = kldap
+# disable_last_success = true
+# ldap_kdc_dn = cn=krbadmin dc=mit,dc=edu
+# ldap_kadmind_dn = cn=krbadmin dc=mit dc=edu
+# ldap_service_password_file = /etc/kerberos/service.keyfile
+# ldap_servers = ldaps://kerberos.mit.edu
+# ldap_conns_per_server = 5
+# }
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTest.java b/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTest.java
new file mode 100644
index 0000000..c98c00d
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTest.java
@@ -0,0 +1,70 @@
+/**
+ * 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.server;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+
+public class KdcTest {
+
+ private String serverHost = "localhost";
+ private short serverPort = 8089;
+
+ private SimpleKdcServer kdcServer;
+
+ @Before
+ public void setUp() throws Exception {
+ kdcServer = new SimpleKdcServer();
+ kdcServer.setKdcHost(serverHost);
+ kdcServer.setKdcTcpPort(serverPort);
+ kdcServer.init();
+ kdcServer.start();
+ }
+
+ @Test
+ public void testKdc() throws IOException, InterruptedException {
+ Thread.sleep(15);
+
+ SocketChannel socketChannel = SocketChannel.open();
+ socketChannel.configureBlocking(true);
+ SocketAddress sa = new InetSocketAddress(serverHost, serverPort);
+ socketChannel.connect(sa);
+
+ String BAD_KRB_MESSAGE = "Hello World!";
+ ByteBuffer writeBuffer = ByteBuffer.allocate(4 + BAD_KRB_MESSAGE.getBytes().length);
+ writeBuffer.putInt(BAD_KRB_MESSAGE.getBytes().length);
+ writeBuffer.put(BAD_KRB_MESSAGE.getBytes());
+ writeBuffer.flip();
+
+ socketChannel.write(writeBuffer);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ kdcServer.stop();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcConfigLoad.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcConfigLoad.java b/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcConfigLoad.java
new file mode 100644
index 0000000..548574f
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcConfigLoad.java
@@ -0,0 +1,57 @@
+/**
+ * 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.server;
+
+import org.apache.kerby.config.Conf;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public class TestKdcConfigLoad {
+
+ @Test
+ public void test() throws URISyntaxException, IOException {
+ URL confFileUrl = TestKdcConfigLoad.class.getResource("/kdc.conf");
+ File confFile = new File(confFileUrl.toURI());
+
+ KdcConfig krbConfig = new KdcConfig();
+ Conf conf = krbConfig.getConf();
+ conf.addIniConfig(confFile);
+
+ Assert.assertEquals(krbConfig.getDefaultLoggingLocation(), "FILE:/var/log/krb5libs.log");
+ Assert.assertEquals(krbConfig.getKdcLoggingLocation(), "FILE:/var/log/krb5kdc.log");
+ Assert.assertEquals(krbConfig.getAdminLoggingLocation(), "FILE:/var/log/kadmind.log");
+
+ Assert.assertEquals(krbConfig.getKdcUdpPort(), 88);
+ Assert.assertEquals(krbConfig.getKdcTcpPort(), 8014);
+ Assert.assertTrue(krbConfig.isRestrictAnonymousToTgt());
+ Assert.assertEquals(krbConfig.getKdcMaxDgramReplySize(), 4096);
+
+ String[] ldapContainerDn = krbConfig.getLdapKerberosContainerDn();
+ Assert.assertEquals(ldapContainerDn.length, 3);
+ Assert.assertEquals(ldapContainerDn[0], "cn=krbcontainer");
+ Assert.assertEquals(ldapContainerDn[1], "dc=mit");
+ Assert.assertEquals(ldapContainerDn[2], "dc=edu");
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/pom.xml b/kerby-kerb/kerb-util/pom.xml
new file mode 100644
index 0000000..e50f748
--- /dev/null
+++ b/kerby-kerb/kerb-util/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed 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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-kerb</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>kerb-util</artifactId>
+
+ <name>Kerby-kerb Util</name>
+ <description>Kerby-kerb Utilities</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-config</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-crypto</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbInputStream.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbInputStream.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbInputStream.java
new file mode 100644
index 0000000..224cec3
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbInputStream.java
@@ -0,0 +1,74 @@
+/**
+ * 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;
+
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.common.EncryptionType;
+import org.apache.kerby.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class KrbInputStream extends DataInputStream
+{
+ public KrbInputStream(InputStream in) {
+ super(in);
+ }
+
+ public KerberosTime readTime() throws IOException {
+ long value = readInt();
+ KerberosTime time = new KerberosTime(value * 1000);
+ return time;
+ }
+
+ public abstract PrincipalName readPrincipal(int version) throws IOException;
+
+ public EncryptionKey readKey(int version) throws IOException {
+ int eType = readShort();
+ EncryptionType encryptionType = EncryptionType.fromValue(eType);
+
+ byte[] keyData = readCountedOctets();
+ EncryptionKey key = new EncryptionKey(encryptionType, keyData);
+
+ return key;
+ }
+
+ public String readCountedString() throws IOException {
+ byte[] countedOctets = readCountedOctets();
+ // ASCII
+ return new String(countedOctets);
+ }
+
+ public byte[] readCountedOctets() throws IOException {
+ int len = readOctetsCount();
+ if (len == 0) {
+ return null;
+ }
+
+ byte[] data = new byte[len];
+ read(data);
+
+ return data;
+ }
+
+ public abstract int readOctetsCount() throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbOutputStream.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbOutputStream.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbOutputStream.java
new file mode 100644
index 0000000..7be0bdf
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/KrbOutputStream.java
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public abstract class KrbOutputStream extends DataOutputStream
+{
+ public KrbOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public abstract void writePrincipal(PrincipalName principal, int version) throws IOException;
+
+ public void writeRealm(String realm) throws IOException {
+ writeCountedString(realm);
+ }
+
+ public abstract void writeKey(EncryptionKey key, int version) throws IOException;
+
+ public void writeTime(KerberosTime ktime) throws IOException {
+ int time = 0;
+ if (ktime != null) {
+ time = (int) (ktime.getValue().getTime() / 1000);
+ }
+ writeInt(time);
+ }
+
+ public void writeCountedString(String string) throws IOException {
+ byte[] data = string != null ? string.getBytes() : null; // ASCII
+
+ writeCountedOctets(data);
+ }
+
+ public void writeCountedOctets(byte[] data) throws IOException {
+ if (data != null) {
+ writeInt(data.length);
+ write(data);
+ } else {
+ writeInt(0);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheInputStream.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheInputStream.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheInputStream.java
new file mode 100644
index 0000000..c97deac
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheInputStream.java
@@ -0,0 +1,167 @@
+/**
+ * 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.ccache;
+
+import org.apache.kerby.kerberos.kerb.KrbInputStream;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.*;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CredCacheInputStream extends KrbInputStream
+{
+ public CredCacheInputStream(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public PrincipalName readPrincipal(int version) throws IOException {
+ NameType nameType = NameType.NT_UNKNOWN;
+ if (version != CredentialCache.FCC_FVNO_1) {
+ int typeValue = readInt();
+ nameType = NameType.fromValue(typeValue);
+ }
+
+ int numComponents = readInt();
+ if (version == CredentialCache.FCC_FVNO_1) {
+ numComponents -= 1;
+ }
+
+ String realm = readCountedString();
+
+ List<String> nameStrings = new ArrayList<String>();
+ String component;
+ for (int i = 0; i < numComponents; i++) { // sub 1 if version 0x501
+ component = readCountedString();
+ nameStrings.add(component);
+ }
+
+ PrincipalName principal = new PrincipalName(nameStrings, nameType);
+ principal.setRealm(realm);
+
+ return principal;
+ }
+
+ public EncryptionKey readKey(int version) throws IOException {
+ if (version == CredentialCache.FCC_FVNO_3) {
+ readShort(); // ignore keytype
+ }
+
+ return super.readKey(version);
+ }
+
+ public KerberosTime[] readTimes() throws IOException {
+ KerberosTime[] times = new KerberosTime[4];
+
+ for (int i = 0; i < times.length; ++i) {
+ times[i] = readTime();
+ }
+
+ return times;
+ }
+
+ public boolean readIsSkey() throws IOException {
+ int value = readByte();
+ return value == 1 ? true : false;
+ }
+
+ public HostAddresses readAddr() throws IOException {
+ int numAddresses = readInt();
+ if (numAddresses <= 0) {
+ return null;
+ }
+
+ HostAddress[] addresses = new HostAddress[numAddresses];
+ for (int i = 0; i < numAddresses; i++) {
+ addresses[i] = readAddress();
+ }
+
+ HostAddresses result = new HostAddresses();
+ result.addElements(addresses);
+ return result;
+ }
+
+ public HostAddress readAddress() throws IOException {
+ int typeValue = readShort();
+ HostAddrType addrType = HostAddrType.fromValue(typeValue);
+ byte[] addrData = readCountedOctets();
+
+ HostAddress addr = new HostAddress();
+ addr.setAddrType(addrType);
+ addr.setAddress(addrData);
+
+ return addr;
+ }
+
+ public AuthorizationData readAuthzData() throws IOException {
+ int numEntries = readInt();
+ if (numEntries <= 0) {
+ return null;
+ }
+
+ AuthorizationDataEntry[] authzData = new AuthorizationDataEntry[numEntries];
+ for (int i = 0; i < numEntries; i++) {
+ authzData[i] = readAuthzDataEntry();
+ }
+
+ AuthorizationData result = new AuthorizationData();
+ result.addElements(authzData);
+ return result;
+ }
+
+ public AuthorizationDataEntry readAuthzDataEntry() throws IOException {
+ int typeValue = readShort();
+ AuthorizationType authzType = AuthorizationType.fromValue(typeValue);
+ byte[] authzData = readCountedOctets();
+
+ AuthorizationDataEntry authzEntry = new AuthorizationDataEntry();
+ authzEntry.setAuthzType(authzType);
+ authzEntry.setAuthzData(authzData);
+
+ return authzEntry;
+ }
+
+ @Override
+ public int readOctetsCount() throws IOException {
+ return readInt();
+ }
+
+ public TicketFlags readTicketFlags() throws IOException {
+ int flags = readInt();
+ TicketFlags tktFlags = new TicketFlags(flags);
+ return tktFlags;
+ }
+
+ public Ticket readTicket() throws IOException {
+ byte[] ticketData = readCountedOctets();
+ if (ticketData == null) {
+ return null;
+ }
+
+ Ticket ticket = new Ticket();
+ ticket.decode(ticketData);
+ return ticket;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheOutputStream.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheOutputStream.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheOutputStream.java
new file mode 100644
index 0000000..30fcd82
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredCacheOutputStream.java
@@ -0,0 +1,123 @@
+/**
+ * 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.ccache;
+
+import org.apache.kerby.kerberos.kerb.KrbOutputStream;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.*;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+public class CredCacheOutputStream extends KrbOutputStream
+{
+ public CredCacheOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ @Override
+ public void writePrincipal(PrincipalName principal, int version) throws IOException {
+ List<String> nameComponents = principal.getNameStrings();
+
+ if (version != CredentialCache.FCC_FVNO_1) {
+ writeInt(principal.getNameType().getValue());
+ }
+
+ int numComponents = nameComponents.size();
+ if (version == CredentialCache.FCC_FVNO_1) {
+ numComponents ++;
+ }
+ writeInt(numComponents);
+
+ writeRealm(principal.getRealm());
+
+ for (String nameCom : nameComponents) {
+ writeCountedString(nameCom);
+ }
+ }
+
+ @Override
+ public void writeKey(EncryptionKey key, int version) throws IOException {
+ writeShort(key.getKeyType().getValue());
+ if (version == CredentialCache.FCC_FVNO_3) {
+ writeShort(key.getKeyType().getValue());
+ }
+
+ writeCountedOctets(key.getKeyData());
+ }
+
+ public void writeTimes(KerberosTime[] times) throws IOException {
+ for (int i = 0; i < times.length; ++i) {
+ writeTime(times[i]);
+ }
+ }
+
+ public void writeAddresses(HostAddresses addrs) throws IOException {
+ if (addrs == null) {
+ writeInt(0);
+ } else {
+ List<HostAddress> addresses = addrs.getElements();
+ write(addresses.size());
+ for (HostAddress addr : addresses) {
+ writeAddress(addr);
+ }
+ }
+ }
+
+ public void writeAddress(HostAddress address) throws IOException {
+ write(address.getAddrType().getValue());
+ write(address.getAddress().length);
+ write(address.getAddress(), 0,
+ address.getAddress().length);
+ }
+
+ public void writeAuthzData(AuthorizationData authData) throws IOException {
+ if (authData == null) {
+ writeInt(0);
+ } else {
+ for (AuthorizationDataEntry entry : authData.getElements()) {
+ write(entry.getAuthzType().getValue());
+ write(entry.getAuthzData().length);
+ write(entry.getAuthzData());
+ }
+ }
+ }
+
+ public void writeTicket(Ticket t) throws IOException {
+ if (t == null) {
+ writeInt(0);
+ } else {
+ byte[] bytes = t.encode();
+ writeInt(bytes.length);
+ write(bytes);
+ }
+ }
+
+ public void writeIsSkey(boolean isEncInSKey) throws IOException {
+ writeByte(isEncInSKey ? 1 : 0);
+ }
+
+ public void writeTicketFlags(TicketFlags ticketFlags) throws IOException {
+ writeInt(ticketFlags.getFlags());
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
new file mode 100644
index 0000000..d0e74f4
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Credential.java
@@ -0,0 +1,225 @@
+/**
+ * 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.ccache;
+
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.common.AuthorizationData;
+import org.apache.kerby.kerberos.kerb.spec.common.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.common.HostAddresses;
+import org.apache.kerby.kerberos.kerb.spec.common.PrincipalName;
+import org.apache.kerby.kerberos.kerb.spec.kdc.EncKdcRepPart;
+import org.apache.kerby.kerberos.kerb.spec.ticket.AbstractServiceTicket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TgtTicket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
+
+import java.io.IOException;
+
+public class Credential
+{
+ private static String CONF_REALM = "X-CACHECONF:";
+
+ private PrincipalName clientName;
+ private String clientRealm;
+ private PrincipalName serverName;
+ private String serverRealm;
+ private EncryptionKey key;
+ private KerberosTime authTime;
+ private KerberosTime startTime;
+ private KerberosTime endTime;
+ private KerberosTime renewTill;
+ private HostAddresses clientAddresses;
+ private AuthorizationData authzData;
+ private boolean isEncInSKey;
+ private TicketFlags ticketFlags;
+ private Ticket ticket;
+ private Ticket secondTicket;
+
+ public Credential() {
+
+ }
+
+ public Credential(TgtTicket tgt) {
+ PrincipalName clientPrincipal = tgt.getClientPrincipal();
+
+ clientPrincipal.setRealm(tgt.getRealm());
+
+ init(tgt, clientPrincipal);
+ }
+
+ public Credential(AbstractServiceTicket tkt, PrincipalName clientPrincipal) {
+ init(tkt, clientPrincipal);
+ }
+
+ private void init(AbstractServiceTicket tkt, PrincipalName clientPrincipal) {
+ EncKdcRepPart kdcRepPart = tkt.getEncKdcRepPart();
+
+ this.serverName = kdcRepPart.getSname();
+ this.serverRealm = kdcRepPart.getSrealm();
+ this.serverName.setRealm(serverRealm);
+
+ this.clientName = clientPrincipal;
+
+ this.key = kdcRepPart.getKey();
+ this.authTime = kdcRepPart.getAuthTime();
+ this.startTime = kdcRepPart.getStartTime();
+ this.endTime = kdcRepPart.getEndTime();
+
+ this.renewTill = kdcRepPart.getRenewTill();
+
+ this.ticketFlags = kdcRepPart.getFlags();
+ this.clientAddresses = kdcRepPart.getCaddr();
+
+ this.ticket = tkt.getTicket();
+
+ this.isEncInSKey = false;
+
+ this.secondTicket = null;
+ }
+
+ public PrincipalName getServicePrincipal() {
+ return serverName;
+ }
+
+ public KerberosTime getAuthTime() {
+ return authTime;
+ }
+
+ public KerberosTime getEndTime() {
+ return endTime;
+ }
+
+ public int getEType() {
+ return key.getKeyType().getValue();
+ }
+
+ public PrincipalName getClientName() {
+ return clientName;
+ }
+
+ public PrincipalName getServerName() {
+ return serverName;
+ }
+
+ public String getClientRealm() {
+ return clientRealm;
+ }
+
+ public EncryptionKey getKey() {
+ return key;
+ }
+
+ public KerberosTime getStartTime() {
+ return startTime;
+ }
+
+ public KerberosTime getRenewTill() {
+ return renewTill;
+ }
+
+ public HostAddresses getClientAddresses() {
+ return clientAddresses;
+ }
+
+ public AuthorizationData getAuthzData() {
+ return authzData;
+ }
+
+ public boolean isEncInSKey() {
+ return isEncInSKey;
+ }
+
+ public TicketFlags getTicketFlags() {
+ return ticketFlags;
+ }
+
+ public Ticket getTicket() {
+ return ticket;
+ }
+
+ public Ticket getSecondTicket() {
+ return secondTicket;
+ }
+
+ public void load(CredCacheInputStream ccis, int version) throws IOException {
+ this.clientName = ccis.readPrincipal(version);
+ if (clientName == null) {
+ throw new IOException("Invalid client principal name");
+ }
+
+ this.serverName = ccis.readPrincipal(version);
+ if (serverName == null) {
+ throw new IOException("Invalid server principal name");
+ }
+
+ boolean isConfEntry = false;
+
+ if (serverName.getRealm().equals(CONF_REALM)) {
+ isConfEntry = true;
+ }
+
+ this.key = ccis.readKey(version);
+
+ KerberosTime[] times = ccis.readTimes();
+ this.authTime = times[0];
+ this.startTime = times[1];
+ this.endTime = times[2];
+ this.renewTill = times[3];
+
+ this.isEncInSKey = ccis.readIsSkey();
+
+ this.ticketFlags = ccis.readTicketFlags();
+
+ this.clientAddresses = ccis.readAddr();
+
+ this.authzData = ccis.readAuthzData();
+
+ if (isConfEntry) {
+ byte[] confData = ccis.readCountedOctets();
+ // ignoring confData for now
+ } else {
+ this.ticket = ccis.readTicket();
+ }
+
+ this.secondTicket = ccis.readTicket();
+
+ // might skip krb5_ccache_conf_data/fast_avail/krbtgt/REALM@REALM in MIT KRB5
+ }
+
+ public void store(CredCacheOutputStream ccos, int version) throws IOException {
+ ccos.writePrincipal(clientName, version);
+ ccos.writePrincipal(serverName, version);
+ ccos.writeKey(key, version);
+
+ ccos.writeTimes(new KerberosTime[]{authTime, startTime, endTime, renewTill});
+
+ ccos.writeIsSkey(isEncInSKey);
+
+ ccos.writeTicketFlags(ticketFlags);
+
+ ccos.writeAddresses(clientAddresses);
+
+ ccos.writeAuthzData(authzData);
+
+ ccos.writeTicket(ticket);
+
+ ccos.writeTicket(secondTicket);
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredentialCache.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredentialCache.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredentialCache.java
new file mode 100644
index 0000000..3598e90
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/CredentialCache.java
@@ -0,0 +1,278 @@
+/**
+ * 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.ccache;
+
+import org.apache.kerby.kerberos.kerb.spec.common.PrincipalName;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CredentialCache implements KrbCredentialCache
+{
+ public static final int FCC_FVNO_1 = 0x501;
+ public static final int FCC_FVNO_2 = 0x502;
+ public static final int FCC_FVNO_3 = 0x503;
+ public static final int FCC_FVNO_4 = 0x504;
+
+ public static final int FCC_TAG_DELTATIME = 1;
+ public static final int NT_UNKNOWN = 0;
+ public static final int MAXNAMELENGTH = 1024;
+
+ private int version = FCC_FVNO_4;
+ private List<Tag> tags;
+ private PrincipalName primaryPrincipal;
+ private List<Credential> credentials = new ArrayList<Credential> ();
+
+ @Override
+ public void store(File ccacheFile) throws IOException {
+ OutputStream outputStream = new FileOutputStream(ccacheFile);
+
+ store(outputStream);
+ }
+
+ @Override
+ public void store(OutputStream outputStream) throws IOException {
+ if (outputStream == null) {
+ throw new IllegalArgumentException("Invalid and null output stream");
+ }
+
+ CredCacheOutputStream ccos = new CredCacheOutputStream(outputStream);
+
+ doStore(ccos);
+
+ ccos.close();
+ }
+
+ private void doStore(CredCacheOutputStream ccos) throws IOException {
+ this.version = FCC_FVNO_3;
+
+ writeVersion(ccos);
+
+ if (version == FCC_FVNO_4) {
+ writeTags(ccos);
+ }
+
+ ccos.writePrincipal(primaryPrincipal, version);
+
+ for (Credential cred : credentials) {
+ cred.store(ccos, version);
+ }
+ }
+
+ @Override
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ @Override
+ public PrincipalName getPrimaryPrincipal() {
+ return primaryPrincipal;
+ }
+
+ @Override
+ public void setPrimaryPrincipal(PrincipalName principal) {
+ primaryPrincipal = principal;
+ }
+
+ @Override
+ public int getVersion() {
+ return version;
+ }
+
+ public void setTags(List<Tag> tags) {
+ this.tags = tags;
+ }
+
+ public List<Tag> getTags() {
+ return this.tags;
+ }
+
+ @Override
+ public List<Credential> getCredentials() {
+ return credentials;
+ }
+
+ @Override
+ public void addCredential(Credential credential) {
+ if (credential != null) {
+ this.credentials.add(credential);
+ }
+ }
+
+ @Override
+ public void addCredentials(List<Credential> credentials) {
+ if (credentials != null) {
+ this.credentials.addAll(credentials);
+ }
+ }
+
+ @Override
+ public void removeCredentials(List<Credential> credentials) {
+ if (credentials != null) {
+ for (Credential cred : credentials) {
+ removeCredential(cred);
+ }
+ }
+ }
+
+ @Override
+ public void removeCredential(Credential credential) {
+ if (credential != null) {
+ for (Credential cred : credentials) {
+ if (cred.equals(credential)) {
+ credentials.remove(cred);
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void load(File ccacheFile) throws IOException {
+ if (! ccacheFile.exists() || ! ccacheFile.canRead()) {
+ throw new IllegalArgumentException("Invalid ccache file: " + ccacheFile.getAbsolutePath());
+ }
+
+ InputStream inputStream = new FileInputStream(ccacheFile);
+
+ load(inputStream);
+ }
+
+ @Override
+ public void load(InputStream inputStream) throws IOException {
+ if (inputStream == null) {
+ throw new IllegalArgumentException("Invalid and null input stream");
+ }
+
+ CredCacheInputStream ccis = new CredCacheInputStream(inputStream);
+
+ doLoad(ccis);
+
+ ccis.close();
+ }
+
+ private void doLoad(CredCacheInputStream ccis) throws IOException {
+ this.version = readVersion(ccis);
+
+ this.tags = readTags(ccis);
+
+ this.primaryPrincipal = ccis.readPrincipal(version);
+
+ this.credentials = readCredentials(ccis);
+ }
+
+ private List<Credential> readCredentials(CredCacheInputStream ccis) throws IOException {
+ List<Credential> results = new ArrayList<Credential>(2);
+
+ Credential cred;
+ while (ccis.available() > 0) {
+ cred = new Credential();
+ cred.load(ccis, version);
+
+ results.add(cred);
+ }
+
+ return results;
+ }
+
+ private int readVersion(CredCacheInputStream ccis) throws IOException {
+ int result = ccis.readShort();
+ return result;
+ }
+
+ private List<Tag> readTags(CredCacheInputStream ccis) throws IOException {
+ int len = ccis.readShort();
+ List<Tag> tags = new ArrayList<Tag>();
+
+ int tag, tagLen, time, usec;
+ while (len > 0) {
+ tag = ccis.readShort();
+ tagLen = ccis.readShort();
+ switch (tag) {
+ case FCC_TAG_DELTATIME:
+ time = ccis.readInt();
+ usec = ccis.readInt();
+ tags.add(new Tag(tag, time, usec));
+ break;
+ default:
+ ccis.read(new byte[tagLen], 0, tagLen); // ignore unknown tag
+ }
+ len = len - (4 + tagLen);
+ }
+
+ return tags;
+ }
+
+ private void writeVersion(CredCacheOutputStream ccos) throws IOException {
+ ccos.writeShort(version);
+ }
+
+ private void writeTags(CredCacheOutputStream ccos) throws IOException {
+ if (tags == null) {
+ ccos.writeShort(0);
+ return;
+ }
+
+ int length = 0;
+ for (Tag tag : tags) {
+ if (tag.tag != FCC_TAG_DELTATIME) {
+ continue;
+ }
+ length += tag.length;
+ }
+ ccos.writeShort(length);
+
+ for (Tag tag : tags) {
+ if (tag.tag != CredentialCache.FCC_TAG_DELTATIME) {
+ continue;
+ }
+ writeTag(ccos, tag);
+ }
+ }
+
+ private void writeTag(CredCacheOutputStream ccos, Tag tag) throws IOException {
+ ccos.writeShort(tag.tag);
+ ccos.writeShort(tag.length);
+ ccos.writeInt(tag.time);
+ ccos.writeInt(tag.usec);
+ }
+
+ public static void main(String[] args) throws IOException {
+ if (args.length != 2) {
+ System.err.println("Dump credential cache file");
+ System.err.println("Usage: CredentialCache <ccache-file>");
+ System.exit(1);
+ }
+
+ String cacheFile = args[1];
+ CredentialCache cc = new CredentialCache();
+ cc.load(new File(cacheFile));
+
+ Ticket tkt;
+ for (Credential cred : cc.getCredentials()) {
+ tkt = cred.getTicket();
+ System.out.println("Tkt server name: " + tkt.getSname().getName());
+ System.out.println("Tkt client name: " + cred.getClientName().getName());
+ System.out.println("Tkt encrypt type: " + tkt.getEncryptedEncPart().getEType().getName());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/KrbCredentialCache.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/KrbCredentialCache.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/KrbCredentialCache.java
new file mode 100644
index 0000000..df70a80
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/KrbCredentialCache.java
@@ -0,0 +1,57 @@
+/**
+ * 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.ccache;
+
+import org.apache.kerby.kerberos.kerb.spec.common.PrincipalName;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+public interface KrbCredentialCache {
+
+ public PrincipalName getPrimaryPrincipal();
+
+ public void setPrimaryPrincipal(PrincipalName principal);
+
+ public int getVersion();
+
+ public void setVersion(int version);
+
+ public List<Credential> getCredentials();
+
+ public void addCredential(Credential credential);
+
+ public void addCredentials(List<Credential> credentials);
+
+ public void removeCredentials(List<Credential> credentials);
+
+ public void removeCredential(Credential credential);
+
+ public void load(File ccacheFile) throws IOException;
+
+ public void load(InputStream inputStream) throws IOException;
+
+ public void store(File ccacheFile) throws IOException;
+
+ public void store(OutputStream outputStream) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Tag.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Tag.java b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Tag.java
new file mode 100644
index 0000000..21b8dd7
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/Tag.java
@@ -0,0 +1,34 @@
+/**
+ * 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.ccache;
+
+public class Tag {
+ int tag = 0;
+ int tagLen = 8;
+ int time = 0;
+ int usec = 0;
+ int length = 2 + 2 + 8; // len(tag) + len(tagLen) + len(tagData);
+
+ public Tag(int tag, int time, int usec) {
+ this.tag = tag;
+ this.time = time;
+ this.usec = usec;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/ceacb982/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/ccache.txt
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/ccache.txt b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/ccache.txt
new file mode 100644
index 0000000..91453ea
--- /dev/null
+++ b/kerby-kerb/kerb-util/src/main/java/org/apache/kerby/kerberos/kerb/ccache/ccache.txt
@@ -0,0 +1,98 @@
+The Kerberos Credential Cache Binary File Format
+Copyright (C) 2006-2013 Simon Josefsson <simon josefsson.org>
+http://josefsson.org/shishi/ccache.txt
+Last updated: Sat Sep 23 12:04:11 CEST 2006
+
+Like the MIT keytab binary format (see Michael B Allen's reverse
+engineered description in keytab.txt), the credential cache format is
+not standard nor documented anywhere.
+
+In C style notation, the MIT credential cache file format is as
+follows. All values are in network byte order. All text is ASCII.
+
+ccache {
+ uint16_t file_format_version; /* 0x0504 */
+ uint16_t headerlen; /* only if version is 0x0504 */
+ header headers[]; /* only if version is 0x0504 */
+ principal primary_principal;
+ credential credentials[*];
+};
+
+header {
+ uint16_t tag; /* 1 = DeltaTime */
+ uint16_t taglen;
+ uint8_t tagdata[taglen]
+};
+
+The ccache.taglen and ccache.tags fields are only present in 0x0504
+versions, not in earlier. Both MIT and Heimdal appear to correctly
+ignore unknown tags, so it appears safe to add them (although there is
+no central place to "register" tags).
+
+Currently only one tag is widely implemented, DeltaTime (0x0001). Its
+taglen is always 8, and tagdata will contain:
+
+DeltaTime {
+ uint32_t time_offset;
+ uint32_t usec_offset;
+};
+
+After reading the file_format_version, header tags, and default
+principal, a list of credentials follow. You deduce from the file
+length when there are no more credentials.
+
+credential {
+ principal client;
+ principal server;
+ keyblock key;
+ times time;
+ uint8_t is_skey; /* 1 if skey, 0 otherwise */
+ uint32_t tktflags; /* stored in reversed byte order */
+ uint32_t num_address;
+ address addrs[num_address];
+ uint32_t num_authdata;
+ authdata authdata[num_authdata];
+ counted_octet_string ticket;
+ counted_octet_string second_ticket;
+};
+
+keyblock {
+ uint16_t keytype;
+ uint16_t etype; /* only present if version 0x0503 */
+ uint32_t keylen; /* [drankye]: corrected, before it was uint16_t */
+ uint8_t keyvalue[keylen];
+};
+
+times {
+ uint32_t authtime;
+ uint32_t starttime;
+ uint32_t endtime;
+ uint32_t renew_till;
+};
+
+address {
+ uint16_t addrtype;
+ counted_octet_string addrdata;
+};
+
+authdata {
+ uint16_t authtype;
+ counted_octet_string authdata;
+};
+
+principal {
+ uint32_t name_type; /* not present if version 0x0501 */
+ uint32_t num_components; /* sub 1 if version 0x501 */
+ counted_octet_string realm;
+ counted_octet_string components[num_components];
+};
+
+counted_octet_string {
+ uint32_t length;
+ uint8_t data[length];
+};
+
+Permission to copy, modify, and distribute this document, with or
+without modification, for any purpose and without fee or royalty is
+hereby granted, provided that you include this copyright notice in ALL
+copies of the document or portions thereof, including modifications.
\ No newline at end of file