Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ReferralsTest.java   Sprache: JAVA

 
/*
 * Copyright (c) 2019, 2021, Red Hat, Inc.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


/*
 * @test
 * @bug 8215032
 * @library /test/lib
 * @run main/othervm/timeout=120 -Dsun.security.krb5.debug=true ReferralsTest
 * @summary Test Kerberos cross-realm referrals (RFC 6806)
 */


import java.io.File;
import java.security.Principal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;

import org.ietf.jgss.GSSName;

import sun.security.jgss.GSSUtil;
import sun.security.krb5.Config;
import sun.security.krb5.PrincipalName;

public class ReferralsTest {
    private static final boolean DEBUG = true;
    private static final String krbConfigName = "krb5-localkdc.conf";
    private static final String krbConfigNameNoCanonicalize =
            "krb5-localkdc-nocanonicalize.conf";
    private static final String realmKDC1 = "RABBIT.HOLE";
    private static final String realmKDC2 = "DEV.RABBIT.HOLE";
    private static final char[] password = "123qwe@Z".toCharArray();

    // Names
    private static final String clientName = "test";
    private static final String userName = "user";
    private static final String serviceName = "http" +
            PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
            "server.dev.rabbit.hole";
    private static final String backendServiceName = "cifs" +
            PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
            "backend.rabbit.hole";

    // Alias
    private static final String clientAlias = clientName +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;

    // Names + realms
    private static final String clientKDC1Name = clientAlias.replaceAll(
            PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
            PrincipalName.NAME_REALM_SEPARATOR_STR) +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    private static final String clientKDC2Name = clientName +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
    private static final String userKDC1Name = userName +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    private static final String serviceKDC2Name = serviceName +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
    private static final String backendKDC1Name = backendServiceName +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    private static final String krbtgtKDC1 =
            PrincipalName.TGS_DEFAULT_SRV_NAME +
            PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1;
    private static final String krbtgtKDC2 =
            PrincipalName.TGS_DEFAULT_SRV_NAME +
            PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2;
    private static final String krbtgtKDC1toKDC2 =
            PrincipalName.TGS_DEFAULT_SRV_NAME +
            PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2 +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
    private static final String krbtgtKDC2toKDC1 =
            PrincipalName.TGS_DEFAULT_SRV_NAME +
            PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1 +
            PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;

    public static void main(String[] args) throws Exception {
        try {
            initializeKDCs();
            testSubjectCredentials();
            testDelegation();
            testImpersonation();
            testDelegationWithReferrals();
            testNoCanonicalize();
        } finally {
            cleanup();
        }
    }

    private static void initializeKDCs() throws Exception {
        KDC kdc1 = KDC.create(realmKDC1, "localhost", 0, true);
        kdc1.addPrincipalRandKey(krbtgtKDC1);
        kdc1.addPrincipal(krbtgtKDC2toKDC1, password);
        kdc1.addPrincipal(krbtgtKDC2, password);
        kdc1.addPrincipal(userKDC1Name, password);
        kdc1.addPrincipal(backendServiceName, password);

        KDC kdc2 = KDC.create(realmKDC2, "localhost", 0, true);
        kdc2.addPrincipalRandKey(krbtgtKDC2);
        kdc2.addPrincipal(clientKDC2Name, password);
        kdc2.addPrincipal(serviceName, password);
        kdc2.addPrincipal(krbtgtKDC1, password);
        kdc2.addPrincipal(krbtgtKDC1toKDC2, password);

        kdc1.registerAlias(clientAlias, kdc2);
        kdc1.registerAlias(serviceName, kdc2);
        kdc2.registerAlias(clientAlias, clientKDC2Name);
        kdc2.registerAlias(backendServiceName, kdc1);

        kdc1.setOption(KDC.Option.ALLOW_S4U2SELF, Arrays.asList(
                new String[]{serviceName + "@" + realmKDC2}));
        Map<String,List<String>> mapKDC1 = new HashMap<>();
        mapKDC1.put(serviceName + "@" + realmKDC2, Arrays.asList(
                new String[]{backendKDC1Name}));
        kdc1.setOption(KDC.Option.ALLOW_S4U2PROXY, mapKDC1);

        Map<String,List<String>> mapKDC2 = new HashMap<>();
        mapKDC2.put(serviceName + "@" + realmKDC2, Arrays.asList(
                new String[]{serviceName + "@" + realmKDC2,
                        krbtgtKDC2toKDC1}));
        kdc2.setOption(KDC.Option.ALLOW_S4U2PROXY, mapKDC2);

        KDC.saveConfig(krbConfigName, kdc1, kdc2,
                "forwardable=true""canonicalize=true");
        KDC.saveConfig(krbConfigNameNoCanonicalize, kdc1, kdc2,
                "forwardable=true");
        System.setProperty("java.security.krb5.conf", krbConfigName);
    }

    private static void cleanup() {
        String[] configFiles = new String[]{krbConfigName,
                krbConfigNameNoCanonicalize};
        for (String configFile : configFiles) {
            File f = new File(configFile);
            if (f.exists()) {
                f.delete();
            }
        }
    }

    /*
     * The client subject (whose principal is
     * test@RABBIT.HOLE@RABBIT.HOLE) will obtain a TGT after
     * realm referral and name canonicalization (TGT cname
     * will be test@DEV.RABBIT.HOLE). With this TGT, the client will request
     * a TGS for service http/server.dev.rabbit.hole@RABBIT.HOLE. After
     * realm referral, a http/server.dev.rabbit.hole@DEV.RABBIT.HOLE TGS
     * will be obtained.
     *
     * Assert that we get the proper TGT and TGS tickets, and that they are
     * associated to the client subject.
     *
     * Assert that if we request a TGS for the same service again (based on the
     * original service name), we don't get a new one but the previous,
     * already in the subject credentials.
     */

    private static void testSubjectCredentials() throws Exception {
        Subject clientSubject = new Subject();
        Context clientContext = Context.fromUserPass(clientSubject,
                clientKDC1Name, password, false);

        Set<Principal> clientPrincipals = clientSubject.getPrincipals();
        if (clientPrincipals.size() != 1) {
            throw new Exception("Only one client subject principal expected");
        }
        Principal clientPrincipal = clientPrincipals.iterator().next();
        if (DEBUG) {
            System.out.println("Client subject principal: " +
                    clientPrincipal.getName());
        }
        if (!clientPrincipal.getName().equals(clientKDC1Name)) {
            throw new Exception("Unexpected client subject principal.");
        }

        clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
        clientContext.take(new byte[0]);
        Set<KerberosTicket> clientTickets =
                clientSubject.getPrivateCredentials(KerberosTicket.class);
        boolean tgtFound = false;
        boolean tgsFound = false;
        for (KerberosTicket clientTicket : clientTickets) {
            String cname = clientTicket.getClient().getName();
            String sname = clientTicket.getServer().getName();
            if (cname.equals(clientKDC2Name)) {
                if (sname.equals(krbtgtKDC2 +
                        PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2)) {
                    tgtFound = true;
                } else if (sname.equals(serviceKDC2Name)) {
                    tgsFound = true;
                }
            }
            if (DEBUG) {
                System.out.println("Client subject KerberosTicket:");
                System.out.println(clientTicket);
            }
        }
        if (!tgtFound || !tgsFound) {
            throw new Exception("client subject tickets (TGT/TGS) not found.");
        }
        int numOfTickets = clientTickets.size();
        clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
        clientContext.take(new byte[0]);
        clientContext.status();
        int newNumOfTickets =
                clientSubject.getPrivateCredentials(KerberosTicket.class).size();
        if (DEBUG) {
            System.out.println("client subject number of tickets: " +
                    numOfTickets);
            System.out.println("client subject new number of tickets: " +
                    newNumOfTickets);
        }
        if (numOfTickets != newNumOfTickets) {
            throw new Exception("Useless client subject TGS request because" +
                    " TGS was not found in private credentials.");
        }
    }

    /*
     * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE)
     * will authenticate on itself on behalf of the client
     * (test@DEV.RABBIT.HOLE). Cross-realm referrals will occur
     * when requesting different TGTs and TGSs (including the
     * request for delegated credentials).
     */

    private static void testDelegation() throws Exception {
        Context c = Context.fromUserPass(clientKDC2Name,
                password, false);
        c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
        Context s = Context.fromUserPass(serviceKDC2Name,
                password, true);
        s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
        Context.handshake(c, s);
        Context delegatedContext = s.delegated();
        delegatedContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
        delegatedContext.x().requestMutualAuth(false);
        Context s2 = Context.fromUserPass(serviceKDC2Name,
                password, true);
        s2.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);

        // Test authentication
        Context.handshake(delegatedContext, s2);
        if (!delegatedContext.x().isEstablished() || !s2.x().isEstablished()) {
            throw new Exception("Delegated authentication failed");
        }

        // Test identities
        GSSName contextInitiatorName = delegatedContext.x().getSrcName();
        GSSName contextAcceptorName = delegatedContext.x().getTargName();
        if (DEBUG) {
            System.out.println("Context initiator: " + contextInitiatorName);
            System.out.println("Context acceptor: " + contextAcceptorName);
        }
        if (!contextInitiatorName.toString().equals(clientKDC2Name) ||
                !contextAcceptorName.toString().equals(serviceName)) {
            throw new Exception("Unexpected initiator or acceptor names");
        }
    }

    /*
     * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE)
     * will get a TGS ticket for itself on behalf of the client
     * (user@RABBIT.HOLE). Cross-realm referrals will be handled
     * in S4U2Self requests because the user and the server are
     * on different realms.
     */

    private static void testImpersonation() throws Exception {
        testImpersonationSingle();

        // Try a second time to force the use of the Referrals Cache.
        // During this execution, the referral ticket from RABBIT.HOLE
        // to DEV.RABBIT.HOLE (upon the initial S4U2Self message) will
        // be obtained from the Cache.
        testImpersonationSingle();
    }

    private static void testImpersonationSingle() throws Exception {
        Context s = Context.fromUserPass(serviceKDC2Name, password, true);
        s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
        GSSName impName = s.impersonate(userKDC1Name).cred().getName();
        if (DEBUG) {
            System.out.println("Impersonated name: " + impName);
        }
        if (!impName.toString().equals(userKDC1Name)) {
            throw new Exception("Unexpected impersonated name");
        }
    }

    /*
     * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE)
     * will use delegated credentials (user@RABBIT.HOLE) to
     * authenticate in the backend (cifs/backend.rabbit.hole@RABBIT.HOLE).
     * Cross-realm referrals will be handled in S4U2Proxy requests
     * because the server and the backend are on different realms.
     */

    private static void testDelegationWithReferrals() throws Exception {
        testDelegationWithReferralsSingle();

        // Try a second time to force the use of the Referrals Cache.
        // During this execution, the referral ticket from RABBIT.HOLE
        // to DEV.RABBIT.HOLE (upon the initial S4U2Proxy message) will
        // be obtained from the Cache.
        testDelegationWithReferralsSingle();
    }

    private static void testDelegationWithReferralsSingle() throws Exception {
        Context c = Context.fromUserPass(userKDC1Name, password, false);
        c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
        Context s = Context.fromUserPass(serviceKDC2Name, password, true);
        s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
        Context.handshake(c, s);
        Context delegatedContext = s.delegated();
        delegatedContext.startAsClient(backendServiceName,
                GSSUtil.GSS_KRB5_MECH_OID);
        delegatedContext.x().requestMutualAuth(false);
        Context b = Context.fromUserPass(backendKDC1Name, password, true);
        b.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);

        // Test authentication
        Context.handshake(delegatedContext, b);
        if (!delegatedContext.x().isEstablished() || !b.x().isEstablished()) {
            throw new Exception("Delegated authentication failed");
        }

        // Test identities
        GSSName contextInitiatorName = delegatedContext.x().getSrcName();
        GSSName contextAcceptorName = delegatedContext.x().getTargName();
        if (DEBUG) {
            System.out.println("Context initiator: " + contextInitiatorName);
            System.out.println("Context acceptor: " + contextAcceptorName);
        }
        if (!contextInitiatorName.toString().equals(userKDC1Name) ||
                !contextAcceptorName.toString().equals(backendServiceName)) {
            throw new Exception("Unexpected initiator or acceptor names");
        }
    }

    /*
     * The client tries to get a TGT (AS protocol) as in testSubjectCredentials
     * but without the canonicalize setting in krb5.conf. The KDC
     * must not return a referral but a failure because the client
     * is not in the local database.
     */

    private static void testNoCanonicalize() throws Exception {
        System.setProperty("java.security.krb5.conf",
                krbConfigNameNoCanonicalize);
        Config.refresh();
        try {
            Context.fromUserPass(new Subject(),
                    clientKDC1Name, password, false);
            throw new Exception("should not succeed");
        } catch (LoginException e) {
            // expected
        }
    }
}

Messung V0.5
C=93 H=91 G=91

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge