org.postgresql.gss.MakeGSS Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdbc-yugabytedb Show documentation
Show all versions of jdbc-yugabytedb Show documentation
Java JDBC 4.2 (JRE 8+) driver for YugaByte SQL database
The newest version!
/*
* Copyright (c) 2008, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.gss;
import static org.postgresql.util.internal.Nullness.castNonNull;
import org.postgresql.PGProperty;
import org.postgresql.core.PGStream;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.ietf.jgss.GSSCredential;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.PrivilegedAction;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
public class MakeGSS {
private static final Logger LOGGER = Logger.getLogger(MakeGSS.class.getName());
private static final @Nullable MethodHandle SUBJECT_CURRENT;
private static final @Nullable MethodHandle ACCESS_CONTROLLER_GET_CONTEXT;
private static final @Nullable MethodHandle SUBJECT_GET_SUBJECT;
// Java <18
private static final @Nullable MethodHandle SUBJECT_DO_AS;
// Java 18+, see https://bugs.openjdk.org/browse/JDK-8267108
private static final @Nullable MethodHandle SUBJECT_CALL_AS;
static {
MethodHandle subjectCurrent = null;
try {
subjectCurrent = MethodHandles.lookup()
.findStatic(Subject.class, "current", MethodType.methodType(Subject.class));
} catch (NoSuchMethodException | IllegalAccessException ignore) {
// E.g. pre Java 18
}
SUBJECT_CURRENT = subjectCurrent;
MethodHandle accessControllerGetContext = null;
MethodHandle subjectGetSubject = null;
try {
Class> accessControllerClass = Class.forName("java.security.AccessController");
Class> accessControlContextClass =
Class.forName("java.security.AccessControlContext");
accessControllerGetContext = MethodHandles.lookup()
.findStatic(accessControllerClass, "getContext",
MethodType.methodType(accessControlContextClass));
subjectGetSubject = MethodHandles.lookup()
.findStatic(Subject.class, "getSubject",
MethodType.methodType(Subject.class, accessControlContextClass));
} catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException ignore) {
// E.g. pre Java 18+
}
ACCESS_CONTROLLER_GET_CONTEXT = accessControllerGetContext;
SUBJECT_GET_SUBJECT = subjectGetSubject;
MethodHandle subjectDoAs = null;
try {
subjectDoAs = MethodHandles.lookup().findStatic(Subject.class, "doAs",
MethodType.methodType(Object.class, Subject.class, PrivilegedAction.class));
} catch (NoSuchMethodException | IllegalAccessException ignore) {
}
SUBJECT_DO_AS = subjectDoAs;
MethodHandle subjectCallAs = null;
try {
subjectCallAs = MethodHandles.lookup().findStatic(Subject.class, "callAs",
MethodType.methodType(Object.class, Subject.class, Callable.class));
} catch (NoSuchMethodException | IllegalAccessException ignore) {
}
SUBJECT_CALL_AS = subjectCallAs;
}
/**
* Use {@code Subject.current()} in Java 18+, and
* {@code Subject.getSubject(AccessController.getContext())} in Java before 18.
* @return current Subject or null
*/
@SuppressWarnings("deprecation")
private static @Nullable Subject getCurrentSubject() {
try {
if (SUBJECT_CURRENT != null) {
return (Subject) SUBJECT_CURRENT.invokeExact();
}
if (SUBJECT_GET_SUBJECT == null || ACCESS_CONTROLLER_GET_CONTEXT == null) {
return null;
}
return (Subject) SUBJECT_GET_SUBJECT.invoke(
ACCESS_CONTROLLER_GET_CONTEXT.invoke()
);
} catch (Throwable e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
if (e instanceof Error) {
throw (Error) e;
}
throw new RuntimeException(e);
}
}
public static void authenticate(boolean encrypted,
PGStream pgStream, String host, String user, char @Nullable [] password,
@Nullable String jaasApplicationName, @Nullable String kerberosServerName,
boolean useSpnego, boolean jaasLogin,
boolean logServerErrorDetail)
throws IOException, PSQLException {
LOGGER.log(Level.FINEST, " <=BE AuthenticationReqGSS");
if (jaasApplicationName == null) {
jaasApplicationName = PGProperty.JAAS_APPLICATION_NAME.getDefaultValue();
}
if (kerberosServerName == null) {
kerberosServerName = "postgres";
}
@Nullable Exception result;
try {
boolean performAuthentication = jaasLogin;
//Check if we can get credential from subject to avoid login.
Subject sub = getCurrentSubject();
if (sub != null) {
Set gssCreds = sub.getPrivateCredentials(GSSCredential.class);
if (gssCreds != null && !gssCreds.isEmpty()) {
performAuthentication = false;
}
}
if (performAuthentication) {
LoginContext lc = new LoginContext(castNonNull(jaasApplicationName), new GSSCallbackHandler(user, password));
lc.login();
sub = lc.getSubject();
}
PrivilegedAction<@Nullable Exception> action;
if ( encrypted ) {
action = new GssEncAction(pgStream, sub, host, user,
kerberosServerName, useSpnego, logServerErrorDetail);
} else {
action = new GssAction(pgStream, sub, host, user,
kerberosServerName, useSpnego, logServerErrorDetail);
}
//noinspection ConstantConditions
@SuppressWarnings({"cast.unsafe", "assignment"})
@NonNull Subject subject = sub;
if (SUBJECT_DO_AS != null) {
result = (Exception) SUBJECT_DO_AS.invoke(subject, action);
} else if (SUBJECT_CALL_AS != null) {
//noinspection ConstantConditions,unchecked
result = (Exception) SUBJECT_CALL_AS.invoke(subject, action);
} else {
throw new PSQLException(
GT.tr("Neither Subject.doAs (Java before 18) nor Subject.callAs (Java 18+) method found"),
PSQLState.OBJECT_NOT_IN_STATE);
}
} catch (Throwable e) {
throw new PSQLException(GT.tr("GSS Authentication failed"), PSQLState.CONNECTION_FAILURE, e);
}
if (result instanceof IOException) {
throw (IOException) result;
} else if (result instanceof PSQLException) {
throw (PSQLException) result;
} else if (result != null) {
throw new PSQLException(GT.tr("GSS Authentication failed"), PSQLState.CONNECTION_FAILURE,
result);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy