163 // different s2kparams for different etypes, pretend they are the same |
163 // different s2kparams for different etypes, pretend they are the same |
164 // at the moment. |
164 // at the moment. |
165 private TreeMap<String,byte[]> s2kparamses = new TreeMap<> |
165 private TreeMap<String,byte[]> s2kparamses = new TreeMap<> |
166 (String.CASE_INSENSITIVE_ORDER); |
166 (String.CASE_INSENSITIVE_ORDER); |
167 |
167 |
|
168 // Alias for referrals. |
|
169 private TreeMap<String,KDC> aliasReferrals = new TreeMap<> |
|
170 (String.CASE_INSENSITIVE_ORDER); |
|
171 |
|
172 // Alias for local resolution. |
|
173 private TreeMap<String,PrincipalName> alias2Principals = new TreeMap<> |
|
174 (String.CASE_INSENSITIVE_ORDER); |
|
175 |
168 // Realm name |
176 // Realm name |
169 private String realm; |
177 private String realm; |
170 // KDC |
178 // KDC |
171 private String kdc; |
179 private String kdc; |
172 // Service port number |
180 // Service port number |
551 */ |
559 */ |
552 public int getPort() { |
560 public int getPort() { |
553 return port; |
561 return port; |
554 } |
562 } |
555 |
563 |
|
564 /** |
|
565 * Register an alias name to be referred to a different KDC for |
|
566 * resolution, according to RFC 6806. |
|
567 * @param alias Alias name (i.e. user@REALM.COM). |
|
568 * @param referredKDC KDC to which the alias is referred for resolution. |
|
569 */ |
|
570 public void registerAlias(String alias, KDC referredKDC) { |
|
571 aliasReferrals.remove(alias); |
|
572 aliasReferrals.put(alias, referredKDC); |
|
573 } |
|
574 |
|
575 /** |
|
576 * Register an alias to be resolved to a Principal Name locally, |
|
577 * according to RFC 6806. |
|
578 * @param alias Alias name (i.e. user@REALM.COM). |
|
579 * @param user Principal Name to which the alias is resolved. |
|
580 */ |
|
581 public void registerAlias(String alias, String user) |
|
582 throws RealmException { |
|
583 alias2Principals.remove(alias); |
|
584 alias2Principals.put(alias, new PrincipalName(user)); |
|
585 } |
|
586 |
556 // Private helper methods |
587 // Private helper methods |
557 |
588 |
558 /** |
589 /** |
559 * Private constructor, cannot be called outside. |
590 * Private constructor, cannot be called outside. |
560 * @param realm |
591 * @param realm |
775 Ticket tkt = null; |
806 Ticket tkt = null; |
776 EncTicketPart etp = null; |
807 EncTicketPart etp = null; |
777 |
808 |
778 PrincipalName cname = null; |
809 PrincipalName cname = null; |
779 boolean allowForwardable = true; |
810 boolean allowForwardable = true; |
|
811 boolean isReferral = false; |
|
812 if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { |
|
813 System.out.println(realm + "> verifying referral for " + |
|
814 body.sname.getNameString()); |
|
815 KDC referral = aliasReferrals.get(body.sname.getNameString()); |
|
816 if (referral != null) { |
|
817 service = new PrincipalName( |
|
818 PrincipalName.TGS_DEFAULT_SRV_NAME + |
|
819 PrincipalName.NAME_COMPONENT_SEPARATOR_STR + |
|
820 referral.getRealm(), PrincipalName.KRB_NT_SRV_INST, |
|
821 this.getRealm()); |
|
822 System.out.println(realm + "> referral to " + |
|
823 referral.getRealm()); |
|
824 isReferral = true; |
|
825 } |
|
826 } |
780 |
827 |
781 if (pas == null || pas.length == 0) { |
828 if (pas == null || pas.length == 0) { |
782 throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP); |
829 throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP); |
783 } else { |
830 } else { |
784 PrincipalName forUserCName = null; |
831 PrincipalName forUserCName = null; |
874 bFlags[Krb5.TKT_OPTS_POSTDATED] = true; |
921 bFlags[Krb5.TKT_OPTS_POSTDATED] = true; |
875 } |
922 } |
876 if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) { |
923 if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) { |
877 bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true; |
924 bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true; |
878 } |
925 } |
879 if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT)) { |
926 if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT) && |
|
927 !isReferral) { |
880 if (!options.containsKey(Option.ALLOW_S4U2PROXY)) { |
928 if (!options.containsKey(Option.ALLOW_S4U2PROXY)) { |
881 // Don't understand CNAME_IN_ADDL_TKT |
929 // Don't understand CNAME_IN_ADDL_TKT |
882 throw new KrbException(Krb5.KDC_ERR_BADOPTION); |
930 throw new KrbException(Krb5.KDC_ERR_BADOPTION); |
883 } else { |
931 } else { |
884 Map<String,List<String>> map = (Map<String,List<String>>) |
932 Map<String,List<String>> map = (Map<String,List<String>>) |
1006 * @return the response |
1055 * @return the response |
1007 * @throws java.lang.Exception for various errors |
1056 * @throws java.lang.Exception for various errors |
1008 */ |
1057 */ |
1009 protected byte[] processAsReq(byte[] in) throws Exception { |
1058 protected byte[] processAsReq(byte[] in) throws Exception { |
1010 ASReq asReq = new ASReq(in); |
1059 ASReq asReq = new ASReq(in); |
|
1060 byte[] asReqbytes = asReq.asn1Encode(); |
1011 int[] eTypes = null; |
1061 int[] eTypes = null; |
1012 List<PAData> outPAs = new ArrayList<>(); |
1062 List<PAData> outPAs = new ArrayList<>(); |
1013 |
1063 |
1014 PrincipalName service = asReq.reqBody.sname; |
1064 PrincipalName service = asReq.reqBody.sname; |
1015 if (options.containsKey(KDC.Option.RESP_NT)) { |
1065 if (options.containsKey(KDC.Option.RESP_NT)) { |
1027 eTypes = filterSupported(KDCReqBodyDotEType(body)); |
1077 eTypes = filterSupported(KDCReqBodyDotEType(body)); |
1028 if (eTypes.length == 0) { |
1078 if (eTypes.length == 0) { |
1029 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP); |
1079 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP); |
1030 } |
1080 } |
1031 int eType = eTypes[0]; |
1081 int eType = eTypes[0]; |
|
1082 |
|
1083 if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { |
|
1084 PrincipalName principal = alias2Principals.get( |
|
1085 body.cname.getNameString()); |
|
1086 if (principal != null) { |
|
1087 body.cname = principal; |
|
1088 } else { |
|
1089 KDC referral = aliasReferrals.get(body.cname.getNameString()); |
|
1090 if (referral != null) { |
|
1091 body.cname = new PrincipalName( |
|
1092 PrincipalName.TGS_DEFAULT_SRV_NAME, |
|
1093 PrincipalName.KRB_NT_SRV_INST, |
|
1094 referral.getRealm()); |
|
1095 throw new KrbException(Krb5.KRB_ERR_WRONG_REALM); |
|
1096 } |
|
1097 } |
|
1098 } |
1032 |
1099 |
1033 EncryptionKey ckey = keyForUser(body.cname, eType, false); |
1100 EncryptionKey ckey = keyForUser(body.cname, eType, false); |
1034 EncryptionKey skey = keyForUser(service, eType, true); |
1101 EncryptionKey skey = keyForUser(service, eType, true); |
1035 |
1102 |
1036 if (options.containsKey(KDC.Option.ONLY_RC4_TGT)) { |
1103 if (options.containsKey(KDC.Option.ONLY_RC4_TGT)) { |
1209 eid.putSequence(pas); |
1276 eid.putSequence(pas); |
1210 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray())); |
1277 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray())); |
1211 } |
1278 } |
1212 |
1279 |
1213 PAData[] inPAs = KDCReqDotPAData(asReq); |
1280 PAData[] inPAs = KDCReqDotPAData(asReq); |
1214 if (inPAs == null || inPAs.length == 0) { |
1281 List<PAData> enc_outPAs = new ArrayList<>(); |
|
1282 |
|
1283 byte[] paEncTimestamp = null; |
|
1284 if (inPAs != null) { |
|
1285 for (PAData inPA : inPAs) { |
|
1286 if (inPA.getType() == Krb5.PA_ENC_TIMESTAMP) { |
|
1287 paEncTimestamp = inPA.getValue(); |
|
1288 } |
|
1289 } |
|
1290 } |
|
1291 |
|
1292 if (paEncTimestamp == null) { |
1215 Object preauth = options.get(Option.PREAUTH_REQUIRED); |
1293 Object preauth = options.get(Option.PREAUTH_REQUIRED); |
1216 if (preauth == null || preauth.equals(Boolean.TRUE)) { |
1294 if (preauth == null || preauth.equals(Boolean.TRUE)) { |
1217 throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED); |
1295 throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED); |
1218 } |
1296 } |
1219 } else { |
1297 } else { |
|
1298 EncryptionKey pakey = null; |
1220 try { |
1299 try { |
1221 EncryptedData data = newEncryptedData( |
1300 EncryptedData data = newEncryptedData( |
1222 new DerValue(inPAs[0].getValue())); |
1301 new DerValue(paEncTimestamp)); |
1223 EncryptionKey pakey |
1302 pakey = keyForUser(body.cname, data.getEType(), false); |
1224 = keyForUser(body.cname, data.getEType(), false); |
|
1225 data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS); |
1303 data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS); |
1226 } catch (Exception e) { |
1304 } catch (Exception e) { |
1227 KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED); |
1305 KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED); |
1228 ke.initCause(e); |
1306 ke.initCause(e); |
1229 throw ke; |
1307 throw ke; |
1230 } |
1308 } |
1231 bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true; |
1309 bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true; |
|
1310 for (PAData pa : inPAs) { |
|
1311 if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { |
|
1312 Checksum ckSum = new Checksum( |
|
1313 Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128, |
|
1314 asReqbytes, ckey, KeyUsage.KU_AS_REQ); |
|
1315 enc_outPAs.add(new PAData(Krb5.PA_REQ_ENC_PA_REP, |
|
1316 ckSum.asn1Encode())); |
|
1317 bFlags[Krb5.TKT_OPTS_ENC_PA_REP] = true; |
|
1318 break; |
|
1319 } |
|
1320 } |
1232 } |
1321 } |
1233 |
1322 |
1234 TicketFlags tFlags = new TicketFlags(bFlags); |
1323 TicketFlags tFlags = new TicketFlags(bFlags); |
1235 EncTicketPart enc = new EncTicketPart( |
1324 EncTicketPart enc = new EncTicketPart( |
1236 tFlags, |
1325 tFlags, |
1257 tFlags, |
1346 tFlags, |
1258 timeAfter(0), |
1347 timeAfter(0), |
1259 from, |
1348 from, |
1260 till, rtime, |
1349 till, rtime, |
1261 service, |
1350 service, |
1262 body.addresses |
1351 body.addresses, |
|
1352 enc_outPAs.toArray(new PAData[enc_outPAs.size()]) |
1263 ); |
1353 ); |
1264 EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), |
1354 EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), |
1265 KeyUsage.KU_ENC_AS_REP_PART); |
1355 KeyUsage.KU_ENC_AS_REP_PART); |
1266 ASRep asRep = new ASRep( |
1356 ASRep asRep = new ASRep( |
1267 outPAs.toArray(new PAData[outPAs.size()]), |
1357 outPAs.toArray(new PAData[outPAs.size()]), |
1305 + " " +ke.returnCodeMessage()); |
1395 + " " +ke.returnCodeMessage()); |
1306 byte[] eData = null; |
1396 byte[] eData = null; |
1307 if (kerr == null) { |
1397 if (kerr == null) { |
1308 if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED || |
1398 if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED || |
1309 ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) { |
1399 ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) { |
|
1400 outPAs.add(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0])); |
|
1401 } |
|
1402 if (outPAs.size() > 0) { |
1310 DerOutputStream bytes = new DerOutputStream(); |
1403 DerOutputStream bytes = new DerOutputStream(); |
1311 bytes.write(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]).asn1Encode()); |
|
1312 for (PAData p: outPAs) { |
1404 for (PAData p: outPAs) { |
1313 bytes.write(p.asn1Encode()); |
1405 bytes.write(p.asn1Encode()); |
1314 } |
1406 } |
1315 DerOutputStream temp = new DerOutputStream(); |
1407 DerOutputStream temp = new DerOutputStream(); |
1316 temp.write(DerValue.tag_Sequence, bytes); |
1408 temp.write(DerValue.tag_Sequence, bytes); |