< prev index next >

test/jdk/sun/security/krb5/auto/KDC.java

Print this page
rev 54745 : 8215032: Support Kerberos cross-realm referrals (RFC 6806)
Reviewed-by: weijun


 148 
 149     // Under the hood.
 150 
 151     // Principal db. principal -> pass. A case-insensitive TreeMap is used
 152     // so that even if the client provides a name with different case, the KDC
 153     // can still locate the principal and give back correct salt.
 154     private TreeMap<String,char[]> passwords = new TreeMap<>
 155             (String.CASE_INSENSITIVE_ORDER);
 156 
 157     // Non default salts. Precisely, there should be different salts for
 158     // different etypes, pretend they are the same at the moment.
 159     private TreeMap<String,String> salts = new TreeMap<>
 160             (String.CASE_INSENSITIVE_ORDER);
 161 
 162     // Non default s2kparams for newer etypes. Precisely, there should be
 163     // different s2kparams for different etypes, pretend they are the same
 164     // at the moment.
 165     private TreeMap<String,byte[]> s2kparamses = new TreeMap<>
 166             (String.CASE_INSENSITIVE_ORDER);
 167 








 168     // Realm name
 169     private String realm;
 170     // KDC
 171     private String kdc;
 172     // Service port number
 173     private int port;
 174     // The request/response job queue
 175     private BlockingQueue<Job> q = new ArrayBlockingQueue<>(100);
 176     // Options
 177     private Map<Option,Object> options = new HashMap<>();
 178     // Realm-specific krb5.conf settings
 179     private List<String> conf = new ArrayList<>();
 180 
 181     private Thread thread1, thread2, thread3;
 182     private volatile boolean udpConsumerReady = false;
 183     private volatile boolean tcpConsumerReady = false;
 184     private volatile boolean dispatcherReady = false;
 185     DatagramSocket u1 = null;
 186     ServerSocket t1 = null;
 187 


 536             }
 537         }
 538         sb.append("\n[realms]\n");
 539         sb.append(kdc.realmLine());
 540         for (Object o : more) {
 541             if (o instanceof KDC) {
 542                 sb.append(((KDC) o).realmLine());
 543             }
 544         }
 545         Files.write(Paths.get(file), sb.toString().getBytes());
 546     }
 547 
 548     /**
 549      * Returns the service port of the KDC server.
 550      * @return the KDC service port
 551      */
 552     public int getPort() {
 553         return port;
 554     }
 555 























 556     // Private helper methods
 557 
 558     /**
 559      * Private constructor, cannot be called outside.
 560      * @param realm
 561      */
 562     private KDC(String realm, String kdc) {
 563         this.realm = realm;
 564         this.kdc = kdc;
 565         this.nativeKdc = null;
 566     }
 567 
 568     /**
 569      * A constructor that starts the KDC service also.
 570      */
 571     protected KDC(String realm, String kdc, int port, boolean asDaemon)
 572             throws IOException {
 573         this.realm = realm;
 574         this.kdc = kdc;
 575         this.nativeKdc = NativeKdc.get(this);


 761         try {
 762             System.out.println(realm + "> " + tgsReq.reqBody.cname +
 763                     " sends TGS-REQ for " +
 764                     service + ", " + tgsReq.reqBody.kdcOptions);
 765             KDCReqBody body = tgsReq.reqBody;
 766             int[] eTypes = filterSupported(KDCReqBodyDotEType(body));
 767             if (eTypes.length == 0) {
 768                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
 769             }
 770             int e2 = eTypes[0];     // etype for outgoing session key
 771             int e3 = eTypes[0];     // etype for outgoing ticket
 772 
 773             PAData[] pas = KDCReqDotPAData(tgsReq);
 774 
 775             Ticket tkt = null;
 776             EncTicketPart etp = null;
 777 
 778             PrincipalName cname = null;
 779             boolean allowForwardable = true;
 780 











 781             if (pas == null || pas.length == 0) {
 782                 throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
 783             } else {
 784                 PrincipalName forUserCName = null;
 785                 for (PAData pa: pas) {
 786                     if (pa.getType() == Krb5.PA_TGS_REQ) {
 787                         APReq apReq = new APReq(pa.getValue());
 788                         EncryptedData ed = apReq.authenticator;
 789                         tkt = apReq.ticket;
 790                         int te = tkt.encPart.getEType();
 791                         EncryptionKey kkey = keyForUser(tkt.sname, te, true);
 792                         byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
 793                         DerInputStream derIn = new DerInputStream(bb);
 794                         DerValue der = derIn.getDerValue();
 795                         etp = new EncTicketPart(der.toByteArray());
 796                         // Finally, cname will be overwritten by PA-FOR-USER
 797                         // if it exists.
 798                         cname = etp.cname;
 799                         System.out.println(realm + "> presenting a ticket of "
 800                                 + etp.cname + " to " + tkt.sname);


 947             }
 948             Ticket t = new Ticket(
 949                     System.getProperty("test.kdc.diff.sname") != null ?
 950                         new PrincipalName("xx" + service.toString()) :
 951                         service,
 952                     new EncryptedData(skey, enc.asn1Encode(), KeyUsage.KU_TICKET)
 953             );
 954             EncTGSRepPart enc_part = new EncTGSRepPart(
 955                     key,
 956                     new LastReq(new LastReqEntry[] {
 957                         new LastReqEntry(0, timeAfter(-10))
 958                     }),
 959                     body.getNonce(),    // TODO: detect replay
 960                     timeAfter(3600 * 24),
 961                     // Next 5 and last MUST be same with ticket
 962                     tFlags,
 963                     timeAfter(0),
 964                     from,
 965                     till, renewTill,
 966                     service,
 967                     body.addresses

 968                     );
 969             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(),
 970                     KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
 971             TGSRep tgsRep = new TGSRep(null,
 972                     cname,
 973                     t,
 974                     edata);
 975             System.out.println("     Return " + tgsRep.cname
 976                     + " ticket for " + tgsRep.ticket.sname + ", flags "
 977                     + tFlags);
 978 
 979             DerOutputStream out = new DerOutputStream();
 980             out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
 981                     true, (byte)Krb5.KRB_TGS_REP), tgsRep.asn1Encode());
 982             return out.toByteArray();
 983         } catch (KrbException ke) {
 984             ke.printStackTrace(System.out);
 985             KRBError kerr = ke.getError();
 986             KDCReqBody body = tgsReq.reqBody;
 987             System.out.println("     Error " + ke.returnCode()


 991                         timeAfter(0),
 992                         0,
 993                         ke.returnCode(),
 994                         body.cname,
 995                         service,
 996                         KrbException.errorMessage(ke.returnCode()),
 997                         null);
 998             }
 999             return kerr.asn1Encode();
1000         }
1001     }
1002 
1003     /**
1004      * Processes a AS_REQ and generates a AS_REP (or KRB_ERROR)
1005      * @param in the request
1006      * @return the response
1007      * @throws java.lang.Exception for various errors
1008      */
1009     protected byte[] processAsReq(byte[] in) throws Exception {
1010         ASReq asReq = new ASReq(in);

1011         int[] eTypes = null;
1012         List<PAData> outPAs = new ArrayList<>();
1013 
1014         PrincipalName service = asReq.reqBody.sname;
1015         if (options.containsKey(KDC.Option.RESP_NT)) {
1016             service = new PrincipalName((int)options.get(KDC.Option.RESP_NT),
1017                     service.getNameStrings(),
1018                     Realm.getDefault());
1019         }
1020         try {
1021             System.out.println(realm + "> " + asReq.reqBody.cname +
1022                     " sends AS-REQ for " +
1023                     service + ", " + asReq.reqBody.kdcOptions);
1024 
1025             KDCReqBody body = asReq.reqBody;
1026 
1027             eTypes = filterSupported(KDCReqBodyDotEType(body));
1028             if (eTypes.length == 0) {
1029                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
1030             }
1031             int eType = eTypes[0];
1032 


















1033             EncryptionKey ckey = keyForUser(body.cname, eType, false);
1034             EncryptionKey skey = keyForUser(service, eType, true);
1035 
1036             if (options.containsKey(KDC.Option.ONLY_RC4_TGT)) {
1037                 int tgtEType = EncryptedData.ETYPE_ARCFOUR_HMAC;
1038                 boolean found = false;
1039                 for (int i=0; i<eTypes.length; i++) {
1040                     if (eTypes[i] == tgtEType) {
1041                         found = true;
1042                         break;
1043                     }
1044                 }
1045                 if (!found) {
1046                     throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
1047                 }
1048                 skey = keyForUser(service, tgtEType, true);
1049             }
1050             if (ckey == null) {
1051                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
1052             }


1194                                 epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
1195                                     null : getSalt(body.cname)
1196                                 ).asn1Encode());
1197                     }
1198                 }
1199             }
1200 
1201             DerOutputStream eid;
1202             if (pas2 != null) {
1203                 eid = new DerOutputStream();
1204                 eid.putSequence(pas2);
1205                 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO2, eid.toByteArray()));
1206             }
1207             if (pas != null) {
1208                 eid = new DerOutputStream();
1209                 eid.putSequence(pas);
1210                 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray()));
1211             }
1212 
1213             PAData[] inPAs = KDCReqDotPAData(asReq);

1214             if (inPAs == null || inPAs.length == 0) {
1215                 Object preauth = options.get(Option.PREAUTH_REQUIRED);
1216                 if (preauth == null || preauth.equals(Boolean.TRUE)) {
1217                     throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED);
1218                 }
1219             } else {

1220                 try {
1221                     EncryptedData data = newEncryptedData(
1222                             new DerValue(inPAs[0].getValue()));
1223                     EncryptionKey pakey
1224                             = keyForUser(body.cname, data.getEType(), false);
1225                     data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS);
1226                 } catch (Exception e) {
1227                     KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED);
1228                     ke.initCause(e);
1229                     throw ke;
1230                 }
1231                 bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true;











1232             }
1233 
1234             TicketFlags tFlags = new TicketFlags(bFlags);
1235             EncTicketPart enc = new EncTicketPart(
1236                     tFlags,
1237                     key,
1238                     body.cname,
1239                     new TransitedEncoding(1, new byte[0]),
1240                     timeAfter(0),
1241                     from,
1242                     till, rtime,
1243                     body.addresses,
1244                     null);
1245             Ticket t = new Ticket(
1246                     service,
1247                     new EncryptedData(skey, enc.asn1Encode(), KeyUsage.KU_TICKET)
1248             );
1249             EncASRepPart enc_part = new EncASRepPart(
1250                     key,
1251                     new LastReq(new LastReqEntry[]{
1252                         new LastReqEntry(0, timeAfter(-10))
1253                     }),
1254                     body.getNonce(),    // TODO: detect replay?
1255                     timeAfter(3600 * 24),
1256                     // Next 5 and last MUST be same with ticket
1257                     tFlags,
1258                     timeAfter(0),
1259                     from,
1260                     till, rtime,
1261                     service,
1262                     body.addresses

1263                     );
1264             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(),
1265                     KeyUsage.KU_ENC_AS_REP_PART);
1266             ASRep asRep = new ASRep(
1267                     outPAs.toArray(new PAData[outPAs.size()]),
1268                     body.cname,
1269                     t,
1270                     edata);
1271 
1272             System.out.println("     Return " + asRep.cname
1273                     + " ticket for " + asRep.ticket.sname + ", flags "
1274                     + tFlags);
1275 
1276             DerOutputStream out = new DerOutputStream();
1277             out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
1278                     true, (byte)Krb5.KRB_AS_REP), asRep.asn1Encode());
1279             byte[] result = out.toByteArray();
1280 
1281             // Added feature:
1282             // Write the current issuing TGT into a ccache file specified


1290                     CredentialsCache.create(asReq.reqBody.cname, ccache);
1291                 if (cache == null) {
1292                    throw new IOException("Unable to create the cache file " +
1293                                          ccache);
1294                 }
1295                 cache.update(credentials);
1296                 cache.save();
1297             }
1298 
1299             return result;
1300         } catch (KrbException ke) {
1301             ke.printStackTrace(System.out);
1302             KRBError kerr = ke.getError();
1303             KDCReqBody body = asReq.reqBody;
1304             System.out.println("     Error " + ke.returnCode()
1305                     + " " +ke.returnCodeMessage());
1306             byte[] eData = null;
1307             if (kerr == null) {
1308                 if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED ||
1309                         ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) {



1310                     DerOutputStream bytes = new DerOutputStream();
1311                     bytes.write(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]).asn1Encode());
1312                     for (PAData p: outPAs) {
1313                         bytes.write(p.asn1Encode());
1314                     }
1315                     DerOutputStream temp = new DerOutputStream();
1316                     temp.write(DerValue.tag_Sequence, bytes);
1317                     eData = temp.toByteArray();
1318                 }
1319                 kerr = new KRBError(null, null, null,
1320                         timeAfter(0),
1321                         0,
1322                         ke.returnCode(),
1323                         body.cname,
1324                         service,
1325                         KrbException.errorMessage(ke.returnCode()),
1326                         eData);
1327             }
1328             return kerr.asn1Encode();
1329         }
1330     }
1331 




 148 
 149     // Under the hood.
 150 
 151     // Principal db. principal -> pass. A case-insensitive TreeMap is used
 152     // so that even if the client provides a name with different case, the KDC
 153     // can still locate the principal and give back correct salt.
 154     private TreeMap<String,char[]> passwords = new TreeMap<>
 155             (String.CASE_INSENSITIVE_ORDER);
 156 
 157     // Non default salts. Precisely, there should be different salts for
 158     // different etypes, pretend they are the same at the moment.
 159     private TreeMap<String,String> salts = new TreeMap<>
 160             (String.CASE_INSENSITIVE_ORDER);
 161 
 162     // Non default s2kparams for newer etypes. Precisely, there should be
 163     // different s2kparams for different etypes, pretend they are the same
 164     // at the moment.
 165     private TreeMap<String,byte[]> s2kparamses = new TreeMap<>
 166             (String.CASE_INSENSITIVE_ORDER);
 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 
 176     // Realm name
 177     private String realm;
 178     // KDC
 179     private String kdc;
 180     // Service port number
 181     private int port;
 182     // The request/response job queue
 183     private BlockingQueue<Job> q = new ArrayBlockingQueue<>(100);
 184     // Options
 185     private Map<Option,Object> options = new HashMap<>();
 186     // Realm-specific krb5.conf settings
 187     private List<String> conf = new ArrayList<>();
 188 
 189     private Thread thread1, thread2, thread3;
 190     private volatile boolean udpConsumerReady = false;
 191     private volatile boolean tcpConsumerReady = false;
 192     private volatile boolean dispatcherReady = false;
 193     DatagramSocket u1 = null;
 194     ServerSocket t1 = null;
 195 


 544             }
 545         }
 546         sb.append("\n[realms]\n");
 547         sb.append(kdc.realmLine());
 548         for (Object o : more) {
 549             if (o instanceof KDC) {
 550                 sb.append(((KDC) o).realmLine());
 551             }
 552         }
 553         Files.write(Paths.get(file), sb.toString().getBytes());
 554     }
 555 
 556     /**
 557      * Returns the service port of the KDC server.
 558      * @return the KDC service port
 559      */
 560     public int getPort() {
 561         return port;
 562     }
 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 
 587     // Private helper methods
 588 
 589     /**
 590      * Private constructor, cannot be called outside.
 591      * @param realm
 592      */
 593     private KDC(String realm, String kdc) {
 594         this.realm = realm;
 595         this.kdc = kdc;
 596         this.nativeKdc = null;
 597     }
 598 
 599     /**
 600      * A constructor that starts the KDC service also.
 601      */
 602     protected KDC(String realm, String kdc, int port, boolean asDaemon)
 603             throws IOException {
 604         this.realm = realm;
 605         this.kdc = kdc;
 606         this.nativeKdc = NativeKdc.get(this);


 792         try {
 793             System.out.println(realm + "> " + tgsReq.reqBody.cname +
 794                     " sends TGS-REQ for " +
 795                     service + ", " + tgsReq.reqBody.kdcOptions);
 796             KDCReqBody body = tgsReq.reqBody;
 797             int[] eTypes = filterSupported(KDCReqBodyDotEType(body));
 798             if (eTypes.length == 0) {
 799                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
 800             }
 801             int e2 = eTypes[0];     // etype for outgoing session key
 802             int e3 = eTypes[0];     // etype for outgoing ticket
 803 
 804             PAData[] pas = KDCReqDotPAData(tgsReq);
 805 
 806             Ticket tkt = null;
 807             EncTicketPart etp = null;
 808 
 809             PrincipalName cname = null;
 810             boolean allowForwardable = true;
 811 
 812             if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
 813                 KDC referral = aliasReferrals.get(body.sname.getNameString());
 814                 if (referral != null) {
 815                     service = new PrincipalName(
 816                             PrincipalName.TGS_DEFAULT_SRV_NAME +
 817                             PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
 818                             referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
 819                             this.getRealm());
 820                 }
 821             }
 822 
 823             if (pas == null || pas.length == 0) {
 824                 throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
 825             } else {
 826                 PrincipalName forUserCName = null;
 827                 for (PAData pa: pas) {
 828                     if (pa.getType() == Krb5.PA_TGS_REQ) {
 829                         APReq apReq = new APReq(pa.getValue());
 830                         EncryptedData ed = apReq.authenticator;
 831                         tkt = apReq.ticket;
 832                         int te = tkt.encPart.getEType();
 833                         EncryptionKey kkey = keyForUser(tkt.sname, te, true);
 834                         byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
 835                         DerInputStream derIn = new DerInputStream(bb);
 836                         DerValue der = derIn.getDerValue();
 837                         etp = new EncTicketPart(der.toByteArray());
 838                         // Finally, cname will be overwritten by PA-FOR-USER
 839                         // if it exists.
 840                         cname = etp.cname;
 841                         System.out.println(realm + "> presenting a ticket of "
 842                                 + etp.cname + " to " + tkt.sname);


 989             }
 990             Ticket t = new Ticket(
 991                     System.getProperty("test.kdc.diff.sname") != null ?
 992                         new PrincipalName("xx" + service.toString()) :
 993                         service,
 994                     new EncryptedData(skey, enc.asn1Encode(), KeyUsage.KU_TICKET)
 995             );
 996             EncTGSRepPart enc_part = new EncTGSRepPart(
 997                     key,
 998                     new LastReq(new LastReqEntry[] {
 999                         new LastReqEntry(0, timeAfter(-10))
1000                     }),
1001                     body.getNonce(),    // TODO: detect replay
1002                     timeAfter(3600 * 24),
1003                     // Next 5 and last MUST be same with ticket
1004                     tFlags,
1005                     timeAfter(0),
1006                     from,
1007                     till, renewTill,
1008                     service,
1009                     body.addresses,
1010                     null
1011                     );
1012             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(),
1013                     KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
1014             TGSRep tgsRep = new TGSRep(null,
1015                     cname,
1016                     t,
1017                     edata);
1018             System.out.println("     Return " + tgsRep.cname
1019                     + " ticket for " + tgsRep.ticket.sname + ", flags "
1020                     + tFlags);
1021 
1022             DerOutputStream out = new DerOutputStream();
1023             out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
1024                     true, (byte)Krb5.KRB_TGS_REP), tgsRep.asn1Encode());
1025             return out.toByteArray();
1026         } catch (KrbException ke) {
1027             ke.printStackTrace(System.out);
1028             KRBError kerr = ke.getError();
1029             KDCReqBody body = tgsReq.reqBody;
1030             System.out.println("     Error " + ke.returnCode()


1034                         timeAfter(0),
1035                         0,
1036                         ke.returnCode(),
1037                         body.cname,
1038                         service,
1039                         KrbException.errorMessage(ke.returnCode()),
1040                         null);
1041             }
1042             return kerr.asn1Encode();
1043         }
1044     }
1045 
1046     /**
1047      * Processes a AS_REQ and generates a AS_REP (or KRB_ERROR)
1048      * @param in the request
1049      * @return the response
1050      * @throws java.lang.Exception for various errors
1051      */
1052     protected byte[] processAsReq(byte[] in) throws Exception {
1053         ASReq asReq = new ASReq(in);
1054         byte[] asReqbytes = asReq.asn1Encode();
1055         int[] eTypes = null;
1056         List<PAData> outPAs = new ArrayList<>();
1057 
1058         PrincipalName service = asReq.reqBody.sname;
1059         if (options.containsKey(KDC.Option.RESP_NT)) {
1060             service = new PrincipalName((int)options.get(KDC.Option.RESP_NT),
1061                     service.getNameStrings(),
1062                     Realm.getDefault());
1063         }
1064         try {
1065             System.out.println(realm + "> " + asReq.reqBody.cname +
1066                     " sends AS-REQ for " +
1067                     service + ", " + asReq.reqBody.kdcOptions);
1068 
1069             KDCReqBody body = asReq.reqBody;
1070 
1071             eTypes = filterSupported(KDCReqBodyDotEType(body));
1072             if (eTypes.length == 0) {
1073                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
1074             }
1075             int eType = eTypes[0];
1076 
1077             if (body.kdcOptions.get(KDCOptions.CANONICALIZE) &&
1078                     body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
1079                 PrincipalName principal = alias2Principals.get(
1080                         body.cname.getNameString());
1081                 if (principal != null) {
1082                     body.cname = principal;
1083                 } else {
1084                     KDC referral = aliasReferrals.get(body.cname.getNameString());
1085                     if (referral != null) {
1086                         body.cname = new PrincipalName(
1087                                 PrincipalName.TGS_DEFAULT_SRV_NAME,
1088                                 PrincipalName.KRB_NT_SRV_INST,
1089                                 referral.getRealm());
1090                         throw new KrbException(Krb5.KRB_ERR_WRONG_REALM);
1091                     }
1092                 }
1093             }
1094 
1095             EncryptionKey ckey = keyForUser(body.cname, eType, false);
1096             EncryptionKey skey = keyForUser(service, eType, true);
1097 
1098             if (options.containsKey(KDC.Option.ONLY_RC4_TGT)) {
1099                 int tgtEType = EncryptedData.ETYPE_ARCFOUR_HMAC;
1100                 boolean found = false;
1101                 for (int i=0; i<eTypes.length; i++) {
1102                     if (eTypes[i] == tgtEType) {
1103                         found = true;
1104                         break;
1105                     }
1106                 }
1107                 if (!found) {
1108                     throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
1109                 }
1110                 skey = keyForUser(service, tgtEType, true);
1111             }
1112             if (ckey == null) {
1113                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
1114             }


1256                                 epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
1257                                     null : getSalt(body.cname)
1258                                 ).asn1Encode());
1259                     }
1260                 }
1261             }
1262 
1263             DerOutputStream eid;
1264             if (pas2 != null) {
1265                 eid = new DerOutputStream();
1266                 eid.putSequence(pas2);
1267                 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO2, eid.toByteArray()));
1268             }
1269             if (pas != null) {
1270                 eid = new DerOutputStream();
1271                 eid.putSequence(pas);
1272                 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray()));
1273             }
1274 
1275             PAData[] inPAs = KDCReqDotPAData(asReq);
1276             List<PAData> enc_outPAs = new ArrayList<>();
1277             if (inPAs == null || inPAs.length == 0) {
1278                 Object preauth = options.get(Option.PREAUTH_REQUIRED);
1279                 if (preauth == null || preauth.equals(Boolean.TRUE)) {
1280                     throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED);
1281                 }
1282             } else {
1283                 EncryptionKey pakey = null;
1284                 try {
1285                     EncryptedData data = newEncryptedData(
1286                             new DerValue(inPAs[0].getValue()));
1287                     pakey = keyForUser(body.cname, data.getEType(), false);

1288                     data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS);
1289                 } catch (Exception e) {
1290                     KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED);
1291                     ke.initCause(e);
1292                     throw ke;
1293                 }
1294                 bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true;
1295                 for (PAData pa : inPAs) {
1296                     if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) {
1297                         Checksum ckSum = new Checksum(
1298                                 Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128,
1299                                 asReqbytes, ckey, KeyUsage.KU_AS_REQ);
1300                         enc_outPAs.add(new PAData(Krb5.PA_REQ_ENC_PA_REP,
1301                                 ckSum.asn1Encode()));
1302                         bFlags[Krb5.TKT_OPTS_ENC_PA_REP] = true;
1303                         break;
1304                     }
1305                 }
1306             }
1307 
1308             TicketFlags tFlags = new TicketFlags(bFlags);
1309             EncTicketPart enc = new EncTicketPart(
1310                     tFlags,
1311                     key,
1312                     body.cname,
1313                     new TransitedEncoding(1, new byte[0]),
1314                     timeAfter(0),
1315                     from,
1316                     till, rtime,
1317                     body.addresses,
1318                     null);
1319             Ticket t = new Ticket(
1320                     service,
1321                     new EncryptedData(skey, enc.asn1Encode(), KeyUsage.KU_TICKET)
1322             );
1323             EncASRepPart enc_part = new EncASRepPart(
1324                     key,
1325                     new LastReq(new LastReqEntry[]{
1326                         new LastReqEntry(0, timeAfter(-10))
1327                     }),
1328                     body.getNonce(),    // TODO: detect replay?
1329                     timeAfter(3600 * 24),
1330                     // Next 5 and last MUST be same with ticket
1331                     tFlags,
1332                     timeAfter(0),
1333                     from,
1334                     till, rtime,
1335                     service,
1336                     body.addresses,
1337                     enc_outPAs.toArray(new PAData[enc_outPAs.size()])
1338                     );
1339             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(),
1340                     KeyUsage.KU_ENC_AS_REP_PART);
1341             ASRep asRep = new ASRep(
1342                     outPAs.toArray(new PAData[outPAs.size()]),
1343                     body.cname,
1344                     t,
1345                     edata);
1346 
1347             System.out.println("     Return " + asRep.cname
1348                     + " ticket for " + asRep.ticket.sname + ", flags "
1349                     + tFlags);
1350 
1351             DerOutputStream out = new DerOutputStream();
1352             out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
1353                     true, (byte)Krb5.KRB_AS_REP), asRep.asn1Encode());
1354             byte[] result = out.toByteArray();
1355 
1356             // Added feature:
1357             // Write the current issuing TGT into a ccache file specified


1365                     CredentialsCache.create(asReq.reqBody.cname, ccache);
1366                 if (cache == null) {
1367                    throw new IOException("Unable to create the cache file " +
1368                                          ccache);
1369                 }
1370                 cache.update(credentials);
1371                 cache.save();
1372             }
1373 
1374             return result;
1375         } catch (KrbException ke) {
1376             ke.printStackTrace(System.out);
1377             KRBError kerr = ke.getError();
1378             KDCReqBody body = asReq.reqBody;
1379             System.out.println("     Error " + ke.returnCode()
1380                     + " " +ke.returnCodeMessage());
1381             byte[] eData = null;
1382             if (kerr == null) {
1383                 if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED ||
1384                         ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) {
1385                     outPAs.add(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]));
1386                 }
1387                 if (outPAs.size() > 0) {
1388                     DerOutputStream bytes = new DerOutputStream();

1389                     for (PAData p: outPAs) {
1390                         bytes.write(p.asn1Encode());
1391                     }
1392                     DerOutputStream temp = new DerOutputStream();
1393                     temp.write(DerValue.tag_Sequence, bytes);
1394                     eData = temp.toByteArray();
1395                 }
1396                 kerr = new KRBError(null, null, null,
1397                         timeAfter(0),
1398                         0,
1399                         ke.returnCode(),
1400                         body.cname,
1401                         service,
1402                         KrbException.errorMessage(ke.returnCode()),
1403                         eData);
1404             }
1405             return kerr.asn1Encode();
1406         }
1407     }
1408 


< prev index next >