package org.apache.kerberos.kerb.client.request; import org.apache.kerberos.kerb.client.KrbContext; import org.apache.kerberos.kerb.client.KrbOptions; import org.apache.kerberos.kerb.client.preauth.FastContext; import org.apache.kerberos.kerb.client.preauth.PreauthContext; import org.apache.kerberos.kerb.client.preauth.PreauthHandler; import org.apache.kerberos.kerb.crypto.EncryptionHandler; import org.apache.kerberos.kerb.KrbException; import org.apache.kerberos.kerb.spec.KerberosTime; import org.apache.kerberos.kerb.spec.common.*; import org.apache.kerberos.kerb.spec.kdc.KdcOptions; import org.apache.kerberos.kerb.spec.kdc.KdcRep; import org.apache.kerberos.kerb.spec.kdc.KdcReq; import org.apache.kerberos.kerb.spec.kdc.KdcReqBody; import org.apache.kerberos.kerb.spec.pa.PaDataType; import org.apache.haox.transport.Transport; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A wrapper for KdcReq request */ public abstract class KdcRequest { private KrbContext context; private Transport transport; private KrbOptions krbOptions; private PrincipalName serverPrincipal; private List<HostAddress> hostAddresses = new ArrayList<HostAddress>(); private KdcOptions kdcOptions = new KdcOptions(); private List<EncryptionType> encryptionTypes; private EncryptionType chosenEncryptionType; private int chosenNonce; private KdcReq kdcReq; private KdcRep kdcRep; protected Map<String, Object> credCache; private PreauthContext preauthContext; private FastContext fastContext; private EncryptionKey asKey; private KrbError errorReply; private boolean isRetrying; public KdcRequest(KrbContext context) { this.context = context; this.isRetrying = false; this.credCache = new HashMap<String, Object>(); this.preauthContext = context.getPreauthHandler() .preparePreauthContext(this); this.fastContext = new FastContext(); } public void setTransport(Transport transport) { this.transport = transport; } public Transport getTransport() { return this.transport; } public void setKrbOptions(KrbOptions options) { this.krbOptions = options; } public KrbOptions getKrbOptions() { return krbOptions; } public boolean isRetrying() { return isRetrying; } public void setAsKey(EncryptionKey asKey) { this.asKey = asKey; } public EncryptionKey getAsKey() throws KrbException { return asKey; } public void setAllowedPreauth(PaDataType paType) { preauthContext.setAllowedPaType(paType); } public Map<String, Object> getCredCache() { return credCache; } public void setPreauthRequired(boolean preauthRequired) { preauthContext.setPreauthRequired(preauthRequired); } public PreauthContext getPreauthContext() { return preauthContext; } protected void loadCredCache() { // TODO } public KdcReq getKdcReq() { return kdcReq; } public void setKdcReq(KdcReq kdcReq) { this.kdcReq = kdcReq; } public KdcRep getKdcRep() { return kdcRep; } public void setKdcRep(KdcRep kdcRep) { this.kdcRep = kdcRep; } protected KdcReqBody makeReqBody() throws KrbException { KdcReqBody body = new KdcReqBody(); long startTime = System.currentTimeMillis(); body.setFrom(new KerberosTime(startTime)); PrincipalName cName = null; cName = getClientPrincipal(); body.setCname(cName); body.setRealm(cName.getRealm()); PrincipalName sName = getServerPrincipal(); body.setSname(sName); body.setTill(new KerberosTime(startTime + getTicketValidTime())); int nonce = generateNonce(); body.setNonce(nonce); setChosenNonce(nonce); body.setKdcOptions(getKdcOptions()); HostAddresses addresses = getHostAddresses(); if (addresses != null) { body.setAddresses(addresses); } body.setEtypes(getEncryptionTypes()); return body; } public KdcOptions getKdcOptions() { return kdcOptions; } public HostAddresses getHostAddresses() { HostAddresses addresses = null; if (!hostAddresses.isEmpty()) { addresses = new HostAddresses(); for(HostAddress ha : hostAddresses) { addresses.addElement(ha); } } return addresses; } public KrbContext getContext() { return context; } protected byte[] decryptWithClientKey(EncryptedData data, KeyUsage usage) throws KrbException { return EncryptionHandler.decrypt(data, getClientKey(), usage); } public void setContext(KrbContext context) { this.context = context; } public void setHostAddresses(List<HostAddress> hostAddresses) { this.hostAddresses = hostAddresses; } public void setKdcOptions(KdcOptions kdcOptions) { this.kdcOptions = kdcOptions; } public abstract PrincipalName getClientPrincipal(); public PrincipalName getServerPrincipal() { return serverPrincipal; } public void setServerPrincipal(PrincipalName serverPrincipal) { this.serverPrincipal = serverPrincipal; } public List<EncryptionType> getEncryptionTypes() { if (encryptionTypes == null) { encryptionTypes = context.getConfig().getEncryptionTypes(); } return encryptionTypes; } public void setEncryptionTypes(List<EncryptionType> encryptionTypes) { this.encryptionTypes = encryptionTypes; } public EncryptionType getChosenEncryptionType() { return chosenEncryptionType; } public void setChosenEncryptionType(EncryptionType chosenEncryptionType) { this.chosenEncryptionType = chosenEncryptionType; } public int generateNonce() { return context.generateNonce(); } public int getChosenNonce() { return chosenNonce; } public void setChosenNonce(int nonce) { this.chosenNonce = nonce; } public abstract EncryptionKey getClientKey() throws KrbException; public long getTicketValidTime() { return context.getTicketValidTime(); } public KerberosTime getTicketTillTime() { long now = System.currentTimeMillis(); return new KerberosTime(now + KerberosTime.MINUTE * 60 * 1000); } public void addHost(String hostNameOrIpAddress) throws UnknownHostException { InetAddress address = InetAddress.getByName(hostNameOrIpAddress); hostAddresses.add(new HostAddress(address)); } public void process() throws KrbException { preauth(); } public abstract void processResponse(KdcRep kdcRep) throws KrbException; public KrbOptions getPreauthOptions() { return new KrbOptions(); } protected void preauth() throws KrbException { loadCredCache(); List<EncryptionType> etypes = getEncryptionTypes(); if (etypes.isEmpty()) { throw new KrbException("No encryption type is configured and available"); } EncryptionType encryptionType = etypes.iterator().next(); setChosenEncryptionType(encryptionType); getPreauthHandler().preauth(this); } protected PreauthHandler getPreauthHandler() { return getContext().getPreauthHandler(); } /** * Indicate interest in the AS key. */ public void needAsKey() throws KrbException { EncryptionKey clientKey = getClientKey(); if (clientKey == null) { throw new RuntimeException("Client key should be prepared or prompted at this time!"); } setAsKey(clientKey); } /** * Get the enctype expected to be used to encrypt the encrypted portion of * the AS_REP packet. When handling a PREAUTH_REQUIRED error, this * typically comes from etype-info2. When handling an AS reply, it is * initialized from the AS reply itself. */ public EncryptionType getEncType() { return getChosenEncryptionType(); } public void askQuestion(String question, String challenge) { preauthContext.getUserResponser().askQuestion(question, challenge); } /** * Get a pointer to the FAST armor key, or NULL if the client is not using FAST. */ public EncryptionKey getArmorKey() { return fastContext.armorKey; } /** * Get the current time for use in a preauth response. If * allow_unauth_time is true and the library has been configured to allow * it, the current time will be offset using unauthenticated timestamp * information received from the KDC in the preauth-required error, if one * has been received. Otherwise, the timestamp in a preauth-required error * will only be used if it is protected by a FAST channel. Only set * allow_unauth_time if using an unauthenticated time offset would not * create a security issue. */ public KerberosTime getPreauthTime() { return KerberosTime.now(); } /** * Get a state item from an input ccache, which may allow it * to retrace the steps it took last time. The returned data string is an * alias and should not be freed. */ public Object getCacheValue(String key) { return credCache.get(key); } /** * Set a state item which will be recorded to an output * ccache, if the calling application supplied one. Both key and data * should be valid UTF-8 text. */ public void cacheValue(String key, Object value) { credCache.put(key, value); } }