提交 d366bf08 编写于 作者: W weijun

8005447: default principal should act as anyone

Reviewed-by: valeriep
上级 23b7eafe
......@@ -86,7 +86,7 @@ class InitSecContextToken extends InitialToken {
* For the context acceptor to call. It reads the bytes out of an
* InputStream and constructs an InitSecContextToken with them.
*/
InitSecContextToken(Krb5Context context, EncryptionKey[] keys,
InitSecContextToken(Krb5Context context, Krb5AcceptCredential cred,
InputStream is)
throws IOException, GSSException, KrbException {
......@@ -105,7 +105,7 @@ class InitSecContextToken extends InitialToken {
if (context.getChannelBinding() != null) {
addr = context.getChannelBinding().getInitiatorAddress();
}
apReq = new KrbApReq(apReqBytes, keys, addr);
apReq = new KrbApReq(apReqBytes, cred, addr);
//debug("\nReceived AP-REQ and authenticated it.\n");
EncryptionKey sessionKey = apReq.getCreds().getSessionKey();
......
......@@ -45,13 +45,10 @@ import javax.security.auth.DestroyFailedException;
public class Krb5AcceptCredential
implements Krb5CredElement {
private static final long serialVersionUID = 7714332137352567952L;
private final Krb5NameElement name;
private final ServiceCreds screds;
private Krb5NameElement name;
private Krb5Util.ServiceCreds screds;
private Krb5AcceptCredential(Krb5NameElement name, Krb5Util.ServiceCreds creds) {
private Krb5AcceptCredential(Krb5NameElement name, ServiceCreds creds) {
/*
* Initialize this instance with the data from the acquired
* KerberosKey. This class needs to be a KerberosKey too
......@@ -69,11 +66,11 @@ public class Krb5AcceptCredential
name.getKrb5PrincipalName().getName());
final AccessControlContext acc = AccessController.getContext();
Krb5Util.ServiceCreds creds = null;
ServiceCreds creds = null;
try {
creds = AccessController.doPrivileged(
new PrivilegedExceptionAction<Krb5Util.ServiceCreds>() {
public Krb5Util.ServiceCreds run() throws Exception {
new PrivilegedExceptionAction<ServiceCreds>() {
public ServiceCreds run() throws Exception {
return Krb5Util.getServiceCreds(
caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller,
serverPrinc, acc);
......@@ -92,8 +89,10 @@ public class Krb5AcceptCredential
if (name == null) {
String fullName = creds.getName();
name = Krb5NameElement.getInstance(fullName,
if (fullName != null) {
name = Krb5NameElement.getInstance(fullName,
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
}
}
return new Krb5AcceptCredential(name, creds);
......@@ -153,8 +152,8 @@ public class Krb5AcceptCredential
return Krb5MechFactory.PROVIDER;
}
EncryptionKey[] getKrb5EncryptionKeys() {
return screds.getEKeys();
public EncryptionKey[] getKrb5EncryptionKeys(PrincipalName princ) {
return screds.getEKeys(princ);
}
/**
......
......@@ -818,16 +818,23 @@ class Krb5Context implements GSSContextSpi {
}
myName = (Krb5NameElement) myCred.getName();
checkPermission(myName.getKrb5PrincipalName().getName(),
"accept");
EncryptionKey[] secretKeys =
((Krb5AcceptCredential) myCred).getKrb5EncryptionKeys();
// If there is already a bound name, check now
if (myName != null) {
Krb5MechFactory.checkAcceptCredPermission(myName, myName);
}
InitSecContextToken token = new InitSecContextToken(this,
secretKeys, is);
(Krb5AcceptCredential) myCred, is);
PrincipalName clientName = token.getKrbApReq().getClient();
peerName = Krb5NameElement.getInstance(clientName);
// If unbound, check after the bound name is found
if (myName == null) {
myName = Krb5NameElement.getInstance(
token.getKrbApReq().getCreds().getServer());
Krb5MechFactory.checkAcceptCredPermission(myName, myName);
}
if (getMutualAuthState()) {
retVal = new AcceptSecContextToken(this,
token.getKrbApReq()).encode();
......
......@@ -158,7 +158,7 @@ public final class Krb5MechFactory implements MechanismFactory {
public static void checkAcceptCredPermission(Krb5NameElement name,
GSSNameSpi originalName) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (sm != null && name != null) {
ServicePermission perm = new ServicePermission
(name.getKrb5PrincipalName().getName(), "accept");
try {
......
......@@ -186,114 +186,6 @@ public class Krb5Util {
return subject;
}
/**
* Credentials of a service, the private secret to authenticate its
* identity, which can be:
* 1. Some KerberosKeys (generated from password)
* 2. A KeyTab (for a typical service)
* 3. A TGT (for S4U2proxy extension)
*
* Note that some creds can coexist. For example, a user2user service
* can use its keytab (or keys) if the client can successfully obtain a
* normal service ticket, otherwise, it can uses the TGT (actually, the
* session key of the TGT) if the client can only acquire a service ticket
* of ENC-TKT-IN-SKEY style.
*/
public static class ServiceCreds {
private KerberosPrincipal kp;
private List<KeyTab> ktabs;
private List<KerberosKey> kk;
private Subject subj;
private KerberosTicket tgt;
private static ServiceCreds getInstance(
Subject subj, String serverPrincipal) {
ServiceCreds sc = new ServiceCreds();
sc.subj = subj;
for (KerberosPrincipal p: subj.getPrincipals(KerberosPrincipal.class)) {
if (serverPrincipal == null ||
p.getName().equals(serverPrincipal)) {
sc.kp = p;
serverPrincipal = p.getName();
break;
}
}
if (sc.kp == null) {
// Compatibility with old behavior: even when there is no
// KerberosPrincipal, we can find one from KerberosKeys
List<KerberosKey> keys = SubjectComber.findMany(
subj, serverPrincipal, null, KerberosKey.class);
if (!keys.isEmpty()) {
sc.kp = keys.get(0).getPrincipal();
serverPrincipal = sc.kp.getName();
if (DEBUG) {
System.out.println(">>> ServiceCreds: no kp?"
+ " find one from kk: " + serverPrincipal);
}
} else {
return null;
}
}
sc.ktabs = SubjectComber.findMany(
subj, null, null, KeyTab.class);
sc.kk = SubjectComber.findMany(
subj, serverPrincipal, null, KerberosKey.class);
sc.tgt = SubjectComber.find(
subj, null, serverPrincipal, KerberosTicket.class);
if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) {
return null;
}
return sc;
}
public String getName() {
return kp.getName();
}
public KerberosKey[] getKKeys() {
List<KerberosKey> keys = new ArrayList<>();
for (KerberosKey k: kk) {
keys.add(k);
}
for (KeyTab ktab: ktabs) {
for (KerberosKey k: ktab.getKeys(kp)) {
keys.add(k);
}
}
return keys.toArray(new KerberosKey[keys.size()]);
}
public EncryptionKey[] getEKeys() {
KerberosKey[] kkeys = getKKeys();
EncryptionKey[] ekeys = new EncryptionKey[kkeys.length];
for (int i=0; i<ekeys.length; i++) {
ekeys[i] = new EncryptionKey(
kkeys[i].getEncoded(), kkeys[i].getKeyType(),
new Integer(kkeys[i].getVersionNumber()));
}
return ekeys;
}
public Credentials getInitCred() {
if (tgt == null) {
return null;
}
try {
return ticketToCreds(tgt);
} catch (KrbException | IOException e) {
return null;
}
}
public void destroy() {
kp = null;
ktabs = null;
kk = null;
tgt = null;
}
}
/**
* Retrieves the ServiceCreds for the specified server principal from
* the Subject in the specified AccessControlContext. If not found, and if
......@@ -361,5 +253,4 @@ public class Krb5Util {
return KerberosSecrets.getJavaxSecurityAuthKerberosAccess().
keyTabGetEncryptionKeys(ktab, cname);
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package sun.security.jgss.krb5;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KeyTab;
import javax.security.auth.Subject;
import sun.security.krb5.Credentials;
import sun.security.krb5.EncryptionKey;
import sun.security.krb5.KrbException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import sun.security.krb5.*;
import sun.security.krb5.internal.Krb5;
/**
* Credentials of a kerberos acceptor. A KerberosPrincipal object (kp) is
* the principal. It can be specified as the serverPrincipal argument
* in the getInstance() method, or uses only KerberosPrincipal in the subject.
* Otherwise, the creds object is unbound and kp is null.
*
* The class also encapsulates various secrets, which can be:
*
* 1. Some KerberosKeys (generated from password)
* 2. Some KeyTabs (for a typical service based on keytabs)
* 3. A TGT (for S4U2proxy extension or user2user)
*
* Note that some secrets can coexist. For example, a user2user service
* can use its keytab (or keys) if the client can successfully obtain a
* normal service ticket, or it can use the TGT (actually, the session key
* of the TGT) if the client can only acquire a service ticket
* of ENC-TKT-IN-SKEY style.
*
* @since 1.8
*/
public final class ServiceCreds {
// The principal, or null if unbound
private KerberosPrincipal kp;
// All principals in the subject's princ set
private Set<KerberosPrincipal> allPrincs;
// All private credentials that can be used
private List<KeyTab> ktabs;
private List<KerberosKey> kk;
private KerberosTicket tgt;
private boolean destroyed;
private ServiceCreds() {
// Make sure this class cannot be instantiated externally.
}
/**
* Creates a ServiceCreds object based on info in a Subject for
* a given principal name (if specified).
* @return the object, or null if there is no private creds for it
*/
public static ServiceCreds getInstance(
Subject subj, String serverPrincipal) {
ServiceCreds sc = new ServiceCreds();
sc.allPrincs =
subj.getPrincipals(KerberosPrincipal.class);
// Compatibility. A key implies its own principal
for (KerberosKey key: SubjectComber.findMany(
subj, serverPrincipal, null, KerberosKey.class)) {
sc.allPrincs.add(key.getPrincipal());
}
if (serverPrincipal != null) { // A named principal
sc.kp = new KerberosPrincipal(serverPrincipal);
} else {
if (sc.allPrincs.size() == 1) { // choose the only one
sc.kp = sc.allPrincs.iterator().next();
serverPrincipal = sc.kp.getName();
}
}
sc.ktabs = SubjectComber.findMany(
subj, serverPrincipal, null, KeyTab.class);
sc.kk = SubjectComber.findMany(
subj, serverPrincipal, null, KerberosKey.class);
sc.tgt = SubjectComber.find(
subj, null, serverPrincipal, KerberosTicket.class);
if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) {
return null;
}
sc.destroyed = false;
return sc;
}
// can be null
public String getName() {
if (destroyed) {
throw new IllegalStateException("This object is destroyed");
}
return kp == null ? null : kp.getName();
}
/**
* Gets keys for someone unknown.
* Used by TLS or as a fallback in getEKeys(). Can still return an
* empty array.
*/
public KerberosKey[] getKKeys() {
if (destroyed) {
throw new IllegalStateException("This object is destroyed");
}
if (kp != null) {
return getKKeys(kp);
} else if (!allPrincs.isEmpty()) {
return getKKeys(allPrincs.iterator().next());
}
return new KerberosKey[0];
}
/**
* Get kkeys for a principal,
* @param princ the target name initiator requests. Not null.
* @return keys for the princ, never null, might be empty
*/
private KerberosKey[] getKKeys(KerberosPrincipal princ) {
ArrayList<KerberosKey> keys = new ArrayList<>();
if (kp != null && !princ.equals(kp)) {
return new KerberosKey[0]; // Not me
}
if (!allPrincs.contains(princ)) {
return new KerberosKey[0]; // Not someone I know, This check
// is necessary but a KeyTab has
// no principal name recorded.
}
for (KerberosKey k: kk) {
if (k.getPrincipal().equals(princ)) {
keys.add(k);
}
}
for (KeyTab ktab: ktabs) {
for (KerberosKey k: ktab.getKeys(princ)) {
keys.add(k);
}
}
return keys.toArray(new KerberosKey[keys.size()]);
}
/**
* Gets EKeys for a principal.
* @param princ the target name initiator requests. Not null.
* @return keys for the princ, never null, might be empty
*/
public EncryptionKey[] getEKeys(PrincipalName princ) {
if (destroyed) {
throw new IllegalStateException("This object is destroyed");
}
KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName()));
if (kkeys.length == 0) {
// Note: old JDK does not perform real name checking. If the
// acceptor starts by name A but initiator requests for B,
// as long as their keys match (i.e. A's keys can decrypt B's
// service ticket), the authentication is OK. There are real
// customers depending on this to use different names for a
// single service.
kkeys = getKKeys();
}
EncryptionKey[] ekeys = new EncryptionKey[kkeys.length];
for (int i=0; i<ekeys.length; i++) {
ekeys[i] = new EncryptionKey(
kkeys[i].getEncoded(), kkeys[i].getKeyType(),
new Integer(kkeys[i].getVersionNumber()));
}
return ekeys;
}
public Credentials getInitCred() {
if (destroyed) {
throw new IllegalStateException("This object is destroyed");
}
if (tgt == null) {
return null;
}
try {
return Krb5Util.ticketToCreds(tgt);
} catch (KrbException | IOException e) {
return null;
}
}
public void destroy() {
// Do not wipe out real keys because they are references to the
// priv creds in subject. Just make it useless.
destroyed = true;
kp = null;
ktabs.clear();
kk.clear();
tgt = null;
}
}
......@@ -33,6 +33,7 @@ import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KeyTab;
/**
......@@ -84,19 +85,37 @@ class SubjectComber {
} else {
List<T> answer = (oneOnly ? null : new ArrayList<T>());
if (credClass == KeyTab.class) { // Principal un-related
// We are looking for credentials unrelated to serverPrincipal
Iterator<T> iterator =
subject.getPrivateCredentials(credClass).iterator();
while (iterator.hasNext()) {
T t = iterator.next();
if (DEBUG) {
System.out.println("Found " + credClass.getSimpleName());
if (credClass == KeyTab.class) {
// TODO: There is currently no good way to filter out keytabs
// not for serverPrincipal. We can only check the principal
// set. If the server is not there, we can be sure none of the
// keytabs should be used, otherwise, use all for safety.
boolean useAll = false;
if (serverPrincipal != null) {
for (KerberosPrincipal princ:
subject.getPrincipals(KerberosPrincipal.class)) {
if (princ.getName().equals(serverPrincipal)) {
useAll = true;
break;
}
}
if (oneOnly) {
return t;
} else {
answer.add(t);
} else {
useAll = true;
}
if (useAll) {
Iterator<KeyTab> iterator =
subject.getPrivateCredentials(KeyTab.class).iterator();
while (iterator.hasNext()) {
KeyTab t = iterator.next();
if (DEBUG) {
System.out.println("Found " + credClass.getSimpleName()
+ " " + t);
}
if (oneOnly) {
return t;
} else {
answer.add(credClass.cast(t));
}
}
}
} else if (credClass == KerberosKey.class) {
......@@ -114,11 +133,6 @@ class SubjectComber {
if (oneOnly) {
return t;
} else {
if (serverPrincipal == null) {
// Record name so that keys returned will all
// belong to the same principal
serverPrincipal = name;
}
answer.add(credClass.cast(t));
}
}
......
......@@ -34,6 +34,7 @@ package sun.security.krb5;
import sun.security.krb5.internal.*;
import sun.security.krb5.internal.crypto.*;
import sun.security.krb5.internal.rcache.*;
import sun.security.jgss.krb5.Krb5AcceptCredential;
import java.net.InetAddress;
import sun.security.util.*;
import java.io.IOException;
......@@ -135,13 +136,13 @@ public class KrbApReq {
*/
// Used in InitSecContextToken (for AP_REQ and not TGS REQ)
public KrbApReq(byte[] message,
EncryptionKey[] keys,
Krb5AcceptCredential cred,
InetAddress initiator)
throws KrbException, IOException {
obuf = message;
if (apReqMessg == null)
decode();
authenticate(keys, initiator);
authenticate(cred, initiator);
}
/**
......@@ -260,10 +261,11 @@ public class KrbApReq {
}
}
private void authenticate(EncryptionKey[] keys, InetAddress initiator)
private void authenticate(Krb5AcceptCredential cred, InetAddress initiator)
throws KrbException, IOException {
int encPartKeyType = apReqMessg.ticket.encPart.getEType();
Integer kvno = apReqMessg.ticket.encPart.getKeyVersionNumber();
EncryptionKey[] keys = cred.getKrb5EncryptionKeys(apReqMessg.ticket.sname);
EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, kvno, keys);
if (dkey == null) {
......
......@@ -382,9 +382,15 @@ public class KeyTab implements KeyTabConstants {
*/
public void addEntry(PrincipalName service, char[] psswd,
int kvno, boolean append) throws KrbException {
addEntry(service, service.getSalt(), psswd, kvno, append);
}
// Called by KDC test
public void addEntry(PrincipalName service, String salt, char[] psswd,
int kvno, boolean append) throws KrbException {
EncryptionKey[] encKeys = EncryptionKey.acquireSecretKeys(
psswd, service.getSalt());
psswd, salt);
// There should be only one maximum KVNO value for all etypes, so that
// all added keys can have the same KVNO.
......
......@@ -36,6 +36,7 @@ import javax.security.auth.login.LoginException;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.krb5.Krb5Util;
import sun.security.jgss.krb5.ServiceCreds;
import sun.security.krb5.PrincipalName;
import sun.security.ssl.Krb5Proxy;
......@@ -62,7 +63,7 @@ public class Krb5ProxyImpl implements Krb5Proxy {
@Override
public SecretKey[] getServerKeys(AccessControlContext acc)
throws LoginException {
Krb5Util.ServiceCreds serviceCreds =
ServiceCreds serviceCreds =
Krb5Util.getServiceCreds(GSSCaller.CALLER_SSL_SERVER, null, acc);
return serviceCreds != null ? serviceCreds.getKKeys() :
new KerberosKey[0];
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* 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 8005447
* @compile -XDignore.symbol.file ServiceCredsCombination.java
* @run main ServiceCredsCombination
* @summary default principal can act as anyone
*/
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Objects;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KeyTab;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import sun.security.jgss.GSSUtil;
public class ServiceCredsCombination {
public static void main(String[] args) throws Exception {
// pass
check("a", "a", princ("a"), key("a"));
check(null, "a", princ("a"), key("a"));
check("x", "NOCRED", princ("a"), key("a"));
// two pass
check("a", "a", princ("a"), key("a"), princ("b"), key("b"));
check("b", "b", princ("a"), key("a"), princ("b"), key("b"));
check(null, null, princ("a"), key("a"), princ("b"), key("b"));
check("x", "NOCRED", princ("a"), key("a"), princ("b"), key("b"));
// old ktab
check("b", "b", princ("b"), oldktab());
check("x", "NOCRED", princ("b"), oldktab());
check(null, "b", princ("b"), oldktab());
// Two old ktab
check("a", "a", princ("a"), princ("b"), oldktab(), oldktab());
check("b", "b", princ("a"), princ("b"), oldktab(), oldktab());
check(null, null, princ("a"), princ("b"), oldktab(), oldktab());
check("x", "NOCRED", princ("a"), princ("b"), oldktab(), oldktab());
// pass + old ktab
check("a", "a", princ("a"), princ("b"), key("a"), oldktab());
check("b", "b", princ("a"), princ("b"), key("a"), oldktab());
check(null, null, princ("a"), princ("b"), key("a"), oldktab());
check("x", "NOCRED", princ("a"), princ("b"), key("a"), oldktab());
// Compatibility, automatically add princ for keys
check(null, "a", key("a"));
check("x", "NOCRED", key("a"));
check(null, "a", key("a"), oldktab());
check("x", "NOCRED", key("a"), oldktab());
// Limitation, "a" has no key, but we don't know oldktab() is for "b"
check("a", "a", princ("a"), princ("b"), oldktab());
}
/**
* Checks the correct bound
* @param a get a creds for this principal, null for default one
* @param b expected name, null for still unbound, "NOCRED" for no creds
* @param objs princs, keys and keytabs in the subject
*/
private static void check(final String a, String b, Object... objs)
throws Exception {
Subject subj = new Subject();
for (Object obj: objs) {
if (obj instanceof KerberosPrincipal) {
subj.getPrincipals().add((KerberosPrincipal)obj);
} else if (obj instanceof KerberosKey || obj instanceof KeyTab) {
subj.getPrivateCredentials().add(obj);
}
}
final GSSManager man = GSSManager.getInstance();
try {
String result = Subject.doAs(
subj, new PrivilegedExceptionAction<String>() {
@Override
public String run() throws GSSException {
GSSCredential cred = man.createCredential(
a == null ? null : man.createName(r(a), null),
GSSCredential.INDEFINITE_LIFETIME,
GSSUtil.GSS_KRB5_MECH_OID,
GSSCredential.ACCEPT_ONLY);
GSSName name = cred.getName();
return name == null ? null : name.toString();
}
});
if (!Objects.equals(result, r(b))) {
throw new Exception("Check failed: getInstance(" + a
+ ") has name " + result + ", not " + b);
}
} catch (PrivilegedActionException e) {
if (!"NOCRED".equals(b)) {
throw new Exception("Check failed: getInstance(" + a
+ ") is null " + ", but not one with name " + b);
}
}
}
private static String r(String s) {
return s == null ? null : (s+"@REALM");
}
private static KerberosPrincipal princ(String s) {
return new KerberosPrincipal(r(s));
}
private static KerberosKey key(String s) {
return new KerberosKey(princ(s), new byte[0], 0, 0);
}
private static KeyTab oldktab() {
return KeyTab.getInstance();
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* 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 9999999
* @summary default principal can act as anyone
* @compile -XDignore.symbol.file AcceptPermissions.java
* @run main/othervm AcceptPermissions
*/
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.Permission;
import javax.security.auth.kerberos.ServicePermission;
import sun.security.jgss.GSSUtil;
import java.util.*;
public class AcceptPermissions extends SecurityManager {
private static Map<Permission,String> perms = new HashMap<>();
@Override
public void checkPermission(Permission perm) {
if (!(perm instanceof ServicePermission)) {
return;
}
ServicePermission sp = (ServicePermission)perm;
if (!sp.getActions().equals("accept")) {
return;
}
// We only care about accept ServicePermission in this test
try {
super.checkPermission(sp);
} catch (SecurityException se) {
if (perms.containsKey(sp)) {
perms.put(sp, "checked");
} else {
throw se; // We didn't expect this is needed
}
}
}
// Fills in permissions we are expecting
private static void initPerms(String... names) {
perms.clear();
for (String name: names) {
perms.put(new ServicePermission(
name + "@" + OneKDC.REALM, "accept"), "expected");
}
}
// Checks if they are all checked
private static void checkPerms() {
for (Map.Entry<Permission,String> entry: perms.entrySet()) {
if (entry.getValue().equals("expected")) {
throw new RuntimeException(
"Expected but not used: " + entry.getKey());
}
}
}
public static void main(String[] args) throws Exception {
System.setSecurityManager(new AcceptPermissions());
new OneKDC(null).writeJAASConf();
String two = "two {\n"
+ " com.sun.security.auth.module.Krb5LoginModule required"
+ " principal=\"" + OneKDC.SERVER + "\" useKeyTab=true"
+ " isInitiator=false storeKey=true;\n"
+ " com.sun.security.auth.module.Krb5LoginModule required"
+ " principal=\"" + OneKDC.BACKEND + "\" useKeyTab=true"
+ " isInitiator=false storeKey=true;\n"
+ "};\n";
Files.write(Paths.get(OneKDC.JAAS_CONF), two.getBytes(),
StandardOpenOption.APPEND);
Context c, s;
// In all cases, a ServicePermission on the acceptor name is needed
// for a handshake. For default principal with no predictable name,
// permission not needed (yet) for credentials creation.
// Named principal
initPerms(OneKDC.SERVER);
c = Context.fromJAAS("client");
s = Context.fromJAAS("server");
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
checkPerms();
initPerms(OneKDC.SERVER);
Context.handshake(c, s);
checkPerms();
// Named principal (even if there are 2 JAAS modules)
initPerms(OneKDC.SERVER);
c = Context.fromJAAS("client");
s = Context.fromJAAS("two");
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
checkPerms();
initPerms(OneKDC.SERVER);
Context.handshake(c, s);
checkPerms();
// Default principal with a predictable name
initPerms(OneKDC.SERVER);
c = Context.fromJAAS("client");
s = Context.fromJAAS("server");
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
checkPerms();
initPerms(OneKDC.SERVER);
Context.handshake(c, s);
checkPerms();
// Default principal with no predictable name
initPerms(); // permission not needed for cred !!!
c = Context.fromJAAS("client");
s = Context.fromJAAS("two");
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
checkPerms();
initPerms(OneKDC.SERVER); // still needed for handshake !!!
Context.handshake(c, s);
checkPerms();
}
}
......@@ -24,6 +24,7 @@
/*
* @test
* @bug 6716534
* @compile -XDignore.symbol.file CleanState.java
* @run main/othervm CleanState
* @summary Krb5LoginModule has not cleaned temp info between authentication attempts
*/
......
......@@ -131,21 +131,24 @@ public class Context {
return out;
}
/**
* Logins with username/password as a new Subject
*/
public static Context fromUserPass(
String user, char[] pass, boolean storeKey) throws Exception {
return fromUserPass(null, user, pass, storeKey);
return fromUserPass(new Subject(), user, pass, storeKey);
}
/**
* Logins with a username and a password, using Krb5LoginModule directly
* @param s existing subject, test multiple princ & creds for single subj
* @param storeKey true if key should be saved, used on acceptor side
* Logins with username/password as an existing Subject. The
* same subject can be used multiple times to simulate multiple logins.
* @param s existing subject
*/
public static Context fromUserPass(Subject s,
String user, char[] pass, boolean storeKey) throws Exception {
Context out = new Context();
out.name = user;
out.s = s == null ? new Subject() : s;
out.s = s;
Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<>();
Map<String, Object> shared = new HashMap<>();
......@@ -172,14 +175,23 @@ public class Context {
}
/**
* Logins with a username and a keytab, using Krb5LoginModule directly
* @param storeKey true if key should be saved, used on acceptor side
* Logins with username/keytab as an existing Subject. The
* same subject can be used multiple times to simulate multiple logins.
* @param s existing subject
*/
public static Context fromUserKtab(String user, String ktab, boolean storeKey)
throws Exception {
public static Context fromUserKtab(
String user, String ktab, boolean storeKey) throws Exception {
return fromUserKtab(new Subject(), user, ktab, storeKey);
}
/**
* Logins with username/keytab as a new subject,
*/
public static Context fromUserKtab(Subject s,
String user, String ktab, boolean storeKey) throws Exception {
Context out = new Context();
out.name = user;
out.s = new Subject();
out.s = s;
Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<>();
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* 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 8005447
* @summary default principal can act as anyone
* @compile -XDignore.symbol.file DiffNameSameKey.java
* @run main/othervm/fail DiffNameSameKey a
* @run main/othervm DiffNameSameKey b
*/
import sun.security.jgss.GSSUtil;
import sun.security.krb5.PrincipalName;
/**
* This test confirms the compatibility codes described in
* ServiceCreds.getEKeys(). If the acceptor starts as x.us.oracle.com
* but client requests for x.us, as long as the KDC supports both names
* and the keys are the same, the auth should succeed.
*/
public class DiffNameSameKey {
static final String SERVER2 = "x" + OneKDC.SERVER;
public static void main(String[] args) throws Exception {
OneKDC kdc = new KDC2();
kdc.addPrincipal(SERVER2, "samepass".toCharArray());
kdc.addPrincipal(OneKDC.SERVER, "samepass".toCharArray());
kdc.writeJAASConf();
kdc.writeKtab(OneKDC.KTAB);
Context c, s;
c = Context.fromJAAS("client");
s = Context.fromJAAS("server");
switch (args[0]) {
case "a": // If server starts as another service, should fail
c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID);
s.startAsServer(SERVER2.replace('/', '@'),
GSSUtil.GSS_SPNEGO_MECH_OID);
break;
case "b": // If client requests another server with the same keys,
// succeed to be compatible
c.startAsClient(SERVER2, GSSUtil.GSS_SPNEGO_MECH_OID);
s.startAsServer(OneKDC.SERVER.replace('/', '@'),
GSSUtil.GSS_SPNEGO_MECH_OID);
break;
}
Context.handshake(c, s);
s.dispose();
c.dispose();
}
/**
* This KDC returns the same salt for all principals. This means same
* passwords generate same keys.
*/
static class KDC2 extends OneKDC {
KDC2() throws Exception {
super(null);
}
@Override
public String getSalt(PrincipalName pn) {
return "SAME";
}
}
}
......@@ -24,6 +24,7 @@
/*
* @test
* @bug 6894072
* @compile -XDignore.symbol.file DynamicKeytab.java
* @run main/othervm DynamicKeytab
* @summary always refresh keytab
*/
......
......@@ -285,10 +285,12 @@ public class KDC {
if (Character.isDigit(pass[pass.length-1])) {
kvno = pass[pass.length-1] - '0';
}
ktab.addEntry(new PrincipalName(name,
name.indexOf('/') < 0 ?
PrincipalName.KRB_NT_UNKNOWN :
PrincipalName.KRB_NT_SRV_HST),
PrincipalName pn = new PrincipalName(name,
name.indexOf('/') < 0 ?
PrincipalName.KRB_NT_UNKNOWN :
PrincipalName.KRB_NT_SRV_HST);
ktab.addEntry(pn,
getSalt(pn),
pass,
kvno,
true);
......@@ -534,7 +536,7 @@ public class KDC {
if (pass == null) {
throw new KrbException(server?
Krb5.KDC_ERR_S_PRINCIPAL_UNKNOWN:
Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN, pn.toString());
}
return pass;
}
......@@ -544,7 +546,7 @@ public class KDC {
* @param p principal
* @return the salt
*/
private String getSalt(PrincipalName p) {
protected String getSalt(PrincipalName p) {
String pn = p.toString();
if (p.getRealmString() == null) {
pn = pn + "@" + getRealm();
......
......@@ -38,7 +38,7 @@ import sun.security.jgss.GSSUtil;
*
* 1. If there is only KerberosKeys in private credential set and no
* KerberosPrincipal. JAAS login should go on.
* 2. Even if KeyTab is used, user can still get KerberosKeys from
* 2. If KeyTab is used, user won't get KerberosKeys from
* private credentials set.
*/
public class KeyTabCompat {
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* 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 8005447
* @summary default principal can act as anyone
* @compile -XDignore.symbol.file TwoOrThree.java
* @run main/othervm TwoOrThree first first
* @run main/othervm/fail TwoOrThree first second
* @run main/othervm TwoOrThree - first
* @run main/othervm TwoOrThree - second
* @run main/othervm/fail TwoOrThree - third
*/
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import javax.security.auth.Subject;
import sun.security.jgss.GSSUtil;
/*
* The JAAS login has two krb5 modules
* 1. principal is A
* 2. principal is B
* A named principal can only accept itself. The default principal can accept
* either, but not any other service even if the keytab also include its keys.
*/
public class TwoOrThree {
public static void main(String[] args) throws Exception {
String server = args[0].equals("-") ? null : args[0];
String target = args[1];
OneKDC kdc = new OneKDC(null);
kdc.addPrincipal("first", "first".toCharArray());
kdc.addPrincipal("second", "second".toCharArray());
kdc.addPrincipal("third", "third".toCharArray());
kdc.writeKtab(OneKDC.KTAB);
Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
// Using keytabs
Subject sub4s = new Subject();
Context.fromUserKtab(sub4s, "first", OneKDC.KTAB, true);
Context s = Context.fromUserKtab(sub4s, "second", OneKDC.KTAB, true);
c.startAsClient(target, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID);
Context.handshake(c, s);
// Using keys
sub4s = new Subject();
Context.fromUserPass(sub4s, "first", "first".toCharArray(), true);
s = Context.fromUserPass(sub4s, "second", "second".toCharArray(), true);
c.startAsClient(target, GSSUtil.GSS_KRB5_MECH_OID);
s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID);
Context.handshake(c, s);
s.dispose();
c.dispose();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册