8267108: Alternate Subject.getSubject and doAs APIs that do not depend on Security Manager APIs

Reviewed-by: mullan
This commit is contained in:
Weijun Wang 2021-11-10 19:35:17 +00:00
parent ce3ed65ac3
commit a5c160c711
20 changed files with 569 additions and 216 deletions

View File

@ -27,18 +27,18 @@ package javax.security.auth;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.text.MessageFormat;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.DomainCombiner;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.security.ProtectionDomain;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
import sun.security.action.GetBooleanAction;
import sun.security.util.ResourcesMgr;
/**
@ -289,9 +289,10 @@ public final class Subject implements java.io.Serializable {
* @deprecated This method depends on {@link AccessControlContext}
* which, in conjunction with
* {@linkplain SecurityManager the Security Manager}, is deprecated
* and subject to removal in a future release. However, obtaining a
* Subject is useful independent of the Security Manager, so a
* replacement for this method may be added in a future release.
* and subject to removal in a future release. However,
* obtaining a Subject is useful independent of the Security Manager.
* Thus, a replacement API named {@link #current()} has been added
* which can be used to obtain the current subject.
*/
@SuppressWarnings("removal")
@Deprecated(since="17", forRemoval=true)
@ -319,6 +320,112 @@ public final class Subject implements java.io.Serializable {
});
}
// Store the current subject in a ThreadLocal when a system property is set.
private static final boolean USE_TL = GetBooleanAction
.privilegedGetProperty("jdk.security.auth.subject.useTL");
private static final InheritableThreadLocal<Subject> SUBJECT_THREAD_LOCAL =
USE_TL ?
new InheritableThreadLocal<>() {
@Override protected Subject initialValue() {
return null;
}
} : null;
/**
* Returns the current subject.
* <p>
* The current subject is installed by the {@link #callAs} method.
* When {@code callAs(subject, action)} is called, {@code action} is
* executed with {@code subject} as its current subject which can be
* retrieved by this method. After {@code action} is finished, the current
* subject is reset to its previous value. The current
* subject is {@code null} before the first call of {@code callAs()}.
* <p>
* When a new thread is created, its current subject is the same as
* the one of its parent thread, and will not change even if
* its parent thread's current subject is changed to another value.
*
* @implNote
* By default, this method returns the same value as
* {@code Subject.getSubject(AccessController.getContext())}. This
* preserves compatibility with code that may still be calling {@code doAs}
* which installs the subject in an {@code AccessControlContext}. However,
* if the system property {@systemProperty jdk.security.auth.subject.useTL}
* is set to {@code true}, the subject is retrieved from an inheritable
* {@code ThreadLocal} object. This behavior is subject to
* change in a future version.
*
* @return the current subject, or {@code null} if a current subject is
* not installed or the current subject is set to {@code null}.
* @see #callAs(Subject, Callable)
* @since 18
*/
@SuppressWarnings("removal")
public static Subject current() {
return USE_TL
? SUBJECT_THREAD_LOCAL.get()
: getSubject(AccessController.getContext());
}
/**
* Executes a {@code Callable} with {@code subject} as the
* current subject.
*
* @implNote
* By default, this method calls {@link #doAs(Subject, PrivilegedExceptionAction)
* Subject.doAs(subject, altAction)} which stores the subject in
* a new {@code AccessControlContext}, where {@code altAction.run()}
* is equivalent to {@code action.call()} and the exception thrown is
* modified to match the specification of this method. This preserves
* compatibility with code that may still be calling
* {@code getSubject(AccessControlContext)} which retrieves the subject
* from an {@code AccessControlContext}. However,
* if the system property {@code jdk.security.auth.subject.useTL}
* is set to {@code true}, the current subject will be stored in an inheritable
* {@code ThreadLocal} object. This behavior is subject to change in a
* future version.
*
* @param subject the {@code Subject} that the specified {@code action}
* will run as. This parameter may be {@code null}.
* @param action the code to be run with {@code subject} as its current
* subject. Must not be {@code null}.
* @param <T> the type of value returned by the {@code call} method
* of {@code action}
* @return the value returned by the {@code call} method of {@code action}
* @throws NullPointerException if {@code action} is {@code null}
* @throws CompletionException if {@code action.call()} throws an exception.
* The cause of the {@code CompletionException} is set to the exception
* thrown by {@code action.call()}.
* @see #current()
* @since 18
*/
public static <T> T callAs(final Subject subject,
final Callable<T> action) throws CompletionException {
if (USE_TL) {
Subject oldSubject = SUBJECT_THREAD_LOCAL.get();
SUBJECT_THREAD_LOCAL.set(subject);
try {
return action.call();
} catch (Exception e) {
throw new CompletionException(e);
} finally {
SUBJECT_THREAD_LOCAL.set(oldSubject);
}
} else {
try {
PrivilegedExceptionAction<T> pa = () -> action.call();
@SuppressWarnings("removal")
var result = doAs(subject, pa);
return result;
} catch (PrivilegedActionException e) {
throw new CompletionException(e.getCause());
} catch (Exception e) {
throw new CompletionException(e);
}
}
}
/**
* Perform work as a particular {@code Subject}.
*
@ -354,8 +461,17 @@ public final class Subject implements java.io.Serializable {
* {@link AuthPermission#AuthPermission(String)
* AuthPermission("doAs")} permission to invoke this
* method.
*
* @deprecated This method depends on {@link AccessControlContext}
* which, in conjunction with
* {@linkplain SecurityManager the Security Manager}, is deprecated
* and subject to removal in a future release. However, performing
* work as a Subject is useful independent of the Security Manager.
* Thus, a replacement API named {@link #callAs} has been added
* which can be used to perform the same work.
*/
@SuppressWarnings("removal")
@Deprecated(since="18", forRemoval=true)
public static <T> T doAs(final Subject subject,
final java.security.PrivilegedAction<T> action) {
@ -417,8 +533,17 @@ public final class Subject implements java.io.Serializable {
* {@link AuthPermission#AuthPermission(String)
* AuthPermission("doAs")} permission to invoke this
* method.
*
* @deprecated This method depends on {@link AccessControlContext}
* which, in conjunction with
* {@linkplain SecurityManager the Security Manager}, is deprecated
* and subject to removal in a future release. However, performing
* work as a Subject is useful independent of the Security Manager.
* Thus, a replacement API named {@link #callAs} has been added
* which can be used to perform the same work.
*/
@SuppressWarnings("removal")
@Deprecated(since="18", forRemoval=true)
public static <T> T doAs(final Subject subject,
final java.security.PrivilegedExceptionAction<T> action)
throws java.security.PrivilegedActionException {
@ -857,10 +982,7 @@ public final class Subject implements java.io.Serializable {
// avoid deadlock from dual locks
thatPrivCredentials = new HashSet<>(that.privCredentials);
}
if (!privCredentials.equals(thatPrivCredentials)) {
return false;
}
return true;
return privCredentials.equals(thatPrivCredentials);
}
return false;
}
@ -933,7 +1055,7 @@ public final class Subject implements java.io.Serializable {
@Override
public int hashCode() {
/**
/*
* The hashcode is derived exclusive or-ing the
* hashcodes of this Subject's Principals and credentials.
*
@ -1244,7 +1366,7 @@ public final class Subject implements java.io.Serializable {
} else {
// For private credentials:
// If the caller does not have read permission for
// If the caller does not have read permission
// for o.getClass(), we throw a SecurityException.
// Otherwise we check the private cred set to see whether
// it contains the Object
@ -1316,7 +1438,7 @@ public final class Subject implements java.io.Serializable {
c = collectionNullClean(c);
for (Object item : c) {
if (this.contains(item) == false) {
if (!this.contains(item)) {
return false;
}
}
@ -1534,7 +1656,7 @@ public final class Subject implements java.io.Serializable {
break;
}
// Check whether the caller has permisson to get
// Check whether the caller has permission to get
// credentials of Class c
while (iterator.hasNext()) {

View File

@ -40,7 +40,6 @@ import java.util.HashSet;
import java.util.Vector;
import java.util.Iterator;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import javax.security.auth.callback.CallbackHandler;
@ -313,20 +312,18 @@ public class GSSUtil {
(initiate? " INIT" : " ACCEPT") + " cred (" +
(name == null? "<<DEF>>" : name.toString()) + ", " +
credCls.getName() + ")");
@SuppressWarnings("removal")
final AccessControlContext acc = AccessController.getContext();
try {
@SuppressWarnings("removal")
Vector<T> creds =
AccessController.doPrivileged
AccessController.doPrivilegedWithCombiner
(new PrivilegedExceptionAction<Vector<T>>() {
public Vector<T> run() throws Exception {
Subject accSubj = Subject.getSubject(acc);
Subject currSubj = Subject.current();
Vector<T> result = null;
if (accSubj != null) {
if (currSubj != null) {
result = new Vector<T>();
Iterator<GSSCredentialImpl> iterator =
accSubj.getPrivateCredentials
currSubj.getPrivateCredentials
(GSSCredentialImpl.class).iterator();
while (iterator.hasNext()) {
GSSCredentialImpl cred = iterator.next();

View File

@ -25,7 +25,6 @@
package sun.security.jgss.krb5;
import java.io.IOException;
import org.ietf.jgss.*;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.spi.*;
@ -33,7 +32,6 @@ import sun.security.krb5.*;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.AccessController;
import java.security.AccessControlContext;
import javax.security.auth.DestroyFailedException;
/**
@ -65,16 +63,15 @@ public class Krb5AcceptCredential
final String serverPrinc = (name == null? null:
name.getKrb5PrincipalName().getName());
final AccessControlContext acc = AccessController.getContext();
ServiceCreds creds = null;
try {
creds = AccessController.doPrivileged(
creds = AccessController.doPrivilegedWithCombiner(
new PrivilegedExceptionAction<ServiceCreds>() {
public ServiceCreds run() throws Exception {
return Krb5Util.getServiceCreds(
caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller,
serverPrinc, acc);
serverPrinc);
}});
} catch (PrivilegedActionException e) {
GSSException ge =

View File

@ -37,7 +37,6 @@ import java.io.OutputStream;
import java.io.IOException;
import java.security.Provider;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.Key;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@ -641,16 +640,12 @@ class Krb5Context implements GSSContextSpi {
* for this service in the Subject and reuse it
*/
@SuppressWarnings("removal")
final AccessControlContext acc =
AccessController.getContext();
if (GSSUtil.useSubjectCredsOnly(caller)) {
KerberosTicket kerbTicket = null;
try {
// get service ticket from caller's subject
@SuppressWarnings("removal")
var tmp = AccessController.doPrivileged(
var tmp = AccessController.doPrivilegedWithCombiner(
new PrivilegedExceptionAction<KerberosTicket>() {
public KerberosTicket run() throws Exception {
// XXX to be cleaned
@ -665,8 +660,7 @@ class Krb5Context implements GSSContextSpi {
second == null ?
myName.getKrb5PrincipalName().getName():
second.getName().getKrb5PrincipalName().getName(),
peerName.getKrb5PrincipalName().getName(),
acc);
peerName.getKrb5PrincipalName().getName());
}});
kerbTicket = tmp;
} catch (PrivilegedActionException e) {
@ -710,10 +704,10 @@ class Krb5Context implements GSSContextSpi {
if (GSSUtil.useSubjectCredsOnly(caller)) {
@SuppressWarnings("removal")
final Subject subject =
AccessController.doPrivileged(
AccessController.doPrivilegedWithCombiner(
new java.security.PrivilegedAction<Subject>() {
public Subject run() {
return (Subject.getSubject(acc));
return (Subject.current());
}
});
if (subject != null &&

View File

@ -35,7 +35,6 @@ import java.net.InetAddress;
import java.io.IOException;
import java.util.Date;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
@ -365,20 +364,17 @@ public class Krb5InitCredential
clientPrincipal = null;
}
final AccessControlContext acc = AccessController.getContext();
try {
final GSSCaller realCaller = (caller == GSSCaller.CALLER_UNKNOWN)
? GSSCaller.CALLER_INITIATE
: caller;
return AccessController.doPrivileged(
return AccessController.doPrivilegedWithCombiner(
new PrivilegedExceptionAction<KerberosTicket>() {
public KerberosTicket run() throws Exception {
// It's OK to use null as serverPrincipal. TGT is almost
// the first ticket for a principal and we use list.
return Krb5Util.getInitialTicket(
realCaller,
clientPrincipal, acc);
realCaller, clientPrincipal);
}});
} catch (PrivilegedActionException e) {
GSSException ge =

View File

@ -30,7 +30,6 @@ import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KeyTab;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import java.security.AccessControlContext;
import sun.security.action.GetBooleanAction;
import sun.security.jgss.GSSUtil;
@ -62,14 +61,12 @@ public class Krb5Util {
* pair from the Subject in the specified AccessControlContext.
*/
static KerberosTicket getServiceTicket(GSSCaller caller,
String clientPrincipal, String serverPrincipal,
@SuppressWarnings("removal") AccessControlContext acc) throws LoginException {
// Try to get ticket from acc's Subject
String clientPrincipal, String serverPrincipal) {
// Try to get ticket from current Subject
@SuppressWarnings("removal")
Subject accSubj = Subject.getSubject(acc);
Subject currSubj = Subject.current();
KerberosTicket ticket =
SubjectComber.find(accSubj, serverPrincipal, clientPrincipal,
SubjectComber.find(currSubj, serverPrincipal, clientPrincipal,
KerberosTicket.class);
return ticket;
@ -83,14 +80,11 @@ public class Krb5Util {
* a LoginContext.
*/
static KerberosTicket getInitialTicket(GSSCaller caller,
String clientPrincipal,
@SuppressWarnings("removal") AccessControlContext acc) throws LoginException {
String clientPrincipal) throws LoginException {
// Try to get ticket from acc's Subject
@SuppressWarnings("removal")
Subject accSubj = Subject.getSubject(acc);
Subject currSubj = Subject.current();
KerberosTicket ticket =
SubjectComber.find(accSubj, null, clientPrincipal,
SubjectComber.find(currSubj, null, clientPrincipal,
KerberosTicket.class);
// Try to get ticket from Subject obtained from GSSUtil
@ -106,18 +100,14 @@ public class Krb5Util {
* Retrieves the ServiceCreds for the specified server principal from
* the Subject in the specified AccessControlContext. If not found, and if
* useSubjectCredsOnly is false, then obtain from a LoginContext.
*
* NOTE: This method is also used by JSSE Kerberos Cipher Suites
*/
public static ServiceCreds getServiceCreds(GSSCaller caller,
String serverPrincipal, @SuppressWarnings("removal") AccessControlContext acc)
throws LoginException {
String serverPrincipal) throws LoginException {
@SuppressWarnings("removal")
Subject accSubj = Subject.getSubject(acc);
Subject currSubj = Subject.current();
ServiceCreds sc = null;
if (accSubj != null) {
sc = ServiceCreds.getInstance(accSubj, serverPrincipal);
if (currSubj != null) {
sc = ServiceCreds.getInstance(currSubj, serverPrincipal);
}
if (sc == null && !GSSUtil.useSubjectCredsOnly(caller)) {
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -35,11 +35,11 @@
import javax.security.sasl.*;
import javax.security.auth.callback.*;
import java.security.*;
import javax.security.auth.Subject;
import javax.security.auth.login.*;
import com.sun.security.auth.callback.*;
import java.util.HashMap;
import java.util.concurrent.Callable;
public class AuthOnly {
private static final String MECH = "GSSAPI";
@ -84,8 +84,8 @@ public class AuthOnly {
srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf");
final SaslClient clnt = (SaslClient)
Subject.doAs(clntSubj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
Subject.callAs(clntSubj, new Callable<>() {
public Object call() throws Exception {
return Sasl.createSaslClient(
new String[]{MECH}, null, PROTOCOL, SERVER_FQDN,
clntprops, null);
@ -97,8 +97,8 @@ public class AuthOnly {
System.out.println(srvSubj);
}
final SaslServer srv = (SaslServer)
Subject.doAs(srvSubj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
Subject.callAs(srvSubj, new Callable<Object>() {
public Object call() throws Exception {
return Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN,
srvprops, srvCbh);
}
@ -117,27 +117,18 @@ public class AuthOnly {
byte[] response;
byte[] challenge;
response = (byte[]) Subject.doAs(clntSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY);
}});
response = (byte[]) Subject.callAs(clntSubj,
() -> (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY));
while (!clnt.isComplete() || !srv.isComplete()) {
final byte[] responseCopy = response;
challenge = (byte[]) Subject.doAs(srvSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return srv.evaluateResponse(responseCopy);
}});
challenge = (byte[]) Subject.callAs(srvSubj,
() -> srv.evaluateResponse(responseCopy));
if (challenge != null) {
final byte[] challengeCopy = challenge;
response = (byte[]) Subject.doAs(clntSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return clnt.evaluateChallenge(challengeCopy);
}});
response = (byte[]) Subject.callAs(clntSubj,
() -> clnt.evaluateChallenge(challengeCopy));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2021, 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
@ -36,7 +36,6 @@
import javax.security.sasl.*;
import javax.security.auth.callback.*;
import java.security.*;
import javax.security.auth.Subject;
import javax.security.auth.login.*;
import com.sun.security.auth.callback.*;
@ -85,25 +84,18 @@ public class ConfSecurityLayer {
srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf");
final SaslClient clnt = (SaslClient)
Subject.doAs(clntSubj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
return Sasl.createSaslClient(
Subject.callAs(clntSubj, () ->Sasl.createSaslClient(
new String[]{MECH}, null, PROTOCOL, SERVER_FQDN,
clntprops, null);
}
});
clntprops, null));
if (verbose) {
System.out.println(clntSubj);
System.out.println(srvSubj);
}
final SaslServer srv = (SaslServer)
Subject.doAs(srvSubj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
return Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN,
srvprops, srvCbh);
}
});
Subject.callAs(srvSubj, () ->
Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN,
srvprops, srvCbh));
if (clnt == null) {
@ -118,27 +110,18 @@ public class ConfSecurityLayer {
byte[] response;
byte[] challenge;
response = (byte[]) Subject.doAs(clntSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY);
}});
response = Subject.callAs(clntSubj,
() -> (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY));
while (!clnt.isComplete() || !srv.isComplete()) {
final byte[] responseCopy = response;
challenge = (byte[]) Subject.doAs(srvSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return srv.evaluateResponse(responseCopy);
}});
challenge = Subject.callAs(srvSubj,
() -> srv.evaluateResponse(responseCopy));
if (challenge != null) {
final byte[] challengeCopy = challenge;
response = (byte[]) Subject.doAs(clntSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return clnt.evaluateChallenge(challengeCopy);
}});
response = Subject.callAs(clntSubj,
() -> clnt.evaluateChallenge(challengeCopy));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -36,7 +36,6 @@
import javax.security.sasl.*;
import javax.security.auth.callback.*;
import java.security.*;
import javax.security.auth.Subject;
import javax.security.auth.login.*;
import com.sun.security.auth.callback.*;
@ -84,26 +83,20 @@ public class NoSecurityLayer {
clntprops.put(Sasl.QOP, "auth");
srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf");
final SaslClient clnt = (SaslClient)
Subject.doAs(clntSubj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
return Sasl.createSaslClient(
final SaslClient clnt =
Subject.callAs(clntSubj, () ->
Sasl.createSaslClient(
new String[]{MECH}, null, PROTOCOL, SERVER_FQDN,
clntprops, null);
}
});
clntprops, null));
if (verbose) {
System.out.println(clntSubj);
System.out.println(srvSubj);
}
final SaslServer srv = (SaslServer)
Subject.doAs(srvSubj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
return Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN,
srvprops, srvCbh);
}
});
final SaslServer srv =
Subject.callAs(srvSubj, () ->
Sasl.createSaslServer(MECH, PROTOCOL, SERVER_FQDN,
srvprops, srvCbh));
if (clnt == null) {
@ -118,27 +111,18 @@ public class NoSecurityLayer {
byte[] response;
byte[] challenge;
response = (byte[]) Subject.doAs(clntSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY);
}});
response = Subject.callAs(clntSubj,
() -> (clnt.hasInitialResponse()? clnt.evaluateChallenge(EMPTY) : EMPTY));
while (!clnt.isComplete() || !srv.isComplete()) {
final byte[] responseCopy = response;
challenge = (byte[]) Subject.doAs(srvSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return srv.evaluateResponse(responseCopy);
}});
challenge = Subject.callAs(srvSubj,
() -> srv.evaluateResponse(responseCopy));
if (challenge != null) {
final byte[] challengeCopy = challenge;
response = (byte[]) Subject.doAs(clntSubj,
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return clnt.evaluateChallenge(challengeCopy);
}});
response = Subject.callAs(clntSubj,
() -> clnt.evaluateChallenge(challengeCopy));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2021, 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
@ -28,6 +28,7 @@
*/
import java.security.*;
import java.util.concurrent.Callable;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
@ -38,16 +39,15 @@ public class PreserveCombiner {
Subject s = new Subject();
s.getPrincipals().add(new X500Principal("cn=duke"));
String result = (String)Subject.doAs(s, new PrivilegedAction() {
public Object run() {
String result = Subject.callAs(s, new Callable<String>() {
public String call() {
// get subject from current ACC - this always worked
Subject doAsSubject =
Subject.getSubject(AccessController.getContext());
if (doAsSubject == null) {
Subject callAsSubject = Subject.current();
if (callAsSubject == null) {
return "test 1 failed";
} else {
System.out.println(doAsSubject);
System.out.println(callAsSubject);
System.out.println("test 1 passed");
}
@ -56,8 +56,7 @@ public class PreserveCombiner {
(new PrivilegedAction<String>() {
public String run() {
// get subject after doPriv
Subject doPrivSubject =
Subject.getSubject(AccessController.getContext());
Subject doPrivSubject = Subject.current();
if (doPrivSubject == null) {
return "test 2 failed";
} else {
@ -79,8 +78,7 @@ public class PreserveCombiner {
(new PrivilegedExceptionAction<String>() {
public String run() throws PrivilegedActionException {
// get subject after doPriv
Subject doPrivSubject = Subject.getSubject
(AccessController.getContext());
Subject doPrivSubject = Subject.current();
if (doPrivSubject == null) {
return "test 3 failed";
} else {

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2021, 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.
*/
import javax.security.auth.Subject;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
/*
* @test
* @bug 8267108
* @summary confirm current subject specification
* @run main/othervm
* -Djdk.security.auth.subject.useTL=false -Dtest=both CurrentSubject
* @run main/othervm
* -Djdk.security.auth.subject.useTL=true -Dtest=old CurrentSubject
* @run main/othervm
* -Djdk.security.auth.subject.useTL=true -Dtest=new CurrentSubject
*/
public class CurrentSubject {
static final boolean TEST_NEW = !System.getProperty("test").equals("old");
static final boolean TEST_OLD = !System.getProperty("test").equals("new");
static transient boolean failed = false;
static CountDownLatch cl = new CountDownLatch(1);
static AtomicInteger count = new AtomicInteger();
public static void main(String[] args) throws Exception {
// At the beginning, current subject is null
test("", null);
cl.await();
if (failed) {
throw new Exception("Failed");
}
}
/**
* Ensure the current subject is the expected Subject object.
*
* @param label label to print out
* @param expected the expected Subject
*/
synchronized static void check(String label, Subject expected) {
Subject cas = Subject.current();
Subject accs = Subject.getSubject(AccessController.getContext());
if (TEST_NEW && TEST_OLD && cas != accs) {
failed = true;
System.out.println(label + ": current " + s2s(cas)
+ " but getSubject is " + s2s(accs));
}
Subject interested = TEST_NEW ? cas : accs;
if (interested != expected) {
failed = true;
System.out.println(label + ": expected " + s2s(expected)
+ " but see " + s2s(interested));
} else {
System.out.println(label + ": " + s2s(expected));
}
}
/**
* Recursively testing on current subject with getAs() and thread creations.
*
* @param name the current label
* @param expected the expected Subject
*/
static Void test(String name, Subject expected) {
// Now it's the expected current subject
check(" ".repeat(name.length()) + "-> " + name, expected);
// Recursively check, do not go infinity
if (name.length() < 4) {
Subject another = new Subject();
another.getPrincipals().add(new RawPrincipal(name + "d"));
// run with a new subject, inside current subject will be the new subject
if (TEST_NEW) Subject.callAs(another, () -> test(name + 'c', another));
if (TEST_OLD) Subject.doAs(another, (PrivilegedAction<Void>) () -> test(name + 'd', another));
// run with null, inside current subject will be null
if (TEST_NEW) Subject.callAs(null, () -> test(name + 'C', null));
if (TEST_OLD) Subject.doAs(null, (PrivilegedAction<Void>) () -> test(name + 'D', null));
// new thread, inside current subject is unchanged
count.incrementAndGet();
new Thread(() -> {
try {
test(name + 't', expected);
try {
Thread.sleep(500);
} catch (Exception e) {
throw new AssertionError(e);
}
// by this time, parent thread should have exited the
// action and current subject reset, but here
// current subject unchanged.
test(name + 'T', expected);
} finally {
var n = count.decrementAndGet();
if (n == 0) {
cl.countDown();
}
assert n >= 0;
}
}).start();
}
// Now it's reset to original
check(" ".repeat(name.length()) + "<- " + name, expected);
return null;
}
static class RawPrincipal implements Principal {
String name;
RawPrincipal(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
static String s2s(Subject s) {
return s == null ? null
: s.getPrincipals().iterator().next().getName();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -26,10 +26,6 @@
* @bug 8214583
* @summary Check that getSubject works after JIT compiler escape analysis.
*/
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@ -44,9 +40,8 @@ public class DoAs {
for (int i = 0; i < 100_000; ++i) {
final int index = i;
Subject.doAs(subject, (PrivilegedExceptionAction<Integer>)() -> {
AccessControlContext c1 = AccessController.getContext();
Subject s = Subject.getSubject(c1);
Subject.callAs(subject, () -> {
Subject s = Subject.current();
if (s != subject) {
throw new AssertionError("outer Oops! " + "iteration " + index + " " + s + " != " + subject);
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2021, 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 8267108
* @library /test/lib
* @summary Check that callAs and doAs throw the specified exceptions
* @run main/othervm -Djava.security.manager=allow -Djdk.security.auth.subject.useTL=true Exceptions
* @run main/othervm -Djava.security.manager=allow -Djdk.security.auth.subject.useTL=false Exceptions
*/
import jdk.test.lib.Asserts;
import javax.security.auth.Subject;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
public class Exceptions {
public static void main(String[] args) throws Exception {
// Checked exceptions are always wrapped
new TestCase(() -> { throw new Exception("Hi"); })
.testDoAs(PrivilegedActionException.class, Exception.class)
.testCallAs(CompletionException.class, Exception.class);
// PrivilegedActionException itself is checked
new TestCase(() -> { throw new PrivilegedActionException(new Exception("Hi")); })
.testDoAs(PrivilegedActionException.class, PrivilegedActionException.class, Exception.class)
.testCallAs(CompletionException.class, PrivilegedActionException.class, Exception.class);
// Unchecked exception: rethrown by doAs(), wrapped by callAs()
new TestCase(() -> { throw new RuntimeException("Hi"); })
.testDoAs(RuntimeException.class)
.testCallAs(CompletionException.class, RuntimeException.class);
// CompletionException itself is unchecked
new TestCase(() -> { throw new CompletionException(new Exception("Hi")); })
.testDoAs(CompletionException.class, Exception.class)
.testCallAs(CompletionException.class, CompletionException.class, Exception.class);
}
static class TestCase {
final Callable<Void> action;
TestCase(Callable<Void> action) {
this.action = action;
}
TestCase testDoAs(Class<?>... exceptions) {
return test(true, exceptions);
}
TestCase testCallAs(Class<?>... exceptions) {
return test(false, exceptions);
}
// Perform the action in doAs() or callAs() and inspect
// the exception (and its causes, recursively) it throws
private TestCase test(boolean doAs, Class<?>... exceptions) {
int pos = 0;
try {
if (doAs) {
Subject.doAs(null, (PrivilegedExceptionAction<Object>) action::call);
} else {
Subject.callAs(null, action::call);
}
} catch (Exception e) {
while (e != null) {
Asserts.assertEQ(e.getClass(), exceptions[pos++]);
e = (Exception) e.getCause();
}
}
// Make sure the list is the exact size
Asserts.assertTrue(pos == exceptions.length);
return this;
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2021, 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.
*/
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
/*
* @test
* @bug 8267108
* @summary confirm current installed subject specification
* @run main/othervm -Djava.security.manager=allow FromACC
* @run main/othervm -Djava.security.manager=disallow FromACC
*/
public class FromACC {
public static void main(String[] args) throws Exception {
var n = Subject.doAs(from("a"), (PrivilegedAction<AccessControlContext>)
() -> AccessController.getContext());
if (!get(Subject.getSubject(n)).equals("CN=a")) {
throw new RuntimeException();
}
}
static Subject from(String name) {
Subject s = new Subject();
s.getPrincipals().add(new X500Principal("CN=" + name));
return s;
}
static String get(Subject s) {
if (s == null) {
return "none";
}
var v = s.getPrincipals(X500Principal.class);
if (v == null || v.isEmpty()) {
return "none";
} else {
return v.iterator().next().getName();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -28,9 +28,9 @@
*/
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
@ -52,18 +52,18 @@ public class Synch {
}
}.start();
for (int i = 0; i < 1000; i++) {
Subject.doAs(
Subject.callAs(
subject,
new PrivilegedAction() {
public Object run() {
return Subject.doAs(
new Callable() {
public Object call() {
return Subject.callAs(
new Subject(true,
Collections.singleton(
new X500Principal("CN=Claire")),
Collections.EMPTY_SET,
Collections.EMPTY_SET),
new PrivilegedAction() {
public Object run() {
new Callable() {
public Object call() {
return null;
}
});

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, 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
@ -31,7 +31,7 @@
*/
import java.io.FileOutputStream;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.Callable;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
@ -59,8 +59,8 @@ public class KrbCredSubKey {
subj.getPrincipals().add(kp);
subj.getPrivateCredentials().add(kk);
Subject.doAs(subj, new PrivilegedExceptionAction() {
public Object run() throws Exception {
Subject.callAs(subj, new Callable<>() {
public Object call() throws Exception {
GSSManager man = GSSManager.getInstance();
GSSContext ctxt = man.createContext(man.createCredential(
null, GSSCredential.INDEFINITE_LIFETIME,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021, 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
@ -29,9 +29,9 @@
* @summary default principal can act as anyone
*/
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
@ -122,10 +122,10 @@ public class ServiceCredsCombination {
}
final GSSManager man = GSSManager.getInstance();
try {
String result = Subject.doAs(
subj, new PrivilegedExceptionAction<String>() {
String result = Subject.callAs(
subj, new Callable<String>() {
@Override
public String run() throws GSSException {
public String call() throws GSSException {
GSSCredential cred = man.createCredential(
a == null ? null : man.createName(r(a), null),
GSSCredential.INDEFINITE_LIFETIME,
@ -139,7 +139,7 @@ public class ServiceCredsCombination {
throw new Exception("Check failed: getInstance(" + a
+ ") has name " + result + ", not " + b);
}
} catch (PrivilegedActionException e) {
} catch (CompletionException e) {
if (!"NOCRED".equals(b)) {
throw new Exception("Check failed: getInstance(" + a
+ ") is null " + ", but not one with name " + b);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2021, 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
@ -26,8 +26,6 @@ import com.sun.security.auth.module.Krb5LoginModule;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -55,6 +53,8 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.Principal;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
/**
* Context of a JGSS subject, encapsulating Subject and GSSContext.
@ -100,9 +100,9 @@ public class Context {
Context out = new Context();
out.s = s;
try {
out.cred = Subject.doAs(s, new PrivilegedExceptionAction<GSSCredential>() {
out.cred = Subject.callAs(s, new Callable<GSSCredential>() {
@Override
public GSSCredential run() throws Exception {
public GSSCredential call() throws Exception {
GSSCredential cred = x.getDelegCred();
if (cred == null && x.getCredDelegState() ||
cred != null && !x.getCredDelegState()) {
@ -111,8 +111,8 @@ public class Context {
return cred;
}
});
} catch (PrivilegedActionException pae) {
throw pae.getException();
} catch (CompletionException ce) {
throw (Exception) ce.getCause();
}
out.name = name + " as " + out.cred.getName().toString();
return out;
@ -339,15 +339,15 @@ public class Context {
*/
public byte[] doAs(final Action action, final byte[] in) throws Exception {
try {
return Subject.doAs(s, new PrivilegedExceptionAction<byte[]>() {
return Subject.callAs(s, new Callable<byte[]>() {
@Override
public byte[] run() throws Exception {
public byte[] call() throws Exception {
return action.run(Context.this, in);
}
});
} catch (PrivilegedActionException pae) {
throw pae.getException();
} catch (CompletionException ce) {
throw (Exception) ce.getCause();
}
}
@ -612,9 +612,9 @@ public class Context {
public Context impersonate(final String someone) throws Exception {
try {
GSSCredential creds = Subject.doAs(s, new PrivilegedExceptionAction<GSSCredential>() {
GSSCredential creds = Subject.callAs(s, new Callable<GSSCredential>() {
@Override
public GSSCredential run() throws Exception {
public GSSCredential call() throws Exception {
GSSManager m = GSSManager.getInstance();
GSSName other = m.createName(someone, GSSName.NT_USER_NAME);
if (Context.this.cred == null) {
@ -631,8 +631,8 @@ public class Context {
out.cred = creds;
out.name = name + " as " + out.cred.getName().toString();
return out;
} catch (PrivilegedActionException pae) {
Exception e = pae.getException();
} catch (CompletionException ce) {
Exception e = (Exception) ce.getCause();
if (e instanceof InvocationTargetException) {
throw (Exception)((InvocationTargetException) e).getTargetException();
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2021, 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
@ -83,6 +83,8 @@ import org.ietf.jgss.GSSManager;
import sun.security.jgss.GSSUtil;
import sun.security.krb5.Config;
import java.util.Base64;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
/**
* Basic JGSS/krb5 test with 3 parties: client, server, backend server. Each
@ -375,9 +377,9 @@ public class HttpNegotiateServer {
Subject subject = context.getSubject();
final PrivilegedExceptionAction<Object> test_action
= new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
final Callable<Object> test_action
= new Callable<Object>() {
public Object call() throws Exception {
testConnect();
return null;
}
@ -387,10 +389,10 @@ public class HttpNegotiateServer {
"with the the logged in subject.");
try {
Subject.doAs(subject, test_action);
Subject.callAs(subject, test_action);
System.err.println("\n\nConnection succeed when executing " +
"with the the logged in subject.");
} catch (PrivilegedActionException e) {
} catch (CompletionException e) {
System.err.println("\n\nFailure unexpected when executing " +
"with the the logged in subject.");
e.printStackTrace();
@ -466,9 +468,9 @@ public class HttpNegotiateServer {
krb5.login();
krb5.commit();
m = GSSManager.getInstance();
cred = Subject.doAs(s, new PrivilegedExceptionAction<GSSCredential>() {
cred = Subject.callAs(s, new Callable<GSSCredential>() {
@Override
public GSSCredential run() throws Exception {
public GSSCredential call() throws Exception {
System.err.println("Creating GSSCredential");
return m.createCredential(
null,
@ -494,12 +496,7 @@ public class HttpNegotiateServer {
if (auth == null) { // First request
Headers map = exch.getResponseHeaders();
map.set (reqHdr, scheme); // Challenge!
c = Subject.doAs(s, new PrivilegedExceptionAction<GSSContext>() {
@Override
public GSSContext run() throws Exception {
return m.createContext(cred);
}
});
c = Subject.callAs(s, () -> m.createContext(cred));
exch.getHttpContext().getAttributes().put("GSSContext", c);
return new com.sun.net.httpserver.Authenticator.Retry(err);
} else { // Later requests

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, 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
@ -36,7 +36,6 @@ import org.ietf.jgss.GSSManager;
import sun.security.krb5.Config;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosTicket;
import java.security.PrivilegedExceptionAction;
public class LongLife {
@ -72,8 +71,7 @@ public class LongLife {
Context c = Context.fromJAAS("client");
GSSCredential cred = Subject.doAs(c.s(),
(PrivilegedExceptionAction<GSSCredential>)
GSSCredential cred = Subject.callAs(c.s(),
()-> {
GSSManager m = GSSManager.getInstance();
return m.createCredential(GSSCredential.INITIATE_ONLY);