blob: e1e3dd2741fb7b9be71f4184cad7f51a79b43d7e [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.server.request;
import org.apache.kerby.kerberos.kerb.KrbCodec;
import org.apache.kerby.kerberos.kerb.KrbConstant;
import org.apache.kerby.kerberos.kerb.KrbErrorCode;
import org.apache.kerby.kerberos.kerb.KrbException;
import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
import org.apache.kerby.kerberos.kerb.server.KdcContext;
import org.apache.kerby.kerberos.kerb.type.KerberosTime;
import org.apache.kerby.kerberos.kerb.type.ap.ApOption;
import org.apache.kerby.kerberos.kerb.type.ap.ApReq;
import org.apache.kerby.kerberos.kerb.type.ap.Authenticator;
import org.apache.kerby.kerberos.kerb.type.base.EncryptedData;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
import org.apache.kerby.kerberos.kerb.type.base.HostAddresses;
import org.apache.kerby.kerberos.kerb.type.base.KeyUsage;
import org.apache.kerby.kerberos.kerb.type.base.KrbMessageType;
import org.apache.kerby.kerberos.kerb.type.base.LastReq;
import org.apache.kerby.kerberos.kerb.type.base.LastReqEntry;
import org.apache.kerby.kerberos.kerb.type.base.LastReqType;
import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
import org.apache.kerby.kerberos.kerb.type.kdc.EncTgsRepPart;
import org.apache.kerby.kerberos.kerb.type.kdc.KdcReq;
import org.apache.kerby.kerberos.kerb.type.kdc.TgsRep;
import org.apache.kerby.kerberos.kerb.type.kdc.TgsReq;
import org.apache.kerby.kerberos.kerb.type.pa.PaDataEntry;
import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
import org.apache.kerby.kerberos.kerb.type.ticket.Ticket;
import org.apache.kerby.kerberos.kerb.type.ticket.TicketFlag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
public class TgsRequest extends KdcRequest {
private static final Logger LOG = LoggerFactory.getLogger(TgsRequest.class);
private EncryptionKey tgtSessionKey;
private Ticket tgtTicket;
/**
* @param tgsReq TGS request
* @param kdcContext kdc context
*/
public TgsRequest(TgsReq tgsReq, KdcContext kdcContext) {
super(tgsReq, kdcContext);
setPreauthRequired(true);
}
/**
* Get tgt session key.
*
* @return The tgt session key
*/
public EncryptionKey getTgtSessionKey() {
return tgtSessionKey;
}
/**
* Set tgt session key.
*
* @param tgtSessionKey The tgt session key
*/
public void setTgtSessionKey(EncryptionKey tgtSessionKey) {
this.tgtSessionKey = tgtSessionKey;
}
/**
* {@inheritDoc}
*/
@Override
protected void checkClient() throws KrbException {
// Nothing to do at this phase because client couldn't be checked out yet.
}
/**
* Get tgt ticket.
*
* @return The tgt ticket.
*/
public Ticket getTgtTicket() {
return tgtTicket;
}
/**
* {@inheritDoc}
*/
@Override
protected void issueTicket() throws KrbException {
TicketIssuer issuer = new ServiceTicketIssuer(this);
Ticket newTicket = issuer.issueTicket();
LOG.info("TGS_REQ ISSUE: authtime " + newTicket.getEncPart().getAuthTime().getTime() + ","
+ newTicket.getEncPart().getCname() + " for "
+ newTicket.getSname());
setTicket(newTicket);
}
/**
* Verify authenticator.
* @throws org.apache.kerby.kerberos.kerb.KrbException e
* @param paDataEntry preauthentication data entry
*/
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);
}
tgtTicket = apReq.getTicket();
EncryptionKey tgsKey;
EncryptionType encType = tgtTicket.getEncryptedEncPart().getEType();
String remoteRealm = tgtTicket.getRealm();
if (checkCrossRealm(remoteRealm)) {
KrbIdentity tgs = getCrossRealmTgsEntry(remoteRealm);
if (tgs != null) {
tgsKey = tgs.getKey(encType);
} else {
throw new KrbException("Fail to get the tgs entry for remote realm: " + remoteRealm);
}
} else {
tgsKey = getTgsEntry().getKeys().get(encType);
}
if (tgsKey == null) {
throw new KrbException("Fail to get the tgs key for the type: " + encType);
}
if (tgtTicket.getTktvno() != KrbConstant.KRB_V5) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADVERSION);
}
EncTicketPart encPart = EncryptionUtil.unseal(tgtTicket.getEncryptedEncPart(),
tgsKey, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
tgtTicket.setEncPart(encPart);
EncryptionKey encKey = null;
//if (apReq.getApOptions().isFlagSet(ApOptions.USE_SESSION_KEY)) {
encKey = tgtTicket.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(tgtTicket.getEncPart().getCname())) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADMATCH);
}
HostAddresses hostAddresses = tgtTicket.getEncPart().getClientAddresses();
if (hostAddresses == null || hostAddresses.isEmpty()) {
if (!getKdcContext().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 = tgtTicket.getSname();
serverPrincipal.setRealm(tgtTicket.getRealm());
/* The client principal does not exist in backend when it's a cross realm request */
if (authenticator.getCrealm() != null
&& authenticator.getCrealm().equals(getKdcContext().getKdcRealm())) {
PrincipalName clientPrincipal = authenticator.getCname();
clientPrincipal.setRealm(authenticator.getCrealm());
KrbIdentity clientEntry = getEntry(clientPrincipal.getName());
setClientEntry(clientEntry);
}
if (!authenticator.getCtime().isInClockSkew(
getKdcContext().getConfig().getAllowableClockSkew() * 1000)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_SKEW);
}
KerberosTime now = KerberosTime.now();
KerberosTime startTime = tgtTicket.getEncPart().getStartTime();
if (startTime == null) {
startTime = tgtTicket.getEncPart().getAuthTime();
}
if (!startTime.lessThan(now)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_NYV);
}
KerberosTime endTime = tgtTicket.getEncPart().getEndTime();
if (!endTime.greaterThan(now)) {
throw new KrbException(KrbErrorCode.KRB_AP_ERR_TKT_EXPIRED);
}
apReq.getApOptions().setFlag(ApOption.MUTUAL_REQUIRED);
setTgtSessionKey(tgtTicket.getEncPart().getKey());
}
/**
* {@inheritDoc}
*/
@Override
protected void makeReply() throws KrbException {
Ticket ticket = getTicket();
TgsRep reply = new TgsRep();
if (getClientEntry() == null) {
reply.setCname(ticket.getEncPart().getCname());
reply.setCrealm(ticket.getEncPart().getCrealm());
} else {
reply.setCname(getClientEntry().getPrincipal());
reply.setCrealm(getKdcContext().getKdcRealm());
}
reply.setTicket(ticket);
EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();
reply.setEncPart(encKdcRepPart);
EncryptionKey sessionKey;
if (getToken() != null) {
sessionKey = getSessionKey();
} else {
sessionKey = getTgtSessionKey();
}
EncryptedData encryptedData = EncryptionUtil.seal(encKdcRepPart,
sessionKey, KeyUsage.TGS_REP_ENCPART_SESSKEY);
reply.setEncryptedEncPart(encryptedData);
setReply(reply);
}
/**
* Make EncKdcRepPart.
* @return encryption kdc response part
*/
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;
}
/**
* @return request body
* @throws KrbException e
*/
public ByteBuffer getRequestBody() throws KrbException {
return null;
}
}