8243592: Subject$SecureSet::addAll should not call contains(null)
Reviewed-by: mullan
This commit is contained in:
parent
e2353cc324
commit
fc1b24e4e8
src/java.base/share/classes/javax/security/auth
test/jdk/javax/security/auth/Subject
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2020, 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
|
||||
@ -203,18 +203,20 @@ public final class Subject implements java.io.Serializable {
|
||||
* Sets.
|
||||
*/
|
||||
public Subject(boolean readOnly, Set<? extends Principal> principals,
|
||||
Set<?> pubCredentials, Set<?> privCredentials)
|
||||
{
|
||||
collectionNullClean(principals);
|
||||
collectionNullClean(pubCredentials);
|
||||
collectionNullClean(privCredentials);
|
||||
Set<?> pubCredentials, Set<?> privCredentials) {
|
||||
LinkedList<Principal> principalList
|
||||
= collectionNullClean(principals);
|
||||
LinkedList<Object> pubCredsList
|
||||
= collectionNullClean(pubCredentials);
|
||||
LinkedList<Object> privCredsList
|
||||
= collectionNullClean(privCredentials);
|
||||
|
||||
this.principals = Collections.synchronizedSet(new SecureSet<>
|
||||
(this, PRINCIPAL_SET, principals));
|
||||
this.pubCredentials = Collections.synchronizedSet(new SecureSet<>
|
||||
(this, PUB_CREDENTIAL_SET, pubCredentials));
|
||||
this.privCredentials = Collections.synchronizedSet(new SecureSet<>
|
||||
(this, PRIV_CREDENTIAL_SET, privCredentials));
|
||||
this.principals = Collections.synchronizedSet(
|
||||
new SecureSet<>(this, PRINCIPAL_SET, principalList));
|
||||
this.pubCredentials = Collections.synchronizedSet(
|
||||
new SecureSet<>(this, PUB_CREDENTIAL_SET, pubCredsList));
|
||||
this.privCredentials = Collections.synchronizedSet(
|
||||
new SecureSet<>(this, PRIV_CREDENTIAL_SET, privCredsList));
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
@ -975,8 +977,9 @@ public final class Subject implements java.io.Serializable {
|
||||
|
||||
// Rewrap the principals into a SecureSet
|
||||
try {
|
||||
LinkedList<Principal> principalList = collectionNullClean(inputPrincs);
|
||||
principals = Collections.synchronizedSet(new SecureSet<>
|
||||
(this, PRINCIPAL_SET, inputPrincs));
|
||||
(this, PRINCIPAL_SET, principalList));
|
||||
} catch (NullPointerException npe) {
|
||||
// Sometimes people deserialize the principals set only.
|
||||
// Subject is not accessible, so just don't fail.
|
||||
@ -1001,26 +1004,18 @@ public final class Subject implements java.io.Serializable {
|
||||
* @throws NullPointerException if the specified collection is either
|
||||
* {@code null} or contains a {@code null} element
|
||||
*/
|
||||
private static void collectionNullClean(Collection<?> coll) {
|
||||
boolean hasNullElements = false;
|
||||
private static <E> LinkedList<E> collectionNullClean(
|
||||
Collection<? extends E> coll) {
|
||||
|
||||
Objects.requireNonNull(coll,
|
||||
ResourcesMgr.getString("invalid.null.input.s."));
|
||||
|
||||
try {
|
||||
hasNullElements = coll.contains(null);
|
||||
} catch (NullPointerException npe) {
|
||||
// A null-hostile collection may choose to throw
|
||||
// NullPointerException if contains(null) is called on it
|
||||
// rather than returning false.
|
||||
// If this happens we know the collection is null-clean.
|
||||
hasNullElements = false;
|
||||
} finally {
|
||||
if (hasNullElements) {
|
||||
throw new NullPointerException
|
||||
(ResourcesMgr.getString("invalid.null.input.s."));
|
||||
}
|
||||
LinkedList<E> output = new LinkedList<>();
|
||||
for (E e : coll) {
|
||||
output.add(Objects.requireNonNull(e,
|
||||
ResourcesMgr.getString("invalid.null.input.s.")));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1066,10 +1061,10 @@ public final class Subject implements java.io.Serializable {
|
||||
this.elements = new LinkedList<E>();
|
||||
}
|
||||
|
||||
SecureSet(Subject subject, int which, Set<? extends E> set) {
|
||||
SecureSet(Subject subject, int which, LinkedList<E> list) {
|
||||
this.subject = subject;
|
||||
this.which = which;
|
||||
this.elements = new LinkedList<E>(set);
|
||||
this.elements = list;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
@ -1242,7 +1237,7 @@ public final class Subject implements java.io.Serializable {
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
boolean result = false;
|
||||
|
||||
collectionNullClean(c);
|
||||
c = collectionNullClean(c);
|
||||
|
||||
for (E item : c) {
|
||||
result |= this.add(item);
|
||||
@ -1252,7 +1247,7 @@ public final class Subject implements java.io.Serializable {
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
collectionNullClean(c);
|
||||
c = collectionNullClean(c);
|
||||
|
||||
boolean modified = false;
|
||||
final Iterator<E> e = iterator();
|
||||
@ -1282,7 +1277,7 @@ public final class Subject implements java.io.Serializable {
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
collectionNullClean(c);
|
||||
c = collectionNullClean(c);
|
||||
|
||||
for (Object item : c) {
|
||||
if (this.contains(item) == false) {
|
||||
@ -1294,7 +1289,7 @@ public final class Subject implements java.io.Serializable {
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
collectionNullClean(c);
|
||||
c = collectionNullClean(c);
|
||||
|
||||
boolean modified = false;
|
||||
final Iterator<E> e = iterator();
|
||||
@ -1314,8 +1309,8 @@ public final class Subject implements java.io.Serializable {
|
||||
if (c.contains(next) == false) {
|
||||
e.remove();
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
@ -1443,13 +1438,7 @@ public final class Subject implements java.io.Serializable {
|
||||
|
||||
LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null);
|
||||
|
||||
Subject.collectionNullClean(tmp);
|
||||
|
||||
if (tmp.getClass() != LinkedList.class) {
|
||||
elements = new LinkedList<E>(tmp);
|
||||
} else {
|
||||
elements = tmp;
|
||||
}
|
||||
elements = Subject.collectionNullClean(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
68
test/jdk/javax/security/auth/Subject/UnreliableContains.java
Normal file
68
test/jdk/javax/security/auth/Subject/UnreliableContains.java
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8243592
|
||||
* @summary Subject$SecureSet::addAll should not call contains(null)
|
||||
*/
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UnreliableContains {
|
||||
|
||||
public static void main(String[] args) {
|
||||
MySet<Principal> set = new MySet<>();
|
||||
set.add(null);
|
||||
Subject s = null;
|
||||
try {
|
||||
s = new Subject(false, set, Collections.emptySet(),
|
||||
Collections.emptySet());
|
||||
} catch (NullPointerException e) {
|
||||
// The correct exit
|
||||
return;
|
||||
}
|
||||
// Suppose NPE was not caught. At least null was not added?
|
||||
for (Principal p : s.getPrincipals()) {
|
||||
Objects.requireNonNull(p);
|
||||
}
|
||||
// Still must fail. We don't want this Subject created
|
||||
throw new RuntimeException("Fail");
|
||||
}
|
||||
|
||||
// This is a Map that implements contains(null) differently
|
||||
static class MySet<E> extends HashSet<E> {
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
} else {
|
||||
return super.contains(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user