package org.apache.kerberos.kerb.server;
import org.apache.kerberos.kerb.common.KrbUtil;
import org.apache.kerberos.kerb.identity.IdentityService;
import org.apache.kerberos.kerb.server.preauth.PreauthHandler;
import org.apache.kerberos.kerb.server.replay.ReplayCheckService;
import org.apache.kerberos.kerb.server.request.AsRequest;
import org.apache.kerberos.kerb.server.request.KdcRequest;
import org.apache.kerberos.kerb.server.request.TgsRequest;
import org.apache.kerberos.kerb.KrbException;
import org.apache.kerberos.kerb.spec.common.KrbMessage;
import org.apache.kerberos.kerb.spec.common.KrbMessageType;
import org.apache.kerberos.kerb.spec.kdc.AsReq;
import org.apache.kerberos.kerb.spec.kdc.KdcReq;
import org.apache.kerberos.kerb.spec.kdc.TgsReq;
import org.apache.haox.transport.MessageHandler;
import org.apache.haox.transport.Transport;
import org.apache.haox.transport.event.MessageEvent;
import org.apache.haox.transport.tcp.TcpTransport;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class KdcHandler extends MessageHandler {
private List<String> kdcRealms = new ArrayList<String>(1);
private Map<String, KdcContext> kdcContexts;
private KdcConfig kdcConfig;
private PreauthHandler preauthHandler;
// TODO: per realm for below
private IdentityService identityService;
private ReplayCheckService replayCheckService;
/**
* Should be called when all the necessary properties are set
*/
public void init() {
loadKdcRealms();
preauthHandler = new PreauthHandler();
preauthHandler.init(kdcConfig);
kdcContexts = new HashMap<String, KdcContext>(1);
for (String realm : kdcRealms) {
initRealmContext(realm);
}
}
private void initRealmContext(String kdcRealm) {
KdcContext kdcContext = new KdcContext();
kdcContext.init(kdcConfig);
kdcContext.setKdcRealm(kdcRealm);
kdcContext.setPreauthHandler(preauthHandler);
kdcContext.setIdentityService(identityService);
kdcContext.setReplayCache(replayCheckService);
kdcContexts.put(kdcRealm, kdcContext);
}
public void setKdcRealm(String realm) {
this.kdcRealms.add(realm);
}
public void setConfig(KdcConfig config) {
this.kdcConfig = config;
}
public void setIdentityService(IdentityService identityService) {
this.identityService = identityService;
}
@Override
protected void handleMessage(MessageEvent event) throws Exception {
ByteBuffer message = event.getMessage();
Transport transport = event.getTransport();
KrbMessage krbRequest = KrbUtil.decodeMessage(message);
KdcRequest kdcRequest = null;
KrbMessageType messageType = krbRequest.getMsgType();
if (messageType == KrbMessageType.TGS_REQ || messageType == KrbMessageType.AS_REQ) {
KdcReq kdcReq = (KdcReq) krbRequest;
String realm = getRequestRealm(kdcReq);
if (realm == null || !kdcContexts.containsKey(realm)) {
throw new KrbException("Invalid realm from kdc request: " + realm);
}
KdcContext kdcContext = kdcContexts.get(realm);
if (messageType == KrbMessageType.TGS_REQ) {
kdcRequest = new TgsRequest((TgsReq) kdcReq, kdcContext);
} else if (messageType == KrbMessageType.AS_REQ) {
kdcRequest = new AsRequest((AsReq) kdcReq, kdcContext);
}
}
InetSocketAddress clientAddress = transport.getRemoteAddress();
kdcRequest.setClientAddress(clientAddress.getAddress());
boolean isTcp = (transport instanceof TcpTransport);
kdcRequest.isTcp(isTcp);
kdcRequest.process();
KrbMessage krbResponse = kdcRequest.getReply();
KrbUtil.sendMessage(krbResponse, transport);
}
private void loadKdcRealms() {
if (kdcRealms.isEmpty()) {
kdcRealms.add(kdcConfig.getKdcRealm());
}
}
private String getRequestRealm(KdcReq kdcReq) {
String realm = kdcReq.getReqBody().getRealm();
if (realm == null && kdcReq.getReqBody().getCname() != null) {
realm = kdcReq.getReqBody().getCname().getRealm();
}
if (realm == null || realm.isEmpty()) {
realm = "NULL-KDC-REALM";
}
return realm;
}
}